@kenkaiiii/gg-boss 4.3.143 → 4.3.144

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js CHANGED
@@ -164,7 +164,7 @@ init_esm_shims();
164
164
  // package.json
165
165
  var package_default = {
166
166
  name: "@kenkaiiii/gg-boss",
167
- version: "4.3.143",
167
+ version: "4.3.144",
168
168
  type: "module",
169
169
  description: "Orchestrator agent that drives multiple ggcoder sessions across projects from a single chat",
170
170
  license: "MIT",
@@ -2026,7 +2026,11 @@ function StreamingToolRow({ tool }) {
2026
2026
  function renderBossApp(opts) {
2027
2027
  const ref = { instance: null };
2028
2028
  const resetUI = () => {
2029
- ref.instance?.clear();
2029
+ const inst = ref.instance;
2030
+ if (!inst) return;
2031
+ process.stdout.write("\x1B[2J\x1B[3J\x1B[H");
2032
+ const log2 = inst.log;
2033
+ log2?.reset?.();
2030
2034
  };
2031
2035
  const instance = render_default(/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(BossApp, { boss: opts.boss, resetUI }), {
2032
2036
  // Disable Ink's built-in exit-on-Ctrl+C — we need our own double-press
package/dist/cli.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/cli.ts","../src/links.ts","../src/link-command.tsx","../src/discover.ts","../src/banner.tsx","../src/branding.ts","../package.json","../src/orchestrator-app.tsx","../../ggcoder/src/ui/components/index.ts","../../ggcoder/src/ui/components/DiffView.tsx","../../ggcoder/src/ui/components/Overlay.tsx","../../ggcoder/src/ui/components/SessionSelector.tsx","../../ggcoder/src/ui/components/SettingsSelector.tsx","../../ggcoder/src/ui/components/ThinkingIndicator.tsx","../src/boss-footer.tsx","../src/slash-commands.ts","../src/tool-formatters.ts","../src/colors.ts","../src/boss-phrases.ts","../src/boss-tasks-overlay.tsx","../src/radio-picker.tsx","../src/radio.ts","../src/auto-update.ts","../src/splash.tsx"],"sourcesContent":["#!/usr/bin/env node\nimport path from \"node:path\";\nimport chalk from \"chalk\";\nimport type { Provider } from \"@kenkaiiii/gg-ai\";\nimport { GGBoss } from \"./orchestrator.js\";\nimport type { ProjectSpec } from \"./types.js\";\nimport { loadLinks } from \"./links.js\";\nimport { runLinkCommand } from \"./link-command.js\";\nimport { COLORS, clearScreen } from \"./branding.js\";\nimport { renderBossApp } from \"./orchestrator-app.js\";\nimport { loadSettings } from \"./settings.js\";\nimport { showSplash } from \"./splash.js\";\nimport { initLogger, log } from \"./logger.js\";\nimport { VERSION } from \"./branding.js\";\nimport { checkAndAutoUpdate } from \"./auto-update.js\";\nimport { stopRadio } from \"./radio.js\";\n\ninterface CliArgs {\n /** Undefined when not passed on the CLI — settings file then defaults take over. */\n bossProvider?: Provider;\n bossModel?: string;\n workerProvider?: Provider;\n workerModel?: string;\n projects: ProjectSpec[];\n continueRecent?: boolean;\n resumeSessionId?: string;\n}\n\nfunction parseProjectSpec(raw: string): ProjectSpec {\n const eq = raw.indexOf(\"=\");\n if (eq > 0) {\n const name = raw.slice(0, eq);\n const cwd = path.resolve(raw.slice(eq + 1));\n return { name, cwd };\n }\n const cwd = path.resolve(raw);\n return { name: path.basename(cwd), cwd };\n}\n\nfunction parseArgs(argv: string[]): CliArgs {\n const args: CliArgs = {\n projects: [],\n };\n\n for (let i = 0; i < argv.length; i++) {\n const a = argv[i]!;\n if (a === \"--project\" || a === \"-p\") {\n const v = argv[++i];\n if (!v) throw new Error(\"--project requires a value\");\n args.projects.push(parseProjectSpec(v));\n } else if (a === \"--boss-model\") {\n const v = argv[++i];\n if (!v) throw new Error(\"--boss-model requires a value\");\n args.bossModel = v;\n } else if (a === \"--worker-model\") {\n const v = argv[++i];\n if (!v) throw new Error(\"--worker-model requires a value\");\n args.workerModel = v;\n } else if (a === \"--resume\") {\n const v = argv[++i];\n if (!v) throw new Error(\"--resume requires a session id\");\n args.resumeSessionId = v;\n } else if (a === \"--help\" || a === \"-h\") {\n printHelpAndExit();\n } else {\n throw new Error(`Unknown argument: ${a}`);\n }\n }\n\n return args;\n}\n\nfunction printHelpAndExit(): never {\n const c = (color: string, text: string): string => chalk.hex(color)(text);\n process.stdout.write(\n \"\\n\" +\n c(COLORS.primary, \"GG Boss\") +\n c(COLORS.textDim, \" — orchestrator that drives multiple ggcoder workers from one chat.\\n\\n\") +\n c(COLORS.text, \"Usage\\n\") +\n \" \" +\n c(COLORS.accent, \"ggboss\") +\n c(\n COLORS.textDim,\n \" start orchestrator using linked projects\\n\",\n ) +\n \" \" +\n c(COLORS.accent, \"ggboss link\") +\n c(COLORS.textDim, \" pick which projects to link (interactive)\\n\") +\n \" \" +\n c(COLORS.accent, \"ggboss continue\") +\n c(COLORS.textDim, \" resume the most recent boss session\\n\") +\n \" \" +\n c(COLORS.accent, \"ggboss --resume <id>\") +\n c(COLORS.textDim, \" resume a specific boss session\\n\") +\n \" \" +\n c(COLORS.accent, \"ggboss --project <spec> [...]\") +\n c(COLORS.textDim, \" override links with explicit project(s)\\n\\n\") +\n c(COLORS.text, \"Options\\n\") +\n \" \" +\n c(COLORS.primary, \"--project, -p <spec>\") +\n c(COLORS.textDim, ' project to manage. spec is \"cwd\" or \"name=cwd\". repeatable.\\n') +\n \" \" +\n c(COLORS.primary, \"--boss-model <id>\") +\n c(COLORS.textDim, \" model for the orchestrator (default: claude-opus-4-7)\\n\") +\n \" \" +\n c(COLORS.primary, \"--worker-model <id>\") +\n c(COLORS.textDim, \" model for workers (default: claude-sonnet-4-6)\\n\") +\n \" \" +\n c(COLORS.primary, \"--help, -h\") +\n c(COLORS.textDim, \" show this help\\n\\n\") +\n c(COLORS.textDim, \"Talk to the boss at the prompt. Press \") +\n c(COLORS.accent, \"Ctrl+C\") +\n c(COLORS.textDim, \" twice to exit.\\n\\n\"),\n );\n process.exit(0);\n}\n\nasync function runOrchestrator(args: CliArgs): Promise<void> {\n if (args.projects.length === 0) {\n const links = await loadLinks();\n if (links.projects.length === 0) {\n process.stderr.write(\n \"\\n\" +\n chalk.hex(COLORS.warning)(\"No linked projects.\") +\n chalk.hex(COLORS.textDim)(\" Run \") +\n chalk.hex(COLORS.accent)(\"ggboss link\") +\n chalk.hex(COLORS.textDim)(\" to choose, or pass \") +\n chalk.hex(COLORS.accent)(\"--project\") +\n chalk.hex(COLORS.textDim)(\".\\n\\n\"),\n );\n process.exit(1);\n }\n args.projects = links.projects.map((p) => ({ name: p.name, cwd: p.cwd }));\n }\n\n clearScreen();\n\n // Splash — Ink-rendered ASCII logo with shimmering gradient, shown while\n // the boss spins up its workers. dismiss() blocks until min-visible-time\n // has elapsed AND Ink has flushed the unmount, so the chat UI never\n // overlaps with the splash on screen.\n const splash = showSplash({\n caption: `Spinning up ${args.projects.length} worker${args.projects.length === 1 ? \"\" : \"s\"}…`,\n });\n\n // Resolve final boss/worker models: CLI flags > saved settings > defaults.\n // Settings persist user choices made via /model boss / /model workers across\n // restarts so the user doesn't have to re-pick every session.\n const settings = await loadSettings();\n const finalBossProvider = args.bossProvider ?? settings.bossProvider ?? \"anthropic\";\n const finalBossModel = args.bossModel ?? settings.bossModel ?? \"claude-opus-4-7\";\n const finalWorkerProvider = args.workerProvider ?? settings.workerProvider ?? \"anthropic\";\n const finalWorkerModel = args.workerModel ?? settings.workerModel ?? \"claude-sonnet-4-6\";\n\n // Open ~/.gg/boss/debug.log in append mode and stamp a startup line so\n // future tail/grep diagnoses have the full session context up front.\n initLogger({\n version: VERSION,\n bossProvider: finalBossProvider,\n bossModel: finalBossModel,\n bossThinking: settings.bossThinkingLevel,\n workerProvider: finalWorkerProvider,\n workerModel: finalWorkerModel,\n projectCount: args.projects.length,\n });\n log(\"INFO\", \"cli\", \"linked projects\", {\n projects: args.projects.map((p) => p.name).join(\",\"),\n });\n\n // Auto-update: instantly applies any pending install from the prior run\n // (background spawn, takes effect next launch) and schedules a fresh\n // registry check. Returns a one-liner if an install just kicked off so\n // we can surface it before the splash takes over.\n const updateMessage = checkAndAutoUpdate(VERSION);\n if (updateMessage) log(\"INFO\", \"auto_update\", updateMessage);\n\n const boss = new GGBoss({\n bossProvider: finalBossProvider,\n bossModel: finalBossModel,\n bossThinkingLevel: settings.bossThinkingLevel,\n workerProvider: finalWorkerProvider,\n workerModel: finalWorkerModel,\n projects: args.projects,\n continueRecent: args.continueRecent,\n resumeSessionId: args.resumeSessionId,\n });\n\n await boss.initialize();\n await splash.dismiss();\n\n clearScreen();\n\n const ink = renderBossApp({ boss });\n\n // Don't register process.on(\"SIGINT\") here. Ink puts stdin in raw mode, so\n // Ctrl+C is delivered as a byte (0x03) to InputArea — not as a process\n // signal. Registering SIGINT would race InputArea's onAbort and exit\n // immediately on the first press, breaking the double-press exit flow.\n\n // Run boss in background; await Ink unmount (triggered by useApp().exit()\n // in BossApp when the user double-presses Ctrl+C).\n const runPromise = boss.run();\n await ink.waitUntilExit();\n await boss.dispose();\n // Kill any in-flight radio stream before exiting — otherwise the detached\n // mpv/ffplay child keeps playing after the user closed gg-boss.\n stopRadio();\n await runPromise.catch(() => {});\n process.exit(0);\n}\n\nasync function main(): Promise<void> {\n const argv = process.argv.slice(2);\n\n if (argv[0] === \"link\") {\n await runLinkCommand();\n process.exit(0);\n }\n\n // `ggboss continue` is a subcommand alias for \"resume the most recent session\".\n // Accept any flags after `continue` as normal flag args.\n const isContinue = argv[0] === \"continue\";\n const args = parseArgs(isContinue ? argv.slice(1) : argv);\n if (isContinue) args.continueRecent = true;\n await runOrchestrator(args);\n}\n\nmain().catch((err) => {\n const message = err instanceof Error ? err.message : String(err);\n process.stderr.write(chalk.hex(COLORS.error)(`\\ngg-boss failed: ${message}\\n`));\n process.exit(1);\n});\n","import fs from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { getAppPaths } from \"@kenkaiiii/ggcoder\";\n\nexport interface LinkedProject {\n name: string;\n cwd: string;\n}\n\nexport interface LinksFile {\n projects: LinkedProject[];\n}\n\nexport function getLinksPath(): string {\n return path.join(getAppPaths().agentDir, \"boss\", \"links.json\");\n}\n\nexport async function loadLinks(): Promise<LinksFile> {\n try {\n const content = await fs.readFile(getLinksPath(), \"utf-8\");\n const parsed = JSON.parse(content) as Partial<LinksFile>;\n return { projects: parsed.projects ?? [] };\n } catch {\n return { projects: [] };\n }\n}\n\nexport async function saveLinks(links: LinksFile): Promise<void> {\n const p = getLinksPath();\n await fs.mkdir(path.dirname(p), { recursive: true, mode: 0o700 });\n await fs.writeFile(p, JSON.stringify(links, null, 2), \"utf-8\");\n}\n","import React, { useState } from \"react\";\nimport { Box, Text, useApp, useInput, render } from \"ink\";\nimport chalk from \"chalk\";\nimport { discoverProjects, type DiscoveredProject } from \"./discover.js\";\nimport { loadLinks, saveLinks, type LinkedProject } from \"./links.js\";\nimport { BossBanner } from \"./banner.js\";\nimport { COLORS, clearScreen } from \"./branding.js\";\n\ninterface LinkScreenProps {\n projects: DiscoveredProject[];\n initialSelected: Set<string>;\n onDone: (selectedPaths: string[], cancelled: boolean) => void;\n}\n\nconst VISIBLE_ROWS = 12;\n\nfunction LinkScreen({ projects, initialSelected, onDone }: LinkScreenProps): React.ReactElement {\n const [cursor, setCursor] = useState(0);\n const [selected, setSelected] = useState<Set<string>>(new Set(initialSelected));\n const [scrollOffset, setScrollOffset] = useState(0);\n\n const visible = projects.slice(scrollOffset, scrollOffset + VISIBLE_ROWS);\n\n useInput((input, key) => {\n // Ctrl+C — cancel cleanly.\n if (key.ctrl && input === \"c\") {\n onDone([], true);\n return;\n }\n\n if (projects.length === 0) {\n if (key.return || key.escape || input === \"q\") onDone([], true);\n return;\n }\n\n if (key.upArrow) {\n const next = Math.max(0, cursor - 1);\n setCursor(next);\n if (next < scrollOffset) setScrollOffset(next);\n } else if (key.downArrow) {\n const next = Math.min(projects.length - 1, cursor + 1);\n setCursor(next);\n if (next >= scrollOffset + VISIBLE_ROWS) setScrollOffset(next - VISIBLE_ROWS + 1);\n } else if (input === \" \") {\n const p = projects[cursor];\n if (!p) return;\n const nextSet = new Set(selected);\n if (nextSet.has(p.path)) nextSet.delete(p.path);\n else nextSet.add(p.path);\n setSelected(nextSet);\n } else if (input === \"a\") {\n const allSelected = projects.every((p) => selected.has(p.path));\n setSelected(allSelected ? new Set() : new Set(projects.map((p) => p.path)));\n } else if (key.return) {\n onDone(\n projects.filter((p) => selected.has(p.path)).map((p) => p.path),\n false,\n );\n } else if (key.escape || input === \"q\") {\n onDone([], true);\n }\n });\n\n const subtitle =\n projects.length === 0\n ? \"Link projects\"\n : `Link projects · ${projects.length} discovered · ${selected.size} selected`;\n const hint = \"↑↓ navigate · space toggle · a all · enter save · esc cancel\";\n\n if (projects.length === 0) {\n return (\n <Box flexDirection=\"column\" paddingX={2}>\n <BossBanner subtitle=\"Link projects\" hint=\"No projects yet\" />\n <Box flexDirection=\"column\" marginLeft={2}>\n <Text color={COLORS.textDim}>No ggcoder projects found in ~/.gg/sessions/.</Text>\n <Text color={COLORS.textDim}>\n Run ggcoder in a project at least once, then re-run{\" \"}\n <Text color={COLORS.accent}>ggboss link</Text>.\n </Text>\n <Box marginTop={1}>\n <Text color={COLORS.textDim}>Press any key to exit.</Text>\n </Box>\n </Box>\n </Box>\n );\n }\n\n const showingTop = scrollOffset > 0;\n const showingBottom = scrollOffset + VISIBLE_ROWS < projects.length;\n\n return (\n <Box flexDirection=\"column\" paddingX={2}>\n <BossBanner subtitle={subtitle} hint={hint} />\n <Box flexDirection=\"column\" marginLeft={2}>\n {showingTop && <Text color={COLORS.textDim}>{\" ↑ more above\"}</Text>}\n {visible.map((p, i) => {\n const realIndex = scrollOffset + i;\n const isCursor = realIndex === cursor;\n const isSelected = selected.has(p.path);\n const checkbox = isSelected ? \"[✓]\" : \"[ ]\";\n const arrow = isCursor ? \"❯\" : \" \";\n const nameColor = isCursor ? COLORS.primary : isSelected ? COLORS.success : COLORS.text;\n const checkboxColor = isSelected ? COLORS.success : COLORS.textDim;\n return (\n <Box key={p.path}>\n <Text color={COLORS.primary}>{arrow}</Text>\n <Text> </Text>\n <Text color={checkboxColor}>{checkbox}</Text>\n <Text> </Text>\n <Text color={nameColor} bold={isCursor}>\n {p.name}\n </Text>\n <Text color={COLORS.textDim}>{\" \"}</Text>\n <Text color={COLORS.textDim}>{p.lastActiveDisplay}</Text>\n </Box>\n );\n })}\n {showingBottom && <Text color={COLORS.textDim}>{\" ↓ more below\"}</Text>}\n </Box>\n </Box>\n );\n}\n\ninterface LinkAppProps {\n projects: DiscoveredProject[];\n initialSelected: Set<string>;\n resolve: (result: { selected: string[]; cancelled: boolean }) => void;\n}\n\nfunction LinkApp({ projects, initialSelected, resolve }: LinkAppProps): React.ReactElement {\n const { exit } = useApp();\n return (\n <LinkScreen\n projects={projects}\n initialSelected={initialSelected}\n onDone={(selected, cancelled) => {\n resolve({ selected, cancelled });\n exit();\n }}\n />\n );\n}\n\nexport async function runLinkCommand(): Promise<void> {\n const projects = await discoverProjects();\n const links = await loadLinks();\n const initialSelected = new Set(links.projects.map((p) => p.cwd));\n\n clearScreen();\n\n const result = await new Promise<{ selected: string[]; cancelled: boolean }>((resolve) => {\n const { waitUntilExit } = render(\n <LinkApp projects={projects} initialSelected={initialSelected} resolve={resolve} />,\n );\n void waitUntilExit();\n });\n\n if (result.cancelled) {\n process.stdout.write(chalk.hex(COLORS.textDim)(\"\\nCancelled. No changes saved.\\n\"));\n return;\n }\n\n const linked: LinkedProject[] = result.selected\n .map((path) => projects.find((p) => p.path === path))\n .filter((p): p is DiscoveredProject => Boolean(p))\n .map((p) => ({ name: p.name, cwd: p.path }));\n\n await saveLinks({ projects: linked });\n\n process.stdout.write(\"\\n\");\n if (linked.length === 0) {\n process.stdout.write(chalk.hex(COLORS.warning)(\"Cleared linked projects.\\n\"));\n } else {\n process.stdout.write(\n chalk.hex(COLORS.success)(\n `Linked ${linked.length} project${linked.length === 1 ? \"\" : \"s\"}:\\n`,\n ),\n );\n for (const p of linked) {\n process.stdout.write(\n \" \" + chalk.hex(COLORS.primary)(\"·\") + \" \" + chalk.hex(COLORS.text)(p.name) + \"\\n\",\n );\n }\n process.stdout.write(\"\\n\");\n process.stdout.write(\n chalk.hex(COLORS.textDim)(`Run `) +\n chalk.hex(COLORS.accent)(\"ggboss\") +\n chalk.hex(COLORS.textDim)(` to start the orchestrator.\\n`),\n );\n }\n}\n","import fs from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { getAppPaths } from \"@kenkaiiii/ggcoder\";\n\nexport interface DiscoveredProject {\n name: string;\n path: string;\n lastActiveMs: number;\n lastActiveDisplay: string;\n}\n\n/**\n * Scan ~/.gg/sessions/ and return projects sorted most-recent first.\n * Each session directory's name is the encoded cwd (slashes → underscores);\n * we decode it back and verify the directory still exists on disk.\n */\nexport async function discoverProjects(): Promise<DiscoveredProject[]> {\n const sessionsDir = getAppPaths().sessionsDir;\n let entries: string[];\n try {\n entries = await fs.readdir(sessionsDir);\n } catch {\n return [];\n }\n\n const results: DiscoveredProject[] = [];\n for (const entry of entries) {\n const dir = path.join(sessionsDir, entry);\n let stat;\n try {\n stat = await fs.stat(dir);\n } catch {\n continue;\n }\n if (!stat.isDirectory()) continue;\n\n let files: string[];\n try {\n files = await fs.readdir(dir);\n } catch {\n continue;\n }\n const sessionFiles = files.filter((f) => f.endsWith(\".jsonl\"));\n if (sessionFiles.length === 0) continue;\n\n let maxMtime = 0;\n for (const f of sessionFiles) {\n try {\n const s = await fs.stat(path.join(dir, f));\n if (s.mtimeMs > maxMtime) maxMtime = s.mtimeMs;\n } catch {\n // skip unreadable files\n }\n }\n\n const decoded = \"/\" + entry.replace(/_/g, \"/\");\n\n // Verify the decoded path still exists — drop dead entries from the list.\n try {\n const pathStat = await fs.stat(decoded);\n if (!pathStat.isDirectory()) continue;\n } catch {\n continue;\n }\n\n results.push({\n name: path.basename(decoded),\n path: decoded,\n lastActiveMs: maxMtime,\n lastActiveDisplay: formatRelativeTime(maxMtime),\n });\n }\n\n results.sort((a, b) => b.lastActiveMs - a.lastActiveMs);\n return results;\n}\n\nfunction formatRelativeTime(ms: number): string {\n if (ms === 0) return \"—\";\n const diff = Date.now() - ms;\n if (diff < 60_000) return \"just now\";\n const min = 60_000;\n const hour = 60 * min;\n const day = 24 * hour;\n const week = 7 * day;\n const month = 30 * day;\n if (diff < hour) return `${Math.floor(diff / min)}m ago`;\n if (diff < day) return `${Math.floor(diff / hour)}h ago`;\n if (diff < week) return `${Math.floor(diff / day)}d ago`;\n if (diff < month) return `${Math.floor(diff / week)}w ago`;\n return `${Math.floor(diff / month)}mo ago`;\n}\n","import React from \"react\";\nimport { Box, Text } from \"ink\";\nimport { AUTHOR, BRAND, COLORS, GRADIENT, LOGO_GAP, LOGO_LINES, VERSION } from \"./branding.js\";\n\ninterface BossBannerProps {\n /** Second line text (e.g. \"Link projects\", \"Orchestrator\"). */\n subtitle: string;\n /** Third line text (e.g. \"↑↓ navigate · enter save\"). */\n hint?: string;\n /**\n * If true, show the standard chat-mode shortcut row (Ctrl+T tasks). Mirrors\n * ggcoder's banner where the third row advertises ^T / ^S / ^P. Override\n * with `hint` for non-chat banners (link picker, task overlay).\n */\n showShortcuts?: boolean;\n}\n\n/** Ink banner — for use inside Ink-rendered screens. */\nexport function BossBanner({ subtitle, hint, showShortcuts }: BossBannerProps): React.ReactElement {\n return (\n <Box flexDirection=\"column\" marginTop={1} marginBottom={1}>\n <Box>\n <GradientText text={LOGO_LINES[0]!} />\n <Text>{LOGO_GAP}</Text>\n <Text color={COLORS.primary} bold>\n {BRAND}\n </Text>\n <Text color={COLORS.textDim}> v{VERSION}</Text>\n <Text color={COLORS.textDim}> · By </Text>\n <Text color={COLORS.text} bold>\n {AUTHOR}\n </Text>\n </Box>\n <Box>\n <GradientText text={LOGO_LINES[1]!} />\n <Text>{LOGO_GAP}</Text>\n <Text color={COLORS.accent}>{subtitle}</Text>\n </Box>\n <Box>\n <GradientText text={LOGO_LINES[2]!} />\n <Text>{LOGO_GAP}</Text>\n {showShortcuts ? (\n <Text>\n <Text color={COLORS.primary}>^T</Text>\n <Text color={COLORS.textDim}> tasks</Text>\n <Text color={COLORS.textDim}>{\" \"}</Text>\n <Text color={COLORS.primary}>Tab</Text>\n <Text color={COLORS.textDim}> scope</Text>\n <Text color={COLORS.textDim}>{\" \"}</Text>\n <Text color={COLORS.primary}>⇧Tab</Text>\n <Text color={COLORS.textDim}> thinking</Text>\n <Text color={COLORS.textDim}>{\" \"}</Text>\n <Text color={COLORS.primary}>ESC</Text>\n <Text color={COLORS.textDim}> interrupt</Text>\n </Text>\n ) : (\n <Text color={COLORS.textDim}>{hint ?? \"\"}</Text>\n )}\n </Box>\n </Box>\n );\n}\n\nfunction GradientText({ text }: { text: string }): React.ReactElement {\n const chars: React.ReactNode[] = [];\n let colorIdx = 0;\n for (let i = 0; i < text.length; i++) {\n const ch = text[i];\n if (ch === \" \") {\n chars.push(ch);\n } else {\n const color = GRADIENT[colorIdx % GRADIENT.length];\n chars.push(\n <Text key={i} color={color}>\n {ch}\n </Text>,\n );\n colorIdx++;\n }\n }\n return <Text>{chars}</Text>;\n}\n","// Pull version from package.json so banner + boot output stay in sync with\n// what npm sees — bumping package.json now updates the TUI automatically.\nimport pkg from \"../package.json\" with { type: \"json\" };\n\nexport const VERSION = pkg.version;\nexport const BRAND = \"GG Boss\";\nexport const AUTHOR = \"Ken Kai\";\n\nexport const LOGO_LINES: readonly string[] = [\" ▄▀▀▀ ▄▀▀▀\", \" █ ▀█ █ ▀█\", \" ▀▄▄▀ ▀▄▄▀\"];\n\nexport const LOGO_GAP = \" \";\n\n/**\n * GG Boss brand gradient — crimson → fuchsia. Deliberately distinct:\n * - gg-coder is cool blues/violets\n * - gg-editor is warm oranges/yellows\n * - gg-boss is fiery reds/pinks/magentas\n *\n * Palindromic 12-stop sequence so the banner gradient animates smoothly\n * (read forward, then back).\n */\nexport const GRADIENT: readonly string[] = [\n \"#dc2626\", // red-600\n \"#e11d48\", // rose-600\n \"#be185d\", // pink-700\n \"#a21caf\", // fuchsia-700\n \"#c026d3\", // fuchsia-600\n \"#d946ef\", // fuchsia-500\n \"#c026d3\", // fuchsia-600 (back)\n \"#a21caf\", // fuchsia-700 (back)\n \"#be185d\", // pink-700 (back)\n \"#e11d48\", // rose-600 (back)\n \"#dc2626\", // red-600 (back)\n \"#b91c1c\", // red-700 (slight darker tail)\n];\n\n/**\n * Pulse colors for the activity-indicator spinner. Tighter loop than GRADIENT\n * so the spinner pulses crisply through the brand palette.\n */\nexport const PULSE_COLORS: readonly string[] = [\n \"#dc2626\", // crimson\n \"#e11d48\", // rose\n \"#be185d\", // wine\n \"#a21caf\", // magenta\n \"#c026d3\", // fuchsia\n \"#a21caf\", // back\n \"#be185d\", // back\n \"#e11d48\", // back\n];\n\nexport const COLORS = {\n primary: \"#e11d48\", // crimson-rose — main brand color\n accent: \"#d946ef\", // fuchsia — secondary\n text: \"#e2e8f0\",\n textDim: \"#6b7280\",\n success: \"#4ade80\",\n warning: \"#fbbf24\",\n error: \"#f87171\",\n} as const;\n\n/** Clear the entire scrollback + visible screen and reset cursor to home. */\nexport function clearScreen(): void {\n process.stdout.write(\"\\x1b[2J\\x1b[3J\\x1b[H\");\n}\n","{\n \"name\": \"@kenkaiiii/gg-boss\",\n \"version\": \"4.3.143\",\n \"type\": \"module\",\n \"description\": \"Orchestrator agent that drives multiple ggcoder sessions across projects from a single chat\",\n \"license\": \"MIT\",\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"git+https://github.com/kenkaiiii/gg-framework.git\",\n \"directory\": \"packages/gg-boss\"\n },\n \"bin\": {\n \"ggboss\": \"./dist/cli.js\"\n },\n \"exports\": {\n \".\": {\n \"import\": \"./dist/index.js\",\n \"types\": \"./dist/index.d.ts\"\n }\n },\n \"files\": [\n \"dist\"\n ],\n \"scripts\": {\n \"build\": \"tsup && cp -R assets/. dist/ && chmod +x dist/cli.js\",\n \"check\": \"tsc --noEmit\",\n \"test\": \"vitest run\"\n },\n \"devDependencies\": {\n \"@kenkaiiii/gg-agent\": \"workspace:*\",\n \"@kenkaiiii/gg-ai\": \"workspace:*\",\n \"@kenkaiiii/ggcoder\": \"workspace:*\",\n \"@types/node\": \"^25.6.0\",\n \"@types/react\": \"^19.2.14\",\n \"chalk\": \"^5.6.2\",\n \"ink\": \"^7.0.2\",\n \"react\": \"^19.2.5\",\n \"tsup\": \"^8.5.1\",\n \"typescript\": \"^6.0.3\",\n \"vitest\": \"^4.1.4\",\n \"zod\": \"^4.4.3\"\n },\n \"publishConfig\": {\n \"access\": \"public\"\n }\n}\n","import React, { useCallback, useEffect, useMemo, useRef, useState } from \"react\";\nimport { Box, Static, Text, render, useApp, useInput, useStdout } from \"ink\";\nimport { ThemeContext, loadTheme, useTheme } from \"@kenkaiiii/ggcoder/ui/theme\";\nimport {\n ActivityIndicator,\n AnimationProvider,\n AssistantMessage,\n CompactionDone,\n CompactionSpinner,\n InputArea,\n MessageResponse,\n ModelSelector,\n StreamingArea,\n ToolExecution,\n ToolUseLoader,\n UserMessage,\n useAnimationActive,\n useAnimationTick,\n} from \"@kenkaiiii/ggcoder/ui\";\nimport { useDoublePress } from \"@kenkaiiii/ggcoder/ui/hooks/double-press\";\nimport type { Provider } from \"@kenkaiiii/gg-ai\";\nimport { TerminalSizeProvider, useTerminalSize } from \"@kenkaiiii/ggcoder/ui/hooks/terminal-size\";\nimport { BossFooter } from \"./boss-footer.js\";\nimport { BossBanner } from \"./banner.js\";\nimport { bossStore, useBossState } from \"./boss-store.js\";\nimport type {\n AssistantItem,\n HistoryItem,\n StreamingTool,\n StreamingTurn,\n ToolItem,\n WorkerEventItem,\n WorkerErrorItem,\n WorkerView,\n} from \"./boss-store.js\";\nimport { BOSS_SLASH_COMMANDS, canonicalName, parseSlash, buildHelpText } from \"./slash-commands.js\";\nimport { bossToolFormatters } from \"./tool-formatters.js\";\nimport { projectColor } from \"./colors.js\";\nimport { BOSS_PHRASES } from \"./boss-phrases.js\";\nimport { COLORS, PULSE_COLORS as BOSS_PULSE_COLORS } from \"./branding.js\";\nimport { BossTasksOverlay } from \"./boss-tasks-overlay.js\";\nimport type { GGBoss } from \"./orchestrator.js\";\nimport { VERSION } from \"./branding.js\";\nimport { RadioPicker } from \"./radio-picker.js\";\nimport { getCurrentStation, playRadio, stopRadio, RADIO_STATIONS } from \"./radio.js\";\nimport {\n getPendingUpdate,\n startPeriodicUpdateCheck,\n stopPeriodicUpdateCheck,\n} from \"./auto-update.js\";\n\ninterface BannerRow {\n kind: \"banner\";\n id: string;\n}\ntype StaticRow = BannerRow | HistoryItem;\n\ninterface BossAppProps {\n boss: GGBoss;\n /**\n * Called from /clear to reset Ink's internal log-update tracking. Without\n * this, the simple `\\x1b[2J\\x1b[3J\\x1b[H + setStaticKey` dance leaves\n * log-update with stale prevLineCount + cursor offsets, which then\n * accumulate position errors on subsequent frames — exactly what we saw\n * as \"input pushed to top, new chats disappear\" after /clear.\n *\n * The cli wires this to `instance.clear()` from Ink's render() return\n * value: it writes ANSI clear AND zeroes log-update's frame state.\n */\n resetUI?: () => void;\n}\n\nexport function BossApp(props: BossAppProps): React.ReactElement {\n const theme = loadTheme(\"dark\");\n return (\n <TerminalSizeProvider>\n <ThemeContext.Provider value={theme}>\n <AnimationProvider>\n <BossAppInner {...props} />\n </AnimationProvider>\n </ThemeContext.Provider>\n </TerminalSizeProvider>\n );\n}\n\nfunction BossAppInner({ boss, resetUI }: BossAppProps): React.ReactElement {\n const state = useBossState();\n const { exit } = useApp();\n const { stdout } = useStdout();\n const { resizeKey, columns } = useTerminalSize();\n const runStartRef = useRef<number | null>(null);\n runStartRef.current = state.runStartMs;\n // Live char count of the current streaming text — drives ActivityIndicator's\n // smooth token-counter animation between turn_end events.\n const charCountRef = useRef<number>(0);\n charCountRef.current = state.streaming?.text.length ?? 0;\n // Accumulated real input tokens across completed turns — used alongside\n // charCountRef so the counter interpolates smoothly between hard updates.\n const realTokensAccumRef = useRef<number>(0);\n realTokensAccumRef.current = state.bossInputTokens;\n // Track the most recent user message so the activity bar's contextual phrase\n // selection has something to riff on (when not using BOSS_PHRASES override).\n const [lastUserMessage, setLastUserMessage] = useState<string>(\"\");\n const [overlay, setOverlay] = useState<\"model-boss\" | \"model-workers\" | \"tasks\" | \"radio\" | null>(\n null,\n );\n // Track the currently-playing station id so the picker can mark it with *\n // and so we have a reactive value for any future \"now playing\" indicator.\n // Seeded from the radio module's module-level state — usually null on\n // launch but resilient to a hot-restart of the React tree.\n const [currentRadio, setCurrentRadio] = useState<string | null>(() => getCurrentStation());\n // Bumped on /clear so <Static> remounts and re-emits its (now banner-only)\n // items into a freshly ANSI-wiped terminal. Mirrors ggcoder's pattern in\n // App.tsx — without the bump, Static's internal emit-set still thinks\n // every old chat row is \"already rendered\" and won't restore them.\n const [staticKey, setStaticKey] = useState(0);\n\n // Auto-update indicator: true when a newer version of @kenkaiiii/gg-boss\n // is on disk waiting for the next restart. Seeded synchronously from the\n // state file (so we show the indicator immediately if a previous session\n // queued one) and bumped to true by the periodic check below if a fresh\n // version drops mid-session.\n const [updatePending, setUpdatePending] = useState<boolean>(\n () => getPendingUpdate(VERSION) !== null,\n );\n\n // Periodic in-session check — pings npm every hour while the session is\n // alive. If a newer version arrives, we set updatePending so the worker\n // bar shows the \"✨ Update ready · restart to apply\" hint, AND drop a\n // friendly info row into chat so the user sees the news immediately.\n useEffect(() => {\n startPeriodicUpdateCheck(VERSION, (msg) => {\n bossStore.appendInfo(msg, \"info\");\n setUpdatePending(true);\n });\n return () => stopPeriodicUpdateCheck();\n }, []);\n\n // Terminal title — dynamically reflects worker activity so the user can\n // glance at the tab/window from another app and see how many workers are\n // still running. OSC 0 sets both window and tab title in most modern\n // terminals (Ghostty, Terminal.app, iTerm2, Kitty).\n //\n // States:\n // N workers running \"● 5 workers running · GG Boss\"\n // 1 worker running \"● 1 worker running · GG Boss\"\n // boss thinking only \"● GG Boss\"\n // idle \"GG Boss\"\n const workersRunning = state.workers.filter((w) => w.status === \"working\").length;\n const titlePrevRef = useRef(\"\");\n useEffect(() => {\n if (!stdout) return;\n let title: string;\n if (workersRunning > 0) {\n const label = `${workersRunning} worker${workersRunning === 1 ? \"\" : \"s\"} running`;\n title = `● ${label} · GG Boss`;\n } else if (state.phase === \"working\") {\n title = \"● GG Boss\";\n } else {\n title = \"GG Boss\";\n }\n if (title !== titlePrevRef.current) {\n titlePrevRef.current = title;\n stdout.write(`\\x1b]0;${title}\\x1b\\\\`);\n }\n }, [stdout, workersRunning, state.phase]);\n useEffect(() => {\n return () => {\n stdout?.write(`\\x1b]0;GG Boss\\x1b\\\\`);\n };\n }, [stdout]);\n\n const staticItems: StaticRow[] = useMemo(\n () => [{ kind: \"banner\", id: \"banner\" }, ...state.history],\n [state.history],\n );\n\n /**\n * No screen clears, no Static remounts. Just toggle React state.\n *\n * Banner is emitted ONCE on initial mount (Static's natural behavior — items\n * by id are emitted exactly once per Static instance lifetime). It lives in\n * scrollback forever after that, never re-emitted. So duplicate banners are\n * structurally impossible.\n *\n * The remaining concern is Ink's log-update cursor math when the live area\n * shrinks (tasks pane → chat chrome). log-update only clears within the\n * previous frame's footprint at the bottom of the viewport — it cannot\n * reach into scrollback. So banner + history in scrollback stay intact.\n */\n const openOverlay = useCallback(\n (next: \"tasks\" | \"model-boss\" | \"model-workers\" | \"radio\"): void => {\n setOverlay(next);\n },\n [],\n );\n\n const closeOverlay = useCallback((): void => {\n setOverlay(null);\n }, []);\n void stdout;\n\n // ggcoder's double-press pattern: 800ms window. First press shows\n // \"Press Ctrl+C again to exit\" in the footer; second within 800ms exits.\n const handleDoubleExit = useDoublePress(\n (pending) => bossStore.setExitPending(pending),\n () => exit(),\n );\n\n // Two-phase flush — see boss-store.ts for the rationale. Phase 1 (orchestrator\n // pushes into pendingFlush, live area shrinks) already happened; phase 2 here\n // commits to history on the next render so Ink doesn't clip long responses.\n useEffect(() => {\n if (state.pendingFlush.length > 0) {\n bossStore.commitPendingFlush();\n }\n }, [state.flushGeneration, state.pendingFlush.length]);\n\n // ── App-level keyboard ──────────────────────────────────\n // ESC: abort current boss call when working (InputArea handles otherwise).\n // Ctrl+T: toggle the Tasks overlay (matches ggcoder's keybind).\n useInput((input, key) => {\n if (key.ctrl && input === \"t\") {\n if (overlay === \"tasks\") closeOverlay();\n else openOverlay(\"tasks\");\n return;\n }\n if (key.escape && state.phase === \"working\") {\n boss.abort();\n }\n });\n\n const handleSlashCommand = async (value: string): Promise<boolean> => {\n const parsed = parseSlash(value);\n if (!parsed) return false;\n const name = canonicalName(parsed.name);\n if (!name) {\n bossStore.appendInfo(`Unknown command: /${parsed.name}`, \"warning\");\n return true;\n }\n switch (name) {\n case \"help\":\n bossStore.appendUser(value);\n // Render help via an assistant block so Markdown formatting + dot prefix.\n bossStore.appendInfo(buildHelpText(), \"info\");\n return true;\n case \"clear\":\n // resetUI() calls Ink's `instance.clear()` which (a) writes the\n // ANSI screen+scrollback clear and (b) zeroes log-update's internal\n // prevLineCount/cursor state. The second part is critical — without\n // it, every subsequent render drifts the cursor up by an\n // accumulating offset, manifesting as \"input keeps pushing to top\n // and new chats disappear\". Bare `\\x1b[...J` writes don't fix this\n // because log-update's tracking lives in JS, not in the terminal.\n resetUI?.();\n bossStore.clearHistory();\n await boss.resetConversation();\n setStaticKey((k) => k + 1);\n bossStore.appendInfo(\"Session cleared.\", \"info\");\n return true;\n case \"model-boss\":\n openOverlay(\"model-boss\");\n return true;\n case \"model-workers\":\n openOverlay(\"model-workers\");\n return true;\n case \"compact\":\n bossStore.appendUser(value);\n await boss.manualCompact();\n return true;\n case \"radio\":\n openOverlay(\"radio\");\n return true;\n case \"quit\":\n exit();\n return true;\n }\n return false;\n };\n\n const handleModelSelect = (value: string): void => {\n const colon = value.indexOf(\":\");\n if (colon < 0) {\n closeOverlay();\n return;\n }\n const provider = value.slice(0, colon) as Provider;\n const model = value.slice(colon + 1);\n if (overlay === \"model-boss\") {\n void boss.switchBossModel(provider, model);\n } else if (overlay === \"model-workers\") {\n void boss.switchWorkerModel(provider, model);\n }\n closeOverlay();\n };\n\n const handleSubmit = (value: string): void => {\n const trimmed = value.trim();\n if (!trimmed) return;\n if (trimmed.startsWith(\"/\") && !trimmed.startsWith(\"//\")) {\n void handleSlashCommand(trimmed);\n return;\n }\n // Show the user's literal text in chat history.\n bossStore.appendUser(trimmed);\n setLastUserMessage(trimmed);\n // Inject the scope pill into the message the boss actually sees, so the\n // user doesn't have to write \"for the yaatuber project, …\" every prompt.\n const scoped = scopePrefix(state.scope) + trimmed;\n boss.enqueueUserMessage(scoped);\n };\n\n const handleAbort = (): void => {\n // Ctrl+C while boss is running → single-press abort (matches ggcoder).\n if (state.phase === \"working\") {\n boss.abort();\n return;\n }\n // Boss is idle → double-press to exit, with footer pending message.\n handleDoubleExit();\n };\n\n return (\n <Box flexDirection=\"column\" width={columns}>\n {/* Static is mounted ONCE for the lifetime of the app and never remounts\n on overlay toggles. resizeKey still triggers a remount on terminal\n resize (which is necessary so the layout recomputes) — that's the\n only legitimate reason to drop and re-emit the scrollback. */}\n <Static key={`${resizeKey}-${staticKey}`} items={staticItems} style={{ width: \"100%\" }}>\n {(item) => (\n <Box key={item.id} flexDirection=\"column\" paddingRight={1}>\n <StaticRowView row={item} />\n </Box>\n )}\n </Static>\n\n {overlay === \"tasks\" ? (\n <BossTasksOverlay boss={boss} workers={state.workers} onClose={closeOverlay} />\n ) : (\n <>\n {state.streaming && (\n <StreamingTurnView turn={state.streaming} isRunning={state.phase === \"working\"} />\n )}\n {state.phase === \"working\" && (\n <Box marginTop={1}>\n <ActivityIndicator\n phase={state.activityPhase}\n elapsedMs={state.runStartMs ? Date.now() - state.runStartMs : 0}\n runStartRef={runStartRef as React.RefObject<number>}\n thinkingMs={state.streaming?.thinkingMs ?? 0}\n isThinking={state.activityPhase === \"thinking\"}\n tokenEstimate={state.bossInputTokens}\n charCountRef={charCountRef}\n realTokensAccumRef={realTokensAccumRef}\n userMessage={lastUserMessage}\n activeToolNames={(state.streaming?.tools ?? [])\n .filter((t) => t.status === \"running\")\n .map((t) => t.name)}\n retryInfo={state.retryInfo}\n phrases={BOSS_PHRASES}\n pulseColors={BOSS_PULSE_COLORS}\n />\n </Box>\n )}\n {state.compaction?.state === \"running\" && <CompactionSpinner />}\n {state.compaction?.state === \"done\" && (\n <CompactionDone\n originalCount={state.compaction.originalCount}\n newCount={state.compaction.newCount}\n tokensBefore={state.compaction.tokensBefore}\n tokensAfter={state.compaction.tokensAfter}\n />\n )}\n\n <InputArea\n onSubmit={handleSubmit}\n onAbort={handleAbort}\n disabled={state.phase === \"working\"}\n isActive={!overlay}\n cwd={process.cwd()}\n commands={BOSS_SLASH_COMMANDS}\n scopeBadge={<ScopePill scope={state.scope} />}\n // Mouse-tracking escape sequences cause Ghostty to emit phantom\n // pastes of the system clipboard during high-frequency UI updates\n // (workers running, shimmer animating). gg-boss's UI updates a lot,\n // so we forfeit click-to-position-cursor in the input to keep\n // the clipboard from leaking into the chat field.\n disableMouseTracking\n onTab={() => bossStore.cycleScope()}\n onShiftTab={() => {\n // Don't appendInfo — Static lives outside the overlay branch, so\n // any history row added here renders in scrollback above the\n // tasks pane and looks like it's inside it. The footer already\n // shows live \"Thinking on/off\" — that's the indicator.\n const next = state.bossThinkingLevel ? undefined : \"medium\";\n void boss.setBossThinking(next);\n }}\n />\n\n {overlay === \"model-boss\" || overlay === \"model-workers\" ? (\n <ModelSelector\n onSelect={handleModelSelect}\n onCancel={closeOverlay}\n loggedInProviders={state.loggedInProviders}\n currentModel={overlay === \"model-boss\" ? state.bossModel : state.workerModel}\n currentProvider={overlay === \"model-boss\" ? state.bossProvider : state.workerProvider}\n />\n ) : overlay === \"radio\" ? (\n <RadioPicker\n currentStationId={currentRadio}\n onCancel={closeOverlay}\n onSelect={(value) => {\n if (value === \"off\") {\n stopRadio();\n setCurrentRadio(null);\n bossStore.appendInfo(\"Radio off.\", \"info\");\n } else {\n const result = playRadio(value);\n if (result.ok) {\n setCurrentRadio(value);\n const station = RADIO_STATIONS.find((s) => s.id === value);\n bossStore.appendInfo(`Now playing: ${station?.name ?? value}`, \"info\");\n } else {\n bossStore.appendInfo(result.error ?? \"Radio failed to start.\", \"warning\");\n }\n }\n closeOverlay();\n }}\n />\n ) : (\n <>\n <BossFooter\n bossModel={state.bossModel}\n workerModel={state.workerModel}\n tokensIn={state.bossInputTokens}\n exitPending={state.exitPending}\n bossThinkingLevel={state.bossThinkingLevel}\n updatePending={updatePending}\n currentRadioStationId={currentRadio}\n />\n {!state.exitPending && (\n <WorkerStatusBar\n workers={state.workers}\n pendingMessages={state.pendingUserMessages}\n />\n )}\n </>\n )}\n </>\n )}\n </Box>\n );\n}\n\n// ── Scope pill (gg-boss specific) ──────────────────────────\n\nfunction ScopePill({ scope }: { scope: string }): React.ReactElement {\n const theme = useTheme();\n const isAll = scope === \"all\";\n // \"All\" → boss accent (fuchsia) so multi-project mode wears the brand.\n // Specific project → its stable project color so the pill matches its\n // appearances elsewhere in the TUI.\n const bg = isAll ? COLORS.accent : projectColor(scope);\n const label = isAll ? \"All\" : scope;\n // Black text reads cleanly on every color in the palette — the project hues\n // are deliberately light/saturated, which is unreadable with white on top.\n return (\n <Text>\n <Text color={theme.textDim}>Project </Text>\n <Text color=\"black\" backgroundColor={bg} bold>\n {` ${label} `}\n </Text>\n <Text color={theme.textDim}>\n {\" \"}\n <Text color={theme.primary}>Tab</Text>\n {\" to switch\"}\n </Text>\n </Text>\n );\n}\n\n/**\n * Prepend the active scope to the user's message before it reaches the boss.\n * Boss's system prompt teaches it to interpret these prefixes.\n */\nfunction scopePrefix(scope: string): string {\n if (scope === \"all\") return \"[scope:all] \";\n return `[scope:${scope}] `;\n}\n\n// ── Worker status row (gg-boss specific) ───────────────────\n\nconst SHIMMER_WIDTH = 3;\n\nfunction formatElapsed(ms: number): string {\n const total = Math.floor(ms / 1000);\n const m = Math.floor(total / 60);\n const s = total % 60;\n return `${m}:${s.toString().padStart(2, \"0\")}`;\n}\n\n/**\n * Mount this when (and only when) the shimmer needs to tick. AnimationProvider\n * stops the global timer when its subscriber count hits zero, so unmounting\n * this sentinel halts the 10Hz re-render loop while every worker is idle.\n */\nfunction AnimationActiveSentinel(): null {\n useAnimationActive();\n return null;\n}\n\n/**\n * Same shimmer pattern used by ggcoder's ActivityIndicator phrases — a bright\n * highlight band of width `SHIMMER_WIDTH` slides across the text while the\n * rest stays dim. Driven by the global animation tick.\n */\nfunction ShimmerName({\n name,\n color,\n tick,\n}: {\n name: string;\n color: string;\n tick: number;\n}): React.ReactElement {\n // Cycle covers the name length plus a SHIMMER_WIDTH-wide pre-roll/post-roll\n // so the bright band fully exits one side before re-entering the other.\n const cycle = name.length + SHIMMER_WIDTH * 2;\n const shimmerPos = (tick % cycle) - SHIMMER_WIDTH;\n return (\n <Text>\n {name.split(\"\").map((ch, i) => {\n const isBright = Math.abs(i - shimmerPos) <= SHIMMER_WIDTH;\n return (\n <Text key={i} color={color} bold={isBright} dimColor={!isBright}>\n {ch}\n </Text>\n );\n })}\n </Text>\n );\n}\n\nfunction WorkerStatusBar({\n workers,\n pendingMessages,\n}: {\n workers: WorkerView[];\n pendingMessages: number;\n}): React.ReactElement | null {\n const theme = useTheme();\n // Active-first layout: only working and errored workers get named slots.\n // Idle workers collapse into a single \"+N idle\" trailer so the bar scales\n // cleanly from 5 projects to 50. With 4 of 50 projects active, you see\n // four shimmering names + \"+46 idle\" instead of fifty repeated glyphs.\n const working = workers.filter((w) => w.status === \"working\");\n const errored = workers.filter((w) => w.status === \"error\");\n const idleCount = workers.length - working.length - errored.length;\n const anyWorking = working.length > 0;\n // Passive tick consumer — when no Sentinel is mounted (no working worker),\n // the global timer is paused and the tick value stops changing, so this\n // component doesn't re-render at 10Hz when everything is idle.\n const tick = useAnimationTick();\n const now = Date.now();\n\n if (workers.length === 0) return null;\n // Render order: working (shimmer + timer) → errored (✗ + name) → idle\n // count (dim \"N idle\"). The shimmer + project hue already announce\n // \"active\" — no need for a leading ● dot. The errored ✗ stays because\n // colour alone isn't enough to call out a stuck worker. The idle slot\n // keeps the ○ as a glyph-only quantifier (\"○ 17\"). Separator: thin\n // vertical bar, matching the footer's style.\n const slots: React.ReactElement[] = [];\n for (const w of working) {\n const projectHue = projectColor(w.name);\n const elapsed = w.workStartedAt ? formatElapsed(now - w.workStartedAt) : null;\n slots.push(\n <React.Fragment key={`w-${w.name}`}>\n <ShimmerName name={w.name} color={projectHue} tick={tick} />\n {elapsed && <Text color={theme.textDim}> {elapsed}</Text>}\n </React.Fragment>,\n );\n }\n for (const w of errored) {\n slots.push(\n <React.Fragment key={`e-${w.name}`}>\n <Text color={theme.error}>✗ {w.name}</Text>\n </React.Fragment>,\n );\n }\n if (idleCount > 0) {\n slots.push(\n <React.Fragment key=\"idle\">\n <Text color={theme.textDim}>○ {idleCount} idle</Text>\n </React.Fragment>,\n );\n }\n return (\n <Box paddingX={1}>\n {anyWorking && <AnimationActiveSentinel />}\n {slots.map((slot, i) => (\n <React.Fragment key={i}>\n {i > 0 && <Text color={theme.border}>{\" │ \"}</Text>}\n {slot}\n </React.Fragment>\n ))}\n {pendingMessages > 0 && (\n <>\n <Text color={theme.textDim}>{\" \"}</Text>\n <Text color={theme.warning}>\n {pendingMessages} message{pendingMessages === 1 ? \"\" : \"s\"} queued\n </Text>\n </>\n )}\n </Box>\n );\n}\n\n// ── Row dispatch ───────────────────────────────────────────\n\nfunction StaticRowView({ row }: { row: StaticRow }): React.ReactElement | null {\n if (row.kind === \"banner\") {\n return (\n <Box paddingX={1}>\n <BossBanner subtitle=\"Orchestrator\" showShortcuts />\n </Box>\n );\n }\n if (row.kind === \"user\") return <UserMessage text={row.text} />;\n if (row.kind === \"assistant\") return <AssistantRow item={row} />;\n if (row.kind === \"tool\") return <ToolHistoryRow item={row} />;\n if (row.kind === \"worker_event\") return <WorkerEventRow item={row} />;\n if (row.kind === \"worker_error\") return <WorkerErrorRow item={row} />;\n if (row.kind === \"info\") return <InfoRow text={row.text} level={row.level ?? \"info\"} />;\n if (row.kind === \"task_dispatch\") return <TaskDispatchRow tasks={row.tasks} />;\n return null;\n}\n\nfunction TaskDispatchRow({\n tasks,\n}: {\n tasks: { project: string; title: string }[];\n}): React.ReactElement {\n const theme = useTheme();\n const count = tasks.length;\n return (\n <Box flexDirection=\"column\" paddingX={1} marginTop={1}>\n <Text>\n <Text color={COLORS.primary} bold>\n {\"⏺ \"}\n </Text>\n <Text color={theme.text} bold>\n Running {count} task{count === 1 ? \"\" : \"s\"}\n {\":\"}\n </Text>\n </Text>\n {tasks.map((t, i) => (\n <Text key={`${t.project}-${i}`}>\n <Text color={theme.textDim}>{\" • \"}</Text>\n <Text color={projectColor(t.project)} bold>\n {t.project}\n </Text>\n <Text color={theme.textDim}>{\": \"}</Text>\n <Text color={theme.text}>{t.title}</Text>\n </Text>\n ))}\n </Box>\n );\n}\n\n/**\n * Auto-highlight common keyboard shortcuts in any boss-written prose by\n * wrapping them in backticks before passing to the Markdown renderer (which\n * styles inline code with a distinctive color/background). Catches things\n * like Ctrl+T, Shift+Tab, Cmd+K, Esc, F-keys, arrow-key combos. The boss may\n * already wrap them itself — these regexes deliberately skip text that's\n * already inside backticks (or fenced blocks) so we don't double-wrap.\n */\nconst SHORTCUT_PATTERNS: RegExp[] = [\n // Modifier+Key combos: Ctrl+T, Shift+Tab, Cmd+K, Ctrl+Shift+P, Ctrl+C\n /\\b(?:Ctrl|Cmd|Alt|Option|Opt|Shift|Meta|Win|Super)(?:\\s*\\+\\s*(?:Ctrl|Cmd|Alt|Option|Opt|Shift|Meta|Win|Super))*\\s*\\+\\s*(?:Tab|Enter|Esc|Escape|Space|Backspace|Delete|Del|Home|End|PageUp|PageDown|Up|Down|Left|Right|F[1-9]|F1[0-2]|[A-Z0-9]|\\/|\\?|\\.|,|;|=|-)\\b/g,\n // Bare named keys (only when surrounded by clear key context)\n /\\b(?:Ctrl-[A-Z]|F[1-9]|F1[0-2])\\b/g,\n];\n\nfunction highlightShortcuts(text: string): string {\n if (!text) return text;\n // Mask code spans + fenced blocks so we don't try to re-wrap shortcuts that\n // are already in backtick territory. The sentinel uses a private-use unicode\n // codepoint so it can't realistically collide with anything the boss writes.\n const SENTINEL = \"\";\n const masks: string[] = [];\n let masked = text.replace(/```[\\s\\S]*?```|`[^`]+`/g, (m) => {\n const idx = masks.push(m) - 1;\n return `${SENTINEL}${idx}${SENTINEL}`;\n });\n for (const re of SHORTCUT_PATTERNS) {\n masked = masked.replace(re, (m) => `\\`${m}\\``);\n }\n return masked.replace(\n new RegExp(`${SENTINEL}(\\\\d+)${SENTINEL}`, \"g\"),\n (_, i) => masks[Number(i)]!,\n );\n}\n\nfunction AssistantRow({ item }: { item: AssistantItem }): React.ReactElement {\n return (\n <AssistantMessage\n text={highlightShortcuts(item.text)}\n thinking={item.thinking}\n thinkingMs={item.thinkingMs}\n />\n );\n}\n\nfunction ToolHistoryRow({ item }: { item: ToolItem }): React.ReactElement {\n return (\n <ToolExecution\n status=\"done\"\n name={item.name}\n args={item.args}\n result={item.result}\n isError={item.isError}\n details={item.details}\n formatters={bossToolFormatters}\n />\n );\n}\n\n// ── Worker rows (gg-boss specific) ─────────────────────────\n\ntype WorkerStatusGrade = \"DONE\" | \"UNVERIFIED\" | \"PARTIAL\" | \"BLOCKED\" | \"INFO\";\n\n/**\n * Pull the `Status:` line out of a worker's final text (the brief in\n * tools.ts asks every worker to end with one of: DONE | UNVERIFIED |\n * PARTIAL | BLOCKED | INFO). Returns null if the line is missing or invalid.\n */\nfunction parseStatusGrade(text: string): WorkerStatusGrade | null {\n // Use the LAST occurrence of \"Status: X\" (some workers explain status\n // mid-text and re-emit it in the trailer). Also accept anything after the\n // grade word — workers occasionally write \"Status: INFO — trailing comment\"\n // which the previous end-of-line anchor would have rejected.\n const matches = [...text.matchAll(/^\\s*Status:\\s*(DONE|UNVERIFIED|PARTIAL|BLOCKED|INFO)\\b/gim)];\n const last = matches[matches.length - 1];\n if (!last) return null;\n return last[1]!.toUpperCase() as WorkerStatusGrade;\n}\n\ninterface WorkerTrailer {\n changed?: string;\n skipped?: string;\n verified?: string;\n notes?: string;\n}\n\n/**\n * Pull the structured fields out of the worker's reply trailer (appended by\n * WORKER_PROMPT_BRIEF). Each field is captured up to (but not including) the\n * next field marker or end-of-text.\n */\nfunction parseWorkerTrailer(text: string): WorkerTrailer {\n const out: WorkerTrailer = {};\n const grab = (label: string): string | undefined => {\n // Match \"Label: value\" up to the next \"Label:\" line or end. Multi-line.\n const re = new RegExp(\n `^\\\\s*${label}:\\\\s*([\\\\s\\\\S]*?)(?=^\\\\s*(?:Changed|Skipped|Verified|Notes|Status):|$)`,\n \"im\",\n );\n const m = re.exec(text);\n if (!m) return undefined;\n const v = m[1]!\n .replace(/```[\\s\\S]*?```/g, \"[code]\")\n .replace(/`([^`]+)`/g, \"$1\")\n .replace(/\\s+/g, \" \")\n .trim();\n return v.length > 0 ? v : undefined;\n };\n out.changed = grab(\"Changed\");\n out.skipped = grab(\"Skipped\");\n out.verified = grab(\"Verified\");\n out.notes = grab(\"Notes\");\n return out;\n}\n\nfunction clip(text: string, maxLen: number): string {\n return text.length <= maxLen ? text : text.slice(0, Math.max(1, maxLen - 1)) + \"…\";\n}\n\n/**\n * Build a one-line summary from the trailer. Prefers the substantive fields\n * (Changed, Verified, Notes) that actually tell the user what happened — not\n * the worker's preamble like \"I'll start by detecting...\". Falls back to\n * first-sentence-of-preamble only when the trailer is empty (non-conforming\n * worker reply).\n */\nfunction summarizeFinalText(text: string, maxLen: number): string {\n if (!text) return \"\";\n const trailer = parseWorkerTrailer(text);\n const parts: string[] = [];\n if (trailer.changed) parts.push(`Changed: ${trailer.changed}`);\n if (trailer.verified) parts.push(`Verified: ${trailer.verified}`);\n if (trailer.skipped) parts.push(`Skipped: ${trailer.skipped}`);\n if (trailer.notes) parts.push(`Notes: ${trailer.notes}`);\n if (parts.length > 0) return clip(parts.join(\" · \"), maxLen);\n\n // No trailer — fall back to the first sentence of the response body.\n const beforeSummary = text.split(/^Changed:|^Skipped:|^Verified:|^Notes:|^Status:/im)[0];\n const stripped = beforeSummary\n .replace(/```[\\s\\S]*?```/g, \"[code]\")\n .replace(/`([^`]+)`/g, \"$1\")\n .replace(/\\*\\*([^*]+)\\*\\*/g, \"$1\")\n .replace(/\\*([^*]+)\\*/g, \"$1\")\n .replace(/^\\s*[-*]\\s+/gm, \"\")\n .replace(/^#+\\s+/gm, \"\")\n .replace(/\\s+/g, \" \")\n .trim();\n if (!stripped) return \"\";\n const firstSentence = stripped.match(/^[^.!?\\n]+[.!?]/);\n return clip(firstSentence ? firstSentence[0] : stripped, maxLen);\n}\n\nfunction statusGradeColor(\n grade: WorkerStatusGrade | null,\n theme: ReturnType<typeof useTheme>,\n): string {\n switch (grade) {\n case \"DONE\":\n return theme.success;\n case \"UNVERIFIED\":\n case \"PARTIAL\":\n return theme.warning;\n case \"BLOCKED\":\n return theme.error;\n case \"INFO\":\n return theme.textDim;\n default:\n return theme.textDim;\n }\n}\n\nfunction WorkerEventRow({ item }: { item: WorkerEventItem }): React.ReactElement {\n const theme = useTheme();\n const { columns } = useTerminalSize();\n const failedCount = item.toolsUsed.filter((t) => !t.ok).length;\n const total = item.toolsUsed.length;\n const grade = parseStatusGrade(item.finalText);\n // Loader status: prefer the worker's self-reported grade. Fall back to\n // tool-error count if the worker omitted Status (older runs / non-conforming).\n const loaderStatus =\n grade === \"BLOCKED\" || failedCount > 0\n ? \"error\"\n : grade === \"UNVERIFIED\" || grade === \"PARTIAL\"\n ? \"queued\"\n : \"done\";\n // Errors override the project hue with red; otherwise the project gets its\n // stable color so successive turns from the same worker visually cluster.\n const headerColor = loaderStatus === \"error\" ? theme.toolError : projectColor(item.project);\n const toolSummary =\n total === 0\n ? \"no tools\"\n : failedCount > 0\n ? `${total} tools (${failedCount} failed)`\n : `${total} tool${total === 1 ? \"\" : \"s\"}`;\n // MessageResponse uses 6 chars for \" ⎿ \" gutter; reserve a few more for\n // safety. Each trailer field renders on its own line so users can scan\n // Changed / Verified / Notes independently rather than a single squished line.\n const fieldMaxLen = Math.max(20, columns - 14);\n const trailer = parseWorkerTrailer(item.finalText);\n const hasTrailer = !!(trailer.changed || trailer.skipped || trailer.verified || trailer.notes);\n const fallbackSummary = hasTrailer ? \"\" : summarizeFinalText(item.finalText, fieldMaxLen);\n return (\n <Box flexDirection=\"column\" marginTop={1}>\n <Box flexDirection=\"row\">\n <ToolUseLoader status={loaderStatus} />\n <Box flexGrow={1}>\n <Text wrap=\"wrap\">\n <Text color={headerColor} bold>\n {item.project}\n </Text>\n <Text color={theme.text}>{` turn ${item.turnIndex}`}</Text>\n <Text color={theme.textDim}>{` · ${toolSummary}`}</Text>\n {grade && (\n <>\n <Text color={theme.textDim}>{\" · \"}</Text>\n <Text color={statusGradeColor(grade, theme)} bold>\n {grade}\n </Text>\n </>\n )}\n </Text>\n </Box>\n </Box>\n {hasTrailer ? (\n <>\n {trailer.changed && (\n <TrailerLine label=\"Changed\" value={trailer.changed} maxLen={fieldMaxLen} />\n )}\n {trailer.verified && (\n <TrailerLine\n label=\"Verified\"\n value={trailer.verified}\n maxLen={fieldMaxLen}\n labelColor={theme.success}\n />\n )}\n {trailer.skipped && (\n <TrailerLine\n label=\"Skipped\"\n value={trailer.skipped}\n maxLen={fieldMaxLen}\n labelColor={theme.warning}\n />\n )}\n {trailer.notes && (\n <TrailerLine label=\"Notes\" value={trailer.notes} maxLen={fieldMaxLen} />\n )}\n </>\n ) : (\n fallbackSummary && (\n <MessageResponse>\n <Text color={theme.textDim} wrap=\"truncate\">\n {fallbackSummary}\n </Text>\n </MessageResponse>\n )\n )}\n </Box>\n );\n}\n\nfunction TrailerLine({\n label,\n value,\n maxLen,\n labelColor,\n}: {\n label: string;\n value: string;\n maxLen: number;\n labelColor?: string;\n}): React.ReactElement {\n const theme = useTheme();\n return (\n <MessageResponse>\n <Text wrap=\"truncate\">\n <Text color={labelColor ?? theme.textDim} bold>\n {label}:\n </Text>\n <Text color={theme.text}>{` ${clip(value, maxLen - label.length - 2)}`}</Text>\n </Text>\n </MessageResponse>\n );\n}\n\nfunction WorkerErrorRow({ item }: { item: WorkerErrorItem }): React.ReactElement {\n const theme = useTheme();\n return (\n <Box flexDirection=\"column\" marginTop={1}>\n <Box flexDirection=\"row\">\n <ToolUseLoader status=\"error\" />\n <Box flexGrow={1}>\n <Text wrap=\"wrap\">\n <Text color={theme.toolError} bold>\n {item.project}\n </Text>\n <Text color={theme.textDim}>{\" worker error\"}</Text>\n </Text>\n </Box>\n </Box>\n <MessageResponse>\n <Text color={theme.error} wrap=\"wrap\">\n {item.message}\n </Text>\n </MessageResponse>\n </Box>\n );\n}\n\nfunction InfoRow({\n text,\n level,\n}: {\n text: string;\n level: \"info\" | \"warning\" | \"error\";\n}): React.ReactElement {\n // info → render through AssistantMessage so it gets the dot + Markdown.\n if (level === \"info\") return <AssistantMessage text={text} />;\n // warning / error → match the ToolUseLoader chrome so the row reads as a\n // first-class event (consistent with worker errors / failed tool calls)\n // rather than bare colored text.\n const theme = useTheme();\n const color = level === \"error\" ? theme.error : theme.warning;\n return (\n <Box marginTop={1} flexDirection=\"row\">\n <ToolUseLoader status={level === \"error\" ? \"error\" : \"queued\"} />\n <Box flexGrow={1}>\n <Text color={color} wrap=\"wrap\">\n {text}\n </Text>\n </Box>\n </Box>\n );\n}\n\n// ── Streaming (live) ───────────────────────────────────────\n\nfunction StreamingTurnView({\n turn,\n isRunning,\n}: {\n turn: StreamingTurn;\n isRunning: boolean;\n}): React.ReactElement {\n return (\n <Box flexDirection=\"column\">\n <StreamingArea\n isRunning={isRunning}\n streamingText={turn.text}\n streamingThinking={turn.thinking}\n thinkingMs={turn.thinkingMs}\n />\n {turn.tools.map((t) => (\n <StreamingToolRow key={t.toolCallId} tool={t} />\n ))}\n </Box>\n );\n}\n\nfunction StreamingToolRow({ tool }: { tool: StreamingTool }): React.ReactElement {\n if (tool.status === \"running\") {\n return (\n <ToolExecution\n status=\"running\"\n name={tool.name}\n args={tool.args}\n formatters={bossToolFormatters}\n />\n );\n }\n return (\n <ToolExecution\n status=\"done\"\n name={tool.name}\n args={tool.args}\n result={tool.result ?? \"\"}\n isError={tool.status === \"error\"}\n details={tool.details}\n formatters={bossToolFormatters}\n />\n );\n}\n\n// ── Renderer ───────────────────────────────────────────────\n\nexport interface RenderBossAppOptions {\n boss: GGBoss;\n}\n\nexport function renderBossApp(opts: RenderBossAppOptions): {\n waitUntilExit: () => Promise<void>;\n unmount: () => void;\n} {\n // We need a forward reference: BossApp's resetUI prop wants to call\n // instance.clear(), but `instance` doesn't exist until after render() is\n // invoked. Closing over a holder lets the prop see the instance once it's\n // assigned, without restructuring the whole BossApp tree.\n const ref: { instance: ReturnType<typeof render> | null } = { instance: null };\n const resetUI = (): void => {\n ref.instance?.clear();\n };\n const instance = render(<BossApp boss={opts.boss} resetUI={resetUI} />, {\n // Disable Ink's built-in exit-on-Ctrl+C — we need our own double-press\n // handler in BossApp to drive the \"Press Ctrl+C again to exit\" footer\n // message. With this flag true (the default), Ink kills the process on\n // the very first Ctrl+C and InputArea's onAbort never runs.\n exitOnCtrlC: false,\n });\n ref.instance = instance;\n return {\n waitUntilExit: async () => {\n await instance.waitUntilExit();\n },\n unmount: () => instance.unmount(),\n };\n}\n","export {\n AnimationProvider,\n useAnimationTick,\n useAnimationActive,\n deriveFrame,\n} from \"./AnimationContext.js\";\nexport { Spinner } from \"./Spinner.js\";\nexport { UserMessage } from \"./UserMessage.js\";\nexport { AssistantMessage } from \"./AssistantMessage.js\";\nexport { DiffView } from \"./DiffView.js\";\nexport { ToolExecution, type ToolExecutionFormatters } from \"./ToolExecution.js\";\nexport { ToolUseLoader } from \"./ToolUseLoader.js\";\nexport { MessageResponse } from \"./MessageResponse.js\";\nexport { Footer } from \"./Footer.js\";\nexport { StreamingArea } from \"./StreamingArea.js\";\nexport { InputArea } from \"./InputArea.js\";\nexport { Overlay } from \"./Overlay.js\";\nexport { SelectList } from \"./SelectList.js\";\nexport { ModelSelector } from \"./ModelSelector.js\";\nexport { SessionSelector } from \"./SessionSelector.js\";\nexport { SettingsSelector } from \"./SettingsSelector.js\";\nexport { Markdown } from \"./Markdown.js\";\nexport { ThinkingBlock } from \"./ThinkingBlock.js\";\nexport { ThinkingIndicator } from \"./ThinkingIndicator.js\";\nexport { ActivityIndicator } from \"./ActivityIndicator.js\";\nexport { SlashCommandMenu, type SlashCommandInfo } from \"./SlashCommandMenu.js\";\nexport { Banner } from \"./Banner.js\";\nexport { CompactionSpinner, CompactionDone } from \"./CompactionNotice.js\";\nexport type { ActivityPhase, RetryInfo } from \"../hooks/useAgentLoop.js\";\n","import React from \"react\";\nimport { Text, Box } from \"ink\";\nimport { useTheme } from \"../theme/theme.js\";\n\nconst MAX_DISPLAY_LINES = 20;\n\nexport function DiffView({ diff }: { diff: string }) {\n const theme = useTheme();\n const lines = diff.split(\"\\n\");\n const truncated = lines.length > MAX_DISPLAY_LINES;\n const displayLines = truncated ? lines.slice(0, MAX_DISPLAY_LINES) : lines;\n\n return (\n <Box flexDirection=\"column\" marginLeft={2}>\n {displayLines.map((line, i) => {\n let color = theme.diffContext;\n if (line.startsWith(\"+\")) color = theme.diffAdded;\n else if (line.startsWith(\"-\")) color = theme.diffRemoved;\n\n return (\n <Text key={i} color={color}>\n {line}\n </Text>\n );\n })}\n {truncated && (\n <Text color={theme.textDim}>... ({lines.length - MAX_DISPLAY_LINES} more lines)</Text>\n )}\n </Box>\n );\n}\n","import React from \"react\";\nimport { Box, Text } from \"ink\";\nimport { useTheme } from \"../theme/theme.js\";\n\ninterface OverlayProps {\n title: string;\n children: React.ReactNode;\n}\n\nexport function Overlay({ title, children }: OverlayProps) {\n const theme = useTheme();\n\n return (\n <Box flexDirection=\"column\" borderStyle=\"round\" borderColor={theme.border} paddingX={1}>\n <Box marginBottom={1}>\n <Text color={theme.primary} bold>\n {title}\n </Text>\n </Box>\n {children}\n </Box>\n );\n}\n","import React from \"react\";\nimport type { SessionInfo } from \"../../core/session-manager.js\";\nimport { Overlay } from \"./Overlay.js\";\nimport { SelectList } from \"./SelectList.js\";\n\ninterface SessionSelectorProps {\n sessions: SessionInfo[];\n onSelect: (sessionPath: string) => void;\n onCancel: () => void;\n}\n\nexport function SessionSelector({ sessions, onSelect, onCancel }: SessionSelectorProps) {\n const items = sessions.map((s) => ({\n label: `${s.id.slice(0, 8)} — ${s.timestamp}`,\n value: s.path,\n description: `${s.messageCount} messages`,\n }));\n\n return (\n <Overlay title=\"Select Session\">\n <SelectList items={items} onSelect={onSelect} onCancel={onCancel} />\n </Overlay>\n );\n}\n","import React from \"react\";\nimport type { Settings } from \"../../core/settings-manager.js\";\nimport { Overlay } from \"./Overlay.js\";\nimport { SelectList } from \"./SelectList.js\";\n\ninterface SettingsSelectorProps {\n settings: Settings;\n onSelect: (key: string) => void;\n onCancel: () => void;\n}\n\nexport function SettingsSelector({ settings, onSelect, onCancel }: SettingsSelectorProps) {\n const items = Object.entries(settings).map(([key, value]) => ({\n label: key,\n value: key,\n description: String(value),\n }));\n\n return (\n <Overlay title=\"Settings\">\n <SelectList items={items} onSelect={onSelect} onCancel={onCancel} />\n </Overlay>\n );\n}\n","import React, { useMemo } from \"react\";\nimport { Text, Box } from \"ink\";\nimport { useTheme } from \"../theme/theme.js\";\n\nimport { SPINNER_FRAMES, SPINNER_INTERVAL } from \"../spinner-frames.js\";\nimport { useAnimationTick, useAnimationActive, deriveFrame } from \"./AnimationContext.js\";\n\n// ── Color pulse cycle ─────────────────────────────────────\n\nconst PULSE_COLORS = [\n \"#60a5fa\", // blue\n \"#818cf8\", // indigo\n \"#a78bfa\", // violet\n \"#818cf8\", // indigo (back)\n \"#60a5fa\", // blue (back)\n \"#38bdf8\", // sky\n \"#60a5fa\", // blue (back)\n];\nconst PULSE_INTERVAL = 400;\n\n// ── Ellipsis animation ────────────────────────────────────\n\nconst ELLIPSIS_FRAMES = [\"\", \".\", \"..\", \"...\"];\nconst ELLIPSIS_INTERVAL = 500;\n\n// ── Phrase rotation ───────────────────────────────────────\n\nconst PHRASE_INTERVAL = 3000;\n\ninterface PhraseSet {\n keywords: RegExp;\n phrases: string[];\n}\n\nconst CONTEXTUAL_PHRASES: PhraseSet[] = [\n {\n keywords: /\\b(bug|fix|error|issue|broken|crash|fail|wrong)\\b/i,\n phrases: [\n \"Investigating\",\n \"Diagnosing\",\n \"Tracing the issue\",\n \"Hunting the bug\",\n \"Analyzing the problem\",\n \"Narrowing it down\",\n ],\n },\n {\n keywords: /\\b(refactor|clean|improve|optimize|simplify|restructure)\\b/i,\n phrases: [\n \"Studying the code\",\n \"Planning improvements\",\n \"Mapping dependencies\",\n \"Finding patterns\",\n \"Designing the approach\",\n ],\n },\n {\n keywords: /\\b(test|spec|coverage|assert|expect|describe|it\\()\\b/i,\n phrases: [\n \"Designing tests\",\n \"Thinking about edge cases\",\n \"Planning test coverage\",\n \"Considering scenarios\",\n ],\n },\n {\n keywords: /\\b(build|deploy|ci|cd|pipeline|docker|config)\\b/i,\n phrases: [\n \"Checking the config\",\n \"Analyzing the pipeline\",\n \"Working through setup\",\n \"Reviewing the build\",\n ],\n },\n {\n keywords: /\\b(style|css|ui|layout|design|color|theme|display|render)\\b/i,\n phrases: [\n \"Visualizing the layout\",\n \"Crafting the design\",\n \"Considering the aesthetics\",\n \"Sketching it out\",\n \"Polishing the pixels\",\n ],\n },\n {\n keywords: /\\b(add|create|new|implement|feature|make|build)\\b/i,\n phrases: [\n \"Architecting\",\n \"Drafting the approach\",\n \"Planning the implementation\",\n \"Mapping it out\",\n \"Designing the solution\",\n ],\n },\n {\n keywords: /\\b(explain|how|why|what|understand|describe)\\b/i,\n phrases: [\n \"Reading through the code\",\n \"Connecting the dots\",\n \"Building understanding\",\n \"Tracing the logic\",\n \"Piecing it together\",\n ],\n },\n];\n\nconst GENERAL_PHRASES = [\n \"Thinking\",\n \"Reasoning\",\n \"Processing\",\n \"Mulling it over\",\n \"Working on it\",\n \"Contemplating\",\n \"Figuring it out\",\n \"Crunching\",\n \"Assembling thoughts\",\n \"Cooking up a plan\",\n \"Brewing ideas\",\n \"Spinning up neurons\",\n \"Loading wisdom\",\n \"Parsing the universe\",\n \"Channeling clarity\",\n];\n\nfunction selectPhrases(userMessage: string): string[] {\n for (const set of CONTEXTUAL_PHRASES) {\n if (set.keywords.test(userMessage)) {\n return [...set.phrases, ...GENERAL_PHRASES.slice(0, 3)];\n }\n }\n return GENERAL_PHRASES;\n}\n\nfunction shuffleArray<T>(arr: T[]): T[] {\n const shuffled = [...arr];\n for (let i = shuffled.length - 1; i > 0; i--) {\n const j = Math.floor(Math.random() * (i + 1));\n [shuffled[i], shuffled[j]] = [shuffled[j], shuffled[i]];\n }\n return shuffled;\n}\n\n// ── Component ─────────────────────────────────────────────\n\ninterface ThinkingIndicatorProps {\n userMessage?: string;\n}\n\nexport function ThinkingIndicator({ userMessage = \"\" }: ThinkingIndicatorProps) {\n const theme = useTheme();\n useAnimationActive();\n const tick = useAnimationTick();\n\n // Derive all animation frames from the single global tick\n const spinnerFrame = deriveFrame(tick, SPINNER_INTERVAL, SPINNER_FRAMES.length);\n const colorFrame = deriveFrame(tick, PULSE_INTERVAL, PULSE_COLORS.length);\n const ellipsisFrame = deriveFrame(tick, ELLIPSIS_INTERVAL, ELLIPSIS_FRAMES.length);\n\n // Phrase rotation — pick phrases based on user message, shuffle, rotate\n const phrases = useMemo(() => shuffleArray(selectPhrases(userMessage)), [userMessage]);\n const phraseIndex = deriveFrame(tick, PHRASE_INTERVAL, phrases.length);\n\n const spinnerColor = PULSE_COLORS[colorFrame];\n const phrase = phrases[phraseIndex];\n const ellipsis = ELLIPSIS_FRAMES[ellipsisFrame];\n // Pad ellipsis to prevent text from shifting\n const paddedEllipsis = ellipsis + \" \".repeat(3 - ellipsis.length);\n\n return (\n <Box>\n <Text color={spinnerColor} bold>\n {SPINNER_FRAMES[spinnerFrame]}{\" \"}\n </Text>\n <Text color={spinnerColor} bold>\n {phrase}\n </Text>\n <Text color={theme.textDim}>{paddedEllipsis}</Text>\n </Box>\n );\n}\n","import React from \"react\";\nimport { Text, Box } from \"ink\";\nimport { useTheme } from \"@kenkaiiii/ggcoder/ui/theme\";\nimport { useTerminalSize } from \"@kenkaiiii/ggcoder/ui/hooks/terminal-size\";\nimport { getContextWindow } from \"@kenkaiiii/ggcoder\";\nimport { COLORS } from \"./branding.js\";\n\nconst PARTIAL_BLOCKS = [\" \", \"▏\", \"▎\", \"▍\", \"▌\", \"▋\", \"▊\", \"▉\", \"█\"];\nconst LIGHT_SHADE = \"░\";\n\nconst SHORT_MODELS: Record<string, string> = {\n \"claude-opus-4-7\": \"Opus\",\n \"claude-sonnet-4-6\": \"Sonnet\",\n \"claude-haiku-4-5\": \"Haiku\",\n \"claude-haiku-4-5-20251001\": \"Haiku\",\n \"gpt-5.5\": \"GPT-5.5\",\n \"gpt-5.5-pro\": \"GPT-5.5 Pro\",\n \"gpt-5.4\": \"GPT-5.4\",\n \"gpt-5.4-mini\": \"GPT-5.4 Mini\",\n \"gpt-5.3-codex\": \"GPT-5.3 Codex\",\n};\n\nfunction shortModel(model: string): string {\n return SHORT_MODELS[model] ?? model;\n}\n\nfunction getContextPercent(model: string, tokensIn: number): number {\n const limit = getContextWindow(model);\n if (!limit || tokensIn === 0) return 0;\n return Math.round((tokensIn / limit) * 100);\n}\n\ninterface BossFooterProps {\n bossModel: string;\n workerModel: string;\n /** Total input tokens of the boss's last turn — drives the context bar. */\n tokensIn: number;\n exitPending: boolean;\n /** Boss extended-thinking level. Falsy when thinking is off. */\n bossThinkingLevel?: string;\n /** Auto-updater has installed a newer @kenkaiiii/gg-boss in the background.\n * Show a \"restart to apply\" hint at the end of the footer row. */\n updatePending?: boolean;\n /** id of the currently-playing radio station (from RADIO_STATIONS), or null\n * when the radio is off. Renders as `♪ <short name>` between thinking and\n * the update notice. */\n currentRadioStationId?: string | null;\n}\n\n// Short, recognisable station names for the footer slot. The picker shows the\n// full name; here we just want enough to tell stations apart without eating\n// column budget. Order matters: more-frequent first because pattern matching\n// in the renderer is cheap-but-still-O(n).\nconst SHORT_RADIO: Record<string, string> = {\n \"somafm-groove-salad\": \"Groove Salad\",\n \"somafm-drone-zone\": \"Drone Zone\",\n \"radio-paradise\": \"Radio Paradise\",\n \"george-fm\": \"George FM\",\n};\n\n/**\n * Footer for gg-boss that mirrors ggcoder's Footer visual style — context bar\n * with partial-block precision, percent, then BOTH models displayed in the\n * same bold/coloured treatment so neither feels secondary.\n */\nexport function BossFooter({\n bossModel,\n workerModel,\n tokensIn,\n exitPending,\n bossThinkingLevel,\n updatePending,\n currentRadioStationId,\n}: BossFooterProps): React.ReactElement {\n const theme = useTheme();\n const { columns } = useTerminalSize();\n\n if (exitPending) {\n return (\n <Box paddingX={1}>\n <Text color={theme.warning}>Press Ctrl+C again to exit</Text>\n </Box>\n );\n }\n\n const contextPct = getContextPercent(bossModel, tokensIn);\n const contextColor =\n contextPct >= 80 ? theme.error : contextPct >= 50 ? theme.warning : theme.success;\n\n const sep = <Text color={theme.border}>{\" │ \"}</Text>;\n\n // Context bar — same partial-block precision as ggcoder's Footer.\n const barWidth = 8;\n const fillFloat = Math.min((contextPct / 100) * barWidth, barWidth);\n const barChars: React.ReactElement[] = [];\n for (let i = 0; i < barWidth; i++) {\n const cellFill = Math.max(0, Math.min(1, fillFloat - i));\n const eighths = Math.round(cellFill * 8);\n if (eighths === 8) {\n barChars.push(\n <Text key={i} color={contextColor}>\n {PARTIAL_BLOCKS[8]}\n </Text>,\n );\n } else if (eighths > 0) {\n barChars.push(\n <Text key={i} color={contextColor}>\n {PARTIAL_BLOCKS[eighths]}\n </Text>,\n );\n } else {\n barChars.push(\n <Text key={i} color={theme.textDim}>\n {LIGHT_SHADE}\n </Text>,\n );\n }\n }\n\n // Priority-drop layout: when terminal is narrower than the full footer\n // would need, we shed lower-priority chrome to keep the row from wrapping.\n // Ranked highest-to-lowest priority:\n // 1. context bar + % — always visible (essential)\n // 2. update notice — actionable; user needs to know\n // 3. radio — visible state of an audio process they started\n // 4. boss/worker model names — frequent reference, but stable\n // 5. thinking indicator — least chatty, easiest to hide first\n // 6. \"boss \"/\"workers \" text labels — pure decoration\n //\n // Approximate per-section widths (with separator \" │ \"):\n // bar+% = ~12, model = ~5+name+3 sep, thinking = ~14, radio ≈ ♪+name+3,\n // update = ~30. We compute and degrade in stages.\n const radioName = currentRadioStationId\n ? (SHORT_RADIO[currentRadioStationId] ?? currentRadioStationId)\n : null;\n const bossM = shortModel(bossModel);\n const wkrM = shortModel(workerModel);\n\n // Rough char estimate; padding=2, separators are \" │ \" (3 each).\n const estFull =\n 2 +\n 12 + // bar + \" 99%\"\n 3 +\n 5 +\n bossM.length + // \" │ boss <model>\"\n 3 +\n 8 +\n wkrM.length + // \" │ workers <model>\"\n 3 +\n 12 + // \" │ Thinking off\"\n (radioName ? 3 + 2 + radioName.length : 0) + // \" │ ♪ Name\"\n (updatePending ? 3 + 28 : 0); // \" │ Update ready. Restart GG Boss.\"\n\n const dropLabels = estFull > columns; // stage 1: kill \"boss \"/\"workers \" words\n const dropThinking = estFull > columns + 14; // stage 2: kill thinking indicator\n const useShortUpdate = updatePending && estFull > columns + 6; // stage 3: shrink the update notice\n\n return (\n <Box paddingX={1} width={columns}>\n <Box flexGrow={1} />\n <Box flexShrink={0}>\n <Text>{barChars}</Text>\n <Text color={contextColor}> {contextPct}%</Text>\n {sep}\n {!dropLabels && <Text color={theme.textDim}>boss </Text>}\n <Text color={COLORS.primary} bold>\n {bossM}\n </Text>\n {sep}\n {!dropLabels && <Text color={theme.textDim}>workers </Text>}\n <Text color={COLORS.accent} bold>\n {wkrM}\n </Text>\n {!dropThinking && (\n <>\n {sep}\n <Text color={bossThinkingLevel ? theme.accent : theme.textDim}>\n {bossThinkingLevel ? \"Thinking on\" : \"Thinking off\"}\n </Text>\n </>\n )}\n {radioName && (\n <>\n {sep}\n <Text color={theme.secondary ?? theme.accent}>♪ {radioName}</Text>\n </>\n )}\n {updatePending && (\n <>\n {sep}\n <Text color={theme.success} bold wrap=\"truncate\">\n {useShortUpdate ? \"Update ready\" : \"Update ready. Restart GG Boss.\"}\n </Text>\n </>\n )}\n </Box>\n </Box>\n );\n}\n","import type { SlashCommandInfo } from \"@kenkaiiii/ggcoder/ui\";\n\n/**\n * Slash commands the boss CLI recognizes. Shape matches ggcoder's\n * SlashCommandInfo so the existing SlashCommandMenu in InputArea renders them.\n *\n * The actual handlers live in BossApp's handleSubmit — we just declare the\n * surface here so the menu is in one place.\n */\nexport const BOSS_SLASH_COMMANDS: SlashCommandInfo[] = [\n { name: \"help\", aliases: [\"?\"], description: \"Show available commands\" },\n { name: \"model-boss\", aliases: [], description: \"Switch the orchestrator's model\" },\n { name: \"model-workers\", aliases: [], description: \"Switch every worker's model\" },\n { name: \"compact\", aliases: [], description: \"Compact the boss's context now\" },\n { name: \"clear\", aliases: [], description: \"Clear chat history and terminal\" },\n { name: \"radio\", aliases: [], description: \"Stream a free internet radio station\" },\n { name: \"quit\", aliases: [\"q\", \"exit\"], description: \"Exit gg-boss\" },\n];\n\nexport function isSlashCommand(value: string): boolean {\n return value.startsWith(\"/\") && !value.startsWith(\"//\");\n}\n\nexport interface ParsedSlashCommand {\n name: string;\n args: string;\n}\n\nexport function parseSlash(value: string): ParsedSlashCommand | null {\n if (!isSlashCommand(value)) return null;\n const rest = value.slice(1).trim();\n if (!rest) return null;\n const space = rest.indexOf(\" \");\n if (space === -1) return { name: rest.toLowerCase(), args: \"\" };\n return { name: rest.slice(0, space).toLowerCase(), args: rest.slice(space + 1).trim() };\n}\n\n/** Resolve aliases to the canonical command name. */\nexport function canonicalName(name: string): string | null {\n for (const cmd of BOSS_SLASH_COMMANDS) {\n if (cmd.name === name) return cmd.name;\n if (cmd.aliases.includes(name)) return cmd.name;\n }\n return null;\n}\n\nexport function buildHelpText(): string {\n const lines: string[] = [\"**gg-boss commands**\", \"\"];\n for (const cmd of BOSS_SLASH_COMMANDS) {\n const aliases =\n cmd.aliases.length > 0 ? ` (${cmd.aliases.map((a) => \"/\" + a).join(\", \")})` : \"\";\n lines.push(`- \\`/${cmd.name}\\`${aliases} — ${cmd.description}`);\n }\n lines.push(\"\");\n lines.push(\"**Global keybindings**\");\n lines.push(\"- `Ctrl+T` — open the Tasks pane\");\n lines.push(\"- `Tab` — switch project scope (All / per-project pill in the input)\");\n lines.push(\"- `Shift+Tab` — toggle the boss's extended thinking on/off\");\n lines.push(\"- `Esc` — interrupt the boss while it's running\");\n lines.push(\"- `Ctrl+C` (twice) — exit\");\n lines.push(\"\");\n lines.push(\"**Inside the Tasks pane (Ctrl+T)**\");\n lines.push(\"- `↑` / `↓` (or `k` / `j`) — navigate tasks\");\n lines.push(\"- `r` — run all pending and blocked tasks across idle workers\");\n lines.push(\"- `d` — delete the selected task\");\n lines.push(\"- `Esc` — close the Tasks pane\");\n lines.push(\"\");\n lines.push(\"**Inside model pickers (`/model-boss`, `/model-workers`)**\");\n lines.push(\"- `↑` / `↓` — navigate models\");\n lines.push(\"- `Enter` — select\");\n lines.push(\"- `Esc` — cancel\");\n lines.push(\"\");\n lines.push(\"**Radio** (`/radio`)\");\n lines.push(\"- Pick a station to stream while you work, or select `Off` to stop.\");\n lines.push(\"- Requires `mpv` (recommended), `ffplay`, `mpg123`, or `vlc/cvlc` installed.\");\n lines.push(\"\");\n lines.push(\"**Input area**\");\n lines.push(\"- `↑` / `↓` — recall previous prompts (when input is empty)\");\n lines.push(\"- `Enter` — send · `Shift+Enter` — newline\");\n lines.push(\"- `/` — open the slash-command menu (Tab / arrows to pick, Enter to insert)\");\n return lines.join(\"\\n\");\n}\n","import type { ToolExecutionFormatters } from \"@kenkaiiii/ggcoder/ui\";\nimport { projectColor } from \"./colors.js\";\n\nfunction truncate(s: string, max: number): string {\n if (max <= 1) return \"…\";\n return s.length > max ? s.slice(0, max - 1) + \"…\" : s;\n}\n\n/**\n * Compute how many chars of the prompt-worker message detail can fit on a\n * single line of the current terminal. Header chrome ≈ \"⏺ Prompt Worker(<proj>\n * · …) <inline>\" — we subtract the fixed pieces so the message gets whatever\n * room remains.\n */\nfunction promptWorkerDetailLen(project: string): number {\n const cols = process.stdout.columns ?? 80;\n // Fixed overhead estimate: dot(2) + label \"Prompt Worker\"(13) + \"(\"(1)\n // + project + \" · \"(3) + \")\"(1) + \" \"(1) + \" dispatched\"(11) + safety(6).\n const fixed = 2 + 13 + 1 + project.length + 3 + 1 + 1 + 11 + 6;\n return Math.max(20, cols - fixed);\n}\n\n/**\n * Custom label / detail / inline-summary rendering for the boss's own tools.\n * Falls through to ggcoder's defaults for anything else.\n */\nexport const bossToolFormatters: ToolExecutionFormatters = {\n formatLabel(name) {\n switch (name) {\n case \"list_workers\":\n return \"List Workers\";\n case \"get_worker_status\":\n return \"Worker Status\";\n case \"prompt_worker\":\n return \"Prompt Worker\";\n case \"get_worker_summary\":\n return \"Worker Summary\";\n default:\n return undefined;\n }\n },\n\n formatDetail(name, args) {\n switch (name) {\n case \"list_workers\":\n return \"\";\n case \"get_worker_status\":\n case \"get_worker_summary\":\n return truncate(String(args.project ?? \"\"), 40);\n case \"prompt_worker\": {\n const project = String(args.project ?? \"\");\n const message = String(args.message ?? \"\").replace(/\\s+/g, \" \");\n const fresh = args.fresh === true;\n const maxMsg = promptWorkerDetailLen(project) - (fresh ? 8 : 0); // \"fresh · \" is 8 chars\n const truncMsg = truncate(message, Math.max(15, maxMsg));\n const head = fresh ? \"fresh · \" : \"\";\n return project ? `${head}${project} · ${truncMsg}` : `${head}${truncMsg}`;\n }\n default:\n return undefined;\n }\n },\n\n formatInline(name, result, isError) {\n if (isError) return undefined;\n switch (name) {\n case \"list_workers\": {\n const lines = result.split(\"\\n\").filter((l) => l.startsWith(\"-\"));\n return `${lines.length} worker${lines.length === 1 ? \"\" : \"s\"}`;\n }\n case \"prompt_worker\": {\n if (result.includes(\"currently working\")) {\n return { text: \"busy — skipped\", color: \"#fbbf24\" };\n }\n if (result.includes(\"Unknown project\")) {\n return { text: \"unknown project\", color: \"#f87171\" };\n }\n // Color the badge by project — same project always reads as the same\n // hue across scrollback so the user can scan dispatches at a glance.\n // (When fresh: true, the \"fresh ·\" prefix is already in the detail\n // parens — no need to double up here, was causing line wraps.)\n const project = String(result.match(/\"([^\"]+)\"/)?.[1] ?? \"\");\n const color = project ? projectColor(project) : \"#e11d48\";\n return { text: \"dispatched\", color };\n }\n case \"get_worker_status\": {\n const parts = result.split(\":\");\n if (parts.length < 2) return undefined;\n const status = parts.slice(1).join(\":\").trim();\n const project = parts[0]!.trim();\n return { text: status, color: projectColor(project) };\n }\n case \"get_worker_summary\": {\n const turnMatch = result.match(/Turn:\\s*(\\d+)/);\n const projectMatch = result.match(/Project:\\s*(.+)/);\n const toolsMatch = result.match(/Tools used:\\s*(.+)/);\n const tools = toolsMatch ? toolsMatch[1] : \"\";\n const toolCount = tools && tools !== \"(no tools used)\" ? tools.split(\",\").length : 0;\n const turn = turnMatch ? `turn ${turnMatch[1]}` : undefined;\n const tCount = toolCount > 0 ? `${toolCount} tool${toolCount === 1 ? \"\" : \"s\"}` : undefined;\n const summary = [turn, tCount].filter(Boolean).join(\" · \");\n if (!summary) return undefined;\n const project = projectMatch ? projectMatch[1].trim() : \"\";\n return project\n ? { text: summary, color: projectColor(project) }\n : { text: summary, color: \"#9ca3af\" };\n }\n default:\n return undefined;\n }\n },\n};\n","/**\n * Stable project-color palette. Hashing the project name to a fixed slot lets\n * every UI surface (worker event row, status bar, scope pill, dispatched\n * badge, etc.) tag the same project with the same hue — turns scrollback into\n * a glanceable colour-coded timeline.\n *\n * Picked to look decent in both dark and light themes — saturated enough to\n * read on dim backgrounds, soft enough not to scream.\n */\nexport const PROJECT_COLORS: readonly string[] = [\n \"#60a5fa\", // blue\n \"#a78bfa\", // violet\n \"#4ade80\", // green\n \"#fbbf24\", // amber\n \"#f472b6\", // pink\n \"#22d3ee\", // cyan\n \"#fb923c\", // orange\n \"#34d399\", // emerald\n];\n\nexport function stableHash(s: string): number {\n let h = 0;\n for (let i = 0; i < s.length; i++) {\n h = (h * 31 + s.charCodeAt(i)) | 0;\n }\n return Math.abs(h);\n}\n\n/** Pick a color for a project — same project name always returns the same color. */\nexport function projectColor(name: string): string {\n return PROJECT_COLORS[stableHash(name) % PROJECT_COLORS.length]!;\n}\n","import type { ActivityPhase } from \"@kenkaiiii/ggcoder/ui\";\n\n/**\n * Boss-themed phrase library for the activity indicator. Replaces ggcoder's\n * coder-flavored phrases (\"Cogitating\", \"Sleuthing\", etc.) with vocabulary\n * that fits an orchestrator role — managing, dispatching, reviewing — so the\n * spinner reads as \"the boss is at work\" not \"the boss is writing code\".\n */\nexport const BOSS_PHRASES: Record<ActivityPhase, string[]> = {\n // Generic between-states fallback. Probably never shown but keep for safety.\n idle: [\"Standing by\", \"Waiting for orders\", \"On call\"],\n\n // Boss has issued a request, waiting for the LLM to begin streaming.\n waiting: [\n \"Briefing\",\n \"Reviewing the room\",\n \"Triaging\",\n \"Lining up the brief\",\n \"Surveying projects\",\n \"Reading the room\",\n \"Picking the right hand\",\n \"Marshalling thoughts\",\n \"Checking the board\",\n \"Sizing up the work\",\n ],\n\n // LLM is mid-thinking-block (extended reasoning).\n thinking: [\n \"Strategising\",\n \"Plotting next move\",\n \"Weighing options\",\n \"Reasoning\",\n \"Deliberating\",\n \"Thinking it through\",\n \"Mapping the play\",\n \"Considering angles\",\n \"Calculating odds\",\n \"Drafting the call\",\n ],\n\n // LLM is streaming text — boss is forming its dispatch / response.\n generating: [\n \"Drafting\",\n \"Composing dispatch\",\n \"Writing the brief\",\n \"Penning instructions\",\n \"Wording it up\",\n \"Putting it on paper\",\n \"Phrasing the ask\",\n \"Forming the directive\",\n \"Scripting the plan\",\n ],\n\n // Boss is invoking a tool — most often prompt_worker.\n tools: [\n \"Coordinating\",\n \"Dispatching\",\n \"Routing\",\n \"Delegating\",\n \"Issuing orders\",\n \"Handing off\",\n \"Aligning workers\",\n \"Conducting\",\n \"Calling the team\",\n \"Steering\",\n \"Pulling levers\",\n ],\n\n // Provider retry (overloaded / rate-limited / etc.).\n retrying: [\n \"Reattempting\",\n \"Course correcting\",\n \"Trying again\",\n \"Pushing through\",\n \"Holding the line\",\n ],\n};\n","import React, { useCallback, useEffect, useRef, useState } from \"react\";\nimport { Box, Text, useInput } from \"ink\";\nimport { useTheme } from \"@kenkaiiii/ggcoder/ui/theme\";\nimport { useTasksState, tasksStore, type BossTask, type TaskStatus } from \"./tasks-store.js\";\nimport { bossStore } from \"./boss-store.js\";\nimport { projectColor } from \"./colors.js\";\nimport { COLORS } from \"./branding.js\";\nimport type { GGBoss } from \"./orchestrator.js\";\nimport type { WorkerView } from \"./boss-store.js\";\n\nfunction statusGlyph(status: TaskStatus): string {\n switch (status) {\n case \"done\":\n return \"✓\";\n case \"in_progress\":\n return \"~\";\n case \"blocked\":\n return \"✗\";\n case \"skipped\":\n return \"—\";\n default:\n return \" \";\n }\n}\n\ninterface BossTasksOverlayProps {\n boss: GGBoss;\n workers: WorkerView[];\n onClose: () => void;\n}\n\n/**\n * Multi-project task overlay for gg-boss. Read-mostly: tasks are added by the\n * boss agent (via add_task tool), so the overlay is just a backlog viewer with\n * two actions — delete a stuck task, or run all pending across idle workers.\n *\n * Keybinds (all the user actually needs):\n * ↑↓ / k j navigate\n * d delete selected task\n * r dispatch_pending across all idle workers (parallel fan-out)\n * Esc close\n */\nexport function BossTasksOverlay({\n boss,\n workers,\n onClose,\n}: BossTasksOverlayProps): React.ReactElement {\n const theme = useTheme();\n const tasksState = useTasksState();\n const tasks = tasksState.tasks;\n const [selectedIndex, setSelectedIndex] = useState(0);\n const [status, setStatusMsg] = useState(\"\");\n const statusTimer = useRef<ReturnType<typeof setTimeout> | null>(null);\n\n const showStatus = useCallback((msg: string): void => {\n setStatusMsg(msg);\n if (statusTimer.current) clearTimeout(statusTimer.current);\n statusTimer.current = setTimeout(() => setStatusMsg(\"\"), 2500);\n }, []);\n\n // Group tasks by project (in worker order).\n const groupedTasks: { project: string; tasks: BossTask[] }[] = workers.map((w) => ({\n project: w.name,\n tasks: tasks\n .filter((t) => t.project === w.name)\n .sort((a, b) => a.createdAt.localeCompare(b.createdAt)),\n }));\n\n const flatTasks: BossTask[] = groupedTasks.flatMap((g) => g.tasks);\n\n // Clamp selection.\n useEffect(() => {\n if (flatTasks.length === 0) {\n setSelectedIndex(0);\n } else if (selectedIndex >= flatTasks.length) {\n setSelectedIndex(flatTasks.length - 1);\n }\n }, [flatTasks.length, selectedIndex]);\n\n const selected = flatTasks[selectedIndex];\n\n // Cap how many tasks render at once so the live-area height stays bounded.\n // Ink's log-update mispositions the cursor when the live area is much\n // larger than the next frame — going from a 30-line tasks pane back to a\n // 5-line chat chrome was clipping the user's scrollback above on close.\n // Mirrors ggcoder's `maxVisible = 15` cap. Selection stays visible by\n // scrolling the window when the cursor reaches the bottom.\n const MAX_VISIBLE = 12;\n const startIdx = Math.max(\n 0,\n Math.min(flatTasks.length - MAX_VISIBLE, selectedIndex - MAX_VISIBLE + 1, selectedIndex),\n );\n const endIdx = Math.min(flatTasks.length, startIdx + MAX_VISIBLE);\n const visibleIdSet = new Set(flatTasks.slice(startIdx, endIdx).map((t) => t.id));\n const showingTop = startIdx > 0;\n const showingBottom = endIdx < flatTasks.length;\n\n useInput((input, key) => {\n if (key.escape) {\n onClose();\n return;\n }\n if (key.upArrow || input === \"k\") {\n setSelectedIndex((i) => Math.max(0, i - 1));\n return;\n }\n if (key.downArrow || input === \"j\") {\n setSelectedIndex((i) => Math.min(flatTasks.length - 1, i + 1));\n return;\n }\n if (input === \"d\" && selected) {\n void tasksStore.remove(selected.id).then(() => showStatus(\"Deleted\"));\n return;\n }\n if (input === \"r\") {\n // Close immediately so the user lands back in the chat view and can\n // watch worker activity stream in. Dispatch fires in the background;\n // worker_turn_complete events flow into history as normal.\n onClose();\n void (async (): Promise<void> => {\n const dispatched: { project: string; title: string }[] = [];\n for (const w of workers) {\n // nextDispatchable picks pending OR blocked — so blocked tasks get\n // retried alongside fresh pending ones. Pending is preferred.\n const next = tasksStore.nextDispatchable(w.name);\n if (!next) continue;\n // Reset blocked → pending so the dispatch path's in_progress flip\n // lands on a clean state and not \"blocked → in_progress\" (which\n // looks like a status going backwards in the overlay).\n if (next.status === \"blocked\") {\n await tasksStore.update(next.id, { status: \"pending\", notes: undefined });\n }\n const res = await boss.dispatchTaskById(next.id);\n if (res.ok) dispatched.push({ project: w.name, title: next.title });\n }\n if (dispatched.length === 0) {\n bossStore.appendInfo(\"No pending or blocked tasks to run.\", \"info\");\n } else {\n bossStore.appendTaskDispatch(dispatched);\n }\n })();\n return;\n }\n });\n\n const doneCount = tasks.filter((t) => t.status === \"done\").length;\n const inProgressCount = tasks.filter((t) => t.status === \"in_progress\").length;\n const pendingCount = tasks.filter((t) => t.status === \"pending\").length;\n const blockedCount = tasks.filter((t) => t.status === \"blocked\").length;\n\n return (\n <Box flexDirection=\"column\" marginTop={1} paddingX={1}>\n {/* Single header line — the main GG Boss banner sits in scrollback\n above (from <Static>), so we just announce the pane state here.\n Inner BossBanner caused visible duplicates on toggle round-trips. */}\n <Box>\n <Text color={COLORS.primary} bold>\n Tasks\n </Text>\n <Text color={theme.textDim}>{` · ${tasks.length} total · `}</Text>\n <CountsRow\n theme={theme}\n done={doneCount}\n active={inProgressCount}\n pending={pendingCount}\n blocked={blockedCount}\n />\n </Box>\n\n {flatTasks.length === 0 && (\n <Box marginTop={1}>\n <Text color={theme.textDim}>\n {\" No tasks yet. Ask the boss to plan some — e.g. \"}\n <Text color={theme.text}>\"plan some work\"</Text>\n {\".\"}\n </Text>\n </Box>\n )}\n\n {showingTop && <Text color={theme.textDim}>{` ↑ ${startIdx} more above`}</Text>}\n\n {/* Per-project sections — only tasks in the visible window are rendered.\n Sections with no visible tasks are hidden entirely so the layout\n stays compact across scroll. */}\n {groupedTasks.map((group, gIdx) => {\n const startInFlat = groupedTasks.slice(0, gIdx).reduce((acc, g) => acc + g.tasks.length, 0);\n const visibleInSection = group.tasks.filter((t) => visibleIdSet.has(t.id));\n if (visibleInSection.length === 0) return null;\n return (\n <Box key={group.project} flexDirection=\"column\" marginTop={1}>\n <Text>\n <Text color={projectColor(group.project)} bold>\n {group.project}\n </Text>\n <Text color={theme.textDim}>{` · ${group.tasks.length}`}</Text>\n </Text>\n {visibleInSection.map((task) => {\n const realIdx = startInFlat + group.tasks.indexOf(task);\n const isSelected = realIdx === selectedIndex;\n const prefix = isSelected ? \"❯ \" : \" \";\n const glyph = statusGlyph(task.status);\n const color = isSelected\n ? theme.primary\n : task.status === \"done\"\n ? theme.success\n : task.status === \"in_progress\"\n ? theme.warning\n : task.status === \"blocked\"\n ? theme.error\n : theme.text;\n return (\n <Text key={task.id} color={color} bold={isSelected}>\n {prefix}[{glyph}] {task.title}\n </Text>\n );\n })}\n </Box>\n );\n })}\n\n {showingBottom && (\n <Text color={theme.textDim}>{` ↓ ${flatTasks.length - endIdx} more below`}</Text>\n )}\n\n {status && (\n <Box marginTop={1}>\n <Text color={theme.success}>{\" \" + status}</Text>\n </Box>\n )}\n\n <Box marginTop={1}>\n <Text color={theme.textDim}>\n <Text color={theme.primary}>↑↓</Text>\n {\" move · (\"}\n <Text color={theme.primary}>d</Text>\n {\")elete · (\"}\n <Text color={theme.primary}>r</Text>\n {\")un pending · \"}\n <Text color={theme.primary}>ESC</Text>\n {\" close\"}\n </Text>\n </Box>\n </Box>\n );\n}\n\nfunction CountsRow({\n theme,\n done,\n active,\n pending,\n blocked,\n}: {\n theme: ReturnType<typeof useTheme>;\n done: number;\n active: number;\n pending: number;\n blocked: number;\n}): React.ReactElement {\n return (\n <Text>\n <Text color={theme.success}>{done} done</Text>\n <Text color={theme.textDim}> · </Text>\n <Text color={theme.warning}>{active} active</Text>\n <Text color={theme.textDim}> · </Text>\n <Text color={theme.text}>{pending} pending</Text>\n {blocked > 0 && (\n <>\n <Text color={theme.textDim}> · </Text>\n <Text color={theme.error}>{blocked} blocked</Text>\n </>\n )}\n </Text>\n );\n}\n","import React from \"react\";\nimport { SelectList } from \"@kenkaiiii/ggcoder/ui\";\nimport { RADIO_STATIONS } from \"./radio.js\";\n\ninterface RadioPickerProps {\n /** Currently-playing station id, or null when off. Drives the * marker. */\n currentStationId: string | null;\n onSelect: (stationId: string | \"off\") => void;\n onCancel: () => void;\n}\n\n/**\n * Picker overlay shown when the user types `/radio`. Mirrors ModelSelector's\n * pattern (SelectList + currentValue marker) so the keybinds and visual\n * weight match the rest of the boss overlays — ↑↓ to navigate, Enter to\n * select, Esc to cancel.\n *\n * The \"Off\" entry is always last and selectable regardless of current state,\n * so users can stop the radio from inside the picker without remembering a\n * separate /radio-off command.\n */\nexport function RadioPicker({\n currentStationId,\n onSelect,\n onCancel,\n}: RadioPickerProps): React.ReactElement {\n const items = [\n ...RADIO_STATIONS.map((s) => ({\n label: `${currentStationId === s.id ? \"* \" : \" \"}${s.name}`,\n value: s.id,\n description: s.description,\n })),\n {\n label: `${currentStationId === null ? \"* \" : \" \"}Off`,\n value: \"off\",\n description: \"Stop the radio\",\n },\n ];\n const initialIndex = Math.max(\n 0,\n items.findIndex((i) => i.value === (currentStationId ?? \"off\")),\n );\n return (\n <SelectList\n items={items}\n onSelect={(v) => onSelect(v === \"off\" ? \"off\" : v)}\n onCancel={onCancel}\n initialIndex={initialIndex}\n windowSize={6}\n />\n );\n}\n","import { spawn, type ChildProcess } from \"node:child_process\";\nimport { log } from \"./logger.js\";\n\n/**\n * Terminal radio — stream a free internet radio station while you're working.\n * Curated short list of long-running, royalty-free, no-API-key streams that\n * have been stable for years (SomaFM started in 2000, Radio Paradise in 2006).\n *\n * Player binary detection mirrors the audio.ts chain for one-shot effects:\n * mpv > ffplay > mpg123 > cvlc. macOS's built-in afplay isn't a streaming\n * player, so users who haven't installed any of those will get a one-line\n * \"install mpv\" hint and the radio request just no-ops gracefully.\n *\n * One station at a time — switching stations or selecting \"Off\" kills the\n * existing player process before spawning a new one.\n */\n\nexport interface RadioStation {\n /** Stable identifier used in slash command + settings persistence. */\n id: string;\n /** Display name in the picker. */\n name: string;\n /** Short subtitle shown next to the name. */\n description: string;\n /** Direct stream URL — must be MP3/AAC/Ogg, anything mpv handles. */\n url: string;\n}\n\nexport const RADIO_STATIONS: readonly RadioStation[] = [\n {\n id: \"somafm-groove-salad\",\n name: \"SomaFM · Groove Salad\",\n description: \"Chilled downtempo, ambient grooves\",\n url: \"http://ice1.somafm.com/groovesalad-128-mp3\",\n },\n {\n id: \"somafm-drone-zone\",\n name: \"SomaFM · Drone Zone\",\n description: \"Atmospheric textures with minimal beats\",\n url: \"http://ice1.somafm.com/dronezone-128-mp3\",\n },\n {\n id: \"radio-paradise\",\n name: \"Radio Paradise\",\n description: \"Eclectic mix — rock, electronica, jazz\",\n url: \"http://stream.radioparadise.com/mp3-128\",\n },\n {\n id: \"george-fm\",\n name: \"George FM\",\n description: \"NZ dance + electronic\",\n url: \"https://mediaworks.streamguys1.com/george_net_icy\",\n },\n];\n\ninterface PlayerCandidate {\n cmd: string;\n args: (url: string) => string[];\n}\n\n/**\n * Streaming-capable players in priority order. Each gets its quietest flag\n * combination — radio runs in the background, we don't want stdout/stderr\n * spam fighting with the TUI. Stdio is also redirected to \"ignore\" at spawn\n * time, but quiet flags help in case the player decides to write to tty.\n */\nconst PLAYERS: readonly PlayerCandidate[] = [\n { cmd: \"mpv\", args: (u) => [\"--really-quiet\", \"--no-video\", \"--no-terminal\", u] },\n {\n cmd: \"ffplay\",\n args: (u) => [\"-nodisp\", \"-autoexit\", \"-loglevel\", \"quiet\", u],\n },\n { cmd: \"mpg123\", args: (u) => [\"-q\", u] },\n { cmd: \"cvlc\", args: (u) => [\"--play-and-exit\", \"--quiet\", u] },\n];\n\nlet currentChild: ChildProcess | null = null;\nlet currentStationId: string | null = null;\n\nexport function getCurrentStation(): string | null {\n return currentStationId;\n}\n\n/**\n * Stop whatever's currently playing. Idempotent — safe to call when nothing\n * is playing. Sends SIGTERM (graceful), child cleans up the audio device.\n */\nexport function stopRadio(): void {\n if (!currentChild) return;\n try {\n // Detached children sit in their own process group on POSIX; kill the\n // whole group so any helper threads/forks die too. On Windows there's\n // no process group concept — kill() targets the child only.\n if (process.platform !== \"win32\" && currentChild.pid) {\n try {\n process.kill(-currentChild.pid, \"SIGTERM\");\n } catch {\n currentChild.kill(\"SIGTERM\");\n }\n } else {\n currentChild.kill(\"SIGTERM\");\n }\n } catch {\n // Already exited — nothing to do.\n }\n currentChild = null;\n currentStationId = null;\n log(\"INFO\", \"radio\", \"stopped\");\n}\n\ninterface PlayResult {\n ok: boolean;\n /** Friendly error to surface to the user when ok=false. */\n error?: string;\n}\n\n/**\n * Spawn a streaming player for the given station. If one is already playing,\n * it's killed first. Returns ok=false with a hint if no compatible player is\n * installed — caller should surface the error to the user.\n */\nexport function playRadio(stationId: string): PlayResult {\n const station = RADIO_STATIONS.find((s) => s.id === stationId);\n if (!station) return { ok: false, error: `Unknown station: ${stationId}` };\n\n // Always stop the previous stream before starting a new one.\n stopRadio();\n\n for (const player of PLAYERS) {\n try {\n const child = spawn(player.cmd, player.args(station.url), {\n detached: process.platform !== \"win32\",\n stdio: \"ignore\",\n });\n // Race: we don't know yet whether the spawn succeeded (ENOENT fires async).\n // Listen for the error event AND optimistically assume success. If error\n // fires within 100ms we'll fall through to the next candidate.\n let errored = false;\n child.once(\"error\", () => {\n errored = true;\n });\n // Synchronous check after a tick — if the child has a pid by now, the\n // OS accepted the spawn. ENOENT is reported async via the \"error\" event,\n // so a non-null pid alone isn't conclusive, but combined with the\n // optimistic try/next-candidate loop it's enough.\n if (child.pid && !errored) {\n currentChild = child;\n currentStationId = stationId;\n log(\"INFO\", \"radio\", \"playing\", {\n station: station.id,\n player: player.cmd,\n url: station.url,\n });\n // Detach so the radio outlives boss exit if the user wants it to.\n // (We still kill it on stopRadio() and on graceful boss shutdown.)\n child.unref();\n return { ok: true };\n }\n } catch {\n // ENOENT or permission — try the next player.\n }\n }\n log(\"WARN\", \"radio\", \"no compatible player found\", { platform: process.platform });\n return {\n ok: false,\n error: buildInstallHint(),\n };\n}\n\n/**\n * Platform-specific one-line install hint. Picks the most likely working\n * command for the current OS so the user can copy-paste rather than reading\n * a wall of generic suggestions. Falls back to the official mpv site for\n * platforms we don't recognise.\n */\nfunction buildInstallHint(): string {\n const base =\n \"Radio needs a streaming player. Install one of: mpv (recommended), ffplay, mpg123, or vlc.\";\n switch (process.platform) {\n case \"darwin\":\n return `${base} On macOS: \\`brew install mpv\\` (or \\`brew install ffmpeg\\` for ffplay).`;\n case \"linux\":\n return `${base} On Linux (Debian/Ubuntu): \\`sudo apt install mpv\\`. Fedora: \\`sudo dnf install mpv\\`. Arch: \\`sudo pacman -S mpv\\`.`;\n case \"win32\":\n return `${base} On Windows: \\`winget install mpv.mpv\\` (or download from https://mpv.io).`;\n default:\n return `${base} See https://mpv.io for platform installation instructions.`;\n }\n}\n","import { spawn } from \"node:child_process\";\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport os from \"node:os\";\n\n/**\n * gg-boss auto-update — mirrors ggcoder's pattern (packages/ggcoder/src/core/\n * auto-update.ts) but pinned to @kenkaiiii/gg-boss and with its own state\n * file under ~/.gg/boss/ so it can't fight with ggcoder's checker.\n *\n * Two-phase strategy:\n * - Phase 1 (instant, blocking): if a previous run found a newer version,\n * spawn `npm i -g @kenkaiiii/gg-boss@latest` (or pnpm/yarn equivalent)\n * in a detached child. Takes effect on the user's NEXT launch.\n * - Phase 2 (async, non-blocking): hit the npm registry to compare versions\n * so the next startup knows if there's anything to install. Throttled to\n * once an hour per state-file timestamp.\n *\n * Plus a periodic in-session check so a user who never restarts still gets\n * notified when a new version drops.\n */\n\nconst PACKAGE_NAME = \"@kenkaiiii/gg-boss\";\nconst REGISTRY_URL = `https://registry.npmjs.org/${PACKAGE_NAME}/latest`;\nconst CHECK_INTERVAL_MS = 60 * 60 * 1000; // 1 hour\nconst FETCH_TIMEOUT_MS = 10_000;\n\ninterface UpdateState {\n lastCheckedAt: number;\n latestVersion?: string;\n updatePending?: boolean;\n lastUpdateAttempt?: number;\n}\n\nenum PackageManager {\n NPM = \"npm\",\n PNPM = \"pnpm\",\n YARN = \"yarn\",\n UNKNOWN = \"unknown\",\n}\n\ninterface InstallInfo {\n packageManager: PackageManager;\n updateCommand: string | null;\n}\n\nfunction getStateFilePath(): string {\n return path.join(os.homedir(), \".gg\", \"boss\", \"update-state.json\");\n}\n\nfunction readState(): UpdateState | null {\n try {\n const raw = fs.readFileSync(getStateFilePath(), \"utf-8\");\n return JSON.parse(raw) as UpdateState;\n } catch {\n return null;\n }\n}\n\nfunction writeState(state: UpdateState): void {\n try {\n const dir = path.dirname(getStateFilePath());\n fs.mkdirSync(dir, { recursive: true, mode: 0o700 });\n fs.writeFileSync(getStateFilePath(), JSON.stringify(state));\n } catch {\n // Non-fatal — we'll just retry next launch.\n }\n}\n\nfunction compareVersions(a: string, b: string): number {\n const pa = a.split(\".\").map(Number);\n const pb = b.split(\".\").map(Number);\n for (let i = 0; i < 3; i++) {\n const diff = (pa[i] ?? 0) - (pb[i] ?? 0);\n if (diff !== 0) return diff;\n }\n return 0;\n}\n\nfunction detectInstallInfo(): InstallInfo {\n const scriptPath = (process.argv[1] ?? \"\").replace(/\\\\/g, \"/\");\n // npx invocations are ephemeral — never auto-update.\n if (scriptPath.includes(\"/_npx/\")) {\n return { packageManager: PackageManager.UNKNOWN, updateCommand: null };\n }\n if (scriptPath.includes(\"/.pnpm\") || scriptPath.includes(\"/pnpm/global\")) {\n return {\n packageManager: PackageManager.PNPM,\n updateCommand: `pnpm add -g ${PACKAGE_NAME}@latest`,\n };\n }\n if (scriptPath.includes(\"/.yarn/\") || scriptPath.includes(\"/yarn/global\")) {\n return {\n packageManager: PackageManager.YARN,\n updateCommand: `yarn global add ${PACKAGE_NAME}@latest`,\n };\n }\n return {\n packageManager: PackageManager.NPM,\n updateCommand: `npm install -g ${PACKAGE_NAME}@latest`,\n };\n}\n\nasync function fetchLatestVersion(): Promise<string | null> {\n try {\n const controller = new AbortController();\n const timeout = setTimeout(() => controller.abort(), FETCH_TIMEOUT_MS);\n const response = await fetch(REGISTRY_URL, { signal: controller.signal });\n clearTimeout(timeout);\n const data = (await response.json()) as { version?: string };\n const version = data.version?.trim();\n return version && /^\\d+\\.\\d+\\.\\d+/.test(version) ? version : null;\n } catch {\n return null;\n }\n}\n\nfunction performUpdateInBackground(command: string): void {\n try {\n const parts = command.split(\" \");\n const child = spawn(parts[0]!, parts.slice(1), {\n detached: true,\n stdio: \"ignore\",\n env: { ...process.env, npm_config_loglevel: \"silent\" },\n });\n child.unref();\n } catch {\n // Non-fatal — the next launch will try again.\n }\n}\n\n/**\n * Called on CLI startup. If the previous run flagged a newer version, kicks\n * off `npm i -g` in the background and returns a one-line \"installing…\"\n * message for the caller to print. Always also schedules a fresh registry\n * check (rate-limited) so the next startup has up-to-date info.\n */\nexport function checkAndAutoUpdate(currentVersion: string): string | null {\n try {\n const state = readState();\n let message: string | null = null;\n\n // Phase 1: install if a previous check found something newer.\n if (state?.updatePending && state.latestVersion) {\n if (compareVersions(state.latestVersion, currentVersion) > 0) {\n const info = detectInstallInfo();\n if (info.updateCommand) {\n performUpdateInBackground(info.updateCommand);\n message = `Ken just shipped ${state.latestVersion}! Installing in the background — takes effect next launch.`;\n writeState({\n ...state,\n lastCheckedAt: Date.now(),\n updatePending: false,\n lastUpdateAttempt: Date.now(),\n });\n }\n } else {\n // Already on latest (user updated manually) — clear the pending flag.\n writeState({ ...state, updatePending: false });\n }\n }\n\n // Phase 2: schedule a fresh check, throttled.\n const shouldCheck = !state || Date.now() - state.lastCheckedAt > CHECK_INTERVAL_MS;\n if (shouldCheck) scheduleBackgroundCheck(currentVersion);\n\n return message;\n } catch {\n return null;\n }\n}\n\n/**\n * Synchronous TUI getter — reads the state file and returns the pending\n * update info (if any). Drives the \"✨ Update ready\" indicator in the\n * worker bar so users know to restart.\n */\nexport function getPendingUpdate(currentVersion: string): { latestVersion: string } | null {\n try {\n const state = readState();\n if (!state?.latestVersion) return null;\n if (compareVersions(state.latestVersion, currentVersion) <= 0) return null;\n return { latestVersion: state.latestVersion };\n } catch {\n return null;\n }\n}\n\nfunction scheduleBackgroundCheck(currentVersion: string): void {\n fetchLatestVersion()\n .then((latestVersion) => {\n const newState: UpdateState = {\n lastCheckedAt: Date.now(),\n latestVersion: latestVersion ?? undefined,\n updatePending: false,\n };\n if (latestVersion && compareVersions(latestVersion, currentVersion) > 0) {\n newState.updatePending = true;\n }\n writeState(newState);\n })\n .catch(() => {\n // Non-fatal — we'll try again next launch.\n });\n}\n\n// ── In-session periodic check ──────────────────────────────\n\nlet periodicTimer: ReturnType<typeof setInterval> | null = null;\n\n/**\n * Start a long-running session timer that pings npm hourly. If a newer\n * version is found, calls `onUpdate(message)` with a friendly notification\n * and stops further checks (no point pinging again — restart is needed).\n * The timer is unref'd so it doesn't keep the process alive on its own.\n */\nexport function startPeriodicUpdateCheck(\n currentVersion: string,\n onUpdate: (message: string) => void,\n): void {\n if (periodicTimer) return;\n periodicTimer = setInterval(() => {\n fetchLatestVersion()\n .then((latestVersion) => {\n if (!latestVersion) return;\n if (compareVersions(latestVersion, currentVersion) <= 0) return;\n const info = detectInstallInfo();\n if (!info.updateCommand) return;\n writeState({\n lastCheckedAt: Date.now(),\n latestVersion,\n updatePending: true,\n });\n onUpdate(\n `Ken just pushed a fresh update — ${currentVersion} → ${latestVersion}! Restart ggboss to grab it (or run ${info.updateCommand} if you can't wait).`,\n );\n stopPeriodicUpdateCheck();\n })\n .catch(() => {\n // Non-fatal.\n });\n }, CHECK_INTERVAL_MS);\n periodicTimer.unref();\n}\n\nexport function stopPeriodicUpdateCheck(): void {\n if (periodicTimer) {\n clearInterval(periodicTimer);\n periodicTimer = null;\n }\n}\n","import React, { useEffect, useState } from \"react\";\nimport { Box, Text, render } from \"ink\";\nimport { AUTHOR, BRAND, COLORS, GRADIENT, VERSION } from \"./branding.js\";\nimport { getSplashAudioDurationMs, playSplashAudio } from \"./audio.js\";\n\n/**\n * Big ASCII \"GG Boss\" rendered for the splash. The block characters here are\n * ANSI Shadow-style figlet output. Whitespace is significant — every line is\n * the same width so the gradient striping aligns vertically. Do not reformat.\n */\nconst SPLASH_LINES: readonly string[] = [\n \" █████████ █████████ ███████████ \",\n \" ███░░░░░███ ███░░░░░███ ░░███░░░░░███ \",\n \" ███ ░░░ ███ ░░░ ░███ ░███ ██████ █████ █████ \",\n \"░███ ░███ ░██████████ ███░░███ ███░░ ███░░ \",\n \"░███ █████░███ █████ ░███░░░░░███░███ ░███░░█████ ░░█████ \",\n \"░░███ ░░███ ░░███ ░░███ ░███ ░███░███ ░███ ░░░░███ ░░░░███\",\n \" ░░█████████ ░░█████████ ███████████ ░░██████ ██████ ██████ \",\n \" ░░░░░░░░░ ░░░░░░░░░ ░░░░░░░░░░░ ░░░░░░ ░░░░░░ ░░░░░░ \",\n];\n\nconst SPLASH_WIDTH = SPLASH_LINES[0]!.length;\n\n/**\n * Vertical gradient stripe — assigns each line a colour from the brand\n * gradient so the logo gets a soft top→bottom hue transition. Filled glyphs\n * (`█`) take the line's hue at full brightness; shadow glyphs (`░`) inherit\n * the same hue but render at lower intensity (via `dimColor`) so they read\n * as a drop-shadow rather than fighting for visual weight with the fill.\n */\nfunction colorForLine(lineIdx: number, totalLines: number, offset: number): string {\n const t = totalLines <= 1 ? 0 : (lineIdx + offset) % totalLines;\n const idx = Math.floor((t / totalLines) * GRADIENT.length) % GRADIENT.length;\n return GRADIENT[idx]!;\n}\n\ninterface SplashProps {\n /** Pulse offset — bumping this on a timer rotates the gradient through the\n * logo for a subtle \"shimmer\" while the splash is mounted. */\n offset: number;\n}\n\nfunction SplashLogo({ offset }: SplashProps): React.ReactElement {\n return (\n <Box flexDirection=\"column\">\n {SPLASH_LINES.map((line, i) => {\n const hue = colorForLine(i, SPLASH_LINES.length, offset);\n // Split into runs so we can dim the shadow glyphs (░) without breaking\n // the line into one Text per char (which Ink would happily handle but\n // is wasteful at this scale).\n const segments: { text: string; dim: boolean }[] = [];\n let buf = \"\";\n let bufDim = false;\n for (const ch of line) {\n const dim = ch === \"░\";\n if (segments.length === 0 && buf.length === 0) {\n buf = ch;\n bufDim = dim;\n continue;\n }\n if (dim === bufDim) {\n buf += ch;\n } else {\n segments.push({ text: buf, dim: bufDim });\n buf = ch;\n bufDim = dim;\n }\n }\n if (buf) segments.push({ text: buf, dim: bufDim });\n\n return (\n <Text key={i}>\n {segments.map((seg, j) => (\n <Text key={j} color={hue} dimColor={seg.dim}>\n {seg.text}\n </Text>\n ))}\n </Text>\n );\n })}\n </Box>\n );\n}\n\ninterface SplashScreenProps {\n /** Optional caption shown under the logo — defaults to a \"Loading…\" line. */\n caption?: string;\n}\n\nexport function SplashScreen({ caption }: SplashScreenProps): React.ReactElement {\n const [offset, setOffset] = useState(0);\n // Soft shimmer — rotates the gradient through the logo every 120ms. Stops\n // when the component unmounts (the cli swaps the splash out as soon as the\n // boss has finished initialising).\n useEffect(() => {\n const timer = setInterval(() => {\n setOffset((o) => o + 1);\n }, 120);\n return () => {\n clearInterval(timer);\n };\n }, []);\n\n // Re-center on terminal resize. process.stdout.columns/rows are read live\n // each render and a \"resize\" event re-renders us so the centring stays\n // accurate even if the user resizes their window mid-splash.\n const [size, setSize] = useState(() => ({\n columns: process.stdout.columns ?? 80,\n rows: process.stdout.rows ?? 24,\n }));\n useEffect(() => {\n const handler = (): void =>\n setSize({\n columns: process.stdout.columns ?? 80,\n rows: process.stdout.rows ?? 24,\n });\n process.stdout.on(\"resize\", handler);\n return () => {\n process.stdout.off(\"resize\", handler);\n };\n }, []);\n\n // Splash height: 8 logo rows + 1 spacer + 1 brand line + 1 caption line ≈ 11.\n // We pad the top with empty rows to push the logo to the vertical centre,\n // and use Ink's flex `alignItems` for horizontal centring (works even when\n // the logo is wider than the terminal — flex just clips, no crash).\n const SPLASH_BLOCK_HEIGHT = SPLASH_LINES.length + 3;\n const verticalPad = Math.max(0, Math.floor((size.rows - SPLASH_BLOCK_HEIGHT) / 2));\n\n return (\n <Box flexDirection=\"column\" width={size.columns} height={size.rows} alignItems=\"center\">\n {/* Top spacer fills the available vertical space above the centred block. */}\n <Box height={verticalPad} flexShrink={0} />\n <Box flexDirection=\"column\" alignItems=\"flex-start\" flexShrink={0}>\n <SplashLogo offset={offset} />\n <Box width={SPLASH_WIDTH} marginTop={1} justifyContent=\"center\">\n <Text>\n <Text color={COLORS.text} bold>\n {BRAND}\n </Text>\n <Text color={COLORS.textDim}> v{VERSION}</Text>\n <Text color={COLORS.textDim}> · By </Text>\n <Text color={COLORS.text} bold>\n {AUTHOR}\n </Text>\n </Text>\n </Box>\n <Box width={SPLASH_WIDTH} justifyContent=\"center\">\n <Text color={COLORS.textDim}>{caption ?? \"Spinning up the orchestrator…\"}</Text>\n </Box>\n </Box>\n </Box>\n );\n}\n\n/**\n * Render the splash to stdout. Returns a `dismiss()` that holds the splash\n * for at least `minMs` total visible time (so even fast inits get a real\n * flash of branding) before unmounting, and resolves only after the unmount\n * has actually completed — so the caller can safely render the main app\n * next without two Ink trees coexisting on screen.\n */\nexport function showSplash(opts: { minMs?: number; caption?: string }): {\n dismiss: () => Promise<void>;\n} {\n const start = Date.now();\n // Fire-and-forget — never await. If the platform has no working player or\n // the bundled mp3 is missing, this resolves to nothing and the splash just\n // plays silently. Errors are swallowed inside playSplashAudio so the user\n // never sees an audio-related crash on launch.\n void playSplashAudio();\n const instance = render(<SplashScreen caption={opts.caption} />);\n // Default the minimum visible time to the audio duration so the user\n // doesn't get dumped into the chat mid-jingle. A small +200ms tail keeps\n // the last beat from being clipped by terminal-app sound shutdown.\n const audioDurationMs = getSplashAudioDurationMs();\n const defaultMinMs = audioDurationMs + 200;\n return {\n dismiss: async () => {\n const minMs = opts.minMs ?? defaultMinMs;\n const elapsed = Date.now() - start;\n const remaining = Math.max(0, minMs - elapsed);\n if (remaining > 0) {\n await new Promise((r) => setTimeout(r, remaining));\n }\n instance.unmount();\n // Give Ink one tick to flush the unmount writes before the caller\n // starts mounting the next tree.\n await new Promise((r) => setImmediate(r));\n },\n };\n}\n"],"mappings":"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","names":["path","import_react","fs","path","fs","path","import_jsx_runtime","path","import_react","import_react","import_react","import_react","import_react","import_react","import_react","import_jsx_runtime","import_react","import_jsx_runtime","import_react","import_jsx_runtime","currentStationId","spawn","fs","path","path","fs","spawn","import_jsx_runtime","React","import_react","import_jsx_runtime","cwd","path"]}
1
+ {"version":3,"sources":["../src/cli.ts","../src/links.ts","../src/link-command.tsx","../src/discover.ts","../src/banner.tsx","../src/branding.ts","../package.json","../src/orchestrator-app.tsx","../../ggcoder/src/ui/components/index.ts","../../ggcoder/src/ui/components/DiffView.tsx","../../ggcoder/src/ui/components/Overlay.tsx","../../ggcoder/src/ui/components/SessionSelector.tsx","../../ggcoder/src/ui/components/SettingsSelector.tsx","../../ggcoder/src/ui/components/ThinkingIndicator.tsx","../src/boss-footer.tsx","../src/slash-commands.ts","../src/tool-formatters.ts","../src/colors.ts","../src/boss-phrases.ts","../src/boss-tasks-overlay.tsx","../src/radio-picker.tsx","../src/radio.ts","../src/auto-update.ts","../src/splash.tsx"],"sourcesContent":["#!/usr/bin/env node\nimport path from \"node:path\";\nimport chalk from \"chalk\";\nimport type { Provider } from \"@kenkaiiii/gg-ai\";\nimport { GGBoss } from \"./orchestrator.js\";\nimport type { ProjectSpec } from \"./types.js\";\nimport { loadLinks } from \"./links.js\";\nimport { runLinkCommand } from \"./link-command.js\";\nimport { COLORS, clearScreen } from \"./branding.js\";\nimport { renderBossApp } from \"./orchestrator-app.js\";\nimport { loadSettings } from \"./settings.js\";\nimport { showSplash } from \"./splash.js\";\nimport { initLogger, log } from \"./logger.js\";\nimport { VERSION } from \"./branding.js\";\nimport { checkAndAutoUpdate } from \"./auto-update.js\";\nimport { stopRadio } from \"./radio.js\";\n\ninterface CliArgs {\n /** Undefined when not passed on the CLI — settings file then defaults take over. */\n bossProvider?: Provider;\n bossModel?: string;\n workerProvider?: Provider;\n workerModel?: string;\n projects: ProjectSpec[];\n continueRecent?: boolean;\n resumeSessionId?: string;\n}\n\nfunction parseProjectSpec(raw: string): ProjectSpec {\n const eq = raw.indexOf(\"=\");\n if (eq > 0) {\n const name = raw.slice(0, eq);\n const cwd = path.resolve(raw.slice(eq + 1));\n return { name, cwd };\n }\n const cwd = path.resolve(raw);\n return { name: path.basename(cwd), cwd };\n}\n\nfunction parseArgs(argv: string[]): CliArgs {\n const args: CliArgs = {\n projects: [],\n };\n\n for (let i = 0; i < argv.length; i++) {\n const a = argv[i]!;\n if (a === \"--project\" || a === \"-p\") {\n const v = argv[++i];\n if (!v) throw new Error(\"--project requires a value\");\n args.projects.push(parseProjectSpec(v));\n } else if (a === \"--boss-model\") {\n const v = argv[++i];\n if (!v) throw new Error(\"--boss-model requires a value\");\n args.bossModel = v;\n } else if (a === \"--worker-model\") {\n const v = argv[++i];\n if (!v) throw new Error(\"--worker-model requires a value\");\n args.workerModel = v;\n } else if (a === \"--resume\") {\n const v = argv[++i];\n if (!v) throw new Error(\"--resume requires a session id\");\n args.resumeSessionId = v;\n } else if (a === \"--help\" || a === \"-h\") {\n printHelpAndExit();\n } else {\n throw new Error(`Unknown argument: ${a}`);\n }\n }\n\n return args;\n}\n\nfunction printHelpAndExit(): never {\n const c = (color: string, text: string): string => chalk.hex(color)(text);\n process.stdout.write(\n \"\\n\" +\n c(COLORS.primary, \"GG Boss\") +\n c(COLORS.textDim, \" — orchestrator that drives multiple ggcoder workers from one chat.\\n\\n\") +\n c(COLORS.text, \"Usage\\n\") +\n \" \" +\n c(COLORS.accent, \"ggboss\") +\n c(\n COLORS.textDim,\n \" start orchestrator using linked projects\\n\",\n ) +\n \" \" +\n c(COLORS.accent, \"ggboss link\") +\n c(COLORS.textDim, \" pick which projects to link (interactive)\\n\") +\n \" \" +\n c(COLORS.accent, \"ggboss continue\") +\n c(COLORS.textDim, \" resume the most recent boss session\\n\") +\n \" \" +\n c(COLORS.accent, \"ggboss --resume <id>\") +\n c(COLORS.textDim, \" resume a specific boss session\\n\") +\n \" \" +\n c(COLORS.accent, \"ggboss --project <spec> [...]\") +\n c(COLORS.textDim, \" override links with explicit project(s)\\n\\n\") +\n c(COLORS.text, \"Options\\n\") +\n \" \" +\n c(COLORS.primary, \"--project, -p <spec>\") +\n c(COLORS.textDim, ' project to manage. spec is \"cwd\" or \"name=cwd\". repeatable.\\n') +\n \" \" +\n c(COLORS.primary, \"--boss-model <id>\") +\n c(COLORS.textDim, \" model for the orchestrator (default: claude-opus-4-7)\\n\") +\n \" \" +\n c(COLORS.primary, \"--worker-model <id>\") +\n c(COLORS.textDim, \" model for workers (default: claude-sonnet-4-6)\\n\") +\n \" \" +\n c(COLORS.primary, \"--help, -h\") +\n c(COLORS.textDim, \" show this help\\n\\n\") +\n c(COLORS.textDim, \"Talk to the boss at the prompt. Press \") +\n c(COLORS.accent, \"Ctrl+C\") +\n c(COLORS.textDim, \" twice to exit.\\n\\n\"),\n );\n process.exit(0);\n}\n\nasync function runOrchestrator(args: CliArgs): Promise<void> {\n if (args.projects.length === 0) {\n const links = await loadLinks();\n if (links.projects.length === 0) {\n process.stderr.write(\n \"\\n\" +\n chalk.hex(COLORS.warning)(\"No linked projects.\") +\n chalk.hex(COLORS.textDim)(\" Run \") +\n chalk.hex(COLORS.accent)(\"ggboss link\") +\n chalk.hex(COLORS.textDim)(\" to choose, or pass \") +\n chalk.hex(COLORS.accent)(\"--project\") +\n chalk.hex(COLORS.textDim)(\".\\n\\n\"),\n );\n process.exit(1);\n }\n args.projects = links.projects.map((p) => ({ name: p.name, cwd: p.cwd }));\n }\n\n clearScreen();\n\n // Splash — Ink-rendered ASCII logo with shimmering gradient, shown while\n // the boss spins up its workers. dismiss() blocks until min-visible-time\n // has elapsed AND Ink has flushed the unmount, so the chat UI never\n // overlaps with the splash on screen.\n const splash = showSplash({\n caption: `Spinning up ${args.projects.length} worker${args.projects.length === 1 ? \"\" : \"s\"}…`,\n });\n\n // Resolve final boss/worker models: CLI flags > saved settings > defaults.\n // Settings persist user choices made via /model boss / /model workers across\n // restarts so the user doesn't have to re-pick every session.\n const settings = await loadSettings();\n const finalBossProvider = args.bossProvider ?? settings.bossProvider ?? \"anthropic\";\n const finalBossModel = args.bossModel ?? settings.bossModel ?? \"claude-opus-4-7\";\n const finalWorkerProvider = args.workerProvider ?? settings.workerProvider ?? \"anthropic\";\n const finalWorkerModel = args.workerModel ?? settings.workerModel ?? \"claude-sonnet-4-6\";\n\n // Open ~/.gg/boss/debug.log in append mode and stamp a startup line so\n // future tail/grep diagnoses have the full session context up front.\n initLogger({\n version: VERSION,\n bossProvider: finalBossProvider,\n bossModel: finalBossModel,\n bossThinking: settings.bossThinkingLevel,\n workerProvider: finalWorkerProvider,\n workerModel: finalWorkerModel,\n projectCount: args.projects.length,\n });\n log(\"INFO\", \"cli\", \"linked projects\", {\n projects: args.projects.map((p) => p.name).join(\",\"),\n });\n\n // Auto-update: instantly applies any pending install from the prior run\n // (background spawn, takes effect next launch) and schedules a fresh\n // registry check. Returns a one-liner if an install just kicked off so\n // we can surface it before the splash takes over.\n const updateMessage = checkAndAutoUpdate(VERSION);\n if (updateMessage) log(\"INFO\", \"auto_update\", updateMessage);\n\n const boss = new GGBoss({\n bossProvider: finalBossProvider,\n bossModel: finalBossModel,\n bossThinkingLevel: settings.bossThinkingLevel,\n workerProvider: finalWorkerProvider,\n workerModel: finalWorkerModel,\n projects: args.projects,\n continueRecent: args.continueRecent,\n resumeSessionId: args.resumeSessionId,\n });\n\n await boss.initialize();\n await splash.dismiss();\n\n clearScreen();\n\n const ink = renderBossApp({ boss });\n\n // Don't register process.on(\"SIGINT\") here. Ink puts stdin in raw mode, so\n // Ctrl+C is delivered as a byte (0x03) to InputArea — not as a process\n // signal. Registering SIGINT would race InputArea's onAbort and exit\n // immediately on the first press, breaking the double-press exit flow.\n\n // Run boss in background; await Ink unmount (triggered by useApp().exit()\n // in BossApp when the user double-presses Ctrl+C).\n const runPromise = boss.run();\n await ink.waitUntilExit();\n await boss.dispose();\n // Kill any in-flight radio stream before exiting — otherwise the detached\n // mpv/ffplay child keeps playing after the user closed gg-boss.\n stopRadio();\n await runPromise.catch(() => {});\n process.exit(0);\n}\n\nasync function main(): Promise<void> {\n const argv = process.argv.slice(2);\n\n if (argv[0] === \"link\") {\n await runLinkCommand();\n process.exit(0);\n }\n\n // `ggboss continue` is a subcommand alias for \"resume the most recent session\".\n // Accept any flags after `continue` as normal flag args.\n const isContinue = argv[0] === \"continue\";\n const args = parseArgs(isContinue ? argv.slice(1) : argv);\n if (isContinue) args.continueRecent = true;\n await runOrchestrator(args);\n}\n\nmain().catch((err) => {\n const message = err instanceof Error ? err.message : String(err);\n process.stderr.write(chalk.hex(COLORS.error)(`\\ngg-boss failed: ${message}\\n`));\n process.exit(1);\n});\n","import fs from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { getAppPaths } from \"@kenkaiiii/ggcoder\";\n\nexport interface LinkedProject {\n name: string;\n cwd: string;\n}\n\nexport interface LinksFile {\n projects: LinkedProject[];\n}\n\nexport function getLinksPath(): string {\n return path.join(getAppPaths().agentDir, \"boss\", \"links.json\");\n}\n\nexport async function loadLinks(): Promise<LinksFile> {\n try {\n const content = await fs.readFile(getLinksPath(), \"utf-8\");\n const parsed = JSON.parse(content) as Partial<LinksFile>;\n return { projects: parsed.projects ?? [] };\n } catch {\n return { projects: [] };\n }\n}\n\nexport async function saveLinks(links: LinksFile): Promise<void> {\n const p = getLinksPath();\n await fs.mkdir(path.dirname(p), { recursive: true, mode: 0o700 });\n await fs.writeFile(p, JSON.stringify(links, null, 2), \"utf-8\");\n}\n","import React, { useState } from \"react\";\nimport { Box, Text, useApp, useInput, render } from \"ink\";\nimport chalk from \"chalk\";\nimport { discoverProjects, type DiscoveredProject } from \"./discover.js\";\nimport { loadLinks, saveLinks, type LinkedProject } from \"./links.js\";\nimport { BossBanner } from \"./banner.js\";\nimport { COLORS, clearScreen } from \"./branding.js\";\n\ninterface LinkScreenProps {\n projects: DiscoveredProject[];\n initialSelected: Set<string>;\n onDone: (selectedPaths: string[], cancelled: boolean) => void;\n}\n\nconst VISIBLE_ROWS = 12;\n\nfunction LinkScreen({ projects, initialSelected, onDone }: LinkScreenProps): React.ReactElement {\n const [cursor, setCursor] = useState(0);\n const [selected, setSelected] = useState<Set<string>>(new Set(initialSelected));\n const [scrollOffset, setScrollOffset] = useState(0);\n\n const visible = projects.slice(scrollOffset, scrollOffset + VISIBLE_ROWS);\n\n useInput((input, key) => {\n // Ctrl+C — cancel cleanly.\n if (key.ctrl && input === \"c\") {\n onDone([], true);\n return;\n }\n\n if (projects.length === 0) {\n if (key.return || key.escape || input === \"q\") onDone([], true);\n return;\n }\n\n if (key.upArrow) {\n const next = Math.max(0, cursor - 1);\n setCursor(next);\n if (next < scrollOffset) setScrollOffset(next);\n } else if (key.downArrow) {\n const next = Math.min(projects.length - 1, cursor + 1);\n setCursor(next);\n if (next >= scrollOffset + VISIBLE_ROWS) setScrollOffset(next - VISIBLE_ROWS + 1);\n } else if (input === \" \") {\n const p = projects[cursor];\n if (!p) return;\n const nextSet = new Set(selected);\n if (nextSet.has(p.path)) nextSet.delete(p.path);\n else nextSet.add(p.path);\n setSelected(nextSet);\n } else if (input === \"a\") {\n const allSelected = projects.every((p) => selected.has(p.path));\n setSelected(allSelected ? new Set() : new Set(projects.map((p) => p.path)));\n } else if (key.return) {\n onDone(\n projects.filter((p) => selected.has(p.path)).map((p) => p.path),\n false,\n );\n } else if (key.escape || input === \"q\") {\n onDone([], true);\n }\n });\n\n const subtitle =\n projects.length === 0\n ? \"Link projects\"\n : `Link projects · ${projects.length} discovered · ${selected.size} selected`;\n const hint = \"↑↓ navigate · space toggle · a all · enter save · esc cancel\";\n\n if (projects.length === 0) {\n return (\n <Box flexDirection=\"column\" paddingX={2}>\n <BossBanner subtitle=\"Link projects\" hint=\"No projects yet\" />\n <Box flexDirection=\"column\" marginLeft={2}>\n <Text color={COLORS.textDim}>No ggcoder projects found in ~/.gg/sessions/.</Text>\n <Text color={COLORS.textDim}>\n Run ggcoder in a project at least once, then re-run{\" \"}\n <Text color={COLORS.accent}>ggboss link</Text>.\n </Text>\n <Box marginTop={1}>\n <Text color={COLORS.textDim}>Press any key to exit.</Text>\n </Box>\n </Box>\n </Box>\n );\n }\n\n const showingTop = scrollOffset > 0;\n const showingBottom = scrollOffset + VISIBLE_ROWS < projects.length;\n\n return (\n <Box flexDirection=\"column\" paddingX={2}>\n <BossBanner subtitle={subtitle} hint={hint} />\n <Box flexDirection=\"column\" marginLeft={2}>\n {showingTop && <Text color={COLORS.textDim}>{\" ↑ more above\"}</Text>}\n {visible.map((p, i) => {\n const realIndex = scrollOffset + i;\n const isCursor = realIndex === cursor;\n const isSelected = selected.has(p.path);\n const checkbox = isSelected ? \"[✓]\" : \"[ ]\";\n const arrow = isCursor ? \"❯\" : \" \";\n const nameColor = isCursor ? COLORS.primary : isSelected ? COLORS.success : COLORS.text;\n const checkboxColor = isSelected ? COLORS.success : COLORS.textDim;\n return (\n <Box key={p.path}>\n <Text color={COLORS.primary}>{arrow}</Text>\n <Text> </Text>\n <Text color={checkboxColor}>{checkbox}</Text>\n <Text> </Text>\n <Text color={nameColor} bold={isCursor}>\n {p.name}\n </Text>\n <Text color={COLORS.textDim}>{\" \"}</Text>\n <Text color={COLORS.textDim}>{p.lastActiveDisplay}</Text>\n </Box>\n );\n })}\n {showingBottom && <Text color={COLORS.textDim}>{\" ↓ more below\"}</Text>}\n </Box>\n </Box>\n );\n}\n\ninterface LinkAppProps {\n projects: DiscoveredProject[];\n initialSelected: Set<string>;\n resolve: (result: { selected: string[]; cancelled: boolean }) => void;\n}\n\nfunction LinkApp({ projects, initialSelected, resolve }: LinkAppProps): React.ReactElement {\n const { exit } = useApp();\n return (\n <LinkScreen\n projects={projects}\n initialSelected={initialSelected}\n onDone={(selected, cancelled) => {\n resolve({ selected, cancelled });\n exit();\n }}\n />\n );\n}\n\nexport async function runLinkCommand(): Promise<void> {\n const projects = await discoverProjects();\n const links = await loadLinks();\n const initialSelected = new Set(links.projects.map((p) => p.cwd));\n\n clearScreen();\n\n const result = await new Promise<{ selected: string[]; cancelled: boolean }>((resolve) => {\n const { waitUntilExit } = render(\n <LinkApp projects={projects} initialSelected={initialSelected} resolve={resolve} />,\n );\n void waitUntilExit();\n });\n\n if (result.cancelled) {\n process.stdout.write(chalk.hex(COLORS.textDim)(\"\\nCancelled. No changes saved.\\n\"));\n return;\n }\n\n const linked: LinkedProject[] = result.selected\n .map((path) => projects.find((p) => p.path === path))\n .filter((p): p is DiscoveredProject => Boolean(p))\n .map((p) => ({ name: p.name, cwd: p.path }));\n\n await saveLinks({ projects: linked });\n\n process.stdout.write(\"\\n\");\n if (linked.length === 0) {\n process.stdout.write(chalk.hex(COLORS.warning)(\"Cleared linked projects.\\n\"));\n } else {\n process.stdout.write(\n chalk.hex(COLORS.success)(\n `Linked ${linked.length} project${linked.length === 1 ? \"\" : \"s\"}:\\n`,\n ),\n );\n for (const p of linked) {\n process.stdout.write(\n \" \" + chalk.hex(COLORS.primary)(\"·\") + \" \" + chalk.hex(COLORS.text)(p.name) + \"\\n\",\n );\n }\n process.stdout.write(\"\\n\");\n process.stdout.write(\n chalk.hex(COLORS.textDim)(`Run `) +\n chalk.hex(COLORS.accent)(\"ggboss\") +\n chalk.hex(COLORS.textDim)(` to start the orchestrator.\\n`),\n );\n }\n}\n","import fs from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { getAppPaths } from \"@kenkaiiii/ggcoder\";\n\nexport interface DiscoveredProject {\n name: string;\n path: string;\n lastActiveMs: number;\n lastActiveDisplay: string;\n}\n\n/**\n * Scan ~/.gg/sessions/ and return projects sorted most-recent first.\n * Each session directory's name is the encoded cwd (slashes → underscores);\n * we decode it back and verify the directory still exists on disk.\n */\nexport async function discoverProjects(): Promise<DiscoveredProject[]> {\n const sessionsDir = getAppPaths().sessionsDir;\n let entries: string[];\n try {\n entries = await fs.readdir(sessionsDir);\n } catch {\n return [];\n }\n\n const results: DiscoveredProject[] = [];\n for (const entry of entries) {\n const dir = path.join(sessionsDir, entry);\n let stat;\n try {\n stat = await fs.stat(dir);\n } catch {\n continue;\n }\n if (!stat.isDirectory()) continue;\n\n let files: string[];\n try {\n files = await fs.readdir(dir);\n } catch {\n continue;\n }\n const sessionFiles = files.filter((f) => f.endsWith(\".jsonl\"));\n if (sessionFiles.length === 0) continue;\n\n let maxMtime = 0;\n for (const f of sessionFiles) {\n try {\n const s = await fs.stat(path.join(dir, f));\n if (s.mtimeMs > maxMtime) maxMtime = s.mtimeMs;\n } catch {\n // skip unreadable files\n }\n }\n\n const decoded = \"/\" + entry.replace(/_/g, \"/\");\n\n // Verify the decoded path still exists — drop dead entries from the list.\n try {\n const pathStat = await fs.stat(decoded);\n if (!pathStat.isDirectory()) continue;\n } catch {\n continue;\n }\n\n results.push({\n name: path.basename(decoded),\n path: decoded,\n lastActiveMs: maxMtime,\n lastActiveDisplay: formatRelativeTime(maxMtime),\n });\n }\n\n results.sort((a, b) => b.lastActiveMs - a.lastActiveMs);\n return results;\n}\n\nfunction formatRelativeTime(ms: number): string {\n if (ms === 0) return \"—\";\n const diff = Date.now() - ms;\n if (diff < 60_000) return \"just now\";\n const min = 60_000;\n const hour = 60 * min;\n const day = 24 * hour;\n const week = 7 * day;\n const month = 30 * day;\n if (diff < hour) return `${Math.floor(diff / min)}m ago`;\n if (diff < day) return `${Math.floor(diff / hour)}h ago`;\n if (diff < week) return `${Math.floor(diff / day)}d ago`;\n if (diff < month) return `${Math.floor(diff / week)}w ago`;\n return `${Math.floor(diff / month)}mo ago`;\n}\n","import React from \"react\";\nimport { Box, Text } from \"ink\";\nimport { AUTHOR, BRAND, COLORS, GRADIENT, LOGO_GAP, LOGO_LINES, VERSION } from \"./branding.js\";\n\ninterface BossBannerProps {\n /** Second line text (e.g. \"Link projects\", \"Orchestrator\"). */\n subtitle: string;\n /** Third line text (e.g. \"↑↓ navigate · enter save\"). */\n hint?: string;\n /**\n * If true, show the standard chat-mode shortcut row (Ctrl+T tasks). Mirrors\n * ggcoder's banner where the third row advertises ^T / ^S / ^P. Override\n * with `hint` for non-chat banners (link picker, task overlay).\n */\n showShortcuts?: boolean;\n}\n\n/** Ink banner — for use inside Ink-rendered screens. */\nexport function BossBanner({ subtitle, hint, showShortcuts }: BossBannerProps): React.ReactElement {\n return (\n <Box flexDirection=\"column\" marginTop={1} marginBottom={1}>\n <Box>\n <GradientText text={LOGO_LINES[0]!} />\n <Text>{LOGO_GAP}</Text>\n <Text color={COLORS.primary} bold>\n {BRAND}\n </Text>\n <Text color={COLORS.textDim}> v{VERSION}</Text>\n <Text color={COLORS.textDim}> · By </Text>\n <Text color={COLORS.text} bold>\n {AUTHOR}\n </Text>\n </Box>\n <Box>\n <GradientText text={LOGO_LINES[1]!} />\n <Text>{LOGO_GAP}</Text>\n <Text color={COLORS.accent}>{subtitle}</Text>\n </Box>\n <Box>\n <GradientText text={LOGO_LINES[2]!} />\n <Text>{LOGO_GAP}</Text>\n {showShortcuts ? (\n <Text>\n <Text color={COLORS.primary}>^T</Text>\n <Text color={COLORS.textDim}> tasks</Text>\n <Text color={COLORS.textDim}>{\" \"}</Text>\n <Text color={COLORS.primary}>Tab</Text>\n <Text color={COLORS.textDim}> scope</Text>\n <Text color={COLORS.textDim}>{\" \"}</Text>\n <Text color={COLORS.primary}>⇧Tab</Text>\n <Text color={COLORS.textDim}> thinking</Text>\n <Text color={COLORS.textDim}>{\" \"}</Text>\n <Text color={COLORS.primary}>ESC</Text>\n <Text color={COLORS.textDim}> interrupt</Text>\n </Text>\n ) : (\n <Text color={COLORS.textDim}>{hint ?? \"\"}</Text>\n )}\n </Box>\n </Box>\n );\n}\n\nfunction GradientText({ text }: { text: string }): React.ReactElement {\n const chars: React.ReactNode[] = [];\n let colorIdx = 0;\n for (let i = 0; i < text.length; i++) {\n const ch = text[i];\n if (ch === \" \") {\n chars.push(ch);\n } else {\n const color = GRADIENT[colorIdx % GRADIENT.length];\n chars.push(\n <Text key={i} color={color}>\n {ch}\n </Text>,\n );\n colorIdx++;\n }\n }\n return <Text>{chars}</Text>;\n}\n","// Pull version from package.json so banner + boot output stay in sync with\n// what npm sees — bumping package.json now updates the TUI automatically.\nimport pkg from \"../package.json\" with { type: \"json\" };\n\nexport const VERSION = pkg.version;\nexport const BRAND = \"GG Boss\";\nexport const AUTHOR = \"Ken Kai\";\n\nexport const LOGO_LINES: readonly string[] = [\" ▄▀▀▀ ▄▀▀▀\", \" █ ▀█ █ ▀█\", \" ▀▄▄▀ ▀▄▄▀\"];\n\nexport const LOGO_GAP = \" \";\n\n/**\n * GG Boss brand gradient — crimson → fuchsia. Deliberately distinct:\n * - gg-coder is cool blues/violets\n * - gg-editor is warm oranges/yellows\n * - gg-boss is fiery reds/pinks/magentas\n *\n * Palindromic 12-stop sequence so the banner gradient animates smoothly\n * (read forward, then back).\n */\nexport const GRADIENT: readonly string[] = [\n \"#dc2626\", // red-600\n \"#e11d48\", // rose-600\n \"#be185d\", // pink-700\n \"#a21caf\", // fuchsia-700\n \"#c026d3\", // fuchsia-600\n \"#d946ef\", // fuchsia-500\n \"#c026d3\", // fuchsia-600 (back)\n \"#a21caf\", // fuchsia-700 (back)\n \"#be185d\", // pink-700 (back)\n \"#e11d48\", // rose-600 (back)\n \"#dc2626\", // red-600 (back)\n \"#b91c1c\", // red-700 (slight darker tail)\n];\n\n/**\n * Pulse colors for the activity-indicator spinner. Tighter loop than GRADIENT\n * so the spinner pulses crisply through the brand palette.\n */\nexport const PULSE_COLORS: readonly string[] = [\n \"#dc2626\", // crimson\n \"#e11d48\", // rose\n \"#be185d\", // wine\n \"#a21caf\", // magenta\n \"#c026d3\", // fuchsia\n \"#a21caf\", // back\n \"#be185d\", // back\n \"#e11d48\", // back\n];\n\nexport const COLORS = {\n primary: \"#e11d48\", // crimson-rose — main brand color\n accent: \"#d946ef\", // fuchsia — secondary\n text: \"#e2e8f0\",\n textDim: \"#6b7280\",\n success: \"#4ade80\",\n warning: \"#fbbf24\",\n error: \"#f87171\",\n} as const;\n\n/** Clear the entire scrollback + visible screen and reset cursor to home. */\nexport function clearScreen(): void {\n process.stdout.write(\"\\x1b[2J\\x1b[3J\\x1b[H\");\n}\n","{\n \"name\": \"@kenkaiiii/gg-boss\",\n \"version\": \"4.3.144\",\n \"type\": \"module\",\n \"description\": \"Orchestrator agent that drives multiple ggcoder sessions across projects from a single chat\",\n \"license\": \"MIT\",\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"git+https://github.com/kenkaiiii/gg-framework.git\",\n \"directory\": \"packages/gg-boss\"\n },\n \"bin\": {\n \"ggboss\": \"./dist/cli.js\"\n },\n \"exports\": {\n \".\": {\n \"import\": \"./dist/index.js\",\n \"types\": \"./dist/index.d.ts\"\n }\n },\n \"files\": [\n \"dist\"\n ],\n \"scripts\": {\n \"build\": \"tsup && cp -R assets/. dist/ && chmod +x dist/cli.js\",\n \"check\": \"tsc --noEmit\",\n \"test\": \"vitest run\"\n },\n \"devDependencies\": {\n \"@kenkaiiii/gg-agent\": \"workspace:*\",\n \"@kenkaiiii/gg-ai\": \"workspace:*\",\n \"@kenkaiiii/ggcoder\": \"workspace:*\",\n \"@types/node\": \"^25.6.0\",\n \"@types/react\": \"^19.2.14\",\n \"chalk\": \"^5.6.2\",\n \"ink\": \"^7.0.2\",\n \"react\": \"^19.2.5\",\n \"tsup\": \"^8.5.1\",\n \"typescript\": \"^6.0.3\",\n \"vitest\": \"^4.1.4\",\n \"zod\": \"^4.4.3\"\n },\n \"publishConfig\": {\n \"access\": \"public\"\n }\n}\n","import React, { useCallback, useEffect, useMemo, useRef, useState } from \"react\";\nimport { Box, Static, Text, render, useApp, useInput, useStdout } from \"ink\";\nimport { ThemeContext, loadTheme, useTheme } from \"@kenkaiiii/ggcoder/ui/theme\";\nimport {\n ActivityIndicator,\n AnimationProvider,\n AssistantMessage,\n CompactionDone,\n CompactionSpinner,\n InputArea,\n MessageResponse,\n ModelSelector,\n StreamingArea,\n ToolExecution,\n ToolUseLoader,\n UserMessage,\n useAnimationActive,\n useAnimationTick,\n} from \"@kenkaiiii/ggcoder/ui\";\nimport { useDoublePress } from \"@kenkaiiii/ggcoder/ui/hooks/double-press\";\nimport type { Provider } from \"@kenkaiiii/gg-ai\";\nimport { TerminalSizeProvider, useTerminalSize } from \"@kenkaiiii/ggcoder/ui/hooks/terminal-size\";\nimport { BossFooter } from \"./boss-footer.js\";\nimport { BossBanner } from \"./banner.js\";\nimport { bossStore, useBossState } from \"./boss-store.js\";\nimport type {\n AssistantItem,\n HistoryItem,\n StreamingTool,\n StreamingTurn,\n ToolItem,\n WorkerEventItem,\n WorkerErrorItem,\n WorkerView,\n} from \"./boss-store.js\";\nimport { BOSS_SLASH_COMMANDS, canonicalName, parseSlash, buildHelpText } from \"./slash-commands.js\";\nimport { bossToolFormatters } from \"./tool-formatters.js\";\nimport { projectColor } from \"./colors.js\";\nimport { BOSS_PHRASES } from \"./boss-phrases.js\";\nimport { COLORS, PULSE_COLORS as BOSS_PULSE_COLORS } from \"./branding.js\";\nimport { BossTasksOverlay } from \"./boss-tasks-overlay.js\";\nimport type { GGBoss } from \"./orchestrator.js\";\nimport { VERSION } from \"./branding.js\";\nimport { RadioPicker } from \"./radio-picker.js\";\nimport { getCurrentStation, playRadio, stopRadio, RADIO_STATIONS } from \"./radio.js\";\nimport {\n getPendingUpdate,\n startPeriodicUpdateCheck,\n stopPeriodicUpdateCheck,\n} from \"./auto-update.js\";\n\ninterface BannerRow {\n kind: \"banner\";\n id: string;\n}\ntype StaticRow = BannerRow | HistoryItem;\n\ninterface BossAppProps {\n boss: GGBoss;\n /**\n * Called from /clear to reset Ink's internal log-update tracking. Without\n * this, the simple `\\x1b[2J\\x1b[3J\\x1b[H + setStaticKey` dance leaves\n * log-update with stale prevLineCount + cursor offsets, which then\n * accumulate position errors on subsequent frames — exactly what we saw\n * as \"input pushed to top, new chats disappear\" after /clear.\n *\n * The cli wires this to `instance.clear()` from Ink's render() return\n * value: it writes ANSI clear AND zeroes log-update's frame state.\n */\n resetUI?: () => void;\n}\n\nexport function BossApp(props: BossAppProps): React.ReactElement {\n const theme = loadTheme(\"dark\");\n return (\n <TerminalSizeProvider>\n <ThemeContext.Provider value={theme}>\n <AnimationProvider>\n <BossAppInner {...props} />\n </AnimationProvider>\n </ThemeContext.Provider>\n </TerminalSizeProvider>\n );\n}\n\nfunction BossAppInner({ boss, resetUI }: BossAppProps): React.ReactElement {\n const state = useBossState();\n const { exit } = useApp();\n const { stdout } = useStdout();\n const { resizeKey, columns } = useTerminalSize();\n const runStartRef = useRef<number | null>(null);\n runStartRef.current = state.runStartMs;\n // Live char count of the current streaming text — drives ActivityIndicator's\n // smooth token-counter animation between turn_end events.\n const charCountRef = useRef<number>(0);\n charCountRef.current = state.streaming?.text.length ?? 0;\n // Accumulated real input tokens across completed turns — used alongside\n // charCountRef so the counter interpolates smoothly between hard updates.\n const realTokensAccumRef = useRef<number>(0);\n realTokensAccumRef.current = state.bossInputTokens;\n // Track the most recent user message so the activity bar's contextual phrase\n // selection has something to riff on (when not using BOSS_PHRASES override).\n const [lastUserMessage, setLastUserMessage] = useState<string>(\"\");\n const [overlay, setOverlay] = useState<\"model-boss\" | \"model-workers\" | \"tasks\" | \"radio\" | null>(\n null,\n );\n // Track the currently-playing station id so the picker can mark it with *\n // and so we have a reactive value for any future \"now playing\" indicator.\n // Seeded from the radio module's module-level state — usually null on\n // launch but resilient to a hot-restart of the React tree.\n const [currentRadio, setCurrentRadio] = useState<string | null>(() => getCurrentStation());\n // Bumped on /clear so <Static> remounts and re-emits its (now banner-only)\n // items into a freshly ANSI-wiped terminal. Mirrors ggcoder's pattern in\n // App.tsx — without the bump, Static's internal emit-set still thinks\n // every old chat row is \"already rendered\" and won't restore them.\n const [staticKey, setStaticKey] = useState(0);\n\n // Auto-update indicator: true when a newer version of @kenkaiiii/gg-boss\n // is on disk waiting for the next restart. Seeded synchronously from the\n // state file (so we show the indicator immediately if a previous session\n // queued one) and bumped to true by the periodic check below if a fresh\n // version drops mid-session.\n const [updatePending, setUpdatePending] = useState<boolean>(\n () => getPendingUpdate(VERSION) !== null,\n );\n\n // Periodic in-session check — pings npm every hour while the session is\n // alive. If a newer version arrives, we set updatePending so the worker\n // bar shows the \"✨ Update ready · restart to apply\" hint, AND drop a\n // friendly info row into chat so the user sees the news immediately.\n useEffect(() => {\n startPeriodicUpdateCheck(VERSION, (msg) => {\n bossStore.appendInfo(msg, \"info\");\n setUpdatePending(true);\n });\n return () => stopPeriodicUpdateCheck();\n }, []);\n\n // Terminal title — dynamically reflects worker activity so the user can\n // glance at the tab/window from another app and see how many workers are\n // still running. OSC 0 sets both window and tab title in most modern\n // terminals (Ghostty, Terminal.app, iTerm2, Kitty).\n //\n // States:\n // N workers running \"● 5 workers running · GG Boss\"\n // 1 worker running \"● 1 worker running · GG Boss\"\n // boss thinking only \"● GG Boss\"\n // idle \"GG Boss\"\n const workersRunning = state.workers.filter((w) => w.status === \"working\").length;\n const titlePrevRef = useRef(\"\");\n useEffect(() => {\n if (!stdout) return;\n let title: string;\n if (workersRunning > 0) {\n const label = `${workersRunning} worker${workersRunning === 1 ? \"\" : \"s\"} running`;\n title = `● ${label} · GG Boss`;\n } else if (state.phase === \"working\") {\n title = \"● GG Boss\";\n } else {\n title = \"GG Boss\";\n }\n if (title !== titlePrevRef.current) {\n titlePrevRef.current = title;\n stdout.write(`\\x1b]0;${title}\\x1b\\\\`);\n }\n }, [stdout, workersRunning, state.phase]);\n useEffect(() => {\n return () => {\n stdout?.write(`\\x1b]0;GG Boss\\x1b\\\\`);\n };\n }, [stdout]);\n\n const staticItems: StaticRow[] = useMemo(\n () => [{ kind: \"banner\", id: \"banner\" }, ...state.history],\n [state.history],\n );\n\n /**\n * No screen clears, no Static remounts. Just toggle React state.\n *\n * Banner is emitted ONCE on initial mount (Static's natural behavior — items\n * by id are emitted exactly once per Static instance lifetime). It lives in\n * scrollback forever after that, never re-emitted. So duplicate banners are\n * structurally impossible.\n *\n * The remaining concern is Ink's log-update cursor math when the live area\n * shrinks (tasks pane → chat chrome). log-update only clears within the\n * previous frame's footprint at the bottom of the viewport — it cannot\n * reach into scrollback. So banner + history in scrollback stay intact.\n */\n const openOverlay = useCallback(\n (next: \"tasks\" | \"model-boss\" | \"model-workers\" | \"radio\"): void => {\n setOverlay(next);\n },\n [],\n );\n\n const closeOverlay = useCallback((): void => {\n setOverlay(null);\n }, []);\n void stdout;\n\n // ggcoder's double-press pattern: 800ms window. First press shows\n // \"Press Ctrl+C again to exit\" in the footer; second within 800ms exits.\n const handleDoubleExit = useDoublePress(\n (pending) => bossStore.setExitPending(pending),\n () => exit(),\n );\n\n // Two-phase flush — see boss-store.ts for the rationale. Phase 1 (orchestrator\n // pushes into pendingFlush, live area shrinks) already happened; phase 2 here\n // commits to history on the next render so Ink doesn't clip long responses.\n useEffect(() => {\n if (state.pendingFlush.length > 0) {\n bossStore.commitPendingFlush();\n }\n }, [state.flushGeneration, state.pendingFlush.length]);\n\n // ── App-level keyboard ──────────────────────────────────\n // ESC: abort current boss call when working (InputArea handles otherwise).\n // Ctrl+T: toggle the Tasks overlay (matches ggcoder's keybind).\n useInput((input, key) => {\n if (key.ctrl && input === \"t\") {\n if (overlay === \"tasks\") closeOverlay();\n else openOverlay(\"tasks\");\n return;\n }\n if (key.escape && state.phase === \"working\") {\n boss.abort();\n }\n });\n\n const handleSlashCommand = async (value: string): Promise<boolean> => {\n const parsed = parseSlash(value);\n if (!parsed) return false;\n const name = canonicalName(parsed.name);\n if (!name) {\n bossStore.appendInfo(`Unknown command: /${parsed.name}`, \"warning\");\n return true;\n }\n switch (name) {\n case \"help\":\n bossStore.appendUser(value);\n // Render help via an assistant block so Markdown formatting + dot prefix.\n bossStore.appendInfo(buildHelpText(), \"info\");\n return true;\n case \"clear\":\n // resetUI() calls Ink's `instance.clear()` which (a) writes the\n // ANSI screen+scrollback clear and (b) zeroes log-update's internal\n // prevLineCount/cursor state. The second part is critical — without\n // it, every subsequent render drifts the cursor up by an\n // accumulating offset, manifesting as \"input keeps pushing to top\n // and new chats disappear\". Bare `\\x1b[...J` writes don't fix this\n // because log-update's tracking lives in JS, not in the terminal.\n resetUI?.();\n bossStore.clearHistory();\n await boss.resetConversation();\n setStaticKey((k) => k + 1);\n bossStore.appendInfo(\"Session cleared.\", \"info\");\n return true;\n case \"model-boss\":\n openOverlay(\"model-boss\");\n return true;\n case \"model-workers\":\n openOverlay(\"model-workers\");\n return true;\n case \"compact\":\n bossStore.appendUser(value);\n await boss.manualCompact();\n return true;\n case \"radio\":\n openOverlay(\"radio\");\n return true;\n case \"quit\":\n exit();\n return true;\n }\n return false;\n };\n\n const handleModelSelect = (value: string): void => {\n const colon = value.indexOf(\":\");\n if (colon < 0) {\n closeOverlay();\n return;\n }\n const provider = value.slice(0, colon) as Provider;\n const model = value.slice(colon + 1);\n if (overlay === \"model-boss\") {\n void boss.switchBossModel(provider, model);\n } else if (overlay === \"model-workers\") {\n void boss.switchWorkerModel(provider, model);\n }\n closeOverlay();\n };\n\n const handleSubmit = (value: string): void => {\n const trimmed = value.trim();\n if (!trimmed) return;\n if (trimmed.startsWith(\"/\") && !trimmed.startsWith(\"//\")) {\n void handleSlashCommand(trimmed);\n return;\n }\n // Show the user's literal text in chat history.\n bossStore.appendUser(trimmed);\n setLastUserMessage(trimmed);\n // Inject the scope pill into the message the boss actually sees, so the\n // user doesn't have to write \"for the yaatuber project, …\" every prompt.\n const scoped = scopePrefix(state.scope) + trimmed;\n boss.enqueueUserMessage(scoped);\n };\n\n const handleAbort = (): void => {\n // Ctrl+C while boss is running → single-press abort (matches ggcoder).\n if (state.phase === \"working\") {\n boss.abort();\n return;\n }\n // Boss is idle → double-press to exit, with footer pending message.\n handleDoubleExit();\n };\n\n return (\n <Box flexDirection=\"column\" width={columns}>\n {/* Static is mounted ONCE for the lifetime of the app and never remounts\n on overlay toggles. resizeKey still triggers a remount on terminal\n resize (which is necessary so the layout recomputes) — that's the\n only legitimate reason to drop and re-emit the scrollback. */}\n <Static key={`${resizeKey}-${staticKey}`} items={staticItems} style={{ width: \"100%\" }}>\n {(item) => (\n <Box key={item.id} flexDirection=\"column\" paddingRight={1}>\n <StaticRowView row={item} />\n </Box>\n )}\n </Static>\n\n {overlay === \"tasks\" ? (\n <BossTasksOverlay boss={boss} workers={state.workers} onClose={closeOverlay} />\n ) : (\n <>\n {state.streaming && (\n <StreamingTurnView turn={state.streaming} isRunning={state.phase === \"working\"} />\n )}\n {state.phase === \"working\" && (\n <Box marginTop={1}>\n <ActivityIndicator\n phase={state.activityPhase}\n elapsedMs={state.runStartMs ? Date.now() - state.runStartMs : 0}\n runStartRef={runStartRef as React.RefObject<number>}\n thinkingMs={state.streaming?.thinkingMs ?? 0}\n isThinking={state.activityPhase === \"thinking\"}\n tokenEstimate={state.bossInputTokens}\n charCountRef={charCountRef}\n realTokensAccumRef={realTokensAccumRef}\n userMessage={lastUserMessage}\n activeToolNames={(state.streaming?.tools ?? [])\n .filter((t) => t.status === \"running\")\n .map((t) => t.name)}\n retryInfo={state.retryInfo}\n phrases={BOSS_PHRASES}\n pulseColors={BOSS_PULSE_COLORS}\n />\n </Box>\n )}\n {state.compaction?.state === \"running\" && <CompactionSpinner />}\n {state.compaction?.state === \"done\" && (\n <CompactionDone\n originalCount={state.compaction.originalCount}\n newCount={state.compaction.newCount}\n tokensBefore={state.compaction.tokensBefore}\n tokensAfter={state.compaction.tokensAfter}\n />\n )}\n\n <InputArea\n onSubmit={handleSubmit}\n onAbort={handleAbort}\n disabled={state.phase === \"working\"}\n isActive={!overlay}\n cwd={process.cwd()}\n commands={BOSS_SLASH_COMMANDS}\n scopeBadge={<ScopePill scope={state.scope} />}\n // Mouse-tracking escape sequences cause Ghostty to emit phantom\n // pastes of the system clipboard during high-frequency UI updates\n // (workers running, shimmer animating). gg-boss's UI updates a lot,\n // so we forfeit click-to-position-cursor in the input to keep\n // the clipboard from leaking into the chat field.\n disableMouseTracking\n onTab={() => bossStore.cycleScope()}\n onShiftTab={() => {\n // Don't appendInfo — Static lives outside the overlay branch, so\n // any history row added here renders in scrollback above the\n // tasks pane and looks like it's inside it. The footer already\n // shows live \"Thinking on/off\" — that's the indicator.\n const next = state.bossThinkingLevel ? undefined : \"medium\";\n void boss.setBossThinking(next);\n }}\n />\n\n {overlay === \"model-boss\" || overlay === \"model-workers\" ? (\n <ModelSelector\n onSelect={handleModelSelect}\n onCancel={closeOverlay}\n loggedInProviders={state.loggedInProviders}\n currentModel={overlay === \"model-boss\" ? state.bossModel : state.workerModel}\n currentProvider={overlay === \"model-boss\" ? state.bossProvider : state.workerProvider}\n />\n ) : overlay === \"radio\" ? (\n <RadioPicker\n currentStationId={currentRadio}\n onCancel={closeOverlay}\n onSelect={(value) => {\n if (value === \"off\") {\n stopRadio();\n setCurrentRadio(null);\n bossStore.appendInfo(\"Radio off.\", \"info\");\n } else {\n const result = playRadio(value);\n if (result.ok) {\n setCurrentRadio(value);\n const station = RADIO_STATIONS.find((s) => s.id === value);\n bossStore.appendInfo(`Now playing: ${station?.name ?? value}`, \"info\");\n } else {\n bossStore.appendInfo(result.error ?? \"Radio failed to start.\", \"warning\");\n }\n }\n closeOverlay();\n }}\n />\n ) : (\n <>\n <BossFooter\n bossModel={state.bossModel}\n workerModel={state.workerModel}\n tokensIn={state.bossInputTokens}\n exitPending={state.exitPending}\n bossThinkingLevel={state.bossThinkingLevel}\n updatePending={updatePending}\n currentRadioStationId={currentRadio}\n />\n {!state.exitPending && (\n <WorkerStatusBar\n workers={state.workers}\n pendingMessages={state.pendingUserMessages}\n />\n )}\n </>\n )}\n </>\n )}\n </Box>\n );\n}\n\n// ── Scope pill (gg-boss specific) ──────────────────────────\n\nfunction ScopePill({ scope }: { scope: string }): React.ReactElement {\n const theme = useTheme();\n const isAll = scope === \"all\";\n // \"All\" → boss accent (fuchsia) so multi-project mode wears the brand.\n // Specific project → its stable project color so the pill matches its\n // appearances elsewhere in the TUI.\n const bg = isAll ? COLORS.accent : projectColor(scope);\n const label = isAll ? \"All\" : scope;\n // Black text reads cleanly on every color in the palette — the project hues\n // are deliberately light/saturated, which is unreadable with white on top.\n return (\n <Text>\n <Text color={theme.textDim}>Project </Text>\n <Text color=\"black\" backgroundColor={bg} bold>\n {` ${label} `}\n </Text>\n <Text color={theme.textDim}>\n {\" \"}\n <Text color={theme.primary}>Tab</Text>\n {\" to switch\"}\n </Text>\n </Text>\n );\n}\n\n/**\n * Prepend the active scope to the user's message before it reaches the boss.\n * Boss's system prompt teaches it to interpret these prefixes.\n */\nfunction scopePrefix(scope: string): string {\n if (scope === \"all\") return \"[scope:all] \";\n return `[scope:${scope}] `;\n}\n\n// ── Worker status row (gg-boss specific) ───────────────────\n\nconst SHIMMER_WIDTH = 3;\n\nfunction formatElapsed(ms: number): string {\n const total = Math.floor(ms / 1000);\n const m = Math.floor(total / 60);\n const s = total % 60;\n return `${m}:${s.toString().padStart(2, \"0\")}`;\n}\n\n/**\n * Mount this when (and only when) the shimmer needs to tick. AnimationProvider\n * stops the global timer when its subscriber count hits zero, so unmounting\n * this sentinel halts the 10Hz re-render loop while every worker is idle.\n */\nfunction AnimationActiveSentinel(): null {\n useAnimationActive();\n return null;\n}\n\n/**\n * Same shimmer pattern used by ggcoder's ActivityIndicator phrases — a bright\n * highlight band of width `SHIMMER_WIDTH` slides across the text while the\n * rest stays dim. Driven by the global animation tick.\n */\nfunction ShimmerName({\n name,\n color,\n tick,\n}: {\n name: string;\n color: string;\n tick: number;\n}): React.ReactElement {\n // Cycle covers the name length plus a SHIMMER_WIDTH-wide pre-roll/post-roll\n // so the bright band fully exits one side before re-entering the other.\n const cycle = name.length + SHIMMER_WIDTH * 2;\n const shimmerPos = (tick % cycle) - SHIMMER_WIDTH;\n return (\n <Text>\n {name.split(\"\").map((ch, i) => {\n const isBright = Math.abs(i - shimmerPos) <= SHIMMER_WIDTH;\n return (\n <Text key={i} color={color} bold={isBright} dimColor={!isBright}>\n {ch}\n </Text>\n );\n })}\n </Text>\n );\n}\n\nfunction WorkerStatusBar({\n workers,\n pendingMessages,\n}: {\n workers: WorkerView[];\n pendingMessages: number;\n}): React.ReactElement | null {\n const theme = useTheme();\n // Active-first layout: only working and errored workers get named slots.\n // Idle workers collapse into a single \"+N idle\" trailer so the bar scales\n // cleanly from 5 projects to 50. With 4 of 50 projects active, you see\n // four shimmering names + \"+46 idle\" instead of fifty repeated glyphs.\n const working = workers.filter((w) => w.status === \"working\");\n const errored = workers.filter((w) => w.status === \"error\");\n const idleCount = workers.length - working.length - errored.length;\n const anyWorking = working.length > 0;\n // Passive tick consumer — when no Sentinel is mounted (no working worker),\n // the global timer is paused and the tick value stops changing, so this\n // component doesn't re-render at 10Hz when everything is idle.\n const tick = useAnimationTick();\n const now = Date.now();\n\n if (workers.length === 0) return null;\n // Render order: working (shimmer + timer) → errored (✗ + name) → idle\n // count (dim \"N idle\"). The shimmer + project hue already announce\n // \"active\" — no need for a leading ● dot. The errored ✗ stays because\n // colour alone isn't enough to call out a stuck worker. The idle slot\n // keeps the ○ as a glyph-only quantifier (\"○ 17\"). Separator: thin\n // vertical bar, matching the footer's style.\n const slots: React.ReactElement[] = [];\n for (const w of working) {\n const projectHue = projectColor(w.name);\n const elapsed = w.workStartedAt ? formatElapsed(now - w.workStartedAt) : null;\n slots.push(\n <React.Fragment key={`w-${w.name}`}>\n <ShimmerName name={w.name} color={projectHue} tick={tick} />\n {elapsed && <Text color={theme.textDim}> {elapsed}</Text>}\n </React.Fragment>,\n );\n }\n for (const w of errored) {\n slots.push(\n <React.Fragment key={`e-${w.name}`}>\n <Text color={theme.error}>✗ {w.name}</Text>\n </React.Fragment>,\n );\n }\n if (idleCount > 0) {\n slots.push(\n <React.Fragment key=\"idle\">\n <Text color={theme.textDim}>○ {idleCount} idle</Text>\n </React.Fragment>,\n );\n }\n return (\n <Box paddingX={1}>\n {anyWorking && <AnimationActiveSentinel />}\n {slots.map((slot, i) => (\n <React.Fragment key={i}>\n {i > 0 && <Text color={theme.border}>{\" │ \"}</Text>}\n {slot}\n </React.Fragment>\n ))}\n {pendingMessages > 0 && (\n <>\n <Text color={theme.textDim}>{\" \"}</Text>\n <Text color={theme.warning}>\n {pendingMessages} message{pendingMessages === 1 ? \"\" : \"s\"} queued\n </Text>\n </>\n )}\n </Box>\n );\n}\n\n// ── Row dispatch ───────────────────────────────────────────\n\nfunction StaticRowView({ row }: { row: StaticRow }): React.ReactElement | null {\n if (row.kind === \"banner\") {\n return (\n <Box paddingX={1}>\n <BossBanner subtitle=\"Orchestrator\" showShortcuts />\n </Box>\n );\n }\n if (row.kind === \"user\") return <UserMessage text={row.text} />;\n if (row.kind === \"assistant\") return <AssistantRow item={row} />;\n if (row.kind === \"tool\") return <ToolHistoryRow item={row} />;\n if (row.kind === \"worker_event\") return <WorkerEventRow item={row} />;\n if (row.kind === \"worker_error\") return <WorkerErrorRow item={row} />;\n if (row.kind === \"info\") return <InfoRow text={row.text} level={row.level ?? \"info\"} />;\n if (row.kind === \"task_dispatch\") return <TaskDispatchRow tasks={row.tasks} />;\n return null;\n}\n\nfunction TaskDispatchRow({\n tasks,\n}: {\n tasks: { project: string; title: string }[];\n}): React.ReactElement {\n const theme = useTheme();\n const count = tasks.length;\n return (\n <Box flexDirection=\"column\" paddingX={1} marginTop={1}>\n <Text>\n <Text color={COLORS.primary} bold>\n {\"⏺ \"}\n </Text>\n <Text color={theme.text} bold>\n Running {count} task{count === 1 ? \"\" : \"s\"}\n {\":\"}\n </Text>\n </Text>\n {tasks.map((t, i) => (\n <Text key={`${t.project}-${i}`}>\n <Text color={theme.textDim}>{\" • \"}</Text>\n <Text color={projectColor(t.project)} bold>\n {t.project}\n </Text>\n <Text color={theme.textDim}>{\": \"}</Text>\n <Text color={theme.text}>{t.title}</Text>\n </Text>\n ))}\n </Box>\n );\n}\n\n/**\n * Auto-highlight common keyboard shortcuts in any boss-written prose by\n * wrapping them in backticks before passing to the Markdown renderer (which\n * styles inline code with a distinctive color/background). Catches things\n * like Ctrl+T, Shift+Tab, Cmd+K, Esc, F-keys, arrow-key combos. The boss may\n * already wrap them itself — these regexes deliberately skip text that's\n * already inside backticks (or fenced blocks) so we don't double-wrap.\n */\nconst SHORTCUT_PATTERNS: RegExp[] = [\n // Modifier+Key combos: Ctrl+T, Shift+Tab, Cmd+K, Ctrl+Shift+P, Ctrl+C\n /\\b(?:Ctrl|Cmd|Alt|Option|Opt|Shift|Meta|Win|Super)(?:\\s*\\+\\s*(?:Ctrl|Cmd|Alt|Option|Opt|Shift|Meta|Win|Super))*\\s*\\+\\s*(?:Tab|Enter|Esc|Escape|Space|Backspace|Delete|Del|Home|End|PageUp|PageDown|Up|Down|Left|Right|F[1-9]|F1[0-2]|[A-Z0-9]|\\/|\\?|\\.|,|;|=|-)\\b/g,\n // Bare named keys (only when surrounded by clear key context)\n /\\b(?:Ctrl-[A-Z]|F[1-9]|F1[0-2])\\b/g,\n];\n\nfunction highlightShortcuts(text: string): string {\n if (!text) return text;\n // Mask code spans + fenced blocks so we don't try to re-wrap shortcuts that\n // are already in backtick territory. The sentinel uses a private-use unicode\n // codepoint so it can't realistically collide with anything the boss writes.\n const SENTINEL = \"\";\n const masks: string[] = [];\n let masked = text.replace(/```[\\s\\S]*?```|`[^`]+`/g, (m) => {\n const idx = masks.push(m) - 1;\n return `${SENTINEL}${idx}${SENTINEL}`;\n });\n for (const re of SHORTCUT_PATTERNS) {\n masked = masked.replace(re, (m) => `\\`${m}\\``);\n }\n return masked.replace(\n new RegExp(`${SENTINEL}(\\\\d+)${SENTINEL}`, \"g\"),\n (_, i) => masks[Number(i)]!,\n );\n}\n\nfunction AssistantRow({ item }: { item: AssistantItem }): React.ReactElement {\n return (\n <AssistantMessage\n text={highlightShortcuts(item.text)}\n thinking={item.thinking}\n thinkingMs={item.thinkingMs}\n />\n );\n}\n\nfunction ToolHistoryRow({ item }: { item: ToolItem }): React.ReactElement {\n return (\n <ToolExecution\n status=\"done\"\n name={item.name}\n args={item.args}\n result={item.result}\n isError={item.isError}\n details={item.details}\n formatters={bossToolFormatters}\n />\n );\n}\n\n// ── Worker rows (gg-boss specific) ─────────────────────────\n\ntype WorkerStatusGrade = \"DONE\" | \"UNVERIFIED\" | \"PARTIAL\" | \"BLOCKED\" | \"INFO\";\n\n/**\n * Pull the `Status:` line out of a worker's final text (the brief in\n * tools.ts asks every worker to end with one of: DONE | UNVERIFIED |\n * PARTIAL | BLOCKED | INFO). Returns null if the line is missing or invalid.\n */\nfunction parseStatusGrade(text: string): WorkerStatusGrade | null {\n // Use the LAST occurrence of \"Status: X\" (some workers explain status\n // mid-text and re-emit it in the trailer). Also accept anything after the\n // grade word — workers occasionally write \"Status: INFO — trailing comment\"\n // which the previous end-of-line anchor would have rejected.\n const matches = [...text.matchAll(/^\\s*Status:\\s*(DONE|UNVERIFIED|PARTIAL|BLOCKED|INFO)\\b/gim)];\n const last = matches[matches.length - 1];\n if (!last) return null;\n return last[1]!.toUpperCase() as WorkerStatusGrade;\n}\n\ninterface WorkerTrailer {\n changed?: string;\n skipped?: string;\n verified?: string;\n notes?: string;\n}\n\n/**\n * Pull the structured fields out of the worker's reply trailer (appended by\n * WORKER_PROMPT_BRIEF). Each field is captured up to (but not including) the\n * next field marker or end-of-text.\n */\nfunction parseWorkerTrailer(text: string): WorkerTrailer {\n const out: WorkerTrailer = {};\n const grab = (label: string): string | undefined => {\n // Match \"Label: value\" up to the next \"Label:\" line or end. Multi-line.\n const re = new RegExp(\n `^\\\\s*${label}:\\\\s*([\\\\s\\\\S]*?)(?=^\\\\s*(?:Changed|Skipped|Verified|Notes|Status):|$)`,\n \"im\",\n );\n const m = re.exec(text);\n if (!m) return undefined;\n const v = m[1]!\n .replace(/```[\\s\\S]*?```/g, \"[code]\")\n .replace(/`([^`]+)`/g, \"$1\")\n .replace(/\\s+/g, \" \")\n .trim();\n return v.length > 0 ? v : undefined;\n };\n out.changed = grab(\"Changed\");\n out.skipped = grab(\"Skipped\");\n out.verified = grab(\"Verified\");\n out.notes = grab(\"Notes\");\n return out;\n}\n\nfunction clip(text: string, maxLen: number): string {\n return text.length <= maxLen ? text : text.slice(0, Math.max(1, maxLen - 1)) + \"…\";\n}\n\n/**\n * Build a one-line summary from the trailer. Prefers the substantive fields\n * (Changed, Verified, Notes) that actually tell the user what happened — not\n * the worker's preamble like \"I'll start by detecting...\". Falls back to\n * first-sentence-of-preamble only when the trailer is empty (non-conforming\n * worker reply).\n */\nfunction summarizeFinalText(text: string, maxLen: number): string {\n if (!text) return \"\";\n const trailer = parseWorkerTrailer(text);\n const parts: string[] = [];\n if (trailer.changed) parts.push(`Changed: ${trailer.changed}`);\n if (trailer.verified) parts.push(`Verified: ${trailer.verified}`);\n if (trailer.skipped) parts.push(`Skipped: ${trailer.skipped}`);\n if (trailer.notes) parts.push(`Notes: ${trailer.notes}`);\n if (parts.length > 0) return clip(parts.join(\" · \"), maxLen);\n\n // No trailer — fall back to the first sentence of the response body.\n const beforeSummary = text.split(/^Changed:|^Skipped:|^Verified:|^Notes:|^Status:/im)[0];\n const stripped = beforeSummary\n .replace(/```[\\s\\S]*?```/g, \"[code]\")\n .replace(/`([^`]+)`/g, \"$1\")\n .replace(/\\*\\*([^*]+)\\*\\*/g, \"$1\")\n .replace(/\\*([^*]+)\\*/g, \"$1\")\n .replace(/^\\s*[-*]\\s+/gm, \"\")\n .replace(/^#+\\s+/gm, \"\")\n .replace(/\\s+/g, \" \")\n .trim();\n if (!stripped) return \"\";\n const firstSentence = stripped.match(/^[^.!?\\n]+[.!?]/);\n return clip(firstSentence ? firstSentence[0] : stripped, maxLen);\n}\n\nfunction statusGradeColor(\n grade: WorkerStatusGrade | null,\n theme: ReturnType<typeof useTheme>,\n): string {\n switch (grade) {\n case \"DONE\":\n return theme.success;\n case \"UNVERIFIED\":\n case \"PARTIAL\":\n return theme.warning;\n case \"BLOCKED\":\n return theme.error;\n case \"INFO\":\n return theme.textDim;\n default:\n return theme.textDim;\n }\n}\n\nfunction WorkerEventRow({ item }: { item: WorkerEventItem }): React.ReactElement {\n const theme = useTheme();\n const { columns } = useTerminalSize();\n const failedCount = item.toolsUsed.filter((t) => !t.ok).length;\n const total = item.toolsUsed.length;\n const grade = parseStatusGrade(item.finalText);\n // Loader status: prefer the worker's self-reported grade. Fall back to\n // tool-error count if the worker omitted Status (older runs / non-conforming).\n const loaderStatus =\n grade === \"BLOCKED\" || failedCount > 0\n ? \"error\"\n : grade === \"UNVERIFIED\" || grade === \"PARTIAL\"\n ? \"queued\"\n : \"done\";\n // Errors override the project hue with red; otherwise the project gets its\n // stable color so successive turns from the same worker visually cluster.\n const headerColor = loaderStatus === \"error\" ? theme.toolError : projectColor(item.project);\n const toolSummary =\n total === 0\n ? \"no tools\"\n : failedCount > 0\n ? `${total} tools (${failedCount} failed)`\n : `${total} tool${total === 1 ? \"\" : \"s\"}`;\n // MessageResponse uses 6 chars for \" ⎿ \" gutter; reserve a few more for\n // safety. Each trailer field renders on its own line so users can scan\n // Changed / Verified / Notes independently rather than a single squished line.\n const fieldMaxLen = Math.max(20, columns - 14);\n const trailer = parseWorkerTrailer(item.finalText);\n const hasTrailer = !!(trailer.changed || trailer.skipped || trailer.verified || trailer.notes);\n const fallbackSummary = hasTrailer ? \"\" : summarizeFinalText(item.finalText, fieldMaxLen);\n return (\n <Box flexDirection=\"column\" marginTop={1}>\n <Box flexDirection=\"row\">\n <ToolUseLoader status={loaderStatus} />\n <Box flexGrow={1}>\n <Text wrap=\"wrap\">\n <Text color={headerColor} bold>\n {item.project}\n </Text>\n <Text color={theme.text}>{` turn ${item.turnIndex}`}</Text>\n <Text color={theme.textDim}>{` · ${toolSummary}`}</Text>\n {grade && (\n <>\n <Text color={theme.textDim}>{\" · \"}</Text>\n <Text color={statusGradeColor(grade, theme)} bold>\n {grade}\n </Text>\n </>\n )}\n </Text>\n </Box>\n </Box>\n {hasTrailer ? (\n <>\n {trailer.changed && (\n <TrailerLine label=\"Changed\" value={trailer.changed} maxLen={fieldMaxLen} />\n )}\n {trailer.verified && (\n <TrailerLine\n label=\"Verified\"\n value={trailer.verified}\n maxLen={fieldMaxLen}\n labelColor={theme.success}\n />\n )}\n {trailer.skipped && (\n <TrailerLine\n label=\"Skipped\"\n value={trailer.skipped}\n maxLen={fieldMaxLen}\n labelColor={theme.warning}\n />\n )}\n {trailer.notes && (\n <TrailerLine label=\"Notes\" value={trailer.notes} maxLen={fieldMaxLen} />\n )}\n </>\n ) : (\n fallbackSummary && (\n <MessageResponse>\n <Text color={theme.textDim} wrap=\"truncate\">\n {fallbackSummary}\n </Text>\n </MessageResponse>\n )\n )}\n </Box>\n );\n}\n\nfunction TrailerLine({\n label,\n value,\n maxLen,\n labelColor,\n}: {\n label: string;\n value: string;\n maxLen: number;\n labelColor?: string;\n}): React.ReactElement {\n const theme = useTheme();\n return (\n <MessageResponse>\n <Text wrap=\"truncate\">\n <Text color={labelColor ?? theme.textDim} bold>\n {label}:\n </Text>\n <Text color={theme.text}>{` ${clip(value, maxLen - label.length - 2)}`}</Text>\n </Text>\n </MessageResponse>\n );\n}\n\nfunction WorkerErrorRow({ item }: { item: WorkerErrorItem }): React.ReactElement {\n const theme = useTheme();\n return (\n <Box flexDirection=\"column\" marginTop={1}>\n <Box flexDirection=\"row\">\n <ToolUseLoader status=\"error\" />\n <Box flexGrow={1}>\n <Text wrap=\"wrap\">\n <Text color={theme.toolError} bold>\n {item.project}\n </Text>\n <Text color={theme.textDim}>{\" worker error\"}</Text>\n </Text>\n </Box>\n </Box>\n <MessageResponse>\n <Text color={theme.error} wrap=\"wrap\">\n {item.message}\n </Text>\n </MessageResponse>\n </Box>\n );\n}\n\nfunction InfoRow({\n text,\n level,\n}: {\n text: string;\n level: \"info\" | \"warning\" | \"error\";\n}): React.ReactElement {\n // info → render through AssistantMessage so it gets the dot + Markdown.\n if (level === \"info\") return <AssistantMessage text={text} />;\n // warning / error → match the ToolUseLoader chrome so the row reads as a\n // first-class event (consistent with worker errors / failed tool calls)\n // rather than bare colored text.\n const theme = useTheme();\n const color = level === \"error\" ? theme.error : theme.warning;\n return (\n <Box marginTop={1} flexDirection=\"row\">\n <ToolUseLoader status={level === \"error\" ? \"error\" : \"queued\"} />\n <Box flexGrow={1}>\n <Text color={color} wrap=\"wrap\">\n {text}\n </Text>\n </Box>\n </Box>\n );\n}\n\n// ── Streaming (live) ───────────────────────────────────────\n\nfunction StreamingTurnView({\n turn,\n isRunning,\n}: {\n turn: StreamingTurn;\n isRunning: boolean;\n}): React.ReactElement {\n return (\n <Box flexDirection=\"column\">\n <StreamingArea\n isRunning={isRunning}\n streamingText={turn.text}\n streamingThinking={turn.thinking}\n thinkingMs={turn.thinkingMs}\n />\n {turn.tools.map((t) => (\n <StreamingToolRow key={t.toolCallId} tool={t} />\n ))}\n </Box>\n );\n}\n\nfunction StreamingToolRow({ tool }: { tool: StreamingTool }): React.ReactElement {\n if (tool.status === \"running\") {\n return (\n <ToolExecution\n status=\"running\"\n name={tool.name}\n args={tool.args}\n formatters={bossToolFormatters}\n />\n );\n }\n return (\n <ToolExecution\n status=\"done\"\n name={tool.name}\n args={tool.args}\n result={tool.result ?? \"\"}\n isError={tool.status === \"error\"}\n details={tool.details}\n formatters={bossToolFormatters}\n />\n );\n}\n\n// ── Renderer ───────────────────────────────────────────────\n\nexport interface RenderBossAppOptions {\n boss: GGBoss;\n}\n\nexport function renderBossApp(opts: RenderBossAppOptions): {\n waitUntilExit: () => Promise<void>;\n unmount: () => void;\n} {\n // We need a forward reference: BossApp's resetUI prop wants to call into\n // the Ink instance, but `instance` doesn't exist until after render() is\n // invoked. Closing over a holder lets the prop see the instance once it's\n // assigned, without restructuring the whole BossApp tree.\n const ref: { instance: ReturnType<typeof render> | null } = { instance: null };\n // The published `instance.clear()` is the WRONG primitive here. It calls\n // log.clear() (good — moves cursor up, erases, sets prevLineCount=0) but\n // then IMMEDIATELY calls log.sync(lastOutput) which restores prevLineCount\n // back to the previous frame's height. Net effect: from log-update's view,\n // the screen still has the old content drawn. Subsequent renders compute\n // cursor.up() based on that stale count, drift the cursor up over real\n // content, and produce the \"input pushed to top\" symptom.\n //\n // Reaching into the private `log` reset() is the only way to actually\n // zero log-update state without log.sync clobbering it back. The cast\n // is intentional — Ink's public types don't surface this, but the field\n // exists on every Ink version we support and is stable between releases.\n const resetUI = (): void => {\n const inst = ref.instance;\n if (!inst) return;\n // 1. ANSI wipe terminal scrollback + viewport.\n process.stdout.write(\"\\x1b[2J\\x1b[3J\\x1b[H\");\n // 2. Force log-update internal state to zero so the next render writes\n // fresh from cursor row 0 instead of trying to undo a phantom prior\n // frame.\n const log = (inst as unknown as { log?: { reset?: () => void } }).log;\n log?.reset?.();\n };\n const instance = render(<BossApp boss={opts.boss} resetUI={resetUI} />, {\n // Disable Ink's built-in exit-on-Ctrl+C — we need our own double-press\n // handler in BossApp to drive the \"Press Ctrl+C again to exit\" footer\n // message. With this flag true (the default), Ink kills the process on\n // the very first Ctrl+C and InputArea's onAbort never runs.\n exitOnCtrlC: false,\n });\n ref.instance = instance;\n return {\n waitUntilExit: async () => {\n await instance.waitUntilExit();\n },\n unmount: () => instance.unmount(),\n };\n}\n","export {\n AnimationProvider,\n useAnimationTick,\n useAnimationActive,\n deriveFrame,\n} from \"./AnimationContext.js\";\nexport { Spinner } from \"./Spinner.js\";\nexport { UserMessage } from \"./UserMessage.js\";\nexport { AssistantMessage } from \"./AssistantMessage.js\";\nexport { DiffView } from \"./DiffView.js\";\nexport { ToolExecution, type ToolExecutionFormatters } from \"./ToolExecution.js\";\nexport { ToolUseLoader } from \"./ToolUseLoader.js\";\nexport { MessageResponse } from \"./MessageResponse.js\";\nexport { Footer } from \"./Footer.js\";\nexport { StreamingArea } from \"./StreamingArea.js\";\nexport { InputArea } from \"./InputArea.js\";\nexport { Overlay } from \"./Overlay.js\";\nexport { SelectList } from \"./SelectList.js\";\nexport { ModelSelector } from \"./ModelSelector.js\";\nexport { SessionSelector } from \"./SessionSelector.js\";\nexport { SettingsSelector } from \"./SettingsSelector.js\";\nexport { Markdown } from \"./Markdown.js\";\nexport { ThinkingBlock } from \"./ThinkingBlock.js\";\nexport { ThinkingIndicator } from \"./ThinkingIndicator.js\";\nexport { ActivityIndicator } from \"./ActivityIndicator.js\";\nexport { SlashCommandMenu, type SlashCommandInfo } from \"./SlashCommandMenu.js\";\nexport { Banner } from \"./Banner.js\";\nexport { CompactionSpinner, CompactionDone } from \"./CompactionNotice.js\";\nexport type { ActivityPhase, RetryInfo } from \"../hooks/useAgentLoop.js\";\n","import React from \"react\";\nimport { Text, Box } from \"ink\";\nimport { useTheme } from \"../theme/theme.js\";\n\nconst MAX_DISPLAY_LINES = 20;\n\nexport function DiffView({ diff }: { diff: string }) {\n const theme = useTheme();\n const lines = diff.split(\"\\n\");\n const truncated = lines.length > MAX_DISPLAY_LINES;\n const displayLines = truncated ? lines.slice(0, MAX_DISPLAY_LINES) : lines;\n\n return (\n <Box flexDirection=\"column\" marginLeft={2}>\n {displayLines.map((line, i) => {\n let color = theme.diffContext;\n if (line.startsWith(\"+\")) color = theme.diffAdded;\n else if (line.startsWith(\"-\")) color = theme.diffRemoved;\n\n return (\n <Text key={i} color={color}>\n {line}\n </Text>\n );\n })}\n {truncated && (\n <Text color={theme.textDim}>... ({lines.length - MAX_DISPLAY_LINES} more lines)</Text>\n )}\n </Box>\n );\n}\n","import React from \"react\";\nimport { Box, Text } from \"ink\";\nimport { useTheme } from \"../theme/theme.js\";\n\ninterface OverlayProps {\n title: string;\n children: React.ReactNode;\n}\n\nexport function Overlay({ title, children }: OverlayProps) {\n const theme = useTheme();\n\n return (\n <Box flexDirection=\"column\" borderStyle=\"round\" borderColor={theme.border} paddingX={1}>\n <Box marginBottom={1}>\n <Text color={theme.primary} bold>\n {title}\n </Text>\n </Box>\n {children}\n </Box>\n );\n}\n","import React from \"react\";\nimport type { SessionInfo } from \"../../core/session-manager.js\";\nimport { Overlay } from \"./Overlay.js\";\nimport { SelectList } from \"./SelectList.js\";\n\ninterface SessionSelectorProps {\n sessions: SessionInfo[];\n onSelect: (sessionPath: string) => void;\n onCancel: () => void;\n}\n\nexport function SessionSelector({ sessions, onSelect, onCancel }: SessionSelectorProps) {\n const items = sessions.map((s) => ({\n label: `${s.id.slice(0, 8)} — ${s.timestamp}`,\n value: s.path,\n description: `${s.messageCount} messages`,\n }));\n\n return (\n <Overlay title=\"Select Session\">\n <SelectList items={items} onSelect={onSelect} onCancel={onCancel} />\n </Overlay>\n );\n}\n","import React from \"react\";\nimport type { Settings } from \"../../core/settings-manager.js\";\nimport { Overlay } from \"./Overlay.js\";\nimport { SelectList } from \"./SelectList.js\";\n\ninterface SettingsSelectorProps {\n settings: Settings;\n onSelect: (key: string) => void;\n onCancel: () => void;\n}\n\nexport function SettingsSelector({ settings, onSelect, onCancel }: SettingsSelectorProps) {\n const items = Object.entries(settings).map(([key, value]) => ({\n label: key,\n value: key,\n description: String(value),\n }));\n\n return (\n <Overlay title=\"Settings\">\n <SelectList items={items} onSelect={onSelect} onCancel={onCancel} />\n </Overlay>\n );\n}\n","import React, { useMemo } from \"react\";\nimport { Text, Box } from \"ink\";\nimport { useTheme } from \"../theme/theme.js\";\n\nimport { SPINNER_FRAMES, SPINNER_INTERVAL } from \"../spinner-frames.js\";\nimport { useAnimationTick, useAnimationActive, deriveFrame } from \"./AnimationContext.js\";\n\n// ── Color pulse cycle ─────────────────────────────────────\n\nconst PULSE_COLORS = [\n \"#60a5fa\", // blue\n \"#818cf8\", // indigo\n \"#a78bfa\", // violet\n \"#818cf8\", // indigo (back)\n \"#60a5fa\", // blue (back)\n \"#38bdf8\", // sky\n \"#60a5fa\", // blue (back)\n];\nconst PULSE_INTERVAL = 400;\n\n// ── Ellipsis animation ────────────────────────────────────\n\nconst ELLIPSIS_FRAMES = [\"\", \".\", \"..\", \"...\"];\nconst ELLIPSIS_INTERVAL = 500;\n\n// ── Phrase rotation ───────────────────────────────────────\n\nconst PHRASE_INTERVAL = 3000;\n\ninterface PhraseSet {\n keywords: RegExp;\n phrases: string[];\n}\n\nconst CONTEXTUAL_PHRASES: PhraseSet[] = [\n {\n keywords: /\\b(bug|fix|error|issue|broken|crash|fail|wrong)\\b/i,\n phrases: [\n \"Investigating\",\n \"Diagnosing\",\n \"Tracing the issue\",\n \"Hunting the bug\",\n \"Analyzing the problem\",\n \"Narrowing it down\",\n ],\n },\n {\n keywords: /\\b(refactor|clean|improve|optimize|simplify|restructure)\\b/i,\n phrases: [\n \"Studying the code\",\n \"Planning improvements\",\n \"Mapping dependencies\",\n \"Finding patterns\",\n \"Designing the approach\",\n ],\n },\n {\n keywords: /\\b(test|spec|coverage|assert|expect|describe|it\\()\\b/i,\n phrases: [\n \"Designing tests\",\n \"Thinking about edge cases\",\n \"Planning test coverage\",\n \"Considering scenarios\",\n ],\n },\n {\n keywords: /\\b(build|deploy|ci|cd|pipeline|docker|config)\\b/i,\n phrases: [\n \"Checking the config\",\n \"Analyzing the pipeline\",\n \"Working through setup\",\n \"Reviewing the build\",\n ],\n },\n {\n keywords: /\\b(style|css|ui|layout|design|color|theme|display|render)\\b/i,\n phrases: [\n \"Visualizing the layout\",\n \"Crafting the design\",\n \"Considering the aesthetics\",\n \"Sketching it out\",\n \"Polishing the pixels\",\n ],\n },\n {\n keywords: /\\b(add|create|new|implement|feature|make|build)\\b/i,\n phrases: [\n \"Architecting\",\n \"Drafting the approach\",\n \"Planning the implementation\",\n \"Mapping it out\",\n \"Designing the solution\",\n ],\n },\n {\n keywords: /\\b(explain|how|why|what|understand|describe)\\b/i,\n phrases: [\n \"Reading through the code\",\n \"Connecting the dots\",\n \"Building understanding\",\n \"Tracing the logic\",\n \"Piecing it together\",\n ],\n },\n];\n\nconst GENERAL_PHRASES = [\n \"Thinking\",\n \"Reasoning\",\n \"Processing\",\n \"Mulling it over\",\n \"Working on it\",\n \"Contemplating\",\n \"Figuring it out\",\n \"Crunching\",\n \"Assembling thoughts\",\n \"Cooking up a plan\",\n \"Brewing ideas\",\n \"Spinning up neurons\",\n \"Loading wisdom\",\n \"Parsing the universe\",\n \"Channeling clarity\",\n];\n\nfunction selectPhrases(userMessage: string): string[] {\n for (const set of CONTEXTUAL_PHRASES) {\n if (set.keywords.test(userMessage)) {\n return [...set.phrases, ...GENERAL_PHRASES.slice(0, 3)];\n }\n }\n return GENERAL_PHRASES;\n}\n\nfunction shuffleArray<T>(arr: T[]): T[] {\n const shuffled = [...arr];\n for (let i = shuffled.length - 1; i > 0; i--) {\n const j = Math.floor(Math.random() * (i + 1));\n [shuffled[i], shuffled[j]] = [shuffled[j], shuffled[i]];\n }\n return shuffled;\n}\n\n// ── Component ─────────────────────────────────────────────\n\ninterface ThinkingIndicatorProps {\n userMessage?: string;\n}\n\nexport function ThinkingIndicator({ userMessage = \"\" }: ThinkingIndicatorProps) {\n const theme = useTheme();\n useAnimationActive();\n const tick = useAnimationTick();\n\n // Derive all animation frames from the single global tick\n const spinnerFrame = deriveFrame(tick, SPINNER_INTERVAL, SPINNER_FRAMES.length);\n const colorFrame = deriveFrame(tick, PULSE_INTERVAL, PULSE_COLORS.length);\n const ellipsisFrame = deriveFrame(tick, ELLIPSIS_INTERVAL, ELLIPSIS_FRAMES.length);\n\n // Phrase rotation — pick phrases based on user message, shuffle, rotate\n const phrases = useMemo(() => shuffleArray(selectPhrases(userMessage)), [userMessage]);\n const phraseIndex = deriveFrame(tick, PHRASE_INTERVAL, phrases.length);\n\n const spinnerColor = PULSE_COLORS[colorFrame];\n const phrase = phrases[phraseIndex];\n const ellipsis = ELLIPSIS_FRAMES[ellipsisFrame];\n // Pad ellipsis to prevent text from shifting\n const paddedEllipsis = ellipsis + \" \".repeat(3 - ellipsis.length);\n\n return (\n <Box>\n <Text color={spinnerColor} bold>\n {SPINNER_FRAMES[spinnerFrame]}{\" \"}\n </Text>\n <Text color={spinnerColor} bold>\n {phrase}\n </Text>\n <Text color={theme.textDim}>{paddedEllipsis}</Text>\n </Box>\n );\n}\n","import React from \"react\";\nimport { Text, Box } from \"ink\";\nimport { useTheme } from \"@kenkaiiii/ggcoder/ui/theme\";\nimport { useTerminalSize } from \"@kenkaiiii/ggcoder/ui/hooks/terminal-size\";\nimport { getContextWindow } from \"@kenkaiiii/ggcoder\";\nimport { COLORS } from \"./branding.js\";\n\nconst PARTIAL_BLOCKS = [\" \", \"▏\", \"▎\", \"▍\", \"▌\", \"▋\", \"▊\", \"▉\", \"█\"];\nconst LIGHT_SHADE = \"░\";\n\nconst SHORT_MODELS: Record<string, string> = {\n \"claude-opus-4-7\": \"Opus\",\n \"claude-sonnet-4-6\": \"Sonnet\",\n \"claude-haiku-4-5\": \"Haiku\",\n \"claude-haiku-4-5-20251001\": \"Haiku\",\n \"gpt-5.5\": \"GPT-5.5\",\n \"gpt-5.5-pro\": \"GPT-5.5 Pro\",\n \"gpt-5.4\": \"GPT-5.4\",\n \"gpt-5.4-mini\": \"GPT-5.4 Mini\",\n \"gpt-5.3-codex\": \"GPT-5.3 Codex\",\n};\n\nfunction shortModel(model: string): string {\n return SHORT_MODELS[model] ?? model;\n}\n\nfunction getContextPercent(model: string, tokensIn: number): number {\n const limit = getContextWindow(model);\n if (!limit || tokensIn === 0) return 0;\n return Math.round((tokensIn / limit) * 100);\n}\n\ninterface BossFooterProps {\n bossModel: string;\n workerModel: string;\n /** Total input tokens of the boss's last turn — drives the context bar. */\n tokensIn: number;\n exitPending: boolean;\n /** Boss extended-thinking level. Falsy when thinking is off. */\n bossThinkingLevel?: string;\n /** Auto-updater has installed a newer @kenkaiiii/gg-boss in the background.\n * Show a \"restart to apply\" hint at the end of the footer row. */\n updatePending?: boolean;\n /** id of the currently-playing radio station (from RADIO_STATIONS), or null\n * when the radio is off. Renders as `♪ <short name>` between thinking and\n * the update notice. */\n currentRadioStationId?: string | null;\n}\n\n// Short, recognisable station names for the footer slot. The picker shows the\n// full name; here we just want enough to tell stations apart without eating\n// column budget. Order matters: more-frequent first because pattern matching\n// in the renderer is cheap-but-still-O(n).\nconst SHORT_RADIO: Record<string, string> = {\n \"somafm-groove-salad\": \"Groove Salad\",\n \"somafm-drone-zone\": \"Drone Zone\",\n \"radio-paradise\": \"Radio Paradise\",\n \"george-fm\": \"George FM\",\n};\n\n/**\n * Footer for gg-boss that mirrors ggcoder's Footer visual style — context bar\n * with partial-block precision, percent, then BOTH models displayed in the\n * same bold/coloured treatment so neither feels secondary.\n */\nexport function BossFooter({\n bossModel,\n workerModel,\n tokensIn,\n exitPending,\n bossThinkingLevel,\n updatePending,\n currentRadioStationId,\n}: BossFooterProps): React.ReactElement {\n const theme = useTheme();\n const { columns } = useTerminalSize();\n\n if (exitPending) {\n return (\n <Box paddingX={1}>\n <Text color={theme.warning}>Press Ctrl+C again to exit</Text>\n </Box>\n );\n }\n\n const contextPct = getContextPercent(bossModel, tokensIn);\n const contextColor =\n contextPct >= 80 ? theme.error : contextPct >= 50 ? theme.warning : theme.success;\n\n const sep = <Text color={theme.border}>{\" │ \"}</Text>;\n\n // Context bar — same partial-block precision as ggcoder's Footer.\n const barWidth = 8;\n const fillFloat = Math.min((contextPct / 100) * barWidth, barWidth);\n const barChars: React.ReactElement[] = [];\n for (let i = 0; i < barWidth; i++) {\n const cellFill = Math.max(0, Math.min(1, fillFloat - i));\n const eighths = Math.round(cellFill * 8);\n if (eighths === 8) {\n barChars.push(\n <Text key={i} color={contextColor}>\n {PARTIAL_BLOCKS[8]}\n </Text>,\n );\n } else if (eighths > 0) {\n barChars.push(\n <Text key={i} color={contextColor}>\n {PARTIAL_BLOCKS[eighths]}\n </Text>,\n );\n } else {\n barChars.push(\n <Text key={i} color={theme.textDim}>\n {LIGHT_SHADE}\n </Text>,\n );\n }\n }\n\n // Priority-drop layout: when terminal is narrower than the full footer\n // would need, we shed lower-priority chrome to keep the row from wrapping.\n // Ranked highest-to-lowest priority:\n // 1. context bar + % — always visible (essential)\n // 2. update notice — actionable; user needs to know\n // 3. radio — visible state of an audio process they started\n // 4. boss/worker model names — frequent reference, but stable\n // 5. thinking indicator — least chatty, easiest to hide first\n // 6. \"boss \"/\"workers \" text labels — pure decoration\n //\n // Approximate per-section widths (with separator \" │ \"):\n // bar+% = ~12, model = ~5+name+3 sep, thinking = ~14, radio ≈ ♪+name+3,\n // update = ~30. We compute and degrade in stages.\n const radioName = currentRadioStationId\n ? (SHORT_RADIO[currentRadioStationId] ?? currentRadioStationId)\n : null;\n const bossM = shortModel(bossModel);\n const wkrM = shortModel(workerModel);\n\n // Rough char estimate; padding=2, separators are \" │ \" (3 each).\n const estFull =\n 2 +\n 12 + // bar + \" 99%\"\n 3 +\n 5 +\n bossM.length + // \" │ boss <model>\"\n 3 +\n 8 +\n wkrM.length + // \" │ workers <model>\"\n 3 +\n 12 + // \" │ Thinking off\"\n (radioName ? 3 + 2 + radioName.length : 0) + // \" │ ♪ Name\"\n (updatePending ? 3 + 28 : 0); // \" │ Update ready. Restart GG Boss.\"\n\n const dropLabels = estFull > columns; // stage 1: kill \"boss \"/\"workers \" words\n const dropThinking = estFull > columns + 14; // stage 2: kill thinking indicator\n const useShortUpdate = updatePending && estFull > columns + 6; // stage 3: shrink the update notice\n\n return (\n <Box paddingX={1} width={columns}>\n <Box flexGrow={1} />\n <Box flexShrink={0}>\n <Text>{barChars}</Text>\n <Text color={contextColor}> {contextPct}%</Text>\n {sep}\n {!dropLabels && <Text color={theme.textDim}>boss </Text>}\n <Text color={COLORS.primary} bold>\n {bossM}\n </Text>\n {sep}\n {!dropLabels && <Text color={theme.textDim}>workers </Text>}\n <Text color={COLORS.accent} bold>\n {wkrM}\n </Text>\n {!dropThinking && (\n <>\n {sep}\n <Text color={bossThinkingLevel ? theme.accent : theme.textDim}>\n {bossThinkingLevel ? \"Thinking on\" : \"Thinking off\"}\n </Text>\n </>\n )}\n {radioName && (\n <>\n {sep}\n <Text color={theme.secondary ?? theme.accent}>♪ {radioName}</Text>\n </>\n )}\n {updatePending && (\n <>\n {sep}\n <Text color={theme.success} bold wrap=\"truncate\">\n {useShortUpdate ? \"Update ready\" : \"Update ready. Restart GG Boss.\"}\n </Text>\n </>\n )}\n </Box>\n </Box>\n );\n}\n","import type { SlashCommandInfo } from \"@kenkaiiii/ggcoder/ui\";\n\n/**\n * Slash commands the boss CLI recognizes. Shape matches ggcoder's\n * SlashCommandInfo so the existing SlashCommandMenu in InputArea renders them.\n *\n * The actual handlers live in BossApp's handleSubmit — we just declare the\n * surface here so the menu is in one place.\n */\nexport const BOSS_SLASH_COMMANDS: SlashCommandInfo[] = [\n { name: \"help\", aliases: [\"?\"], description: \"Show available commands\" },\n { name: \"model-boss\", aliases: [], description: \"Switch the orchestrator's model\" },\n { name: \"model-workers\", aliases: [], description: \"Switch every worker's model\" },\n { name: \"compact\", aliases: [], description: \"Compact the boss's context now\" },\n { name: \"clear\", aliases: [], description: \"Clear chat history and terminal\" },\n { name: \"radio\", aliases: [], description: \"Stream a free internet radio station\" },\n { name: \"quit\", aliases: [\"q\", \"exit\"], description: \"Exit gg-boss\" },\n];\n\nexport function isSlashCommand(value: string): boolean {\n return value.startsWith(\"/\") && !value.startsWith(\"//\");\n}\n\nexport interface ParsedSlashCommand {\n name: string;\n args: string;\n}\n\nexport function parseSlash(value: string): ParsedSlashCommand | null {\n if (!isSlashCommand(value)) return null;\n const rest = value.slice(1).trim();\n if (!rest) return null;\n const space = rest.indexOf(\" \");\n if (space === -1) return { name: rest.toLowerCase(), args: \"\" };\n return { name: rest.slice(0, space).toLowerCase(), args: rest.slice(space + 1).trim() };\n}\n\n/** Resolve aliases to the canonical command name. */\nexport function canonicalName(name: string): string | null {\n for (const cmd of BOSS_SLASH_COMMANDS) {\n if (cmd.name === name) return cmd.name;\n if (cmd.aliases.includes(name)) return cmd.name;\n }\n return null;\n}\n\nexport function buildHelpText(): string {\n const lines: string[] = [\"**gg-boss commands**\", \"\"];\n for (const cmd of BOSS_SLASH_COMMANDS) {\n const aliases =\n cmd.aliases.length > 0 ? ` (${cmd.aliases.map((a) => \"/\" + a).join(\", \")})` : \"\";\n lines.push(`- \\`/${cmd.name}\\`${aliases} — ${cmd.description}`);\n }\n lines.push(\"\");\n lines.push(\"**Global keybindings**\");\n lines.push(\"- `Ctrl+T` — open the Tasks pane\");\n lines.push(\"- `Tab` — switch project scope (All / per-project pill in the input)\");\n lines.push(\"- `Shift+Tab` — toggle the boss's extended thinking on/off\");\n lines.push(\"- `Esc` — interrupt the boss while it's running\");\n lines.push(\"- `Ctrl+C` (twice) — exit\");\n lines.push(\"\");\n lines.push(\"**Inside the Tasks pane (Ctrl+T)**\");\n lines.push(\"- `↑` / `↓` (or `k` / `j`) — navigate tasks\");\n lines.push(\"- `r` — run all pending and blocked tasks across idle workers\");\n lines.push(\"- `d` — delete the selected task\");\n lines.push(\"- `Esc` — close the Tasks pane\");\n lines.push(\"\");\n lines.push(\"**Inside model pickers (`/model-boss`, `/model-workers`)**\");\n lines.push(\"- `↑` / `↓` — navigate models\");\n lines.push(\"- `Enter` — select\");\n lines.push(\"- `Esc` — cancel\");\n lines.push(\"\");\n lines.push(\"**Radio** (`/radio`)\");\n lines.push(\"- Pick a station to stream while you work, or select `Off` to stop.\");\n lines.push(\"- Requires `mpv` (recommended), `ffplay`, `mpg123`, or `vlc/cvlc` installed.\");\n lines.push(\"\");\n lines.push(\"**Input area**\");\n lines.push(\"- `↑` / `↓` — recall previous prompts (when input is empty)\");\n lines.push(\"- `Enter` — send · `Shift+Enter` — newline\");\n lines.push(\"- `/` — open the slash-command menu (Tab / arrows to pick, Enter to insert)\");\n return lines.join(\"\\n\");\n}\n","import type { ToolExecutionFormatters } from \"@kenkaiiii/ggcoder/ui\";\nimport { projectColor } from \"./colors.js\";\n\nfunction truncate(s: string, max: number): string {\n if (max <= 1) return \"…\";\n return s.length > max ? s.slice(0, max - 1) + \"…\" : s;\n}\n\n/**\n * Compute how many chars of the prompt-worker message detail can fit on a\n * single line of the current terminal. Header chrome ≈ \"⏺ Prompt Worker(<proj>\n * · …) <inline>\" — we subtract the fixed pieces so the message gets whatever\n * room remains.\n */\nfunction promptWorkerDetailLen(project: string): number {\n const cols = process.stdout.columns ?? 80;\n // Fixed overhead estimate: dot(2) + label \"Prompt Worker\"(13) + \"(\"(1)\n // + project + \" · \"(3) + \")\"(1) + \" \"(1) + \" dispatched\"(11) + safety(6).\n const fixed = 2 + 13 + 1 + project.length + 3 + 1 + 1 + 11 + 6;\n return Math.max(20, cols - fixed);\n}\n\n/**\n * Custom label / detail / inline-summary rendering for the boss's own tools.\n * Falls through to ggcoder's defaults for anything else.\n */\nexport const bossToolFormatters: ToolExecutionFormatters = {\n formatLabel(name) {\n switch (name) {\n case \"list_workers\":\n return \"List Workers\";\n case \"get_worker_status\":\n return \"Worker Status\";\n case \"prompt_worker\":\n return \"Prompt Worker\";\n case \"get_worker_summary\":\n return \"Worker Summary\";\n default:\n return undefined;\n }\n },\n\n formatDetail(name, args) {\n switch (name) {\n case \"list_workers\":\n return \"\";\n case \"get_worker_status\":\n case \"get_worker_summary\":\n return truncate(String(args.project ?? \"\"), 40);\n case \"prompt_worker\": {\n const project = String(args.project ?? \"\");\n const message = String(args.message ?? \"\").replace(/\\s+/g, \" \");\n const fresh = args.fresh === true;\n const maxMsg = promptWorkerDetailLen(project) - (fresh ? 8 : 0); // \"fresh · \" is 8 chars\n const truncMsg = truncate(message, Math.max(15, maxMsg));\n const head = fresh ? \"fresh · \" : \"\";\n return project ? `${head}${project} · ${truncMsg}` : `${head}${truncMsg}`;\n }\n default:\n return undefined;\n }\n },\n\n formatInline(name, result, isError) {\n if (isError) return undefined;\n switch (name) {\n case \"list_workers\": {\n const lines = result.split(\"\\n\").filter((l) => l.startsWith(\"-\"));\n return `${lines.length} worker${lines.length === 1 ? \"\" : \"s\"}`;\n }\n case \"prompt_worker\": {\n if (result.includes(\"currently working\")) {\n return { text: \"busy — skipped\", color: \"#fbbf24\" };\n }\n if (result.includes(\"Unknown project\")) {\n return { text: \"unknown project\", color: \"#f87171\" };\n }\n // Color the badge by project — same project always reads as the same\n // hue across scrollback so the user can scan dispatches at a glance.\n // (When fresh: true, the \"fresh ·\" prefix is already in the detail\n // parens — no need to double up here, was causing line wraps.)\n const project = String(result.match(/\"([^\"]+)\"/)?.[1] ?? \"\");\n const color = project ? projectColor(project) : \"#e11d48\";\n return { text: \"dispatched\", color };\n }\n case \"get_worker_status\": {\n const parts = result.split(\":\");\n if (parts.length < 2) return undefined;\n const status = parts.slice(1).join(\":\").trim();\n const project = parts[0]!.trim();\n return { text: status, color: projectColor(project) };\n }\n case \"get_worker_summary\": {\n const turnMatch = result.match(/Turn:\\s*(\\d+)/);\n const projectMatch = result.match(/Project:\\s*(.+)/);\n const toolsMatch = result.match(/Tools used:\\s*(.+)/);\n const tools = toolsMatch ? toolsMatch[1] : \"\";\n const toolCount = tools && tools !== \"(no tools used)\" ? tools.split(\",\").length : 0;\n const turn = turnMatch ? `turn ${turnMatch[1]}` : undefined;\n const tCount = toolCount > 0 ? `${toolCount} tool${toolCount === 1 ? \"\" : \"s\"}` : undefined;\n const summary = [turn, tCount].filter(Boolean).join(\" · \");\n if (!summary) return undefined;\n const project = projectMatch ? projectMatch[1].trim() : \"\";\n return project\n ? { text: summary, color: projectColor(project) }\n : { text: summary, color: \"#9ca3af\" };\n }\n default:\n return undefined;\n }\n },\n};\n","/**\n * Stable project-color palette. Hashing the project name to a fixed slot lets\n * every UI surface (worker event row, status bar, scope pill, dispatched\n * badge, etc.) tag the same project with the same hue — turns scrollback into\n * a glanceable colour-coded timeline.\n *\n * Picked to look decent in both dark and light themes — saturated enough to\n * read on dim backgrounds, soft enough not to scream.\n */\nexport const PROJECT_COLORS: readonly string[] = [\n \"#60a5fa\", // blue\n \"#a78bfa\", // violet\n \"#4ade80\", // green\n \"#fbbf24\", // amber\n \"#f472b6\", // pink\n \"#22d3ee\", // cyan\n \"#fb923c\", // orange\n \"#34d399\", // emerald\n];\n\nexport function stableHash(s: string): number {\n let h = 0;\n for (let i = 0; i < s.length; i++) {\n h = (h * 31 + s.charCodeAt(i)) | 0;\n }\n return Math.abs(h);\n}\n\n/** Pick a color for a project — same project name always returns the same color. */\nexport function projectColor(name: string): string {\n return PROJECT_COLORS[stableHash(name) % PROJECT_COLORS.length]!;\n}\n","import type { ActivityPhase } from \"@kenkaiiii/ggcoder/ui\";\n\n/**\n * Boss-themed phrase library for the activity indicator. Replaces ggcoder's\n * coder-flavored phrases (\"Cogitating\", \"Sleuthing\", etc.) with vocabulary\n * that fits an orchestrator role — managing, dispatching, reviewing — so the\n * spinner reads as \"the boss is at work\" not \"the boss is writing code\".\n */\nexport const BOSS_PHRASES: Record<ActivityPhase, string[]> = {\n // Generic between-states fallback. Probably never shown but keep for safety.\n idle: [\"Standing by\", \"Waiting for orders\", \"On call\"],\n\n // Boss has issued a request, waiting for the LLM to begin streaming.\n waiting: [\n \"Briefing\",\n \"Reviewing the room\",\n \"Triaging\",\n \"Lining up the brief\",\n \"Surveying projects\",\n \"Reading the room\",\n \"Picking the right hand\",\n \"Marshalling thoughts\",\n \"Checking the board\",\n \"Sizing up the work\",\n ],\n\n // LLM is mid-thinking-block (extended reasoning).\n thinking: [\n \"Strategising\",\n \"Plotting next move\",\n \"Weighing options\",\n \"Reasoning\",\n \"Deliberating\",\n \"Thinking it through\",\n \"Mapping the play\",\n \"Considering angles\",\n \"Calculating odds\",\n \"Drafting the call\",\n ],\n\n // LLM is streaming text — boss is forming its dispatch / response.\n generating: [\n \"Drafting\",\n \"Composing dispatch\",\n \"Writing the brief\",\n \"Penning instructions\",\n \"Wording it up\",\n \"Putting it on paper\",\n \"Phrasing the ask\",\n \"Forming the directive\",\n \"Scripting the plan\",\n ],\n\n // Boss is invoking a tool — most often prompt_worker.\n tools: [\n \"Coordinating\",\n \"Dispatching\",\n \"Routing\",\n \"Delegating\",\n \"Issuing orders\",\n \"Handing off\",\n \"Aligning workers\",\n \"Conducting\",\n \"Calling the team\",\n \"Steering\",\n \"Pulling levers\",\n ],\n\n // Provider retry (overloaded / rate-limited / etc.).\n retrying: [\n \"Reattempting\",\n \"Course correcting\",\n \"Trying again\",\n \"Pushing through\",\n \"Holding the line\",\n ],\n};\n","import React, { useCallback, useEffect, useRef, useState } from \"react\";\nimport { Box, Text, useInput } from \"ink\";\nimport { useTheme } from \"@kenkaiiii/ggcoder/ui/theme\";\nimport { useTasksState, tasksStore, type BossTask, type TaskStatus } from \"./tasks-store.js\";\nimport { bossStore } from \"./boss-store.js\";\nimport { projectColor } from \"./colors.js\";\nimport { COLORS } from \"./branding.js\";\nimport type { GGBoss } from \"./orchestrator.js\";\nimport type { WorkerView } from \"./boss-store.js\";\n\nfunction statusGlyph(status: TaskStatus): string {\n switch (status) {\n case \"done\":\n return \"✓\";\n case \"in_progress\":\n return \"~\";\n case \"blocked\":\n return \"✗\";\n case \"skipped\":\n return \"—\";\n default:\n return \" \";\n }\n}\n\ninterface BossTasksOverlayProps {\n boss: GGBoss;\n workers: WorkerView[];\n onClose: () => void;\n}\n\n/**\n * Multi-project task overlay for gg-boss. Read-mostly: tasks are added by the\n * boss agent (via add_task tool), so the overlay is just a backlog viewer with\n * two actions — delete a stuck task, or run all pending across idle workers.\n *\n * Keybinds (all the user actually needs):\n * ↑↓ / k j navigate\n * d delete selected task\n * r dispatch_pending across all idle workers (parallel fan-out)\n * Esc close\n */\nexport function BossTasksOverlay({\n boss,\n workers,\n onClose,\n}: BossTasksOverlayProps): React.ReactElement {\n const theme = useTheme();\n const tasksState = useTasksState();\n const tasks = tasksState.tasks;\n const [selectedIndex, setSelectedIndex] = useState(0);\n const [status, setStatusMsg] = useState(\"\");\n const statusTimer = useRef<ReturnType<typeof setTimeout> | null>(null);\n\n const showStatus = useCallback((msg: string): void => {\n setStatusMsg(msg);\n if (statusTimer.current) clearTimeout(statusTimer.current);\n statusTimer.current = setTimeout(() => setStatusMsg(\"\"), 2500);\n }, []);\n\n // Group tasks by project (in worker order).\n const groupedTasks: { project: string; tasks: BossTask[] }[] = workers.map((w) => ({\n project: w.name,\n tasks: tasks\n .filter((t) => t.project === w.name)\n .sort((a, b) => a.createdAt.localeCompare(b.createdAt)),\n }));\n\n const flatTasks: BossTask[] = groupedTasks.flatMap((g) => g.tasks);\n\n // Clamp selection.\n useEffect(() => {\n if (flatTasks.length === 0) {\n setSelectedIndex(0);\n } else if (selectedIndex >= flatTasks.length) {\n setSelectedIndex(flatTasks.length - 1);\n }\n }, [flatTasks.length, selectedIndex]);\n\n const selected = flatTasks[selectedIndex];\n\n // Cap how many tasks render at once so the live-area height stays bounded.\n // Ink's log-update mispositions the cursor when the live area is much\n // larger than the next frame — going from a 30-line tasks pane back to a\n // 5-line chat chrome was clipping the user's scrollback above on close.\n // Mirrors ggcoder's `maxVisible = 15` cap. Selection stays visible by\n // scrolling the window when the cursor reaches the bottom.\n const MAX_VISIBLE = 12;\n const startIdx = Math.max(\n 0,\n Math.min(flatTasks.length - MAX_VISIBLE, selectedIndex - MAX_VISIBLE + 1, selectedIndex),\n );\n const endIdx = Math.min(flatTasks.length, startIdx + MAX_VISIBLE);\n const visibleIdSet = new Set(flatTasks.slice(startIdx, endIdx).map((t) => t.id));\n const showingTop = startIdx > 0;\n const showingBottom = endIdx < flatTasks.length;\n\n useInput((input, key) => {\n if (key.escape) {\n onClose();\n return;\n }\n if (key.upArrow || input === \"k\") {\n setSelectedIndex((i) => Math.max(0, i - 1));\n return;\n }\n if (key.downArrow || input === \"j\") {\n setSelectedIndex((i) => Math.min(flatTasks.length - 1, i + 1));\n return;\n }\n if (input === \"d\" && selected) {\n void tasksStore.remove(selected.id).then(() => showStatus(\"Deleted\"));\n return;\n }\n if (input === \"r\") {\n // Close immediately so the user lands back in the chat view and can\n // watch worker activity stream in. Dispatch fires in the background;\n // worker_turn_complete events flow into history as normal.\n onClose();\n void (async (): Promise<void> => {\n const dispatched: { project: string; title: string }[] = [];\n for (const w of workers) {\n // nextDispatchable picks pending OR blocked — so blocked tasks get\n // retried alongside fresh pending ones. Pending is preferred.\n const next = tasksStore.nextDispatchable(w.name);\n if (!next) continue;\n // Reset blocked → pending so the dispatch path's in_progress flip\n // lands on a clean state and not \"blocked → in_progress\" (which\n // looks like a status going backwards in the overlay).\n if (next.status === \"blocked\") {\n await tasksStore.update(next.id, { status: \"pending\", notes: undefined });\n }\n const res = await boss.dispatchTaskById(next.id);\n if (res.ok) dispatched.push({ project: w.name, title: next.title });\n }\n if (dispatched.length === 0) {\n bossStore.appendInfo(\"No pending or blocked tasks to run.\", \"info\");\n } else {\n bossStore.appendTaskDispatch(dispatched);\n }\n })();\n return;\n }\n });\n\n const doneCount = tasks.filter((t) => t.status === \"done\").length;\n const inProgressCount = tasks.filter((t) => t.status === \"in_progress\").length;\n const pendingCount = tasks.filter((t) => t.status === \"pending\").length;\n const blockedCount = tasks.filter((t) => t.status === \"blocked\").length;\n\n return (\n <Box flexDirection=\"column\" marginTop={1} paddingX={1}>\n {/* Single header line — the main GG Boss banner sits in scrollback\n above (from <Static>), so we just announce the pane state here.\n Inner BossBanner caused visible duplicates on toggle round-trips. */}\n <Box>\n <Text color={COLORS.primary} bold>\n Tasks\n </Text>\n <Text color={theme.textDim}>{` · ${tasks.length} total · `}</Text>\n <CountsRow\n theme={theme}\n done={doneCount}\n active={inProgressCount}\n pending={pendingCount}\n blocked={blockedCount}\n />\n </Box>\n\n {flatTasks.length === 0 && (\n <Box marginTop={1}>\n <Text color={theme.textDim}>\n {\" No tasks yet. Ask the boss to plan some — e.g. \"}\n <Text color={theme.text}>\"plan some work\"</Text>\n {\".\"}\n </Text>\n </Box>\n )}\n\n {showingTop && <Text color={theme.textDim}>{` ↑ ${startIdx} more above`}</Text>}\n\n {/* Per-project sections — only tasks in the visible window are rendered.\n Sections with no visible tasks are hidden entirely so the layout\n stays compact across scroll. */}\n {groupedTasks.map((group, gIdx) => {\n const startInFlat = groupedTasks.slice(0, gIdx).reduce((acc, g) => acc + g.tasks.length, 0);\n const visibleInSection = group.tasks.filter((t) => visibleIdSet.has(t.id));\n if (visibleInSection.length === 0) return null;\n return (\n <Box key={group.project} flexDirection=\"column\" marginTop={1}>\n <Text>\n <Text color={projectColor(group.project)} bold>\n {group.project}\n </Text>\n <Text color={theme.textDim}>{` · ${group.tasks.length}`}</Text>\n </Text>\n {visibleInSection.map((task) => {\n const realIdx = startInFlat + group.tasks.indexOf(task);\n const isSelected = realIdx === selectedIndex;\n const prefix = isSelected ? \"❯ \" : \" \";\n const glyph = statusGlyph(task.status);\n const color = isSelected\n ? theme.primary\n : task.status === \"done\"\n ? theme.success\n : task.status === \"in_progress\"\n ? theme.warning\n : task.status === \"blocked\"\n ? theme.error\n : theme.text;\n return (\n <Text key={task.id} color={color} bold={isSelected}>\n {prefix}[{glyph}] {task.title}\n </Text>\n );\n })}\n </Box>\n );\n })}\n\n {showingBottom && (\n <Text color={theme.textDim}>{` ↓ ${flatTasks.length - endIdx} more below`}</Text>\n )}\n\n {status && (\n <Box marginTop={1}>\n <Text color={theme.success}>{\" \" + status}</Text>\n </Box>\n )}\n\n <Box marginTop={1}>\n <Text color={theme.textDim}>\n <Text color={theme.primary}>↑↓</Text>\n {\" move · (\"}\n <Text color={theme.primary}>d</Text>\n {\")elete · (\"}\n <Text color={theme.primary}>r</Text>\n {\")un pending · \"}\n <Text color={theme.primary}>ESC</Text>\n {\" close\"}\n </Text>\n </Box>\n </Box>\n );\n}\n\nfunction CountsRow({\n theme,\n done,\n active,\n pending,\n blocked,\n}: {\n theme: ReturnType<typeof useTheme>;\n done: number;\n active: number;\n pending: number;\n blocked: number;\n}): React.ReactElement {\n return (\n <Text>\n <Text color={theme.success}>{done} done</Text>\n <Text color={theme.textDim}> · </Text>\n <Text color={theme.warning}>{active} active</Text>\n <Text color={theme.textDim}> · </Text>\n <Text color={theme.text}>{pending} pending</Text>\n {blocked > 0 && (\n <>\n <Text color={theme.textDim}> · </Text>\n <Text color={theme.error}>{blocked} blocked</Text>\n </>\n )}\n </Text>\n );\n}\n","import React from \"react\";\nimport { SelectList } from \"@kenkaiiii/ggcoder/ui\";\nimport { RADIO_STATIONS } from \"./radio.js\";\n\ninterface RadioPickerProps {\n /** Currently-playing station id, or null when off. Drives the * marker. */\n currentStationId: string | null;\n onSelect: (stationId: string | \"off\") => void;\n onCancel: () => void;\n}\n\n/**\n * Picker overlay shown when the user types `/radio`. Mirrors ModelSelector's\n * pattern (SelectList + currentValue marker) so the keybinds and visual\n * weight match the rest of the boss overlays — ↑↓ to navigate, Enter to\n * select, Esc to cancel.\n *\n * The \"Off\" entry is always last and selectable regardless of current state,\n * so users can stop the radio from inside the picker without remembering a\n * separate /radio-off command.\n */\nexport function RadioPicker({\n currentStationId,\n onSelect,\n onCancel,\n}: RadioPickerProps): React.ReactElement {\n const items = [\n ...RADIO_STATIONS.map((s) => ({\n label: `${currentStationId === s.id ? \"* \" : \" \"}${s.name}`,\n value: s.id,\n description: s.description,\n })),\n {\n label: `${currentStationId === null ? \"* \" : \" \"}Off`,\n value: \"off\",\n description: \"Stop the radio\",\n },\n ];\n const initialIndex = Math.max(\n 0,\n items.findIndex((i) => i.value === (currentStationId ?? \"off\")),\n );\n return (\n <SelectList\n items={items}\n onSelect={(v) => onSelect(v === \"off\" ? \"off\" : v)}\n onCancel={onCancel}\n initialIndex={initialIndex}\n windowSize={6}\n />\n );\n}\n","import { spawn, type ChildProcess } from \"node:child_process\";\nimport { log } from \"./logger.js\";\n\n/**\n * Terminal radio — stream a free internet radio station while you're working.\n * Curated short list of long-running, royalty-free, no-API-key streams that\n * have been stable for years (SomaFM started in 2000, Radio Paradise in 2006).\n *\n * Player binary detection mirrors the audio.ts chain for one-shot effects:\n * mpv > ffplay > mpg123 > cvlc. macOS's built-in afplay isn't a streaming\n * player, so users who haven't installed any of those will get a one-line\n * \"install mpv\" hint and the radio request just no-ops gracefully.\n *\n * One station at a time — switching stations or selecting \"Off\" kills the\n * existing player process before spawning a new one.\n */\n\nexport interface RadioStation {\n /** Stable identifier used in slash command + settings persistence. */\n id: string;\n /** Display name in the picker. */\n name: string;\n /** Short subtitle shown next to the name. */\n description: string;\n /** Direct stream URL — must be MP3/AAC/Ogg, anything mpv handles. */\n url: string;\n}\n\nexport const RADIO_STATIONS: readonly RadioStation[] = [\n {\n id: \"somafm-groove-salad\",\n name: \"SomaFM · Groove Salad\",\n description: \"Chilled downtempo, ambient grooves\",\n url: \"http://ice1.somafm.com/groovesalad-128-mp3\",\n },\n {\n id: \"somafm-drone-zone\",\n name: \"SomaFM · Drone Zone\",\n description: \"Atmospheric textures with minimal beats\",\n url: \"http://ice1.somafm.com/dronezone-128-mp3\",\n },\n {\n id: \"radio-paradise\",\n name: \"Radio Paradise\",\n description: \"Eclectic mix — rock, electronica, jazz\",\n url: \"http://stream.radioparadise.com/mp3-128\",\n },\n {\n id: \"george-fm\",\n name: \"George FM\",\n description: \"NZ dance + electronic\",\n url: \"https://mediaworks.streamguys1.com/george_net_icy\",\n },\n];\n\ninterface PlayerCandidate {\n cmd: string;\n args: (url: string) => string[];\n}\n\n/**\n * Streaming-capable players in priority order. Each gets its quietest flag\n * combination — radio runs in the background, we don't want stdout/stderr\n * spam fighting with the TUI. Stdio is also redirected to \"ignore\" at spawn\n * time, but quiet flags help in case the player decides to write to tty.\n */\nconst PLAYERS: readonly PlayerCandidate[] = [\n { cmd: \"mpv\", args: (u) => [\"--really-quiet\", \"--no-video\", \"--no-terminal\", u] },\n {\n cmd: \"ffplay\",\n args: (u) => [\"-nodisp\", \"-autoexit\", \"-loglevel\", \"quiet\", u],\n },\n { cmd: \"mpg123\", args: (u) => [\"-q\", u] },\n { cmd: \"cvlc\", args: (u) => [\"--play-and-exit\", \"--quiet\", u] },\n];\n\nlet currentChild: ChildProcess | null = null;\nlet currentStationId: string | null = null;\n\nexport function getCurrentStation(): string | null {\n return currentStationId;\n}\n\n/**\n * Stop whatever's currently playing. Idempotent — safe to call when nothing\n * is playing. Sends SIGTERM (graceful), child cleans up the audio device.\n */\nexport function stopRadio(): void {\n if (!currentChild) return;\n try {\n // Detached children sit in their own process group on POSIX; kill the\n // whole group so any helper threads/forks die too. On Windows there's\n // no process group concept — kill() targets the child only.\n if (process.platform !== \"win32\" && currentChild.pid) {\n try {\n process.kill(-currentChild.pid, \"SIGTERM\");\n } catch {\n currentChild.kill(\"SIGTERM\");\n }\n } else {\n currentChild.kill(\"SIGTERM\");\n }\n } catch {\n // Already exited — nothing to do.\n }\n currentChild = null;\n currentStationId = null;\n log(\"INFO\", \"radio\", \"stopped\");\n}\n\ninterface PlayResult {\n ok: boolean;\n /** Friendly error to surface to the user when ok=false. */\n error?: string;\n}\n\n/**\n * Spawn a streaming player for the given station. If one is already playing,\n * it's killed first. Returns ok=false with a hint if no compatible player is\n * installed — caller should surface the error to the user.\n */\nexport function playRadio(stationId: string): PlayResult {\n const station = RADIO_STATIONS.find((s) => s.id === stationId);\n if (!station) return { ok: false, error: `Unknown station: ${stationId}` };\n\n // Always stop the previous stream before starting a new one.\n stopRadio();\n\n for (const player of PLAYERS) {\n try {\n const child = spawn(player.cmd, player.args(station.url), {\n detached: process.platform !== \"win32\",\n stdio: \"ignore\",\n });\n // Race: we don't know yet whether the spawn succeeded (ENOENT fires async).\n // Listen for the error event AND optimistically assume success. If error\n // fires within 100ms we'll fall through to the next candidate.\n let errored = false;\n child.once(\"error\", () => {\n errored = true;\n });\n // Synchronous check after a tick — if the child has a pid by now, the\n // OS accepted the spawn. ENOENT is reported async via the \"error\" event,\n // so a non-null pid alone isn't conclusive, but combined with the\n // optimistic try/next-candidate loop it's enough.\n if (child.pid && !errored) {\n currentChild = child;\n currentStationId = stationId;\n log(\"INFO\", \"radio\", \"playing\", {\n station: station.id,\n player: player.cmd,\n url: station.url,\n });\n // Detach so the radio outlives boss exit if the user wants it to.\n // (We still kill it on stopRadio() and on graceful boss shutdown.)\n child.unref();\n return { ok: true };\n }\n } catch {\n // ENOENT or permission — try the next player.\n }\n }\n log(\"WARN\", \"radio\", \"no compatible player found\", { platform: process.platform });\n return {\n ok: false,\n error: buildInstallHint(),\n };\n}\n\n/**\n * Platform-specific one-line install hint. Picks the most likely working\n * command for the current OS so the user can copy-paste rather than reading\n * a wall of generic suggestions. Falls back to the official mpv site for\n * platforms we don't recognise.\n */\nfunction buildInstallHint(): string {\n const base =\n \"Radio needs a streaming player. Install one of: mpv (recommended), ffplay, mpg123, or vlc.\";\n switch (process.platform) {\n case \"darwin\":\n return `${base} On macOS: \\`brew install mpv\\` (or \\`brew install ffmpeg\\` for ffplay).`;\n case \"linux\":\n return `${base} On Linux (Debian/Ubuntu): \\`sudo apt install mpv\\`. Fedora: \\`sudo dnf install mpv\\`. Arch: \\`sudo pacman -S mpv\\`.`;\n case \"win32\":\n return `${base} On Windows: \\`winget install mpv.mpv\\` (or download from https://mpv.io).`;\n default:\n return `${base} See https://mpv.io for platform installation instructions.`;\n }\n}\n","import { spawn } from \"node:child_process\";\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport os from \"node:os\";\n\n/**\n * gg-boss auto-update — mirrors ggcoder's pattern (packages/ggcoder/src/core/\n * auto-update.ts) but pinned to @kenkaiiii/gg-boss and with its own state\n * file under ~/.gg/boss/ so it can't fight with ggcoder's checker.\n *\n * Two-phase strategy:\n * - Phase 1 (instant, blocking): if a previous run found a newer version,\n * spawn `npm i -g @kenkaiiii/gg-boss@latest` (or pnpm/yarn equivalent)\n * in a detached child. Takes effect on the user's NEXT launch.\n * - Phase 2 (async, non-blocking): hit the npm registry to compare versions\n * so the next startup knows if there's anything to install. Throttled to\n * once an hour per state-file timestamp.\n *\n * Plus a periodic in-session check so a user who never restarts still gets\n * notified when a new version drops.\n */\n\nconst PACKAGE_NAME = \"@kenkaiiii/gg-boss\";\nconst REGISTRY_URL = `https://registry.npmjs.org/${PACKAGE_NAME}/latest`;\nconst CHECK_INTERVAL_MS = 60 * 60 * 1000; // 1 hour\nconst FETCH_TIMEOUT_MS = 10_000;\n\ninterface UpdateState {\n lastCheckedAt: number;\n latestVersion?: string;\n updatePending?: boolean;\n lastUpdateAttempt?: number;\n}\n\nenum PackageManager {\n NPM = \"npm\",\n PNPM = \"pnpm\",\n YARN = \"yarn\",\n UNKNOWN = \"unknown\",\n}\n\ninterface InstallInfo {\n packageManager: PackageManager;\n updateCommand: string | null;\n}\n\nfunction getStateFilePath(): string {\n return path.join(os.homedir(), \".gg\", \"boss\", \"update-state.json\");\n}\n\nfunction readState(): UpdateState | null {\n try {\n const raw = fs.readFileSync(getStateFilePath(), \"utf-8\");\n return JSON.parse(raw) as UpdateState;\n } catch {\n return null;\n }\n}\n\nfunction writeState(state: UpdateState): void {\n try {\n const dir = path.dirname(getStateFilePath());\n fs.mkdirSync(dir, { recursive: true, mode: 0o700 });\n fs.writeFileSync(getStateFilePath(), JSON.stringify(state));\n } catch {\n // Non-fatal — we'll just retry next launch.\n }\n}\n\nfunction compareVersions(a: string, b: string): number {\n const pa = a.split(\".\").map(Number);\n const pb = b.split(\".\").map(Number);\n for (let i = 0; i < 3; i++) {\n const diff = (pa[i] ?? 0) - (pb[i] ?? 0);\n if (diff !== 0) return diff;\n }\n return 0;\n}\n\nfunction detectInstallInfo(): InstallInfo {\n const scriptPath = (process.argv[1] ?? \"\").replace(/\\\\/g, \"/\");\n // npx invocations are ephemeral — never auto-update.\n if (scriptPath.includes(\"/_npx/\")) {\n return { packageManager: PackageManager.UNKNOWN, updateCommand: null };\n }\n if (scriptPath.includes(\"/.pnpm\") || scriptPath.includes(\"/pnpm/global\")) {\n return {\n packageManager: PackageManager.PNPM,\n updateCommand: `pnpm add -g ${PACKAGE_NAME}@latest`,\n };\n }\n if (scriptPath.includes(\"/.yarn/\") || scriptPath.includes(\"/yarn/global\")) {\n return {\n packageManager: PackageManager.YARN,\n updateCommand: `yarn global add ${PACKAGE_NAME}@latest`,\n };\n }\n return {\n packageManager: PackageManager.NPM,\n updateCommand: `npm install -g ${PACKAGE_NAME}@latest`,\n };\n}\n\nasync function fetchLatestVersion(): Promise<string | null> {\n try {\n const controller = new AbortController();\n const timeout = setTimeout(() => controller.abort(), FETCH_TIMEOUT_MS);\n const response = await fetch(REGISTRY_URL, { signal: controller.signal });\n clearTimeout(timeout);\n const data = (await response.json()) as { version?: string };\n const version = data.version?.trim();\n return version && /^\\d+\\.\\d+\\.\\d+/.test(version) ? version : null;\n } catch {\n return null;\n }\n}\n\nfunction performUpdateInBackground(command: string): void {\n try {\n const parts = command.split(\" \");\n const child = spawn(parts[0]!, parts.slice(1), {\n detached: true,\n stdio: \"ignore\",\n env: { ...process.env, npm_config_loglevel: \"silent\" },\n });\n child.unref();\n } catch {\n // Non-fatal — the next launch will try again.\n }\n}\n\n/**\n * Called on CLI startup. If the previous run flagged a newer version, kicks\n * off `npm i -g` in the background and returns a one-line \"installing…\"\n * message for the caller to print. Always also schedules a fresh registry\n * check (rate-limited) so the next startup has up-to-date info.\n */\nexport function checkAndAutoUpdate(currentVersion: string): string | null {\n try {\n const state = readState();\n let message: string | null = null;\n\n // Phase 1: install if a previous check found something newer.\n if (state?.updatePending && state.latestVersion) {\n if (compareVersions(state.latestVersion, currentVersion) > 0) {\n const info = detectInstallInfo();\n if (info.updateCommand) {\n performUpdateInBackground(info.updateCommand);\n message = `Ken just shipped ${state.latestVersion}! Installing in the background — takes effect next launch.`;\n writeState({\n ...state,\n lastCheckedAt: Date.now(),\n updatePending: false,\n lastUpdateAttempt: Date.now(),\n });\n }\n } else {\n // Already on latest (user updated manually) — clear the pending flag.\n writeState({ ...state, updatePending: false });\n }\n }\n\n // Phase 2: schedule a fresh check, throttled.\n const shouldCheck = !state || Date.now() - state.lastCheckedAt > CHECK_INTERVAL_MS;\n if (shouldCheck) scheduleBackgroundCheck(currentVersion);\n\n return message;\n } catch {\n return null;\n }\n}\n\n/**\n * Synchronous TUI getter — reads the state file and returns the pending\n * update info (if any). Drives the \"✨ Update ready\" indicator in the\n * worker bar so users know to restart.\n */\nexport function getPendingUpdate(currentVersion: string): { latestVersion: string } | null {\n try {\n const state = readState();\n if (!state?.latestVersion) return null;\n if (compareVersions(state.latestVersion, currentVersion) <= 0) return null;\n return { latestVersion: state.latestVersion };\n } catch {\n return null;\n }\n}\n\nfunction scheduleBackgroundCheck(currentVersion: string): void {\n fetchLatestVersion()\n .then((latestVersion) => {\n const newState: UpdateState = {\n lastCheckedAt: Date.now(),\n latestVersion: latestVersion ?? undefined,\n updatePending: false,\n };\n if (latestVersion && compareVersions(latestVersion, currentVersion) > 0) {\n newState.updatePending = true;\n }\n writeState(newState);\n })\n .catch(() => {\n // Non-fatal — we'll try again next launch.\n });\n}\n\n// ── In-session periodic check ──────────────────────────────\n\nlet periodicTimer: ReturnType<typeof setInterval> | null = null;\n\n/**\n * Start a long-running session timer that pings npm hourly. If a newer\n * version is found, calls `onUpdate(message)` with a friendly notification\n * and stops further checks (no point pinging again — restart is needed).\n * The timer is unref'd so it doesn't keep the process alive on its own.\n */\nexport function startPeriodicUpdateCheck(\n currentVersion: string,\n onUpdate: (message: string) => void,\n): void {\n if (periodicTimer) return;\n periodicTimer = setInterval(() => {\n fetchLatestVersion()\n .then((latestVersion) => {\n if (!latestVersion) return;\n if (compareVersions(latestVersion, currentVersion) <= 0) return;\n const info = detectInstallInfo();\n if (!info.updateCommand) return;\n writeState({\n lastCheckedAt: Date.now(),\n latestVersion,\n updatePending: true,\n });\n onUpdate(\n `Ken just pushed a fresh update — ${currentVersion} → ${latestVersion}! Restart ggboss to grab it (or run ${info.updateCommand} if you can't wait).`,\n );\n stopPeriodicUpdateCheck();\n })\n .catch(() => {\n // Non-fatal.\n });\n }, CHECK_INTERVAL_MS);\n periodicTimer.unref();\n}\n\nexport function stopPeriodicUpdateCheck(): void {\n if (periodicTimer) {\n clearInterval(periodicTimer);\n periodicTimer = null;\n }\n}\n","import React, { useEffect, useState } from \"react\";\nimport { Box, Text, render } from \"ink\";\nimport { AUTHOR, BRAND, COLORS, GRADIENT, VERSION } from \"./branding.js\";\nimport { getSplashAudioDurationMs, playSplashAudio } from \"./audio.js\";\n\n/**\n * Big ASCII \"GG Boss\" rendered for the splash. The block characters here are\n * ANSI Shadow-style figlet output. Whitespace is significant — every line is\n * the same width so the gradient striping aligns vertically. Do not reformat.\n */\nconst SPLASH_LINES: readonly string[] = [\n \" █████████ █████████ ███████████ \",\n \" ███░░░░░███ ███░░░░░███ ░░███░░░░░███ \",\n \" ███ ░░░ ███ ░░░ ░███ ░███ ██████ █████ █████ \",\n \"░███ ░███ ░██████████ ███░░███ ███░░ ███░░ \",\n \"░███ █████░███ █████ ░███░░░░░███░███ ░███░░█████ ░░█████ \",\n \"░░███ ░░███ ░░███ ░░███ ░███ ░███░███ ░███ ░░░░███ ░░░░███\",\n \" ░░█████████ ░░█████████ ███████████ ░░██████ ██████ ██████ \",\n \" ░░░░░░░░░ ░░░░░░░░░ ░░░░░░░░░░░ ░░░░░░ ░░░░░░ ░░░░░░ \",\n];\n\nconst SPLASH_WIDTH = SPLASH_LINES[0]!.length;\n\n/**\n * Vertical gradient stripe — assigns each line a colour from the brand\n * gradient so the logo gets a soft top→bottom hue transition. Filled glyphs\n * (`█`) take the line's hue at full brightness; shadow glyphs (`░`) inherit\n * the same hue but render at lower intensity (via `dimColor`) so they read\n * as a drop-shadow rather than fighting for visual weight with the fill.\n */\nfunction colorForLine(lineIdx: number, totalLines: number, offset: number): string {\n const t = totalLines <= 1 ? 0 : (lineIdx + offset) % totalLines;\n const idx = Math.floor((t / totalLines) * GRADIENT.length) % GRADIENT.length;\n return GRADIENT[idx]!;\n}\n\ninterface SplashProps {\n /** Pulse offset — bumping this on a timer rotates the gradient through the\n * logo for a subtle \"shimmer\" while the splash is mounted. */\n offset: number;\n}\n\nfunction SplashLogo({ offset }: SplashProps): React.ReactElement {\n return (\n <Box flexDirection=\"column\">\n {SPLASH_LINES.map((line, i) => {\n const hue = colorForLine(i, SPLASH_LINES.length, offset);\n // Split into runs so we can dim the shadow glyphs (░) without breaking\n // the line into one Text per char (which Ink would happily handle but\n // is wasteful at this scale).\n const segments: { text: string; dim: boolean }[] = [];\n let buf = \"\";\n let bufDim = false;\n for (const ch of line) {\n const dim = ch === \"░\";\n if (segments.length === 0 && buf.length === 0) {\n buf = ch;\n bufDim = dim;\n continue;\n }\n if (dim === bufDim) {\n buf += ch;\n } else {\n segments.push({ text: buf, dim: bufDim });\n buf = ch;\n bufDim = dim;\n }\n }\n if (buf) segments.push({ text: buf, dim: bufDim });\n\n return (\n <Text key={i}>\n {segments.map((seg, j) => (\n <Text key={j} color={hue} dimColor={seg.dim}>\n {seg.text}\n </Text>\n ))}\n </Text>\n );\n })}\n </Box>\n );\n}\n\ninterface SplashScreenProps {\n /** Optional caption shown under the logo — defaults to a \"Loading…\" line. */\n caption?: string;\n}\n\nexport function SplashScreen({ caption }: SplashScreenProps): React.ReactElement {\n const [offset, setOffset] = useState(0);\n // Soft shimmer — rotates the gradient through the logo every 120ms. Stops\n // when the component unmounts (the cli swaps the splash out as soon as the\n // boss has finished initialising).\n useEffect(() => {\n const timer = setInterval(() => {\n setOffset((o) => o + 1);\n }, 120);\n return () => {\n clearInterval(timer);\n };\n }, []);\n\n // Re-center on terminal resize. process.stdout.columns/rows are read live\n // each render and a \"resize\" event re-renders us so the centring stays\n // accurate even if the user resizes their window mid-splash.\n const [size, setSize] = useState(() => ({\n columns: process.stdout.columns ?? 80,\n rows: process.stdout.rows ?? 24,\n }));\n useEffect(() => {\n const handler = (): void =>\n setSize({\n columns: process.stdout.columns ?? 80,\n rows: process.stdout.rows ?? 24,\n });\n process.stdout.on(\"resize\", handler);\n return () => {\n process.stdout.off(\"resize\", handler);\n };\n }, []);\n\n // Splash height: 8 logo rows + 1 spacer + 1 brand line + 1 caption line ≈ 11.\n // We pad the top with empty rows to push the logo to the vertical centre,\n // and use Ink's flex `alignItems` for horizontal centring (works even when\n // the logo is wider than the terminal — flex just clips, no crash).\n const SPLASH_BLOCK_HEIGHT = SPLASH_LINES.length + 3;\n const verticalPad = Math.max(0, Math.floor((size.rows - SPLASH_BLOCK_HEIGHT) / 2));\n\n return (\n <Box flexDirection=\"column\" width={size.columns} height={size.rows} alignItems=\"center\">\n {/* Top spacer fills the available vertical space above the centred block. */}\n <Box height={verticalPad} flexShrink={0} />\n <Box flexDirection=\"column\" alignItems=\"flex-start\" flexShrink={0}>\n <SplashLogo offset={offset} />\n <Box width={SPLASH_WIDTH} marginTop={1} justifyContent=\"center\">\n <Text>\n <Text color={COLORS.text} bold>\n {BRAND}\n </Text>\n <Text color={COLORS.textDim}> v{VERSION}</Text>\n <Text color={COLORS.textDim}> · By </Text>\n <Text color={COLORS.text} bold>\n {AUTHOR}\n </Text>\n </Text>\n </Box>\n <Box width={SPLASH_WIDTH} justifyContent=\"center\">\n <Text color={COLORS.textDim}>{caption ?? \"Spinning up the orchestrator…\"}</Text>\n </Box>\n </Box>\n </Box>\n );\n}\n\n/**\n * Render the splash to stdout. Returns a `dismiss()` that holds the splash\n * for at least `minMs` total visible time (so even fast inits get a real\n * flash of branding) before unmounting, and resolves only after the unmount\n * has actually completed — so the caller can safely render the main app\n * next without two Ink trees coexisting on screen.\n */\nexport function showSplash(opts: { minMs?: number; caption?: string }): {\n dismiss: () => Promise<void>;\n} {\n const start = Date.now();\n // Fire-and-forget — never await. If the platform has no working player or\n // the bundled mp3 is missing, this resolves to nothing and the splash just\n // plays silently. Errors are swallowed inside playSplashAudio so the user\n // never sees an audio-related crash on launch.\n void playSplashAudio();\n const instance = render(<SplashScreen caption={opts.caption} />);\n // Default the minimum visible time to the audio duration so the user\n // doesn't get dumped into the chat mid-jingle. A small +200ms tail keeps\n // the last beat from being clipped by terminal-app sound shutdown.\n const audioDurationMs = getSplashAudioDurationMs();\n const defaultMinMs = audioDurationMs + 200;\n return {\n dismiss: async () => {\n const minMs = opts.minMs ?? defaultMinMs;\n const elapsed = Date.now() - start;\n const remaining = Math.max(0, minMs - elapsed);\n if (remaining > 0) {\n await new Promise((r) => setTimeout(r, remaining));\n }\n instance.unmount();\n // Give Ink one tick to flush the unmount writes before the caller\n // starts mounting the next tree.\n await new Promise((r) => setImmediate(r));\n },\n };\n}\n"],"mappings":"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","names":["path","import_react","fs","path","fs","path","import_jsx_runtime","path","import_react","import_react","import_react","import_react","import_react","import_react","import_react","import_jsx_runtime","import_react","import_jsx_runtime","import_react","import_jsx_runtime","currentStationId","spawn","fs","path","path","fs","spawn","import_jsx_runtime","React","log","import_react","import_jsx_runtime","cwd","path"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kenkaiiii/gg-boss",
3
- "version": "4.3.143",
3
+ "version": "4.3.144",
4
4
  "type": "module",
5
5
  "description": "Orchestrator agent that drives multiple ggcoder sessions across projects from a single chat",
6
6
  "license": "MIT",