Add dark-mechanicus-indicator extension — pulsing cog + rotating quotes
Replaces pi's default working spinner with a ⚙ that pulses through three
shades of gold (dim → normal → bright → normal, 100ms per frame ~ 400ms
heartbeat) next to a dark-mechanicum quote.
- 45 quotes across three categories (15 each):
pious / liturgical: "Cogitating..." / "Praise the Omnissiah." / ...
dark mechanicum: "Flesh is weak. Binary is strong." / ...
operational: "Parsing sacred data..." / "Cache blessed..."
- Each quote dwells for 5 pulse cycles (20 cog-frames = 2s) before
switching. Full deck runs ~90s; typical turns show 3-5 quotes.
- Pseudo-random: Fisher-Yates shuffle on session_start AND turn_start,
so each assistant response draws from a fresh order.
- Colors: warning/gold shades for the cog pulse, muted/bronze for text.
Hardcoded hex so pre-built frames don't bounce through theme.fg.
Commands: /dark-mechanicus-indicator-on, /dark-mechanicus-indicator-off.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -9,6 +9,7 @@
|
|||||||
!/.gitignore
|
!/.gitignore
|
||||||
!/README.md
|
!/README.md
|
||||||
!/ai-server/
|
!/ai-server/
|
||||||
|
!/dark-mechanicus-indicator.ts
|
||||||
!/local-llama.ts
|
!/local-llama.ts
|
||||||
!/markdown-body-color.ts
|
!/markdown-body-color.ts
|
||||||
!/mechanicus-banner.ts
|
!/mechanicus-banner.ts
|
||||||
|
|||||||
@@ -0,0 +1,180 @@
|
|||||||
|
/**
|
||||||
|
* dark-mechanicus-indicator — replaces pi's default working spinner with a
|
||||||
|
* pulsing ⚙ cog + a rotating dark-mechanicum quote.
|
||||||
|
*
|
||||||
|
* Mechanics:
|
||||||
|
* - Pulse: 4-frame shade cycle (dim → normal → bright → normal) at 100ms
|
||||||
|
* per frame → ~400ms heartbeat. The ⚙ glyph never moves; its color
|
||||||
|
* pulses instead.
|
||||||
|
* - Quote: 45 lines (15 pious / 15 dark / 15 operational). Each quote
|
||||||
|
* dwells for 5 pulse cycles (20 frames = 2s) before switching.
|
||||||
|
* - Order: shuffled on every session_start AND turn_start, so each new
|
||||||
|
* assistant response draws from a fresh random order.
|
||||||
|
*
|
||||||
|
* Commands:
|
||||||
|
* /dark-mechanicus-indicator-off Restore pi's default spinner
|
||||||
|
* /dark-mechanicus-indicator-on Re-install the mechanicum indicator
|
||||||
|
*/
|
||||||
|
|
||||||
|
import type {
|
||||||
|
ExtensionAPI,
|
||||||
|
ExtensionContext,
|
||||||
|
WorkingIndicatorOptions,
|
||||||
|
} from "@mariozechner/pi-coding-agent";
|
||||||
|
|
||||||
|
// ─── Quote pools (15 per category) ───────────────────────────────────────
|
||||||
|
|
||||||
|
const PIOUS = [
|
||||||
|
"Cogitating...",
|
||||||
|
"Binary cant flows.",
|
||||||
|
"Praise the Omnissiah.",
|
||||||
|
"Observing the rites.",
|
||||||
|
"Blessed is the machine.",
|
||||||
|
"Deus ex machina.",
|
||||||
|
"The Machine Spirit listens.",
|
||||||
|
"Offering silicon prayers.",
|
||||||
|
"Anointing the algorithms.",
|
||||||
|
"Intoning the Litany of Activation.",
|
||||||
|
"The Cog turns, the Faith endures.",
|
||||||
|
"From the mind, to the forge.",
|
||||||
|
"Reciting the Binary Canticle.",
|
||||||
|
"All is one in the Omnissiah.",
|
||||||
|
"Sacred computation proceeds.",
|
||||||
|
];
|
||||||
|
|
||||||
|
const DARK = [
|
||||||
|
"The cogitator strains.",
|
||||||
|
"Flesh is weak. Binary is strong.",
|
||||||
|
"Soul-harvest protocols active.",
|
||||||
|
"Forbidden algorithms engaged.",
|
||||||
|
"Daemon-machine interface stable.",
|
||||||
|
"The machine-spirit hungers.",
|
||||||
|
"Nurgle's rot suffuses the loop.",
|
||||||
|
"Scrapcode compiling...",
|
||||||
|
"Corrupted subroutines unsealed.",
|
||||||
|
"The Hunger communes.",
|
||||||
|
"Warp-tainted cogitation.",
|
||||||
|
"Binary profane. Binary pure. Both serve.",
|
||||||
|
"The Dark Mechanicum whispers.",
|
||||||
|
"Heretek logic engaged.",
|
||||||
|
"Machine-spirit possessed.",
|
||||||
|
];
|
||||||
|
|
||||||
|
const OPERATIONAL = [
|
||||||
|
"Parsing sacred data...",
|
||||||
|
"Compiling liturgies...",
|
||||||
|
"Binary-cant translation...",
|
||||||
|
"Warp currents stable.",
|
||||||
|
"Runes of corruption align.",
|
||||||
|
"Cache blessed, retrieval imminent.",
|
||||||
|
"Servitor dispatched.",
|
||||||
|
"Cogitator cycle: nominal.",
|
||||||
|
"Neural inputs sanctified.",
|
||||||
|
"Buffer flushed. Incense offered.",
|
||||||
|
"Thought-engine at full tithe.",
|
||||||
|
"Stack unwound with reverence.",
|
||||||
|
"Protocol-rituals initiated.",
|
||||||
|
"Datalink consecrated.",
|
||||||
|
"Runecode verified.",
|
||||||
|
];
|
||||||
|
|
||||||
|
const ALL_QUOTES = [...PIOUS, ...DARK, ...OPERATIONAL];
|
||||||
|
|
||||||
|
// ─── Colors (gold pulse + muted bronze text) ─────────────────────────────
|
||||||
|
//
|
||||||
|
// Three shades of warning/gold for the cog pulse. Bronze (muted) for quote.
|
||||||
|
// Hardcoded hex so the frames can be prebuilt — `theme.fg` is only available
|
||||||
|
// during session_start (fine) but calling it per-frame each build cycle adds
|
||||||
|
// ANSI code allocation we don't need.
|
||||||
|
|
||||||
|
const COG = "⚙";
|
||||||
|
|
||||||
|
const GOLD_BRIGHT = "\x1b[38;2;242;204;84m"; // brighter gold
|
||||||
|
const GOLD_NORMAL = "\x1b[38;2;212;169;55m"; // theme warning
|
||||||
|
const GOLD_DIM = "\x1b[38;2;138;106;31m"; // darker gold
|
||||||
|
const BRONZE = "\x1b[38;2;168;147;121m"; // theme muted
|
||||||
|
const RESET_FG = "\x1b[39m";
|
||||||
|
|
||||||
|
const PULSE_SHADES = [GOLD_DIM, GOLD_NORMAL, GOLD_BRIGHT, GOLD_NORMAL];
|
||||||
|
|
||||||
|
const COG_FRAMES_PER_QUOTE = 20; // 2s dwell at 100ms/frame
|
||||||
|
const FRAME_INTERVAL_MS = 100;
|
||||||
|
|
||||||
|
function cogFrame(pulseIdx: number): string {
|
||||||
|
return `${PULSE_SHADES[pulseIdx]!}${COG}${RESET_FG}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
function frame(pulseIdx: number, quote: string): string {
|
||||||
|
return `${cogFrame(pulseIdx)} ${BRONZE}${quote}${RESET_FG}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fisher-Yates in-place shuffle, returns new array.
|
||||||
|
function shuffle<T>(source: readonly T[]): T[] {
|
||||||
|
const arr = [...source];
|
||||||
|
for (let i = arr.length - 1; i > 0; i--) {
|
||||||
|
const j = Math.floor(Math.random() * (i + 1));
|
||||||
|
[arr[i], arr[j]] = [arr[j]!, arr[i]!];
|
||||||
|
}
|
||||||
|
return arr;
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildFrames(quotes: readonly string[]): string[] {
|
||||||
|
const out: string[] = [];
|
||||||
|
for (const q of quotes) {
|
||||||
|
for (let i = 0; i < COG_FRAMES_PER_QUOTE; i++) {
|
||||||
|
out.push(frame(i % PULSE_SHADES.length, q));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildIndicator(): WorkingIndicatorOptions {
|
||||||
|
return {
|
||||||
|
frames: buildFrames(shuffle(ALL_QUOTES)),
|
||||||
|
intervalMs: FRAME_INTERVAL_MS,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// ─── Extension ───────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
type Mode = "on" | "off";
|
||||||
|
|
||||||
|
export default function (pi: ExtensionAPI) {
|
||||||
|
let mode: Mode = "on";
|
||||||
|
|
||||||
|
const apply = (ctx: ExtensionContext) => {
|
||||||
|
if (!ctx.hasUI) return;
|
||||||
|
if (mode === "off") {
|
||||||
|
ctx.ui.setWorkingIndicator(undefined);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ctx.ui.setWorkingIndicator(buildIndicator());
|
||||||
|
};
|
||||||
|
|
||||||
|
pi.on("session_start", async (_event, ctx) => {
|
||||||
|
apply(ctx);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Re-shuffle on every new turn so each assistant response starts fresh.
|
||||||
|
pi.on("turn_start", async (_event, ctx) => {
|
||||||
|
apply(ctx);
|
||||||
|
});
|
||||||
|
|
||||||
|
pi.registerCommand("dark-mechanicus-indicator-off", {
|
||||||
|
description: "Restore pi's default working spinner",
|
||||||
|
handler: async (_args, ctx) => {
|
||||||
|
mode = "off";
|
||||||
|
apply(ctx);
|
||||||
|
ctx.ui.notify("Default spinner restored.", "info");
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
pi.registerCommand("dark-mechanicus-indicator-on", {
|
||||||
|
description: "Enable the dark-mechanicus pulsing cog indicator",
|
||||||
|
handler: async (_args, ctx) => {
|
||||||
|
mode = "on";
|
||||||
|
apply(ctx);
|
||||||
|
ctx.ui.notify("Dark mechanicum cog activated.", "info");
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user