@iroaxel/arcena 4.3.159 → 4.3.161
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.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/serve-mode.ts","../src/voice-transcriber.ts","../src/telegram.ts","../src/telegram-setup.ts","../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 -S node --max-old-space-size=8192 --expose-gc\n// Heap default (~1.5–4GB) fatal-OOMs on long boss sessions: 6 workers, large\n// tool results in message history, and Whisper/Ink tensors all live in the\n// same V8 heap. 8GB gives headroom; --expose-gc lets us nudge GC after\n// post-turn truncation. Users can override via NODE_OPTIONS — Node merges\n// shebang flags with the env var.\nimport path from \"node:path\";\nimport chalk from \"chalk\";\nimport type { Provider } from \"@iroaxel/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 { runBossServeMode, loadBossTelegramConfig } from \"./serve-mode.js\";\nimport { runBossTelegramSetup } from \"./telegram-setup.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, \"ARCena\") +\n c(COLORS.textDim, \" — orchestrator that drives multiple arcicoder workers from one chat.\\n\\n\") +\n c(COLORS.text, \"Usage\\n\") +\n \" \" +\n c(COLORS.accent, \"arcena\") +\n c(\n COLORS.textDim,\n \" start orchestrator using linked projects\\n\",\n ) +\n \" \" +\n c(COLORS.accent, \"arcena link\") +\n c(COLORS.textDim, \" pick which projects to link (interactive)\\n\") +\n \" \" +\n c(COLORS.accent, \"arcena telegram\") +\n c(COLORS.textDim, \" configure Telegram bot integration\\n\") +\n \" \" +\n c(COLORS.accent, \"arcena serve\") +\n c(COLORS.textDim, \" run the boss over Telegram (no TUI)\\n\") +\n \" \" +\n c(COLORS.accent, \"arcena continue\") +\n c(COLORS.textDim, \" resume the most recent boss session\\n\") +\n \" \" +\n c(COLORS.accent, \"arcena --resume <id>\") +\n c(COLORS.textDim, \" resume a specific boss session\\n\") +\n \" \" +\n c(COLORS.accent, \"arcena --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\n// ── `arcena serve` ────────────────────────────────────────────\n//\n// Runs the orchestrator headless and bridges it to Telegram. Resolves the bot\n// token + user ID from CLI flags > env > saved config (`arcena telegram`).\n// Boss/worker provider+model resolution mirrors interactive mode so the user\n// doesn't have to repeat themselves between `arcena` and `arcena serve`.\nasync function runServeSubcommand(argv: string[]): Promise<void> {\n let cliBotToken: string | undefined;\n let cliUserId: string | undefined;\n let cliBossModel: string | undefined;\n let cliWorkerModel: string | undefined;\n for (let i = 0; i < argv.length; i++) {\n const a = argv[i]!;\n if (a === \"--bot-token\") cliBotToken = argv[++i];\n else if (a === \"--user-id\") cliUserId = argv[++i];\n else if (a === \"--boss-model\") cliBossModel = argv[++i];\n else if (a === \"--worker-model\") cliWorkerModel = argv[++i];\n else if (a === \"--help\" || a === \"-h\") {\n process.stdout.write(\n \"\\nggboss serve — drive the boss from Telegram\\n\\n\" +\n \"Options\\n\" +\n \" --bot-token <token> Telegram bot token (or env GG_BOSS_TELEGRAM_BOT_TOKEN)\\n\" +\n \" --user-id <id> Allowed Telegram user ID (or env GG_BOSS_TELEGRAM_USER_ID)\\n\" +\n \" --boss-model <id> Override boss model\\n\" +\n \" --worker-model <id> Override worker model\\n\\n\" +\n \"Run `arcena telegram` first to save credentials interactively.\\n\\n\",\n );\n process.exit(0);\n } else {\n throw new Error(`Unknown argument: ${a}`);\n }\n }\n\n const saved = await loadBossTelegramConfig();\n const botToken = cliBotToken ?? process.env.GG_BOSS_TELEGRAM_BOT_TOKEN ?? saved?.botToken;\n const userIdStr = cliUserId ?? process.env.GG_BOSS_TELEGRAM_USER_ID;\n const userId = userIdStr ? parseInt(userIdStr, 10) : saved?.userId;\n\n if (!botToken || !userId || isNaN(userId)) {\n process.stderr.write(\n chalk.hex(COLORS.error)(\"Telegram not configured.\\n\\n\") +\n \"Run \" +\n chalk.hex(COLORS.primary).bold(\"arcena telegram\") +\n \" to set up your bot token and user ID.\\n\\n\" +\n chalk.hex(COLORS.textDim)(\"Or provide manually:\\n\") +\n chalk.hex(COLORS.textDim)(\" arcena serve --bot-token TOKEN --user-id ID\\n\"),\n );\n process.exit(1);\n }\n\n const settings = await loadSettings();\n const bossProvider = settings.bossProvider ?? \"anthropic\";\n const bossModel = cliBossModel ?? settings.bossModel ?? \"claude-opus-4-7\";\n const workerProvider = settings.workerProvider ?? \"anthropic\";\n const workerModel = cliWorkerModel ?? settings.workerModel ?? \"claude-sonnet-4-6\";\n\n await runBossServeMode({\n bossProvider,\n bossModel,\n bossThinkingLevel: settings.bossThinkingLevel,\n workerProvider,\n workerModel,\n telegram: { botToken, userId },\n });\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)(\"arcena 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 arcena.\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 if (argv[0] === \"telegram\") {\n await runBossTelegramSetup();\n process.exit(0);\n }\n\n if (argv[0] === \"serve\") {\n await runServeSubcommand(argv.slice(1));\n return;\n }\n\n // `arcena 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\n// Process-level error guards. With ~6 workers sharing the same Node process,\n// any uncaught throw or unhandled rejection would otherwise take the whole\n// orchestrator down — losing every worker's in-flight task. We log the\n// failure to ~/.gg/boss/debug.log (already initialized by this point) and\n// keep running. Truly unrecoverable conditions (OOM, native segfault) still\n// kill the process; nothing JS-side can guard against those.\nprocess.on(\"uncaughtException\", (err) => {\n const message = err instanceof Error ? err.message : String(err);\n const stack = err instanceof Error ? err.stack : undefined;\n log(\"ERROR\", \"uncaught_exception\", message, { stack });\n // Don't exit. The boss orchestrator and Ink TUI keep running; any worker\n // that got into a bad state will surface the issue via worker_error events\n // on its next interaction. This is far less disruptive than dying outright.\n});\n\nprocess.on(\"unhandledRejection\", (reason) => {\n const message = reason instanceof Error ? reason.message : String(reason);\n const stack = reason instanceof Error ? reason.stack : undefined;\n log(\"ERROR\", \"unhandled_rejection\", message, { stack });\n // Same rationale as uncaughtException — log and survive.\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 \"@iroaxel/arcicoder\";\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, type ProjectSource } 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 sourceBadge(sources: ProjectSource[]): { label: string; color: string } {\n // Fixed-width 5-char badges so names stay aligned across rows.\n if (sources.length > 1) return { label: \"[mix]\", color: COLORS.success };\n const only = sources[0];\n if (only === \"arcicoder\") return { label: \"[gg ]\", color: COLORS.accent };\n if (only === \"claude-code\") return { label: \"[cc ]\", color: COLORS.warning };\n if (only === \"codex\") return { label: \"[cx ]\", color: COLORS.primary };\n return { label: \"[?? ]\", color: COLORS.textDim };\n}\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 arcicoder projects found in ~/.gg/sessions/.</Text>\n <Text color={COLORS.textDim}>\n Run arcicoder in a project at least once, then re-run{\" \"}\n <Text color={COLORS.accent}>arcena 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 const badge = sourceBadge(p.sources);\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={badge.color}>{badge.label}</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)(\"arcena\") +\n chalk.hex(COLORS.textDim)(` to start the orchestrator.\\n`),\n );\n }\n}\n","import fs from \"node:fs/promises\";\nimport { createReadStream } from \"node:fs\";\nimport readline from \"node:readline\";\nimport os from \"node:os\";\nimport path from \"node:path\";\nimport { getAppPaths } from \"@iroaxel/arcicoder\";\n\nexport type ProjectSource = \"arcicoder\" | \"claude-code\" | \"codex\";\n\nexport interface DiscoveredProject {\n name: string;\n path: string;\n lastActiveMs: number;\n lastActiveDisplay: string;\n /** Sorted, deduped list of stores this project showed up in. */\n sources: ProjectSource[];\n}\n\n/**\n * Scan arcicoder + Claude Code + Codex session stores and return one row per\n * project, sorted most-recent first. Duplicates (same cwd) are collapsed; the\n * `sources` field lists every store the project appeared in so the picker can\n * show a combined badge.\n */\nexport async function discoverProjects(): Promise<DiscoveredProject[]> {\n const [gg, cc, cx] = await Promise.all([\n discoverGgcoderProjects(),\n discoverClaudeProjects(),\n discoverCodexProjects(),\n ]);\n\n const byPath = new Map<string, DiscoveredProject>();\n for (const p of [...gg, ...cc, ...cx]) {\n const existing = byPath.get(p.path);\n if (!existing) {\n byPath.set(p.path, p);\n continue;\n }\n byPath.set(p.path, {\n name: existing.name,\n path: existing.path,\n lastActiveMs: Math.max(existing.lastActiveMs, p.lastActiveMs),\n lastActiveDisplay: \"\", // recomputed below\n sources: mergeSources(existing.sources, p.sources),\n });\n }\n\n const merged = Array.from(byPath.values()).map((p) => ({\n ...p,\n lastActiveDisplay: formatRelativeTime(p.lastActiveMs),\n }));\n merged.sort((a, b) => b.lastActiveMs - a.lastActiveMs);\n return merged;\n}\n\nconst SOURCE_ORDER: Record<ProjectSource, number> = {\n arcicoder: 0,\n \"claude-code\": 1,\n codex: 2,\n};\n\nfunction mergeSources(a: ProjectSource[], b: ProjectSource[]): ProjectSource[] {\n const set = new Set<ProjectSource>([...a, ...b]);\n return Array.from(set).sort((x, y) => SOURCE_ORDER[x] - SOURCE_ORDER[y]);\n}\n\n/**\n * Scan ~/.gg/sessions/. Each session directory's name is the encoded cwd\n * (slashes → underscores); we decode it back and verify the directory still\n * exists on disk.\n */\nasync function discoverGgcoderProjects(): 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 const mtime = await maxJsonlMtime(dir);\n if (mtime === null) continue;\n\n const decoded = \"/\" + entry.replace(/_/g, \"/\");\n if (!(await isDirectory(decoded))) continue;\n\n results.push({\n name: path.basename(decoded),\n path: decoded,\n lastActiveMs: mtime,\n lastActiveDisplay: formatRelativeTime(mtime),\n sources: [\"arcicoder\"],\n });\n }\n return results;\n}\n\n/**\n * Scan ~/.claude/projects/. Claude Code's directory encoding replaces every\n * \"/\" with \"-\", which is genuinely ambiguous — a real dash in a path component\n * (e.g. \"gg-coder\") collides with the separator. So we extract the cwd from\n * the JSONL events themselves; Claude writes it into user/assistant records.\n * Falls back to a best-effort dash decode only if no event carries a cwd.\n */\nasync function discoverClaudeProjects(): Promise<DiscoveredProject[]> {\n const projectsDir = path.join(os.homedir(), \".claude\", \"projects\");\n let entries: string[];\n try {\n entries = await fs.readdir(projectsDir);\n } catch {\n return [];\n }\n\n const results = await Promise.all(\n entries.map(async (entry): Promise<DiscoveredProject | null> => {\n const dir = path.join(projectsDir, entry);\n const mtime = await maxJsonlMtime(dir);\n if (mtime === null) return null;\n\n const cwd =\n (await readFirstFromJsonlDir(dir, claudeCwdExtractor)) ?? fallbackDashDecode(entry);\n if (!cwd) return null;\n if (!(await isDirectory(cwd))) return null;\n\n return {\n name: path.basename(cwd),\n path: cwd,\n lastActiveMs: mtime,\n lastActiveDisplay: formatRelativeTime(mtime),\n sources: [\"claude-code\"],\n };\n }),\n );\n return results.filter((p): p is DiscoveredProject => p !== null);\n}\n\n/**\n * Scan ~/.codex/sessions/. Codex stores sessions flat by date\n * (`YYYY/MM/DD/rollout-*.jsonl`) with the cwd embedded in the first user\n * message as `<environment_context><cwd>/abs/path</cwd>...</environment_context>`.\n * We group sessions by extracted cwd and take max mtime per group.\n */\nasync function discoverCodexProjects(): Promise<DiscoveredProject[]> {\n const sessionsDir = path.join(os.homedir(), \".codex\", \"sessions\");\n if (!(await isDirectory(sessionsDir))) return [];\n\n // Layout is YYYY/MM/DD/*.jsonl — depth 4 covers it.\n const files = await collectJsonlFiles(sessionsDir, 4);\n if (files.length === 0) return [];\n\n // Process newest first so per-cwd we always start with the latest mtime.\n files.sort((a, b) => b.mtime - a.mtime);\n\n const byCwd = new Map<string, number>();\n for (const f of files) {\n const cwd = await readFirstFromFile(f.path, codexCwdExtractor);\n if (!cwd) continue;\n const prev = byCwd.get(cwd);\n if (prev === undefined || f.mtime > prev) byCwd.set(cwd, f.mtime);\n }\n\n const results: DiscoveredProject[] = [];\n for (const [cwd, mtime] of byCwd) {\n if (!(await isDirectory(cwd))) continue;\n results.push({\n name: path.basename(cwd),\n path: cwd,\n lastActiveMs: mtime,\n lastActiveDisplay: formatRelativeTime(mtime),\n sources: [\"codex\"],\n });\n }\n return results;\n}\n\nasync function isDirectory(p: string): Promise<boolean> {\n try {\n const s = await fs.stat(p);\n return s.isDirectory();\n } catch {\n return false;\n }\n}\n\nasync function maxJsonlMtime(dir: string): Promise<number | null> {\n if (!(await isDirectory(dir))) return null;\n const files = await collectJsonlFiles(dir, 2);\n if (files.length === 0) return null;\n let max = 0;\n for (const f of files) if (f.mtime > max) max = f.mtime;\n return max > 0 ? max : null;\n}\n\n/**\n * Walk `dir` up to `maxDepth` levels deep collecting every .jsonl file. Used\n * for both Claude Code (top-level + `<uuid>/subagents/`) and Codex\n * (`YYYY/MM/DD/`) layouts.\n */\nasync function collectJsonlFiles(\n dir: string,\n maxDepth: number,\n): Promise<{ path: string; mtime: number }[]> {\n const out: { path: string; mtime: number }[] = [];\n await walk(dir, 0);\n return out;\n\n async function walk(current: string, depth: number): Promise<void> {\n let entries;\n try {\n entries = await fs.readdir(current, { withFileTypes: true });\n } catch {\n return;\n }\n for (const e of entries) {\n const full = path.join(current, e.name);\n if (e.isFile() && e.name.endsWith(\".jsonl\")) {\n try {\n const s = await fs.stat(full);\n out.push({ path: full, mtime: s.mtimeMs });\n } catch {\n // skip unreadable\n }\n } else if (e.isDirectory() && depth < maxDepth) {\n await walk(full, depth + 1);\n }\n }\n }\n}\n\ntype LineExtractor = (line: string) => string | null;\n\nconst claudeCwdExtractor: LineExtractor = (line) => {\n try {\n const parsed = JSON.parse(line) as { cwd?: unknown };\n if (typeof parsed.cwd === \"string\" && parsed.cwd.startsWith(\"/\")) return parsed.cwd;\n } catch {\n // skip malformed\n }\n return null;\n};\n\nconst CODEX_CWD_RE = /<cwd>([^<]+)<\\/cwd>/;\nconst codexCwdExtractor: LineExtractor = (line) => {\n // Current format (openai/codex protocol.rs, late-2025+): RolloutLine wraps\n // SessionMeta / TurnContext items with `{ type, payload: { cwd, ... } }`.\n // First line is always SessionMeta, so this hits on read 1.\n try {\n const parsed = JSON.parse(line) as { payload?: { cwd?: unknown } };\n const cwd = parsed.payload?.cwd;\n if (typeof cwd === \"string\" && cwd.startsWith(\"/\")) return cwd;\n } catch {\n // not JSON or unexpected shape; fall through to legacy regex\n }\n // Legacy format (pre-late-2025): cwd embedded as <cwd>...</cwd> inside an\n // <environment_context> user-message string.\n const m = CODEX_CWD_RE.exec(line);\n if (m && m[1] && m[1].startsWith(\"/\")) return m[1];\n return null;\n};\n\n/**\n * Walk all .jsonl files under `dir` newest-first, returning the first non-null\n * extractor result. Walks two levels deep (matches Claude Code's nested\n * layout).\n */\nasync function readFirstFromJsonlDir(\n dir: string,\n extractor: LineExtractor,\n): Promise<string | null> {\n const files = await collectJsonlFiles(dir, 2);\n if (files.length === 0) return null;\n files.sort((a, b) => b.mtime - a.mtime);\n for (const f of files) {\n const v = await readFirstFromFile(f.path, extractor);\n if (v) return v;\n }\n return null;\n}\n\n/**\n * Stream `file` line-by-line and return the first non-null extractor result.\n * Caps lines so a giant transcript can't stall discovery.\n */\nasync function readFirstFromFile(file: string, extractor: LineExtractor): Promise<string | null> {\n return new Promise((resolve) => {\n const stream = createReadStream(file, { encoding: \"utf-8\" });\n const rl = readline.createInterface({ input: stream, crlfDelay: Infinity });\n let lines = 0;\n let done = false;\n const MAX_LINES = 200;\n // Resolve before tearing down. rl.close() synchronously emits 'close',\n // and if the close handler resolves first our real value gets swallowed.\n const finish = (value: string | null) => {\n if (done) return;\n done = true;\n resolve(value);\n rl.close();\n stream.destroy();\n };\n rl.on(\"line\", (line) => {\n if (done) return;\n lines++;\n if (lines > MAX_LINES) {\n finish(null);\n return;\n }\n const v = extractor(line);\n if (v) finish(v);\n });\n rl.on(\"close\", () => finish(null));\n rl.on(\"error\", () => finish(null));\n stream.on(\"error\", () => finish(null));\n });\n}\n\nfunction fallbackDashDecode(entry: string): string | null {\n // Strip leading \"-\" then turn remaining \"-\" into \"/\". Lossy by design — only\n // used when the JSONLs have no cwd events; the caller still verifies the\n // result is an existing directory.\n if (!entry.startsWith(\"-\")) return null;\n return \"/\" + entry.slice(1).replace(/-/g, \"/\");\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 * arcicoder'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 = \"ARCena\";\nexport const AUTHOR = \"Axel\";\n\nexport const LOGO_LINES: readonly string[] = [\n \" ▄▀▀▄ █▀▀▄ ▄▀▀▀ ▀█▀\",\n \" █▀▀█ █▀█▀ █ █ \",\n \" █ █ █ █ ▀▄▄▄ ▄█▄\",\n];\n\nexport const LOGO_GAP = \" \";\n\n/**\n * ARCena brand gradient — crimson → fuchsia. Deliberately distinct:\n * - gg-coder is cool blues/violets\n * - gg-editor is warm oranges/yellows\n * - arcena 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\": \"@iroaxel/arcena\",\n \"version\": \"4.3.159\",\n \"type\": \"module\",\n \"description\": \"Orchestrator agent that drives multiple arcicoder sessions across projects from a single chat\",\n \"license\": \"MIT\",\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"git+https://github.com/BigBlindGorg/ARCena.git\",\n \"directory\": \"packages/gg-boss\"\n },\n \"bin\": {\n \"arcena\": \"./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 \"@iroaxel/gg-agent\": \"workspace:*\",\n \"@iroaxel/gg-ai\": \"workspace:*\",\n \"@iroaxel/arcicoder\": \"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 \"optionalDependencies\": {\n \"@huggingface/transformers\": \"^3.6.0\",\n \"ogg-opus-decoder\": \"^1.6.13\"\n },\n \"publishConfig\": {\n \"access\": \"public\"\n }\n}\n","import path from \"node:path\";\nimport fs from \"node:fs/promises\";\nimport chalk from \"chalk\";\nimport { getAppPaths, MODELS, type ModelInfo } from \"@iroaxel/arcicoder\";\nimport type { Provider, ThinkingLevel } from \"@iroaxel/gg-ai\";\nimport { GGBoss } from \"./orchestrator.js\";\nimport { loadLinks } from \"./links.js\";\nimport { tasksStore } from \"./tasks-store.js\";\nimport { saveSettings } from \"./settings.js\";\nimport { transcribeVoice, isModelLoaded, setProgressCallback } from \"./voice-transcriber.js\";\nimport {\n subscribeToBossStore,\n getBossState,\n bossStore,\n type HistoryItem,\n type BossUiState,\n} from \"./boss-store.js\";\nimport { TelegramBot, type TelegramMessage, type TelegramVoiceMessage } from \"./telegram.js\";\nimport { initLogger, log, closeLogger } from \"./logger.js\";\nimport { VERSION, BRAND, AUTHOR, LOGO_LINES, LOGO_GAP, GRADIENT, COLORS } from \"./branding.js\";\n\n/**\n * `arcena serve` — drive the orchestrator from Telegram.\n *\n * Mirrors `arcicoder serve` shape (long-poll bot, allowedUserId gate) but instead\n * of one-AgentSession-per-chat, there's a single GGBoss instance. The user's\n * linked projects (from `~/.gg/boss/links.json`) are spun up as workers at\n * boot, just like `arcena` interactive mode.\n *\n * Bridge model:\n * - Telegram text → boss.enqueueUserMessage(text). The boss's run loop picks\n * it up FIFO with worker_turn_complete events.\n * - bossStore history additions → forwarded to Telegram. We subscribe to the\n * same store the Ink TUI uses, diff history length on each notify, and\n * format only the new items. This way every assistant reply, tool call,\n * worker_event, and info row the user would see in the TUI also lands in\n * the chat.\n *\n * Voice notes, multi-chat /link, and project-switching from Telegram are\n * intentionally out of scope for v1: the boss is tied to its linked projects\n * for the lifetime of the process.\n */\n\nexport interface BossServeOptions {\n bossProvider: Provider;\n bossModel: string;\n bossThinkingLevel?: ThinkingLevel;\n workerProvider: Provider;\n workerModel: string;\n workerThinkingLevel?: ThinkingLevel;\n telegram: {\n botToken: string;\n userId: number;\n };\n}\n\nexport interface BossTelegramConfig {\n botToken: string;\n userId: number;\n}\n\nfunction getTelegramConfigPath(): string {\n return path.join(getAppPaths().agentDir, \"boss\", \"telegram.json\");\n}\n\nexport async function loadBossTelegramConfig(): Promise<BossTelegramConfig | null> {\n try {\n const raw = await fs.readFile(getTelegramConfigPath(), \"utf-8\");\n const data = JSON.parse(raw) as BossTelegramConfig;\n if (data.botToken && data.userId) return data;\n return null;\n } catch {\n return null;\n }\n}\n\nexport async function saveBossTelegramConfig(config: BossTelegramConfig): Promise<void> {\n const file = getTelegramConfigPath();\n await fs.mkdir(path.dirname(file), { recursive: true });\n await fs.writeFile(file, JSON.stringify(config, null, 2), { encoding: \"utf-8\", mode: 0o600 });\n}\n\n// ── History → Telegram formatter ─────────────────────────────\n\n/**\n * Telegram is a chat surface, not a scrollback buffer — every history item\n * becomes a phone notification. We aggressively prune to only what the user\n * needs to track progress on a phone:\n *\n * keep → boss assistant text (the actual reply), errors, dispatch\n * announcements, update notices\n * drop → individual orchestration tool calls (prompt_worker,\n * dispatch_pending, add_task, peek_worker, …), per-turn\n * worker_event recaps (the boss already narrates these in its\n * assistant reply), info-level chatter, and the user's own echo\n *\n * The dropped channels are still visible in the TUI on the user's machine —\n * Telegram just sees the distilled signal.\n */\nfunction formatItemForTelegram(item: HistoryItem): string | null {\n switch (item.kind) {\n case \"user\":\n case \"tool\":\n case \"worker_event\":\n // user: echo of what they just sent\n // tool: orchestration plumbing the boss already summarizes in prose\n // worker_event: boss replies with its own narrative of the same outcome\n return null;\n\n case \"assistant\": {\n const cleaned = stripScopePrefix(item.text).trim();\n return cleaned ? truncate(cleaned, 1500) : null;\n }\n\n case \"worker_error\":\n return `✗ *${item.project}* — ${truncate(item.message, 300)}`;\n\n case \"info\":\n // Skip plain info — those are TUI-hint level (\"Ctrl+T to view tasks\",\n // \"Compacted N → M\", etc.) and just add notification noise on mobile.\n if (item.level !== \"warning\" && item.level !== \"error\") return null;\n return `${item.level === \"error\" ? \"✗ \" : \"⚠ \"}_${truncate(item.text, 300)}_`;\n\n case \"task_dispatch\": {\n if (item.tasks.length === 0) return null;\n const projects = [...new Set(item.tasks.map((t) => t.project))];\n // Single-project, single-task → one-liner. Multi → short list.\n if (item.tasks.length === 1) {\n const t = item.tasks[0]!;\n return `→ *${t.project}*: ${truncate(t.title, 140)}`;\n }\n return `→ Dispatched ${item.tasks.length} tasks across ${projects.length} project${projects.length === 1 ? \"\" : \"s\"}`;\n }\n\n case \"update_notice\":\n return `✨ ${item.text}`;\n }\n}\n\nfunction stripScopePrefix(text: string): string {\n // Boss occasionally echoes its own scope tag back in assistant text; drop it.\n return text.replace(/^\\s*\\[scope:[^\\]]+\\]\\s*/, \"\");\n}\n\nfunction truncate(text: string, max: number): string {\n if (text.length <= max) return text;\n return text.slice(0, max - 1).trimEnd() + \"…\";\n}\n\n/** Mirrors the TUI's scope pill — prefixes user messages with the active scope\n * so the boss knows whether to think globally or focus on one project. */\nfunction scopePrefix(scope: string): string {\n if (scope === \"all\") return \"[scope:all] \";\n return `[scope:${scope}] `;\n}\n\n// ── Run ──────────────────────────────────────────────────────\n\nexport async function runBossServeMode(options: BossServeOptions): Promise<void> {\n // Init persistent logger early so any boot failure has a paper trail.\n initLogger({\n version: VERSION,\n bossProvider: options.bossProvider,\n bossModel: options.bossModel,\n bossThinking: options.bossThinkingLevel,\n workerProvider: options.workerProvider,\n workerModel: options.workerModel,\n projectCount: 0,\n });\n\n // Load linked projects — same path as interactive `arcena`. Without links\n // the boss has nothing to manage, so bail with a clear error.\n const links = await loadLinks();\n if (links.projects.length === 0) {\n console.error(\n chalk.hex(COLORS.error)(\"No linked projects.\\n\") +\n chalk.hex(COLORS.textDim)(\"Run \") +\n chalk.hex(COLORS.accent)(\"arcena link\") +\n chalk.hex(COLORS.textDim)(\" first to choose which projects the boss should manage.\"),\n );\n process.exit(1);\n }\n const projects = links.projects.map((p) => ({ name: p.name, cwd: p.cwd }));\n\n await tasksStore.load();\n\n const bot = new TelegramBot({\n botToken: options.telegram.botToken,\n allowedUserId: options.telegram.userId,\n });\n\n const boss = new GGBoss({\n bossProvider: options.bossProvider,\n bossModel: options.bossModel,\n bossThinkingLevel: options.bossThinkingLevel,\n workerProvider: options.workerProvider,\n workerModel: options.workerModel,\n workerThinkingLevel: options.workerThinkingLevel,\n projects,\n });\n\n await boss.initialize();\n log(\"INFO\", \"serve\", \"boss initialized\", { projects: projects.map((p) => p.name).join(\",\") });\n\n // ── Telegram bridge: history → chat ────────────────────────\n\n const allowedChatId = options.telegram.userId; // DM with the user. Group support could be added later.\n /** Chats waiting on a number reply after `/scope` showed the picker. */\n const pendingScopeSelections = new Map<number, string[]>();\n /** Chats waiting on a number reply after `/m` / `/model-*` showed the picker.\n * Stores the target (\"boss\" or \"workers\") alongside the model list so the\n * same numeric reply path handles both pickers. */\n const pendingModelSelections = new Map<\n number,\n { target: \"boss\" | \"workers\"; models: ModelInfo[] }\n >();\n let lastHistoryLen = getBossState().history.length;\n let typingInterval: ReturnType<typeof setInterval> | null = null;\n let isStreaming = false;\n\n function sendQueued(text: string): void {\n bot.send(allowedChatId, text).catch((err) => {\n log(\"WARN\", \"telegram\", `send failed: ${err instanceof Error ? err.message : String(err)}`);\n // Retry without markdown to survive any formatting edge case.\n bot.sendPlain(allowedChatId, text.replace(/[*_`]/g, \"\")).catch(() => {});\n });\n }\n\n function startTyping(): void {\n if (typingInterval) return;\n bot.sendTyping(allowedChatId).catch(() => {});\n typingInterval = setInterval(() => {\n bot.sendTyping(allowedChatId).catch(() => {});\n }, 4000);\n }\n\n function stopTyping(): void {\n if (typingInterval) {\n clearInterval(typingInterval);\n typingInterval = null;\n }\n }\n\n function flushNewItems(state: BossUiState): void {\n const len = state.history.length;\n if (len <= lastHistoryLen) return;\n const fresh = state.history.slice(lastHistoryLen);\n lastHistoryLen = len;\n for (const item of fresh) {\n const formatted = formatItemForTelegram(item);\n if (formatted) sendQueued(formatted);\n }\n }\n\n /**\n * Apply a model choice to either the boss or every worker, persist it to\n * settings.json so the next launch defaults to the same picks, and confirm\n * via Telegram. Used by both the picker reply path and the direct\n * `/m <name>` arg path.\n */\n async function applyModelChoice(target: \"boss\" | \"workers\", selected: ModelInfo): Promise<void> {\n try {\n if (target === \"boss\") {\n await boss.switchBossModel(selected.provider, selected.id);\n await saveSettings({ bossProvider: selected.provider, bossModel: selected.id });\n await bot.send(allowedChatId, `Boss → *${selected.name}*`);\n } else {\n await boss.switchWorkerModel(selected.provider, selected.id);\n await saveSettings({ workerProvider: selected.provider, workerModel: selected.id });\n await bot.send(allowedChatId, `Workers → *${selected.name}*`);\n }\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n log(\"WARN\", \"model_switch\", message, { target, model: selected.id });\n await bot.send(allowedChatId, `Failed to switch ${target}: ${message}`);\n }\n }\n\n const unsubscribe = subscribeToBossStore(() => {\n // Drain the two-phase flush queue. In the Ink TUI a useEffect calls this\n // on every render so log-update can shrink the live area before Static\n // grows; serve mode has no Ink, so without this items would sit in\n // pendingFlush forever and the user would see \"Typing...\" with no reply.\n if (getBossState().pendingFlush.length > 0) {\n bossStore.commitPendingFlush();\n }\n\n const state = getBossState();\n flushNewItems(state);\n\n // Drive a typing indicator off the streaming flag so the user sees\n // activity even between text chunks (tools running, etc.).\n const streamingNow = state.streaming !== null;\n if (streamingNow && !isStreaming) {\n isStreaming = true;\n startTyping();\n } else if (!streamingNow && isStreaming) {\n isStreaming = false;\n stopTyping();\n }\n });\n\n // ── Telegram → boss ─────────────────────────────────────────\n\n bot.onText(async (msg: TelegramMessage) => {\n const { text, chatId } = msg;\n if (chatId !== allowedChatId) return;\n\n // Pending /scope reply (user sent just a number after the picker).\n const pendingScopes = pendingScopeSelections.get(chatId);\n if (pendingScopes && /^\\s*\\d+\\s*$/.test(text)) {\n pendingScopeSelections.delete(chatId);\n const num = parseInt(text.trim(), 10);\n if (num < 1 || num > pendingScopes.length) {\n await bot.send(chatId, \"Invalid selection. Send /scope to try again.\");\n return;\n }\n const chosen = pendingScopes[num - 1]!;\n bossStore.setScope(chosen);\n await bot.send(chatId, `Scope: *${chosen}*`);\n return;\n }\n\n // Pending /m or /model-* reply. Same number-only path for boss + workers;\n // the picker stashes which target the number applies to.\n const pendingModel = pendingModelSelections.get(chatId);\n if (pendingModel && /^\\s*\\d+\\s*$/.test(text)) {\n pendingModelSelections.delete(chatId);\n const num = parseInt(text.trim(), 10);\n if (num < 1 || num > pendingModel.models.length) {\n await bot.send(chatId, \"Invalid selection. Send /m to try again.\");\n return;\n }\n const selected = pendingModel.models[num - 1]!;\n await applyModelChoice(pendingModel.target, selected);\n return;\n }\n\n if (!text.startsWith(\"/\")) {\n // Match the TUI: prepend the active scope so the boss knows whether\n // the user is talking about all projects or a specific worker. Without\n // this every Telegram message would be implicitly \"all\" regardless of\n // /scope — same prefix the orchestrator-app uses on submit.\n const scoped = scopePrefix(getBossState().scope) + text;\n boss.enqueueUserMessage(scoped);\n return;\n }\n\n const parts = text.trim().split(/\\s+/);\n const cmd = parts[0]!.slice(1).toLowerCase().replace(/@\\w+$/, \"\");\n\n if (cmd === \"help\" || cmd === \"start\") {\n await bot.send(chatId, buildTelegramHelpText());\n return;\n }\n\n // /m, /model, /model-boss, /model-workers — mirrors the TUI's two pickers.\n // Bare /m and /model open the BOSS picker (most common ask); the explicit\n // -workers form is required to swap workers since that touches every active\n // session and we want it deliberate.\n if (cmd === \"m\" || cmd === \"model\" || cmd === \"model-boss\" || cmd === \"model-workers\") {\n const target: \"boss\" | \"workers\" = cmd === \"model-workers\" ? \"workers\" : \"boss\";\n const arg = parts.slice(1).join(\" \").trim().toLowerCase();\n const state = getBossState();\n const currentId = target === \"boss\" ? state.bossModel : state.workerModel;\n\n if (arg) {\n const num = parseInt(arg, 10);\n let match: ModelInfo | undefined;\n if (!isNaN(num) && num >= 1 && num <= MODELS.length) {\n match = MODELS[num - 1]!;\n } else {\n match = MODELS.find(\n (m) => m.name.toLowerCase().includes(arg) || m.id.toLowerCase().includes(arg),\n );\n }\n if (!match) {\n await bot.send(chatId, `No model matching \"${arg}\". Send /${cmd} to see the list.`);\n return;\n }\n await applyModelChoice(target, match);\n return;\n }\n\n // No arg → numbered picker grouped by provider.\n let listText = `*${target === \"boss\" ? \"Boss\" : \"Worker\"} model*\\n`;\n let lastProvider = \"\";\n MODELS.forEach((m, i) => {\n if (m.provider !== lastProvider) {\n lastProvider = m.provider;\n listText += `\\n_${providerLabel(m.provider)}_\\n`;\n }\n const active = m.id === currentId ? \" ←\" : \"\";\n listText += ` *${i + 1}.* ${m.name}${active}\\n`;\n });\n listText += `\\nSend the number, or \\`/${cmd} <name>\\`.`;\n pendingModelSelections.set(chatId, { target, models: [...MODELS] });\n await bot.send(chatId, listText);\n return;\n }\n\n if (cmd === \"scope\" || cmd === \"s\") {\n const state = getBossState();\n const arg = parts.slice(1).join(\" \").trim().toLowerCase();\n const names = [\"all\", ...state.workers.map((w) => w.name)];\n\n // No arg → show numbered picker. Tap-friendly on mobile.\n if (!arg) {\n const lines = names.map((n, i) => {\n const active = n === state.scope ? \" ←\" : \"\";\n const label = n === \"all\" ? \"*All*\" : `*${n}*`;\n return `*${i + 1}.* ${label}${active}`;\n });\n pendingScopeSelections.set(chatId, names);\n await bot.send(\n chatId,\n `*Scope* — current: *${state.scope}*\\n\\n${lines.join(\"\\n\")}\\n\\nSend the number, or \\`/scope <name>\\`.`,\n );\n return;\n }\n\n // Direct switch by number or name fragment.\n const num = parseInt(arg, 10);\n let chosen: string | null;\n if (!isNaN(num) && num >= 1 && num <= names.length) {\n chosen = names[num - 1]!;\n } else {\n const exact = names.find((n) => n.toLowerCase() === arg);\n chosen = exact ?? names.find((n) => n.toLowerCase().includes(arg)) ?? null;\n }\n if (!chosen) {\n await bot.send(chatId, `No scope matching \"${arg}\". Send /scope to see the list.`);\n return;\n }\n bossStore.setScope(chosen);\n await bot.send(chatId, `Scope: *${chosen}*`);\n return;\n }\n\n if (cmd === \"status\") {\n const state = getBossState();\n const lines: string[] = [`*${BRAND}* — ${state.bossModel}`, `Scope *${state.scope}*`, \"\"];\n lines.push(\"*Workers*\");\n for (const w of state.workers) {\n const dot = w.status === \"working\" ? \"●\" : w.status === \"error\" ? \"✗\" : \"○\";\n lines.push(` ${dot} *${w.name}* — _${w.status}_`);\n }\n const tasks = tasksStore.list();\n const open = tasks.filter((t) => t.status === \"pending\" || t.status === \"in_progress\").length;\n lines.push(\"\");\n lines.push(`Tasks ${open} open · ${tasks.length} total`);\n await bot.send(chatId, lines.join(\"\\n\"));\n return;\n }\n\n if (cmd === \"cancel\") {\n boss.abort();\n await bot.send(chatId, \"_Aborted current boss turn._\");\n return;\n }\n\n if (cmd === \"new\" || cmd === \"n\") {\n await boss.newSession();\n await bot.send(chatId, \"── *New session* ──\");\n return;\n }\n\n if (cmd === \"tasks\") {\n const tasks = tasksStore.list();\n if (tasks.length === 0) {\n await bot.send(chatId, \"_No tasks._\");\n return;\n }\n const lines = tasks.slice(0, 30).map((t, i) => {\n const status = t.status.replace(\"_\", \" \");\n return `*${i + 1}.* [${status}] *${t.project}* — ${t.description.split(\"\\n\")[0]}`;\n });\n await bot.send(chatId, `*Tasks*\\n\\n${lines.join(\"\\n\")}`);\n return;\n }\n\n // Anything else — pass straight through as a prompt; the boss may\n // recognize its own slash conventions (e.g. /compact handled in the TUI\n // layer) or just treat it as text. For unknown commands we still ship\n // the raw text so the boss can interpret it in context.\n boss.enqueueUserMessage(text);\n });\n\n // ── Voice notes ──────────────────────────────────────────────\n //\n // Mirrors `arcicoder serve`: download the OGG Opus blob from Telegram, decode\n // + transcribe locally with Whisper-tiny.en, then route the transcribed text\n // through the same scope-prefix path as a typed message. Whisper model is\n // ~75MB and downloaded on first use; we surface that as a one-time hint so\n // the user understands the initial silence.\n bot.onVoice(async (msg: TelegramVoiceMessage) => {\n const { chatId } = msg;\n if (chatId !== allowedChatId) return;\n\n try {\n if (!isModelLoaded()) {\n await bot.send(\n chatId,\n \"Setting up voice transcription — downloading Whisper model. This only happens once.\",\n );\n setProgressCallback((info) => {\n if (info.status === \"progress\" && info.progress !== undefined) {\n const pct = Math.round(info.progress);\n // Keep the typing indicator alive while a long download streams.\n if (pct % 25 === 0 && pct > 0) {\n bot.sendTyping(chatId).catch(() => {});\n }\n }\n });\n }\n await bot.sendTyping(chatId);\n\n const fileUrl = await bot.getFileUrl(msg.fileId);\n const transcribed = await transcribeVoice(fileUrl);\n if (!transcribed) {\n await bot.send(chatId, \"_Could not transcribe voice note._\");\n return;\n }\n\n await bot.send(chatId, `_Voice: \"${transcribed}\"_`);\n const scoped = scopePrefix(getBossState().scope) + transcribed;\n boss.enqueueUserMessage(scoped);\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n log(\"ERROR\", \"voice\", message);\n // Common failure: optional dep missing on user's install.\n const hint = /Cannot find module|Cannot resolve|MODULE_NOT_FOUND/.test(message)\n ? \"\\n\\nVoice transcription needs the optional `@huggingface/transformers` and `ogg-opus-decoder` packages. Reinstall with `npm i -g @iroaxel/arcena` and ensure optional deps installed.\"\n : \"\";\n await bot.send(chatId, `_Voice transcription failed: ${message}_${hint}`);\n }\n });\n\n // ── Boot banner ─────────────────────────────────────────────\n\n process.stdout.write(\"\\x1b[2J\\x1b[3J\\x1b[H\");\n printBanner({\n bossModel: options.bossModel,\n workerModel: options.workerModel,\n userId: options.telegram.userId,\n projectCount: projects.length,\n });\n\n // ── Shutdown ────────────────────────────────────────────────\n\n let shuttingDown = false;\n const shutdown = async (): Promise<void> => {\n if (shuttingDown) return;\n shuttingDown = true;\n console.log(chalk.hex(COLORS.textDim)(\"\\nShutting down...\"));\n bot.stop();\n stopTyping();\n unsubscribe();\n await boss.dispose().catch(() => {});\n closeLogger();\n process.exit(0);\n };\n process.on(\"SIGINT\", () => void shutdown());\n process.on(\"SIGTERM\", () => void shutdown());\n\n // ── Run ─────────────────────────────────────────────────────\n\n // Boss event loop. Runs forever, processes user_message + worker events.\n const runPromise = boss.run().catch((err) => {\n log(\"ERROR\", \"boss\", err instanceof Error ? err.message : String(err));\n });\n\n // Long-poll Telegram. Returns when bot.stop() is called.\n await bot.start();\n await runPromise;\n}\n\n// ── Help & banner ──────────────────────────────────────────────\n\nfunction buildTelegramHelpText(): string {\n return [\n \"*ARCena* — orchestrator over Telegram\",\n \"\",\n \"*Commands*\",\n \"/scope (/s) — switch project focus (All / per-worker)\",\n \"/m, /model-boss — switch the orchestrator's model\",\n \"/model-workers — switch every worker's model\",\n \"/status — workers + open tasks\",\n \"/tasks — list tasks\",\n \"/new — fresh boss session\",\n \"/cancel — abort the current boss turn\",\n \"/help — this message\",\n \"\",\n \"Voice notes are transcribed locally with Whisper and sent as prompts.\",\n \"Send any message to talk to the boss.\",\n ].join(\"\\n\");\n}\n\nfunction providerLabel(provider: Provider): string {\n switch (provider) {\n case \"anthropic\":\n return \"Anthropic\";\n case \"openai\":\n return \"OpenAI\";\n case \"glm\":\n return \"Z.AI\";\n case \"moonshot\":\n return \"Moonshot\";\n case \"minimax\":\n return \"MiniMax\";\n case \"deepseek\":\n return \"DeepSeek\";\n case \"openrouter\":\n return \"OpenRouter\";\n case \"xiaomi\":\n return \"Xiaomi\";\n default:\n return provider;\n }\n}\n\nfunction gradientText(text: string): string {\n let i = 0;\n return text\n .split(\"\")\n .map((ch) => (ch === \" \" ? ch : chalk.hex(GRADIENT[i++ % GRADIENT.length]!)(ch)))\n .join(\"\");\n}\n\nfunction printBanner(opts: {\n bossModel: string;\n workerModel: string;\n userId: number;\n projectCount: number;\n}): void {\n console.log();\n console.log(\n ` ${gradientText(LOGO_LINES[0]!)}${LOGO_GAP}` +\n chalk.hex(COLORS.primary).bold(BRAND) +\n chalk.hex(COLORS.textDim)(` v${VERSION}`) +\n chalk.hex(COLORS.textDim)(\" · By \") +\n chalk.white.bold(AUTHOR),\n );\n console.log(\n ` ${gradientText(LOGO_LINES[1]!)}${LOGO_GAP}` +\n chalk.hex(COLORS.accent)(`Boss: ${opts.bossModel}`),\n );\n console.log(\n ` ${gradientText(LOGO_LINES[2]!)}${LOGO_GAP}` +\n chalk.hex(COLORS.textDim)(`Workers: ${opts.workerModel}`),\n );\n console.log();\n console.log(\n chalk.hex(COLORS.textDim)(\" Mode \") +\n chalk.hex(COLORS.accent)(\"Telegram\") +\n chalk.hex(COLORS.textDim)(\" · User \") +\n chalk.white(String(opts.userId)) +\n chalk.hex(COLORS.textDim)(\n ` · ${opts.projectCount} project${opts.projectCount === 1 ? \"\" : \"s\"}`,\n ),\n );\n console.log();\n console.log(\n chalk.hex(COLORS.success)(\" Ready. \") +\n chalk.hex(COLORS.textDim)(\"Open Telegram and message your bot.\"),\n );\n console.log();\n console.log(\n chalk.hex(COLORS.textDim)(\" /help \") +\n chalk.hex(COLORS.textDim)(\"commands\") +\n chalk.hex(COLORS.textDim)(\" /status \") +\n chalk.hex(COLORS.textDim)(\"workers + tasks\") +\n chalk.hex(COLORS.textDim)(\" /cancel \") +\n chalk.hex(COLORS.textDim)(\"abort turn\"),\n );\n console.log();\n}\n","/**\n * Voice note transcription using local Whisper model.\n * Uses @huggingface/transformers (pure JS/WASM) — no native deps, no API keys.\n * Model (~75MB) is downloaded on first use and cached locally.\n */\n\nimport type { AutomaticSpeechRecognitionPipeline } from \"@huggingface/transformers\";\n\nconst TARGET_SAMPLE_RATE = 16000;\nconst MODEL_ID = \"Xenova/whisper-tiny.en\";\n\nlet transcriber: AutomaticSpeechRecognitionPipeline | null = null;\nlet loadPromise: Promise<AutomaticSpeechRecognitionPipeline> | null = null;\n\n/** Optional callback for model download progress. */\nexport type ProgressCallback = (info: { status: string; progress?: number; file?: string }) => void;\n\nlet onProgress: ProgressCallback | null = null;\n\n/** Set a callback to receive model download progress updates. */\nexport function setProgressCallback(cb: ProgressCallback | null): void {\n onProgress = cb;\n}\n\n/**\n * Resample audio from one sample rate to another using linear interpolation.\n */\nexport function resample(audio: Float32Array, fromRate: number, toRate: number): Float32Array {\n if (fromRate === toRate) return audio;\n const ratio = fromRate / toRate;\n const newLength = Math.round(audio.length / ratio);\n const result = new Float32Array(newLength);\n for (let i = 0; i < newLength; i++) {\n const srcIndex = i * ratio;\n const low = Math.floor(srcIndex);\n const high = Math.min(low + 1, audio.length - 1);\n const frac = srcIndex - low;\n result[i] = audio[low]! * (1 - frac) + audio[high]! * frac;\n }\n return result;\n}\n\n/**\n * Downmix multi-channel audio to mono by averaging all channels.\n */\nexport function downmixToMono(channelData: Float32Array[]): Float32Array {\n if (channelData.length === 0) return new Float32Array();\n if (channelData.length === 1) return channelData[0]!;\n\n const samples = channelData[0]!.length;\n const out = new Float32Array(samples);\n const scale = 1 / channelData.length;\n for (let i = 0; i < samples; i++) {\n let mixed = 0;\n for (const channel of channelData) mixed += channel[i] ?? 0;\n out[i] = mixed * scale;\n }\n return out;\n}\n\n/**\n * Decode OGG Opus audio buffer to 16kHz mono PCM Float32Array.\n */\nexport async function decodeOggOpus(buffer: Uint8Array): Promise<Float32Array> {\n const { OggOpusDecoder } = await import(\"ogg-opus-decoder\");\n const decoder = new OggOpusDecoder();\n await decoder.ready;\n try {\n const decoded = await decoder.decodeFile(buffer);\n\n if (!decoded.channelData?.length || !decoded.channelData[0]?.length) {\n throw new Error(\"Decoded audio is empty\");\n }\n\n const mono = downmixToMono(decoded.channelData);\n return resample(mono, decoded.sampleRate, TARGET_SAMPLE_RATE);\n } finally {\n decoder.free();\n }\n}\n\n/**\n * Get or initialize the Whisper transcription pipeline.\n * Model is downloaded on first use and cached by transformers.js.\n */\nasync function getTranscriber(): Promise<AutomaticSpeechRecognitionPipeline> {\n if (transcriber) return transcriber;\n\n if (!loadPromise) {\n loadPromise = (async () => {\n const { pipeline } = await import(\"@huggingface/transformers\");\n const instance = await pipeline(\"automatic-speech-recognition\", MODEL_ID, {\n dtype: \"fp32\",\n progress_callback: onProgress ?? undefined,\n });\n transcriber = instance;\n return instance;\n })();\n }\n\n return loadPromise;\n}\n\n/** Whether the model has been loaded already. */\nexport function isModelLoaded(): boolean {\n return transcriber !== null;\n}\n\n/**\n * Transcribe a voice message from its Telegram file URL.\n * Downloads the OGG Opus file, decodes to PCM, and runs Whisper locally.\n */\nexport async function transcribeVoice(fileUrl: string): Promise<string> {\n // Download the audio file\n const response = await fetch(fileUrl);\n if (!response.ok) throw new Error(`Failed to download voice file: ${response.status}`);\n const buffer = new Uint8Array(await response.arrayBuffer());\n\n // Decode OGG Opus → 16kHz mono PCM\n const pcm = await decodeOggOpus(buffer);\n\n // Transcribe with Whisper\n const asr = await getTranscriber();\n const result = await asr(pcm);\n\n const text = Array.isArray(result) ? result[0]?.text : (result as { text: string }).text;\n return (text ?? \"\").trim();\n}\n","/**\n * Minimal Telegram Bot API client using raw fetch().\n * Supports long polling, markdown messages, inline keyboards, and message splitting.\n */\n\nconst TELEGRAM_API = \"https://api.telegram.org\";\nconst MAX_MESSAGE_LENGTH = 4096;\n\nexport interface TelegramConfig {\n botToken: string;\n /** Only accept messages from this Telegram user ID. */\n allowedUserId: number;\n}\n\nexport interface TelegramUpdate {\n update_id: number;\n message?: {\n message_id: number;\n from: { id: number; first_name: string };\n chat: { id: number; type: string; title?: string };\n text?: string;\n voice?: { file_id: string; duration: number; mime_type?: string; file_size?: number };\n };\n callback_query?: {\n id: string;\n from: { id: number };\n message: { chat: { id: number } };\n data: string;\n };\n my_chat_member?: {\n chat: { id: number; type: string; title?: string };\n from: { id: number };\n new_chat_member: { status: string };\n };\n}\n\nexport interface InlineButton {\n text: string;\n callback_data: string;\n}\n\n/** Incoming message with chat context. */\nexport interface TelegramMessage {\n text: string;\n chatId: number;\n chatType: \"private\" | \"group\" | \"supergroup\" | \"channel\";\n chatTitle?: string;\n}\n\n/** Incoming voice note with chat context. */\nexport interface TelegramVoiceMessage {\n fileId: string;\n duration: number;\n chatId: number;\n chatType: \"private\" | \"group\" | \"supergroup\" | \"channel\";\n chatTitle?: string;\n}\n\nexport class TelegramBot {\n private token: string;\n private allowedUserId: number;\n private offset = 0;\n private running = false;\n\n private onMessage: ((msg: TelegramMessage) => void) | null = null;\n private onVoiceMessage: ((msg: TelegramVoiceMessage) => void) | null = null;\n private onCallback: ((data: string, chatId: number) => void) | null = null;\n private onBotAdded: ((chatId: number, chatTitle?: string) => void) | null = null;\n private onBotRemoved: ((chatId: number) => void) | null = null;\n\n constructor(config: TelegramConfig) {\n this.token = config.botToken;\n this.allowedUserId = config.allowedUserId;\n }\n\n /** Register handler for incoming text messages. */\n onText(handler: (msg: TelegramMessage) => void): void {\n this.onMessage = handler;\n }\n\n /** Register handler for incoming voice notes. */\n onVoice(handler: (msg: TelegramVoiceMessage) => void): void {\n this.onVoiceMessage = handler;\n }\n\n /** Register handler for inline keyboard button presses. */\n onCallbackQuery(handler: (data: string, chatId: number) => void): void {\n this.onCallback = handler;\n }\n\n /** Register handler for when the bot is added to a group. */\n onAddedToGroup(handler: (chatId: number, chatTitle?: string) => void): void {\n this.onBotAdded = handler;\n }\n\n /** Register handler for when the bot is removed from a group. */\n onRemovedFromGroup(handler: (chatId: number) => void): void {\n this.onBotRemoved = handler;\n }\n\n /** Start long polling. Blocks until stop() is called. */\n async start(): Promise<void> {\n this.running = true;\n\n // Verify bot token works\n const me = await this.apiCall(\"getMe\");\n if (!me.ok) {\n throw new Error(`Invalid bot token: ${JSON.stringify(me)}`);\n }\n\n while (this.running) {\n try {\n const updates = await this.getUpdates();\n for (const update of updates) {\n await this.handleUpdate(update);\n }\n } catch (err) {\n if (!this.running) break;\n console.error(`[telegram] Poll error: ${err instanceof Error ? err.message : err}`);\n await sleep(3000);\n }\n }\n }\n\n /** Stop long polling. */\n stop(): void {\n this.running = false;\n }\n\n /** Send a text message to a specific chat. Converts markdown and splits long messages. */\n async send(chatId: number, text: string, buttons?: InlineButton[][]): Promise<void> {\n const converted = toTelegramMarkdown(text);\n const chunks = splitMessage(converted);\n\n for (let i = 0; i < chunks.length; i++) {\n const isLast = i === chunks.length - 1;\n const replyMarkup =\n isLast && buttons\n ? {\n inline_keyboard: buttons.map((row) =>\n row.map((b) => ({ text: b.text, callback_data: b.callback_data })),\n ),\n }\n : undefined;\n\n await this.apiCall(\"sendMessage\", {\n chat_id: chatId,\n text: chunks[i],\n parse_mode: \"Markdown\",\n ...(replyMarkup ? { reply_markup: replyMarkup } : {}),\n });\n }\n }\n\n /** Send a plain text message (no markdown parsing) to a specific chat. */\n async sendPlain(chatId: number, text: string): Promise<void> {\n const chunks = splitMessage(text);\n for (const chunk of chunks) {\n await this.apiCall(\"sendMessage\", {\n chat_id: chatId,\n text: chunk,\n });\n }\n }\n\n /** Send a typing indicator to a specific chat. */\n async sendTyping(chatId: number): Promise<void> {\n await this.apiCall(\"sendChatAction\", {\n chat_id: chatId,\n action: \"typing\",\n });\n }\n\n /** Get a direct download URL for a Telegram file. */\n async getFileUrl(fileId: string): Promise<string> {\n const result = await this.apiCall(\"getFile\", { file_id: fileId });\n if (!result.ok) throw new Error(`Failed to get file: ${JSON.stringify(result)}`);\n const filePath = (result.result as { file_path: string }).file_path;\n return `${TELEGRAM_API}/file/bot${this.token}/${filePath}`;\n }\n\n // ── Private ───────────────────────────────────────────\n\n private async getUpdates(): Promise<TelegramUpdate[]> {\n const result = await this.apiCall(\"getUpdates\", {\n offset: this.offset,\n timeout: 30,\n allowed_updates: [\"message\", \"callback_query\", \"my_chat_member\"],\n });\n\n if (!result.ok || !Array.isArray(result.result)) return [];\n\n const updates = result.result as TelegramUpdate[];\n if (updates.length > 0) {\n this.offset = updates[updates.length - 1]!.update_id + 1;\n }\n return updates;\n }\n\n private async handleUpdate(update: TelegramUpdate): Promise<void> {\n if (update.message) {\n const msg = update.message;\n\n // Auth check\n if (msg.from.id !== this.allowedUserId) {\n return;\n }\n\n if (msg.text && this.onMessage) {\n this.onMessage({\n text: msg.text,\n chatId: msg.chat.id,\n chatType: msg.chat.type as TelegramMessage[\"chatType\"],\n chatTitle: msg.chat.title,\n });\n } else if (msg.voice && this.onVoiceMessage) {\n this.onVoiceMessage({\n fileId: msg.voice.file_id,\n duration: msg.voice.duration,\n chatId: msg.chat.id,\n chatType: msg.chat.type as TelegramMessage[\"chatType\"],\n chatTitle: msg.chat.title,\n });\n }\n }\n\n // Bot membership changed in a group\n if (update.my_chat_member) {\n const member = update.my_chat_member;\n const status = member.new_chat_member.status;\n if ((status === \"member\" || status === \"administrator\") && this.onBotAdded) {\n this.onBotAdded(member.chat.id, member.chat.title);\n } else if ((status === \"left\" || status === \"kicked\") && this.onBotRemoved) {\n this.onBotRemoved(member.chat.id);\n }\n }\n\n if (update.callback_query) {\n const cb = update.callback_query;\n\n if (cb.from.id !== this.allowedUserId) return;\n\n await this.apiCall(\"answerCallbackQuery\", { callback_query_id: cb.id });\n\n if (cb.data && this.onCallback) {\n this.onCallback(cb.data, cb.message.chat.id);\n }\n }\n }\n\n private async apiCall(\n method: string,\n body?: Record<string, unknown>,\n ): Promise<{ ok: boolean; result?: unknown }> {\n const url = `${TELEGRAM_API}/bot${this.token}/${method}`;\n\n const response = await fetch(url, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: body ? JSON.stringify(body) : undefined,\n });\n\n if (!response.ok) {\n return { ok: false };\n }\n\n return response.json() as Promise<{ ok: boolean; result?: unknown }>;\n }\n}\n\n// ── Markdown Conversion ──────────────────────────────────\n\n/**\n * Convert GitHub-flavored markdown to Telegram-compatible Markdown.\n *\n * Telegram supports: *bold*, _italic_, `code`, ```pre```, [link](url)\n * Does NOT support: headings, horizontal rules, tables, HTML tags, images\n */\nfunction toTelegramMarkdown(text: string): string {\n const lines = text.split(\"\\n\");\n const result: string[] = [];\n let inCodeBlock = false;\n\n for (const line of lines) {\n if (line.trimStart().startsWith(\"```\")) {\n inCodeBlock = !inCodeBlock;\n result.push(line);\n continue;\n }\n\n if (inCodeBlock) {\n result.push(line);\n continue;\n }\n\n let transformed = line;\n\n // Headings → bold text\n const headingMatch = transformed.match(/^(#{1,6})\\s+(.+)$/);\n if (headingMatch) {\n transformed = `*${headingMatch[2]}*`;\n result.push(transformed);\n continue;\n }\n\n // Horizontal rules → empty line\n if (/^(-{3,}|_{3,}|\\*{3,})$/.test(transformed.trim())) {\n result.push(\"\");\n continue;\n }\n\n // **bold** → *bold*\n transformed = transformed.replace(/\\*\\*(.+?)\\*\\*/g, \"*$1*\");\n\n result.push(transformed);\n }\n\n return result.join(\"\\n\");\n}\n\n// ── Helpers ───────────────────────────────────────────────\n\nfunction splitMessage(text: string): string[] {\n if (text.length <= MAX_MESSAGE_LENGTH) return [text];\n\n const chunks: string[] = [];\n let remaining = text;\n\n while (remaining.length > 0) {\n if (remaining.length <= MAX_MESSAGE_LENGTH) {\n chunks.push(remaining);\n break;\n }\n\n let splitAt = remaining.lastIndexOf(\"\\n\", MAX_MESSAGE_LENGTH);\n if (splitAt === -1 || splitAt < MAX_MESSAGE_LENGTH * 0.5) {\n splitAt = remaining.lastIndexOf(\" \", MAX_MESSAGE_LENGTH);\n }\n if (splitAt === -1 || splitAt < MAX_MESSAGE_LENGTH * 0.5) {\n splitAt = MAX_MESSAGE_LENGTH;\n }\n\n chunks.push(remaining.slice(0, splitAt));\n remaining = remaining.slice(splitAt).trimStart();\n }\n\n return chunks;\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((r) => setTimeout(r, ms));\n}\n","import readline from \"node:readline/promises\";\nimport chalk from \"chalk\";\nimport { COLORS, GRADIENT, LOGO_LINES, LOGO_GAP, BRAND, AUTHOR, VERSION } from \"./branding.js\";\nimport {\n loadBossTelegramConfig,\n saveBossTelegramConfig,\n type BossTelegramConfig,\n} from \"./serve-mode.js\";\n\n/**\n * `arcena telegram` — interactive setup wizard. Mirrors `arcicoder telegram` but\n * writes to `~/.gg/boss/telegram.json` so the boss has its own bot identity\n * (distinct from arcicoder's coding bot).\n */\nexport async function runBossTelegramSetup(): Promise<void> {\n process.stdout.write(\"\\x1b[2J\\x1b[3J\\x1b[H\");\n printSetupBanner();\n\n const existing = await loadBossTelegramConfig();\n if (existing) {\n console.log(\n chalk.hex(COLORS.textDim)(\" Current config:\\n\") +\n chalk.hex(COLORS.textDim)(\n ` Bot token: ${existing.botToken.slice(0, 10)}...${existing.botToken.slice(-4)}\\n`,\n ) +\n chalk.hex(COLORS.textDim)(` User ID: ${existing.userId}\\n`),\n );\n }\n\n const rl = readline.createInterface({ input: process.stdin, output: process.stdout });\n try {\n console.log(\n chalk.hex(COLORS.accent)(\" Step 1: Bot Token\\n\") +\n chalk.hex(COLORS.textDim)(\" 1. Open BotFather: \") +\n chalk.hex(COLORS.primary).underline(\"https://t.me/BotFather\") +\n \"\\n\" +\n chalk.hex(COLORS.textDim)(\" 2. Send /newbot and follow the prompts\\n\") +\n chalk.hex(COLORS.textDim)(\" 3. Copy the bot token\\n\"),\n );\n\n const tokenPrompt = existing\n ? chalk.hex(COLORS.primary)(\" Paste bot token (enter to keep current): \")\n : chalk.hex(COLORS.primary)(\" Paste bot token: \");\n const tokenInput = await rl.question(tokenPrompt);\n const botToken = tokenInput.trim() || existing?.botToken;\n\n if (!botToken) {\n console.log(chalk.hex(COLORS.error)(\"\\n No bot token provided. Setup cancelled.\"));\n return;\n }\n if (!/^\\d+:[A-Za-z0-9_-]+$/.test(botToken)) {\n console.log(\n chalk.hex(COLORS.error)(\"\\n Invalid token format. Expected: 123456789:ABCdef...\"),\n );\n return;\n }\n\n console.log(\n chalk.hex(COLORS.accent)(\"\\n Step 2: User ID\\n\") +\n chalk.hex(COLORS.textDim)(\" 1. Open userinfobot: \") +\n chalk.hex(COLORS.primary).underline(\"https://t.me/userinfobot\") +\n \"\\n\" +\n chalk.hex(COLORS.textDim)(\" 2. Send any message — it replies with your numeric ID\\n\") +\n chalk.hex(COLORS.textDim)(\" Only this user ID can control the boss.\\n\"),\n );\n\n const userPrompt = existing\n ? chalk.hex(COLORS.primary)(` Your Telegram user ID (enter to keep ${existing.userId}): `)\n : chalk.hex(COLORS.primary)(\" Your Telegram user ID: \");\n const userInput = await rl.question(userPrompt);\n const userId = userInput.trim() ? parseInt(userInput.trim(), 10) : existing?.userId;\n\n if (!userId || isNaN(userId)) {\n console.log(chalk.hex(COLORS.error)(\"\\n Invalid user ID. Must be a number.\"));\n return;\n }\n\n console.log(chalk.hex(COLORS.textDim)(\"\\n Verifying bot token...\"));\n const verifyRes = await fetch(`https://api.telegram.org/bot${botToken}/getMe`, {\n method: \"POST\",\n });\n const verifyData = (await verifyRes.json()) as {\n ok: boolean;\n result?: { username: string; first_name: string };\n };\n if (!verifyData.ok || !verifyData.result) {\n console.log(\n chalk.hex(COLORS.error)(\n \"\\n Invalid bot token — Telegram rejected it. Check and try again.\",\n ),\n );\n return;\n }\n\n const config: BossTelegramConfig = { botToken, userId };\n await saveBossTelegramConfig(config);\n\n console.log(\n chalk.hex(COLORS.success)(\n `\\n ✓ Connected to @${verifyData.result.username} (${verifyData.result.first_name})\\n`,\n ) +\n chalk.hex(COLORS.success)(` ✓ Authorized user ID: ${userId}\\n\\n`) +\n chalk.hex(COLORS.primary)(\" To start:\\n\") +\n chalk.hex(COLORS.textDim)(\" arcena serve\\n\"),\n );\n } finally {\n rl.close();\n }\n}\n\nfunction gradientText(text: string): string {\n let i = 0;\n return text\n .split(\"\")\n .map((ch) => (ch === \" \" ? ch : chalk.hex(GRADIENT[i++ % GRADIENT.length]!)(ch)))\n .join(\"\");\n}\n\nfunction printSetupBanner(): void {\n console.log();\n console.log(\n ` ${gradientText(LOGO_LINES[0]!)}${LOGO_GAP}` +\n chalk.hex(COLORS.primary).bold(BRAND) +\n chalk.hex(COLORS.textDim)(` v${VERSION}`) +\n chalk.hex(COLORS.textDim)(\" · By \") +\n chalk.white.bold(AUTHOR),\n );\n console.log(\n ` ${gradientText(LOGO_LINES[1]!)}${LOGO_GAP}` + chalk.hex(COLORS.accent)(\"Telegram Setup\"),\n );\n console.log(\n ` ${gradientText(LOGO_LINES[2]!)}${LOGO_GAP}` + chalk.hex(COLORS.textDim)(\"Remote Control\"),\n );\n console.log();\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 \"@iroaxel/arcicoder/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 \"@iroaxel/arcicoder/ui\";\nimport { useDoublePress } from \"@iroaxel/arcicoder/ui/hooks/double-press\";\nimport type { Provider } from \"@iroaxel/gg-ai\";\nimport { TerminalSizeProvider, useTerminalSize } from \"@iroaxel/arcicoder/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 BossOverlay,\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. Wired in `renderBossApp` to ANSI-wipe the terminal,\n * unmount the current Ink instance, and render a fresh one — the only\n * reliable way to reset log-update's internal cursor/line-count tracking\n * without the drift that manifests as \"input pushed upward\" after /clear.\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, rows } = 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 // Overlay state lives in bossStore so it survives the unmount/remount\n // performed by openOverlay/closeOverlay. The new mount reads this back\n // and renders the same overlay it had pre-remount. See the resetUI\n // comment in renderBossApp for why we remount instead of just toggling\n // React state.\n const overlay = state.overlay;\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 // Auto-update indicator: true when a newer version of @iroaxel/arcena\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 // Dedicated update_notice item so the renderer wraps it in a\n // rounded success-bordered ✨ box. Plain info rows render flat and\n // disappear into worker chatter.\n bossStore.appendUpdateNotice(msg);\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 · ARCena\"\n // 1 worker running \"● 1 worker running · ARCena\"\n // boss thinking only \"● ARCena\"\n // idle \"ARCena\"\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} · ARCena`;\n } else if (state.phase === \"working\") {\n title = \"● ARCena\";\n } else {\n title = \"ARCena\";\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;ARCena\\x1b\\\\`);\n };\n }, [stdout]);\n\n const staticItems: StaticRow[] = useMemo(\n () => [{ kind: \"banner\", id: \"banner\" }, ...state.history],\n [state.history],\n );\n\n /**\n * Opening or closing an overlay shrinks/grows the live area dramatically\n * (tasks pane → chat chrome, model picker → chat chrome, etc.). Toggling\n * React state alone leaves Ink's log-update cursor math drifting on the\n * very next streaming response, surfacing as \"input pushed upward, new\n * chat lines disappear off the top\". Mirrors arcicoder's broader fix\n * (commit 0246c6d): every overlay open/close goes through resetUI which\n * unmounts the Ink instance and renders a fresh one. The overlay\n * selection survives via bossStore.overlay.\n */\n const openOverlay = useCallback(\n (next: BossOverlay): void => {\n bossStore.setOverlay(next);\n if (resetUI) resetUI();\n },\n [resetUI],\n );\n\n const closeOverlay = useCallback((): void => {\n bossStore.setOverlay(null);\n if (resetUI) resetUI();\n }, [resetUI]);\n void stdout;\n\n // arcicoder'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 arcicoder'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 // Order matters. resetUI() unmounts the old Ink instance and\n // synchronously renders a fresh one — that first render reads the\n // bossStore via useBossState(). If we clear the store AFTER resetUI,\n // the new <Static> emits every old history item into the just-wiped\n // scrollback, which is exactly the \"input pushed upward, subsequent\n // messages look cleared\" symptom. Empty the store first so the new\n // instance mounts against an empty history.\n bossStore.clearHistory();\n resetUI?.();\n await boss.resetConversation();\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 arcicoder).\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 // Live area = streaming + activity + input (≥3 lines, bordered) + footer +\n // workerbar. Below ~14 rows we can't fit all of it without log-update\n // running out of vertical space — at which point Ink's cursor math drifts\n // and you see \"input pushed upward, new output disappears.\" Render a\n // friendly resize hint instead so the user knows what's happening rather\n // than thinking the app is broken. We're already past the static history\n // mount, so scrollback survives the resize that brings the user back.\n if (rows < 14) {\n return (\n <Box flexDirection=\"column\" width={columns} paddingX={1} marginTop={1}>\n <Text bold color={COLORS.accent}>\n {\"Terminal too small\"}\n </Text>\n <Text color={COLORS.primary}>\n {`Resize to at least 14 rows to use ARCena (currently ${rows}).`}\n </Text>\n </Box>\n );\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} 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). arcena'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 (arcena 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 (arcena 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 arcicoder'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}: {\n name: string;\n color: string;\n tick: number;\n}): React.ReactElement {\n return (\n <Text color={color} bold>\n {name}\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 const { columns } = useTerminalSize();\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 // Hard-pin the bar to a single line: any wrap multiplies live-area height\n // and Ink's log-update can't redraw a varying-height live area while a\n // streaming response is mid-flight (the symptom: bordered input duplicates\n // upward and new chat lines fall off the top). With many workers + a\n // narrow terminal this would otherwise wrap to two or three lines, so we\n // truncate at the right edge instead. Width=columns + flexShrink lets the\n // truncation kick in cleanly inside the parent column layout.\n return (\n <Box paddingX={1} width={columns} flexShrink={1}>\n {anyWorking && <AnimationActiveSentinel />}\n <Text wrap=\"truncate\">\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 </Text>\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 if (row.kind === \"update_notice\") return <UpdateNoticeRow text={row.text} />;\n return null;\n}\n\n/**\n * Update-available notice — arcena brand aesthetic. Rounded box, fuchsia\n * accent border, crimson primary body text. Mirrors the gradient feel of the\n * splash + banner so the notice reads as part of arcena rather than a\n * borrowed-green arcicoder element. The ✨ rides the accent so the eye lands\n * on the highlight first, then reads the primary-colored body.\n */\nfunction UpdateNoticeRow({ text }: { text: string }): React.ReactElement {\n return (\n <Box marginTop={1} flexShrink={1} borderStyle=\"round\" borderColor={COLORS.accent} paddingX={1}>\n <Text wrap=\"wrap\">\n <Text color={COLORS.accent} bold>\n {\"✨ \"}\n </Text>\n <Text color={COLORS.primary} bold>\n {text}\n </Text>\n </Text>\n </Box>\n );\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 (arcena 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 // Nuke-and-rebuild approach for /clear. Three earlier attempts at patching\n // Ink's internal frame-tracking state in place all hit the same wall: even\n // with log-update reset + lastOutput cleared + fullStaticOutput dropped,\n // the live area drifts after the next streaming response because Ink's\n // cursor math depends on terminal-state assumptions that ANSI clearing\n // breaks. The only RELIABLE reset is to teardown the React tree entirely\n // and render a fresh Ink instance. State outside React (GGBoss class,\n // bossStore singleton) survives and the new tree picks it up correctly.\n const ref: { instance: ReturnType<typeof render> | null } = { instance: null };\n const resetUI = (): void => {\n const old = ref.instance;\n if (!old) return;\n // Wipe the terminal first so the scrollback that the old instance wrote\n // doesn't linger above the new instance's banner.\n process.stdout.write(\"\\x1b[2J\\x1b[3J\\x1b[H\");\n // Unmount unsubscribes Ink's stdin handlers + tears down the React tree.\n old.unmount();\n // Build a fresh Ink instance with totally clean log-update state and\n // start cursor tracking. BossApp re-mounts and reads the (already\n // cleared) bossStore, so the chat shows just the banner + \"Session\n // cleared.\" info row — exactly as the user expects.\n ref.instance = render(<BossApp boss={opts.boss} resetUI={resetUI} />, {\n exitOnCtrlC: false,\n });\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\n // Terminal resize → full unmount/remount of the Ink instance.\n //\n // useTerminalSize already debounces resize events (300ms) and writes a\n // screen clear at the end of a drag, but that doesn't reset Ink's\n // log-update internal line-count tracking — so on the very next render\n // the live area is positioned against stale cursor state and the input\n // box ends up pinned to the top of the viewport with new chat lines\n // disappearing off-screen. That's the exact symptom /clear hit, and the\n // fix is the same: tear down the React tree and start fresh.\n //\n // Debounce is 250ms — slightly shorter than the hook's 300ms so resetUI\n // wins the race. When resetUI's unmount runs, the hook's pending\n // setTimeout is cleared by its own useEffect cleanup, so we don't\n // double-fire. State outside React (GGBoss class, bossStore singleton,\n // overlay) survives.\n let resizeTimer: ReturnType<typeof setTimeout> | null = null;\n const onTerminalResize = (): void => {\n if (resizeTimer) clearTimeout(resizeTimer);\n resizeTimer = setTimeout(() => {\n resizeTimer = null;\n resetUI();\n }, 250);\n };\n process.stdout.on(\"resize\", onTerminalResize);\n\n return {\n // Follow ref.instance through restarts: when /clear nukes the current\n // instance and creates a new one, this promise re-binds to whichever\n // Ink instance is alive now. Without the loop, we'd wait on the OLD\n // instance's waitUntilExit (which already resolved on unmount) and\n // exit the CLI immediately after every /clear.\n waitUntilExit: async () => {\n while (true) {\n const current = ref.instance;\n if (!current) {\n process.stdout.off(\"resize\", onTerminalResize);\n if (resizeTimer) clearTimeout(resizeTimer);\n return;\n }\n await current.waitUntilExit();\n // If the user ran /clear, ref.instance is now a NEW instance —\n // loop and wait on that one. If exit was final (no replacement),\n // ref.instance was nulled below and the loop ends.\n if (ref.instance === current) {\n ref.instance = null;\n process.stdout.off(\"resize\", onTerminalResize);\n if (resizeTimer) clearTimeout(resizeTimer);\n return;\n }\n }\n },\n unmount: () => {\n process.stdout.off(\"resize\", onTerminalResize);\n if (resizeTimer) clearTimeout(resizeTimer);\n ref.instance?.unmount();\n },\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 \"@iroaxel/arcicoder/ui/theme\";\nimport { useTerminalSize } from \"@iroaxel/arcicoder/ui/hooks/terminal-size\";\nimport { getContextWindow } from \"@iroaxel/arcicoder\";\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 @iroaxel/arcena 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 arcena that mirrors arcicoder'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 arcicoder'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 ARCena.\"\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 ARCena.\"}\n </Text>\n </>\n )}\n </Box>\n </Box>\n );\n}\n","import type { SlashCommandInfo } from \"@iroaxel/arcicoder/ui\";\n\n/**\n * Slash commands the boss CLI recognizes. Shape matches arcicoder'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 arcena\" },\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[] = [\"**arcena 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 \"@iroaxel/arcicoder/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 arcicoder'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 \"@iroaxel/arcicoder/ui\";\n\n/**\n * Boss-themed phrase library for the activity indicator. Replaces arcicoder'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 \"@iroaxel/arcicoder/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 arcena. 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 arcicoder'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 ARCena 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 \"@iroaxel/arcicoder/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 { existsSync } from \"node:fs\";\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 * On WSL2, native Linux audio binaries can't reach the Windows audio device\n * through WSLg's bridge in any useful way for streaming — `ffplay` accepts\n * the spawn (so we report \"Now playing\" to the user) but no audio actually\n * comes out. Returning a successful spawn handle that doesn't produce sound\n * is worse than failing fast: the user thinks it's working and goes off to\n * troubleshoot their speakers / VPN / firewall.\n *\n * Detect WSL via $WSL_DISTRO_NAME or /proc/sys/fs/binfmt_misc/WSLInterop.\n */\nfunction isWsl(): boolean {\n // WSL env vars can leak into a Windows shell launched from a WSL session,\n // but process.platform stays \"win32\" there. Anchor detection to platform\n // so isWsl() means \"I am running on a Linux distro inside WSL\", never\n // \"WSL env vars happen to be set somewhere upstream\".\n if (process.platform !== \"linux\") return false;\n return !!process.env.WSL_DISTRO_NAME || existsSync(\"/proc/sys/fs/binfmt_misc/WSLInterop\");\n}\n\n/**\n * Stream a station through powershell.exe + WPF MediaPlayer on the Windows\n * host instead of a Linux binary. Returns the ChildProcess or null if the\n * spawn failed — caller falls through to the native Linux candidates so a\n * WSL user with mpv installed and WSLg audio working keeps the existing\n * behaviour.\n *\n * Why a Dispatcher::Run() at the end of the script: WPF's MediaPlayer is\n * async — Open() and Play() return immediately and the actual playback runs\n * on a background thread that needs the COM message loop pumped. Without\n * Dispatcher::Run(), powershell.exe exits seconds later, the MediaPlayer\n * gets garbage-collected, and you hear silence. Pumping the dispatcher\n * keeps the player alive until stopRadio() kills the powershell process.\n *\n * Security:\n * - station.url is double-checked against the in-process RADIO_STATIONS\n * allowlist before spawning, even though the only call site already\n * looked it up there. Belt-and-suspenders against any future code path\n * that constructs a station object outside the constant array.\n * - Scheme is enforced as http/https so a future entry can't slip a\n * file:// or javascript: URL through.\n * - The URL is passed via GGBOSS_RADIO_URL env, never string-interpolated\n * into the PowerShell -Command argument. WSLENV lists the var so it\n * actually crosses the WSL→Windows process boundary (custom env vars\n * don't propagate by default — powershell.exe just sees them as empty\n * without WSLENV). Existing $WSLENV is preserved.\n * - powershell.exe runs -NoProfile -WindowStyle Hidden.\n */\nfunction tryPlayOnWindowsHost(station: RadioStation): ChildProcess | null {\n const allowedUrls = new Set(RADIO_STATIONS.map((s) => s.url));\n if (!allowedUrls.has(station.url)) return null;\n if (!/^https?:\\/\\//i.test(station.url)) return null;\n const psScript = [\n \"Add-Type -AssemblyName presentationCore;\",\n \"Add-Type -AssemblyName WindowsBase;\",\n \"$p = New-Object System.Windows.Media.MediaPlayer;\",\n \"$p.Open([uri]$env:GGBOSS_RADIO_URL);\",\n \"$p.Play();\",\n \"[System.Windows.Threading.Dispatcher]::Run();\",\n ].join(\" \");\n try {\n const child = spawn(\n \"powershell.exe\",\n [\"-NoProfile\", \"-WindowStyle\", \"Hidden\", \"-Command\", psScript],\n {\n detached: true,\n stdio: \"ignore\",\n env: {\n ...process.env,\n GGBOSS_RADIO_URL: station.url,\n WSLENV: (process.env.WSLENV ? process.env.WSLENV + \":\" : \"\") + \"GGBOSS_RADIO_URL\",\n },\n },\n );\n return child;\n } catch {\n return null;\n }\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 // WSL2: route through the Windows host before falling back to native\n // Linux players. Without this, ffplay reports a successful spawn but\n // produces no audio (WSLg audio bridge is fragile for streaming).\n if (isWsl()) {\n const child = tryPlayOnWindowsHost(station);\n if (child) {\n let errored = false;\n child.once(\"error\", () => {\n errored = true;\n });\n if (child.pid && !errored) {\n currentChild = child;\n currentStationId = stationId;\n log(\"INFO\", \"radio\", \"playing\", {\n station: station.id,\n player: \"powershell.exe (wsl→host)\",\n url: station.url,\n });\n child.unref();\n return { ok: true };\n }\n }\n }\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 * arcena auto-update — mirrors arcicoder's pattern (packages/ggcoder/src/core/\n * auto-update.ts) but pinned to @iroaxel/arcena and with its own state\n * file under ~/.gg/boss/ so it can't fight with arcicoder'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 @iroaxel/arcena@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 = \"@iroaxel/arcena\";\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 = `Axel 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 arcena 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 \"ARCena\" 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\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 = 0;\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","path","fs","path","fs","readline","readline","gradientText","import_react","import_react","import_react","import_react","import_react","import_react","import_react","import_jsx_runtime","truncate","import_react","import_jsx_runtime","import_react","import_jsx_runtime","currentStationId","spawn","fs","path","os","path","os","fs","spawn","import_jsx_runtime","scopePrefix","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/serve-mode.ts","../src/voice-transcriber.ts","../src/telegram.ts","../src/telegram-setup.ts","../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 -S node --max-old-space-size=8192 --expose-gc\n// Heap default (~1.5–4GB) fatal-OOMs on long boss sessions: 6 workers, large\n// tool results in message history, and Whisper/Ink tensors all live in the\n// same V8 heap. 8GB gives headroom; --expose-gc lets us nudge GC after\n// post-turn truncation. Users can override via NODE_OPTIONS — Node merges\n// shebang flags with the env var.\nimport path from \"node:path\";\nimport chalk from \"chalk\";\nimport type { Provider } from \"@iroaxel/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 { runBossServeMode, loadBossTelegramConfig } from \"./serve-mode.js\";\nimport { runBossTelegramSetup } from \"./telegram-setup.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, \"ARCena\") +\n c(COLORS.textDim, \" — orchestrator that drives multiple arcicoder workers from one chat.\\n\\n\") +\n c(COLORS.text, \"Usage\\n\") +\n \" \" +\n c(COLORS.accent, \"arcena\") +\n c(\n COLORS.textDim,\n \" start orchestrator using linked projects\\n\",\n ) +\n \" \" +\n c(COLORS.accent, \"arcena link\") +\n c(COLORS.textDim, \" pick which projects to link (interactive)\\n\") +\n \" \" +\n c(COLORS.accent, \"arcena telegram\") +\n c(COLORS.textDim, \" configure Telegram bot integration\\n\") +\n \" \" +\n c(COLORS.accent, \"arcena serve\") +\n c(COLORS.textDim, \" run the boss over Telegram (no TUI)\\n\") +\n \" \" +\n c(COLORS.accent, \"arcena continue\") +\n c(COLORS.textDim, \" resume the most recent boss session\\n\") +\n \" \" +\n c(COLORS.accent, \"arcena --resume <id>\") +\n c(COLORS.textDim, \" resume a specific boss session\\n\") +\n \" \" +\n c(COLORS.accent, \"arcena --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\n// ── `arcena serve` ────────────────────────────────────────────\n//\n// Runs the orchestrator headless and bridges it to Telegram. Resolves the bot\n// token + user ID from CLI flags > env > saved config (`arcena telegram`).\n// Boss/worker provider+model resolution mirrors interactive mode so the user\n// doesn't have to repeat themselves between `arcena` and `arcena serve`.\nasync function runServeSubcommand(argv: string[]): Promise<void> {\n let cliBotToken: string | undefined;\n let cliUserId: string | undefined;\n let cliBossModel: string | undefined;\n let cliWorkerModel: string | undefined;\n for (let i = 0; i < argv.length; i++) {\n const a = argv[i]!;\n if (a === \"--bot-token\") cliBotToken = argv[++i];\n else if (a === \"--user-id\") cliUserId = argv[++i];\n else if (a === \"--boss-model\") cliBossModel = argv[++i];\n else if (a === \"--worker-model\") cliWorkerModel = argv[++i];\n else if (a === \"--help\" || a === \"-h\") {\n process.stdout.write(\n \"\\nggboss serve — drive the boss from Telegram\\n\\n\" +\n \"Options\\n\" +\n \" --bot-token <token> Telegram bot token (or env GG_BOSS_TELEGRAM_BOT_TOKEN)\\n\" +\n \" --user-id <id> Allowed Telegram user ID (or env GG_BOSS_TELEGRAM_USER_ID)\\n\" +\n \" --boss-model <id> Override boss model\\n\" +\n \" --worker-model <id> Override worker model\\n\\n\" +\n \"Run `arcena telegram` first to save credentials interactively.\\n\\n\",\n );\n process.exit(0);\n } else {\n throw new Error(`Unknown argument: ${a}`);\n }\n }\n\n const saved = await loadBossTelegramConfig();\n const botToken = cliBotToken ?? process.env.GG_BOSS_TELEGRAM_BOT_TOKEN ?? saved?.botToken;\n const userIdStr = cliUserId ?? process.env.GG_BOSS_TELEGRAM_USER_ID;\n const userId = userIdStr ? parseInt(userIdStr, 10) : saved?.userId;\n\n if (!botToken || !userId || isNaN(userId)) {\n process.stderr.write(\n chalk.hex(COLORS.error)(\"Telegram not configured.\\n\\n\") +\n \"Run \" +\n chalk.hex(COLORS.primary).bold(\"arcena telegram\") +\n \" to set up your bot token and user ID.\\n\\n\" +\n chalk.hex(COLORS.textDim)(\"Or provide manually:\\n\") +\n chalk.hex(COLORS.textDim)(\" arcena serve --bot-token TOKEN --user-id ID\\n\"),\n );\n process.exit(1);\n }\n\n const settings = await loadSettings();\n const bossProvider = settings.bossProvider ?? \"anthropic\";\n const bossModel = cliBossModel ?? settings.bossModel ?? \"claude-opus-4-7\";\n const workerProvider = settings.workerProvider ?? \"anthropic\";\n const workerModel = cliWorkerModel ?? settings.workerModel ?? \"claude-sonnet-4-6\";\n\n await runBossServeMode({\n bossProvider,\n bossModel,\n bossThinkingLevel: settings.bossThinkingLevel,\n workerProvider,\n workerModel,\n telegram: { botToken, userId },\n });\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)(\"arcena 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 arcena.\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 if (argv[0] === \"telegram\") {\n await runBossTelegramSetup();\n process.exit(0);\n }\n\n if (argv[0] === \"serve\") {\n await runServeSubcommand(argv.slice(1));\n return;\n }\n\n // `arcena 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\n// Process-level error guards. With ~6 workers sharing the same Node process,\n// any uncaught throw or unhandled rejection would otherwise take the whole\n// orchestrator down — losing every worker's in-flight task. We log the\n// failure to ~/.gg/boss/debug.log (already initialized by this point) and\n// keep running. Truly unrecoverable conditions (OOM, native segfault) still\n// kill the process; nothing JS-side can guard against those.\nprocess.on(\"uncaughtException\", (err) => {\n const message = err instanceof Error ? err.message : String(err);\n const stack = err instanceof Error ? err.stack : undefined;\n log(\"ERROR\", \"uncaught_exception\", message, { stack });\n // Don't exit. The boss orchestrator and Ink TUI keep running; any worker\n // that got into a bad state will surface the issue via worker_error events\n // on its next interaction. This is far less disruptive than dying outright.\n});\n\nprocess.on(\"unhandledRejection\", (reason) => {\n const message = reason instanceof Error ? reason.message : String(reason);\n const stack = reason instanceof Error ? reason.stack : undefined;\n log(\"ERROR\", \"unhandled_rejection\", message, { stack });\n // Same rationale as uncaughtException — log and survive.\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 \"@iroaxel/arcicoder\";\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, type ProjectSource } 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 sourceBadge(sources: ProjectSource[]): { label: string; color: string } {\n // Fixed-width 5-char badges so names stay aligned across rows.\n if (sources.length > 1) return { label: \"[mix]\", color: COLORS.success };\n const only = sources[0];\n if (only === \"arcicoder\") return { label: \"[gg ]\", color: COLORS.accent };\n if (only === \"claude-code\") return { label: \"[cc ]\", color: COLORS.warning };\n if (only === \"codex\") return { label: \"[cx ]\", color: COLORS.primary };\n return { label: \"[?? ]\", color: COLORS.textDim };\n}\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 arcicoder projects found in ~/.gg/sessions/.</Text>\n <Text color={COLORS.textDim}>\n Run arcicoder in a project at least once, then re-run{\" \"}\n <Text color={COLORS.accent}>arcena 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 const badge = sourceBadge(p.sources);\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={badge.color}>{badge.label}</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)(\"arcena\") +\n chalk.hex(COLORS.textDim)(` to start the orchestrator.\\n`),\n );\n }\n}\n","import fs from \"node:fs/promises\";\nimport { createReadStream } from \"node:fs\";\nimport readline from \"node:readline\";\nimport os from \"node:os\";\nimport path from \"node:path\";\nimport { getAppPaths } from \"@iroaxel/arcicoder\";\n\nexport type ProjectSource = \"arcicoder\" | \"claude-code\" | \"codex\";\n\nexport interface DiscoveredProject {\n name: string;\n path: string;\n lastActiveMs: number;\n lastActiveDisplay: string;\n /** Sorted, deduped list of stores this project showed up in. */\n sources: ProjectSource[];\n}\n\n/**\n * Scan arcicoder + Claude Code + Codex session stores and return one row per\n * project, sorted most-recent first. Duplicates (same cwd) are collapsed; the\n * `sources` field lists every store the project appeared in so the picker can\n * show a combined badge.\n */\nexport async function discoverProjects(): Promise<DiscoveredProject[]> {\n const [gg, cc, cx] = await Promise.all([\n discoverGgcoderProjects(),\n discoverClaudeProjects(),\n discoverCodexProjects(),\n ]);\n\n const byPath = new Map<string, DiscoveredProject>();\n for (const p of [...gg, ...cc, ...cx]) {\n const existing = byPath.get(p.path);\n if (!existing) {\n byPath.set(p.path, p);\n continue;\n }\n byPath.set(p.path, {\n name: existing.name,\n path: existing.path,\n lastActiveMs: Math.max(existing.lastActiveMs, p.lastActiveMs),\n lastActiveDisplay: \"\", // recomputed below\n sources: mergeSources(existing.sources, p.sources),\n });\n }\n\n const merged = Array.from(byPath.values()).map((p) => ({\n ...p,\n lastActiveDisplay: formatRelativeTime(p.lastActiveMs),\n }));\n merged.sort((a, b) => b.lastActiveMs - a.lastActiveMs);\n return merged;\n}\n\nconst SOURCE_ORDER: Record<ProjectSource, number> = {\n arcicoder: 0,\n \"claude-code\": 1,\n codex: 2,\n};\n\nfunction mergeSources(a: ProjectSource[], b: ProjectSource[]): ProjectSource[] {\n const set = new Set<ProjectSource>([...a, ...b]);\n return Array.from(set).sort((x, y) => SOURCE_ORDER[x] - SOURCE_ORDER[y]);\n}\n\n/**\n * Scan ~/.gg/sessions/. Each session directory's name is the encoded cwd\n * (slashes → underscores); we decode it back and verify the directory still\n * exists on disk.\n */\nasync function discoverGgcoderProjects(): 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 const mtime = await maxJsonlMtime(dir);\n if (mtime === null) continue;\n\n const decoded = \"/\" + entry.replace(/_/g, \"/\");\n if (!(await isDirectory(decoded))) continue;\n\n results.push({\n name: path.basename(decoded),\n path: decoded,\n lastActiveMs: mtime,\n lastActiveDisplay: formatRelativeTime(mtime),\n sources: [\"arcicoder\"],\n });\n }\n return results;\n}\n\n/**\n * Scan ~/.claude/projects/. Claude Code's directory encoding replaces every\n * \"/\" with \"-\", which is genuinely ambiguous — a real dash in a path component\n * (e.g. \"gg-coder\") collides with the separator. So we extract the cwd from\n * the JSONL events themselves; Claude writes it into user/assistant records.\n * Falls back to a best-effort dash decode only if no event carries a cwd.\n */\nasync function discoverClaudeProjects(): Promise<DiscoveredProject[]> {\n const projectsDir = path.join(os.homedir(), \".claude\", \"projects\");\n let entries: string[];\n try {\n entries = await fs.readdir(projectsDir);\n } catch {\n return [];\n }\n\n const results = await Promise.all(\n entries.map(async (entry): Promise<DiscoveredProject | null> => {\n const dir = path.join(projectsDir, entry);\n const mtime = await maxJsonlMtime(dir);\n if (mtime === null) return null;\n\n const cwd =\n (await readFirstFromJsonlDir(dir, claudeCwdExtractor)) ?? fallbackDashDecode(entry);\n if (!cwd) return null;\n if (!(await isDirectory(cwd))) return null;\n\n return {\n name: path.basename(cwd),\n path: cwd,\n lastActiveMs: mtime,\n lastActiveDisplay: formatRelativeTime(mtime),\n sources: [\"claude-code\"],\n };\n }),\n );\n return results.filter((p): p is DiscoveredProject => p !== null);\n}\n\n/**\n * Scan ~/.codex/sessions/. Codex stores sessions flat by date\n * (`YYYY/MM/DD/rollout-*.jsonl`) with the cwd embedded in the first user\n * message as `<environment_context><cwd>/abs/path</cwd>...</environment_context>`.\n * We group sessions by extracted cwd and take max mtime per group.\n */\nasync function discoverCodexProjects(): Promise<DiscoveredProject[]> {\n const sessionsDir = path.join(os.homedir(), \".codex\", \"sessions\");\n if (!(await isDirectory(sessionsDir))) return [];\n\n // Layout is YYYY/MM/DD/*.jsonl — depth 4 covers it.\n const files = await collectJsonlFiles(sessionsDir, 4);\n if (files.length === 0) return [];\n\n // Process newest first so per-cwd we always start with the latest mtime.\n files.sort((a, b) => b.mtime - a.mtime);\n\n const byCwd = new Map<string, number>();\n for (const f of files) {\n const cwd = await readFirstFromFile(f.path, codexCwdExtractor);\n if (!cwd) continue;\n const prev = byCwd.get(cwd);\n if (prev === undefined || f.mtime > prev) byCwd.set(cwd, f.mtime);\n }\n\n const results: DiscoveredProject[] = [];\n for (const [cwd, mtime] of byCwd) {\n if (!(await isDirectory(cwd))) continue;\n results.push({\n name: path.basename(cwd),\n path: cwd,\n lastActiveMs: mtime,\n lastActiveDisplay: formatRelativeTime(mtime),\n sources: [\"codex\"],\n });\n }\n return results;\n}\n\nasync function isDirectory(p: string): Promise<boolean> {\n try {\n const s = await fs.stat(p);\n return s.isDirectory();\n } catch {\n return false;\n }\n}\n\nasync function maxJsonlMtime(dir: string): Promise<number | null> {\n if (!(await isDirectory(dir))) return null;\n const files = await collectJsonlFiles(dir, 2);\n if (files.length === 0) return null;\n let max = 0;\n for (const f of files) if (f.mtime > max) max = f.mtime;\n return max > 0 ? max : null;\n}\n\n/**\n * Walk `dir` up to `maxDepth` levels deep collecting every .jsonl file. Used\n * for both Claude Code (top-level + `<uuid>/subagents/`) and Codex\n * (`YYYY/MM/DD/`) layouts.\n */\nasync function collectJsonlFiles(\n dir: string,\n maxDepth: number,\n): Promise<{ path: string; mtime: number }[]> {\n const out: { path: string; mtime: number }[] = [];\n await walk(dir, 0);\n return out;\n\n async function walk(current: string, depth: number): Promise<void> {\n let entries;\n try {\n entries = await fs.readdir(current, { withFileTypes: true });\n } catch {\n return;\n }\n for (const e of entries) {\n const full = path.join(current, e.name);\n if (e.isFile() && e.name.endsWith(\".jsonl\")) {\n try {\n const s = await fs.stat(full);\n out.push({ path: full, mtime: s.mtimeMs });\n } catch {\n // skip unreadable\n }\n } else if (e.isDirectory() && depth < maxDepth) {\n await walk(full, depth + 1);\n }\n }\n }\n}\n\ntype LineExtractor = (line: string) => string | null;\n\nconst claudeCwdExtractor: LineExtractor = (line) => {\n try {\n const parsed = JSON.parse(line) as { cwd?: unknown };\n if (typeof parsed.cwd === \"string\" && parsed.cwd.startsWith(\"/\")) return parsed.cwd;\n } catch {\n // skip malformed\n }\n return null;\n};\n\nconst CODEX_CWD_RE = /<cwd>([^<]+)<\\/cwd>/;\nconst codexCwdExtractor: LineExtractor = (line) => {\n // Current format (openai/codex protocol.rs, late-2025+): RolloutLine wraps\n // SessionMeta / TurnContext items with `{ type, payload: { cwd, ... } }`.\n // First line is always SessionMeta, so this hits on read 1.\n try {\n const parsed = JSON.parse(line) as { payload?: { cwd?: unknown } };\n const cwd = parsed.payload?.cwd;\n if (typeof cwd === \"string\" && cwd.startsWith(\"/\")) return cwd;\n } catch {\n // not JSON or unexpected shape; fall through to legacy regex\n }\n // Legacy format (pre-late-2025): cwd embedded as <cwd>...</cwd> inside an\n // <environment_context> user-message string.\n const m = CODEX_CWD_RE.exec(line);\n if (m && m[1] && m[1].startsWith(\"/\")) return m[1];\n return null;\n};\n\n/**\n * Walk all .jsonl files under `dir` newest-first, returning the first non-null\n * extractor result. Walks two levels deep (matches Claude Code's nested\n * layout).\n */\nasync function readFirstFromJsonlDir(\n dir: string,\n extractor: LineExtractor,\n): Promise<string | null> {\n const files = await collectJsonlFiles(dir, 2);\n if (files.length === 0) return null;\n files.sort((a, b) => b.mtime - a.mtime);\n for (const f of files) {\n const v = await readFirstFromFile(f.path, extractor);\n if (v) return v;\n }\n return null;\n}\n\n/**\n * Stream `file` line-by-line and return the first non-null extractor result.\n * Caps lines so a giant transcript can't stall discovery.\n */\nasync function readFirstFromFile(file: string, extractor: LineExtractor): Promise<string | null> {\n return new Promise((resolve) => {\n const stream = createReadStream(file, { encoding: \"utf-8\" });\n const rl = readline.createInterface({ input: stream, crlfDelay: Infinity });\n let lines = 0;\n let done = false;\n const MAX_LINES = 200;\n // Resolve before tearing down. rl.close() synchronously emits 'close',\n // and if the close handler resolves first our real value gets swallowed.\n const finish = (value: string | null) => {\n if (done) return;\n done = true;\n resolve(value);\n rl.close();\n stream.destroy();\n };\n rl.on(\"line\", (line) => {\n if (done) return;\n lines++;\n if (lines > MAX_LINES) {\n finish(null);\n return;\n }\n const v = extractor(line);\n if (v) finish(v);\n });\n rl.on(\"close\", () => finish(null));\n rl.on(\"error\", () => finish(null));\n stream.on(\"error\", () => finish(null));\n });\n}\n\nfunction fallbackDashDecode(entry: string): string | null {\n // Strip leading \"-\" then turn remaining \"-\" into \"/\". Lossy by design — only\n // used when the JSONLs have no cwd events; the caller still verifies the\n // result is an existing directory.\n if (!entry.startsWith(\"-\")) return null;\n return \"/\" + entry.slice(1).replace(/-/g, \"/\");\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 * arcicoder'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 = \"ARCena\";\nexport const AUTHOR = \"Axel\";\n\nexport const LOGO_LINES: readonly string[] = [\n \" ▄▀▀▄ █▀▀▄ ▄▀▀▀ ▀█▀\",\n \" █▀▀█ █▀█▀ █ █ \",\n \" █ █ █ █ ▀▄▄▄ ▄█▄\",\n];\n\nexport const LOGO_GAP = \" \";\n\n/**\n * ARCena brand gradient — crimson → fuchsia. Deliberately distinct:\n * - gg-coder is cool blues/violets\n * - gg-editor is warm oranges/yellows\n * - arcena 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\": \"@iroaxel/arcena\",\n \"version\": \"4.3.161\",\n \"type\": \"module\",\n \"description\": \"Orchestrator agent that drives multiple arcicoder sessions across projects from a single chat\",\n \"license\": \"MIT\",\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"git+https://github.com/BigBlindGorg/ARCena.git\",\n \"directory\": \"packages/gg-boss\"\n },\n \"bin\": {\n \"arcena\": \"./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 \"@iroaxel/gg-agent\": \"workspace:*\",\n \"@iroaxel/gg-ai\": \"workspace:*\",\n \"@iroaxel/arcicoder\": \"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 \"optionalDependencies\": {\n \"@huggingface/transformers\": \"^3.6.0\",\n \"ogg-opus-decoder\": \"^1.6.13\"\n },\n \"publishConfig\": {\n \"access\": \"public\"\n }\n}\n","import path from \"node:path\";\nimport fs from \"node:fs/promises\";\nimport chalk from \"chalk\";\nimport { getAppPaths, MODELS, type ModelInfo } from \"@iroaxel/arcicoder\";\nimport type { Provider, ThinkingLevel } from \"@iroaxel/gg-ai\";\nimport { GGBoss } from \"./orchestrator.js\";\nimport { loadLinks } from \"./links.js\";\nimport { tasksStore } from \"./tasks-store.js\";\nimport { saveSettings } from \"./settings.js\";\nimport { transcribeVoice, isModelLoaded, setProgressCallback } from \"./voice-transcriber.js\";\nimport {\n subscribeToBossStore,\n getBossState,\n bossStore,\n type HistoryItem,\n type BossUiState,\n} from \"./boss-store.js\";\nimport { TelegramBot, type TelegramMessage, type TelegramVoiceMessage } from \"./telegram.js\";\nimport { initLogger, log, closeLogger } from \"./logger.js\";\nimport { VERSION, BRAND, AUTHOR, LOGO_LINES, LOGO_GAP, GRADIENT, COLORS } from \"./branding.js\";\n\n/**\n * `arcena serve` — drive the orchestrator from Telegram.\n *\n * Mirrors `arcicoder serve` shape (long-poll bot, allowedUserId gate) but instead\n * of one-AgentSession-per-chat, there's a single GGBoss instance. The user's\n * linked projects (from `~/.gg/boss/links.json`) are spun up as workers at\n * boot, just like `arcena` interactive mode.\n *\n * Bridge model:\n * - Telegram text → boss.enqueueUserMessage(text). The boss's run loop picks\n * it up FIFO with worker_turn_complete events.\n * - bossStore history additions → forwarded to Telegram. We subscribe to the\n * same store the Ink TUI uses, diff history length on each notify, and\n * format only the new items. This way every assistant reply, tool call,\n * worker_event, and info row the user would see in the TUI also lands in\n * the chat.\n *\n * Voice notes, multi-chat /link, and project-switching from Telegram are\n * intentionally out of scope for v1: the boss is tied to its linked projects\n * for the lifetime of the process.\n */\n\nexport interface BossServeOptions {\n bossProvider: Provider;\n bossModel: string;\n bossThinkingLevel?: ThinkingLevel;\n workerProvider: Provider;\n workerModel: string;\n workerThinkingLevel?: ThinkingLevel;\n telegram: {\n botToken: string;\n userId: number;\n };\n}\n\nexport interface BossTelegramConfig {\n botToken: string;\n userId: number;\n}\n\nfunction getTelegramConfigPath(): string {\n return path.join(getAppPaths().agentDir, \"boss\", \"telegram.json\");\n}\n\nexport async function loadBossTelegramConfig(): Promise<BossTelegramConfig | null> {\n try {\n const raw = await fs.readFile(getTelegramConfigPath(), \"utf-8\");\n const data = JSON.parse(raw) as BossTelegramConfig;\n if (data.botToken && data.userId) return data;\n return null;\n } catch {\n return null;\n }\n}\n\nexport async function saveBossTelegramConfig(config: BossTelegramConfig): Promise<void> {\n const file = getTelegramConfigPath();\n await fs.mkdir(path.dirname(file), { recursive: true });\n await fs.writeFile(file, JSON.stringify(config, null, 2), { encoding: \"utf-8\", mode: 0o600 });\n}\n\n// ── History → Telegram formatter ─────────────────────────────\n\n/**\n * Telegram is a chat surface, not a scrollback buffer — every history item\n * becomes a phone notification. We aggressively prune to only what the user\n * needs to track progress on a phone:\n *\n * keep → boss assistant text (the actual reply), errors, dispatch\n * announcements, update notices\n * drop → individual orchestration tool calls (prompt_worker,\n * dispatch_pending, add_task, peek_worker, …), per-turn\n * worker_event recaps (the boss already narrates these in its\n * assistant reply), info-level chatter, and the user's own echo\n *\n * The dropped channels are still visible in the TUI on the user's machine —\n * Telegram just sees the distilled signal.\n */\nfunction formatItemForTelegram(item: HistoryItem): string | null {\n switch (item.kind) {\n case \"user\":\n case \"tool\":\n case \"worker_event\":\n // user: echo of what they just sent\n // tool: orchestration plumbing the boss already summarizes in prose\n // worker_event: boss replies with its own narrative of the same outcome\n return null;\n\n case \"assistant\": {\n const cleaned = stripScopePrefix(item.text).trim();\n return cleaned ? truncate(cleaned, 1500) : null;\n }\n\n case \"worker_error\":\n return `✗ *${item.project}* — ${truncate(item.message, 300)}`;\n\n case \"info\":\n // Skip plain info — those are TUI-hint level (\"Ctrl+T to view tasks\",\n // \"Compacted N → M\", etc.) and just add notification noise on mobile.\n if (item.level !== \"warning\" && item.level !== \"error\") return null;\n return `${item.level === \"error\" ? \"✗ \" : \"⚠ \"}_${truncate(item.text, 300)}_`;\n\n case \"task_dispatch\": {\n if (item.tasks.length === 0) return null;\n const projects = [...new Set(item.tasks.map((t) => t.project))];\n // Single-project, single-task → one-liner. Multi → short list.\n if (item.tasks.length === 1) {\n const t = item.tasks[0]!;\n return `→ *${t.project}*: ${truncate(t.title, 140)}`;\n }\n return `→ Dispatched ${item.tasks.length} tasks across ${projects.length} project${projects.length === 1 ? \"\" : \"s\"}`;\n }\n\n case \"update_notice\":\n return `✨ ${item.text}`;\n }\n}\n\nfunction stripScopePrefix(text: string): string {\n // Boss occasionally echoes its own scope tag back in assistant text; drop it.\n return text.replace(/^\\s*\\[scope:[^\\]]+\\]\\s*/, \"\");\n}\n\nfunction truncate(text: string, max: number): string {\n if (text.length <= max) return text;\n return text.slice(0, max - 1).trimEnd() + \"…\";\n}\n\n/** Mirrors the TUI's scope pill — prefixes user messages with the active scope\n * so the boss knows whether to think globally or focus on one project. */\nfunction scopePrefix(scope: string): string {\n if (scope === \"all\") return \"[scope:all] \";\n return `[scope:${scope}] `;\n}\n\n// ── Run ──────────────────────────────────────────────────────\n\nexport async function runBossServeMode(options: BossServeOptions): Promise<void> {\n // Init persistent logger early so any boot failure has a paper trail.\n initLogger({\n version: VERSION,\n bossProvider: options.bossProvider,\n bossModel: options.bossModel,\n bossThinking: options.bossThinkingLevel,\n workerProvider: options.workerProvider,\n workerModel: options.workerModel,\n projectCount: 0,\n });\n\n // Load linked projects — same path as interactive `arcena`. Without links\n // the boss has nothing to manage, so bail with a clear error.\n const links = await loadLinks();\n if (links.projects.length === 0) {\n console.error(\n chalk.hex(COLORS.error)(\"No linked projects.\\n\") +\n chalk.hex(COLORS.textDim)(\"Run \") +\n chalk.hex(COLORS.accent)(\"arcena link\") +\n chalk.hex(COLORS.textDim)(\" first to choose which projects the boss should manage.\"),\n );\n process.exit(1);\n }\n const projects = links.projects.map((p) => ({ name: p.name, cwd: p.cwd }));\n\n await tasksStore.load();\n\n const bot = new TelegramBot({\n botToken: options.telegram.botToken,\n allowedUserId: options.telegram.userId,\n });\n\n const boss = new GGBoss({\n bossProvider: options.bossProvider,\n bossModel: options.bossModel,\n bossThinkingLevel: options.bossThinkingLevel,\n workerProvider: options.workerProvider,\n workerModel: options.workerModel,\n workerThinkingLevel: options.workerThinkingLevel,\n projects,\n });\n\n await boss.initialize();\n log(\"INFO\", \"serve\", \"boss initialized\", { projects: projects.map((p) => p.name).join(\",\") });\n\n // ── Telegram bridge: history → chat ────────────────────────\n\n const allowedChatId = options.telegram.userId; // DM with the user. Group support could be added later.\n /** Chats waiting on a number reply after `/scope` showed the picker. */\n const pendingScopeSelections = new Map<number, string[]>();\n /** Chats waiting on a number reply after `/m` / `/model-*` showed the picker.\n * Stores the target (\"boss\" or \"workers\") alongside the model list so the\n * same numeric reply path handles both pickers. */\n const pendingModelSelections = new Map<\n number,\n { target: \"boss\" | \"workers\"; models: ModelInfo[] }\n >();\n let lastHistoryLen = getBossState().history.length;\n let typingInterval: ReturnType<typeof setInterval> | null = null;\n let isStreaming = false;\n\n function sendQueued(text: string): void {\n bot.send(allowedChatId, text).catch((err) => {\n log(\"WARN\", \"telegram\", `send failed: ${err instanceof Error ? err.message : String(err)}`);\n // Retry without markdown to survive any formatting edge case.\n bot.sendPlain(allowedChatId, text.replace(/[*_`]/g, \"\")).catch(() => {});\n });\n }\n\n function startTyping(): void {\n if (typingInterval) return;\n bot.sendTyping(allowedChatId).catch(() => {});\n typingInterval = setInterval(() => {\n bot.sendTyping(allowedChatId).catch(() => {});\n }, 4000);\n }\n\n function stopTyping(): void {\n if (typingInterval) {\n clearInterval(typingInterval);\n typingInterval = null;\n }\n }\n\n function flushNewItems(state: BossUiState): void {\n const len = state.history.length;\n if (len <= lastHistoryLen) return;\n const fresh = state.history.slice(lastHistoryLen);\n lastHistoryLen = len;\n for (const item of fresh) {\n const formatted = formatItemForTelegram(item);\n if (formatted) sendQueued(formatted);\n }\n }\n\n /**\n * Apply a model choice to either the boss or every worker, persist it to\n * settings.json so the next launch defaults to the same picks, and confirm\n * via Telegram. Used by both the picker reply path and the direct\n * `/m <name>` arg path.\n */\n async function applyModelChoice(target: \"boss\" | \"workers\", selected: ModelInfo): Promise<void> {\n try {\n if (target === \"boss\") {\n await boss.switchBossModel(selected.provider, selected.id);\n await saveSettings({ bossProvider: selected.provider, bossModel: selected.id });\n await bot.send(allowedChatId, `Boss → *${selected.name}*`);\n } else {\n await boss.switchWorkerModel(selected.provider, selected.id);\n await saveSettings({ workerProvider: selected.provider, workerModel: selected.id });\n await bot.send(allowedChatId, `Workers → *${selected.name}*`);\n }\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n log(\"WARN\", \"model_switch\", message, { target, model: selected.id });\n await bot.send(allowedChatId, `Failed to switch ${target}: ${message}`);\n }\n }\n\n const unsubscribe = subscribeToBossStore(() => {\n // Drain the two-phase flush queue. In the Ink TUI a useEffect calls this\n // on every render so log-update can shrink the live area before Static\n // grows; serve mode has no Ink, so without this items would sit in\n // pendingFlush forever and the user would see \"Typing...\" with no reply.\n if (getBossState().pendingFlush.length > 0) {\n bossStore.commitPendingFlush();\n }\n\n const state = getBossState();\n flushNewItems(state);\n\n // Drive a typing indicator off the streaming flag so the user sees\n // activity even between text chunks (tools running, etc.).\n const streamingNow = state.streaming !== null;\n if (streamingNow && !isStreaming) {\n isStreaming = true;\n startTyping();\n } else if (!streamingNow && isStreaming) {\n isStreaming = false;\n stopTyping();\n }\n });\n\n // ── Telegram → boss ─────────────────────────────────────────\n\n bot.onText(async (msg: TelegramMessage) => {\n const { text, chatId } = msg;\n if (chatId !== allowedChatId) return;\n\n // Pending /scope reply (user sent just a number after the picker).\n const pendingScopes = pendingScopeSelections.get(chatId);\n if (pendingScopes && /^\\s*\\d+\\s*$/.test(text)) {\n pendingScopeSelections.delete(chatId);\n const num = parseInt(text.trim(), 10);\n if (num < 1 || num > pendingScopes.length) {\n await bot.send(chatId, \"Invalid selection. Send /scope to try again.\");\n return;\n }\n const chosen = pendingScopes[num - 1]!;\n bossStore.setScope(chosen);\n await bot.send(chatId, `Scope: *${chosen}*`);\n return;\n }\n\n // Pending /m or /model-* reply. Same number-only path for boss + workers;\n // the picker stashes which target the number applies to.\n const pendingModel = pendingModelSelections.get(chatId);\n if (pendingModel && /^\\s*\\d+\\s*$/.test(text)) {\n pendingModelSelections.delete(chatId);\n const num = parseInt(text.trim(), 10);\n if (num < 1 || num > pendingModel.models.length) {\n await bot.send(chatId, \"Invalid selection. Send /m to try again.\");\n return;\n }\n const selected = pendingModel.models[num - 1]!;\n await applyModelChoice(pendingModel.target, selected);\n return;\n }\n\n if (!text.startsWith(\"/\")) {\n // Match the TUI: prepend the active scope so the boss knows whether\n // the user is talking about all projects or a specific worker. Without\n // this every Telegram message would be implicitly \"all\" regardless of\n // /scope — same prefix the orchestrator-app uses on submit.\n const scoped = scopePrefix(getBossState().scope) + text;\n boss.enqueueUserMessage(scoped);\n return;\n }\n\n const parts = text.trim().split(/\\s+/);\n const cmd = parts[0]!.slice(1).toLowerCase().replace(/@\\w+$/, \"\");\n\n if (cmd === \"help\" || cmd === \"start\") {\n await bot.send(chatId, buildTelegramHelpText());\n return;\n }\n\n // /m, /model, /model-boss, /model-workers — mirrors the TUI's two pickers.\n // Bare /m and /model open the BOSS picker (most common ask); the explicit\n // -workers form is required to swap workers since that touches every active\n // session and we want it deliberate.\n if (cmd === \"m\" || cmd === \"model\" || cmd === \"model-boss\" || cmd === \"model-workers\") {\n const target: \"boss\" | \"workers\" = cmd === \"model-workers\" ? \"workers\" : \"boss\";\n const arg = parts.slice(1).join(\" \").trim().toLowerCase();\n const state = getBossState();\n const currentId = target === \"boss\" ? state.bossModel : state.workerModel;\n\n if (arg) {\n const num = parseInt(arg, 10);\n let match: ModelInfo | undefined;\n if (!isNaN(num) && num >= 1 && num <= MODELS.length) {\n match = MODELS[num - 1]!;\n } else {\n match = MODELS.find(\n (m) => m.name.toLowerCase().includes(arg) || m.id.toLowerCase().includes(arg),\n );\n }\n if (!match) {\n await bot.send(chatId, `No model matching \"${arg}\". Send /${cmd} to see the list.`);\n return;\n }\n await applyModelChoice(target, match);\n return;\n }\n\n // No arg → numbered picker grouped by provider.\n let listText = `*${target === \"boss\" ? \"Boss\" : \"Worker\"} model*\\n`;\n let lastProvider = \"\";\n MODELS.forEach((m, i) => {\n if (m.provider !== lastProvider) {\n lastProvider = m.provider;\n listText += `\\n_${providerLabel(m.provider)}_\\n`;\n }\n const active = m.id === currentId ? \" ←\" : \"\";\n listText += ` *${i + 1}.* ${m.name}${active}\\n`;\n });\n listText += `\\nSend the number, or \\`/${cmd} <name>\\`.`;\n pendingModelSelections.set(chatId, { target, models: [...MODELS] });\n await bot.send(chatId, listText);\n return;\n }\n\n if (cmd === \"scope\" || cmd === \"s\") {\n const state = getBossState();\n const arg = parts.slice(1).join(\" \").trim().toLowerCase();\n const names = [\"all\", ...state.workers.map((w) => w.name)];\n\n // No arg → show numbered picker. Tap-friendly on mobile.\n if (!arg) {\n const lines = names.map((n, i) => {\n const active = n === state.scope ? \" ←\" : \"\";\n const label = n === \"all\" ? \"*All*\" : `*${n}*`;\n return `*${i + 1}.* ${label}${active}`;\n });\n pendingScopeSelections.set(chatId, names);\n await bot.send(\n chatId,\n `*Scope* — current: *${state.scope}*\\n\\n${lines.join(\"\\n\")}\\n\\nSend the number, or \\`/scope <name>\\`.`,\n );\n return;\n }\n\n // Direct switch by number or name fragment.\n const num = parseInt(arg, 10);\n let chosen: string | null;\n if (!isNaN(num) && num >= 1 && num <= names.length) {\n chosen = names[num - 1]!;\n } else {\n const exact = names.find((n) => n.toLowerCase() === arg);\n chosen = exact ?? names.find((n) => n.toLowerCase().includes(arg)) ?? null;\n }\n if (!chosen) {\n await bot.send(chatId, `No scope matching \"${arg}\". Send /scope to see the list.`);\n return;\n }\n bossStore.setScope(chosen);\n await bot.send(chatId, `Scope: *${chosen}*`);\n return;\n }\n\n if (cmd === \"status\") {\n const state = getBossState();\n const lines: string[] = [`*${BRAND}* — ${state.bossModel}`, `Scope *${state.scope}*`, \"\"];\n lines.push(\"*Workers*\");\n for (const w of state.workers) {\n const dot = w.status === \"working\" ? \"●\" : w.status === \"error\" ? \"✗\" : \"○\";\n lines.push(` ${dot} *${w.name}* — _${w.status}_`);\n }\n const tasks = tasksStore.list();\n const open = tasks.filter((t) => t.status === \"pending\" || t.status === \"in_progress\").length;\n lines.push(\"\");\n lines.push(`Tasks ${open} open · ${tasks.length} total`);\n await bot.send(chatId, lines.join(\"\\n\"));\n return;\n }\n\n if (cmd === \"cancel\") {\n boss.abort();\n await bot.send(chatId, \"_Aborted current boss turn._\");\n return;\n }\n\n if (cmd === \"new\" || cmd === \"n\") {\n await boss.newSession();\n await bot.send(chatId, \"── *New session* ──\");\n return;\n }\n\n if (cmd === \"tasks\") {\n const tasks = tasksStore.list();\n if (tasks.length === 0) {\n await bot.send(chatId, \"_No tasks._\");\n return;\n }\n const lines = tasks.slice(0, 30).map((t, i) => {\n const status = t.status.replace(\"_\", \" \");\n return `*${i + 1}.* [${status}] *${t.project}* — ${t.description.split(\"\\n\")[0]}`;\n });\n await bot.send(chatId, `*Tasks*\\n\\n${lines.join(\"\\n\")}`);\n return;\n }\n\n // Anything else — pass straight through as a prompt; the boss may\n // recognize its own slash conventions (e.g. /compact handled in the TUI\n // layer) or just treat it as text. For unknown commands we still ship\n // the raw text so the boss can interpret it in context.\n boss.enqueueUserMessage(text);\n });\n\n // ── Voice notes ──────────────────────────────────────────────\n //\n // Mirrors `arcicoder serve`: download the OGG Opus blob from Telegram, decode\n // + transcribe locally with Whisper-tiny.en, then route the transcribed text\n // through the same scope-prefix path as a typed message. Whisper model is\n // ~75MB and downloaded on first use; we surface that as a one-time hint so\n // the user understands the initial silence.\n bot.onVoice(async (msg: TelegramVoiceMessage) => {\n const { chatId } = msg;\n if (chatId !== allowedChatId) return;\n\n try {\n if (!isModelLoaded()) {\n await bot.send(\n chatId,\n \"Setting up voice transcription — downloading Whisper model. This only happens once.\",\n );\n setProgressCallback((info) => {\n if (info.status === \"progress\" && info.progress !== undefined) {\n const pct = Math.round(info.progress);\n // Keep the typing indicator alive while a long download streams.\n if (pct % 25 === 0 && pct > 0) {\n bot.sendTyping(chatId).catch(() => {});\n }\n }\n });\n }\n await bot.sendTyping(chatId);\n\n const fileUrl = await bot.getFileUrl(msg.fileId);\n const transcribed = await transcribeVoice(fileUrl);\n if (!transcribed) {\n await bot.send(chatId, \"_Could not transcribe voice note._\");\n return;\n }\n\n await bot.send(chatId, `_Voice: \"${transcribed}\"_`);\n const scoped = scopePrefix(getBossState().scope) + transcribed;\n boss.enqueueUserMessage(scoped);\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n log(\"ERROR\", \"voice\", message);\n // Common failure: optional dep missing on user's install.\n const hint = /Cannot find module|Cannot resolve|MODULE_NOT_FOUND/.test(message)\n ? \"\\n\\nVoice transcription needs the optional `@huggingface/transformers` and `ogg-opus-decoder` packages. Reinstall with `npm i -g @iroaxel/arcena` and ensure optional deps installed.\"\n : \"\";\n await bot.send(chatId, `_Voice transcription failed: ${message}_${hint}`);\n }\n });\n\n // ── Boot banner ─────────────────────────────────────────────\n\n process.stdout.write(\"\\x1b[2J\\x1b[3J\\x1b[H\");\n printBanner({\n bossModel: options.bossModel,\n workerModel: options.workerModel,\n userId: options.telegram.userId,\n projectCount: projects.length,\n });\n\n // ── Shutdown ────────────────────────────────────────────────\n\n let shuttingDown = false;\n const shutdown = async (): Promise<void> => {\n if (shuttingDown) return;\n shuttingDown = true;\n console.log(chalk.hex(COLORS.textDim)(\"\\nShutting down...\"));\n bot.stop();\n stopTyping();\n unsubscribe();\n await boss.dispose().catch(() => {});\n closeLogger();\n process.exit(0);\n };\n process.on(\"SIGINT\", () => void shutdown());\n process.on(\"SIGTERM\", () => void shutdown());\n\n // ── Run ─────────────────────────────────────────────────────\n\n // Boss event loop. Runs forever, processes user_message + worker events.\n const runPromise = boss.run().catch((err) => {\n log(\"ERROR\", \"boss\", err instanceof Error ? err.message : String(err));\n });\n\n // Long-poll Telegram. Returns when bot.stop() is called.\n await bot.start();\n await runPromise;\n}\n\n// ── Help & banner ──────────────────────────────────────────────\n\nfunction buildTelegramHelpText(): string {\n return [\n \"*ARCena* — orchestrator over Telegram\",\n \"\",\n \"*Commands*\",\n \"/scope (/s) — switch project focus (All / per-worker)\",\n \"/m, /model-boss — switch the orchestrator's model\",\n \"/model-workers — switch every worker's model\",\n \"/status — workers + open tasks\",\n \"/tasks — list tasks\",\n \"/new — fresh boss session\",\n \"/cancel — abort the current boss turn\",\n \"/help — this message\",\n \"\",\n \"Voice notes are transcribed locally with Whisper and sent as prompts.\",\n \"Send any message to talk to the boss.\",\n ].join(\"\\n\");\n}\n\nfunction providerLabel(provider: Provider): string {\n switch (provider) {\n case \"anthropic\":\n return \"Anthropic\";\n case \"openai\":\n return \"OpenAI\";\n case \"glm\":\n return \"Z.AI\";\n case \"moonshot\":\n return \"Moonshot\";\n case \"minimax\":\n return \"MiniMax\";\n case \"deepseek\":\n return \"DeepSeek\";\n case \"openrouter\":\n return \"OpenRouter\";\n case \"xiaomi\":\n return \"Xiaomi\";\n default:\n return provider;\n }\n}\n\nfunction gradientText(text: string): string {\n let i = 0;\n return text\n .split(\"\")\n .map((ch) => (ch === \" \" ? ch : chalk.hex(GRADIENT[i++ % GRADIENT.length]!)(ch)))\n .join(\"\");\n}\n\nfunction printBanner(opts: {\n bossModel: string;\n workerModel: string;\n userId: number;\n projectCount: number;\n}): void {\n console.log();\n console.log(\n ` ${gradientText(LOGO_LINES[0]!)}${LOGO_GAP}` +\n chalk.hex(COLORS.primary).bold(BRAND) +\n chalk.hex(COLORS.textDim)(` v${VERSION}`) +\n chalk.hex(COLORS.textDim)(\" · By \") +\n chalk.white.bold(AUTHOR),\n );\n console.log(\n ` ${gradientText(LOGO_LINES[1]!)}${LOGO_GAP}` +\n chalk.hex(COLORS.accent)(`Boss: ${opts.bossModel}`),\n );\n console.log(\n ` ${gradientText(LOGO_LINES[2]!)}${LOGO_GAP}` +\n chalk.hex(COLORS.textDim)(`Workers: ${opts.workerModel}`),\n );\n console.log();\n console.log(\n chalk.hex(COLORS.textDim)(\" Mode \") +\n chalk.hex(COLORS.accent)(\"Telegram\") +\n chalk.hex(COLORS.textDim)(\" · User \") +\n chalk.white(String(opts.userId)) +\n chalk.hex(COLORS.textDim)(\n ` · ${opts.projectCount} project${opts.projectCount === 1 ? \"\" : \"s\"}`,\n ),\n );\n console.log();\n console.log(\n chalk.hex(COLORS.success)(\" Ready. \") +\n chalk.hex(COLORS.textDim)(\"Open Telegram and message your bot.\"),\n );\n console.log();\n console.log(\n chalk.hex(COLORS.textDim)(\" /help \") +\n chalk.hex(COLORS.textDim)(\"commands\") +\n chalk.hex(COLORS.textDim)(\" /status \") +\n chalk.hex(COLORS.textDim)(\"workers + tasks\") +\n chalk.hex(COLORS.textDim)(\" /cancel \") +\n chalk.hex(COLORS.textDim)(\"abort turn\"),\n );\n console.log();\n}\n","/**\n * Voice note transcription using local Whisper model.\n * Uses @huggingface/transformers (pure JS/WASM) — no native deps, no API keys.\n * Model (~75MB) is downloaded on first use and cached locally.\n */\n\nimport type { AutomaticSpeechRecognitionPipeline } from \"@huggingface/transformers\";\n\nconst TARGET_SAMPLE_RATE = 16000;\nconst MODEL_ID = \"Xenova/whisper-tiny.en\";\n\nlet transcriber: AutomaticSpeechRecognitionPipeline | null = null;\nlet loadPromise: Promise<AutomaticSpeechRecognitionPipeline> | null = null;\n\n/** Optional callback for model download progress. */\nexport type ProgressCallback = (info: { status: string; progress?: number; file?: string }) => void;\n\nlet onProgress: ProgressCallback | null = null;\n\n/** Set a callback to receive model download progress updates. */\nexport function setProgressCallback(cb: ProgressCallback | null): void {\n onProgress = cb;\n}\n\n/**\n * Resample audio from one sample rate to another using linear interpolation.\n */\nexport function resample(audio: Float32Array, fromRate: number, toRate: number): Float32Array {\n if (fromRate === toRate) return audio;\n const ratio = fromRate / toRate;\n const newLength = Math.round(audio.length / ratio);\n const result = new Float32Array(newLength);\n for (let i = 0; i < newLength; i++) {\n const srcIndex = i * ratio;\n const low = Math.floor(srcIndex);\n const high = Math.min(low + 1, audio.length - 1);\n const frac = srcIndex - low;\n result[i] = audio[low]! * (1 - frac) + audio[high]! * frac;\n }\n return result;\n}\n\n/**\n * Downmix multi-channel audio to mono by averaging all channels.\n */\nexport function downmixToMono(channelData: Float32Array[]): Float32Array {\n if (channelData.length === 0) return new Float32Array();\n if (channelData.length === 1) return channelData[0]!;\n\n const samples = channelData[0]!.length;\n const out = new Float32Array(samples);\n const scale = 1 / channelData.length;\n for (let i = 0; i < samples; i++) {\n let mixed = 0;\n for (const channel of channelData) mixed += channel[i] ?? 0;\n out[i] = mixed * scale;\n }\n return out;\n}\n\n/**\n * Decode OGG Opus audio buffer to 16kHz mono PCM Float32Array.\n */\nexport async function decodeOggOpus(buffer: Uint8Array): Promise<Float32Array> {\n const { OggOpusDecoder } = await import(\"ogg-opus-decoder\");\n const decoder = new OggOpusDecoder();\n await decoder.ready;\n try {\n const decoded = await decoder.decodeFile(buffer);\n\n if (!decoded.channelData?.length || !decoded.channelData[0]?.length) {\n throw new Error(\"Decoded audio is empty\");\n }\n\n const mono = downmixToMono(decoded.channelData);\n return resample(mono, decoded.sampleRate, TARGET_SAMPLE_RATE);\n } finally {\n decoder.free();\n }\n}\n\n/**\n * Get or initialize the Whisper transcription pipeline.\n * Model is downloaded on first use and cached by transformers.js.\n */\nasync function getTranscriber(): Promise<AutomaticSpeechRecognitionPipeline> {\n if (transcriber) return transcriber;\n\n if (!loadPromise) {\n loadPromise = (async () => {\n const { pipeline } = await import(\"@huggingface/transformers\");\n const instance = await pipeline(\"automatic-speech-recognition\", MODEL_ID, {\n dtype: \"fp32\",\n progress_callback: onProgress ?? undefined,\n });\n transcriber = instance;\n return instance;\n })();\n }\n\n return loadPromise;\n}\n\n/** Whether the model has been loaded already. */\nexport function isModelLoaded(): boolean {\n return transcriber !== null;\n}\n\n/**\n * Transcribe a voice message from its Telegram file URL.\n * Downloads the OGG Opus file, decodes to PCM, and runs Whisper locally.\n */\nexport async function transcribeVoice(fileUrl: string): Promise<string> {\n // Download the audio file\n const response = await fetch(fileUrl);\n if (!response.ok) throw new Error(`Failed to download voice file: ${response.status}`);\n const buffer = new Uint8Array(await response.arrayBuffer());\n\n // Decode OGG Opus → 16kHz mono PCM\n const pcm = await decodeOggOpus(buffer);\n\n // Transcribe with Whisper\n const asr = await getTranscriber();\n const result = await asr(pcm);\n\n const text = Array.isArray(result) ? result[0]?.text : (result as { text: string }).text;\n return (text ?? \"\").trim();\n}\n","/**\n * Minimal Telegram Bot API client using raw fetch().\n * Supports long polling, markdown messages, inline keyboards, and message splitting.\n */\n\nconst TELEGRAM_API = \"https://api.telegram.org\";\nconst MAX_MESSAGE_LENGTH = 4096;\n\nexport interface TelegramConfig {\n botToken: string;\n /** Only accept messages from this Telegram user ID. */\n allowedUserId: number;\n}\n\nexport interface TelegramUpdate {\n update_id: number;\n message?: {\n message_id: number;\n from: { id: number; first_name: string };\n chat: { id: number; type: string; title?: string };\n text?: string;\n voice?: { file_id: string; duration: number; mime_type?: string; file_size?: number };\n };\n callback_query?: {\n id: string;\n from: { id: number };\n message: { chat: { id: number } };\n data: string;\n };\n my_chat_member?: {\n chat: { id: number; type: string; title?: string };\n from: { id: number };\n new_chat_member: { status: string };\n };\n}\n\nexport interface InlineButton {\n text: string;\n callback_data: string;\n}\n\n/** Incoming message with chat context. */\nexport interface TelegramMessage {\n text: string;\n chatId: number;\n chatType: \"private\" | \"group\" | \"supergroup\" | \"channel\";\n chatTitle?: string;\n}\n\n/** Incoming voice note with chat context. */\nexport interface TelegramVoiceMessage {\n fileId: string;\n duration: number;\n chatId: number;\n chatType: \"private\" | \"group\" | \"supergroup\" | \"channel\";\n chatTitle?: string;\n}\n\nexport class TelegramBot {\n private token: string;\n private allowedUserId: number;\n private offset = 0;\n private running = false;\n\n private onMessage: ((msg: TelegramMessage) => void) | null = null;\n private onVoiceMessage: ((msg: TelegramVoiceMessage) => void) | null = null;\n private onCallback: ((data: string, chatId: number) => void) | null = null;\n private onBotAdded: ((chatId: number, chatTitle?: string) => void) | null = null;\n private onBotRemoved: ((chatId: number) => void) | null = null;\n\n constructor(config: TelegramConfig) {\n this.token = config.botToken;\n this.allowedUserId = config.allowedUserId;\n }\n\n /** Register handler for incoming text messages. */\n onText(handler: (msg: TelegramMessage) => void): void {\n this.onMessage = handler;\n }\n\n /** Register handler for incoming voice notes. */\n onVoice(handler: (msg: TelegramVoiceMessage) => void): void {\n this.onVoiceMessage = handler;\n }\n\n /** Register handler for inline keyboard button presses. */\n onCallbackQuery(handler: (data: string, chatId: number) => void): void {\n this.onCallback = handler;\n }\n\n /** Register handler for when the bot is added to a group. */\n onAddedToGroup(handler: (chatId: number, chatTitle?: string) => void): void {\n this.onBotAdded = handler;\n }\n\n /** Register handler for when the bot is removed from a group. */\n onRemovedFromGroup(handler: (chatId: number) => void): void {\n this.onBotRemoved = handler;\n }\n\n /** Start long polling. Blocks until stop() is called. */\n async start(): Promise<void> {\n this.running = true;\n\n // Verify bot token works\n const me = await this.apiCall(\"getMe\");\n if (!me.ok) {\n throw new Error(`Invalid bot token: ${JSON.stringify(me)}`);\n }\n\n while (this.running) {\n try {\n const updates = await this.getUpdates();\n for (const update of updates) {\n await this.handleUpdate(update);\n }\n } catch (err) {\n if (!this.running) break;\n console.error(`[telegram] Poll error: ${err instanceof Error ? err.message : err}`);\n await sleep(3000);\n }\n }\n }\n\n /** Stop long polling. */\n stop(): void {\n this.running = false;\n }\n\n /** Send a text message to a specific chat. Converts markdown and splits long messages. */\n async send(chatId: number, text: string, buttons?: InlineButton[][]): Promise<void> {\n const converted = toTelegramMarkdown(text);\n const chunks = splitMessage(converted);\n\n for (let i = 0; i < chunks.length; i++) {\n const isLast = i === chunks.length - 1;\n const replyMarkup =\n isLast && buttons\n ? {\n inline_keyboard: buttons.map((row) =>\n row.map((b) => ({ text: b.text, callback_data: b.callback_data })),\n ),\n }\n : undefined;\n\n await this.apiCall(\"sendMessage\", {\n chat_id: chatId,\n text: chunks[i],\n parse_mode: \"Markdown\",\n ...(replyMarkup ? { reply_markup: replyMarkup } : {}),\n });\n }\n }\n\n /** Send a plain text message (no markdown parsing) to a specific chat. */\n async sendPlain(chatId: number, text: string): Promise<void> {\n const chunks = splitMessage(text);\n for (const chunk of chunks) {\n await this.apiCall(\"sendMessage\", {\n chat_id: chatId,\n text: chunk,\n });\n }\n }\n\n /** Send a typing indicator to a specific chat. */\n async sendTyping(chatId: number): Promise<void> {\n await this.apiCall(\"sendChatAction\", {\n chat_id: chatId,\n action: \"typing\",\n });\n }\n\n /** Get a direct download URL for a Telegram file. */\n async getFileUrl(fileId: string): Promise<string> {\n const result = await this.apiCall(\"getFile\", { file_id: fileId });\n if (!result.ok) throw new Error(`Failed to get file: ${JSON.stringify(result)}`);\n const filePath = (result.result as { file_path: string }).file_path;\n return `${TELEGRAM_API}/file/bot${this.token}/${filePath}`;\n }\n\n // ── Private ───────────────────────────────────────────\n\n private async getUpdates(): Promise<TelegramUpdate[]> {\n const result = await this.apiCall(\"getUpdates\", {\n offset: this.offset,\n timeout: 30,\n allowed_updates: [\"message\", \"callback_query\", \"my_chat_member\"],\n });\n\n if (!result.ok || !Array.isArray(result.result)) return [];\n\n const updates = result.result as TelegramUpdate[];\n if (updates.length > 0) {\n this.offset = updates[updates.length - 1]!.update_id + 1;\n }\n return updates;\n }\n\n private async handleUpdate(update: TelegramUpdate): Promise<void> {\n if (update.message) {\n const msg = update.message;\n\n // Auth check\n if (msg.from.id !== this.allowedUserId) {\n return;\n }\n\n if (msg.text && this.onMessage) {\n this.onMessage({\n text: msg.text,\n chatId: msg.chat.id,\n chatType: msg.chat.type as TelegramMessage[\"chatType\"],\n chatTitle: msg.chat.title,\n });\n } else if (msg.voice && this.onVoiceMessage) {\n this.onVoiceMessage({\n fileId: msg.voice.file_id,\n duration: msg.voice.duration,\n chatId: msg.chat.id,\n chatType: msg.chat.type as TelegramMessage[\"chatType\"],\n chatTitle: msg.chat.title,\n });\n }\n }\n\n // Bot membership changed in a group\n if (update.my_chat_member) {\n const member = update.my_chat_member;\n const status = member.new_chat_member.status;\n if ((status === \"member\" || status === \"administrator\") && this.onBotAdded) {\n this.onBotAdded(member.chat.id, member.chat.title);\n } else if ((status === \"left\" || status === \"kicked\") && this.onBotRemoved) {\n this.onBotRemoved(member.chat.id);\n }\n }\n\n if (update.callback_query) {\n const cb = update.callback_query;\n\n if (cb.from.id !== this.allowedUserId) return;\n\n await this.apiCall(\"answerCallbackQuery\", { callback_query_id: cb.id });\n\n if (cb.data && this.onCallback) {\n this.onCallback(cb.data, cb.message.chat.id);\n }\n }\n }\n\n private async apiCall(\n method: string,\n body?: Record<string, unknown>,\n ): Promise<{ ok: boolean; result?: unknown }> {\n const url = `${TELEGRAM_API}/bot${this.token}/${method}`;\n\n const response = await fetch(url, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: body ? JSON.stringify(body) : undefined,\n });\n\n if (!response.ok) {\n return { ok: false };\n }\n\n return response.json() as Promise<{ ok: boolean; result?: unknown }>;\n }\n}\n\n// ── Markdown Conversion ──────────────────────────────────\n\n/**\n * Convert GitHub-flavored markdown to Telegram-compatible Markdown.\n *\n * Telegram supports: *bold*, _italic_, `code`, ```pre```, [link](url)\n * Does NOT support: headings, horizontal rules, tables, HTML tags, images\n */\nfunction toTelegramMarkdown(text: string): string {\n const lines = text.split(\"\\n\");\n const result: string[] = [];\n let inCodeBlock = false;\n\n for (const line of lines) {\n if (line.trimStart().startsWith(\"```\")) {\n inCodeBlock = !inCodeBlock;\n result.push(line);\n continue;\n }\n\n if (inCodeBlock) {\n result.push(line);\n continue;\n }\n\n let transformed = line;\n\n // Headings → bold text\n const headingMatch = transformed.match(/^(#{1,6})\\s+(.+)$/);\n if (headingMatch) {\n transformed = `*${headingMatch[2]}*`;\n result.push(transformed);\n continue;\n }\n\n // Horizontal rules → empty line\n if (/^(-{3,}|_{3,}|\\*{3,})$/.test(transformed.trim())) {\n result.push(\"\");\n continue;\n }\n\n // **bold** → *bold*\n transformed = transformed.replace(/\\*\\*(.+?)\\*\\*/g, \"*$1*\");\n\n result.push(transformed);\n }\n\n return result.join(\"\\n\");\n}\n\n// ── Helpers ───────────────────────────────────────────────\n\nfunction splitMessage(text: string): string[] {\n if (text.length <= MAX_MESSAGE_LENGTH) return [text];\n\n const chunks: string[] = [];\n let remaining = text;\n\n while (remaining.length > 0) {\n if (remaining.length <= MAX_MESSAGE_LENGTH) {\n chunks.push(remaining);\n break;\n }\n\n let splitAt = remaining.lastIndexOf(\"\\n\", MAX_MESSAGE_LENGTH);\n if (splitAt === -1 || splitAt < MAX_MESSAGE_LENGTH * 0.5) {\n splitAt = remaining.lastIndexOf(\" \", MAX_MESSAGE_LENGTH);\n }\n if (splitAt === -1 || splitAt < MAX_MESSAGE_LENGTH * 0.5) {\n splitAt = MAX_MESSAGE_LENGTH;\n }\n\n chunks.push(remaining.slice(0, splitAt));\n remaining = remaining.slice(splitAt).trimStart();\n }\n\n return chunks;\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((r) => setTimeout(r, ms));\n}\n","import readline from \"node:readline/promises\";\nimport chalk from \"chalk\";\nimport { COLORS, GRADIENT, LOGO_LINES, LOGO_GAP, BRAND, AUTHOR, VERSION } from \"./branding.js\";\nimport {\n loadBossTelegramConfig,\n saveBossTelegramConfig,\n type BossTelegramConfig,\n} from \"./serve-mode.js\";\n\n/**\n * `arcena telegram` — interactive setup wizard. Mirrors `arcicoder telegram` but\n * writes to `~/.gg/boss/telegram.json` so the boss has its own bot identity\n * (distinct from arcicoder's coding bot).\n */\nexport async function runBossTelegramSetup(): Promise<void> {\n process.stdout.write(\"\\x1b[2J\\x1b[3J\\x1b[H\");\n printSetupBanner();\n\n const existing = await loadBossTelegramConfig();\n if (existing) {\n console.log(\n chalk.hex(COLORS.textDim)(\" Current config:\\n\") +\n chalk.hex(COLORS.textDim)(\n ` Bot token: ${existing.botToken.slice(0, 10)}...${existing.botToken.slice(-4)}\\n`,\n ) +\n chalk.hex(COLORS.textDim)(` User ID: ${existing.userId}\\n`),\n );\n }\n\n const rl = readline.createInterface({ input: process.stdin, output: process.stdout });\n try {\n console.log(\n chalk.hex(COLORS.accent)(\" Step 1: Bot Token\\n\") +\n chalk.hex(COLORS.textDim)(\" 1. Open BotFather: \") +\n chalk.hex(COLORS.primary).underline(\"https://t.me/BotFather\") +\n \"\\n\" +\n chalk.hex(COLORS.textDim)(\" 2. Send /newbot and follow the prompts\\n\") +\n chalk.hex(COLORS.textDim)(\" 3. Copy the bot token\\n\"),\n );\n\n const tokenPrompt = existing\n ? chalk.hex(COLORS.primary)(\" Paste bot token (enter to keep current): \")\n : chalk.hex(COLORS.primary)(\" Paste bot token: \");\n const tokenInput = await rl.question(tokenPrompt);\n const botToken = tokenInput.trim() || existing?.botToken;\n\n if (!botToken) {\n console.log(chalk.hex(COLORS.error)(\"\\n No bot token provided. Setup cancelled.\"));\n return;\n }\n if (!/^\\d+:[A-Za-z0-9_-]+$/.test(botToken)) {\n console.log(\n chalk.hex(COLORS.error)(\"\\n Invalid token format. Expected: 123456789:ABCdef...\"),\n );\n return;\n }\n\n console.log(\n chalk.hex(COLORS.accent)(\"\\n Step 2: User ID\\n\") +\n chalk.hex(COLORS.textDim)(\" 1. Open userinfobot: \") +\n chalk.hex(COLORS.primary).underline(\"https://t.me/userinfobot\") +\n \"\\n\" +\n chalk.hex(COLORS.textDim)(\" 2. Send any message — it replies with your numeric ID\\n\") +\n chalk.hex(COLORS.textDim)(\" Only this user ID can control the boss.\\n\"),\n );\n\n const userPrompt = existing\n ? chalk.hex(COLORS.primary)(` Your Telegram user ID (enter to keep ${existing.userId}): `)\n : chalk.hex(COLORS.primary)(\" Your Telegram user ID: \");\n const userInput = await rl.question(userPrompt);\n const userId = userInput.trim() ? parseInt(userInput.trim(), 10) : existing?.userId;\n\n if (!userId || isNaN(userId)) {\n console.log(chalk.hex(COLORS.error)(\"\\n Invalid user ID. Must be a number.\"));\n return;\n }\n\n console.log(chalk.hex(COLORS.textDim)(\"\\n Verifying bot token...\"));\n const verifyRes = await fetch(`https://api.telegram.org/bot${botToken}/getMe`, {\n method: \"POST\",\n });\n const verifyData = (await verifyRes.json()) as {\n ok: boolean;\n result?: { username: string; first_name: string };\n };\n if (!verifyData.ok || !verifyData.result) {\n console.log(\n chalk.hex(COLORS.error)(\n \"\\n Invalid bot token — Telegram rejected it. Check and try again.\",\n ),\n );\n return;\n }\n\n const config: BossTelegramConfig = { botToken, userId };\n await saveBossTelegramConfig(config);\n\n console.log(\n chalk.hex(COLORS.success)(\n `\\n ✓ Connected to @${verifyData.result.username} (${verifyData.result.first_name})\\n`,\n ) +\n chalk.hex(COLORS.success)(` ✓ Authorized user ID: ${userId}\\n\\n`) +\n chalk.hex(COLORS.primary)(\" To start:\\n\") +\n chalk.hex(COLORS.textDim)(\" arcena serve\\n\"),\n );\n } finally {\n rl.close();\n }\n}\n\nfunction gradientText(text: string): string {\n let i = 0;\n return text\n .split(\"\")\n .map((ch) => (ch === \" \" ? ch : chalk.hex(GRADIENT[i++ % GRADIENT.length]!)(ch)))\n .join(\"\");\n}\n\nfunction printSetupBanner(): void {\n console.log();\n console.log(\n ` ${gradientText(LOGO_LINES[0]!)}${LOGO_GAP}` +\n chalk.hex(COLORS.primary).bold(BRAND) +\n chalk.hex(COLORS.textDim)(` v${VERSION}`) +\n chalk.hex(COLORS.textDim)(\" · By \") +\n chalk.white.bold(AUTHOR),\n );\n console.log(\n ` ${gradientText(LOGO_LINES[1]!)}${LOGO_GAP}` + chalk.hex(COLORS.accent)(\"Telegram Setup\"),\n );\n console.log(\n ` ${gradientText(LOGO_LINES[2]!)}${LOGO_GAP}` + chalk.hex(COLORS.textDim)(\"Remote Control\"),\n );\n console.log();\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 \"@iroaxel/arcicoder/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 \"@iroaxel/arcicoder/ui\";\nimport { useDoublePress } from \"@iroaxel/arcicoder/ui/hooks/double-press\";\nimport type { Provider } from \"@iroaxel/gg-ai\";\nimport { TerminalSizeProvider, useTerminalSize } from \"@iroaxel/arcicoder/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 BossOverlay,\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. Wired in `renderBossApp` to ANSI-wipe the terminal,\n * unmount the current Ink instance, and render a fresh one — the only\n * reliable way to reset log-update's internal cursor/line-count tracking\n * without the drift that manifests as \"input pushed upward\" after /clear.\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, rows } = 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 // Overlay state lives in bossStore so it survives the unmount/remount\n // performed by openOverlay/closeOverlay. The new mount reads this back\n // and renders the same overlay it had pre-remount. See the resetUI\n // comment in renderBossApp for why we remount instead of just toggling\n // React state.\n const overlay = state.overlay;\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 // Auto-update indicator: true when a newer version of @iroaxel/arcena\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 // Dedicated update_notice item so the renderer wraps it in a\n // rounded success-bordered ✨ box. Plain info rows render flat and\n // disappear into worker chatter.\n bossStore.appendUpdateNotice(msg);\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 · ARCena\"\n // 1 worker running \"● 1 worker running · ARCena\"\n // boss thinking only \"● ARCena\"\n // idle \"ARCena\"\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} · ARCena`;\n } else if (state.phase === \"working\") {\n title = \"● ARCena\";\n } else {\n title = \"ARCena\";\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;ARCena\\x1b\\\\`);\n };\n }, [stdout]);\n\n const staticItems: StaticRow[] = useMemo(\n () => [{ kind: \"banner\", id: \"banner\" }, ...state.history],\n [state.history],\n );\n\n /**\n * Opening or closing an overlay shrinks/grows the live area dramatically\n * (tasks pane → chat chrome, model picker → chat chrome, etc.). Toggling\n * React state alone leaves Ink's log-update cursor math drifting on the\n * very next streaming response, surfacing as \"input pushed upward, new\n * chat lines disappear off the top\". Mirrors arcicoder's broader fix\n * (commit 0246c6d): every overlay open/close goes through resetUI which\n * unmounts the Ink instance and renders a fresh one. The overlay\n * selection survives via bossStore.overlay.\n */\n const openOverlay = useCallback(\n (next: BossOverlay): void => {\n bossStore.setOverlay(next);\n if (resetUI) resetUI();\n },\n [resetUI],\n );\n\n const closeOverlay = useCallback((): void => {\n bossStore.setOverlay(null);\n if (resetUI) resetUI();\n }, [resetUI]);\n void stdout;\n\n // arcicoder'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 arcicoder'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 // Order matters. resetUI() unmounts the old Ink instance and\n // synchronously renders a fresh one — that first render reads the\n // bossStore via useBossState(). If we clear the store AFTER resetUI,\n // the new <Static> emits every old history item into the just-wiped\n // scrollback, which is exactly the \"input pushed upward, subsequent\n // messages look cleared\" symptom. Empty the store first so the new\n // instance mounts against an empty history.\n bossStore.clearHistory();\n resetUI?.();\n await boss.resetConversation();\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 arcicoder).\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 // Live area = streaming + activity + input (≥3 lines, bordered) + footer +\n // workerbar. Below ~14 rows we can't fit all of it without log-update\n // running out of vertical space — at which point Ink's cursor math drifts\n // and you see \"input pushed upward, new output disappears.\" Render a\n // friendly resize hint instead so the user knows what's happening rather\n // than thinking the app is broken. We're already past the static history\n // mount, so scrollback survives the resize that brings the user back.\n if (rows < 14) {\n return (\n <Box flexDirection=\"column\" width={columns} paddingX={1} marginTop={1}>\n <Text bold color={COLORS.accent}>\n {\"Terminal too small\"}\n </Text>\n <Text color={COLORS.primary}>\n {`Resize to at least 14 rows to use ARCena (currently ${rows}).`}\n </Text>\n </Box>\n );\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} 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). arcena'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 (arcena 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 (arcena 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 arcicoder'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}: {\n name: string;\n color: string;\n tick: number;\n}): React.ReactElement {\n return (\n <Text color={color} bold>\n {name}\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 const { columns } = useTerminalSize();\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 // Hard-pin the bar to a single line: any wrap multiplies live-area height\n // and Ink's log-update can't redraw a varying-height live area while a\n // streaming response is mid-flight (the symptom: bordered input duplicates\n // upward and new chat lines fall off the top). With many workers + a\n // narrow terminal this would otherwise wrap to two or three lines, so we\n // truncate at the right edge instead. Width=columns + flexShrink lets the\n // truncation kick in cleanly inside the parent column layout.\n return (\n <Box paddingX={1} width={columns} flexShrink={1}>\n {anyWorking && <AnimationActiveSentinel />}\n <Text wrap=\"truncate\">\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 </Text>\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 if (row.kind === \"update_notice\") return <UpdateNoticeRow text={row.text} />;\n return null;\n}\n\n/**\n * Update-available notice — arcena brand aesthetic. Rounded box, fuchsia\n * accent border, crimson primary body text. Mirrors the gradient feel of the\n * splash + banner so the notice reads as part of arcena rather than a\n * borrowed-green arcicoder element. The ✨ rides the accent so the eye lands\n * on the highlight first, then reads the primary-colored body.\n */\nfunction UpdateNoticeRow({ text }: { text: string }): React.ReactElement {\n return (\n <Box marginTop={1} flexShrink={1} borderStyle=\"round\" borderColor={COLORS.accent} paddingX={1}>\n <Text wrap=\"wrap\">\n <Text color={COLORS.accent} bold>\n {\"✨ \"}\n </Text>\n <Text color={COLORS.primary} bold>\n {text}\n </Text>\n </Text>\n </Box>\n );\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 (arcena 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 // Nuke-and-rebuild approach for /clear. Three earlier attempts at patching\n // Ink's internal frame-tracking state in place all hit the same wall: even\n // with log-update reset + lastOutput cleared + fullStaticOutput dropped,\n // the live area drifts after the next streaming response because Ink's\n // cursor math depends on terminal-state assumptions that ANSI clearing\n // breaks. The only RELIABLE reset is to teardown the React tree entirely\n // and render a fresh Ink instance. State outside React (GGBoss class,\n // bossStore singleton) survives and the new tree picks it up correctly.\n const ref: { instance: ReturnType<typeof render> | null } = { instance: null };\n const resetUI = (): void => {\n const old = ref.instance;\n if (!old) return;\n // Wipe the terminal first so the scrollback that the old instance wrote\n // doesn't linger above the new instance's banner.\n process.stdout.write(\"\\x1b[2J\\x1b[3J\\x1b[H\");\n // Unmount unsubscribes Ink's stdin handlers + tears down the React tree.\n old.unmount();\n // Build a fresh Ink instance with totally clean log-update state and\n // start cursor tracking. BossApp re-mounts and reads the (already\n // cleared) bossStore, so the chat shows just the banner + \"Session\n // cleared.\" info row — exactly as the user expects.\n ref.instance = render(<BossApp boss={opts.boss} resetUI={resetUI} />, {\n exitOnCtrlC: false,\n });\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\n // Terminal resize → full unmount/remount of the Ink instance.\n //\n // useTerminalSize already debounces resize events (300ms) and writes a\n // screen clear at the end of a drag, but that doesn't reset Ink's\n // log-update internal line-count tracking — so on the very next render\n // the live area is positioned against stale cursor state and the input\n // box ends up pinned to the top of the viewport with new chat lines\n // disappearing off-screen. That's the exact symptom /clear hit, and the\n // fix is the same: tear down the React tree and start fresh.\n //\n // Debounce is 250ms — slightly shorter than the hook's 300ms so resetUI\n // wins the race. When resetUI's unmount runs, the hook's pending\n // setTimeout is cleared by its own useEffect cleanup, so we don't\n // double-fire. State outside React (GGBoss class, bossStore singleton,\n // overlay) survives.\n let resizeTimer: ReturnType<typeof setTimeout> | null = null;\n const onTerminalResize = (): void => {\n if (resizeTimer) clearTimeout(resizeTimer);\n resizeTimer = setTimeout(() => {\n resizeTimer = null;\n resetUI();\n }, 250);\n };\n process.stdout.on(\"resize\", onTerminalResize);\n\n return {\n // Follow ref.instance through restarts: when /clear nukes the current\n // instance and creates a new one, this promise re-binds to whichever\n // Ink instance is alive now. Without the loop, we'd wait on the OLD\n // instance's waitUntilExit (which already resolved on unmount) and\n // exit the CLI immediately after every /clear.\n waitUntilExit: async () => {\n while (true) {\n const current = ref.instance;\n if (!current) {\n process.stdout.off(\"resize\", onTerminalResize);\n if (resizeTimer) clearTimeout(resizeTimer);\n return;\n }\n await current.waitUntilExit();\n // If the user ran /clear, ref.instance is now a NEW instance —\n // loop and wait on that one. If exit was final (no replacement),\n // ref.instance was nulled below and the loop ends.\n if (ref.instance === current) {\n ref.instance = null;\n process.stdout.off(\"resize\", onTerminalResize);\n if (resizeTimer) clearTimeout(resizeTimer);\n return;\n }\n }\n },\n unmount: () => {\n process.stdout.off(\"resize\", onTerminalResize);\n if (resizeTimer) clearTimeout(resizeTimer);\n ref.instance?.unmount();\n },\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 \"@iroaxel/arcicoder/ui/theme\";\nimport { useTerminalSize } from \"@iroaxel/arcicoder/ui/hooks/terminal-size\";\nimport { getContextWindow } from \"@iroaxel/arcicoder\";\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 @iroaxel/arcena 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 arcena that mirrors arcicoder'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 arcicoder'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 ARCena.\"\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 ? \"Installing…\" : \"Installing in background · relaunch when done\"}\n </Text>\n </>\n )}\n </Box>\n </Box>\n );\n}\n","import type { SlashCommandInfo } from \"@iroaxel/arcicoder/ui\";\n\n/**\n * Slash commands the boss CLI recognizes. Shape matches arcicoder'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 arcena\" },\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[] = [\"**arcena 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 \"@iroaxel/arcicoder/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 arcicoder'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 \"@iroaxel/arcicoder/ui\";\n\n/**\n * Boss-themed phrase library for the activity indicator. Replaces arcicoder'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 \"@iroaxel/arcicoder/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 arcena. 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 arcicoder'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 ARCena 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 \"@iroaxel/arcicoder/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 { existsSync } from \"node:fs\";\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 * On WSL2, native Linux audio binaries can't reach the Windows audio device\n * through WSLg's bridge in any useful way for streaming — `ffplay` accepts\n * the spawn (so we report \"Now playing\" to the user) but no audio actually\n * comes out. Returning a successful spawn handle that doesn't produce sound\n * is worse than failing fast: the user thinks it's working and goes off to\n * troubleshoot their speakers / VPN / firewall.\n *\n * Detect WSL via $WSL_DISTRO_NAME or /proc/sys/fs/binfmt_misc/WSLInterop.\n */\nfunction isWsl(): boolean {\n // WSL env vars can leak into a Windows shell launched from a WSL session,\n // but process.platform stays \"win32\" there. Anchor detection to platform\n // so isWsl() means \"I am running on a Linux distro inside WSL\", never\n // \"WSL env vars happen to be set somewhere upstream\".\n if (process.platform !== \"linux\") return false;\n return !!process.env.WSL_DISTRO_NAME || existsSync(\"/proc/sys/fs/binfmt_misc/WSLInterop\");\n}\n\n/**\n * Stream a station through powershell.exe + WPF MediaPlayer on the Windows\n * host instead of a Linux binary. Returns the ChildProcess or null if the\n * spawn failed — caller falls through to the native Linux candidates so a\n * WSL user with mpv installed and WSLg audio working keeps the existing\n * behaviour.\n *\n * Why a Dispatcher::Run() at the end of the script: WPF's MediaPlayer is\n * async — Open() and Play() return immediately and the actual playback runs\n * on a background thread that needs the COM message loop pumped. Without\n * Dispatcher::Run(), powershell.exe exits seconds later, the MediaPlayer\n * gets garbage-collected, and you hear silence. Pumping the dispatcher\n * keeps the player alive until stopRadio() kills the powershell process.\n *\n * Security:\n * - station.url is double-checked against the in-process RADIO_STATIONS\n * allowlist before spawning, even though the only call site already\n * looked it up there. Belt-and-suspenders against any future code path\n * that constructs a station object outside the constant array.\n * - Scheme is enforced as http/https so a future entry can't slip a\n * file:// or javascript: URL through.\n * - The URL is passed via GGBOSS_RADIO_URL env, never string-interpolated\n * into the PowerShell -Command argument. WSLENV lists the var so it\n * actually crosses the WSL→Windows process boundary (custom env vars\n * don't propagate by default — powershell.exe just sees them as empty\n * without WSLENV). Existing $WSLENV is preserved.\n * - powershell.exe runs -NoProfile -WindowStyle Hidden.\n */\nfunction tryPlayOnWindowsHost(station: RadioStation): ChildProcess | null {\n const allowedUrls = new Set(RADIO_STATIONS.map((s) => s.url));\n if (!allowedUrls.has(station.url)) return null;\n if (!/^https?:\\/\\//i.test(station.url)) return null;\n const psScript = [\n \"Add-Type -AssemblyName presentationCore;\",\n \"Add-Type -AssemblyName WindowsBase;\",\n \"$p = New-Object System.Windows.Media.MediaPlayer;\",\n \"$p.Open([uri]$env:GGBOSS_RADIO_URL);\",\n \"$p.Play();\",\n \"[System.Windows.Threading.Dispatcher]::Run();\",\n ].join(\" \");\n try {\n const child = spawn(\n \"powershell.exe\",\n [\"-NoProfile\", \"-WindowStyle\", \"Hidden\", \"-Command\", psScript],\n {\n detached: true,\n stdio: \"ignore\",\n env: {\n ...process.env,\n GGBOSS_RADIO_URL: station.url,\n WSLENV: (process.env.WSLENV ? process.env.WSLENV + \":\" : \"\") + \"GGBOSS_RADIO_URL\",\n },\n },\n );\n return child;\n } catch {\n return null;\n }\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 // WSL2: route through the Windows host before falling back to native\n // Linux players. Without this, ffplay reports a successful spawn but\n // produces no audio (WSLg audio bridge is fragile for streaming).\n if (isWsl()) {\n const child = tryPlayOnWindowsHost(station);\n if (child) {\n let errored = false;\n child.once(\"error\", () => {\n errored = true;\n });\n if (child.pid && !errored) {\n currentChild = child;\n currentStationId = stationId;\n log(\"INFO\", \"radio\", \"playing\", {\n station: station.id,\n player: \"powershell.exe (wsl→host)\",\n url: station.url,\n });\n child.unref();\n return { ok: true };\n }\n }\n }\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 * arcena auto-update — mirrors arcicoder's pattern (packages/ggcoder/src/core/\n * auto-update.ts) but pinned to @iroaxel/arcena and with its own state\n * file under ~/.gg/boss/ so it can't fight with arcicoder'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 @iroaxel/arcena@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 = \"@iroaxel/arcena\";\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 = `Axel 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 arcena 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 \"ARCena\" 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\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 = 0;\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","path","fs","path","fs","readline","readline","gradientText","import_react","import_react","import_react","import_react","import_react","import_react","import_react","import_jsx_runtime","truncate","import_react","import_jsx_runtime","import_react","import_jsx_runtime","currentStationId","spawn","fs","path","os","path","os","fs","spawn","import_jsx_runtime","scopePrefix","React","import_react","import_jsx_runtime","cwd","path"]}
|