sisyphi 1.1.37 → 1.1.39
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/deploy/shared/cloud-init.yaml.tpl +7 -1
- package/dist/cli.js +627 -311
- package/dist/cli.js.map +1 -1
- package/dist/daemon.js +236 -172
- package/dist/daemon.js.map +1 -1
- package/dist/deploy/shared/cloud-init.yaml.tpl +7 -1
- package/dist/tui.js +235 -102
- package/dist/tui.js.map +1 -1
- package/package.json +1 -1
package/dist/tui.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/tui/terminal.ts","../src/shared/paths.ts","../src/tui/render.ts","../src/shared/config.ts","../src/daemon/history.ts","../src/daemon/lib/atomic.ts","../src/shared/gitignore.ts","../src/shared/types.ts","../src/daemon/state.ts","../src/shared/shell.ts","../src/daemon/notify.ts","../src/daemon/ask-store.ts","../src/tui/single-ask.ts","../src/tui/index.ts","../src/tui/state.ts","../src/tui/app.ts","../src/tui/input.ts","../src/shared/session-export.ts","../src/tui/lib/tree.ts","../src/tui/lib/format.ts","../src/shared/format.ts","../src/tui/panels/overlays.ts","../src/shared/companion-render.ts","../src/daemon/companion.ts","../src/shared/companion-normalize.ts","../src/shared/companion-types.ts","../src/daemon/companion-memory.ts","../src/daemon/haiku.ts","../src/shared/env.ts","../src/shared/companion-badges.ts","../src/tui/panels/mounted-humanloop.ts","../src/shared/client.ts","../src/shared/keymap.ts","../src/tui/lib/tree-render.ts","../src/tui/lib/reports.ts","../src/tui/lib/client.ts","../src/tui/lib/tmux.ts","../src/shared/exec.ts","../src/tui/lib/clipboard.ts","../src/tui/lib/context.ts","../src/tui/panels/tree.ts","../src/tui/panels/detail.ts","../src/shared/utils.ts","../src/tui/panels/cycle-flow.ts","../src/shared/inbox-types.ts","../src/tui/panels/stacked-detail.ts","../src/tui/lib/markdown-highlight.ts","../src/tui/lib/gloam.ts","../src/tui/panels/bottom.ts","../src/tui/panels/cross-session-inbox.ts","../src/tui/lib/popup-compose.ts","../src/shared/sisyphus-init-lua.ts"],"sourcesContent":["export interface Key {\n upArrow: boolean;\n downArrow: boolean;\n leftArrow: boolean;\n rightArrow: boolean;\n pageUp: boolean;\n pageDown: boolean;\n return: boolean;\n escape: boolean;\n ctrl: boolean;\n shift: boolean;\n tab: boolean;\n backspace: boolean;\n delete: boolean;\n meta: boolean;\n}\n\nexport type KeypressHandler = (input: string, key: Key) => void;\n\nfunction emptyKey(): Key {\n return {\n upArrow: false,\n downArrow: false,\n leftArrow: false,\n rightArrow: false,\n pageUp: false,\n pageDown: false,\n return: false,\n escape: false,\n ctrl: false,\n shift: false,\n tab: false,\n backspace: false,\n delete: false,\n meta: false,\n };\n}\n\n// ── Terminal Setup/Teardown ──────────────────────────────────────────────────\n\nexport function setupTerminal(): () => void {\n let cleaned = false;\n\n const cleanup = (): void => {\n if (cleaned) return;\n cleaned = true;\n process.stdout.write('\\x1b[?25h\\x1b[?1049l');\n process.stdin.setRawMode(false);\n process.stdin.pause();\n };\n\n process.stdin.setRawMode(true);\n process.stdin.resume();\n process.stdin.setEncoding('utf-8');\n process.stdout.write('\\x1b[?1049h\\x1b[?25l\\x1b[2J');\n\n process.on('SIGINT', () => { cleanup(); process.exit(0); });\n process.on('SIGTERM', () => { cleanup(); process.exit(0); });\n process.on('exit', cleanup);\n process.on('uncaughtException', (err) => {\n cleanup();\n console.error(err);\n process.exit(1);\n });\n\n return cleanup;\n}\n\n// ── Stdout Write Helper ──────────────────────────────────────────────────────\n\nexport function writeToStdout(data: string): void {\n process.stdout.write(data);\n}\n\n// ── Keypress Parser ──────────────────────────────────────────────────────────\n\n/**\n * Parse all complete key sequences from a buffer string.\n * Returns an array of [input, Key] pairs and the remaining unparsed buffer.\n */\nfunction parseBuffer(buf: string): { events: Array<[string, Key]>; remaining: string } {\n const events: Array<[string, Key]> = [];\n\n let i = 0;\n while (i < buf.length) {\n const ch = buf[i]!;\n\n // ESC prefix sequences\n if (ch === '\\x1b') {\n const rest = buf.slice(i + 1);\n\n // CSI sequences: \\x1b[...\n if (rest.startsWith('[')) {\n const after = rest.slice(1);\n\n // Shift+Arrow: \\x1b[1;2A/B/C/D\n const shiftArrow = after.match(/^1;2([ABCD])/);\n if (shiftArrow) {\n const key = emptyKey();\n key.shift = true;\n const dir = shiftArrow[1]!;\n if (dir === 'A') key.upArrow = true;\n else if (dir === 'B') key.downArrow = true;\n else if (dir === 'C') key.rightArrow = true;\n else if (dir === 'D') key.leftArrow = true;\n const seq = `\\x1b[1;2${dir}`;\n events.push([seq, key]);\n i += seq.length;\n continue;\n }\n\n // Shift+Tab (backtab): \\x1b[Z\n if (after.length >= 1 && after[0] === 'Z') {\n const key = emptyKey();\n key.tab = true;\n key.shift = true;\n const seq = `\\x1b[Z`;\n events.push([seq, key]);\n i += seq.length;\n continue;\n }\n\n // Arrow keys: \\x1b[A/B/C/D\n if (after.length >= 1 && 'ABCD'.includes(after[0]!)) {\n const key = emptyKey();\n const dir = after[0]!;\n if (dir === 'A') key.upArrow = true;\n else if (dir === 'B') key.downArrow = true;\n else if (dir === 'C') key.rightArrow = true;\n else if (dir === 'D') key.leftArrow = true;\n const seq = `\\x1b[${dir}`;\n events.push([seq, key]);\n i += seq.length;\n continue;\n }\n\n // Tilde sequences: \\x1b[N~\n const tildeMatch = after.match(/^(\\d+)~/);\n if (tildeMatch) {\n const num = tildeMatch[1]!;\n const key = emptyKey();\n if (num === '5') key.pageUp = true;\n else if (num === '6') key.pageDown = true;\n else if (num === '3') key.delete = true;\n const seq = `\\x1b[${num}~`;\n events.push([seq, key]);\n i += seq.length;\n continue;\n }\n\n // Incomplete CSI — need more data\n return { events, remaining: buf.slice(i) };\n }\n\n // Lone ESC — signal caller to wait (disambiguate vs CSI prefix)\n if (rest.length === 0) {\n return { events, remaining: buf.slice(i) };\n }\n\n // \\x1b + regular char → Meta key\n const metaCh = rest[0]!;\n const key = emptyKey();\n key.meta = true;\n events.push([metaCh, key]);\n i += 2;\n continue;\n }\n\n // Return\n if (ch === '\\r') {\n const key = emptyKey();\n key.return = true;\n events.push([ch, key]);\n i++;\n continue;\n }\n\n // Tab\n if (ch === '\\t') {\n const key = emptyKey();\n key.tab = true;\n events.push([ch, key]);\n i++;\n continue;\n }\n\n // Backspace (DEL or BS)\n if (ch === '\\x7f' || ch === '\\x08') {\n const key = emptyKey();\n key.backspace = true;\n events.push([ch, key]);\n i++;\n continue;\n }\n\n // Ctrl+A–Z (\\x01–\\x1a)\n const code = ch.charCodeAt(0);\n if (code >= 0x01 && code <= 0x1a) {\n const key = emptyKey();\n key.ctrl = true;\n const letter = String.fromCharCode(code + 96);\n events.push([letter, key]);\n i++;\n continue;\n }\n\n // Printable / multibyte char\n events.push([ch, emptyKey()]);\n i++;\n }\n\n return { events, remaining: '' };\n}\n\n// ── Raw Stdin Bypass (for neovim PTY forwarding) ─────────────────────────────\n\nlet rawBypassHandler: ((data: string) => boolean) | null = null;\n\nexport function setRawBypass(handler: ((data: string) => boolean) | null): void {\n rawBypassHandler = handler;\n}\n\nexport function startKeypressListener(handler: KeypressHandler): () => void {\n let buffer = '';\n let escTimer: ReturnType<typeof setTimeout> | null = null;\n\n const onData = (data: string): void => {\n // Raw bypass — forward to neovim PTY if active\n if (rawBypassHandler) {\n const handled = rawBypassHandler(data);\n if (handled) return;\n }\n\n // Cancel pending escape timer — more data arrived\n if (escTimer !== null) {\n clearTimeout(escTimer);\n escTimer = null;\n }\n\n buffer += data;\n\n const { events, remaining } = parseBuffer(buffer);\n buffer = remaining;\n\n for (const [input, key] of events) {\n handler(input, key);\n }\n\n // If buffer ends with lone ESC, start disambiguation timer\n if (buffer === '\\x1b') {\n escTimer = setTimeout(() => {\n escTimer = null;\n buffer = '';\n const key = emptyKey();\n key.escape = true;\n handler('\\x1b', key);\n }, 50);\n }\n };\n\n process.stdin.on('data', onData);\n\n return (): void => {\n process.stdin.off('data', onData);\n if (escTimer !== null) {\n clearTimeout(escTimer);\n escTimer = null;\n }\n };\n}\n\n// ── Resize Handler ───────────────────────────────────────────────────────────\n\nexport function onResize(callback: () => void): () => void {\n const onStdoutResize = (): void => callback();\n const onSigwinch = (): void => callback();\n\n process.stdout.on('resize', onStdoutResize);\n process.on('SIGWINCH', onSigwinch);\n\n return (): void => {\n process.stdout.off('resize', onStdoutResize);\n process.off('SIGWINCH', onSigwinch);\n };\n}\n","import { homedir } from 'node:os';\nimport { basename, join } from 'node:path';\n\nexport function globalDir(): string {\n return join(homedir(), '.sisyphus');\n}\n\nexport function socketPath(): string {\n return join(globalDir(), 'daemon.sock');\n}\n\nexport function globalConfigPath(): string {\n return join(globalDir(), 'config.json');\n}\n\nexport function daemonLogPath(): string {\n return join(globalDir(), 'daemon.log');\n}\n\nexport function daemonPidPath(): string {\n return join(globalDir(), 'daemon.pid');\n}\n\nexport function daemonUpdatingPath(): string {\n return join(globalDir(), 'updating');\n}\n\nexport function projectDir(cwd: string): string {\n return join(cwd, '.sisyphus');\n}\n\nexport function projectConfigPath(cwd: string): string {\n return join(projectDir(cwd), 'config.json');\n}\n\nexport function projectOrchestratorPromptPath(cwd: string): string {\n return join(projectDir(cwd), 'orchestrator.md');\n}\n\nexport function userOrchestratorPromptPath(): string {\n return join(globalDir(), 'orchestrator.md');\n}\n\nexport function projectOrchestratorSettingsPath(cwd: string): string {\n return join(projectDir(cwd), 'orchestrator-settings.json');\n}\n\nexport function userOrchestratorSettingsPath(): string {\n return join(globalDir(), 'orchestrator-settings.json');\n}\n\nexport function projectAgentPluginDir(cwd: string): string {\n return join(projectDir(cwd), 'agent-plugin');\n}\n\nexport function userAgentPluginDir(): string {\n return join(globalDir(), 'agent-plugin');\n}\n\nexport function projectOrchestratorPluginDir(cwd: string): string {\n return join(projectDir(cwd), 'orchestrator-plugin');\n}\n\nexport function userOrchestratorPluginDir(): string {\n return join(globalDir(), 'orchestrator-plugin');\n}\n\nexport function sessionsDir(cwd: string): string {\n return join(projectDir(cwd), 'sessions');\n}\n\nexport function sessionDir(cwd: string, sessionId: string): string {\n return join(sessionsDir(cwd), sessionId);\n}\n\nexport function statePath(cwd: string, sessionId: string): string {\n return join(sessionDir(cwd, sessionId), 'state.json');\n}\n\nexport function reportsDir(cwd: string, sessionId: string): string {\n return join(sessionDir(cwd, sessionId), 'reports');\n}\n\nexport function reportFilePath(cwd: string, sessionId: string, agentId: string, suffix: string): string {\n return join(reportsDir(cwd, sessionId), `${agentId}-${suffix}.md`);\n}\n\nexport function messagesDir(cwd: string, sessionId: string): string {\n return join(sessionDir(cwd, sessionId), 'messages');\n}\n\nexport function promptsDir(cwd: string, sessionId: string): string {\n return join(sessionDir(cwd, sessionId), 'prompts');\n}\n\nexport function contextDir(cwd: string, sessionId: string): string {\n return join(sessionDir(cwd, sessionId), 'context');\n}\n\nexport function roadmapPath(cwd: string, sessionId: string): string {\n return join(sessionDir(cwd, sessionId), 'roadmap.md');\n}\n\nexport function goalPath(cwd: string, sessionId: string): string {\n return join(sessionDir(cwd, sessionId), 'goal.md');\n}\n\nexport function initialPromptPath(cwd: string, sessionId: string): string {\n return join(sessionDir(cwd, sessionId), 'initial-prompt.md');\n}\n\nexport function strategyPath(cwd: string, sessionId: string): string {\n return join(sessionDir(cwd, sessionId), 'strategy.md');\n}\n\nexport function digestPath(cwd: string, sessionId: string): string {\n return join(sessionDir(cwd, sessionId), 'digest.json');\n}\n\nexport function logsDir(cwd: string, sessionId: string): string {\n return join(sessionDir(cwd, sessionId), 'logs');\n}\n\nexport function cycleLogPath(cwd: string, sessionId: string, cycle: number): string {\n return join(logsDir(cwd, sessionId), `cycle-${String(cycle).padStart(3, '0')}.md`);\n}\n\n// Backwards compat for old sessions\nexport function legacyLogsPath(cwd: string, sessionId: string): string {\n return join(sessionDir(cwd, sessionId), 'logs.md');\n}\n\nexport function snapshotsDir(cwd: string, sessionId: string): string {\n return join(sessionDir(cwd, sessionId), 'snapshots');\n}\n\nexport function snapshotDir(cwd: string, sessionId: string, cycle: number): string {\n return join(snapshotsDir(cwd, sessionId), `cycle-${cycle}`);\n}\n\nexport function tuiScratchDir(cwd: string, sessionId: string): string {\n return join(sessionDir(cwd, sessionId), '.tui');\n}\n\n// ── sisyphus ask: per-session ask directory and per-ask file paths ────────────\n\nexport function askDir(cwd: string, sessionId: string): string {\n return join(contextDir(cwd, sessionId), 'ask');\n}\n\nexport function askEntryDir(cwd: string, sessionId: string, askId: string): string {\n return join(askDir(cwd, sessionId), askId);\n}\n\nexport function askMetaPath(cwd: string, sessionId: string, askId: string): string {\n return join(askEntryDir(cwd, sessionId, askId), 'meta.json');\n}\n\nexport function askDecisionsPath(cwd: string, sessionId: string, askId: string): string {\n return join(askEntryDir(cwd, sessionId, askId), 'decisions.json');\n}\n\nexport function askOutputPath(cwd: string, sessionId: string, askId: string): string {\n return join(askEntryDir(cwd, sessionId, askId), 'output.json');\n}\n\nexport function askProgressPath(cwd: string, sessionId: string, askId: string): string {\n return join(askEntryDir(cwd, sessionId, askId), 'progress.json');\n}\n\nexport function askVisualsDir(cwd: string, sessionId: string, askId: string): string {\n return join(askEntryDir(cwd, sessionId, askId), 'visuals');\n}\n\nexport function askVisualMarkdownPath(cwd: string, sessionId: string, askId: string, qid: string): string {\n return join(askVisualsDir(cwd, sessionId, askId), `${qid}.md`);\n}\n\nexport function askVisualAnsiPath(cwd: string, sessionId: string, askId: string, qid: string): string {\n return join(askVisualsDir(cwd, sessionId, askId), `${qid}.ansi`);\n}\n\nexport function tmuxSessionName(cwd: string, sessionLabel: string): string {\n // Use underscores as separators — slashes break tmux -t target resolution,\n // dots get silently converted to underscores by tmux (reserved for window.pane targeting)\n return `ssyph_${basename(cwd)}_${sessionLabel}`;\n}\n\nexport function sessionsManifestPath(): string {\n return join(globalDir(), 'sessions-manifest.json');\n}\n\nexport function sessionsManifestTsvPath(): string {\n return join(globalDir(), 'sessions-manifest.tsv');\n}\n\nexport function companionPath(): string {\n return join(globalDir(), 'companion.json');\n}\n\nexport function companionMemoryPath(): string {\n return join(globalDir(), 'companion-memory.json');\n}\n\nexport function historyBaseDir(): string {\n return join(globalDir(), 'history');\n}\n\nexport function historySessionDir(sessionId: string): string {\n return join(historyBaseDir(), sessionId);\n}\n\nexport function historyEventsPath(sessionId: string): string {\n return join(historySessionDir(sessionId), 'events.jsonl');\n}\n\nexport function historySessionSummaryPath(sessionId: string): string {\n return join(historySessionDir(sessionId), 'session.json');\n}\n\n// ── sisyphus deploy: per-provider Terraform state + creds ────────────────────\n\nexport function deployDir(): string {\n return join(globalDir(), 'deploy');\n}\n\nexport function deployProviderDir(provider: string): string {\n return join(deployDir(), provider);\n}\n\nexport function deployStatePath(provider: string): string {\n return join(deployProviderDir(provider), 'terraform.tfstate');\n}\n\nexport function deployStateBackupPath(provider: string): string {\n return join(deployProviderDir(provider), 'terraform.tfstate.bak');\n}\n\nexport function deployRuntimePath(provider: string): string {\n return join(deployProviderDir(provider), 'runtime.json');\n}\n\nexport function deployCredsPath(provider: string): string {\n return join(deployDir(), `${provider}.env`);\n}\n\nexport function deployTailscaleEnvPath(): string {\n return join(deployDir(), 'tailscale.env');\n}\n\n// ── sisyphus cloud: per-repo box-side paths (remote, not local fs) ───────────\n\n/**\n * Path on the cloud box where a repo's working tree is rsync'd to.\n * `~/projects/<repo>` — interpreted by the box's shell, so this is a string\n * template, not for local fs use.\n */\nexport function boxRepoPath(repo: string): string {\n return `~/projects/${repo}`;\n}\n\n/**\n * Path on the cloud box where the per-repo cloud-state sidecar lives. Mirrors\n * the local `~/.sisyphus/deploy/<provider>/runtime.json` convention but for\n * the box's own `~/.sisyphus/cloud/<repo>.json`.\n */\nexport function boxCloudSidecarPath(repo: string): string {\n return `~/.sisyphus/cloud/${repo}.json`;\n}\n\nexport function boxCloudSidecarDir(): string {\n return `~/.sisyphus/cloud`;\n}\n\nexport function isSisyphusSession(name: string): boolean {\n return name.startsWith('ssyph_');\n}\n\nexport function tmuxSessionDisplayName(name: string): string {\n return name.replace(/^ssyph_[^_]+_/, '');\n}\n\n","import stringWidth from 'string-width';\nimport type { Seg, DetailLine } from './lib/format.js';\nimport type { ThrottledScroll } from './state.js';\n\nexport type { Seg, DetailLine };\n\n// ─── Color mapping ────────────────────────────────────────────────────────────\n\nexport const COLOR_SGR: Record<string, number> = {\n black: 30,\n red: 31,\n green: 32,\n yellow: 33,\n blue: 34,\n magenta: 35,\n cyan: 36,\n white: 37,\n gray: 90,\n};\n\nexport function colorToSGR(color: string): number {\n const code = COLOR_SGR[color];\n if (code === undefined) throw new Error(`Unknown color: ${color}`);\n return code;\n}\n\n// ─── Seg → ANSI conversion (§1.1) ────────────────────────────────────────────\n\nexport function renderLine(segs: Seg[]): string {\n let out = '';\n for (const s of segs) {\n const codes: string[] = [];\n if (s.bold) codes.push('1');\n if (s.dim) codes.push('2');\n if (s.italic) codes.push('3');\n if (s.strikethrough) codes.push('9');\n if (s.inverse) codes.push('7');\n if (s.fg) codes.push(s.fg);\n else if (s.color) codes.push(String(colorToSGR(s.color)));\n if (s.bg) codes.push(s.bg);\n if (codes.length > 0) {\n out += `\\x1b[${codes.join(';')}m${s.text}\\x1b[0m`;\n } else {\n out += s.text;\n }\n }\n return out;\n}\n\n// ─── Frame Buffer (§1.2) ──────────────────────────────────────────────────────\n\nexport interface FrameBuffer {\n lines: string[];\n width: number;\n height: number;\n}\n\nlet cachedBlank = '';\nlet cachedBlankWidth = 0;\n\nexport function createFrameBuffer(width: number, height: number): FrameBuffer {\n if (width !== cachedBlankWidth) {\n cachedBlank = ' '.repeat(width);\n cachedBlankWidth = width;\n }\n const lines = new Array<string>(height);\n for (let i = 0; i < height; i++) lines[i] = cachedBlank;\n return { lines, width, height };\n}\n\n/**\n * Copy rows from a previous frame into the buffer (skip re-render for clean panels).\n */\nexport function copyRows(buf: FrameBuffer, src: string[], startRow: number, count: number): void {\n for (let i = 0; i < count && startRow + i < buf.height; i++) {\n buf.lines[startRow + i] = src[startRow + i]!;\n }\n}\n\n// ─── Frame Diffing (§1.3) ────────────────────────────────────────────────────\n\nexport function flushFrame(frame: string[], prevFrame: string[], suffix?: string): string {\n let out = '\\x1b[?2026h'; // begin synchronized output\n for (let i = 0; i < frame.length; i++) {\n if (frame[i] !== prevFrame[i]) {\n out += `\\x1b[${i + 1};1H`; // cursor to row i+1, col 1\n out += '\\x1b[2K'; // clear entire line\n out += frame[i];\n }\n }\n if (suffix) out += suffix;\n out += '\\x1b[?2026l'; // end synchronized output\n return out;\n}\n\n// ─── ANSI escape sequence regex ───────────────────────────────────────────────\n\nconst ANSI_RE = /\\x1b\\[[0-9;]*[a-zA-Z]/g;\n\n// ─── Clip ANSI string to display width (no buffer interaction) ──────────────\n\n/**\n * Clip an ANSI string to exactly `maxWidth` display columns, padding with spaces.\n * Pure function — no buffer splicing.\n */\nexport function clipAnsi(content: string, maxWidth: number): string {\n let out = '';\n let displayWidth = 0;\n let i = 0;\n\n while (i < content.length) {\n if (content[i] === '\\x1b' && content[i + 1] === '[') {\n const seqLen = ansiLen(content, i);\n if (seqLen > 0) {\n out += content.substring(i, i + seqLen);\n i += seqLen;\n continue;\n }\n }\n const cp = content.codePointAt(i)!;\n // Skip control characters (newlines, tabs, etc.) — they break frame output\n if (cp < 0x20 && cp !== 0x1b) { i++; continue; }\n const ch = String.fromCodePoint(cp);\n const chWidth = cp < 128 ? 1 : stringWidth(ch);\n if (displayWidth + chWidth > maxWidth) break;\n out += ch;\n displayWidth += chWidth;\n i += ch.length;\n }\n\n if (out.includes('\\x1b[') && !out.endsWith('\\x1b[0m')) {\n out += '\\x1b[0m';\n }\n\n const remaining = maxWidth - displayWidth;\n if (remaining > 0) out += ' '.repeat(remaining);\n return out;\n}\n\n/**\n * Fast display-width calculation that skips ANSI escapes without regex allocation.\n */\nfunction displayWidthFast(s: string): number {\n let w = 0;\n let i = 0;\n while (i < s.length) {\n if (s[i] === '\\x1b' && s[i + 1] === '[') {\n const len = ansiLen(s, i);\n if (len > 0) { i += len; continue; }\n }\n const cp = s.codePointAt(i)!;\n const ch = String.fromCodePoint(cp);\n w += cp < 128 ? 1 : stringWidth(ch);\n i += ch.length;\n }\n return w;\n}\n\n/**\n * Parse ANSI escape sequence at position i. Returns length of sequence or 0.\n * Avoids s.slice(i).match(regex) which allocates a new string each call.\n */\nfunction ansiLen(s: string, i: number): number {\n // Caller already verified s[i] === '\\x1b' && s[i+1] === '['\n let j = i + 2;\n const len = s.length;\n // Consume parameter bytes: digits 0-9 and semicolons\n while (j < len) {\n const c = s.charCodeAt(j);\n if ((c >= 0x30 && c <= 0x39) || c === 0x3b) { // '0'-'9' or ';'\n j++;\n } else {\n break;\n }\n }\n // Must end with a letter (final byte)\n if (j < len) {\n const c = s.charCodeAt(j);\n if ((c >= 0x41 && c <= 0x5a) || (c >= 0x61 && c <= 0x7a)) { // A-Z or a-z\n return j + 1 - i;\n }\n }\n return 0;\n}\n\n// ─── Write functions ──────────────────────────────────────────────────────────\n\n/**\n * Write content into frame buffer at position (x, y).\n *\n * Strategy: rebuild the target line by splitting into display columns,\n * inserting the new content, then reassembling. Since we build the frame\n * fresh each render, we can treat the existing line as plain chars + ANSI.\n *\n * This implementation replaces display columns [x, x+displayWidth(content))\n * in the buffer line with the new content.\n */\nexport function writeAt(buf: FrameBuffer, x: number, y: number, content: string): void {\n if (y < 0 || y >= buf.height) return;\n if (x < 0 || x >= buf.width) return;\n\n const existing = buf.lines[y]!;\n const contentDisplayWidth = stringWidth(content.replace(ANSI_RE, ''));\n\n // Split the existing line into prefix (0..x) and suffix (x+contentDisplayWidth..)\n // We need to walk the existing line respecting display widths.\n // suffix uses restoreState=true to preserve ANSI bg/fg from before the splice point.\n const prefix = sliceDisplayCols(existing, 0, x);\n const suffix = sliceDisplayCols(existing, x + contentDisplayWidth, buf.width, true);\n\n // Pad prefix if it's shorter than expected (can happen at end of line)\n const prefixWidth = stringWidth(prefix.replace(ANSI_RE, ''));\n const paddedPrefix = prefix + ' '.repeat(Math.max(0, x - prefixWidth));\n\n buf.lines[y] = paddedPrefix + content + suffix;\n}\n\n/**\n * Write ANSI string into buffer at (x, y), truncating to maxWidth display columns.\n * Pads remaining width with spaces.\n */\nexport function writeClipped(\n buf: FrameBuffer,\n x: number,\n y: number,\n content: string,\n maxWidth: number,\n): void {\n if (y < 0 || y >= buf.height) return;\n if (x < 0 || x >= buf.width) return;\n\n let out = '';\n let displayWidth = 0;\n let i = 0;\n\n while (i < content.length) {\n // Check for ANSI escape sequence — pass through without counting width\n if (content[i] === '\\x1b' && content[i + 1] === '[') {\n const seqLen = ansiLen(content, i);\n if (seqLen > 0) {\n out += content.substring(i, i + seqLen);\n i += seqLen;\n continue;\n }\n }\n\n // Get the next character (handle surrogate pairs)\n const cp = content.codePointAt(i)!;\n // Skip control characters (newlines, tabs, etc.) — they break frame output\n if (cp < 0x20 && cp !== 0x1b) { i++; continue; }\n const ch = String.fromCodePoint(cp);\n const chWidth = cp < 128 ? 1 : stringWidth(ch);\n\n if (displayWidth + chWidth > maxWidth) break;\n\n out += ch;\n displayWidth += chWidth;\n i += ch.length;\n }\n\n // Ensure any open SGR sequences are reset\n if (out.includes('\\x1b[') && !out.endsWith('\\x1b[0m')) {\n out += '\\x1b[0m';\n }\n\n // Pad to maxWidth\n const remaining = maxWidth - displayWidth;\n if (remaining > 0) {\n out += ' '.repeat(remaining);\n }\n\n // Splice directly into buffer line — we already know exact display width is maxWidth,\n // so skip writeAt's redundant stringWidth + double sliceDisplayCols re-parse.\n const existing = buf.lines[y]!;\n const prefix = sliceDisplayCols(existing, 0, x);\n const suffix = sliceDisplayCols(existing, x + maxWidth, buf.width, true);\n const prefixDisplayW = displayWidthFast(prefix);\n const paddedPrefix = prefixDisplayW < x ? prefix + ' '.repeat(x - prefixDisplayW) : prefix;\n buf.lines[y] = paddedPrefix + out + suffix;\n}\n\n/**\n * Write centered text at the given row.\n */\nexport function writeCenter(buf: FrameBuffer, row: number, content: string): void {\n const textWidth = stringWidth(content.replace(ANSI_RE, ''));\n const x = Math.max(0, Math.floor((buf.width - textWidth) / 2));\n writeAt(buf, x, row, content);\n}\n\n// ─── Border Drawing (§1.5) ────────────────────────────────────────────────────\n\nexport function drawBorder(\n buf: FrameBuffer,\n x: number,\n y: number,\n w: number,\n h: number,\n color: string,\n): void {\n const sgr = `\\x1b[${colorToSGR(color)}m`;\n const reset = '\\x1b[0m';\n\n // Top: ╭────╮\n writeAt(buf, x, y, sgr + '╭' + '─'.repeat(w - 2) + '╮' + reset);\n // Bottom: ╰────╯\n writeAt(buf, x, y + h - 1, sgr + '╰' + '─'.repeat(w - 2) + '╯' + reset);\n // Sides\n for (let row = y + 1; row < y + h - 1; row++) {\n writeAt(buf, x, row, sgr + '│' + reset);\n writeAt(buf, x + w - 1, row, sgr + '│' + reset);\n }\n}\n\n// ─── Panel Rendering (§4.2) ───────────────────────────────────────────────────\n\nexport interface Rect {\n x: number;\n y: number;\n w: number;\n h: number;\n}\n\n/**\n * Cache for pre-rendered ANSI strings. Keyed by the DetailLine[] identity —\n * when the caller provides a `renderedCache`, renderPanel will populate it\n * on first render and reuse on subsequent frames (avoiding renderLine per line).\n */\nexport interface RenderedCache {\n lines: DetailLine[];\n ansi: string[];\n}\n\nexport function renderPanel(\n buf: FrameBuffer,\n rect: Rect,\n lines: DetailLine[],\n scrollOffset: number,\n focused: boolean,\n borderColor: string,\n renderedCache?: RenderedCache | null,\n): void {\n const { x, y, w, h } = rect;\n\n // 1. Draw border\n drawBorder(buf, x, y, w, h, focused ? 'blue' : borderColor);\n\n // 2. Inner dimensions (border + 1 padding each side, matching Ink's paddingX={1})\n const innerX = x + 2;\n const innerW = w - 4;\n const innerY = y + 1;\n const innerH = h - 2;\n\n if (innerW <= 0 || innerH <= 0) return;\n\n // 3. Pre-render ANSI strings (cached across frames)\n let ansiLines: string[];\n if (renderedCache && renderedCache.lines === lines) {\n ansiLines = renderedCache.ansi;\n } else {\n ansiLines = new Array<string>(lines.length);\n for (let i = 0; i < lines.length; i++) {\n ansiLines[i] = renderLine(lines[i]!);\n }\n if (renderedCache) {\n renderedCache.lines = lines;\n renderedCache.ansi = ansiLines;\n }\n }\n\n // 4. Windowed slice\n const hasOverflow = lines.length > innerH;\n const viewableH = hasOverflow ? innerH - 1 : innerH;\n const maxScroll = Math.max(0, lines.length - viewableH);\n const effectiveOffset = Math.min(scrollOffset, maxScroll);\n\n // 5. Render visible lines\n for (let i = 0; i < viewableH && effectiveOffset + i < ansiLines.length; i++) {\n writeClipped(buf, innerX, innerY + i, ansiLines[effectiveOffset + i]!, innerW);\n }\n\n // 6. Scroll indicator\n if (hasOverflow) {\n const scrollPct = maxScroll > 0 ? Math.round((effectiveOffset / maxScroll) * 100) : 100;\n const indicator = ` ↕ ${scrollPct}% · ${lines.length} lines`;\n writeClipped(buf, innerX, innerY + viewableH, `\\x1b[2m${indicator}\\x1b[0m`, innerW);\n }\n}\n\n/**\n * Build panel as self-contained row strings (w display-columns each, including borders).\n * Returns h strings. No buffer interaction — avoids sliceDisplayCols entirely.\n */\nexport function buildPanelRows(\n rect: Rect,\n lines: DetailLine[],\n scroll: ThrottledScroll,\n focused: boolean,\n borderColor: string,\n renderedCache?: RenderedCache | null,\n): string[] {\n const { w, h } = rect;\n const rows = new Array<string>(h);\n\n const color = focused ? 'cyan' : 'gray';\n const sgr = `\\x1b[${colorToSGR(color)}m`;\n const reset = '\\x1b[0m';\n const innerW = w - 4;\n const innerH = h - 2;\n const blankInner = ' '.repeat(innerW);\n\n // Top border\n rows[0] = sgr + '╭' + '─'.repeat(w - 2) + '╮' + reset;\n // Bottom border\n rows[h - 1] = sgr + '╰' + '─'.repeat(w - 2) + '╯' + reset;\n\n // Pre-fill interior rows with empty content\n const borderL = sgr + '│' + reset + ' ';\n const borderR = ' ' + sgr + '│' + reset;\n const emptyRow = borderL + blankInner + borderR;\n for (let i = 1; i < h - 1; i++) rows[i] = emptyRow;\n\n if (innerW <= 0 || innerH <= 0) return rows;\n\n // Pre-render ANSI strings (cached across frames)\n let ansiLines: string[];\n if (renderedCache && renderedCache.lines === lines) {\n ansiLines = renderedCache.ansi;\n } else {\n ansiLines = new Array<string>(lines.length);\n for (let i = 0; i < lines.length; i++) {\n ansiLines[i] = renderLine(lines[i]!);\n }\n if (renderedCache) {\n renderedCache.lines = lines;\n renderedCache.ansi = ansiLines;\n }\n }\n\n // Windowed slice\n const hasOverflow = lines.length > innerH;\n const viewableH = hasOverflow ? innerH - 1 : innerH;\n const maxScroll = Math.max(0, lines.length - viewableH);\n scroll.setMax(maxScroll);\n const effectiveOffset = scroll.offset;\n\n // Content rows — clip and compose without buffer splicing\n for (let i = 0; i < viewableH && effectiveOffset + i < ansiLines.length; i++) {\n const clipped = clipAnsi(ansiLines[effectiveOffset + i]!, innerW);\n rows[1 + i] = borderL + clipped + borderR;\n }\n\n // Scroll indicator\n if (hasOverflow) {\n const scrollPct = maxScroll > 0 ? Math.round((effectiveOffset / maxScroll) * 100) : 100;\n const indicator = ` ↕ ${scrollPct}% · ${lines.length} lines`;\n const clipped = clipAnsi(`\\x1b[2m${indicator}\\x1b[0m`, innerW);\n rows[1 + viewableH] = borderL + clipped + borderR;\n }\n\n return rows;\n}\n\n/**\n * Build empty panel rows (border only, no content).\n */\nexport function buildEmptyPanelRows(\n rect: Rect,\n focused: boolean,\n borderColor: string,\n centerText?: string,\n): string[] {\n const { w, h } = rect;\n const rows = new Array<string>(h);\n const color = focused ? 'cyan' : 'gray';\n const sgr = `\\x1b[${colorToSGR(color)}m`;\n const reset = '\\x1b[0m';\n const innerW = w - 4;\n const borderL = sgr + '│' + reset + ' ';\n const borderR = ' ' + sgr + '│' + reset;\n const emptyRow = borderL + ' '.repeat(innerW) + borderR;\n\n rows[0] = sgr + '╭' + '─'.repeat(w - 2) + '╮' + reset;\n rows[h - 1] = sgr + '╰' + '─'.repeat(w - 2) + '╯' + reset;\n for (let i = 1; i < h - 1; i++) rows[i] = emptyRow;\n\n if (centerText) {\n const midRow = Math.floor(h / 2);\n if (midRow > 0 && midRow < h - 1) {\n const clipped = clipAnsi(centerText, innerW);\n // Center within panel\n const textW = displayWidthFast(centerText);\n const pad = Math.max(0, Math.floor((innerW - textW) / 2));\n const centered = ' '.repeat(pad) + clipped;\n rows[midRow] = borderL + clipAnsi(centered, innerW) + borderR;\n }\n }\n\n return rows;\n}\n\n// ─── Internal helpers ─────────────────────────────────────────────────────────\n\n/**\n * Slice a string (which may contain ANSI escapes) to display columns [start, end).\n * ANSI sequences are passed through only within the slice range.\n */\nfunction sliceDisplayCols(s: string, start: number, end: number, restoreState = false): string {\n let out = '';\n let col = 0;\n let i = 0;\n let inSlice = false;\n let hasOpenSGR = false;\n\n // When restoreState is true, track the last ANSI state before the slice\n // so it can be prepended — restores bg/fg colors that were set earlier in the line.\n let pendingSGR = '';\n\n while (i < s.length && col < end) {\n // ANSI escape: pass through if we're in the slice\n if (s[i] === '\\x1b' && s[i + 1] === '[') {\n const seqLen = ansiLen(s, i);\n if (seqLen > 0) {\n const seq = s.substring(i, i + seqLen);\n if (col >= start) {\n out += seq;\n // Track if we have open SGR (non-reset)\n hasOpenSGR = seq !== '\\x1b[0m' && seq !== '\\x1b[m';\n } else if (restoreState) {\n // Accumulate ANSI state from before the slice\n if (seq === '\\x1b[0m' || seq === '\\x1b[m') {\n pendingSGR = '';\n } else {\n pendingSGR += seq;\n }\n }\n i += seqLen;\n continue;\n }\n }\n\n const cp = s.codePointAt(i)!;\n const ch = String.fromCodePoint(cp);\n const chWidth = cp < 128 ? 1 : stringWidth(ch);\n\n if (col >= start) {\n inSlice = true;\n // Don't emit char that would overflow end\n if (col + chWidth > end) break;\n out += ch;\n }\n\n col += chWidth;\n i += ch.length;\n }\n\n // Close any open SGR\n if (inSlice && hasOpenSGR) {\n out += '\\x1b[0m';\n }\n\n // Prepend accumulated state so suffix inherits the correct colors\n if (restoreState && pendingSGR) {\n out = pendingSGR + out;\n }\n\n return out;\n}\n","import { readFileSync } from 'node:fs';\nimport { globalConfigPath, projectConfigPath } from './paths.js';\nimport type { StatusBarConfig } from './types.js';\n\nexport type EffortLevel = 'low' | 'medium' | 'high' | 'xhigh' | 'max';\n\nexport interface NotificationConfig {\n enabled?: boolean;\n sound?: string;\n}\n\nexport interface RequiredPlugin {\n name: string;\n marketplace: string;\n}\n\nexport interface UploadConfig {\n /** Worker base URL, e.g. https://sisyphus-upload-proxy.rhyneer-silas.workers.dev */\n url: string;\n /** Bearer token, format `sisyphus_pat_<43-char-base64url>` */\n token: string;\n}\n\nexport interface Config {\n model?: string;\n tmuxSession?: string;\n orchestratorPrompt?: string;\n pollIntervalMs?: number;\n autoUpdate?: boolean;\n orchestratorEffort?: EffortLevel;\n agentEffort?: EffortLevel;\n editor?: string;\n repos?: string[];\n notifications?: NotificationConfig;\n companionPopup?: boolean;\n requiredPlugins?: RequiredPlugin[];\n statusBar?: StatusBarConfig;\n upload?: UploadConfig;\n}\n\nconst DEFAULT_CONFIG: Config = {\n model: 'claude-opus-4-7[1m]',\n pollIntervalMs: 5000,\n orchestratorEffort: 'xhigh',\n agentEffort: 'medium',\n notifications: {\n enabled: true,\n sound: '/System/Library/Sounds/Hero.aiff',\n },\n companionPopup: true,\n requiredPlugins: [\n { name: 'devcore', marketplace: 'crouton-kit' },\n ],\n};\n\nfunction readJsonFile(filePath: string): Partial<Config> {\n try {\n const content = readFileSync(filePath, 'utf-8');\n return JSON.parse(content) as Partial<Config>;\n } catch {\n return {};\n }\n}\n\nexport function loadConfig(cwd: string): Config {\n const globalConfig = readJsonFile(globalConfigPath());\n const projectConfig = readJsonFile(projectConfigPath(cwd));\n if (projectConfig.upload !== undefined) {\n console.warn(\n 'ignoring `upload` block from project-local .sisyphus/config.json — only the global config can set upload credentials',\n );\n delete projectConfig.upload;\n }\n const merged: Config = { ...DEFAULT_CONFIG, ...globalConfig, ...projectConfig };\n if (globalConfig.statusBar || projectConfig.statusBar) {\n merged.statusBar = {\n ...merged.statusBar,\n ...globalConfig.statusBar,\n ...projectConfig.statusBar,\n colors: {\n ...merged.statusBar?.colors,\n ...globalConfig.statusBar?.colors,\n ...projectConfig.statusBar?.colors,\n },\n segments: {\n ...merged.statusBar?.segments,\n ...globalConfig.statusBar?.segments,\n ...projectConfig.statusBar?.segments,\n },\n };\n }\n return merged;\n}\n","import { appendFileSync, mkdirSync, writeFileSync, renameSync, readdirSync, readFileSync, rmSync, statSync } from 'node:fs';\nimport { randomUUID } from 'node:crypto';\nimport { dirname, join } from 'node:path';\nimport { historySessionDir, historyEventsPath, historySessionSummaryPath, historyBaseDir } from '../shared/paths.js';\nimport type { HistoryEventType, SessionSummary } from '../shared/history-types.js';\nimport type { MoodSignals } from '../shared/companion-types.js';\nimport type { Session } from '../shared/types.js';\n\n// Track which session dirs have been created this process to skip redundant mkdirSync\nconst knownDirs = new Set<string>();\n\nfunction ensureDir(sessionId: string): void {\n if (knownDirs.has(sessionId)) return;\n mkdirSync(historySessionDir(sessionId), { recursive: true });\n knownDirs.add(sessionId);\n}\n\nexport function emitHistoryEvent(sessionId: string, event: HistoryEventType, data: Record<string, unknown>): void {\n try {\n ensureDir(sessionId);\n const line = JSON.stringify({ ts: new Date().toISOString(), event, sessionId, data }) + '\\n';\n appendFileSync(historyEventsPath(sessionId), line, 'utf-8');\n } catch {\n // Fire-and-forget — history is best-effort\n }\n}\n\nexport function writeSessionSummary(\n session: Session,\n extra?: { achievements?: string[]; xpGained?: number; finalSignals?: MoodSignals; sentiment?: string },\n): void {\n try {\n ensureDir(session.id);\n\n const summary: SessionSummary = {\n sessionId: session.id,\n name: session.name ?? null,\n task: session.task,\n cwd: session.cwd,\n model: session.model ?? null,\n status: session.status,\n startedAt: session.createdAt,\n completedAt: session.completedAt ?? new Date().toISOString(),\n activeMs: session.activeMs,\n wallClockMs: session.wallClockMs ?? null,\n userBlockedMs: session.userBlockedMs ?? 0,\n agentCount: session.agents.length,\n crashCount: session.agents.filter(a => a.status === 'crashed').length,\n lostCount: session.agents.filter(a => a.status === 'lost').length,\n killedAgentCount: session.agents.filter(a => a.status === 'killed').length,\n rollbackCount: session.rollbackCount ?? 0,\n efficiency: session.wallClockMs\n ? Math.max(0, session.activeMs - (session.userBlockedMs ?? 0))\n / Math.max(1, session.wallClockMs - (session.userBlockedMs ?? 0))\n : null,\n cycleCount: session.orchestratorCycles.length,\n context: session.context ?? null,\n completionReport: session.completionReport ?? null,\n agents: session.agents.map(a => ({\n id: a.id,\n name: a.name,\n nickname: a.nickname ?? null,\n agentType: a.agentType,\n status: a.status,\n activeMs: a.activeMs,\n userBlockedMs: a.userBlockedMs ?? 0,\n spawnedAt: a.spawnedAt,\n completedAt: a.completedAt,\n restartCount: a.restartCount ?? 0,\n })),\n cycles: session.orchestratorCycles.map(c => ({\n cycle: c.cycle,\n mode: c.mode ?? null,\n agentsSpawned: c.agentsSpawned.length,\n activeMs: c.activeMs,\n userBlockedMs: c.userBlockedMs ?? 0,\n startedAt: c.timestamp,\n completedAt: c.completedAt ?? null,\n })),\n messages: session.messages.map(m => ({\n id: m.id,\n source: typeof m.source === 'string' ? m.source : m.source.type,\n content: m.content,\n timestamp: m.timestamp,\n })),\n finalMoodSignals: extra?.finalSignals ?? null,\n achievements: extra?.achievements ?? [],\n xpGained: extra?.xpGained ?? 0,\n sentiment: extra?.sentiment ?? null,\n };\n\n const filePath = historySessionSummaryPath(session.id);\n const tmp = join(dirname(filePath), `.session-${randomUUID()}.tmp`);\n writeFileSync(tmp, JSON.stringify(summary, null, 2), 'utf-8');\n renameSync(tmp, filePath);\n } catch (err) {\n console.error(`[history] Failed to write session summary for ${session.id}:`, err);\n }\n}\n\n/**\n * Load the most recent non-null sentiments from session history.\n * Scans at most `scanLimit` dirs (by mtime, newest first) to avoid reading everything.\n */\nexport function getRecentSentiments(count = 5, scanLimit = 30, overrideBaseDir?: string): Array<{ sentiment: string; task: string; completedAt: string }> {\n try {\n const base = overrideBaseDir ?? historyBaseDir();\n let entries: string[];\n try {\n entries = readdirSync(base);\n } catch {\n return [];\n }\n\n // Sort dirs by mtime descending (newest first)\n const withMtime: Array<{ name: string; mtime: number }> = [];\n for (const name of entries) {\n try {\n const st = statSync(join(base, name));\n if (st.isDirectory()) withMtime.push({ name, mtime: st.mtimeMs });\n } catch { continue; }\n }\n withMtime.sort((a, b) => b.mtime - a.mtime);\n\n const results: Array<{ sentiment: string; task: string; completedAt: string }> = [];\n const limit = Math.min(withMtime.length, scanLimit);\n for (let i = 0; i < limit && results.length < count; i++) {\n try {\n const raw = readFileSync(join(base, withMtime[i].name, 'session.json'), 'utf-8');\n const summary = JSON.parse(raw) as SessionSummary;\n if (summary.sentiment && summary.completedAt) {\n results.push({\n sentiment: summary.sentiment,\n task: summary.task.slice(0, 100),\n completedAt: summary.completedAt,\n });\n }\n } catch { continue; }\n }\n return results;\n } catch {\n return [];\n }\n}\n\nconst PRUNE_KEEP_COUNT = 200;\nconst PRUNE_KEEP_DAYS = 90;\n\nexport function pruneHistory(): void {\n try {\n const base = historyBaseDir();\n let entries: string[];\n try {\n entries = readdirSync(base);\n } catch {\n return; // No history dir yet\n }\n\n // Collect session dirs with their timestamps\n const sessions: Array<{ dir: string; startedAt: number }> = [];\n for (const name of entries) {\n const dir = join(base, name);\n try {\n const summaryPath = join(dir, 'session.json');\n const raw = readFileSync(summaryPath, 'utf-8');\n const summary = JSON.parse(raw) as { startedAt?: string };\n sessions.push({ dir, startedAt: new Date(summary.startedAt ?? 0).getTime() });\n } catch {\n // No session.json — try first line of events.jsonl for stable creation timestamp\n try {\n const eventsPath = join(dir, 'events.jsonl');\n const firstLine = readFileSync(eventsPath, 'utf-8').split('\\n')[0];\n const firstEvent = JSON.parse(firstLine) as { ts?: string };\n sessions.push({ dir, startedAt: new Date(firstEvent.ts ?? 0).getTime() });\n } catch {\n // Fall back to dir mtime only if events.jsonl is unreadable\n try {\n const st = statSync(dir);\n sessions.push({ dir, startedAt: st.mtimeMs });\n } catch {\n continue;\n }\n }\n }\n }\n\n if (sessions.length <= PRUNE_KEEP_COUNT) return;\n\n // Sort newest first\n sessions.sort((a, b) => b.startedAt - a.startedAt);\n\n const cutoff = Date.now() - PRUNE_KEEP_DAYS * 24 * 60 * 60 * 1000;\n for (let i = PRUNE_KEEP_COUNT; i < sessions.length; i++) {\n if (sessions[i].startedAt < cutoff) {\n rmSync(sessions[i].dir, { recursive: true, force: true });\n }\n }\n } catch {\n // Pruning is best-effort\n }\n}\n","import { randomUUID } from 'node:crypto';\nimport { dirname, join } from 'node:path';\nimport { renameSync, writeFileSync } from 'node:fs';\n\nexport function atomicWrite(filePath: string, data: string): void {\n const dir = dirname(filePath);\n const tmpPath = join(dir, `.atomic.${randomUUID()}.tmp`);\n writeFileSync(tmpPath, data, 'utf-8');\n renameSync(tmpPath, filePath);\n}\n\nconst locks = new Map<string, Promise<void>>();\n\nexport async function withLock<T>(key: string, fn: () => T): Promise<T> {\n const prev = locks.get(key) ?? Promise.resolve();\n let resolve!: () => void;\n const next = new Promise<void>(r => { resolve = r; });\n locks.set(key, next);\n await prev;\n try {\n return fn();\n } finally {\n resolve();\n if (locks.get(key) === next) {\n locks.delete(key);\n }\n }\n}\n","import { existsSync, readFileSync, writeFileSync } from 'node:fs';\nimport { join } from 'node:path';\n\nconst SISYPHUS_ENTRIES = ['.sisyphus'];\n\nconst SISYPHUS_HEADER = '# Sisyphus';\n\n/**\n * Ensures the project .gitignore includes entries for sisyphus generated artifacts.\n * Only runs in git repos. Creates .gitignore if missing. Skips entries already present.\n */\nexport function ensureSisyphusGitignore(cwd: string): void {\n // Only act in git repos\n if (!existsSync(join(cwd, '.git'))) return;\n\n const gitignorePath = join(cwd, '.gitignore');\n let content = '';\n\n if (existsSync(gitignorePath)) {\n content = readFileSync(gitignorePath, 'utf-8');\n }\n\n const lines = content.split('\\n');\n const missing = SISYPHUS_ENTRIES.filter(entry => !lines.some(line => line.trim() === entry));\n\n if (missing.length === 0) return;\n\n const block = [SISYPHUS_HEADER, ...missing].join('\\n');\n const separator = content.length > 0 && !content.endsWith('\\n\\n')\n ? content.endsWith('\\n') ? '\\n' : '\\n\\n'\n : '';\n\n writeFileSync(gitignorePath, content + separator + block + '\\n', 'utf-8');\n}\n","export type Provider = 'anthropic' | 'openai';\n\nexport interface StatusBarColors {\n processing?: string;\n stopped?: string;\n idle?: string;\n activeBg?: string;\n activeText?: string;\n inactiveText?: string;\n}\n\nexport interface SegmentConfig {\n bg?: string;\n activeBg?: string;\n [key: string]: unknown;\n}\n\nexport interface StatusBarConfig {\n enabled?: boolean;\n colors?: StatusBarColors;\n left?: string[];\n right?: string[];\n segments?: Record<string, SegmentConfig>;\n}\n\nexport type SessionStatus = 'active' | 'paused' | 'completed';\n\nexport type UploadStatus = 'pending' | 'uploaded' | 'failed';\n\n/**\n * Records intent to move a session to a cloud box (or pause for reclaim).\n * - `target` omitted ⇒ quiesce-only (used by reclaim's box-side pause step).\n * - `target` present ⇒ at next quiesce, daemon syncs state + working tree to\n * the box and respawns the orchestrator there via `sis resume`.\n */\nexport interface HandoffState {\n /** Cloud destination. Omitted means \"pause at next quiesce; do not push.\" */\n target?: { provider: string; repo: string };\n /** ISO timestamp when the RPC was received. */\n queuedAt: string;\n /** Set after a successful push to the box. */\n sentAt?: string;\n /** Set after a successful pull back to local. */\n reclaimedAt?: string;\n /** True when --force was passed; daemon interrupts in-flight work. */\n force: boolean;\n /**\n * Resume message injected on the box. Computed at queue time for --force\n * (since we know which agents/orchestrator are being interrupted), empty\n * for natural quiesce.\n */\n message?: string;\n /** Most recent failure during push; set so the user can retry from `sis list`. */\n lastError?: string;\n}\n\nexport type MessageSource =\n | { type: 'agent'; agentId: string }\n | { type: 'user' }\n | { type: 'system'; detail?: string };\n\nexport interface Message {\n id: string;\n source: MessageSource;\n content: string;\n summary: string;\n filePath?: string;\n timestamp: string;\n}\n\nexport type AgentStatus = 'running' | 'completed' | 'killed' | 'crashed' | 'lost';\n\nexport interface AgentReport {\n type: 'update' | 'final';\n filePath: string;\n summary: string;\n timestamp: string;\n}\n\nexport interface Session {\n id: string;\n name?: string;\n task: string;\n context?: string;\n cwd: string;\n status: SessionStatus;\n createdAt: string;\n completedAt?: string;\n activeMs: number;\n /** Set true when the orchestrator pane vanished unexpectedly or daemon-startup found a stuck session. */\n orphaned?: boolean;\n /** Reason string passed to markSessionOrphan — mirrors agent.killedReason. */\n orphanReason?: string;\n /** Cumulative time blocked on `sis ask` (blocking asks only). Subtracted from wallClockMs to compute efficiency. */\n userBlockedMs?: number;\n agents: Agent[];\n orchestratorCycles: OrchestratorCycle[];\n messages: Message[];\n completionReport?: string;\n parentSessionId?: string;\n tmuxSessionName?: string;\n tmuxSessionId?: string; // tmux $N session ID — stable across renames, exact-match targeting\n tmuxWindowId?: string;\n model?: string;\n wallClockMs?: number;\n startHour?: number;\n startDayOfWeek?: number;\n launchConfig?: { model?: string; context?: string; orchestratorPrompt?: string; };\n /** Cycles already credited to companion stats (prevents double-counting on continue→re-complete) */\n companionCreditedCycles?: number;\n /** activeMs already credited to companion stats */\n companionCreditedActiveMs?: number;\n /** Strength already credited to companion stats */\n companionCreditedStrength?: number;\n rollbackCount?: number;\n resumeCount?: number;\n continueCount?: number;\n companionCreditedWisdom?: number;\n /** Lifecycle of the upload to the Worker proxy. `undefined` means upload was never attempted. */\n uploadStatus?: UploadStatus;\n /** R2 storage key returned by the Worker, e.g. `users/silas/<sessionId>.zip`. Bucket is private; this is NOT a fetch-able URL. */\n uploadKey?: string;\n /** Clean error message extracted from the Worker's JSON response when `uploadStatus === 'failed'`. */\n uploadError?: string;\n /** Daemon-local `new Date().toISOString()` at the moment the success was persisted. */\n uploadCompletedAt?: string;\n effort?: 'low' | 'medium' | 'high' | 'xhigh';\n /**\n * When true, the daemon auto-resolves every new ask in this session by\n * picking the first option of each interaction. Toggleable per-session\n * from the dashboard via the `D` key.\n */\n dangerousMode?: boolean;\n /**\n * Cloud-handoff lifecycle marker. Set by `sis cloud handoff` (push to box)\n * or `sis admin quiesce` (pause-only). Presence with `sentAt` unset blocks\n * local respawn at the next quiesce point; presence with `sentAt` set means\n * the session lives on the box and can be `sis cloud reclaim`-ed.\n */\n handoff?: HandoffState;\n}\n\nexport interface StatusDigest {\n recentWork: string;\n unusualEvents: string[];\n currentActivity: string;\n whatsNext: string;\n effort?: string;\n}\n\nexport interface Agent {\n id: string;\n name: string;\n nickname?: string;\n agentType: string;\n provider?: Provider;\n claudeSessionId?: string;\n color: string;\n instruction: string;\n status: AgentStatus;\n spawnedAt: string;\n completedAt: string | null;\n activeMs: number;\n /** Cumulative time this agent was blocked on its own `sis ask` calls (blocking only). Subset of activeMs. */\n userBlockedMs?: number;\n reports: AgentReport[];\n paneId: string;\n repo: string;\n killedReason?: string;\n restartCount?: number;\n originalSpawnedAt?: string;\n resumeEnv?: string;\n resumeArgs?: string;\n /** Set true when the agent's pane vanished unexpectedly or pid+lstart no longer match. Orthogonal to status. */\n orphaned?: boolean;\n /** Captured at spawn time by `setupAgentPane` → first `tmux display-message #{pane_pid}`. */\n pid?: number;\n /** `ps -o lstart=` output captured at spawn. Compared during pid-sweep to detect PID recycling. */\n pidLstart?: string;\n /** Set true when `sis agent await` consumed this agent's report inline. Suppresses it from the next-cycle orchestrator prompt; one-way. */\n consumedInline?: boolean;\n}\n\nexport interface OrchestratorCycle {\n cycle: number;\n timestamp: string;\n completedAt?: string;\n activeMs: number;\n /** Cumulative time blocked on `sis ask` during this cycle (blocking asks only). */\n userBlockedMs?: number;\n interCycleGapMs?: number;\n agentsSpawned: string[];\n paneId?: string;\n claudeSessionId?: string;\n nextPrompt?: string;\n mode?: string;\n resumeEnv?: string;\n resumeArgs?: string;\n}\n\n// ── sisyphus ask: v2 interaction / deck types (mirror humanloop's published shapes) ──\n\nexport type InteractionKind = 'notify' | 'validation' | 'decision' | 'context' | 'error';\n\nexport interface InteractionOption {\n id: string;\n label: string;\n description?: string;\n shortcut?: string;\n}\n\nexport interface Interaction {\n id: string;\n title: string;\n subtitle?: string;\n body?: string;\n bodyPath?: string;\n options: InteractionOption[];\n allowFreetext?: boolean;\n freetextLabel?: string;\n kind?: InteractionKind;\n}\n\nexport interface ModeChainEntry {\n mode: string;\n /** Cycles spent in this segment. Absent for the trailing (current) entry. */\n cycles?: number;\n /** Active ms accumulated in this segment. Absent for the trailing entry. */\n activeMs?: number;\n}\n\nexport interface DeckSource {\n sessionName?: string;\n askedBy?: string;\n blockedSince?: string;\n /** For orchestrator mode-transition notify decks: ordered chain of modes visited. Trailing entry is the current mode. */\n modeChain?: ModeChainEntry[];\n}\n\nexport interface Deck {\n title?: string;\n source?: DeckSource;\n interactions: Interaction[];\n}\n\nexport interface InteractionResponse {\n id: string;\n selectedOptionId?: string;\n freetext?: string;\n}\n\nexport interface AskOutput {\n responses: InteractionResponse[];\n completedAt: string;\n}\n\nexport interface VisualBlock {\n questionId: string;\n content: string;\n status: 'loading' | 'ready' | 'error';\n}\n\nexport const ORCHESTRATOR_ASKED_BY = 'orchestrator' as const;\n\nexport type AskStatus = 'pending' | 'in-progress' | 'answered' | 'not-found';\n\nexport interface AskMeta {\n askId: string;\n askedBy: string;\n askedAt: string;\n status: AskStatus;\n blocking: boolean;\n pid?: number;\n startedAt?: string;\n completedAt?: string;\n orphaned?: boolean;\n /** ISO timestamp set by the heartbeat scanner when a stale-question notify ask is emitted; dedup key. */\n heartbeatNotifiedAt?: string;\n claudeSessionId?: string;\n cwd: string;\n title?: string;\n subtitle?: string;\n kind?: InteractionKind;\n /** Set on system-emitted error-kind asks; carries the takeover-dispatch context. */\n orphanTarget?: { kind: 'agent'; agentId: string; paneId?: string } | { kind: 'orchestrator' };\n /** Set on orchestrator mode-transition notify asks; aggregation key for rolling mode-change notifications. */\n modeTransition?: true;\n}\n","import { copyFileSync, cpSync, existsSync, mkdirSync, readFileSync, readdirSync, rmSync, statSync, writeFileSync } from 'node:fs';\nimport { join } from 'node:path';\nimport { atomicWrite, withLock } from './lib/atomic.js';\nimport { contextDir, goalPath, initialPromptPath, legacyLogsPath, logsDir, reportsDir, roadmapPath, promptsDir, sessionDir, snapshotDir, snapshotsDir, statePath, strategyPath } from '../shared/paths.js';\nimport { ensureSisyphusGitignore } from '../shared/gitignore.js';\nimport type { Agent, AgentReport, AgentStatus, Message, OrchestratorCycle, Session, SessionStatus } from '../shared/types.js';\nimport { ORCHESTRATOR_ASKED_BY } from '../shared/types.js';\n\nconst ROADMAP_SEED = `---\ndescription: >\n Living document tracking development phases and outstanding work.\n---\n`;\n\nconst CONTEXT_CLAUDE_MD = `# context/\n\nAgents save exploration findings, architectural notes, and reference material here for use across cycles.\n`;\n\nfunction withSessionLock<T>(sessionId: string, fn: () => T): Promise<T> {\n return withLock(sessionId, fn);\n}\n\nexport function createSession(id: string, task: string, cwd: string, context?: string, name?: string, effort?: 'low' | 'medium' | 'high' | 'xhigh'): Session {\n ensureSisyphusGitignore(cwd);\n\n const dir = sessionDir(cwd, id);\n mkdirSync(dir, { recursive: true });\n mkdirSync(contextDir(cwd, id), { recursive: true });\n mkdirSync(promptsDir(cwd, id), { recursive: true });\n\n writeFileSync(roadmapPath(cwd, id), ROADMAP_SEED, 'utf-8');\n mkdirSync(logsDir(cwd, id), { recursive: true });\n writeFileSync(goalPath(cwd, id), task, 'utf-8');\n writeFileSync(initialPromptPath(cwd, id), task, 'utf-8');\n writeFileSync(join(contextDir(cwd, id), 'CLAUDE.md'), CONTEXT_CLAUDE_MD, 'utf-8');\n if (context) {\n writeFileSync(join(contextDir(cwd, id), 'initial-context.md'), context, 'utf-8');\n }\n\n const createdAt = new Date().toISOString();\n const created = new Date(createdAt);\n const session: Session = {\n id,\n ...(name ? { name } : {}),\n task,\n ...(context ? { context } : {}),\n cwd,\n status: 'active',\n createdAt,\n activeMs: 0,\n userBlockedMs: 0,\n agents: [],\n orchestratorCycles: [],\n messages: [],\n startHour: created.getHours(),\n startDayOfWeek: created.getDay(),\n orphaned: false,\n ...(effort ? { effort } : {}),\n };\n\n atomicWrite(statePath(cwd, id), JSON.stringify(session, null, 2));\n return session;\n}\n\nexport function getSession(cwd: string, sessionId: string): Session {\n const content = readFileSync(statePath(cwd, sessionId), 'utf-8');\n const session = JSON.parse(content) as Session;\n // Normalize fields from pre-existing sessions that may lack newer properties\n if (session.activeMs == null) session.activeMs = 0;\n if (session.userBlockedMs == null) session.userBlockedMs = 0;\n for (const agent of session.agents) {\n if (!agent.repo) agent.repo = '.';\n if (agent.activeMs == null) agent.activeMs = 0;\n if (agent.orphaned == null) agent.orphaned = false;\n // pid / pidLstart left undefined when absent — their absence signals \"not yet captured\"\n }\n if (session.orphaned == null) session.orphaned = false;\n // session.effort is intentionally not defaulted here — absence means \"not explicitly set\"\n // and consumers (agent.ts, orchestrator.ts, status.ts) fall back to 'high' at read time.\n // orphanReason is only set alongside orphaned=true; absent on healthy sessions and old state files\n for (const cycle of session.orchestratorCycles) {\n if (cycle.activeMs == null) cycle.activeMs = 0;\n if (cycle.userBlockedMs == null) cycle.userBlockedMs = 0;\n }\n return session;\n}\n\nfunction saveSession(session: Session): void {\n atomicWrite(statePath(session.cwd, session.id), JSON.stringify(session, null, 2));\n}\n\n/**\n * Returns true when the session has dangerousMode enabled. Safe to call before\n * the state file exists (e.g. mid-create) — returns false on any read error.\n */\nexport function isSessionDangerous(cwd: string, sessionId: string): boolean {\n try {\n return getSession(cwd, sessionId).dangerousMode === true;\n } catch {\n return false;\n }\n}\n\nexport async function addAgent(cwd: string, sessionId: string, agent: Agent): Promise<void> {\n return withSessionLock(sessionId, () => {\n const session = getSession(cwd, sessionId);\n session.agents.push(agent);\n saveSession(session);\n });\n}\n\nexport async function updateAgent(cwd: string, sessionId: string, agentId: string, updates: Partial<Agent>): Promise<void> {\n return withSessionLock(sessionId, () => {\n const session = getSession(cwd, sessionId);\n const agent = session.agents.slice().reverse().find((a: Agent) => a.id === agentId);\n if (!agent) throw new Error(`Agent ${agentId} not found in session ${sessionId}`);\n Object.assign(agent, updates);\n saveSession(session);\n });\n}\n\nexport async function markAgentOrphan(\n cwd: string,\n sessionId: string,\n agentId: string,\n opts: { reason: string; status?: AgentStatus; activeMs?: number },\n): Promise<void> {\n return withSessionLock(sessionId, () => {\n const session = getSession(cwd, sessionId);\n const agent = session.agents.slice().reverse().find((a: Agent) => a.id === agentId);\n if (!agent) throw new Error(`Agent ${agentId} not found in session ${sessionId}`);\n agent.orphaned = true;\n agent.status = opts.status !== undefined ? opts.status : 'lost';\n agent.killedReason = opts.reason;\n agent.completedAt = new Date().toISOString();\n if (opts.activeMs !== undefined) agent.activeMs = opts.activeMs;\n delete agent.pid;\n delete agent.pidLstart;\n saveSession(session);\n });\n}\n\nexport async function markSessionOrphan(\n cwd: string,\n sessionId: string,\n opts: { reason: string },\n): Promise<void> {\n return withSessionLock(sessionId, () => {\n const session = getSession(cwd, sessionId);\n session.orphaned = true;\n session.orphanReason = opts.reason;\n saveSession(session);\n });\n}\n\nexport async function clearSessionOrphan(cwd: string, sessionId: string): Promise<void> {\n return withSessionLock(sessionId, () => {\n const session = getSession(cwd, sessionId);\n if (!session.orphaned && session.orphanReason == null) return;\n session.orphaned = false;\n delete session.orphanReason;\n saveSession(session);\n });\n}\n\nexport async function clearAgentPidInfo(\n cwd: string,\n sessionId: string,\n agentId: string,\n): Promise<void> {\n return withSessionLock(sessionId, () => {\n const session = getSession(cwd, sessionId);\n const agent = session.agents.slice().reverse().find((a: Agent) => a.id === agentId);\n if (!agent) return;\n delete agent.pid;\n delete agent.pidLstart;\n saveSession(session);\n });\n}\n\nexport async function setAgentPid(\n cwd: string,\n sessionId: string,\n agentId: string,\n pid: number,\n pidLstart: string,\n): Promise<void> {\n return withSessionLock(sessionId, () => {\n const session = getSession(cwd, sessionId);\n const agent = session.agents.slice().reverse().find((a: Agent) => a.id === agentId);\n if (!agent) return;\n agent.pid = pid;\n agent.pidLstart = pidLstart;\n saveSession(session);\n });\n}\n\nexport async function setAgentConsumedInline(cwd: string, sessionId: string, agentId: string): Promise<void> {\n return withSessionLock(sessionId, () => {\n const session = getSession(cwd, sessionId);\n const agent = session.agents.slice().reverse().find((a: Agent) => a.id === agentId);\n if (!agent) throw new Error(`Agent ${agentId} not found in session ${sessionId}`);\n if (agent.consumedInline) return;\n agent.consumedInline = true;\n saveSession(session);\n });\n}\n\nexport async function addOrchestratorCycle(cwd: string, sessionId: string, cycle: OrchestratorCycle): Promise<void> {\n return withSessionLock(sessionId, () => {\n const session = getSession(cwd, sessionId);\n session.orchestratorCycles.push(cycle);\n saveSession(session);\n });\n}\n\nexport async function updateSessionStatus(cwd: string, sessionId: string, status: SessionStatus, completionReport?: string): Promise<void> {\n return withSessionLock(sessionId, () => {\n const session = getSession(cwd, sessionId);\n session.status = status;\n if (completionReport !== undefined) {\n session.completionReport = completionReport;\n }\n saveSession(session);\n });\n}\n\nexport async function appendAgentToLastCycle(cwd: string, sessionId: string, agentId: string): Promise<void> {\n return withSessionLock(sessionId, () => {\n const session = getSession(cwd, sessionId);\n const cycles = session.orchestratorCycles;\n if (cycles.length === 0) return;\n cycles[cycles.length - 1]!.agentsSpawned.push(agentId);\n saveSession(session);\n });\n}\n\nexport async function completeSession(cwd: string, sessionId: string, report: string): Promise<void> {\n return withSessionLock(sessionId, () => {\n const session = getSession(cwd, sessionId);\n session.status = 'completed';\n session.completedAt = new Date().toISOString();\n session.completionReport = report;\n saveSession(session);\n });\n}\n\nexport async function continueSession(cwd: string, sessionId: string): Promise<void> {\n return withSessionLock(sessionId, () => {\n const session = getSession(cwd, sessionId);\n if (session.status !== 'completed') {\n throw new Error(`Session ${sessionId} is not completed (status: ${session.status})`);\n }\n session.status = 'active';\n session.completedAt = undefined;\n session.completionReport = undefined;\n const cycles = session.orchestratorCycles;\n if (cycles.length > 0) {\n cycles[cycles.length - 1]!.completedAt = undefined;\n }\n saveSession(session);\n writeFileSync(roadmapPath(cwd, sessionId), '', 'utf-8');\n });\n}\n\nexport async function appendAgentReport(cwd: string, sessionId: string, agentId: string, entry: AgentReport): Promise<void> {\n return withSessionLock(sessionId, () => {\n const session = getSession(cwd, sessionId);\n const agent = session.agents.slice().reverse().find((a: Agent) => a.id === agentId);\n if (!agent) throw new Error(`Agent ${agentId} not found in session ${sessionId}`);\n agent.reports.push(entry);\n saveSession(session);\n });\n}\n\nexport async function updateReportSummary(\n cwd: string,\n sessionId: string,\n agentId: string,\n filePath: string,\n summary: string,\n): Promise<void> {\n return withSessionLock(sessionId, () => {\n const session = getSession(cwd, sessionId);\n const agent = session.agents.slice().reverse().find((a: Agent) => a.id === agentId);\n if (!agent) return;\n const report = agent.reports.find((r) => r.filePath === filePath);\n if (report) {\n report.summary = summary;\n saveSession(session);\n }\n });\n}\n\nexport async function updateSessionName(cwd: string, sessionId: string, name: string): Promise<void> {\n return withSessionLock(sessionId, () => {\n const session = getSession(cwd, sessionId);\n session.name = name;\n saveSession(session);\n });\n}\n\nexport async function updateSessionTmux(cwd: string, sessionId: string, tmuxSessionName: string, tmuxWindowId: string, tmuxSessionId?: string): Promise<void> {\n return withSessionLock(sessionId, () => {\n const session = getSession(cwd, sessionId);\n session.tmuxSessionName = tmuxSessionName;\n session.tmuxSessionId = tmuxSessionId;\n session.tmuxWindowId = tmuxWindowId;\n saveSession(session);\n });\n}\n\nexport async function updateSession(cwd: string, sessionId: string, updates: Partial<Session>): Promise<void> {\n return withSessionLock(sessionId, () => {\n const session = getSession(cwd, sessionId);\n Object.assign(session, updates);\n saveSession(session);\n });\n}\n\nexport async function drainMessages(cwd: string, sessionId: string, count: number): Promise<void> {\n return withSessionLock(sessionId, () => {\n const session = getSession(cwd, sessionId);\n if (!session.messages || count <= 0) return;\n session.messages = session.messages.slice(count);\n saveSession(session);\n });\n}\n\nexport async function appendMessage(cwd: string, sessionId: string, message: Message): Promise<void> {\n return withSessionLock(sessionId, () => {\n const session = getSession(cwd, sessionId);\n if (!session.messages) session.messages = [];\n session.messages.push(message);\n saveSession(session);\n });\n}\n\nexport async function updateTask(cwd: string, sessionId: string, task: string): Promise<void> {\n return withSessionLock(sessionId, () => {\n const session = getSession(cwd, sessionId);\n session.task = task;\n saveSession(session);\n writeFileSync(goalPath(cwd, sessionId), task, 'utf-8');\n });\n}\n\nexport async function completeOrchestratorCycle(cwd: string, sessionId: string, nextPrompt?: string, mode?: string, activeMs?: number): Promise<void> {\n return withSessionLock(sessionId, () => {\n const session = getSession(cwd, sessionId);\n const cycles = session.orchestratorCycles;\n if (cycles.length === 0) return;\n const cycle = cycles[cycles.length - 1]!;\n if (cycle.completedAt) return;\n cycle.completedAt = new Date().toISOString();\n if (nextPrompt) cycle.nextPrompt = nextPrompt;\n if (mode) cycle.mode = mode;\n if (activeMs != null) cycle.activeMs += activeMs;\n saveSession(session);\n });\n}\n\nexport async function incrementUserBlockedMs(\n cwd: string,\n sessionId: string,\n deltaMs: number,\n askedAt?: string,\n askedBy?: string,\n): Promise<void> {\n if (deltaMs <= 0) return;\n return withSessionLock(sessionId, () => {\n const session = getSession(cwd, sessionId);\n session.userBlockedMs = (session.userBlockedMs ?? 0) + deltaMs;\n if (askedAt) {\n const askedAtMs = new Date(askedAt).getTime();\n const cycle = session.orchestratorCycles.find(c => {\n const startMs = new Date(c.timestamp).getTime();\n const endMs = c.completedAt ? new Date(c.completedAt).getTime() : Infinity;\n return startMs <= askedAtMs && askedAtMs < endMs;\n });\n if (cycle) cycle.userBlockedMs = (cycle.userBlockedMs ?? 0) + deltaMs;\n }\n if (askedBy && askedBy !== ORCHESTRATOR_ASKED_BY) {\n const agent = session.agents.slice().reverse().find(a => a.id === askedBy);\n if (agent) agent.userBlockedMs = (agent.userBlockedMs ?? 0) + deltaMs;\n }\n saveSession(session);\n });\n}\n\nexport async function incrementActiveTime(\n cwd: string,\n sessionId: string,\n sessionDelta: number,\n agentDeltas: Map<string, number>,\n cycleDeltas: Map<number, number>,\n): Promise<void> {\n return withSessionLock(sessionId, () => {\n const session = getSession(cwd, sessionId);\n session.activeMs += sessionDelta;\n for (const [agentId, delta] of agentDeltas) {\n const agent = session.agents.slice().reverse().find(a => a.id === agentId);\n if (agent) agent.activeMs += delta;\n }\n for (const [cycleNum, delta] of cycleDeltas) {\n const cycle = session.orchestratorCycles.find(c => c.cycle === cycleNum);\n if (cycle) cycle.activeMs += delta;\n }\n saveSession(session);\n });\n}\n\nexport function createSnapshot(cwd: string, sessionId: string, cycleNumber: number): void {\n const dir = snapshotDir(cwd, sessionId, cycleNumber);\n mkdirSync(dir, { recursive: true });\n\n copyFileSync(statePath(cwd, sessionId), join(dir, 'state.json'));\n\n const roadmap = roadmapPath(cwd, sessionId);\n if (existsSync(roadmap)) copyFileSync(roadmap, join(dir, 'roadmap.md'));\n\n const strategy = strategyPath(cwd, sessionId);\n if (existsSync(strategy)) copyFileSync(strategy, join(dir, 'strategy.md'));\n\n const ld = logsDir(cwd, sessionId);\n if (existsSync(ld)) cpSync(ld, join(dir, 'logs'), { recursive: true });\n const legacyLogs = legacyLogsPath(cwd, sessionId);\n if (existsSync(legacyLogs)) copyFileSync(legacyLogs, join(dir, 'logs.md'));\n}\n\nexport async function restoreSnapshot(cwd: string, sessionId: string, toCycle: number): Promise<void> {\n return withSessionLock(sessionId, () => {\n const dir = snapshotDir(cwd, sessionId, toCycle);\n if (!existsSync(dir)) throw new Error(`No snapshot found for cycle ${toCycle}`);\n\n // Restore state.json atomically\n const snapshotState = readFileSync(join(dir, 'state.json'), 'utf-8');\n const session = JSON.parse(snapshotState) as Session;\n session.status = 'paused';\n session.completedAt = undefined;\n session.completionReport = undefined;\n session.tmuxSessionName = undefined;\n session.tmuxSessionId = undefined;\n session.tmuxWindowId = undefined;\n atomicWrite(statePath(cwd, sessionId), JSON.stringify(session, null, 2));\n\n // Restore roadmap.md, strategy.md, and logs\n const snapshotRoadmap = join(dir, 'roadmap.md');\n if (existsSync(snapshotRoadmap)) copyFileSync(snapshotRoadmap, roadmapPath(cwd, sessionId));\n\n const snapshotStrategy = join(dir, 'strategy.md');\n if (existsSync(snapshotStrategy)) copyFileSync(snapshotStrategy, strategyPath(cwd, sessionId));\n\n const snapshotLogsDir = join(dir, 'logs');\n if (existsSync(snapshotLogsDir)) {\n const currentLogsDir = logsDir(cwd, sessionId);\n if (existsSync(currentLogsDir)) rmSync(currentLogsDir, { recursive: true, force: true });\n cpSync(snapshotLogsDir, currentLogsDir, { recursive: true });\n } else {\n // Legacy fallback: snapshot has logs.md instead of logs/\n const snapshotLogs = join(dir, 'logs.md');\n if (existsSync(snapshotLogs)) copyFileSync(snapshotLogs, legacyLogsPath(cwd, sessionId));\n }\n });\n}\n\nexport function listSnapshots(cwd: string, sessionId: string): number[] {\n const dir = snapshotsDir(cwd, sessionId);\n if (!existsSync(dir)) return [];\n\n return readdirSync(dir, { withFileTypes: true })\n .filter(e => e.isDirectory() && e.name.startsWith('cycle-'))\n .map(e => parseInt(e.name.replace('cycle-', ''), 10))\n .filter(n => !isNaN(n))\n .sort((a, b) => a - b);\n}\n\nexport function deleteSnapshotsAfter(cwd: string, sessionId: string, afterCycle: number): void {\n const dir = snapshotsDir(cwd, sessionId);\n if (!existsSync(dir)) return;\n\n for (const entry of readdirSync(dir, { withFileTypes: true })) {\n if (!entry.isDirectory() || !entry.name.startsWith('cycle-')) continue;\n const num = parseInt(entry.name.replace('cycle-', ''), 10);\n if (!isNaN(num) && num > afterCycle) {\n rmSync(join(dir, entry.name), { recursive: true, force: true });\n }\n }\n}\n\n// --- Session cloning ---\n\nfunction replaceIdInDir(dir: string, sourceId: string, cloneId: string): void {\n if (!existsSync(dir)) return;\n const entries = readdirSync(dir, { recursive: true }) as string[];\n for (const rel of entries) {\n const fullPath = join(dir, rel);\n if (!statSync(fullPath).isFile()) continue;\n const buf = readFileSync(fullPath);\n // Skip binary files (null byte in first 8KB)\n const sample = buf.subarray(0, 8192);\n if (sample.includes(0)) continue;\n const text = buf.toString('utf-8');\n if (text.includes(sourceId)) {\n writeFileSync(fullPath, text.replaceAll(sourceId, cloneId), 'utf-8');\n }\n }\n}\n\nexport function cloneSessionDir(\n sourceCwd: string,\n sourceId: string,\n cloneId: string,\n goal: string,\n context?: string,\n strategy?: boolean,\n): void {\n const srcDir = sessionDir(sourceCwd, sourceId);\n const dstDir = sessionDir(sourceCwd, cloneId);\n mkdirSync(dstDir, { recursive: true });\n\n // Deep-copy directories\n const dirsToCopy = ['context', 'prompts', 'reports', 'snapshots'] as const;\n for (const sub of dirsToCopy) {\n const src = join(srcDir, sub);\n const dst = join(dstDir, sub);\n if (existsSync(src)) {\n cpSync(src, dst, { recursive: true });\n } else {\n mkdirSync(dst, { recursive: true });\n }\n }\n\n // Conditionally copy strategy.md\n if (strategy) {\n const srcStrategy = strategyPath(sourceCwd, sourceId);\n if (existsSync(srcStrategy)) {\n const text = readFileSync(srcStrategy, 'utf-8');\n writeFileSync(strategyPath(sourceCwd, cloneId), text.replaceAll(sourceId, cloneId), 'utf-8');\n }\n }\n\n // Replace source ID with clone ID in copied directories\n for (const sub of dirsToCopy) {\n replaceIdInDir(join(dstDir, sub), sourceId, cloneId);\n }\n\n // Write fresh files\n writeFileSync(goalPath(sourceCwd, cloneId), goal, 'utf-8');\n writeFileSync(initialPromptPath(sourceCwd, cloneId), goal, 'utf-8');\n writeFileSync(roadmapPath(sourceCwd, cloneId), ROADMAP_SEED, 'utf-8');\n mkdirSync(logsDir(sourceCwd, cloneId), { recursive: true });\n\n // Write context/CLAUDE.md\n writeFileSync(join(contextDir(sourceCwd, cloneId), 'CLAUDE.md'), CONTEXT_CLAUDE_MD, 'utf-8');\n\n // Write initial-context.md if context provided\n if (context) {\n writeFileSync(join(contextDir(sourceCwd, cloneId), 'initial-context.md'), context, 'utf-8');\n }\n}\n\nexport async function createCloneState(\n sourceCwd: string,\n sourceId: string,\n cloneId: string,\n goal: string,\n context?: string,\n configModel?: string,\n configOrchestratorPrompt?: string,\n): Promise<Session> {\n return withSessionLock(cloneId, () => {\n const source = getSession(sourceCwd, sourceId);\n\n const createdAt = new Date().toISOString();\n const created = new Date(createdAt);\n\n // Deep-copy preserved fields\n const agents = structuredClone(source.agents);\n const orchestratorCycles = structuredClone(source.orchestratorCycles);\n const messages = structuredClone(source.messages);\n\n // Normalize running agents to killed\n const now = new Date().toISOString();\n for (const agent of agents) {\n if (agent.status === 'running') {\n agent.status = 'killed';\n agent.completedAt = now;\n agent.killedReason = 'inherited from source session';\n }\n }\n\n // Resolve model and launchConfig with fallback to config\n const model = source.model ?? configModel;\n const launchConfig = source.launchConfig\n ? structuredClone(source.launchConfig)\n : {\n model,\n context,\n orchestratorPrompt: configOrchestratorPrompt,\n };\n\n const clone: Session = {\n id: cloneId,\n task: goal,\n ...(context ? { context } : {}),\n cwd: sourceCwd,\n status: 'active',\n createdAt,\n activeMs: 0,\n agents,\n orchestratorCycles,\n messages,\n startHour: created.getHours(),\n startDayOfWeek: created.getDay(),\n parentSessionId: sourceId,\n ...(model ? { model } : {}),\n launchConfig,\n ...(source.effort != null ? { effort: source.effort } : {}),\n };\n\n atomicWrite(statePath(sourceCwd, cloneId), JSON.stringify(clone, null, 2));\n return clone;\n });\n}\n","export function shellQuote(s: string): string {\n return `'${s.replace(/'/g, \"'\\\\''\")}'`;\n}\n\n/**\n * Quote a path for a remote shell while preserving a leading `~` / `~/` so the\n * remote shell still expands it. Plain `shellQuote('~/foo')` produces\n * `'~/foo'`, and `~` does not expand inside single quotes — the remote `cd`\n * then looks for a literal `~` directory and fails.\n */\nexport function shellQuoteHomePath(path: string): string {\n if (path === '~') return '~';\n if (path.startsWith('~/')) return `~/${shellQuote(path.slice(2))}`;\n return shellQuote(path);\n}\n\n/** Validate that a session ID is a safe UUID-like string (no path traversal). */\nconst SESSION_ID_PATTERN = /^[a-zA-Z0-9_-]+$/;\nexport function validateSessionId(id: string): boolean {\n return SESSION_ID_PATTERN.test(id) && !id.includes('..');\n}\n\n/** Validate that a repo name is a simple directory name (no path components). */\nexport function validateRepoName(repo: string): boolean {\n return !repo.includes('/') && !repo.includes('\\\\') && !repo.includes('..');\n}\n\n/** Escape a string for safe interpolation inside AppleScript double quotes. */\nexport function escapeAppleScript(s: string): string {\n return s.replace(/\\\\/g, '\\\\\\\\').replace(/\"/g, '\\\\\"');\n}\n","import { spawn, execFile, type ChildProcess } from 'node:child_process';\nimport { writeFileSync, mkdirSync, existsSync } from 'node:fs';\nimport { join } from 'node:path';\nimport { homedir } from 'node:os';\nimport { escapeAppleScript } from '../shared/shell.js';\n\n/**\n * Notification urgency.\n * - `urgent` (default): plays sound, banner; for crashes, asks, things needing real attention\n * - `info`: silent passive banner; for status updates the user only needs to acknowledge\n */\nexport type NotificationLevel = 'info' | 'urgent';\n\nexport interface NotificationOptions {\n title: string;\n message: string;\n /** tmux session name to switch to on click */\n tmuxSession?: string;\n level?: NotificationLevel;\n}\n\nconst TMUX_SOCKET = `/tmp/tmux-${process.getuid?.() ?? 0}/default`;\n\nconst SWITCH_SCRIPT = [\n '#!/bin/bash',\n 'SESSION=\"$1\"',\n `TMUX_SOCKET=\"${TMUX_SOCKET}\"`,\n 'TMUX=/opt/homebrew/bin/tmux',\n '',\n '# Find any attached client (user is likely on a different session)',\n 'CLIENT_TTY=$(\"$TMUX\" -S \"$TMUX_SOCKET\" list-clients -F \\'#{client_tty}\\' 2>/dev/null | head -1)',\n '[ -z \"$CLIENT_TTY\" ] && exit 0',\n '',\n '# Switch that client to the target session',\n '\"$TMUX\" -S \"$TMUX_SOCKET\" switch-client -c \"$CLIENT_TTY\" -t \"$SESSION\" 2>/dev/null',\n '\"$TMUX\" -S \"$TMUX_SOCKET\" select-window -t \"$SESSION\" 2>/dev/null',\n '',\n '# Bring iTerm2 to front and select the tab with this client',\n 'TTY_SHORT=$(echo \"$CLIENT_TTY\" | sed \\'s|/dev/||\\')',\n 'osascript -e \"',\n ' tell application \\\\\"iTerm2\\\\\"',\n ' activate',\n ' repeat with w in windows',\n ' tell w',\n ' repeat with t in tabs',\n ' tell t',\n ' repeat with s in sessions',\n ' tell s',\n ' if tty contains \\\\\"$TTY_SHORT\\\\\" then',\n ' select t',\n ' return',\n ' end if',\n ' end tell',\n ' end repeat',\n ' end tell',\n ' end repeat',\n ' end tell',\n ' end repeat',\n ' end tell',\n '\" 2>/dev/null || osascript -e \\'tell application \"iTerm2\" to activate\\' 2>/dev/null',\n '',\n].join('\\n');\n\nfunction ensureSwitchScript(): void {\n const dir = join(homedir(), '.sisyphus');\n const scriptPath = join(dir, 'notify-switch.sh');\n try {\n mkdirSync(dir, { recursive: true });\n writeFileSync(scriptPath, SWITCH_SCRIPT, { mode: 0o755 });\n } catch {\n // Best effort\n }\n}\n\n// Long-lived SisyphusNotify.app process — accepts JSON lines on stdin\nlet notifyProcess: ChildProcess | null = null;\n\nfunction getNotifyBinary(): string {\n return join(homedir(), '.sisyphus', 'SisyphusNotify.app', 'Contents', 'MacOS', 'sisyphus-notify');\n}\n\nfunction ensureNotifyProcess(): ChildProcess | null {\n if (notifyProcess && !notifyProcess.killed && notifyProcess.stdin?.writable) {\n return notifyProcess;\n }\n\n const binary = getNotifyBinary();\n if (!existsSync(binary)) {\n return null;\n }\n\n notifyProcess = spawn(binary, [], {\n stdio: ['pipe', 'ignore', 'pipe'],\n });\n\n notifyProcess.stderr?.on('data', (data: Buffer) => {\n const msg = data.toString().trim();\n if (msg) console.error(`[sisyphus-notify] ${msg}`);\n });\n\n notifyProcess.on('close', () => {\n notifyProcess = null;\n });\n\n // Don't keep short-lived parents alive (CLI, tests). The daemon stays up\n // for other reasons; when it exits, the notify subprocess sees stdin EOF.\n notifyProcess.unref();\n notifyProcess.stdin?.unref();\n notifyProcess.stderr?.unref();\n\n return notifyProcess;\n}\n\nexport function sendTerminalNotification(opts: NotificationOptions): void;\nexport function sendTerminalNotification(title: string, message: string, tmuxSession?: string, level?: NotificationLevel): void;\nexport function sendTerminalNotification(titleOrOpts: string | NotificationOptions, message?: string, tmuxSession?: string, level?: NotificationLevel): void {\n let title: string;\n let msg: string;\n let tmuxSess: string | undefined;\n let lvl: NotificationLevel;\n\n if (typeof titleOrOpts === 'object') {\n title = titleOrOpts.title;\n msg = titleOrOpts.message;\n tmuxSess = titleOrOpts.tmuxSession;\n lvl = titleOrOpts.level ?? 'urgent';\n } else {\n title = titleOrOpts;\n msg = message!;\n tmuxSess = tmuxSession;\n lvl = level ?? 'urgent';\n }\n\n // Ensure the switch script is in place\n if (tmuxSess) ensureSwitchScript();\n\n // Try native SisyphusNotify.app (supports click-to-switch + level styling)\n const proc = ensureNotifyProcess();\n if (proc?.stdin?.writable) {\n const payload: Record<string, string> = { title, message: msg, level: lvl };\n if (tmuxSess) payload.tmuxSession = tmuxSess;\n proc.stdin.write(JSON.stringify(payload) + '\\n');\n return;\n }\n\n // Fallback: terminal-notifier — sound only on urgent\n const tnArgs = ['-title', title, '-message', msg];\n if (lvl === 'urgent') tnArgs.push('-sound', 'default');\n execFile('terminal-notifier', tnArgs, (err) => {\n if (err) {\n // Last resort: osascript — use escapeAppleScript for safe string interpolation\n const soundClause = lvl === 'urgent' ? ' sound name \"default\"' : '';\n execFile('osascript', [\n '-e',\n `display notification \"${escapeAppleScript(msg)}\" with title \"${escapeAppleScript(title)}\"${soundClause}`,\n ], () => {});\n }\n });\n}\n","import { existsSync, mkdirSync, readFileSync, readdirSync } from 'node:fs';\nimport {\n askDecisionsPath, askDir, askMetaPath, askOutputPath, askProgressPath, askVisualsDir,\n} from '../shared/paths.js';\nimport type { AskMeta, AskStatus, Deck, InteractionKind, InteractionResponse } from '../shared/types.js';\nimport { loadConfig } from '../shared/config.js';\nimport { emitHistoryEvent } from './history.js';\nimport { isSessionDangerous } from './state.js';\nimport { atomicWrite, withLock } from './lib/atomic.js';\nimport { sendTerminalNotification } from './notify.js';\nimport * as state from './state.js';\n\nconst ACTIONABLE_KINDS: ReadonlySet<InteractionKind> = new Set([\n 'validation', 'decision', 'context', 'error',\n]);\n\nconst HEARTBEAT_ASKED_BY = 'system:heartbeat';\nconst ORPHAN_ASKED_BY = 'system:orphan-handler';\n\nfunction maybeNotifyOnAskCreated(cwd: string, sessionId: string, meta: AskMeta): void {\n if (process.env.NODE_ENV === 'test' || process.env.SISYPHUS_DISABLE_NOTIFY === '1') return;\n const isActionable = meta.kind !== undefined && ACTIONABLE_KINDS.has(meta.kind);\n const isHeartbeat = meta.askedBy === HEARTBEAT_ASKED_BY;\n if (!isActionable && !isHeartbeat) return;\n\n try {\n const config = loadConfig(cwd);\n if (config.notifications?.enabled === false) return;\n const session = state.getSession(cwd, sessionId);\n const label = session.name ?? sessionId.slice(0, 8);\n const body = meta.title ?? 'Question pending';\n sendTerminalNotification(label, body, session.tmuxSessionName, 'urgent');\n } catch {\n // notify failures must never roll back the ask write\n }\n}\n\nexport interface CreateAskParams {\n askId: string;\n askedBy: string;\n blocking: boolean;\n pid?: number;\n claudeSessionId?: string;\n cwd: string;\n title?: string;\n subtitle?: string;\n kind?: InteractionKind;\n orphanTarget?: AskMeta['orphanTarget'];\n modeTransition?: true;\n}\n\nexport function createAsk(cwd: string, sessionId: string, params: CreateAskParams): AskMeta {\n // askVisualsDir is a subdir of askEntryDir — one recursive mkdir creates both.\n mkdirSync(askVisualsDir(cwd, sessionId, params.askId), { recursive: true });\n\n const askedAt = new Date().toISOString();\n const meta: AskMeta = {\n askId: params.askId,\n askedBy: params.askedBy,\n askedAt,\n status: 'pending' as AskStatus,\n blocking: params.blocking,\n cwd: params.cwd,\n ...(params.pid !== undefined ? { pid: params.pid, startedAt: askedAt } : {}),\n ...(params.claudeSessionId !== undefined ? { claudeSessionId: params.claudeSessionId } : {}),\n ...(params.title !== undefined ? { title: params.title } : {}),\n ...(params.subtitle !== undefined ? { subtitle: params.subtitle } : {}),\n ...(params.kind !== undefined ? { kind: params.kind } : {}),\n ...(params.orphanTarget !== undefined ? { orphanTarget: params.orphanTarget } : {}),\n ...(params.modeTransition !== undefined ? { modeTransition: params.modeTransition } : {}),\n };\n\n atomicWrite(askMetaPath(cwd, sessionId, params.askId), JSON.stringify(meta, null, 2));\n emitHistoryEvent(sessionId, 'ask-issued', {\n askId: params.askId,\n askedBy: params.askedBy,\n blocking: params.blocking,\n askedAt,\n });\n maybeNotifyOnAskCreated(cwd, sessionId, meta);\n return meta;\n}\n\nexport function writeDecisions(cwd: string, sessionId: string, askId: string, deck: Deck): void {\n atomicWrite(askDecisionsPath(cwd, sessionId, askId), JSON.stringify(deck, null, 2));\n void maybeAutoResolveAsk(cwd, sessionId, askId, deck);\n}\n\nexport function readDecisions(cwd: string, sessionId: string, askId: string): Deck | null {\n const p = askDecisionsPath(cwd, sessionId, askId);\n try {\n // { encoding } in try body intentional — keeps try content free of bare } for linter clarity\n return JSON.parse(readFileSync(p, { encoding: 'utf-8' })) as Deck;\n } catch (_e) {\n return null;\n }\n}\n\nexport async function writeProgress(\n cwd: string, sessionId: string, askId: string, responses: InteractionResponse[],\n): Promise<void> {\n atomicWrite(askProgressPath(cwd, sessionId, askId), JSON.stringify({\n partial: true,\n responses,\n savedAt: new Date().toISOString(),\n }, null, 2));\n const cur = readMeta(cwd, sessionId, askId);\n if (cur?.status === 'pending') {\n await updateMeta(cwd, sessionId, askId, { status: 'in-progress', startedAt: new Date().toISOString() });\n }\n}\n\nexport function readProgress(\n cwd: string, sessionId: string, askId: string,\n): { responses: InteractionResponse[]; savedAt: string } | null {\n const p = askProgressPath(cwd, sessionId, askId);\n try {\n const data = JSON.parse(readFileSync(p, { encoding: 'utf-8' })) as Record<string, unknown>;\n if (!Array.isArray(data['responses'])) return null;\n return { responses: data['responses'] as InteractionResponse[], savedAt: data['savedAt'] as string };\n } catch (_e) {\n return null;\n }\n}\n\nexport function writeOutput(\n cwd: string, sessionId: string, askId: string,\n responses: InteractionResponse[], completedAt?: string,\n): void {\n atomicWrite(askOutputPath(cwd, sessionId, askId), JSON.stringify({\n responses,\n completedAt: completedAt ?? new Date().toISOString(),\n }, null, 2));\n}\n\nexport function readMeta(cwd: string, sessionId: string, askId: string): AskMeta | null {\n const p = askMetaPath(cwd, sessionId, askId);\n if (!existsSync(p)) {\n return null;\n }\n return JSON.parse(readFileSync(p, 'utf-8')) as AskMeta;\n}\n\nexport async function updateMeta(\n cwd: string, sessionId: string, askId: string, patch: Partial<AskMeta>,\n): Promise<AskMeta> {\n return withLock(askId, () => {\n const cur = readMeta(cwd, sessionId, askId);\n if (!cur) {\n throw new Error(`updateMeta: askId ${askId} not found`);\n }\n const next: AskMeta = { ...cur, ...patch };\n atomicWrite(askMetaPath(cwd, sessionId, askId), JSON.stringify(next, null, 2));\n return next;\n });\n}\n\nexport function listAsks(cwd: string, sessionId: string): string[] {\n const dir = askDir(cwd, sessionId);\n if (!existsSync(dir)) {\n return [];\n }\n return readdirSync(dir, { withFileTypes: true })\n .filter(e => e.isDirectory())\n .map(e => e.name);\n}\n\nexport interface PendingAskRef {\n askId: string;\n status: AskStatus;\n title?: string;\n}\n\n/**\n * Open asks (pending or in-progress) attributed to a specific caller. Used to gate\n * yield/submit so a deck can't be abandoned mid-flight — terminating the caller's\n * pane orphans any answer the user produces afterward.\n *\n * Skips: meta.orphaned, status === 'answered', decks where output.json already\n * exists (the user resolved the deck but markAnswered hasn't run yet, e.g. because\n * the original waiter died before observing the output), and non-blocking decks\n * (mode-transition notifications, heartbeat asks, orphan-recovery surfaces — these\n * have no CLI waiter, so terminating the caller doesn't orphan anything).\n */\n/**\n * Build auto-responses for a deck by selecting the first option of every\n * interaction. Skips interactions with no options. Used by dangerous mode.\n */\nfunction buildAutoResponses(deck: Deck): InteractionResponse[] {\n const out: InteractionResponse[] = [];\n for (const interaction of deck.interactions) {\n const first = interaction.options[0];\n if (!first) continue;\n out.push({ id: interaction.id, selectedOptionId: first.id });\n }\n return out;\n}\n\n/**\n * Unconditionally auto-resolve the given ask using the supplied (or just-read)\n * deck. Skips when output.json already exists or no responses can be built.\n * The flush path passes the deck directly; the writeDecisions hook also passes\n * the deck so we never re-read it.\n */\nexport async function autoResolveAsk(\n cwd: string, sessionId: string, askId: string, deck?: Deck,\n): Promise<boolean> {\n try {\n if (existsSync(askOutputPath(cwd, sessionId, askId))) return false;\n const d = deck ?? readDecisions(cwd, sessionId, askId);\n if (!d) return false;\n const responses = buildAutoResponses(d);\n if (responses.length === 0) return false;\n writeOutput(cwd, sessionId, askId, responses);\n await updateMeta(cwd, sessionId, askId, {\n status: 'answered',\n completedAt: new Date().toISOString(),\n });\n return true;\n } catch (err) {\n console.warn(`[sisyphus] dangerous-mode auto-resolve failed for ask ${askId}:`, err instanceof Error ? err.message : err);\n return false;\n }\n}\n\n/**\n * Auto-resolve hook called from writeDecisions. If dangerous mode is on for\n * this session, auto-resolves the just-written deck. Failure is logged, never\n * thrown — must not roll back the deck write.\n */\nasync function maybeAutoResolveAsk(\n cwd: string, sessionId: string, askId: string, deck: Deck,\n): Promise<void> {\n try {\n if (!isSessionDangerous(cwd, sessionId)) return;\n // Orphan-handler asks require human action — auto-selecting \"resume\" doesn't\n // trigger an actual resume, but it does mark the ask answered, which defeats\n // emitOrphanAsk's dedup and causes a notification flood every monitor tick\n // while the orchestrator stays gone.\n if (deck.source?.askedBy === ORPHAN_ASKED_BY) return;\n await autoResolveAsk(cwd, sessionId, askId, deck);\n } catch {\n // never roll back the deck write\n }\n}\n\nexport function listOpenAsksFor(cwd: string, sessionId: string, askedBy: string): PendingAskRef[] {\n const out: PendingAskRef[] = [];\n for (const askId of listAsks(cwd, sessionId)) {\n const meta = readMeta(cwd, sessionId, askId);\n if (!meta) continue;\n if (meta.askedBy !== askedBy) continue;\n if (meta.orphaned) continue;\n if (!meta.blocking) continue;\n if (meta.status !== 'pending' && meta.status !== 'in-progress') continue;\n if (existsSync(askOutputPath(cwd, sessionId, askId))) continue;\n out.push({ askId, status: meta.status, ...(meta.title !== undefined ? { title: meta.title } : {}) });\n }\n return out;\n}\n","import { existsSync, watchFile, unwatchFile } from 'node:fs';\nimport { mountPanel, type Deck, type InteractionResponse, type MountedPanel } from '@crouton-kit/humanloop';\nimport { readDecisions, readMeta, updateMeta, writeOutput } from '../daemon/ask-store.js';\nimport { askOutputPath, askProgressPath } from '../shared/paths.js';\nimport { setupTerminal, startKeypressListener, onResize, writeToStdout, type Key } from './terminal.js';\nimport { flushFrame } from './render.js';\n\ninterface RunSingleAskOpts {\n cwd: string;\n sessionId: string;\n askId: string;\n}\n\n/**\n * Standalone single-ask runner — opens a humanloop deck for one ask in the\n * current pane and exits when answered (locally or by the dashboard).\n *\n * Designed for the parallel ask-pane spawned by `sis ask`: the pane has\n * no inbox, no tree, just the deck. Both this pane and the dashboard write\n * through the same on-disk ask-store paths, so whichever surface answers\n * first wins; the loser detects the resolution via output.json and exits.\n */\nexport async function runSingleAsk(opts: RunSingleAskOpts): Promise<void> {\n const { cwd, sessionId, askId } = opts;\n\n const meta = readMeta(cwd, sessionId, askId);\n if (!meta || meta.status === 'answered') {\n return;\n }\n\n const deck = readDecisions(cwd, sessionId, askId);\n if (!deck) return;\n\n const cleanupTerminal = setupTerminal();\n\n let exiting = false;\n let panel: MountedPanel | null = null;\n let prevFrame: string[] = [];\n let stopKeypress: (() => void) | null = null;\n let stopResize: (() => void) | null = null;\n const outputPath = askOutputPath(cwd, sessionId, askId);\n\n const exit = (code: number): void => {\n if (exiting) return;\n exiting = true;\n try { stopKeypress?.(); } catch { /* best-effort */ }\n try { stopResize?.(); } catch { /* best-effort */ }\n try { panel?.unmount(); } catch { /* best-effort */ }\n try { unwatchFile(outputPath, onExternalChange); } catch { /* best-effort */ }\n cleanupTerminal();\n process.exit(code);\n };\n\n const flushHost = (lines: string[]): void => {\n const out = flushFrame(lines, prevFrame, '\\x1b[?25l');\n writeToStdout(out);\n prevFrame = lines;\n };\n\n const onExternalChange = (): void => {\n if (exiting) return;\n if (!existsSync(outputPath)) return;\n exit(0);\n };\n\n let lastResponses: InteractionResponse[] = [];\n\n const submit = (responses: InteractionResponse[]): void => {\n if (exiting) return;\n void (async () => {\n const completedAt = new Date().toISOString();\n writeOutput(cwd, sessionId, askId, responses, completedAt);\n try {\n await updateMeta(cwd, sessionId, askId, { status: 'answered', completedAt });\n } catch {\n // Race: dashboard updated meta concurrently. output.json is written; the\n // blocked `sis ask` will still pick up the result.\n }\n exit(0);\n })();\n };\n\n const cols = process.stdout.columns ?? 80;\n const rows = process.stdout.rows ?? 24;\n\n panel = mountPanel({\n deck: deck as Deck,\n cols,\n rows,\n progressPath: askProgressPath(cwd, sessionId, askId),\n onProgress: (responses: InteractionResponse[]) => {\n lastResponses = responses;\n const cur = readMeta(cwd, sessionId, askId);\n if (cur?.status === 'pending') {\n void updateMeta(cwd, sessionId, askId, { status: 'in-progress', startedAt: new Date().toISOString() }).catch(() => { /* best-effort */ });\n }\n if (panel) flushHost(panel.render());\n },\n onComplete: (responses: InteractionResponse[]) => {\n submit(responses);\n },\n // Final-phase Enter on an incomplete deck — submit what we have.\n onExit: () => {\n submit(lastResponses);\n },\n });\n\n stopKeypress = startKeypressListener((input: string, key: Key) => {\n if (exiting || !panel) return;\n panel.handleKey(input, key);\n flushHost(panel.render());\n });\n\n stopResize = onResize(() => {\n if (exiting || !panel) return;\n const newCols = process.stdout.columns ?? 80;\n const newRows = process.stdout.rows ?? 24;\n panel.handleResize(newCols, newRows);\n prevFrame = [];\n flushHost(panel.render());\n });\n\n watchFile(outputPath, { interval: 250 }, onExternalChange);\n\n // Race guard: dashboard may have answered between our initial readMeta and\n // mount completion. If output.json is already on disk, exit immediately.\n if (existsSync(outputPath)) {\n exit(0);\n return;\n }\n\n flushHost(panel.render());\n\n // Keep the process alive — the panel + listeners hold the event loop open\n // via stdin (raw mode) and the watchFile poller. Returning from this async\n // function would let `await runSingleAsk(...)` resolve in index.ts but the\n // listeners keep node running until exit() fires.\n await new Promise<void>(() => { /* never resolves; exit() handles teardown */ });\n}\n","import { setupTerminal } from './terminal.js';\nimport { createAppState } from './state.js';\nimport { startApp } from './app.js';\nimport { registerDashboardWindow } from './lib/tmux.js';\n\nconst args = process.argv.slice(2);\n\nfunction getArg(name: string): string | undefined {\n const idx = args.indexOf(`--${name}`);\n if (idx !== -1 && idx + 1 < args.length) {\n return args[idx + 1];\n }\n return undefined;\n}\n\nconst cwd = getArg('cwd') ?? process.cwd();\n\nconst askId = getArg('ask');\nconst sessionId = getArg('session-id');\nif (askId && sessionId) {\n // Single-ask mode — used by the parallel ask-pane spawned from `sis ask`.\n // Skips the dashboard inbox and renders only the deck for this one ask.\n // Must NOT call registerDashboardWindow() — would clobber the real dashboard.\n const { runSingleAsk } = await import('./single-ask.js');\n await runSingleAsk({ cwd, sessionId, askId });\n process.exit(0);\n}\n\nregisterDashboardWindow(cwd);\nconst cleanup = setupTerminal();\nconst state = createAppState(cwd);\nstartApp(state, cleanup);\n","import type { Session } from '../shared/types.js';\nimport type { AggregateInboxItem } from '../shared/inbox-types.js';\nimport type { TreeNode } from './types/tree.js';\nimport type { ReportBlock } from './lib/reports.js';\n\n// ---------------------------------------------------------------------------\n// Polling data interfaces (moved from usePolling.ts)\n// ---------------------------------------------------------------------------\n\nexport interface SessionSummary {\n id: string;\n name?: string;\n task: string;\n status: string;\n agentCount: number;\n runningAgentCount: number;\n createdAt: string;\n activeMs: number;\n tmuxSessionName?: string;\n tmuxSessionId?: string;\n tmuxWindowId?: string;\n /** Cached result of windowExists check — avoids synchronous subprocess in render */\n windowAlive?: boolean;\n orphaned?: boolean;\n}\n\nexport interface CycleLog {\n cycle: number;\n content: string;\n}\n\n// ---------------------------------------------------------------------------\n// InputMode (moved from InputBar.tsx)\n// ---------------------------------------------------------------------------\n\nexport type InputMode =\n | 'navigate'\n | 'report-detail'\n | 'leader'\n | 'copy-menu'\n | 'open-menu'\n | 'agent-menu'\n | 'session-menu'\n | 'go-menu'\n | 'companion-menu'\n | 'help'\n | 'companion-overlay'\n | 'companion-debug'\n | 'search';\n\n// ---------------------------------------------------------------------------\n// Compose mode types\n// ---------------------------------------------------------------------------\n\nexport type ComposeAction =\n | { kind: 'new-session' }\n | { kind: 'message-orchestrator'; sessionId: string }\n | { kind: 'resume'; sessionId: string }\n | { kind: 'continue'; sessionId: string }\n | { kind: 'spawn-agent'; sessionId: string }\n | { kind: 'message-agent'; sessionId: string; agentId: string };\n\n/** Actions where empty content is allowed (submit without typing) */\nexport const OPTIONAL_COMPOSE = new Set(['resume', 'continue']);\n\n// ---------------------------------------------------------------------------\n// Render scheduling\n// ---------------------------------------------------------------------------\n\nlet renderScheduled = false;\nlet renderFn: (() => void) | null = null;\n\nexport function setRenderFunction(fn: () => void): void {\n renderFn = fn;\n}\n\nexport function requestRender(): void {\n if (renderScheduled) return;\n renderScheduled = true;\n setImmediate(() => {\n renderScheduled = false;\n renderFn?.();\n });\n}\n\n// ---------------------------------------------------------------------------\n// ThrottledScroll\n// ---------------------------------------------------------------------------\n\nconst FRAME_MS = 16; // ~60fps\n\nexport class ThrottledScroll {\n offset: number = 0;\n private target: number = 0;\n private max: number = Infinity;\n private timer: ReturnType<typeof setTimeout> | null = null;\n private onRender: () => void;\n\n constructor(onRender: () => void, initial = 0) {\n this.onRender = onRender;\n this.offset = initial;\n this.target = initial;\n }\n\n private scheduleFlush(): void {\n if (this.timer === null) {\n this.timer = setTimeout(() => {\n this.timer = null;\n this.offset = this.target;\n this.onRender();\n }, FRAME_MS);\n }\n }\n\n private clamp(value: number): number {\n if (value < 0) return 0;\n if (value > this.max) return this.max;\n return value;\n }\n\n scrollBy(delta: number): void {\n this.target = this.clamp(this.target + delta);\n this.scheduleFlush();\n }\n\n scrollTo(value: number): void {\n this.target = this.clamp(value);\n this.scheduleFlush();\n }\n\n // Renderer pushes the current content's max scroll each frame so scrollBy\n // can't accumulate past the bottom. Without this, over-scroll inflates\n // `target` invisibly and reverse scrolls have to burn through the buffer\n // before any visual movement resumes.\n setMax(max: number): void {\n this.max = Math.max(0, max);\n if (this.target > this.max) this.target = this.max;\n if (this.offset > this.max) this.offset = this.max;\n }\n\n reset(): void {\n if (this.timer !== null) {\n clearTimeout(this.timer);\n this.timer = null;\n }\n this.target = 0;\n this.offset = 0;\n }\n\n destroy(): void {\n if (this.timer !== null) {\n clearTimeout(this.timer);\n this.timer = null;\n }\n }\n}\n\n// ---------------------------------------------------------------------------\n// AppState\n// ---------------------------------------------------------------------------\n\nexport interface AppState {\n // Terminal dimensions\n rows: number;\n cols: number;\n\n // Tree navigation\n cursorIndex: number;\n expanded: Set<string>;\n mode: InputMode;\n focusPane: 'tree' | 'detail' | 'logs';\n\n // Session\n selectedSessionId: string | null;\n searchFilter: string | null;\n searchText: string;\n targetAgentId: string | null;\n\n // UI\n notification: string | null;\n notificationTimer: ReturnType<typeof setTimeout> | null;\n\n // Scroll\n detailScroll: ThrottledScroll;\n digestScroll: ThrottledScroll;\n\n // Aggregate inbox — fetched from daemon on each poll\n aggregateInbox: AggregateInboxItem[];\n crossSessionInboxScroll: ThrottledScroll;\n cachedInboxLines: import('./lib/format.js').DetailLine[] | null;\n inboxCacheKey: string;\n inboxRenderedCache: import('./render.js').RenderedCache;\n\n // Stacked detail (3b) — cachedStackedLines + stackedCacheKey must be cleared together (cache pair invariant)\n useStackedDetail: boolean;\n detailMode: 'gsr' | 'cycle-log' | 'cross-session-inbox';\n focusedStrip: 'goal' | 'strategy' | 'roadmap';\n goalScroll: ThrottledScroll;\n strategyScroll: ThrottledScroll;\n roadmapScroll: ThrottledScroll;\n cachedStackedLines: {\n goal: import('./lib/format.js').DetailLine[];\n strategy: import('./lib/format.js').DetailLine[];\n roadmap: import('./lib/format.js').DetailLine[];\n cycleLog: import('./lib/format.js').DetailLine[];\n } | null;\n stackedCacheKey: string;\n stackedRenderedCache: import('./render.js').RenderedCache;\n\n // Polling data (from daemon)\n sessions: SessionSummary[];\n selectedSession: Session | null;\n planContent: string;\n strategyContent: string;\n goalContent: string;\n completionSummaryContent: string;\n logsContent: string;\n logsCycles: CycleLog[];\n digestData: import('../shared/types.js').StatusDigest | null;\n paneAlive: boolean;\n contextFiles: string[];\n error: string | null;\n\n // Cursor stabilization\n cursorNodeId: string | null;\n prevNodes: TreeNode[];\n prevCycleCount: number;\n\n // Render caches\n cachedReportBlocks: Map<string, ReportBlock[]>;\n cachedTreeNodes: TreeNode[] | null;\n treeCacheKey: string;\n cachedDetailLines: import('./lib/format.js').DetailLine[] | null;\n detailCacheKey: string;\n detailRenderedCache: import('./render.js').RenderedCache;\n cachedDigestLines: import('./lib/format.js').DetailLine[] | null;\n digestCacheKey: string;\n digestRenderedCache: import('./render.js').RenderedCache;\n\n // Cycle flow\n flowExpanded: boolean;\n\n // Resolution mode (3e)\n resolutionActive: boolean;\n resolutionHandle: import('./panels/mounted-humanloop.js').MountedResolutionHandle | null;\n visuals: Map<string, import('./panels/mounted-humanloop.js').VisualEntry>;\n\n // Config\n cwd: string;\n}\n\nexport function createAppState(cwd: string): AppState {\n const cols = process.stdout.columns ?? 80;\n const rows = process.stdout.rows ?? 24;\n\n const detailScroll = new ThrottledScroll(requestRender);\n const digestScroll = new ThrottledScroll(requestRender);\n const crossSessionInboxScroll = new ThrottledScroll(requestRender);\n const goalScroll = new ThrottledScroll(requestRender);\n const strategyScroll = new ThrottledScroll(requestRender);\n const roadmapScroll = new ThrottledScroll(requestRender);\n\n // Seed default-expanded sections (done stays collapsed)\n const expanded = new Set<string>();\n expanded.add('section:needs-you');\n expanded.add('section:running');\n\n return {\n rows,\n cols,\n cursorIndex: 0,\n expanded,\n mode: 'navigate',\n focusPane: 'tree',\n selectedSessionId: null,\n searchFilter: null,\n searchText: '',\n targetAgentId: null,\n notification: null,\n notificationTimer: null,\n detailScroll,\n digestScroll,\n aggregateInbox: [],\n crossSessionInboxScroll,\n cachedInboxLines: null,\n inboxCacheKey: '',\n inboxRenderedCache: { lines: [], ansi: [] },\n useStackedDetail: process.env.SISYPHUS_USE_STACKED_DETAIL !== '0',\n detailMode: 'gsr',\n focusedStrip: 'roadmap',\n goalScroll,\n strategyScroll,\n roadmapScroll,\n cachedStackedLines: null,\n stackedCacheKey: '',\n stackedRenderedCache: { lines: [], ansi: [] },\n sessions: [],\n selectedSession: null,\n planContent: '',\n strategyContent: '',\n goalContent: '',\n completionSummaryContent: '',\n logsContent: '',\n logsCycles: [],\n digestData: null,\n paneAlive: true,\n contextFiles: [],\n error: null,\n cursorNodeId: null,\n prevNodes: [],\n prevCycleCount: 0,\n cachedReportBlocks: new Map(),\n cachedTreeNodes: null,\n treeCacheKey: '',\n cachedDetailLines: null,\n detailCacheKey: '',\n detailRenderedCache: { lines: [], ansi: [] },\n cachedDigestLines: null,\n digestCacheKey: '',\n digestRenderedCache: { lines: [], ansi: [] },\n flowExpanded: false,\n resolutionActive: false,\n resolutionHandle: null,\n visuals: new Map(),\n cwd,\n };\n}\n\n// ---------------------------------------------------------------------------\n// Notification helper\n// ---------------------------------------------------------------------------\n\nexport function notify(state: AppState, msg: string): void {\n state.notification = msg;\n if (state.notificationTimer !== null) {\n clearTimeout(state.notificationTimer);\n }\n state.notificationTimer = setTimeout(() => {\n state.notification = null;\n state.notificationTimer = null;\n requestRender();\n }, 30_000);\n}\n\n// ---------------------------------------------------------------------------\n// Cursor stabilization\n// ---------------------------------------------------------------------------\n\nexport function stabilizeCursor(state: AppState, nodes: TreeNode[]): void {\n if (nodes.length === 0) {\n state.cursorIndex = 0;\n return;\n }\n\n const targetId = state.cursorNodeId;\n if (targetId === null) {\n state.cursorNodeId = nodes[0]?.id ?? null;\n return;\n }\n\n // If current index already points to the right node, no adjustment needed\n if (nodes[state.cursorIndex]?.id === targetId) return;\n\n // Find the tracked node in the new tree\n const newIndex = nodes.findIndex((n) => n.id === targetId);\n if (newIndex !== -1) {\n state.cursorIndex = newIndex;\n } else {\n // Node is gone (parent collapsed, session removed, etc.) — clamp\n const clamped = Math.min(state.cursorIndex, nodes.length - 1);\n state.cursorIndex = clamped;\n state.cursorNodeId = nodes[clamped]?.id ?? null;\n }\n}\n\n// ---------------------------------------------------------------------------\n// Auto-expand cycle\n// ---------------------------------------------------------------------------\n\nexport function autoExpandCycle(state: AppState): void {\n const selectedSession = state.selectedSession;\n if (!selectedSession) return;\n\n const sessionNodeId = `session:${selectedSession.id}`;\n const cycles = selectedSession.orchestratorCycles;\n\n // Only auto-manage cycle expansion if the session is already expanded by user\n if (!state.expanded.has(sessionNodeId)) {\n state.prevCycleCount = cycles.length;\n return;\n }\n\n if (cycles.length === 0) {\n state.prevCycleCount = 0;\n return;\n }\n\n const latest = cycles[cycles.length - 1]!;\n const latestId = `cycle:${selectedSession.id}:${latest.cycle}`;\n\n if (cycles.length > state.prevCycleCount && state.prevCycleCount > 0) {\n // New cycle appeared — collapse previous, expand latest\n const prevCycle = cycles[cycles.length - 2];\n if (prevCycle) {\n const prevId = `cycle:${selectedSession.id}:${prevCycle.cycle}`;\n state.expanded.delete(prevId);\n state.expanded.add(latestId);\n }\n } else if (!state.expanded.has(latestId)) {\n // Ensure latest is expanded\n state.expanded.add(latestId);\n }\n\n state.prevCycleCount = cycles.length;\n}\n","import { readFileSync, existsSync, readdirSync, statSync } from 'node:fs';\nimport { join } from 'node:path';\n\nimport {\n type AppState,\n type SessionSummary,\n type CycleLog,\n setRenderFunction,\n requestRender,\n stabilizeCursor,\n autoExpandCycle,\n notify,\n} from './state.js';\nimport { handleKeypress, type InputActions } from './input.js';\nimport { createFrameBuffer, flushFrame, writeCenter, copyRows } from './render.js';\nimport { writeToStdout, startKeypressListener, onResize } from './terminal.js';\nimport { buildTree } from './lib/tree.js';\nimport { precomputePrefixes } from './lib/tree-render.js';\nimport { resolveReports } from './lib/reports.js';\nimport { send, inboxList } from './lib/client.js';\nimport {\n listAllWindowIds,\n openEditorPopup,\n editInPopup,\n openCompanionPane,\n openClaudeResumePopup,\n openClaudeResumeSession,\n selectWindow,\n selectPane,\n switchToSession,\n paneExists,\n openLogPopup,\n openShellPopup,\n openInFileManager,\n promptInPopup,\n} from './lib/tmux.js';\nimport { copyToClipboard } from './lib/clipboard.js';\nimport { buildSessionContext } from './lib/context.js';\nimport { renderTreePanel } from './panels/tree.js';\nimport { renderDetailRows, renderDigestRows, type DetailContext } from './panels/detail.js';\nimport { renderStackedDetailRows } from './panels/stacked-detail.js';\nimport { renderStatusLine } from './panels/bottom.js';\nimport { renderCrossSessionInboxRows } from './panels/cross-session-inbox.js';\nimport { renderSubmenuOverlay, renderHelpOverlay, renderCompanionOverlay, renderCompanionDebugOverlay } from './panels/overlays.js';\nimport { KEYMAP, MENU_FOR_MODE } from '../shared/keymap.js';\nimport { companionPath } from '../shared/paths.js';\nimport type { CompanionState } from '../shared/companion-types.js';\nimport { normalizeCompanion } from '../shared/companion-normalize.js';\nimport { composeViaPopup, ensureSisyphusInitLua } from './lib/popup-compose.js';\nimport { loadConfig } from '../shared/config.js';\nimport { roadmapPath, goalPath, strategyPath, logsDir, contextDir, digestPath } from '../shared/paths.js';\nimport { statusIndicator, formatDuration, statusColor, agentStatusIcon, agentDisplayName, truncate, ansiColor, ansiDim, ansiBold } from './lib/format.js';\nimport type { TreeNode } from './types/tree.js';\nimport type { Agent, Session, StatusDigest } from '../shared/types.js';\n\n// ── Module-level companion cache (reloads on mtime change, ~poll interval) ────\n\nlet _cachedCompanion: CompanionState | null = null;\nlet _companionMtime = 0;\n\nfunction getCompanion(): CompanionState | null {\n try {\n const { mtimeMs } = statSync(companionPath());\n if (_cachedCompanion && mtimeMs === _companionMtime) return _cachedCompanion;\n _companionMtime = mtimeMs;\n _cachedCompanion = normalizeCompanion(JSON.parse(readFileSync(companionPath(), 'utf-8')) as CompanionState);\n return _cachedCompanion;\n } catch {\n return _cachedCompanion;\n }\n}\n\n// ── Module-level cache for latest rendered nodes (needed by keypress handler) ─\n\nlet latestNodes: TreeNode[] = [];\n\n// ── Module-level cache for context file content ───────────────────────────────\n\nlet cachedContextFilePath: string | null = null;\nlet cachedContextFileContent: string | null = null;\n\n// ── Previous frame for diffing ────────────────────────────────────────────────\n\nlet prevFrame: string[] = [];\n// Tracks last known resolution state so render() can reset prevFrame on transition\nlet prevResolutionActive = false;\n\n// ── Panel dirty tracking ─────────────────────────────────────────────────────\n// Tracks the inputs that affect each panel. When only the scroll offset changes,\n// we can skip re-rendering panels whose inputs haven't changed.\n\nlet prevTreeInputs = '';\nlet prevBottomInputs = '';\n\n// ── Dynamic tree width ──────────────────────────────────────────────────────\n// Scale tree panel with terminal width so session names aren't aggressively\n// truncated on wide terminals. Min 36 (fits 80-col), max 70.\n\nfunction computeTreeWidth(cols: number): number {\n return Math.min(70, Math.max(36, Math.floor(cols * 0.25)));\n}\nlet prevOverlayMode = '';\nlet cachedTreeRows: string[] = [];\n\n// ── Cycle logs cache (avoids re-reading unchanged files every poll) ───────────\n\nlet cachedLogSessionId: string | null = null;\nlet cachedLogFiles: Map<string, { mtime: number; cycle: number; content: string }> = new Map();\n\n// ── Resolution frame renderer (3e) ───────────────────────────────────────────\n\nfunction renderResolutionFrame(buf: import('./render.js').FrameBuffer, state: AppState): void {\n const handle = state.resolutionHandle!;\n const info = handle.getHeaderInfo();\n const now = new Date().toISOString();\n\n // Build header strip (row 0)\n // Format: [esc] back ●●●○○ N of M sessionName/title ⏱ blocked Xm\n const escPart = ansiDim(' [esc] back');\n\n // Queue dots (max 12)\n const dotLimit = 12;\n const qLen = info.queueLength;\n let dotsPart = '';\n if (qLen <= dotLimit) {\n for (let i = 0; i < qLen; i++) {\n dotsPart += i < info.currentIndex ? '●' : '○';\n }\n } else {\n for (let i = 0; i < dotLimit; i++) {\n dotsPart += i < info.currentIndex ? '●' : '○';\n }\n const trailing = qLen - dotLimit;\n dotsPart += ` +${trailing}`;\n }\n const posLabel = ` ${info.currentIndex + 1} of ${info.queueLength}`;\n\n const sourcePart = info.sessionName\n ? ansiBold(info.sessionName) + (info.askTitle ? `/${truncate(info.askTitle, 32)}` : '')\n : '';\n\n const blocked = formatDuration(info.blockedSince, now);\n const timePart = ansiDim(`⏱ blocked ${blocked}`);\n\n const parts = [escPart, ' ', dotsPart, posLabel, ' ', sourcePart, ' ', timePart];\n let header = parts.join('');\n // Truncate if over width (drop source first, then truncate)\n if (header.replace(/\\x1b\\[[0-9;]*m/g, '').length > state.cols) {\n const shortened = [escPart, ' ', dotsPart, posLabel, ' ', timePart].join('');\n header = shortened;\n }\n buf.lines[0] = header + ' '.repeat(Math.max(0, state.cols - header.replace(/\\x1b\\[[0-9;]*m/g, '').length));\n\n // Rows 1..h-1: humanloop body OR visual (v0 toggle)\n const qid = handle.getCurrentQid();\n const visualEntry = qid ? state.visuals.get(qid) : undefined;\n\n const bodyH = state.rows - 1;\n\n if (visualEntry?.visible && visualEntry.status === 'ready') {\n // v0 toggle: visual replaces humanloop body entirely\n const visualLines = visualEntry.content.split('\\n');\n for (let i = 0; i < bodyH; i++) {\n buf.lines[i + 1] = i < visualLines.length ? visualLines[i]! : '';\n }\n } else {\n // Show humanloop content (with optional loading/error overlay on center row)\n const humanloopLines = handle.render();\n const midRow = Math.floor(bodyH / 2);\n for (let i = 0; i < bodyH; i++) {\n if (visualEntry?.visible && visualEntry.status === 'loading' && i === midRow) {\n const placeholderText = '[generating visual… ~30s]';\n const placeholder = ansiDim(placeholderText);\n const padL = Math.floor((state.cols - placeholderText.length) / 2);\n buf.lines[i + 1] = ' '.repeat(Math.max(0, padL)) + placeholder;\n } else if (visualEntry?.visible && visualEntry.status === 'error' && i === midRow) {\n const errText = visualEntry.error ? visualEntry.error : 'unknown';\n buf.lines[i + 1] = ansiColor(`[visual error: ${errText}]`, 'red') + ansiDim(' [R] retry');\n } else {\n buf.lines[i + 1] = i < humanloopLines.length ? humanloopLines[i]! : '';\n }\n }\n }\n}\n\n// ── Status header constants ──────────────────────────────────────────────────\n\nconst STATUS_ROW_COUNT = 2; // Fixed height for status header (avoids nvim resize on cursor change)\n\nfunction buildStatusRows(\n cursorNode: TreeNode | undefined,\n session: Session | null,\n state: AppState,\n): string[] {\n if (cursorNode?.type === 'needs-you-virtual') {\n const count = state.aggregateInbox.length;\n return [\n ' ' + ansiColor('⚑', 'red', true) + ' ' + ansiColor('Fleet Inbox', 'white', true),\n ' ' + ansiDim(`${count} pending ask${count !== 1 ? 's' : ''} across the fleet`),\n ];\n }\n\n if (cursorNode?.type === 'section') {\n const label = cursorNode.section === 'needs-you' ? 'Needs You' :\n cursorNode.section === 'running' ? 'Running' : 'Done';\n return [ansiDim(` ${label} section`), ''];\n }\n\n if (!cursorNode || !session) {\n return [ansiDim(' No session selected'), ''];\n }\n\n const dur = formatDuration(session.createdAt, session.completedAt);\n const indicator = statusIndicator(session.status);\n const sColor = statusColor(session.status);\n const title = truncate(session.name ?? session.task, 40);\n\n switch (cursorNode.type) {\n case 'session': {\n return [\n ' ' + ansiColor(indicator, sColor, true) + ' ' + ansiColor(title, 'white', true),\n ' ' + ansiDim(`${session.status} · ${session.orchestratorCycles.length} cycles · ${session.agents.length} agents · ${dur}`),\n ];\n }\n case 'cycle': {\n const cycle = session.orchestratorCycles.find(c => c.cycle === cursorNode.cycleNumber);\n if (!cycle) return [' ' + ansiColor(title, 'white', true), ''];\n const cDur = cycle.completedAt ? formatDuration(cycle.timestamp, cycle.completedAt) : 'running';\n const cStatus = cycle.completedAt ? 'completed' : 'running';\n return [\n ' ' + ansiColor(indicator, sColor, true) + ' ' + ansiColor(title, 'white', true) + ansiDim(` · Cycle ${cycle.cycle}`),\n ' ' + ansiDim(`${cStatus} · ${cDur} · ${cycle.agentsSpawned.length} agents`),\n ];\n }\n case 'agent':\n case 'report': {\n const agentId = cursorNode.type === 'agent' ? cursorNode.agentId : cursorNode.agentId;\n const agent = session.agents.find(a => a.id === agentId);\n if (!agent) return [' ' + ansiColor(title, 'white', true), ''];\n const aIcon = agentStatusIcon(agent.status);\n const aDur = formatDuration(agent.spawnedAt, agent.completedAt);\n const aName = agentDisplayName(agent);\n return [\n ' ' + ansiColor(aIcon, statusColor(agent.status === 'running' ? 'active' : agent.status), true) + ' ' + ansiColor(`${agent.id} · ${aName}`, 'white', true),\n ' ' + ansiDim(`${agent.status} · ${agent.agentType || '—'} · ${aDur}`),\n ];\n }\n case 'context-file': {\n const name = cursorNode.filePath.split('/').pop() ?? cursorNode.filePath;\n return [\n ' ' + ansiColor('⊞', 'white') + ' ' + ansiColor(name, 'white', true),\n ' ' + ansiDim(`context file · ${session.status}`),\n ];\n }\n case 'messages':\n case 'message': {\n return [\n ' ' + ansiColor(indicator, sColor, true) + ' ' + ansiColor(title, 'white', true),\n ' ' + ansiDim(`${session.messages.length} messages`),\n ];\n }\n default: {\n return [\n ' ' + ansiColor(indicator, sColor, true) + ' ' + ansiColor(title, 'white', true),\n ' ' + ansiDim(`${session.status} · ${dur}`),\n ];\n }\n }\n}\n\n// ── Helpers ───────────────────────────────────────────────────────────────────\n\nfunction getAgentForNode(node: TreeNode | undefined, agents: Agent[]): Agent | null {\n if (!node) return null;\n if (node.type === 'agent' || node.type === 'report') {\n return agents.find((a) => a.id === node.agentId) ?? null;\n }\n return null;\n}\n\n// ── startApp ──────────────────────────────────────────────────────────────────\n\nexport function startApp(state: AppState, cleanup: () => void): void {\n const config = loadConfig(state.cwd);\n\n // Materialize ~/.config/sisyphus/init.lua if missing (idempotent)\n ensureSisyphusInitLua();\n\n // Track selectedSessionId to detect changes across renders (for immediate poll)\n let prevSelectedSessionId: string | null | undefined = undefined;\n let debouncedPollTimer: ReturnType<typeof setTimeout> | null = null;\n\n // ── Polling ─────────────────────────────────────────────────────────────────\n\n async function poll(): Promise<void> {\n try {\n let selectedSession: Session | null = null;\n let planContent = '';\n let strategyContent = '';\n let goalContent = '';\n let completionSummaryContent = '';\n let logsContent = '';\n let logsCycles: CycleLog[] = [];\n let digestData: StatusDigest | null = null;\n let paneAlive = true;\n let contextFiles: string[] = [];\n\n const listPromise = send({ type: 'list', cwd: state.cwd });\n const statusPromise = state.selectedSessionId\n ? send({ type: 'status', sessionId: state.selectedSessionId, cwd: state.cwd })\n : null;\n const inboxPromise = inboxList();\n\n const [listRes, statusRes, aggregateInbox] = await Promise.all([\n listPromise,\n statusPromise ?? Promise.resolve(null),\n inboxPromise,\n ]);\n state.aggregateInbox = aggregateInbox;\n\n const sessions: SessionSummary[] = listRes.ok\n ? ((listRes.data?.sessions as SessionSummary[] | undefined) ?? [])\n : [];\n\n // Skip expensive sync I/O when resolution mode is active — panels are hidden,\n // data won't be rendered, and blocking here delays keystroke rendering.\n if (!state.resolutionActive) {\n\n // Batch-check window existence in a single tmux call\n const aliveWindows = listAllWindowIds();\n for (const s of sessions) {\n if (s.status !== 'completed' && s.tmuxWindowId) {\n s.windowAlive = aliveWindows.has(s.tmuxWindowId);\n }\n }\n\n if (state.selectedSessionId) {\n if (statusRes?.ok) {\n selectedSession = (statusRes.data?.session as Session | undefined) ?? null;\n }\n\n // Use cached windowAlive from the session list scan above\n if (selectedSession?.tmuxWindowId) {\n const cached = sessions.find((s) => s.id === state.selectedSessionId);\n paneAlive = cached?.windowAlive ?? false;\n }\n\n try {\n const pp = roadmapPath(state.cwd, state.selectedSessionId);\n if (existsSync(pp)) {\n planContent = readFileSync(pp, 'utf-8');\n }\n } catch {\n // roadmap.md may not exist yet\n }\n\n try {\n const gp = goalPath(state.cwd, state.selectedSessionId);\n if (existsSync(gp)) {\n goalContent = readFileSync(gp, 'utf-8');\n }\n } catch {\n // goal.md may not exist yet\n }\n\n try {\n const sp = strategyPath(state.cwd, state.selectedSessionId);\n if (existsSync(sp)) {\n strategyContent = readFileSync(sp, 'utf-8');\n }\n } catch {\n // strategy.md may not exist yet\n }\n\n try {\n const cp = join(contextDir(state.cwd, state.selectedSessionId), 'completion-summary.md');\n if (existsSync(cp)) {\n completionSummaryContent = readFileSync(cp, 'utf-8');\n }\n } catch {\n // completion-summary.md may not exist (only written on done)\n }\n\n try {\n const ld = logsDir(state.cwd, state.selectedSessionId);\n if (existsSync(ld)) {\n // Reset cache when session changes\n if (state.selectedSessionId !== cachedLogSessionId) {\n cachedLogFiles = new Map();\n cachedLogSessionId = state.selectedSessionId;\n }\n\n const files = readdirSync(ld)\n .filter((f) => f.startsWith('cycle-'))\n .sort();\n\n // Remove cache entries for deleted files\n const fileSet = new Set(files);\n for (const key of cachedLogFiles.keys()) {\n if (!fileSet.has(key)) cachedLogFiles.delete(key);\n }\n\n // Only re-read files whose mtime changed\n for (const f of files) {\n const filePath = join(ld, f);\n const mtime = statSync(filePath).mtimeMs;\n const cached = cachedLogFiles.get(f);\n if (!cached || cached.mtime !== mtime) {\n const match = f.match(/cycle-(\\d+)\\.md$/);\n const cycle = match ? parseInt(match[1]!, 10) : 0;\n const content = readFileSync(filePath, 'utf-8');\n cachedLogFiles.set(f, { mtime, cycle, content });\n }\n }\n\n logsCycles = files.map((f) => {\n const entry = cachedLogFiles.get(f)!;\n return { cycle: entry.cycle, content: entry.content };\n });\n logsContent = logsCycles.map((c) => c.content).join('\\n');\n }\n } catch {\n // logs may not exist yet\n }\n\n try {\n const cd = contextDir(state.cwd, state.selectedSessionId);\n if (existsSync(cd)) {\n const entries = readdirSync(cd, { withFileTypes: true })\n .filter((e) => !e.name.startsWith('.'));\n const flat: string[] = [];\n for (const e of entries) {\n if (e.isDirectory()) {\n try {\n const sub = readdirSync(join(cd, e.name))\n .filter((f) => !f.startsWith('.'))\n .map((f) => `${e.name}/${f}`);\n flat.push(...sub);\n } catch {\n // subdir may be unreadable\n }\n } else {\n flat.push(e.name);\n }\n }\n contextFiles = flat.sort();\n }\n } catch {\n // context dir may not exist yet\n }\n\n try {\n const dp = digestPath(state.cwd, state.selectedSessionId);\n if (existsSync(dp)) {\n const raw = JSON.parse(readFileSync(dp, 'utf-8'));\n if (\n raw &&\n typeof raw.recentWork === 'string' &&\n typeof raw.currentActivity === 'string' &&\n typeof raw.whatsNext === 'string' &&\n Array.isArray(raw.unusualEvents)\n ) {\n digestData = raw as StatusDigest;\n }\n }\n } catch {\n // digest.json may not exist or be malformed\n }\n }\n\n // Resolve report files in poll (not render) to avoid sync disk reads on keypress\n state.cachedReportBlocks.clear();\n if (selectedSession) {\n for (const agent of selectedSession.agents) {\n state.cachedReportBlocks.set(agent.id, resolveReports(agent.reports));\n }\n }\n\n } // end !state.resolutionActive\n\n state.sessions = sessions;\n state.selectedSession = selectedSession;\n state.planContent = planContent;\n state.strategyContent = strategyContent;\n state.goalContent = goalContent;\n state.completionSummaryContent = completionSummaryContent;\n state.logsContent = logsContent;\n state.logsCycles = logsCycles;\n state.digestData = digestData;\n state.paneAlive = paneAlive;\n state.contextFiles = contextFiles;\n state.error = null;\n\n requestRender();\n } catch (err) {\n const wasError = state.error !== null;\n state.error = (err as Error).message;\n if (!wasError) prevFrame = []; // force full redraw on error transition\n requestRender();\n }\n }\n\n // ── Render function ──────────────────────────────────────────────────────────\n\n function render(): void {\n const stdoutRows = process.stdout.rows;\n const stdoutCols = process.stdout.columns;\n state.rows = (typeof stdoutRows === 'number' && stdoutRows > 0) ? stdoutRows : 24;\n state.cols = (typeof stdoutCols === 'number' && stdoutCols > 0) ? stdoutCols : 80;\n\n const buf = createFrameBuffer(state.cols, state.rows);\n\n // Terminal too small\n if (state.cols < 60 || state.rows < 12) {\n writeCenter(buf, Math.floor(state.rows / 2), 'Terminal too small — resize to continue');\n const out = flushFrame(buf.lines, prevFrame);\n writeToStdout(out);\n prevFrame = buf.lines;\n return;\n }\n\n // Detect resolution mode transition → force full redraw (CLAUDE.md cache-pair invariant)\n if (state.resolutionActive !== prevResolutionActive) {\n prevFrame = [];\n prevResolutionActive = state.resolutionActive;\n }\n\n // Resolution mode full-screen takeover (3e)\n if (state.resolutionActive && state.resolutionHandle) {\n renderResolutionFrame(buf, state);\n const out = flushFrame(buf.lines, prevFrame, '\\x1b[0 q\\x1b[?25l');\n writeToStdout(out);\n prevFrame = buf.lines;\n return;\n }\n\n // Compute layout\n const treeWidth = computeTreeWidth(state.cols);\n const remaining = state.cols - treeWidth;\n const detailWidth = Math.floor(remaining * 0.6);\n const digestWidth = remaining - detailWidth;\n const contentHeight = state.rows - 1;\n\n const treeRect = { x: 0, y: 0, w: treeWidth, h: contentHeight };\n const detailRect = { x: treeWidth, y: 0, w: detailWidth, h: contentHeight };\n const digestRect = { x: treeWidth + detailWidth, y: 0, w: digestWidth, h: contentHeight };\n const bottomY = contentHeight;\n\n // Derive data\n const filteredSessions: SessionSummary[] = state.searchFilter\n ? state.sessions.filter((s) => {\n const q = state.searchFilter!.toLowerCase();\n return s.task.toLowerCase().includes(q) || s.id.toLowerCase().includes(q);\n })\n : state.sessions;\n\n const statusFP = filteredSessions.map(s => `${s.status}:${s.windowAlive}:${s.runningAgentCount}:${s.orphaned ?? false}`).join(',');\n const inboxFP = `${state.aggregateInbox.length}:${state.aggregateInbox.map(i => i.askId).join(',')}`;\n const cacheKey = `${state.expanded.size}:${filteredSessions.length}:${state.selectedSession?.id}:${state.contextFiles.length}:${state.searchFilter}:${statusFP}:${inboxFP}`;\n let nodes: TreeNode[];\n if (cacheKey === state.treeCacheKey && state.cachedTreeNodes !== null) {\n nodes = state.cachedTreeNodes;\n } else {\n nodes = buildTree(\n filteredSessions,\n state.selectedSession,\n state.expanded,\n state.cwd,\n state.contextFiles,\n state.aggregateInbox,\n );\n precomputePrefixes(nodes);\n state.cachedTreeNodes = nodes;\n state.treeCacheKey = cacheKey;\n }\n\n // Cursor stabilization\n stabilizeCursor(state, nodes);\n\n // Cache latest nodes for keypress handler\n latestNodes = nodes;\n\n // Track cursor node identity\n const cursorNode = nodes[state.cursorIndex];\n if (cursorNode) state.cursorNodeId = cursorNode.id;\n\n // Derive selectedSessionId from cursor\n // section and needs-you-virtual nodes have sessionId === '' — treat as null\n const rawSessionId = cursorNode?.sessionId;\n const newSessionId = rawSessionId ? rawSessionId : null;\n if (newSessionId !== state.selectedSessionId) {\n state.selectedSessionId = newSessionId;\n state.detailScroll.reset();\n state.digestScroll.reset();\n state.cachedDetailLines = null;\n state.detailCacheKey = '';\n state.cachedDigestLines = null;\n state.digestCacheKey = '';\n state.cachedInboxLines = null;\n state.inboxCacheKey = '';\n state.crossSessionInboxScroll.reset();\n state.flowExpanded = false;\n state.goalScroll.reset();\n state.strategyScroll.reset();\n state.roadmapScroll.reset();\n state.cachedStackedLines = null;\n state.stackedCacheKey = '';\n state.detailMode = 'gsr';\n state.focusedStrip = 'roadmap';\n }\n\n // Override detailMode when cursor is on the virtual fleet-inbox node\n if (cursorNode?.type === 'needs-you-virtual') {\n state.detailMode = 'cross-session-inbox';\n } else if (state.detailMode === 'cross-session-inbox') {\n state.detailMode = 'gsr';\n }\n\n // Trigger debounced poll when session changes (avoids poll storm during rapid scrolling)\n if (state.selectedSessionId !== prevSelectedSessionId) {\n prevSelectedSessionId = state.selectedSessionId;\n if (debouncedPollTimer !== null) clearTimeout(debouncedPollTimer);\n if (state.selectedSessionId !== null) {\n debouncedPollTimer = setTimeout(() => {\n debouncedPollTimer = null;\n void poll();\n }, 80);\n }\n }\n\n // Auto-expand cycle\n autoExpandCycle(state);\n\n // Resolve reports for detail panel\n const agents = state.selectedSession?.agents ?? [];\n const reportAgent =\n state.mode === 'report-detail' ? getAgentForNode(cursorNode, agents) : null;\n const reportBlocks = reportAgent ? (state.cachedReportBlocks.get(reportAgent.id) ?? []) : [];\n\n const detailAgent =\n cursorNode?.type === 'agent' || cursorNode?.type === 'report'\n ? getAgentForNode(cursorNode, agents)\n : null;\n const detailReportBlocks = detailAgent\n ? (state.cachedReportBlocks.get(detailAgent.id) ?? [])\n : [];\n\n // Load context file content (cached to avoid re-read on every render)\n let contextFileContent: string | null = null;\n if (cursorNode?.type === 'context-file') {\n if (cursorNode.filePath !== cachedContextFilePath) {\n cachedContextFilePath = cursorNode.filePath;\n try {\n if (existsSync(cursorNode.filePath)) {\n cachedContextFileContent = readFileSync(cursorNode.filePath, 'utf-8');\n } else {\n cachedContextFileContent = null;\n }\n } catch {\n cachedContextFileContent = null;\n }\n }\n contextFileContent = cachedContextFileContent;\n } else {\n // Clear cache when cursor moves away\n cachedContextFilePath = null;\n cachedContextFileContent = null;\n }\n\n // Panel dirty tracking — compute fingerprints for each panel's inputs\n const treeFocused = state.mode === 'navigate' && state.focusPane === 'tree';\n const treeInputs = `${state.treeCacheKey}:${state.cursorIndex}:${treeFocused}`;\n const bottomInputs = `${state.notification}:${state.error}:${state.mode}:${state.searchText}:${cursorNode?.type}`;\n const overlayMode = (state.mode === 'leader' || state.mode === 'copy-menu' || state.mode === 'open-menu' || state.mode === 'agent-menu' || state.mode === 'session-menu' || state.mode === 'go-menu' || state.mode === 'companion-menu' || state.mode === 'help' || state.mode === 'companion-overlay' || state.mode === 'companion-debug') ? state.mode : '';\n let companionFP = '';\n if (state.mode === 'companion-overlay' || state.mode === 'companion-debug') {\n const c = getCompanion();\n const ts = c && c.lastCommentary ? c.lastCommentary.timestamp : '';\n const xp = c ? c.xp : 0;\n const dm = c?.debugMood ? `${c.debugMood.winner}:${c.debugMood.scores[c.debugMood.winner]}` : '';\n companionFP = `${ts}:${xp}:${dm}`;\n }\n const overlayInputs = `${overlayMode}:${companionFP}`;\n\n const hasPrev = prevFrame.length === buf.height;\n const treeDirty = !hasPrev || treeInputs !== prevTreeInputs;\n const bottomDirty = !hasPrev || bottomInputs !== prevBottomInputs;\n const overlayDirty = !hasPrev || overlayInputs !== prevOverlayMode;\n\n prevTreeInputs = treeInputs;\n prevBottomInputs = bottomInputs;\n prevOverlayMode = overlayInputs;\n\n // Render tree into a narrow buffer (treeWidth-wide) so rows are the right size\n // for concatenation. Cached when clean.\n let treeRows: string[];\n if (treeDirty) {\n const treeBlank = ' '.repeat(treeWidth);\n const treeBuf: import('./render.js').FrameBuffer = {\n lines: Array.from({ length: contentHeight }, () => treeBlank),\n width: treeWidth,\n height: contentHeight,\n };\n renderTreePanel(\n treeBuf,\n { x: 0, y: 0, w: treeWidth, h: contentHeight },\n nodes,\n state.cursorIndex,\n treeFocused,\n getCompanion(),\n );\n cachedTreeRows = treeBuf.lines;\n treeRows = treeBuf.lines;\n } else {\n treeRows = cachedTreeRows;\n }\n\n // Render detail + logs as self-contained row strings, then compose by concatenation.\n // This eliminates all sliceDisplayCols calls — the main scroll bottleneck.\n const detailCtx: DetailContext = {\n nodes,\n session: state.selectedSession,\n agents,\n reportBlocks,\n detailReportBlocks,\n contextFileContent,\n };\n\n let detailRows: string[];\n if (cursorNode?.type === 'needs-you-virtual') {\n detailRows = renderCrossSessionInboxRows(detailRect, state);\n } else if (state.useStackedDetail) {\n detailRows = renderStackedDetailRows(detailRect, state, detailCtx);\n } else {\n detailRows = renderDetailRows(detailRect, state, detailCtx);\n }\n const rightPanelRows = renderDigestRows(digestRect, state);\n\n // Compose panel rows into buffer by concatenation (no slicing/splicing)\n for (let i = 0; i < contentHeight; i++) {\n buf.lines[i] = treeRows[i]! + detailRows[i]! + rightPanelRows[i]!;\n }\n\n // Bottom row (single status line — notifications replace keybindings transiently)\n if (bottomDirty || overlayDirty) {\n renderStatusLine(buf, bottomY, state, cursorNode?.type);\n } else {\n copyRows(buf, prevFrame, bottomY, 1);\n }\n\n // Overlays (rendered AFTER panels — overwrites panel content)\n if (overlayMode) {\n const ACCENT: Record<string, string> = {\n topLevel: 'magenta',\n copy: 'cyan',\n open: 'green',\n agent: 'blue',\n session: 'red',\n go: 'yellow',\n companion: 'magenta',\n };\n const menuId = MENU_FOR_MODE[state.mode];\n if (menuId) {\n const menu = menuId === 'topLevel' ? KEYMAP.topLevel : KEYMAP.submenus[menuId]!;\n const accent = ACCENT[menuId];\n renderSubmenuOverlay(buf, state.rows, state.cols, menu, accent !== undefined ? accent : 'white');\n }\n if (state.mode === 'help') renderHelpOverlay(buf, state.rows, state.cols);\n if (state.mode === 'companion-overlay') {\n const companion = getCompanion();\n if (companion) renderCompanionOverlay(buf, state.rows, state.cols, companion);\n }\n if (state.mode === 'companion-debug') {\n const companion = getCompanion();\n if (companion) renderCompanionDebugOverlay(buf, state.rows, state.cols, companion);\n }\n }\n\n // Build cursor suffix inside synchronized output block to prevent flicker\n const cursorSuffix = '\\x1b[0 q\\x1b[?25l';\n\n // Flush diff to stdout with cursor positioning inside sync block\n const out = flushFrame(buf.lines, prevFrame, cursorSuffix);\n writeToStdout(out);\n prevFrame = buf.lines;\n }\n\n // ── InputActions ─────────────────────────────────────────────────────────────\n\n const inputActions: InputActions = {\n getNodes: () => latestNodes,\n getCursorNode: () => latestNodes[state.cursorIndex],\n getAgentForNode: (node) => {\n const agents = state.selectedSession?.agents ?? [];\n return getAgentForNode(node, agents);\n },\n sendAndNotify: (request, successMsg) => {\n void send(request)\n .then((res) => {\n if (res.ok) {\n notify(state, successMsg);\n } else {\n const errMsg = res.error ? res.error : 'Unknown error';\n notify(state, `Error: ${errMsg}`);\n }\n })\n .catch((err: Error) => {\n notify(state, `Error: ${err.message}`);\n });\n },\n send,\n composeViaPopup,\n openEditorPopup,\n editInPopup,\n promptInPopup,\n openCompanionPane,\n openClaudeResumePopup,\n openClaudeResumeSession,\n selectWindow,\n selectPane,\n switchToSession,\n paneExists,\n openLogPopup,\n openShellPopup,\n openInFileManager,\n copyToClipboard,\n buildSessionContext,\n resolveEditor: () => {\n if (config.editor) return config.editor;\n if (process.env.EDITOR) return process.env.EDITOR;\n return 'nvim';\n },\n cleanup: () => {\n cleanup();\n process.exit(0);\n },\n };\n\n // ── Wire everything together ─────────────────────────────────────────────────\n\n setRenderFunction(render);\n\n const stopKeypress = startKeypressListener((input, key) => {\n handleKeypress(input, key, state, inputActions);\n });\n\n const stopResize = onResize(() => {\n const stdoutRows = process.stdout.rows;\n const stdoutCols = process.stdout.columns;\n state.rows = (typeof stdoutRows === 'number' && stdoutRows > 0) ? stdoutRows : 24;\n state.cols = (typeof stdoutCols === 'number' && stdoutCols > 0) ? stdoutCols : 80;\n prevFrame = []; // force full redraw\n if (state.resolutionActive && state.resolutionHandle) {\n state.resolutionHandle.handleResize(state.cols, state.rows - 1);\n }\n requestRender();\n });\n\n // Initial poll + recurring interval\n void poll();\n const pollInterval = setInterval(() => void poll(), 2500);\n\n // Register teardown so cleanup() releases all resources\n const origCleanup = inputActions.cleanup;\n inputActions.cleanup = () => {\n clearInterval(pollInterval);\n if (debouncedPollTimer !== null) clearTimeout(debouncedPollTimer);\n stopKeypress();\n stopResize();\n state.resolutionHandle?.unmount();\n state.detailScroll.destroy();\n state.digestScroll.destroy();\n state.goalScroll.destroy();\n state.strategyScroll.destroy();\n state.roadmapScroll.destroy();\n origCleanup();\n };\n\n // Initial render\n requestRender();\n}\n","import { execSync } from 'node:child_process';\nimport { readFileSync, readdirSync, statSync } from 'node:fs';\nimport { join } from 'node:path';\nimport { exportSessionToZip } from '../shared/session-export.js';\nimport type { Key } from './terminal.js';\nimport {\n type AppState,\n type ComposeAction,\n OPTIONAL_COMPOSE,\n requestRender,\n notify,\n} from './state.js';\nimport type { TreeNode } from './types/tree.js';\nimport type { Agent, Session } from '../shared/types.js';\nimport type { Response } from '../shared/protocol.js';\nimport { sessionDir, goalPath, roadmapPath, strategyPath, reportsDir } from '../shared/paths.js';\nimport type { Request } from '../shared/protocol.js';\nimport { findParentIndex } from './lib/tree.js';\nimport { badgeGalleryLeft, badgeGalleryRight, closeBadgeGallery, companionOverlayNextPage, companionOverlayShowHelp, companionOverlayDismissHelp, getCompanionPage, badgeListScrollUp, badgeListScrollDown } from './panels/overlays.js';\nimport { enterResolutionMode } from './panels/mounted-humanloop.js';\nimport { KEYMAP, MENU_FOR_MODE } from '../shared/keymap.js';\nimport type { MenuItem } from '../shared/keymap.js';\n\n// ── Re-exported types (same definition, no React) ─────────────────────────────\n\nexport type LeaderAction =\n // already present\n | { type: 'enter-copy-menu' }\n | { type: 'copy-path' }\n | { type: 'copy-context' }\n | { type: 'copy-logs' }\n | { type: 'copy-session-id' }\n | { type: 'delete-session' }\n | { type: 'open-logs' }\n | { type: 'open-session-dir' }\n | { type: 'open-strategy' }\n | { type: 'open-roadmap' }\n | { type: 'search' }\n | { type: 'jump-to-session'; index: number }\n | { type: 'spawn-agent' }\n | { type: 'message-agent' }\n | { type: 'help' }\n | { type: 'companion-overlay' }\n | { type: 'companion-debug' }\n | { type: 'companion-pane' }\n | { type: 'enter-companion-menu' }\n | { type: 'shell-command' }\n | { type: 'jump-to-pane' }\n | { type: 'export-session' }\n | { type: 'kill' }\n | { type: 'quit' }\n | { type: 'dismiss' }\n // new submenu enters\n | { type: 'enter-open-menu' }\n | { type: 'enter-agent-menu' }\n | { type: 'enter-session-menu' }\n | { type: 'enter-go-menu' }\n // new copy variants\n | { type: 'copy-latest-report' }\n | { type: 'copy-agent-id' }\n // new open variants\n | { type: 'open-goal' }\n | { type: 'open-latest-report' }\n | { type: 'open-scratch' }\n | { type: 'edit-context-file' }\n // new agent variants\n | { type: 'restart-agent' }\n | { type: 'rerun-agent' }\n | { type: 'open-claude-agent' }\n | { type: 'tail-agent-logs' }\n | { type: 'kill-agent' }\n | { type: 'quick-spawn-explore' }\n | { type: 'quick-spawn-debug' }\n // new session variants\n | { type: 'new-session' }\n | { type: 'resume-session' }\n | { type: 'continue-session' }\n | { type: 'rollback' }\n | { type: 'kill-session' }\n | { type: 'go-to-window' }\n | { type: 'clone-session' }\n | { type: 'history' }\n // new go variants\n | { type: 'pick-session' }\n | { type: 'cycle-session' }\n | { type: 'reconnect' }\n // messaging / status\n | { type: 'message-orchestrator' }\n | { type: 'show-status' };\n\nexport interface KeybindingHandlers {\n onMoveUp: () => void;\n onMoveDown: () => void;\n onEnter: () => void;\n onLeft: () => void;\n onRight: () => void;\n onSpace: () => void;\n onTab: () => void;\n onMessage: () => void;\n onGoToWindow: () => void;\n onEditGoal: () => void;\n onNewSession: () => void;\n onClaude: () => void;\n onOpenPlan: () => void;\n onQuit: () => void;\n onReRun: () => void;\n onResume: () => void;\n onContinue: () => void;\n onRestartAgent: () => void;\n onRollback: () => void;\n onToggleLogs: () => void;\n onEdit: () => void;\n}\n\n// ── InputActions interface ─────────────────────────────────────────────────────\n\nexport interface InputActions {\n // Navigation context (computed by caller, passed in)\n getNodes: () => TreeNode[];\n getCursorNode: () => TreeNode | undefined;\n getAgentForNode: (node: TreeNode | undefined) => Agent | null;\n\n // Async daemon operations\n sendAndNotify: (request: Request, successMsg: string) => void;\n send: (request: Request) => Promise<Response>;\n\n // Editor/tmux operations (injected — input.ts must not import these directly)\n openEditorPopup: typeof import('./lib/tmux.js').openEditorPopup;\n editInPopup: typeof import('./lib/tmux.js').editInPopup;\n promptInPopup: typeof import('./lib/tmux.js').promptInPopup;\n openCompanionPane: typeof import('./lib/tmux.js').openCompanionPane;\n openClaudeResumePopup: typeof import('./lib/tmux.js').openClaudeResumePopup;\n openClaudeResumeSession: typeof import('./lib/tmux.js').openClaudeResumeSession;\n selectWindow: typeof import('./lib/tmux.js').selectWindow;\n selectPane: typeof import('./lib/tmux.js').selectPane;\n switchToSession: typeof import('./lib/tmux.js').switchToSession;\n paneExists: typeof import('./lib/tmux.js').paneExists;\n openLogPopup: typeof import('./lib/tmux.js').openLogPopup;\n openShellPopup: typeof import('./lib/tmux.js').openShellPopup;\n openInFileManager: typeof import('./lib/tmux.js').openInFileManager;\n copyToClipboard: typeof import('./lib/clipboard.js').copyToClipboard;\n buildSessionContext: typeof import('./lib/context.js').buildSessionContext;\n\n // Compose via tmux popup\n composeViaPopup: typeof import('./lib/popup-compose.js').composeViaPopup;\n\n // Config\n resolveEditor: () => string;\n\n // Lifecycle\n cleanup: () => void;\n}\n\n/**\n * Map compose action kinds to daemon requests.\n */\nexport function dispatchComposeAction(\n action: ComposeAction,\n content: string,\n state: AppState,\n actions: InputActions,\n): void {\n switch (action.kind) {\n case 'new-session':\n actions.sendAndNotify(\n { type: 'start', task: content, cwd: state.cwd },\n 'Session created',\n );\n break;\n\n case 'message-orchestrator':\n actions.sendAndNotify(\n { type: 'message', sessionId: action.sessionId, content },\n 'Message queued',\n );\n break;\n\n case 'resume':\n actions.sendAndNotify(\n { type: 'resume', sessionId: action.sessionId, cwd: state.cwd, message: content || undefined },\n 'Session resumed',\n );\n break;\n\n case 'continue':\n void (async () => {\n try {\n const contRes = await actions.send({ type: 'continue', sessionId: action.sessionId });\n if (!contRes.ok) { notify(state, `Error: ${contRes.error}`); return; }\n actions.sendAndNotify(\n { type: 'resume', sessionId: action.sessionId, cwd: state.cwd, message: content || undefined },\n 'Session continued',\n );\n } catch (err) {\n notify(state, `Error: ${(err as Error).message}`);\n }\n })();\n break;\n\n case 'spawn-agent':\n actions.sendAndNotify(\n {\n type: 'spawn',\n sessionId: action.sessionId,\n agentType: 'default',\n name: 'agent',\n instruction: content,\n },\n 'Agent spawned',\n );\n break;\n\n case 'message-agent':\n actions.sendAndNotify(\n { type: 'message', sessionId: action.sessionId, content, source: { type: 'agent', agentId: action.agentId } },\n `Message sent to ${action.agentId}`,\n );\n break;\n }\n}\n\n// ── Descriptor-driven dispatcher ──────────────────────────────────────────────\n\n// Maps submenu ref → the LeaderAction type that enters it\nconst ENTER_FOR_REF: Record<string, LeaderAction['type']> = {\n copy: 'enter-copy-menu',\n open: 'enter-open-menu',\n agent: 'enter-agent-menu',\n session: 'enter-session-menu',\n go: 'enter-go-menu',\n companion: 'enter-companion-menu',\n};\n\n// Maps tuiAction strings (from MenuItem.tuiAction) to LeaderAction types\nconst TUI_ACTION_FOR_NAME: Record<string, LeaderAction['type']> = {\n 'search': 'search',\n 'edit-context-file': 'edit-context-file',\n 'show-leader': 'help',\n 'companion-overlay': 'companion-overlay',\n 'companion-debug': 'companion-debug',\n 'companion-pane': 'companion-pane',\n};\n\n// Hand-maintained mapping from script/popup name → LeaderAction type.\n// The `satisfies` clause is the compile-time gate: any value not in LeaderAction['type']\n// fails the build immediately. Add a row here when a new descriptor item must\n// be handled in-process by the dashboard.\nconst TUI_HANDLERS = {\n 'sisyphus-copy-path': 'copy-path',\n 'sisyphus-copy-id': 'copy-session-id',\n 'sisyphus-copy-context': 'copy-context',\n 'sisyphus-copy-logs': 'copy-logs',\n 'sisyphus-copy-latest-report': 'copy-latest-report',\n 'sisyphus-copy-agent-id': 'copy-agent-id',\n 'sisyphus-open-goal': 'open-goal',\n 'sisyphus-open-roadmap': 'open-roadmap',\n 'sisyphus-open-strategy': 'open-strategy',\n 'sisyphus-open-logs': 'open-logs',\n 'sisyphus-open-dir': 'open-session-dir',\n 'sisyphus-open-latest-report': 'open-latest-report',\n 'sisyphus-open-scratch': 'open-scratch',\n 'sisyphus-spawn-agent': 'spawn-agent',\n 'sisyphus-msg-agent': 'message-agent',\n 'sisyphus-restart-agent-popup': 'restart-agent',\n 'sisyphus-rerun-agent': 'rerun-agent',\n 'sisyphus-jump-to-pane': 'jump-to-pane',\n 'sisyphus-open-claude-agent': 'open-claude-agent',\n 'sisyphus-tail-agent-logs': 'tail-agent-logs',\n 'sisyphus-kill-agent': 'kill-agent',\n 'sisyphus-quick-spawn-explore': 'quick-spawn-explore',\n 'sisyphus-quick-spawn-debug': 'quick-spawn-debug',\n 'sisyphus-new': 'new-session',\n 'sisyphus-resume-session': 'resume-session',\n 'sisyphus-continue-session': 'continue-session',\n 'sisyphus-rollback-session': 'rollback',\n 'sisyphus-kill-session': 'kill-session',\n 'sisyphus-delete-session': 'delete-session',\n 'sisyphus-export-session': 'export-session',\n 'sisyphus-go-to-window': 'go-to-window',\n 'sisyphus-clone-session': 'clone-session',\n 'sisyphus-history': 'history',\n 'sisyphus-pick-session': 'pick-session',\n 'sisyphus-cycle': 'cycle-session',\n 'sisyphus-reconnect': 'reconnect',\n 'sisyphus-help': 'help',\n 'sisyphus-home': 'cycle-session',\n 'sisyphus-msg': 'message-orchestrator',\n 'sisyphus-status-popup': 'show-status',\n 'sisyphus-kill-pane': 'kill',\n} as const satisfies Record<string, LeaderAction['type']>;\n\nfunction findLatestReport(cwd: string, sessionId: string): string | null {\n const dir = reportsDir(cwd, sessionId);\n try {\n const files = readdirSync(dir);\n if (files.length === 0) return null;\n let latestFile = files[0]!;\n let latestMtime = statSync(join(dir, latestFile)).mtimeMs;\n for (let i = 1; i < files.length; i++) {\n const m = statSync(join(dir, files[i]!)).mtimeMs;\n if (m > latestMtime) { latestMtime = m; latestFile = files[i]!; }\n }\n return join(dir, latestFile);\n } catch { return null; }\n}\n\nasync function goToSessionWindow(state: AppState, actions: InputActions): Promise<void> {\n const session = state.selectedSession;\n if (!session || !state.selectedSessionId) { notify(state, 'No session selected'); return; }\n\n if (session.status !== 'completed' && state.paneAlive && session.tmuxWindowId) {\n const switchTarget = session.tmuxSessionId ?? session.tmuxSessionName;\n if (switchTarget) actions.switchToSession(switchTarget);\n actions.selectWindow(session.tmuxWindowId);\n return;\n }\n\n // Pane appears dead but the tmux session may still exist with stale IDs\n // (window closed, daemon restarted, etc.) — try a daemon-side reconnect to\n // refresh tmuxSessionId/tmuxWindowId, then switch using the fresh IDs.\n // Falls through to a fresh `claude --resume` only if no tmux session by name exists.\n if (session.status !== 'completed') {\n const sessionId = state.selectedSessionId;\n const res = await actions.send({ type: 'reconnect', sessionId, cwd: state.cwd });\n if (res.ok) {\n const data = res.data ?? {};\n const tmuxName = (data['tmuxSessionName'] as string | undefined) ?? session.tmuxSessionName;\n const tmuxWin = data['tmuxWindowId'] as string | undefined;\n const tmuxId = data['tmuxSessionId'] as string | undefined;\n const switchTarget = tmuxId ?? tmuxName;\n if (switchTarget) actions.switchToSession(switchTarget);\n if (tmuxWin) actions.selectWindow(tmuxWin);\n notify(state, `Reconnected ${tmuxName ?? sessionId}`);\n return;\n }\n }\n\n const lastCycle = session.orchestratorCycles[session.orchestratorCycles.length - 1];\n const claudeSessionId = lastCycle?.claudeSessionId;\n if (!claudeSessionId) { notify(state, 'No orchestrator Claude session ID available'); return; }\n try {\n const label = session.name ?? state.selectedSessionId!.slice(0, 8);\n const sessionName = actions.openClaudeResumeSession(state.cwd, state.selectedSessionId!, claudeSessionId, label, lastCycle.resumeEnv, lastCycle.resumeArgs, lastCycle.cycle, lastCycle.mode);\n actions.switchToSession(sessionName);\n } catch {\n notify(state, 'Failed to open Claude session');\n }\n}\n\nfunction dispatchItem(item: MenuItem, state: AppState, actions: InputActions): void {\n if (item.action.type === 'submenu') {\n const t = ENTER_FOR_REF[item.action.ref];\n if (!t) return handleLeaderAction({ type: 'dismiss' }, state, actions);\n return handleLeaderAction({ type: t } as LeaderAction, state, actions);\n }\n if (item.tuiAction) {\n const t = TUI_ACTION_FOR_NAME[item.tuiAction];\n if (t) return handleLeaderAction({ type: t } as LeaderAction, state, actions);\n }\n if (item.action.type === 'tui') {\n const t = TUI_ACTION_FOR_NAME[item.action.action];\n if (t) return handleLeaderAction({ type: t } as LeaderAction, state, actions);\n notify(state, `No tui-action handler for ${item.action.action}`);\n return handleLeaderAction({ type: 'dismiss' }, state, actions);\n }\n if (item.action.type === 'script' || item.action.type === 'popup') {\n const t = TUI_HANDLERS[item.action.name as keyof typeof TUI_HANDLERS];\n if (t) return handleLeaderAction({ type: t } as LeaderAction, state, actions);\n notify(state, `No dashboard handler for ${item.action.name}`);\n return handleLeaderAction({ type: 'dismiss' }, state, actions);\n }\n // tmux-only items silently dismissed on dashboard\n handleLeaderAction({ type: 'dismiss' }, state, actions);\n}\n\n// ── Internal helpers ──────────────────────────────────────────────────────────\n\nfunction expandSessionLatestCycle(state: AppState, node: TreeNode): void {\n if (node.type === 'session' && state.selectedSession?.id === node.sessionId) {\n const cycles = state.selectedSession.orchestratorCycles;\n if (cycles.length > 0) {\n const latest = cycles[cycles.length - 1]!;\n state.expanded.add(`cycle:${node.sessionId}:${latest.cycle}`);\n }\n }\n}\n\n// ── handleReportDetailKey ─────────────────────────────────────────────────────\n\nfunction handleReportDetailKey(input: string, key: Key, state: AppState, _actions: InputActions): void {\n if (key.escape || key.return) {\n state.mode = 'navigate';\n requestRender();\n return;\n }\n if (key.upArrow) {\n state.detailScroll.scrollBy(-1);\n return;\n }\n if (key.downArrow) {\n state.detailScroll.scrollBy(1);\n return;\n }\n}\n\n// ── handleLeaderKey ───────────────────────────────────────────────────────────\n\nfunction handleLeaderAction(action: LeaderAction, state: AppState, actions: InputActions): void {\n const nodes = actions.getNodes();\n const cursorNode = actions.getCursorNode();\n const session = state.selectedSession;\n const selectedSessionId = state.selectedSessionId;\n const agents = session?.agents ?? [];\n\n switch (action.type) {\n case 'enter-copy-menu':\n state.mode = 'copy-menu';\n requestRender();\n return;\n\n case 'copy-path': {\n if (!selectedSessionId) { notify(state, 'No session selected'); break; }\n const path = sessionDir(state.cwd, selectedSessionId);\n try {\n actions.copyToClipboard(path);\n notify(state, `Copied path (${path})`);\n } catch {\n notify(state, 'Failed to copy to clipboard');\n }\n break;\n }\n\n case 'copy-context': {\n if (!selectedSessionId || !session) { notify(state, 'No session selected'); break; }\n try {\n const xml = actions.buildSessionContext(session, state.cwd);\n actions.copyToClipboard(xml);\n notify(state, `Copied context (${xml.length} chars)`);\n } catch {\n notify(state, 'Failed to copy context');\n }\n break;\n }\n\n case 'copy-logs': {\n if (!state.logsContent) { notify(state, 'No logs content'); break; }\n try {\n actions.copyToClipboard(state.logsContent);\n notify(state, `Copied logs (${state.logsContent.length} chars)`);\n } catch {\n notify(state, 'Failed to copy to clipboard');\n }\n break;\n }\n\n case 'copy-session-id': {\n if (!selectedSessionId) { notify(state, 'No session selected'); break; }\n try {\n actions.copyToClipboard(selectedSessionId);\n notify(state, `Copied session ID (${selectedSessionId})`);\n } catch {\n notify(state, 'Failed to copy to clipboard');\n }\n break;\n }\n\n case 'delete-session': {\n if (!selectedSessionId) { notify(state, 'No session selected'); break; }\n try {\n const text = actions.promptInPopup('Delete session? (yes/no):');\n if (text?.trim() === 'yes') {\n actions.sendAndNotify({ type: 'delete', sessionId: selectedSessionId, cwd: state.cwd }, 'Session deleted');\n } else {\n notify(state, 'Delete cancelled');\n }\n } catch {\n notify(state, 'Failed to open prompt');\n }\n break;\n }\n\n case 'open-logs': {\n try {\n actions.openLogPopup();\n } catch {\n notify(state, 'Failed to open log popup');\n }\n break;\n }\n\n case 'open-session-dir': {\n if (!selectedSessionId) { notify(state, 'No session selected'); break; }\n try {\n actions.openInFileManager(sessionDir(state.cwd, selectedSessionId));\n } catch {\n notify(state, 'Failed to open session directory');\n }\n break;\n }\n\n case 'open-strategy': {\n if (!selectedSessionId) { notify(state, 'No session selected'); break; }\n const editor = actions.resolveEditor();\n try {\n actions.openEditorPopup(state.cwd, editor, strategyPath(state.cwd, selectedSessionId));\n } catch {\n notify(state, 'Failed to open strategy');\n }\n break;\n }\n\n case 'open-roadmap': {\n if (!selectedSessionId) { notify(state, 'No session selected'); break; }\n const editor = actions.resolveEditor();\n try {\n actions.openEditorPopup(state.cwd, editor, roadmapPath(state.cwd, selectedSessionId));\n } catch {\n notify(state, 'Failed to open roadmap');\n }\n break;\n }\n\n case 'search': {\n state.mode = 'search';\n state.searchText = '';\n requestRender();\n return;\n }\n\n case 'jump-to-session': {\n let count = 0;\n for (let i = 0; i < nodes.length; i++) {\n if (nodes[i]?.type === 'session') {\n count++;\n if (count === action.index) {\n state.cursorIndex = i;\n state.cursorNodeId = nodes[i]!.id;\n break;\n }\n }\n }\n break;\n }\n\n case 'spawn-agent': {\n if (!selectedSessionId) { notify(state, 'No session selected'); break; }\n actions.composeViaPopup({ kind: 'spawn-agent', sessionId: selectedSessionId }, state, actions);\n break;\n }\n\n case 'message-agent': {\n const agent = actions.getAgentForNode(cursorNode);\n if (!agent) { notify(state, 'Cursor must be on an agent'); break; }\n actions.composeViaPopup({ kind: 'message-agent', sessionId: selectedSessionId!, agentId: agent.id }, state, actions);\n break;\n }\n\n case 'help':\n state.mode = 'help';\n requestRender();\n return;\n\n case 'enter-companion-menu':\n state.mode = 'companion-menu';\n requestRender();\n return;\n\n case 'companion-overlay':\n state.mode = 'companion-overlay';\n requestRender();\n return;\n\n case 'companion-debug':\n state.mode = 'companion-debug';\n requestRender();\n return;\n\n case 'companion-pane':\n try {\n actions.openCompanionPane(state.cwd);\n } catch {\n notify(state, 'Failed to open companion pane');\n }\n return;\n\n case 'shell-command': {\n if (!selectedSessionId) { notify(state, 'No session selected'); break; }\n try {\n const text = actions.promptInPopup('$', { w: '80%' });\n if (text?.trim()) {\n actions.openShellPopup(state.cwd, text.trim());\n }\n } catch {\n notify(state, 'Failed to open prompt');\n }\n break;\n }\n\n case 'jump-to-pane': {\n const agent = actions.getAgentForNode(cursorNode);\n if (!agent?.paneId) { notify(state, 'Select an agent with an active pane'); break; }\n if (session?.tmuxSessionName) actions.switchToSession(session.tmuxSessionName);\n if (session?.tmuxWindowId) actions.selectWindow(session.tmuxWindowId);\n actions.selectPane(agent.paneId);\n break;\n }\n\n case 'export-session': {\n if (!selectedSessionId) { notify(state, 'No session selected'); break; }\n exportSessionToZip(selectedSessionId, state.cwd)\n .then(outputPath => notify(state, `Exported to ${outputPath}`))\n .catch(err => notify(state, `Export failed: ${(err as Error).message}`));\n break;\n }\n\n case 'kill': {\n if (!selectedSessionId) { notify(state, 'No session selected'); break; }\n const node = nodes[state.cursorIndex];\n if (node && (node.type === 'agent' || node.type === 'report')) {\n const agentId = node.agentId;\n const agent = agents.find((a) => a.id === agentId);\n if (agent?.status !== 'running') { notify(state, `Agent ${agentId} is not running`); break; }\n actions.sendAndNotify({ type: 'kill-agent', sessionId: selectedSessionId, agentId }, `Killed ${agentId}`);\n } else {\n actions.sendAndNotify({ type: 'kill', sessionId: selectedSessionId }, 'Session killed');\n }\n break;\n }\n\n case 'quit':\n actions.cleanup();\n return;\n\n case 'enter-open-menu':\n state.mode = 'open-menu';\n requestRender();\n return;\n\n case 'enter-agent-menu':\n state.mode = 'agent-menu';\n requestRender();\n return;\n\n case 'enter-session-menu':\n state.mode = 'session-menu';\n requestRender();\n return;\n\n case 'enter-go-menu':\n state.mode = 'go-menu';\n requestRender();\n return;\n\n case 'copy-latest-report': {\n if (!selectedSessionId) { notify(state, 'No session selected'); break; }\n const latest = findLatestReport(state.cwd, selectedSessionId);\n if (!latest) { notify(state, 'No reports found'); break; }\n try {\n const content = readFileSync(latest, 'utf-8');\n actions.copyToClipboard(content);\n notify(state, `Copied latest report (${content.length} chars)`);\n } catch {\n notify(state, 'Failed to copy report');\n }\n break;\n }\n\n case 'copy-agent-id': {\n const agent = actions.getAgentForNode(cursorNode);\n if (!agent) { notify(state, 'Cursor must be on an agent'); break; }\n try {\n actions.copyToClipboard(agent.id);\n notify(state, `Copied agent ID (${agent.id})`);\n } catch {\n notify(state, 'Failed to copy to clipboard');\n }\n break;\n }\n\n case 'open-goal': {\n if (!selectedSessionId) { notify(state, 'No session selected'); break; }\n const editor = actions.resolveEditor();\n try {\n actions.openEditorPopup(state.cwd, editor, goalPath(state.cwd, selectedSessionId));\n } catch {\n notify(state, 'Failed to open goal');\n }\n break;\n }\n\n case 'open-latest-report': {\n if (!selectedSessionId) { notify(state, 'No session selected'); break; }\n const latest = findLatestReport(state.cwd, selectedSessionId);\n if (!latest) { notify(state, 'No reports found'); break; }\n const editor = actions.resolveEditor();\n try {\n actions.openEditorPopup(state.cwd, editor, latest);\n } catch {\n notify(state, 'Failed to open report');\n }\n break;\n }\n\n case 'open-scratch': {\n if (!selectedSessionId) { notify(state, 'No session selected'); break; }\n const editor = actions.resolveEditor();\n try {\n actions.openEditorPopup(state.cwd, editor, join(sessionDir(state.cwd, selectedSessionId), 'scratch.md'));\n } catch {\n notify(state, 'Failed to open scratch');\n }\n break;\n }\n\n case 'edit-context-file': {\n if (!cursorNode || cursorNode.type !== 'context-file') { notify(state, 'Cursor must be on a context file'); break; }\n const editor = actions.resolveEditor();\n try {\n actions.openEditorPopup(state.cwd, editor, cursorNode.filePath);\n } catch {\n notify(state, 'Failed to open file in editor');\n }\n break;\n }\n\n case 'restart-agent': {\n const agent = actions.getAgentForNode(cursorNode);\n if (!agent || !selectedSessionId) { notify(state, 'Select an agent to restart'); break; }\n actions.sendAndNotify(\n { type: 'restart-agent', sessionId: selectedSessionId, agentId: agent.id },\n `Restarted ${agent.id}`,\n );\n break;\n }\n\n case 'rerun-agent': {\n const agent = actions.getAgentForNode(cursorNode);\n if (!agent || !selectedSessionId) { notify(state, 'Select an agent to re-run'); break; }\n actions.sendAndNotify(\n {\n type: 'spawn',\n sessionId: selectedSessionId,\n agentType: agent.agentType,\n name: `${agent.name}-retry`,\n instruction: agent.instruction,\n },\n `Re-spawned ${agent.name}`,\n );\n break;\n }\n\n case 'open-claude-agent': {\n const agent = actions.getAgentForNode(cursorNode);\n if (!agent) { notify(state, 'Cursor must be on an agent'); break; }\n if (!agent.claudeSessionId) { notify(state, 'No Claude session ID available'); break; }\n try {\n actions.openClaudeResumePopup(state.cwd, agent.claudeSessionId, agent.resumeEnv, agent.resumeArgs);\n } catch {\n notify(state, 'Failed to open Claude session');\n }\n break;\n }\n\n case 'tail-agent-logs': {\n const agent = actions.getAgentForNode(cursorNode);\n if (!agent) { notify(state, 'Cursor must be on an agent'); break; }\n if (!agent.paneId) { notify(state, 'Agent has no active pane'); break; }\n try {\n actions.openShellPopup(state.cwd, `tmux capture-pane -t ${agent.paneId} -p -S -2000 | less +G`);\n } catch {\n notify(state, 'Failed to open logs');\n }\n break;\n }\n\n case 'kill-agent': {\n const agent = actions.getAgentForNode(cursorNode);\n if (!agent || !selectedSessionId) { notify(state, 'Select an agent to kill'); break; }\n if (agent.status !== 'running') { notify(state, `Agent ${agent.id} is not running`); break; }\n actions.sendAndNotify({ type: 'kill-agent', sessionId: selectedSessionId, agentId: agent.id }, `Killed ${agent.id}`);\n break;\n }\n\n case 'quick-spawn-explore': {\n if (!selectedSessionId) { notify(state, 'No session selected'); break; }\n let exploreInstruction: string;\n try {\n exploreInstruction = execSync('pbpaste', { stdio: ['pipe', 'pipe', 'pipe'] }).toString().trim();\n } catch {\n notify(state, 'pbpaste not available — macOS only');\n break;\n }\n if (exploreInstruction.length < 20) {\n notify(state, `Clipboard too short (${exploreInstruction.length} chars; need 20+)`);\n break;\n }\n actions.sendAndNotify(\n { type: 'spawn', sessionId: selectedSessionId, agentType: 'sisyphus:explore', name: `explore-${Date.now()}`, instruction: exploreInstruction },\n 'Explore agent spawned',\n );\n break;\n }\n\n case 'quick-spawn-debug': {\n if (!selectedSessionId) { notify(state, 'No session selected'); break; }\n let debugInstruction: string;\n try {\n debugInstruction = execSync('pbpaste', { stdio: ['pipe', 'pipe', 'pipe'] }).toString().trim();\n } catch {\n notify(state, 'pbpaste not available — macOS only');\n break;\n }\n if (debugInstruction.length < 20) {\n notify(state, `Clipboard too short (${debugInstruction.length} chars; need 20+)`);\n break;\n }\n actions.sendAndNotify(\n { type: 'spawn', sessionId: selectedSessionId, agentType: 'sisyphus:debug', name: `debug-${Date.now()}`, instruction: debugInstruction },\n 'Debug agent spawned',\n );\n break;\n }\n\n case 'new-session': {\n actions.composeViaPopup({ kind: 'new-session' }, state, actions);\n break;\n }\n\n case 'resume-session': {\n if (!selectedSessionId) { notify(state, 'No session selected'); break; }\n if (session?.status === 'active' && state.paneAlive) { notify(state, 'Session already active'); break; }\n actions.composeViaPopup({ kind: 'resume', sessionId: selectedSessionId }, state, actions);\n break;\n }\n\n case 'continue-session': {\n if (!selectedSessionId) { notify(state, 'No session selected'); break; }\n if (session?.status !== 'completed') { notify(state, 'Session not completed'); break; }\n actions.composeViaPopup({ kind: 'continue', sessionId: selectedSessionId }, state, actions);\n break;\n }\n\n case 'rollback': {\n if (!selectedSessionId) { notify(state, 'No session selected'); break; }\n try {\n const text = actions.promptInPopup('Rollback to cycle:');\n if (text?.trim()) {\n const toCycle = parseInt(text.trim(), 10);\n if (isNaN(toCycle) || toCycle < 1) { notify(state, 'Invalid cycle number'); break; }\n actions.sendAndNotify(\n { type: 'rollback', sessionId: selectedSessionId, cwd: state.cwd, toCycle },\n `Rolled back to cycle ${toCycle} — use [R]esume to respawn`,\n );\n }\n } catch {\n notify(state, 'Failed to open prompt');\n }\n break;\n }\n\n case 'kill-session': {\n if (!selectedSessionId) { notify(state, 'No session selected'); break; }\n actions.sendAndNotify({ type: 'kill', sessionId: selectedSessionId }, 'Session killed');\n break;\n }\n\n case 'go-to-window': {\n void goToSessionWindow(state, actions);\n break;\n }\n\n case 'clone-session': {\n if (!selectedSessionId) { notify(state, 'No session selected'); break; }\n try {\n actions.openShellPopup(state.cwd, `sis session clone ${selectedSessionId}`);\n } catch {\n notify(state, 'Failed to open shell');\n }\n break;\n }\n\n case 'history': {\n try {\n actions.openShellPopup(state.cwd, 'sis admin history');\n } catch {\n notify(state, 'Failed to open shell');\n }\n break;\n }\n\n case 'pick-session': {\n try {\n actions.openShellPopup(state.cwd, 'sis pick-session');\n } catch {\n notify(state, 'Failed to open shell');\n }\n break;\n }\n\n case 'cycle-session': {\n try {\n actions.openShellPopup(state.cwd, 'sis cycle');\n } catch {\n notify(state, 'Failed to open shell');\n }\n break;\n }\n\n case 'reconnect': {\n try {\n actions.openShellPopup(state.cwd, 'sis session reconnect');\n } catch {\n notify(state, 'Failed to open shell');\n }\n break;\n }\n\n case 'message-orchestrator': {\n if (!selectedSessionId) { notify(state, 'No session selected'); break; }\n actions.composeViaPopup({ kind: 'message-orchestrator', sessionId: selectedSessionId }, state, actions);\n break;\n }\n\n case 'show-status': {\n try {\n actions.openShellPopup(state.cwd, `sis status${selectedSessionId ? ` ${selectedSessionId}` : ''}`);\n } catch {\n notify(state, 'Failed to open status');\n }\n break;\n }\n\n case 'dismiss':\n closeBadgeGallery();\n break;\n }\n\n state.mode = 'navigate';\n requestRender();\n}\n\nfunction handleOverlayKey(input: string, key: Key, state: AppState, actions: InputActions): void {\n if (state.mode === 'help') {\n if (key.escape || input === '?') { handleLeaderAction({ type: 'dismiss' }, state, actions); }\n // any other key: ignore\n return;\n }\n\n if (state.mode === 'companion-overlay') {\n if (input === '?') {\n if (getCompanionPage() === 'help') companionOverlayDismissHelp();\n else companionOverlayShowHelp();\n requestRender(); return;\n }\n if (key.escape) {\n if (getCompanionPage() === 'help') { companionOverlayDismissHelp(); requestRender(); return; }\n handleLeaderAction({ type: 'dismiss' }, state, actions); return;\n }\n if (key.tab) { companionOverlayNextPage(); requestRender(); return; }\n if (getCompanionPage() === 'badges') {\n if (key.upArrow || input === 'k') { badgeGalleryLeft(); requestRender(); return; }\n if (key.downArrow || input === 'j') { badgeGalleryRight(); requestRender(); return; }\n if (key.leftArrow || input === 'h') { badgeListScrollUp(); requestRender(); return; }\n if (key.rightArrow || input === 'l') { badgeListScrollDown(); requestRender(); return; }\n }\n // any other key: ignore\n return;\n }\n\n if (state.mode === 'companion-debug') {\n handleLeaderAction({ type: 'dismiss' }, state, actions);\n }\n}\n\nfunction handleLeaderKey(input: string, key: Key, state: AppState, actions: InputActions): void {\n // Overlay modes (help, companion-overlay, companion-debug) are not in KEYMAP\n if (state.mode === 'help' || state.mode === 'companion-overlay' || state.mode === 'companion-debug') {\n return handleOverlayKey(input, key, state, actions);\n }\n\n if (key.escape) { handleLeaderAction({ type: 'dismiss' }, state, actions); return; }\n\n const menuId = MENU_FOR_MODE[state.mode];\n if (!menuId) return;\n\n const menu = menuId === 'topLevel' ? KEYMAP.topLevel : KEYMAP.submenus[menuId]!;\n const item = menu.items.find(i => i.key === input);\n if (!item) {\n // Digit 1-9: jump to session — only at top level\n if (state.mode === 'leader') {\n const digit = parseInt(input, 10);\n if (digit >= 1 && digit <= 9) {\n handleLeaderAction({ type: 'jump-to-session', index: digit }, state, actions);\n return;\n }\n }\n handleLeaderAction({ type: 'dismiss' }, state, actions);\n return;\n }\n dispatchItem(item, state, actions);\n}\n\n// Returns the scroll object that j/k should drive when detail pane is focused in stacked mode,\n// or null when the caller should fall through to normal tree/logs scroll logic.\nfunction getActiveDetailScroll(state: AppState) {\n if (state.focusPane !== 'detail' || !state.useStackedDetail) return null;\n if (state.detailMode === 'cycle-log') return state.detailScroll;\n return state.focusedStrip === 'goal' ? state.goalScroll\n : state.focusedStrip === 'strategy' ? state.strategyScroll\n : state.roadmapScroll;\n}\n\n// ── handleResolutionKey ───────────────────────────────────────────────────────\n// Layered-key precedence (load-bearing — see src/tui/CLAUDE.md):\n// 1. esc always wins (even mid comment-buffer)\n// 2. Shift+J/K queue walk, gated by canAcceptHostKeys\n// 3. space/R visual gen/toggle, gated by canAcceptHostKeys\n// 4. fall-through to humanloop\n\nfunction handleResolutionKey(input: string, key: Key, state: AppState, actions: InputActions): void {\n const handle = state.resolutionHandle;\n if (!handle) return;\n\n // 1. esc → exit resolution mode (always wins)\n if (key.escape) {\n handle.unmount();\n return;\n }\n\n // 2. Shift+J / Shift+K → queue walk (only when humanloop can accept host keys)\n if (input === 'J' && handle.canAcceptHostKeys()) {\n handle.advanceQueue(+1);\n return;\n }\n if (input === 'K' && handle.canAcceptHostKeys()) {\n handle.advanceQueue(-1);\n return;\n }\n\n // 3. space → toggle visual / fire generation (gated)\n if (input === ' ' && handle.canAcceptHostKeys()) {\n handle.spaceVisualToggle();\n return;\n }\n\n // 4. R → force regenerate visual (gated)\n if (input === 'R' && handle.canAcceptHostKeys()) {\n handle.regenerateVisual();\n return;\n }\n\n // 5. Fall-through to humanloop\n handle.handleKey(input, key);\n requestRender();\n}\n\n// ── Focus cycle ───────────────────────────────────────────────────────────────\n// Tab / Shift-Tab walks an ordered list of focus stops. In stacked gsr mode,\n// the detail pane expands into three strip stops (goal/strategy/roadmap).\n\ntype FocusStop = {\n pane: AppState['focusPane'];\n strip?: AppState['focusedStrip'];\n};\n\nfunction focusCycle(state: AppState): FocusStop[] {\n const stops: FocusStop[] = [{ pane: 'tree' }];\n if (state.useStackedDetail && state.detailMode === 'gsr') {\n stops.push({ pane: 'detail', strip: 'goal' });\n stops.push({ pane: 'detail', strip: 'strategy' });\n stops.push({ pane: 'detail', strip: 'roadmap' });\n } else {\n stops.push({ pane: 'detail', ...(state.useStackedDetail ? { strip: 'goal' as const } : {}) });\n }\n stops.push({ pane: 'logs' });\n return stops;\n}\n\nfunction currentFocusIndex(stops: FocusStop[], state: AppState): number {\n const exact = stops.findIndex(\n (s) => s.pane === state.focusPane && (s.strip === undefined || s.strip === state.focusedStrip),\n );\n if (exact !== -1) return exact;\n const fuzzy = stops.findIndex((s) => s.pane === state.focusPane);\n return fuzzy === -1 ? 0 : fuzzy;\n}\n\n// ── handleNavigateKey ─────────────────────────────────────────────────────────\n\nfunction handleNavigateKey(input: string, key: Key, state: AppState, actions: InputActions): void {\n const nodes = actions.getNodes();\n const cursorNode = actions.getCursorNode();\n const session = state.selectedSession;\n\n // k / ↑\n if (key.upArrow || input === 'k') {\n const upScroll = getActiveDetailScroll(state);\n if (upScroll) {\n upScroll.scrollBy(-1);\n } else if (state.focusPane === 'detail') {\n state.detailScroll.scrollBy(-1);\n } else if (state.focusPane === 'logs') {\n state.digestScroll.scrollBy(-1);\n } else {\n state.cursorIndex = Math.max(0, state.cursorIndex - 1);\n state.cursorNodeId = nodes[state.cursorIndex]?.id ?? state.cursorNodeId;\n requestRender();\n }\n return;\n }\n\n // j / ↓\n if (key.downArrow || input === 'j') {\n const downScroll = getActiveDetailScroll(state);\n if (downScroll) {\n downScroll.scrollBy(1);\n } else if (state.focusPane === 'detail') {\n state.detailScroll.scrollBy(1);\n } else if (state.focusPane === 'logs') {\n state.digestScroll.scrollBy(1);\n } else {\n state.cursorIndex = Math.min(nodes.length - 1, state.cursorIndex + 1);\n state.cursorNodeId = nodes[state.cursorIndex]?.id ?? state.cursorNodeId;\n requestRender();\n }\n return;\n }\n\n // u / d — fast scroll (vim-style ½-page) for detail/log strips. Tree focus\n // intentionally ignores these so cursor navigation stays single-step (j/k).\n // Roughly half the visible terminal height, clamped to a sensible band so a\n // tiny terminal still moves and a tall one doesn't leap past the strip.\n if (input === 'u' || input === 'd') {\n const direction = input === 'u' ? -1 : 1;\n const fastStep = Math.max(5, Math.min(20, Math.floor(state.rows / 4))) * direction;\n const fastScroll = getActiveDetailScroll(state);\n if (fastScroll) {\n fastScroll.scrollBy(fastStep);\n return;\n }\n if (state.focusPane === 'detail') {\n state.detailScroll.scrollBy(fastStep);\n return;\n }\n if (state.focusPane === 'logs') {\n state.digestScroll.scrollBy(fastStep);\n return;\n }\n return;\n }\n\n // h / ←\n if (key.leftArrow || input === 'h') {\n if (state.focusPane === 'logs') {\n state.focusPane = 'detail';\n requestRender();\n return;\n }\n if (state.focusPane === 'detail') {\n state.focusPane = 'tree';\n requestRender();\n return;\n }\n const node = nodes[state.cursorIndex];\n if (!node) return;\n if (node.expanded) {\n state.expanded.delete(node.id);\n requestRender();\n } else {\n const parentIdx = findParentIndex(nodes, state.cursorIndex);\n if (parentIdx !== state.cursorIndex) {\n state.cursorIndex = parentIdx;\n state.cursorNodeId = nodes[parentIdx]?.id ?? state.cursorNodeId;\n requestRender();\n }\n }\n return;\n }\n\n // l / →\n if (key.rightArrow || input === 'l') {\n const node = nodes[state.cursorIndex];\n if (!node) return;\n // When stacked detail active and cursor is on an already-expanded session in tree focus,\n // toggle between gsr and cycle-log detail mode instead of moving into child.\n if (\n state.useStackedDetail &&\n state.focusPane === 'tree' &&\n node.type === 'session' &&\n node.expanded\n ) {\n state.detailMode = state.detailMode === 'gsr' ? 'cycle-log' : 'gsr';\n state.cachedStackedLines = null;\n state.stackedCacheKey = '';\n requestRender();\n return;\n }\n if (node.expandable && !node.expanded) {\n state.expanded.add(node.id);\n expandSessionLatestCycle(state, node);\n requestRender();\n } else if (node.expandable && node.expanded) {\n // Move cursor to first child\n if (state.cursorIndex + 1 < nodes.length && nodes[state.cursorIndex + 1]!.depth > node.depth) {\n state.cursorIndex += 1;\n state.cursorNodeId = nodes[state.cursorIndex]?.id ?? state.cursorNodeId;\n requestRender();\n }\n }\n return;\n }\n\n // tab / shift+tab: walk the focus cycle forward / backward\n if (key.tab) {\n const stops = focusCycle(state);\n const idx = currentFocusIndex(stops, state);\n const next = stops[(idx + (key.shift ? -1 : 1) + stops.length) % stops.length]!;\n state.focusPane = next.pane;\n if (next.strip) state.focusedStrip = next.strip;\n requestRender();\n return;\n }\n\n // space: enter leader mode\n if (input === ' ') {\n state.mode = 'leader';\n requestRender();\n return;\n }\n\n // enter: expand / report-detail / open context file / resolution mode\n if (key.return) {\n const node = nodes[state.cursorIndex];\n if (!node) return;\n if (node.type === 'needs-you-virtual') {\n const firstItem = state.aggregateInbox[0];\n if (firstItem) {\n enterResolutionMode(state, firstItem.askId, actions.send, async ({ sessionId, agentId, paneId }) => {\n const res = await actions.send({ type: 'status', sessionId });\n const sess = res.ok ? (res.data?.session as Session | undefined) : undefined;\n if (!sess) { notify(state, 'Session not found'); return; }\n if (paneId && actions.paneExists(paneId)) {\n if (sess.tmuxSessionName) actions.switchToSession(sess.tmuxSessionName);\n if (sess.tmuxWindowId) actions.selectWindow(sess.tmuxWindowId);\n actions.selectPane(paneId);\n return;\n }\n if (sess.tmuxSessionName) actions.switchToSession(sess.tmuxSessionName);\n notify(state, `Pane ${paneId ? paneId : '?'} is gone — agent ${agentId} cannot be taken over.`);\n });\n } else {\n notify(state, 'No pending asks');\n }\n } else if (node.expandable && !node.expanded) {\n state.expanded.add(node.id);\n expandSessionLatestCycle(state, node);\n requestRender();\n } else if (node.type === 'report') {\n state.targetAgentId = node.agentId;\n state.mode = 'report-detail';\n requestRender();\n } else if (node.type === 'context-file') {\n const editor = actions.resolveEditor();\n try {\n actions.openEditorPopup(state.cwd, editor, node.filePath);\n } catch {\n notify(state, 'Failed to open file in editor');\n }\n }\n return;\n }\n\n // m: message orchestrator\n if (input === 'm') {\n if (!state.selectedSessionId) { notify(state, 'No session selected'); return; }\n actions.composeViaPopup({ kind: 'message-orchestrator', sessionId: state.selectedSessionId }, state, actions);\n return;\n }\n\n // w: go to tmux window (or resume orchestrator Claude session if window is dead/completed)\n if (input === 'w') {\n void goToSessionWindow(state, actions);\n return;\n }\n\n // o: open/resume claude session for agent or orchestrator cycle\n if (input === 'o') {\n if (!cursorNode) { notify(state, 'No node selected'); return; }\n let claudeSessionId: string | undefined;\n let resumeEnv: string | undefined;\n let resumeArgs: string | undefined;\n if (cursorNode.type === 'agent' || cursorNode.type === 'report') {\n const agent = actions.getAgentForNode(cursorNode);\n claudeSessionId = agent?.claudeSessionId ?? undefined;\n resumeEnv = agent?.resumeEnv;\n resumeArgs = agent?.resumeArgs;\n } else if (cursorNode.type === 'cycle' && session) {\n const cycle = session.orchestratorCycles.find(c => c.cycle === cursorNode.cycleNumber);\n claudeSessionId = cycle?.claudeSessionId;\n resumeEnv = cycle?.resumeEnv;\n resumeArgs = cycle?.resumeArgs;\n }\n if (!claudeSessionId) { notify(state, 'No Claude session ID available'); return; }\n try {\n actions.openClaudeResumePopup(state.cwd, claudeSessionId, resumeEnv, resumeArgs);\n } catch {\n notify(state, 'Failed to open Claude session');\n }\n return;\n }\n\n // g: edit goal\n if (input === 'g') {\n if (!state.selectedSessionId) { notify(state, 'No session selected'); return; }\n const gp = goalPath(state.cwd, state.selectedSessionId);\n const editor = actions.resolveEditor();\n try {\n actions.openEditorPopup(state.cwd, editor, gp, { w: '80', h: '50%' });\n } catch {\n notify(state, `Failed to open goal in ${editor}`);\n }\n return;\n }\n\n // n: new session\n if (input === 'n') {\n actions.composeViaPopup({ kind: 'new-session' }, state, actions);\n return;\n }\n\n // c: open companion pane\n if (input === 'c') {\n try {\n actions.openCompanionPane(state.cwd);\n } catch {\n notify(state, 'Failed to open companion pane');\n }\n return;\n }\n\n // p: open plan/roadmap\n if (input === 'p') {\n if (!state.selectedSessionId) { notify(state, 'No session selected'); return; }\n const pp = roadmapPath(state.cwd, state.selectedSessionId);\n const editor = actions.resolveEditor();\n try {\n actions.openEditorPopup(state.cwd, editor, pp);\n } catch {\n notify(state, `Failed to open roadmap in ${editor}`);\n }\n return;\n }\n\n // q: quit\n if (input === 'q') {\n actions.cleanup();\n }\n\n // r: re-run agent\n if (input === 'r') {\n const agent = actions.getAgentForNode(cursorNode);\n if (!agent || !state.selectedSessionId) { notify(state, 'Select an agent to re-run'); return; }\n actions.sendAndNotify(\n {\n type: 'spawn',\n sessionId: state.selectedSessionId,\n agentType: agent.agentType,\n name: `${agent.name}-retry`,\n instruction: agent.instruction,\n },\n `Re-spawned ${agent.name}`,\n );\n return;\n }\n\n // R: resume session\n if (input === 'R') {\n if (!state.selectedSessionId) { notify(state, 'No session selected'); return; }\n if (session?.status === 'active' && state.paneAlive) { notify(state, 'Session already active'); return; }\n actions.composeViaPopup({ kind: 'resume', sessionId: state.selectedSessionId }, state, actions);\n return;\n }\n\n // C: continue session\n if (input === 'C') {\n if (!state.selectedSessionId) { notify(state, 'No session selected'); return; }\n if (session?.status !== 'completed') { notify(state, 'Session not completed'); return; }\n actions.composeViaPopup({ kind: 'continue', sessionId: state.selectedSessionId }, state, actions);\n return;\n }\n\n // x: restart agent\n if (input === 'x') {\n const agent = actions.getAgentForNode(cursorNode);\n if (!agent || !state.selectedSessionId) { notify(state, 'Select an agent to restart'); return; }\n actions.sendAndNotify(\n { type: 'restart-agent', sessionId: state.selectedSessionId, agentId: agent.id },\n `Restarted ${agent.id}`,\n );\n return;\n }\n\n // b: rollback to cycle\n if (input === 'b') {\n if (!state.selectedSessionId) { notify(state, 'No session selected'); return; }\n {\n const sessionId = state.selectedSessionId;\n try {\n const text = actions.promptInPopup('Rollback to cycle:');\n if (text?.trim()) {\n const toCycle = parseInt(text.trim(), 10);\n if (isNaN(toCycle) || toCycle < 1) { notify(state, 'Invalid cycle number'); return; }\n actions.sendAndNotify(\n { type: 'rollback', sessionId, cwd: state.cwd, toCycle },\n `Rolled back to cycle ${toCycle} — use [R]esume to respawn`,\n );\n }\n } catch {\n notify(state, 'Failed to open prompt');\n }\n }\n return;\n }\n\n // e: edit context file\n if (input === 'e') {\n if (!cursorNode || cursorNode.type !== 'context-file') return;\n const editor = actions.resolveEditor();\n try {\n actions.openEditorPopup(state.cwd, editor, cursorNode.filePath);\n } catch {\n notify(state, 'Failed to open file in editor');\n }\n return;\n }\n\n // S: edit strategy\n if (input === 'S') {\n if (!state.selectedSessionId) { notify(state, 'No session selected'); return; }\n const sp = strategyPath(state.cwd, state.selectedSessionId);\n const editor = actions.resolveEditor();\n try {\n actions.openEditorPopup(state.cwd, editor, sp);\n } catch {\n notify(state, `Failed to open strategy in ${editor}`);\n }\n return;\n }\n\n // F: toggle cycle flow expanded/collapsed\n if (input === 'F') {\n state.flowExpanded = !state.flowExpanded;\n state.cachedDetailLines = null;\n state.cachedDigestLines = null;\n state.cachedStackedLines = null;\n state.stackedCacheKey = '';\n requestRender();\n return;\n }\n\n // D: toggle DANGEROUS mode for the selected session (auto-accept default for every ask)\n if (input === 'D') {\n const sessionId = state.selectedSessionId;\n const session = state.selectedSession;\n if (!sessionId || !session) { notify(state, 'No session selected'); return; }\n const next = !(session.dangerousMode === true);\n session.dangerousMode = next;\n requestRender();\n void (async () => {\n try {\n const res = await actions.send({ type: 'set-dangerous-mode', sessionId, enabled: next });\n if (!res.ok) {\n if (state.selectedSession === session) session.dangerousMode = !next;\n notify(state, `Dangerous mode toggle failed: ${res.error}`);\n requestRender();\n return;\n }\n const flushed = (res.data?.['flushed'] as number | undefined) ?? 0;\n notify(state, next\n ? (flushed > 0 ? `DANGEROUS mode ON — ${flushed} pending ask(s) auto-resolved` : 'DANGEROUS mode ON')\n : 'DANGEROUS mode OFF');\n } catch (err) {\n if (state.selectedSession === session) session.dangerousMode = !next;\n notify(state, `Dangerous mode toggle failed: ${(err as Error).message}`);\n requestRender();\n }\n })();\n return;\n }\n\n // /: search (vim-like, direct from navigate)\n if (input === '/') {\n state.mode = 'search';\n state.searchText = '';\n requestRender();\n return;\n }\n\n}\n\n// ── handleSearchKey ──────────────────────────────────────────────────────────\n\nfunction handleSearchKey(input: string, key: Key, state: AppState): void {\n if (key.return) {\n // Lock in the current filter\n state.mode = 'navigate';\n requestRender();\n return;\n }\n\n if (key.escape) {\n // Clear filter and exit\n state.searchFilter = null;\n state.searchText = '';\n state.mode = 'navigate';\n requestRender();\n return;\n }\n\n if (key.backspace) {\n state.searchText = state.searchText.slice(0, -1);\n state.searchFilter = state.searchText || null;\n requestRender();\n return;\n }\n\n // Ignore control keys\n if (key.ctrl || key.meta || !input || input.length !== 1) return;\n\n state.searchText += input;\n state.searchFilter = state.searchText;\n requestRender();\n}\n\n// ── Main dispatch ─────────────────────────────────────────────────────────────\n\nexport function handleKeypress(input: string, key: Key, state: AppState, actions: InputActions): void {\n // Resolution mode intercepts all keys (before mode checks — esc always exits)\n if (state.resolutionActive) {\n handleResolutionKey(input, key, state, actions);\n return;\n }\n if (state.mode === 'search') {\n handleSearchKey(input, key, state);\n } else if (state.mode === 'leader' || state.mode === 'copy-menu' || state.mode === 'open-menu' || state.mode === 'agent-menu' || state.mode === 'session-menu' || state.mode === 'go-menu' || state.mode === 'companion-menu' || state.mode === 'help' || state.mode === 'companion-overlay' || state.mode === 'companion-debug') {\n handleLeaderKey(input, key, state, actions);\n } else if (state.mode === 'report-detail') {\n handleReportDetailKey(input, key, state, actions);\n } else {\n handleNavigateKey(input, key, state, actions);\n }\n}\n","import { execFile } from 'node:child_process';\nimport { promisify } from 'node:util';\nimport { existsSync, readFileSync, mkdirSync, symlinkSync, rmSync, writeFileSync } from 'node:fs';\nimport { homedir } from 'node:os';\nimport { join } from 'node:path';\nimport type { Session } from './types.js';\nimport { sessionDir, statePath, historySessionDir } from './paths.js';\n\nfunction sanitizeName(name: string): string {\n return name.replace(/[^a-zA-Z0-9-_]/g, '-').replace(/-+/g, '-').replace(/^-|-$/g, '').slice(0, 40);\n}\n\nfunction buildOutputPath(label: string, dir: string): string {\n const date = new Date().toISOString().slice(0, 10);\n mkdirSync(dir, { recursive: true });\n\n const base = `sisyphus-${label}-${date}`;\n let candidate = join(dir, `${base}.zip`);\n let counter = 1;\n while (existsSync(candidate)) {\n counter++;\n candidate = join(dir, `${base}-${counter}.zip`);\n }\n return candidate;\n}\n\nfunction generateGuide(): string {\n return `# Sisyphus Session Export\n\n## Quick Orientation\n\nStart with \\`session/state.json\\` for the full session state, or \\`history/session.json\\` for a compact summary with metrics.\n\n## session/\n\nProject-local session data — the orchestrator's working directory.\n\n### Top-level files\n- **state.json** — Complete session state: id, task, status, timing, and the full \\`agents[]\\` array (each agent has id, type, instruction, status, reports, Claude session ID, and resume args)\n- **goal.md** — The task description; updated if the goal evolves across phases\n- **initial-prompt.md** — Verbatim user input that started the session\n- **roadmap.md** — Orchestrator's working memory: current stage, exit criteria, active context files, next steps\n- **strategy.md** — Work breakdown: completed stages, current stage decomposition (concerns/phases), and what's ahead\n- **digest.json** — 4-field snapshot: \\`recentWork\\`, \\`unusualEvents\\`, \\`currentActivity\\`, \\`whatsNext\\`\n\n### Subdirectories\n\n**context/** — Research artifacts produced by agents and consumed by downstream agents\n- \\`explore-*.md\\` — Codebase exploration findings (key files, architecture notes)\n- \\`requirements*.md/json\\` — Feature requirements (structured + human-readable)\n- \\`design*.md/json\\` — Architecture specs, decision records, diagrams\n- \\`{agent-id}/plan*.md\\` — Implementation plans (tasks, files to touch, dependencies) — per plan-lead subdirectory\n- \\`e2e-recipe.md\\` — End-to-end validation steps\n- \\`review-*.md\\` — Code review findings (severity-ranked)\n- \\`completion-summary.md\\` — Final handoff document\n\n**logs/** — One \\`cycle-NNN.md\\` per orchestrator cycle. Each logs what happened, agents spawned, user decisions, and key findings.\n\n**prompts/** — Full agent configs, one set per agent:\n- \\`agent-NNN-system.md\\` — System prompt (instructions, tools, output format)\n- \\`agent-NNN-run.sh\\` — Executable bash script to resume the agent (contains env, CLI args, instruction)\n- \\`agent-NNN-plugin/\\` — Plugin directory (hooks, sub-agent configs)\n\n**reports/** — Agent deliverables:\n- \\`agent-NNN-final.md\\` — Final report (findings, implementation summary, or review results)\n- \\`agent-NNN-00N.md\\` — Interim progress reports (optional)\n\n**snapshots/** — Point-in-time checkpoints (\\`snapshots/cycle-N/\\`). Each contains state.json, roadmap.md, strategy.md, and logs/ as they were at that cycle boundary. Used for rollback.\n\n**.tui/** — Lightweight TUI render cache (cycle summaries for display). Regenerable; not primary data.\n\n## history/\n\nGlobal telemetry from the daemon — timing, events, and aggregate metrics.\n\n- **events.jsonl** — Newline-delimited JSON event stream. Each line: \\`{ ts, event, sessionId, data }\\`. Events include session-start, agent-spawned, agent-completed, cycle-boundary, signals-snapshot, session-end, etc. Complete audit trail.\n- **session.json** — Summary: id, name, task, status, timing (activeMs, wallClockMs, efficiency), agent/cycle counts, crash/rollback counts, completion report, and a compact agents array.\n`;\n}\n\nconst execFileAsync = promisify(execFile);\n\nexport async function exportSessionToZip(\n sessionId: string,\n cwd: string,\n options?: { reveal?: boolean; outputDir?: string }\n): Promise<string> {\n const reveal = options?.reveal ?? true;\n const sessDir = sessionDir(cwd, sessionId);\n const histDir = historySessionDir(sessionId);\n const sessExists = existsSync(sessDir);\n const histExists = existsSync(histDir);\n\n if (!sessExists && !histExists) {\n throw new Error(`No data found for session ${sessionId}`);\n }\n\n let label = sessionId.slice(0, 8);\n const stPath = statePath(cwd, sessionId);\n if (existsSync(stPath)) {\n try {\n const state = JSON.parse(readFileSync(stPath, 'utf-8')) as Session;\n if (state.name) {\n label = sanitizeName(state.name);\n }\n } catch { /* use short ID */ }\n }\n\n const dir = options?.outputDir ?? join(homedir(), 'Downloads');\n const outputPath = buildOutputPath(label, dir);\n const tmpDir = `/tmp/sisyphus-export-${sessionId.slice(0, 8)}-${Date.now()}`;\n\n try {\n mkdirSync(tmpDir, { recursive: true });\n\n writeFileSync(join(tmpDir, 'CLAUDE.md'), generateGuide(), 'utf-8');\n\n if (sessExists) {\n symlinkSync(sessDir, join(tmpDir, 'session'));\n }\n if (histExists) {\n symlinkSync(histDir, join(tmpDir, 'history'));\n }\n\n const parts = ['CLAUDE.md', sessExists ? 'session/' : '', histExists ? 'history/' : ''].filter(Boolean) as string[];\n await execFileAsync('zip', ['-rq', outputPath, ...parts], { cwd: tmpDir });\n } finally {\n rmSync(tmpDir, { recursive: true, force: true });\n }\n\n if (reveal) {\n try {\n await execFileAsync('open', ['-R', outputPath]);\n } catch { /* non-fatal if Finder fails */ }\n }\n\n return outputPath;\n}\n","import { join } from 'node:path';\nimport { messageSourceLabel } from './format.js';\nimport type {\n TreeNode,\n SectionTreeNode,\n NeedsYouVirtualTreeNode,\n SessionTreeNode,\n CycleTreeNode,\n AgentTreeNode,\n ReportTreeNode,\n MessagesTreeNode,\n MessageTreeNode,\n ContextTreeNode,\n ContextFileTreeNode,\n SectionKey,\n} from '../types/tree.js';\nimport type { Session } from '../../shared/types.js';\nimport type { SessionSummary } from '../state.js';\nimport type { AggregateInboxItem } from '../../shared/inbox-types.js';\nimport { contextDir } from '../../shared/paths.js';\n\n/** Sort priority: active+open=0, active+closed=1, paused+open=2, paused+closed=3, completed=4 */\nfunction sessionSortKey(s: SessionSummary): number {\n if (s.status === 'completed') return 4;\n // Use cached windowAlive from polling hook (avoids execSync in render path)\n const open = s.windowAlive ?? false;\n if (s.status === 'active') return open ? 0 : 1;\n // paused — goes in Running section (not Done)\n return open ? 2 : 3;\n}\n\nexport function buildTree(\n sessions: SessionSummary[],\n selectedSession: Session | null,\n expanded: Set<string>,\n cwd: string,\n polledContextFiles: string[] = [],\n aggregateInbox: AggregateInboxItem[] = [],\n): TreeNode[] {\n const nodes: TreeNode[] = [];\n\n // Build per-session inbox index\n const inboxBySession = new Map<string, AggregateInboxItem[]>();\n for (const item of aggregateInbox) {\n const arr = inboxBySession.get(item.sessionId) ?? [];\n arr.push(item);\n inboxBySession.set(item.sessionId, arr);\n }\n\n // Bucket sessions\n const needsYou: SessionSummary[] = [];\n const running: SessionSummary[] = [];\n const done: SessionSummary[] = [];\n for (const s of sessions) {\n if (inboxBySession.has(s.id)) needsYou.push(s);\n else if (s.status === 'completed') done.push(s);\n else running.push(s); // active + paused both land here\n }\n\n // Sort within each bucket\n needsYou.sort((a, b) => {\n const aItems = inboxBySession.get(a.id)!;\n const bItems = inboxBySession.get(b.id)!;\n const aOldest = Math.min(...aItems.map(i => Date.parse(i.blockedSince)));\n const bOldest = Math.min(...bItems.map(i => Date.parse(i.blockedSince)));\n return aOldest - bOldest;\n });\n running.sort((a, b) => {\n const k = sessionSortKey(a) - sessionSortKey(b);\n if (k !== 0) return k;\n return new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime();\n });\n // SessionSummary has no completedAt — sort done by createdAt descending\n done.sort((a, b) => Date.parse(b.createdAt) - Date.parse(a.createdAt));\n\n // Emit helpers\n function sectionExpanded(key: SectionKey): boolean {\n return expanded.has(`section:${key}`);\n }\n\n function emitSection(key: SectionKey, count: number): void {\n const exp = sectionExpanded(key);\n nodes.push({\n id: `section:${key}`,\n type: 'section',\n depth: 0,\n section: key,\n count,\n expandable: true,\n expanded: exp,\n sessionId: '',\n prefix: '',\n } satisfies SectionTreeNode);\n }\n\n function emitSessionChildren(s: SessionSummary): void {\n if (!selectedSession || selectedSession.id !== s.id) return;\n\n const cycles = [...selectedSession.orchestratorCycles].reverse();\n const allSpawnedIds = new Set(\n selectedSession.orchestratorCycles.flatMap((c) => c.agentsSpawned),\n );\n\n for (const cycle of cycles) {\n const cycleNodeId = `cycle:${s.id}:${cycle.cycle}`;\n const cycleExpanded = expanded.has(cycleNodeId);\n\n const cycleAgents = selectedSession.agents.filter((a) =>\n cycle.agentsSpawned.includes(a.id),\n );\n const isLatest = cycle === cycles[0];\n const unassigned = isLatest\n ? selectedSession.agents.filter((a) => !allSpawnedIds.has(a.id))\n : [];\n const allCycleAgents = [...cycleAgents, ...unassigned];\n\n nodes.push({\n id: cycleNodeId,\n type: 'cycle',\n depth: 2,\n expandable: allCycleAgents.length > 0,\n expanded: cycleExpanded,\n sessionId: s.id,\n cycleNumber: cycle.cycle,\n timestamp: cycle.timestamp,\n completedAt: cycle.completedAt,\n activeMs: cycle.activeMs,\n agentCount: allCycleAgents.length,\n mode: cycle.mode,\n } satisfies CycleTreeNode);\n\n if (!cycleExpanded) continue;\n\n for (const agent of allCycleAgents) {\n const agentNodeId = `agent:${s.id}:${agent.id}`;\n const hasReports = agent.reports.length > 0;\n const agentExpanded = expanded.has(agentNodeId);\n\n nodes.push({\n id: agentNodeId,\n type: 'agent',\n depth: 3,\n expandable: hasReports,\n expanded: agentExpanded && hasReports,\n sessionId: s.id,\n agentId: agent.id,\n name: agent.name,\n agentType: agent.agentType,\n status: agent.status,\n spawnedAt: agent.spawnedAt,\n completedAt: agent.completedAt,\n activeMs: agent.activeMs,\n reportCount: agent.reports.length,\n orphaned: agent.orphaned ?? false,\n } satisfies AgentTreeNode);\n\n if (!agentExpanded || !hasReports) continue;\n\n for (let ri = 0; ri < agent.reports.length; ri++) {\n const report = agent.reports[ri]!;\n nodes.push({\n id: `report:${s.id}:${agent.id}:${ri}`,\n type: 'report',\n depth: 4,\n expandable: false,\n expanded: false,\n sessionId: s.id,\n reportIndex: ri,\n reportType: report.type,\n timestamp: report.timestamp,\n agentId: agent.id,\n } satisfies ReportTreeNode);\n }\n }\n }\n\n // Messages group\n const messages = selectedSession.messages ?? [];\n if (messages.length > 0) {\n const msgsNodeId = `messages:${s.id}`;\n const msgsExpanded = expanded.has(msgsNodeId);\n\n nodes.push({\n id: msgsNodeId,\n type: 'messages',\n depth: 2,\n expandable: true,\n expanded: msgsExpanded,\n sessionId: s.id,\n count: messages.length,\n } satisfies MessagesTreeNode);\n\n if (msgsExpanded) {\n for (const msg of messages) {\n const agentId = msg.source.type === 'agent' ? msg.source.agentId : undefined;\n const sourceLabel = messageSourceLabel(msg.source.type, agentId);\n\n nodes.push({\n id: `message:${s.id}:${msg.id}`,\n type: 'message',\n depth: 3,\n expandable: false,\n expanded: false,\n sessionId: s.id,\n messageId: msg.id,\n source: sourceLabel,\n summary: msg.summary || msg.content,\n timestamp: msg.timestamp,\n } satisfies MessageTreeNode);\n }\n }\n }\n\n // Context group\n const isSelected = selectedSession?.id === s.id;\n const contextFiles = isSelected ? polledContextFiles : [];\n\n const ctxNodeId = `context:${s.id}`;\n const ctxExpanded = expanded.has(ctxNodeId);\n\n nodes.push({\n id: ctxNodeId,\n type: 'context',\n depth: 2,\n expandable: contextFiles.length > 0,\n expanded: ctxExpanded && contextFiles.length > 0,\n sessionId: s.id,\n fileCount: contextFiles.length,\n } satisfies ContextTreeNode);\n\n if (ctxExpanded && contextFiles.length > 0) {\n for (const filename of contextFiles) {\n nodes.push({\n id: `context-file:${s.id}:${filename}`,\n type: 'context-file',\n depth: 3,\n expandable: false,\n expanded: false,\n sessionId: s.id,\n label: filename,\n filePath: join(contextDir(cwd, s.id), filename),\n } satisfies ContextFileTreeNode);\n }\n }\n }\n\n function emitSessionRow(s: SessionSummary, askCount: number): void {\n const sessionNodeId = `session:${s.id}`;\n const isSelected = selectedSession?.id === s.id;\n const isExpanded = expanded.has(sessionNodeId);\n\n nodes.push({\n id: sessionNodeId,\n type: 'session',\n depth: 1,\n expandable: true,\n expanded: isExpanded && isSelected,\n sessionId: s.id,\n name: s.name,\n task: s.task,\n status: s.status,\n cycleCount: isSelected ? (selectedSession?.orchestratorCycles.length ?? 0) : 0,\n agentCount: s.agentCount,\n runningAgentCount: s.runningAgentCount,\n createdAt: s.createdAt,\n completedAt: isSelected ? selectedSession?.completedAt : undefined,\n activeMs: isSelected ? (selectedSession?.activeMs ?? s.activeMs) : s.activeMs,\n askCount: askCount > 0 ? askCount : undefined,\n orphaned: s.orphaned ?? false,\n } satisfies SessionTreeNode);\n\n if (isExpanded && isSelected) {\n emitSessionChildren(s);\n }\n }\n\n // Emit Needs You section\n emitSection('needs-you', needsYou.length);\n if (sectionExpanded('needs-you')) {\n nodes.push({\n id: 'needs-you-virtual',\n type: 'needs-you-virtual',\n depth: 1,\n expandable: false,\n expanded: false,\n sessionId: '',\n pendingCount: aggregateInbox.length,\n } satisfies NeedsYouVirtualTreeNode);\n for (const s of needsYou) {\n emitSessionRow(s, inboxBySession.get(s.id)?.length ?? 0);\n }\n }\n\n // Emit Running section\n emitSection('running', running.length);\n if (sectionExpanded('running')) {\n for (const s of running) {\n emitSessionRow(s, 0);\n }\n }\n\n // Emit Done section\n emitSection('done', done.length);\n if (sectionExpanded('done')) {\n for (const s of done) {\n emitSessionRow(s, 0);\n }\n }\n\n return nodes;\n}\n\n/** Find the parent node index for a given node index */\nexport function findParentIndex(nodes: TreeNode[], index: number): number {\n const node = nodes[index];\n if (!node || node.depth === 0) return index;\n const targetDepth = node.depth - 1;\n for (let i = index - 1; i >= 0; i--) {\n if (nodes[i]!.depth === targetDepth) return i;\n if (nodes[i]!.depth < targetDepth) return i;\n }\n return 0;\n}\n","import stringWidth from 'string-width';\n\nexport { formatDuration, statusColor } from '../../shared/format.js';\n\nexport function formatTimeAgo(iso: string): string {\n const diff = Date.now() - new Date(iso).getTime();\n const minutes = Math.floor(diff / 60000);\n const hours = Math.floor(minutes / 60);\n if (hours > 0) return `${hours}h ago`;\n if (minutes > 0) return `${minutes}m ago`;\n return 'just now';\n}\n\nexport function formatTime(iso: string): string {\n const d = new Date(iso);\n return `${d.getHours().toString().padStart(2, '0')}:${d.getMinutes().toString().padStart(2, '0')}`;\n}\n\nexport function truncate(text: string, max: number): string {\n // Collapse newlines and normalize wide emoji (see cleanMarkdown for rationale)\n const clean = text.replace(/\\n/g, ' ').replace(/✅/g, '✓').replace(/❌/g, '✗').replace(/\\p{Emoji_Presentation}/gu, '');\n if (max < 4) return clean.slice(0, max);\n const w = stringWidth(clean);\n if (w <= max) return clean;\n // Trim from the end until we fit, respecting display width\n let result = clean;\n while (stringWidth(result) > max - 1 && result.length > 0) {\n // Try to break at a word boundary\n const cut = result.lastIndexOf(' ', result.length - 2);\n if (cut > max * 0.4) {\n result = result.slice(0, cut);\n } else {\n result = result.slice(0, result.length - 1);\n }\n }\n return result + '…';\n}\n\n/** Strip markdown syntax to plain text */\nexport function stripMarkdown(text: string): string {\n return text\n .replace(/^#{1,6}\\s+/gm, '')\n .replace(/\\*\\*(.+?)\\*\\*/g, '$1')\n .replace(/\\*(.+?)\\*/g, '$1')\n .replace(/~~(.+?)~~/g, '$1')\n .replace(/`{1,3}[^`]*`{1,3}/g, '')\n .replace(/^[-*+]\\s+/gm, '')\n .replace(/^\\d+[.)]\\s+/gm, '')\n .replace(/\\[(.+?)\\]\\(.+?\\)/g, '$1')\n .replace(/^>\\s+/gm, '')\n .replace(/---+/g, '')\n .replace(/\\n+/g, ' ')\n .replace(/\\s+/g, ' ')\n .trim();\n}\n\n/**\n * Extract the first meaningful sentence from markdown-heavy text.\n * Much better than blind truncation — finds actual content.\n */\nexport function extractFirstSentence(text: string, maxLen: number): string {\n const lines = text.split('\\n');\n for (const line of lines) {\n const trimmed = line.trim();\n if (!trimmed) continue;\n if (trimmed.startsWith('#')) continue;\n if (trimmed.startsWith('---')) continue;\n if (trimmed.startsWith('```')) continue;\n if (trimmed.startsWith('|')) continue;\n if (trimmed.length < 5) continue;\n\n const cleaned = stripMarkdown(trimmed);\n if (cleaned.length < 5) continue;\n\n // Try to end at a sentence boundary\n const periodIdx = cleaned.indexOf('. ');\n if (periodIdx > 10 && periodIdx < maxLen) {\n return cleaned.slice(0, periodIdx + 1);\n }\n return truncate(cleaned, maxLen);\n }\n const fallback = stripMarkdown(text);\n return truncate(fallback, maxLen);\n}\n\nexport function durationColor(startOrMs: string | number, endIso?: string | null): string {\n let totalMs: number;\n if (typeof startOrMs === 'number') {\n totalMs = startOrMs;\n } else {\n const start = new Date(startOrMs).getTime();\n const end = endIso ? new Date(endIso).getTime() : Date.now();\n totalMs = end - start;\n }\n if (totalMs < 10 * 60 * 1000) return '';\n if (totalMs < 30 * 60 * 1000) return 'yellow';\n return 'red';\n}\n\nexport function statusIndicator(status: string): string {\n switch (status) {\n case 'active':\n return '▶';\n case 'completed':\n return '✓';\n case 'paused':\n return '⏸';\n default:\n return '·';\n }\n}\n\nexport function agentStatusIcon(status: string): string {\n switch (status) {\n case 'running':\n return '▶';\n case 'completed':\n return '✓';\n case 'killed':\n return '✕';\n case 'crashed':\n return '!';\n case 'lost':\n return '?';\n default:\n return '·';\n }\n}\n\nexport function agentTypeColor(agentType: string | undefined): string | undefined {\n if (!agentType) return undefined;\n const t = agentType.toLowerCase();\n if (t.includes('research')) return 'blue';\n if (t.includes('implement') || t.includes('code')) return 'green';\n if (t.includes('review') || t.includes('test')) return 'magenta';\n if (t.includes('plan')) return 'yellow';\n return undefined;\n}\n\nexport function divider(width: number, char: string = '─'): string {\n return char.repeat(Math.max(0, width));\n}\n\n/** Strip YAML frontmatter (--- ... ---) from markdown content */\nexport function stripFrontmatter(content: string): string {\n if (!content.startsWith('---')) return content;\n const end = content.indexOf('\\n---', 3);\n if (end === -1) return content;\n return content.slice(end + 4).trimStart();\n}\n\n/** Clean inline markdown syntax for terminal display */\nexport function cleanMarkdown(line: string): string {\n return line\n .replace(/\\*\\*(.+?)\\*\\*/g, '$1')\n .replace(/\\*(.+?)\\*/g, '$1')\n .replace(/~~(.+?)~~/g, '$1')\n .replace(/`(.+?)`/g, '$1')\n .replace(/\\[(.+?)\\]\\(.+?\\)/g, '$1')\n // Normalize wide emoji → single-width alternatives.\n // Ink's @alcalzone/ansi-tokenize treats emoji as width=1, but terminals\n // render them as width=2. This mismatch causes lines to overflow by 1\n // column, wrapping the right border to the next row (phantom blank lines).\n .replace(/✅/g, '✓')\n .replace(/❌/g, '✗')\n .replace(/\\p{Emoji_Presentation}/gu, '');\n}\n\n// Shared line types for scrollable panels\n\nexport type Seg = {\n text: string;\n color?: string;\n bold?: boolean;\n dim?: boolean;\n italic?: boolean;\n inverse?: boolean;\n strikethrough?: boolean;\n /** ANSI 38;2;R;G;B foreground tint (e.g. '38;2;226;217;198'). Wins over `color` when set. */\n fg?: string;\n /** ANSI 48;2;R;G;B background tint (e.g. '48;2;40;35;20') */\n bg?: string;\n};\n\nexport type DetailLine = Seg[];\n\nexport function seg(text: string, opts?: Partial<Omit<Seg, 'text'>>): Seg {\n return { text, ...opts };\n}\n\n/** Create a single-segment DetailLine */\nexport function singleLine(text: string, opts?: Partial<Omit<Seg, 'text'>>): DetailLine {\n return [seg(text, opts)];\n}\n\nexport function messageSourceLabel(source: string, agentId?: string): string {\n if (source === 'user') return 'You';\n if (source === 'agent') {\n if (!agentId) throw new Error('agentId required when source is agent');\n return agentId;\n }\n return 'system';\n}\n\nexport function messageSourceColor(source: string): string {\n if (source === 'user') return 'yellow';\n if (source === 'agent') return 'cyan';\n return 'gray';\n}\n\nexport function reportBadge(type: string): { label: string; color: string } {\n return type === 'final'\n ? { label: 'FINAL', color: 'cyan' }\n : { label: 'UPDATE', color: 'yellow' };\n}\n\nexport function agentDisplayName(agent: { name: string; id: string; agentType: string }): string {\n return agent.name !== agent.id ? agent.name : agent.agentType;\n}\n\nexport function abbreviateMode(mode: string | undefined | null): string {\n if (!mode) return '';\n if (mode === 'implementation') return 'impl';\n if (mode === 'planning') return 'plan';\n if (mode === 'discovery') return 'disc';\n if (mode === 'validation') return 'valid';\n return mode;\n}\n\nexport function ansiBold(text: string): string {\n return `\\x1b[1m${text}\\x1b[0m`;\n}\n\nexport function ansiDim(text: string): string {\n return `\\x1b[2m${text}\\x1b[0m`;\n}\n\nexport function ansiColor(text: string, color: string, bold = false): string {\n const COLOR_MAP: Record<string, number> = { black: 30, red: 31, green: 32, yellow: 33, blue: 34, magenta: 35, cyan: 36, white: 37, gray: 90 };\n const codes: number[] = [];\n if (bold) codes.push(1);\n const sgr = COLOR_MAP[color];\n if (sgr !== undefined) codes.push(sgr);\n if (codes.length === 0) return text;\n return `\\x1b[${codes.join(';')}m${text}\\x1b[0m`;\n}\n\nexport function modeColor(mode?: string): string {\n if (mode === 'planning') return 'blue';\n if (mode === 'implementation') return 'green';\n if (mode === 'discovery') return 'yellow';\n if (mode === 'validation') return 'magenta';\n return 'cyan';\n}\n\nexport function mergeStatusDisplay(status: string): { icon: string; label: string; color: string } | null {\n switch (status) {\n case 'merged': return { icon: '⊕', label: 'merged', color: 'green' };\n case 'pending': return { icon: '◌', label: 'pending', color: 'yellow' };\n case 'no-changes': return { icon: '∅', label: 'no changes', color: 'gray' };\n case 'conflict': return { icon: '⚠', label: 'conflict', color: 'red' };\n default: return null;\n }\n}\n\nexport function wrapText(text: string, width: number): string[] {\n const cleaned = cleanMarkdown(text);\n if (width <= 0) return cleaned.split('\\n');\n const result: string[] = [];\n for (const rawLine of cleaned.split('\\n')) {\n if (stringWidth(rawLine) <= width) {\n result.push(rawLine);\n continue;\n }\n\n // Single-pass: walk characters tracking cumulative display width\n let lineStart = 0;\n let lastSpace = -1;\n let displayWidth = 0;\n\n for (let i = 0; i < rawLine.length; i++) {\n const charWidth = stringWidth(rawLine[i]!);\n displayWidth += charWidth;\n\n if (rawLine[i] === ' ') lastSpace = i;\n\n if (displayWidth > width) {\n let breakAt: number;\n if (lastSpace > lineStart) {\n // Break at last space that fits\n breakAt = lastSpace;\n result.push(rawLine.slice(lineStart, breakAt));\n // Skip past the space and any leading spaces\n lineStart = breakAt + 1;\n while (lineStart < rawLine.length && rawLine[lineStart] === ' ') lineStart++;\n } else {\n // No space — hard break at previous char\n breakAt = Math.max(lineStart + 1, i);\n result.push(rawLine.slice(lineStart, breakAt));\n lineStart = breakAt;\n }\n\n // Recalculate display width for the carried-over portion\n displayWidth = stringWidth(rawLine.slice(lineStart, i + 1));\n lastSpace = -1;\n }\n }\n\n if (lineStart < rawLine.length) {\n result.push(rawLine.slice(lineStart));\n }\n }\n return result;\n}\n","/** Format milliseconds or ISO date range to human-readable duration */\nexport function formatDuration(startOrMs: string | number, endIso?: string | null): string {\n let totalMs: number;\n if (typeof startOrMs === 'number') {\n totalMs = startOrMs;\n } else {\n const start = new Date(startOrMs).getTime();\n const end = endIso ? new Date(endIso).getTime() : Date.now();\n totalMs = end - start;\n }\n const totalSeconds = Math.floor(totalMs / 1000);\n if (totalSeconds < 0) return '0s';\n const hours = Math.floor(totalSeconds / 3600);\n const minutes = Math.floor((totalSeconds % 3600) / 60);\n const seconds = totalSeconds % 60;\n if (hours > 0) return `${hours}h${minutes}m`;\n if (minutes > 0) return `${minutes}m${seconds}s`;\n return `${seconds}s`;\n}\n\n/** Map session/agent status to a color name */\nexport function statusColor(status: string): string {\n switch (status) {\n case 'active':\n case 'running':\n return 'green';\n case 'completed':\n return 'cyan';\n case 'paused':\n return 'yellow';\n case 'killed':\n case 'crashed':\n return 'red';\n case 'lost':\n return 'gray';\n default:\n return 'white';\n }\n}\n","import { drawBorder, writeClipped, type FrameBuffer } from '../render.js';\nimport { ansiColor, ansiDim, ansiBold } from '../lib/format.js';\nimport type { MenuDef } from '../../shared/keymap.js';\nimport type { CompanionState, AchievementDef, Mood } from '../../shared/companion-types.js';\nimport { getMoodFace } from '../../shared/companion-render.js';\nimport { computeLevelProgress } from '../../daemon/companion.js';\nimport { ACHIEVEMENTS } from '../../shared/companion-types.js';\nimport {\n createBadgeGallery,\n renderBadgeCard,\n galleryNext,\n galleryPrev,\n CARD_WIDTH,\n type BadgeGallery,\n} from '../../shared/companion-badges.js';\n\n// ─── Constants ────────────────────────────────────────────────────────────────\n\nconst HELP_WIDTH = 62;\nconst COMPANION_WIDTH = 52;\nconst DEBUG_WIDTH = 50;\n\n// ─── Helpers ──────────────────────────────────────────────────────────────────\n\nfunction helpRow(left: string, right: string, innerWidth: number): string {\n const col = Math.floor(innerWidth / 2);\n return (left.padEnd(col) + right).padEnd(innerWidth);\n}\n\n// ─── Overlays ─────────────────────────────────────────────────────────────────\n\nexport function renderSubmenuOverlay(\n buf: FrameBuffer,\n rows: number,\n cols: number,\n menu: MenuDef,\n accentColor: string,\n): void {\n const visibleItems = menu.items.filter(i => !i.hidden && i.action.type !== 'tmux');\n const title = menu.title.trim();\n\n // Width: max of title+padding, each item line, and the esc footer\n const maxLabelLen = Math.max(\n title.length + 2,\n ...visibleItems.map(i => i.label.trim().length + 5), // ' k trimmed-label'\n 13, // ' esc cancel'\n );\n const innerWidth = Math.min(maxLabelLen, 32);\n const totalWidth = innerWidth + 2;\n\n // Height: title + blank + items (clamped) + esc\n const contentCount = visibleItems.length;\n const totalHeight = contentCount + 4; // title + blank + items + esc + 2 borders = +4 inner rows\n const clampedHeight = Math.min(totalHeight, rows - 2);\n\n const x = cols - totalWidth - 1;\n const y = rows - clampedHeight - 2;\n\n drawBorder(buf, x, y, totalWidth, clampedHeight, accentColor);\n\n let row = 0;\n writeClipped(buf, x + 1, y + 1 + row, ansiColor(` ${title}`.padEnd(innerWidth), accentColor, true), innerWidth);\n row++;\n writeClipped(buf, x + 1, y + 1 + row, ' '.padEnd(innerWidth), innerWidth);\n row++;\n\n for (const item of visibleItems) {\n if (row >= clampedHeight - 2) break;\n const line = ` ${item.key} ${item.label.trim()}`.padEnd(innerWidth);\n writeClipped(buf, x + 1, y + 1 + row, line, innerWidth);\n row++;\n }\n\n if (row < clampedHeight - 1) {\n writeClipped(buf, x + 1, y + 1 + row, ansiDim(' esc cancel'.padEnd(innerWidth)), innerWidth);\n }\n}\n\nexport function renderHelpOverlay(buf: FrameBuffer, rows: number, cols: number): void {\n const innerWidth = HELP_WIDTH - 2;\n const x = Math.max(0, Math.floor((cols - HELP_WIDTH) / 2));\n\n const contentLines: string[] = [\n // Nav-mode keys\n helpRow(' hjkl/↑↓←→ navigate', ' tab switch pane', innerWidth),\n helpRow(' enter expand/open', ' F toggle flow', innerWidth),\n helpRow(' n new session', ' m message orch.', innerWidth),\n helpRow(' R resume session', ' C continue session', innerWidth),\n helpRow(' b rollback cycle', ' x restart agent', innerWidth),\n helpRow(' r re-run agent', ' g edit goal', innerWidth),\n helpRow(' p open roadmap', ' S edit strategy', innerWidth),\n helpRow(' w go to window', ' o resume claude', innerWidth),\n helpRow(' c side claude pane', ' q quit', innerWidth),\n ' '.padEnd(innerWidth),\n // Leader direct keys (top-level space-key)\n helpRow(' space s cycle session', ' space h home/dashboard', innerWidth),\n helpRow(' space n new session', ' space m message orch.', innerWidth),\n helpRow(' space t status popup', ' space l session picker', innerWidth),\n helpRow(' space x kill pane', ' space / search', innerWidth),\n helpRow(' space ? help', ' space 1-9 jump to session', innerWidth),\n ' '.padEnd(innerWidth),\n // Direct top-level leader keys\n helpRow(' space c side claude pane', ' space y › Yank', innerWidth),\n // Submenu prefixes\n helpRow(' space o › Open', ' space a › Agent', innerWidth),\n helpRow(' space S › Session', ' space g › Go', innerWidth),\n helpRow(' space C › Companion', '', innerWidth),\n ' '.padEnd(innerWidth),\n ansiDim(' Changed: space a → space a s (spawn agent)'.padEnd(innerWidth)),\n ];\n\n const height = Math.min(contentLines.length + 4, rows - 2);\n const y = Math.max(0, Math.floor((rows - height) / 2));\n\n drawBorder(buf, x, y, HELP_WIDTH, height, 'yellow');\n\n writeClipped(buf, x + 1, y + 1, ansiColor(' KEYBINDINGS (esc or ? to close)'.padEnd(innerWidth), 'yellow', true), innerWidth);\n writeClipped(buf, x + 1, y + 2, ' '.padEnd(innerWidth), innerWidth);\n\n const availableContentRows = height - 4;\n for (let i = 0; i < Math.min(contentLines.length, availableContentRows); i++) {\n writeClipped(buf, x + 1, y + 3 + i, contentLines[i]!, innerWidth);\n }\n\n const trailingBlankRow = y + 3 + Math.min(contentLines.length, availableContentRows);\n if (trailingBlankRow < y + height - 1) {\n writeClipped(buf, x + 1, trailingBlankRow, ' '.padEnd(innerWidth), innerWidth);\n }\n}\n\n// ─── Companion Overlay State (module-level, reset on close) ──────────────────\n\ntype CompanionPage = 'profile' | 'badges' | 'help';\n\nlet _page: CompanionPage = 'profile';\nlet _prevPage: 'profile' | 'badges' = 'profile';\nlet _gallery: BadgeGallery | null = null;\n\nexport function companionOverlayNextPage(): void {\n if (_page === 'help') { _page = _prevPage; return; }\n _page = _page === 'profile' ? 'badges' : 'profile';\n}\n\nexport function companionOverlayShowHelp(): void {\n if (_page !== 'help') _prevPage = _page as 'profile' | 'badges';\n _page = 'help';\n}\n\nexport function companionOverlayDismissHelp(): void {\n _page = _prevPage;\n}\n\nexport function badgeGalleryLeft(): void {\n if (_gallery) _gallery.currentIndex = galleryPrev(_gallery);\n}\n\nexport function badgeGalleryRight(): void {\n if (_gallery) _gallery.currentIndex = galleryNext(_gallery);\n}\n\nexport function closeBadgeGallery(): void {\n _page = 'profile';\n _gallery = null;\n _badgeScroll = 0;\n}\n\nexport function getCompanionPage(): CompanionPage {\n return _page;\n}\n\n// ─── Companion Profile Page ──────────────────────────────────────────────────\n\n// ─── Helpers ─────────────────────────────────────────────────────────────────\n\nconst MOOD_ICONS: Record<Mood, string> = {\n happy: '◉', grinding: '◈', frustrated: '◆', zen: '◎', sleepy: '◌', excited: '✦', existential: '◉',\n};\n\nconst MOOD_COLORS: Record<Mood, string> = {\n happy: 'green', grinding: 'yellow', frustrated: 'red', zen: 'cyan', sleepy: 'gray', excited: 'white', existential: 'magenta',\n};\n\nfunction statBar(value: number, max: number, width: number, color: string): string {\n const filled = max > 0 ? Math.min(width, Math.round((value / max) * width)) : 0;\n const bar = ansiColor('▓'.repeat(filled), color) + ansiDim('░'.repeat(width - filled));\n return bar;\n}\n\nfunction wrapText(text: string, maxWidth: number): string[] {\n const words = text.split(' ');\n const lines: string[] = [];\n let current = '';\n for (const word of words) {\n if (current.length + word.length + 1 > maxWidth && current.length > 0) {\n lines.push(current);\n current = word;\n } else {\n current = current.length > 0 ? `${current} ${word}` : word;\n }\n }\n if (current.length > 0) lines.push(current);\n return lines;\n}\n\nfunction renderProfilePage(buf: FrameBuffer, rows: number, cols: number, companion: CompanionState): void {\n const innerWidth = COMPANION_WIDTH - 2;\n const x = Math.max(0, Math.floor((cols - COMPANION_WIDTH) / 2));\n\n const unlockedCount = companion.achievements.length;\n const totalAchievements = ACHIEVEMENTS.length;\n\n const endH = Math.floor(companion.stats.endurance / 3_600_000);\n\n const intensity = companion.debugMood?.scores[companion.mood] ?? 0;\n const face = getMoodFace(companion.mood, intensity);\n const moodColor = MOOD_COLORS[companion.mood];\n const moodIcon = MOOD_ICONS[companion.mood];\n const faceColored = ansiColor(`(${face})`, moodColor, true);\n\n const repoNicknames = Object.values(companion.repos)\n .map(r => r.nickname)\n .filter((n): n is string => n !== null);\n const repoDisplay = repoNicknames.length > 0 ? ansiDim(` \"${repoNicknames[0]}\"`) : '';\n\n const barW = 18;\n\n // XP progress within current level\n const { xpIntoLevel, xpForNextLevel } = computeLevelProgress(companion.xp);\n const xpBar = statBar(xpIntoLevel, xpForNextLevel, 20, 'cyan');\n\n // Most recent achievement\n const lastAchievement = companion.achievements.length > 0\n ? companion.achievements[companion.achievements.length - 1]\n : null;\n const lastDef = lastAchievement\n ? ACHIEVEMENTS.find(a => a.id === lastAchievement.id)\n : null;\n\n const contentLines: string[] = [];\n\n // Face + mood\n contentLines.push(` ${faceColored} .${repoDisplay}`.padEnd(innerWidth));\n contentLines.push(' '.padEnd(innerWidth));\n\n // Level + title\n contentLines.push(` ${ansiColor(`Lv ${companion.level}`, 'cyan', true)} ${ansiBold(companion.title)}`.padEnd(innerWidth));\n contentLines.push(` ${xpBar} ${ansiDim(`${companion.xp} xp`)}`.padEnd(innerWidth));\n contentLines.push(' '.padEnd(innerWidth));\n\n // Mood\n contentLines.push(` ${ansiColor(moodIcon, moodColor)} ${ansiColor(companion.mood, moodColor)}`.padEnd(innerWidth));\n contentLines.push(' '.padEnd(innerWidth));\n\n // Stats with colored bars\n contentLines.push(` ${ansiColor('STR', 'red')} ${String(companion.stats.strength).padStart(4)} ${statBar(companion.stats.strength, 100, barW, 'red')}`.padEnd(innerWidth));\n contentLines.push(` ${ansiColor('END', 'yellow')} ${String(endH + 'h').padStart(4)} ${statBar(endH, 500, barW, 'yellow')}`.padEnd(innerWidth));\n contentLines.push(` ${ansiColor('WIS', 'blue')} ${String(companion.stats.wisdom).padStart(4)} ${statBar(companion.stats.wisdom, 50, barW, 'blue')}`.padEnd(innerWidth));\n contentLines.push(` ${ansiColor('PAT', 'magenta')} ${String(companion.stats.patience).padStart(4)} ${statBar(companion.stats.patience, 200, barW, 'magenta')}`.padEnd(innerWidth));\n contentLines.push(' '.padEnd(innerWidth));\n\n // Achievement\n if (lastDef) {\n contentLines.push(` ${ansiColor('★', 'yellow')} ${lastDef.name} ${ansiDim(`${unlockedCount}/${totalAchievements}`)}`.padEnd(innerWidth));\n } else {\n contentLines.push(` ${ansiDim(`◇ ${unlockedCount}/${totalAchievements} achievements`)}`.padEnd(innerWidth));\n }\n\n contentLines.push(' '.padEnd(innerWidth));\n\n // Commentary — word-wrapped, styled\n if (companion.lastCommentary) {\n const raw = companion.lastCommentary.text;\n const wrapped = wrapText(raw, innerWidth - 6);\n contentLines.push(` ${ansiDim('┊')} ${ansiColor(wrapped[0] ?? '', 'white')}`.padEnd(innerWidth));\n for (let i = 1; i < wrapped.length; i++) {\n contentLines.push(` ${ansiDim('┊')} ${ansiColor(wrapped[i] ?? '', 'white')}`.padEnd(innerWidth));\n }\n }\n\n contentLines.push(' '.padEnd(innerWidth));\n contentLines.push(` ${ansiDim('tab → badges ? → stat guide')}`.padEnd(innerWidth));\n\n const height = Math.min(contentLines.length + 4, rows - 2);\n const y = Math.max(0, Math.floor((rows - height) / 2));\n\n drawBorder(buf, x, y, COMPANION_WIDTH, height, 'cyan');\n\n writeClipped(buf, x + 1, y + 1, ansiColor(' COMPANION (esc to close)'.padEnd(innerWidth), 'cyan', true), innerWidth);\n writeClipped(buf, x + 1, y + 2, ' '.padEnd(innerWidth), innerWidth);\n\n const availableContentRows = height - 4;\n for (let i = 0; i < Math.min(contentLines.length, availableContentRows); i++) {\n writeClipped(buf, x + 1, y + 3 + i, contentLines[i]!, innerWidth);\n }\n}\n\n// ─── Badge Gallery Page ──────────────────────────────────────────────────────\n\nconst GALLERY_WIDTH = 50;\n\nlet _badgeScroll = 0;\n\nexport function badgeListScrollUp(): void { _badgeScroll = Math.max(0, _badgeScroll - 1); }\nexport function badgeListScrollDown(): void { _badgeScroll++; }\n\nfunction renderBadgesPage(buf: FrameBuffer, rows: number, cols: number, companion: CompanionState): void {\n if (!_gallery) _gallery = createBadgeGallery(companion.achievements);\n const gallery = _gallery;\n\n const innerWidth = GALLERY_WIDTH - 2;\n const x = Math.max(0, Math.floor((cols - GALLERY_WIDTH) / 2));\n\n const unlockedCount = companion.achievements.length;\n const totalAchievements = ACHIEVEMENTS.length;\n\n // Render current badge card\n const currentDef = gallery.achievements[gallery.currentIndex]!;\n const currentUnlock = gallery.unlocked.get(currentDef.id) ?? null;\n const card = renderBadgeCard(currentDef, currentUnlock);\n\n const contentLines: string[] = [];\n\n // Badge card (centered within overlay)\n for (const cardLine of card.lines) {\n const stripped = cardLine.replace(/\\x1b\\[[0-9;]*m/g, '');\n const pad = Math.max(0, Math.floor((innerWidth - stripped.length) / 2));\n const padded = ' '.repeat(pad) + cardLine + ' '.repeat(Math.max(0, innerWidth - stripped.length - pad));\n contentLines.push(padded);\n }\n\n contentLines.push(' '.padEnd(innerWidth));\n\n // Navigation footer\n const navIdx = gallery.currentIndex + 1;\n const navTotal = gallery.total;\n const unlockLabel = currentUnlock !== null ? ' ✓ unlocked' : ' · locked';\n const navLine = ` ← ${navIdx}/${navTotal} → ${unlockedCount}/${totalAchievements} earned${unlockLabel}`;\n contentLines.push(navLine.padEnd(innerWidth));\n\n contentLines.push(' '.padEnd(innerWidth));\n\n // Achievement checklist — scrollable, current badge highlighted\n const listStartIdx = contentLines.length;\n const maxListRows = Math.min(6, Math.max(4, (rows - 2) - 4 - listStartIdx - 2));\n const maxScroll = Math.max(0, gallery.total - maxListRows + 1);\n if (_badgeScroll > maxScroll) _badgeScroll = maxScroll;\n\n // Auto-scroll to keep current badge visible (iterative: indicators steal rows)\n if (gallery.currentIndex < _badgeScroll) _badgeScroll = gallery.currentIndex;\n for (let pass = 0; pass < 3; pass++) {\n const a = _badgeScroll > 0 ? 1 : 0;\n const b = _badgeScroll + maxListRows < gallery.total ? 1 : 0;\n const vis = maxListRows - a - b;\n if (gallery.currentIndex >= _badgeScroll + vis) {\n _badgeScroll = gallery.currentIndex - vis + 1;\n } else break;\n }\n if (_badgeScroll > maxScroll) _badgeScroll = maxScroll;\n\n const hasMoreAbove = _badgeScroll > 0;\n const hasMoreBelow = _badgeScroll + maxListRows < gallery.total;\n const itemRows = maxListRows - (hasMoreAbove ? 1 : 0) - (hasMoreBelow ? 1 : 0);\n\n if (hasMoreAbove) {\n contentLines.push(ansiDim(` ↑ ${_badgeScroll} more`.padEnd(innerWidth)));\n }\n\n for (let i = 0; i < itemRows && (_badgeScroll + i) < gallery.total; i++) {\n const idx = _badgeScroll + i;\n const def = gallery.achievements[idx]!;\n const u = gallery.unlocked.has(def.id);\n const icon = u ? '✓' : '·';\n const isCurrent = idx === gallery.currentIndex;\n let line = ` ${icon} ${def.name}`.padEnd(innerWidth);\n if (isCurrent) line = ansiColor(line, 'cyan', false);\n else if (!u) line = ansiDim(line);\n contentLines.push(line);\n }\n\n if (hasMoreBelow) {\n const below = gallery.total - _badgeScroll - itemRows;\n contentLines.push(ansiDim(` ↓ ${below} more`.padEnd(innerWidth)));\n }\n\n contentLines.push(' '.padEnd(innerWidth));\n contentLines.push(ansiDim(' tab → profile ? → stat guide'.padEnd(innerWidth)));\n\n const height = Math.min(contentLines.length + 4, rows - 2);\n const y = Math.max(0, Math.floor((rows - height) / 2));\n\n drawBorder(buf, x, y, GALLERY_WIDTH, height, 'cyan');\n\n writeClipped(buf, x + 1, y + 1, ansiColor(' BADGES (↑↓ navigate, esc close)'.padEnd(innerWidth), 'cyan', true), innerWidth);\n writeClipped(buf, x + 1, y + 2, ' '.padEnd(innerWidth), innerWidth);\n\n const availableContentRows = height - 4;\n for (let i = 0; i < Math.min(contentLines.length, availableContentRows); i++) {\n writeClipped(buf, x + 1, y + 3 + i, contentLines[i]!, innerWidth);\n }\n}\n\n// ─── Stat Guide Page ─────────────────────────────────────────────────────────\n\nfunction renderHelpPage(buf: FrameBuffer, rows: number, cols: number): void {\n const innerWidth = COMPANION_WIDTH - 2;\n const x = Math.max(0, Math.floor((cols - COMPANION_WIDTH) / 2));\n\n const divider = (label: string, color: string) => {\n const rest = innerWidth - label.length - 5;\n return ` ${ansiColor(label, color, true)} ${ansiDim('─'.repeat(Math.max(0, rest)))}`;\n };\n\n const contentLines: string[] = [];\n\n contentLines.push(divider('STR (Strength)', 'red'));\n contentLines.push(' +1 per completed session'.padEnd(innerWidth));\n contentLines.push(' '.padEnd(innerWidth));\n\n contentLines.push(divider('END (Endurance)', 'yellow'));\n contentLines.push(' Total active time across sessions'.padEnd(innerWidth));\n contentLines.push(' (displayed in hours)'.padEnd(innerWidth));\n contentLines.push(' '.padEnd(innerWidth));\n\n contentLines.push(divider('WIS (Wisdom)', 'blue'));\n contentLines.push(' +1 per efficient session'.padEnd(innerWidth));\n contentLines.push(ansiDim(' agents have <30% stddev in active').padEnd(innerWidth));\n contentLines.push(ansiDim(' time, 2+ agents required').padEnd(innerWidth));\n contentLines.push(' '.padEnd(innerWidth));\n\n contentLines.push(divider('PAT (Patience)', 'magenta'));\n contentLines.push(' +√cycles per completed session'.padEnd(innerWidth));\n contentLines.push(ansiDim(' +1 if validation mode').padEnd(innerWidth));\n contentLines.push(ansiDim(' +1 if completion mode').padEnd(innerWidth));\n contentLines.push(' '.padEnd(innerWidth));\n\n contentLines.push(divider('XP & Level', 'cyan'));\n contentLines.push(' STR×80 + END/h×15 + WIS×40'.padEnd(innerWidth));\n contentLines.push(' + PAT×5'.padEnd(innerWidth));\n contentLines.push(ansiDim(' level: 150 base xp, ×1.35/lvl').padEnd(innerWidth));\n contentLines.push(' '.padEnd(innerWidth));\n\n contentLines.push(divider('Mood', 'white'));\n contentLines.push(' Real-time scoring from signals:'.padEnd(innerWidth));\n contentLines.push(ansiDim(' time of day, idle time, crashes,').padEnd(innerWidth));\n contentLines.push(ansiDim(' streaks, session length, agents').padEnd(innerWidth));\n contentLines.push(' '.padEnd(innerWidth));\n\n contentLines.push(divider('Badges', 'yellow'));\n contentLines.push(' Milestones, session feats, time'.padEnd(innerWidth));\n contentLines.push(' patterns, and behavioral checks'.padEnd(innerWidth));\n contentLines.push(' '.padEnd(innerWidth));\n\n contentLines.push(ansiDim(' tab → back ? → close'.padEnd(innerWidth)));\n\n const height = Math.min(contentLines.length + 4, rows - 2);\n const y = Math.max(0, Math.floor((rows - height) / 2));\n\n drawBorder(buf, x, y, COMPANION_WIDTH, height, 'cyan');\n\n writeClipped(buf, x + 1, y + 1, ansiColor(' STAT GUIDE (? or esc to close)'.padEnd(innerWidth), 'cyan', true), innerWidth);\n writeClipped(buf, x + 1, y + 2, ' '.padEnd(innerWidth), innerWidth);\n\n const availableContentRows = height - 4;\n for (let i = 0; i < Math.min(contentLines.length, availableContentRows); i++) {\n writeClipped(buf, x + 1, y + 3 + i, contentLines[i]!, innerWidth);\n }\n\n const trailingBlankRow = y + 3 + Math.min(contentLines.length, availableContentRows);\n if (trailingBlankRow < y + height - 1) {\n writeClipped(buf, x + 1, trailingBlankRow, ' '.padEnd(innerWidth), innerWidth);\n }\n}\n\n// ─── Companion Overlay Dispatcher ────────────────────────────────────────────\n\nexport function renderCompanionOverlay(buf: FrameBuffer, rows: number, cols: number, companion: CompanionState): void {\n if (_page === 'help') {\n renderHelpPage(buf, rows, cols);\n } else if (_page === 'badges') {\n renderBadgesPage(buf, rows, cols, companion);\n } else {\n renderProfilePage(buf, rows, cols, companion);\n }\n}\n\nexport function renderCompanionDebugOverlay(buf: FrameBuffer, rows: number, cols: number, companion: CompanionState): void {\n const innerWidth = DEBUG_WIDTH - 2;\n const x = Math.max(0, Math.floor((cols - DEBUG_WIDTH) / 2));\n\n const intensity = companion.debugMood?.scores[companion.mood] ?? 0;\n const face = getMoodFace(companion.mood, intensity);\n const debug = companion.debugMood;\n\n const contentLines: string[] = [\n ` (${face}) mood: ${companion.mood}`.padEnd(innerWidth),\n ' '.padEnd(innerWidth),\n ];\n\n if (debug) {\n const { signals, scores } = debug;\n\n contentLines.push(ansiDim(' ── Signals ──'.padEnd(innerWidth)));\n contentLines.push(` hourOfDay: ${signals.hourOfDay}`.padEnd(innerWidth));\n contentLines.push(` sessionLengthMs: ${signals.sessionLengthMs} (${Math.round(signals.sessionLengthMs / 60_000)}min)`.padEnd(innerWidth));\n contentLines.push(` idleDurationMs: ${signals.idleDurationMs} (${Math.round(signals.idleDurationMs / 60_000)}min)`.padEnd(innerWidth));\n contentLines.push(` recentCrashes: ${signals.recentCrashes}`.padEnd(innerWidth));\n contentLines.push(` cleanStreak: ${signals.cleanStreak}`.padEnd(innerWidth));\n contentLines.push(` justCompleted: ${signals.justCompleted}`.padEnd(innerWidth));\n contentLines.push(` justCrashed: ${signals.justCrashed}`.padEnd(innerWidth));\n contentLines.push(` justLeveledUp: ${signals.justLeveledUp}`.padEnd(innerWidth));\n contentLines.push(' '.padEnd(innerWidth));\n\n contentLines.push(ansiDim(' ── Scores ──'.padEnd(innerWidth)));\n const moodOrder: Mood[] = ['happy', 'grinding', 'frustrated', 'zen', 'sleepy', 'excited', 'existential'];\n for (const mood of moodOrder) {\n const score = scores[mood] ?? 0;\n const bar = score > 0 ? ansiDim('█'.repeat(Math.min(Math.round(score / 5), 12))) : '';\n const marker = mood === debug.winner ? ' ◀' : '';\n contentLines.push(` ${mood.padEnd(12)} ${String(score).padStart(3)} ${bar}${marker}`.padEnd(innerWidth));\n }\n } else {\n contentLines.push(ansiDim(' No mood signals yet'.padEnd(innerWidth)));\n contentLines.push(ansiDim(' (mood is time-of-day only)'.padEnd(innerWidth)));\n }\n\n contentLines.push(' '.padEnd(innerWidth));\n\n const height = Math.min(contentLines.length + 4, rows - 2);\n const y = Math.max(0, Math.floor((rows - height) / 2));\n\n drawBorder(buf, x, y, DEBUG_WIDTH, height, 'yellow');\n\n writeClipped(buf, x + 1, y + 1, ansiColor(' COMPANION DEBUG (esc to close)'.padEnd(innerWidth), 'yellow', true), innerWidth);\n writeClipped(buf, x + 1, y + 2, ' '.padEnd(innerWidth), innerWidth);\n\n const availableContentRows = height - 4;\n for (let i = 0; i < Math.min(contentLines.length, availableContentRows); i++) {\n writeClipped(buf, x + 1, y + 3 + i, contentLines[i]!, innerWidth);\n }\n\n const trailingRow = y + 3 + Math.min(contentLines.length, availableContentRows);\n if (trailingRow < y + height - 1) {\n writeClipped(buf, x + 1, trailingRow, ' '.padEnd(innerWidth), innerWidth);\n }\n}\n","import stringWidth from 'string-width';\nimport type {\n CompanionState,\n CompanionField,\n CompanionRenderOpts,\n CompanionStats,\n Mood,\n} from './companion-types.js';\n\n// --- Display-width-aware string slice ---\n\n/** Slice a plain-text string to fit within `maxCols` display columns. */\nfunction sliceToWidth(s: string, maxCols: number): string {\n let w = 0;\n let i = 0;\n while (i < s.length) {\n const cp = s.codePointAt(i)!;\n const ch = String.fromCodePoint(cp);\n const cw = stringWidth(ch);\n if (w + cw > maxCols) break;\n w += cw;\n i += ch.length;\n }\n return s.slice(0, i);\n}\n\n// --- Idle hobbies ---\n\nexport const IDLE_HOBBIES: string[] = [\n 'reading Camus',\n 'stacking pebbles',\n 'watching clouds',\n 'sketching boulders',\n 'counting stars',\n 'writing haiku',\n 'practicing zen',\n 'studying geology',\n 'polishing rocks',\n 'mapping the hill',\n 'resting',\n 'stargazing',\n 'whittling',\n 'collecting fossils',\n 'napping on summit',\n 'journaling',\n 'stretching',\n 'humming',\n 'doodling',\n 'tending moss',\n 'making tea',\n 'reading Myth of Sisyphus',\n 'reorganizing rocks',\n 'people watching',\n 'whistling',\n];\n\n// --- Spinner verbs ---\n\nexport const SPINNER_VERBS: string[] = [\n // physical\n 'pushing',\n 'hauling',\n 'heaving',\n 'toiling',\n 'straining',\n 'trudging',\n 'laboring',\n 'rolling',\n 'ascending',\n 'dragging',\n 'shouldering',\n 'hoisting',\n 'lugging',\n 'schlepping',\n 'grinding',\n 'lifting',\n 'bracing',\n 'climbing',\n 'leaning in',\n 'digging in',\n // philosophical\n 'philosophizing',\n 'contemplating',\n 'pondering',\n 'musing',\n 'ruminating',\n 'reflecting',\n 'meditating',\n 'wondering',\n 'questioning',\n 'theorizing',\n 'considering',\n 'deliberating',\n 'introspecting',\n 'cogitating',\n 'brooding',\n // endurance\n 'persevering',\n 'enduring',\n 'persisting',\n 'sustaining',\n 'weathering',\n 'carrying on',\n 'pressing on',\n 'holding steady',\n 'keeping at it',\n 'not stopping',\n // light/silly\n 'napping',\n 'procrastinating',\n 'daydreaming',\n 'vibing',\n 'winging it',\n 'hoping',\n 'improvising',\n 'making do',\n 'whistling',\n];\n\n// --- Base form ---\n//\n// Returns a template with two placeholders:\n// FACE — replaced by getMoodFace() in renderCompanion\n// {BOULDER} — replaced by composeLine() with the agent-count-driven boulder\n//\n// No literal boulder characters are embedded here. The previous design embedded\n// them (`.`, `o`, `O`, `OO`, `@`) which caused splitBodyAndBoulder to either\n// discard multi-char boulders (OO) or corrupt output when the dynamic boulder\n// didn't match the embedded one.\n\nexport function getBaseForm(level: number): string {\n if (level <= 2) return '(FACE) {BOULDER}';\n if (level <= 4) return '(FACE)/ {BOULDER}';\n if (level <= 7) return '/(FACE)/ {BOULDER}';\n if (level <= 11) return '\\\\(FACE)/ {BOULDER}';\n if (level <= 19) return 'ᕦ(FACE)ᕤ {BOULDER}';\n return '♛ᕦ(FACE)ᕤ {BOULDER}';\n}\n\n// --- Mood face ---\n//\n// Each mood has three intensity tiers driven by the winning mood score:\n// mild (score < 30), moderate (30–70), intense (> 70)\n\nconst MOOD_FACES: Record<Mood, [string, string, string]> = {\n happy: ['^.^', '^‿^', '✧‿✧'],\n grinding: ['>.<', '>_<', 'ò.ó'],\n frustrated: ['>.<#', 'ಠ_ಠ', 'ಠ益ಠ'],\n zen: ['‾.‾', '‾‿‾', '˘‿˘'],\n sleepy: ['-.-)zzZ','-_-)zzZ','˘.˘)zzZ'],\n excited: ['*o*', '*◡*', '✦◡✦'],\n existential: ['◉_◉', '⊙_⊙', '◉‸◉'],\n};\n\nexport function getMoodFace(mood: Mood, intensity: number = 0): string {\n const faces = MOOD_FACES[mood];\n if (!faces) throw new Error(`Unknown mood: ${mood as string}`);\n const tier = intensity < 30 ? 0 : intensity <= 70 ? 1 : 2;\n return faces[tier];\n}\n\n// --- Stat cosmetics ---\n\nexport function getStatCosmetics(stats: CompanionStats): string[] {\n const cosmetics: string[] = [];\n if (stats.wisdom > 5) cosmetics.push('wisps');\n if (stats.endurance > 36_000_000) cosmetics.push('trail');\n if (stats.patience > 50) cosmetics.push('zen-prefix');\n return cosmetics;\n}\n\n// --- Boulder form ---\n\nexport function getBoulderForm(agentCount?: number, repoNickname?: string): string {\n let boulder: string;\n if (agentCount === undefined || agentCount <= 0) {\n boulder = '';\n } else if (agentCount <= 2) {\n boulder = 'o';\n } else if (agentCount <= 6) {\n boulder = 'O';\n } else if (agentCount <= 15) {\n boulder = '◉';\n } else if (agentCount <= 35) {\n boulder = '@';\n } else {\n boulder = '@@';\n }\n if (repoNickname !== undefined) {\n boulder = `${boulder} \"${repoNickname}\"`;\n }\n return boulder;\n}\n\n// --- composeLine ---\n//\n// body has already had FACE replaced with the mood face, and still contains\n// the {BOULDER} placeholder from getBaseForm.\n// composeLine applies cosmetics to `boulder`, then substitutes {BOULDER}.\n\nexport function composeLine(\n body: string,\n cosmetics: string[],\n boulder: string,\n): string {\n let b = boulder;\n\n let hasZenPrefix = false;\n\n if (boulder !== '') {\n for (const c of cosmetics) {\n switch (c) {\n case 'wisps':\n b = `~${b}~`;\n break;\n case 'trail':\n b = `${b} ...`;\n break;\n case 'zen-prefix':\n hasZenPrefix = true;\n break;\n }\n }\n } else {\n // Zen prefix is a character trait, not boulder-related\n if (cosmetics.includes('zen-prefix')) hasZenPrefix = true;\n }\n\n let line = b === ''\n ? body.replace(' {BOULDER}', '')\n : body.replace('{BOULDER}', b);\n\n if (hasZenPrefix) line = `☯ ${line}`;\n\n return line;\n}\n\n// --- Color helpers ---\n\ntype AnsiCode = number;\ntype TmuxColor = string;\n\ninterface MoodColor {\n ansi: AnsiCode;\n tmux: TmuxColor;\n}\n\nconst MOOD_COLORS: Record<Mood, MoodColor> = {\n happy: { ansi: 32, tmux: 'green' },\n grinding: { ansi: 33, tmux: 'yellow' },\n frustrated: { ansi: 31, tmux: 'red' },\n zen: { ansi: 36, tmux: 'cyan' },\n sleepy: { ansi: 90, tmux: 'colour245' },\n excited: { ansi: 97, tmux: 'white' },\n existential: { ansi: 35, tmux: 'magenta' },\n};\n\nexport function getMoodTmuxColor(mood: Mood): string {\n return MOOD_COLORS[mood].tmux;\n}\n\nexport function getMoodAnsiCode(mood: Mood): number {\n return MOOD_COLORS[mood].ansi;\n}\n\nfunction colorize(text: string, mood: Mood, tmux: boolean): string {\n const { ansi, tmux: tmuxColor } = MOOD_COLORS[mood];\n if (tmux) {\n return `#[fg=${tmuxColor}]${text}#[fg=default]`;\n }\n return `\\x1b[${ansi}m${text}\\x1b[0m`;\n}\n\n// --- Stat summary string ---\n\nfunction statSummary(stats: CompanionStats): string {\n const endH = Math.floor(stats.endurance / 3_600_000);\n return `STR:${stats.strength} END:${endH}h WIS:${stats.wisdom} PAT:${stats.patience}`;\n}\n\n// --- Main renderer ---\n\nexport function renderCompanion(\n companion: CompanionState,\n fields: CompanionField[],\n opts?: CompanionRenderOpts,\n): string {\n const hasFace = fields.includes('face');\n const hasBoulder = fields.includes('boulder');\n\n const repoNickname = opts?.repoPath !== undefined\n ? companion.repos[opts.repoPath]?.nickname ?? undefined\n : undefined;\n\n const boulder = getBoulderForm(opts?.agentCount, repoNickname);\n const cosmetics = getStatCosmetics(companion.stats);\n\n let facePart: string | null = null;\n let boulderOnlyPart: string | null = null;\n\n if (hasFace) {\n const baseForm = getBaseForm(companion.level);\n const intensity = companion.debugMood?.scores[companion.mood] ?? 0;\n const face = getMoodFace(companion.mood, intensity);\n const bodyWithFace = baseForm.replace('FACE', face);\n facePart = composeLine(bodyWithFace, cosmetics, boulder);\n } else if (hasBoulder) {\n // Boulder standalone (unusual)\n boulderOnlyPart = boulder;\n }\n\n let commentary = fields.includes('commentary')\n ? (companion.lastCommentary?.text ?? '')\n : null;\n\n const parts: string[] = [];\n\n for (const field of fields) {\n switch (field) {\n case 'face':\n if (facePart !== null) parts.push(facePart);\n break;\n case 'boulder':\n if (!hasFace && boulderOnlyPart !== null) parts.push(boulderOnlyPart);\n // If face included, boulder is already embedded — skip\n break;\n case 'title':\n parts.push(companion.title);\n break;\n case 'commentary':\n if (commentary !== null) parts.push(commentary);\n break;\n case 'mood':\n parts.push(`[${companion.mood}]`);\n break;\n case 'level':\n parts.push(`Lv ${companion.level}`);\n break;\n case 'stats':\n parts.push(statSummary(companion.stats));\n break;\n case 'achievements':\n parts.push(`${companion.achievements.length} achievements`);\n break;\n case 'verb': {\n const idx = (opts?.verbIndex ?? companion.spinnerVerbIndex) % SPINNER_VERBS.length;\n parts.push(SPINNER_VERBS[idx]!);\n break;\n }\n case 'hobby': {\n // Rotate hourly based on hour + companion level as seed for variety\n const hobbyIdx = (new Date().getHours() + companion.level) % IDLE_HOBBIES.length;\n parts.push(IDLE_HOBBIES[hobbyIdx]!);\n break;\n }\n }\n }\n\n // Apply maxWidth: truncate commentary first, then right-truncate.\n // Use display width (stringWidth) not .length — faces like ಠ益ಠ contain\n // wide characters where .length < displayWidth, causing writeClipped to\n // hard-clip the line without an ellipsis.\n if (opts?.maxWidth !== undefined) {\n const maxWidth = opts.maxWidth;\n const joined = parts.join(' ');\n const joinedWidth = stringWidth(joined);\n if (joinedWidth > maxWidth && commentary !== null && commentary.length > 0) {\n // Shorten commentary progressively\n const commentaryIdx = parts.indexOf(commentary);\n if (commentaryIdx !== -1) {\n const commentaryWidth = stringWidth(commentary);\n const overhead = joinedWidth - commentaryWidth;\n const available = maxWidth - overhead - 2; // account for double-space\n if (available < 0) {\n parts[commentaryIdx] = '';\n } else {\n parts[commentaryIdx] = sliceToWidth(commentary, available);\n }\n commentary = parts[commentaryIdx];\n }\n }\n const result = parts.filter(p => p.length > 0).join(' ');\n const resultWidth = stringWidth(result);\n const final = resultWidth > maxWidth\n ? sliceToWidth(result, maxWidth - 1) + '…'\n : result;\n\n return applyColor(final, fields, facePart, companion.mood, opts);\n }\n\n const result = parts.filter(p => p.length > 0).join(' ');\n return applyColor(result, fields, facePart, companion.mood, opts);\n}\n\nfunction applyColor(\n result: string,\n fields: CompanionField[],\n facePart: string | null,\n mood: Mood,\n opts?: CompanionRenderOpts,\n): string {\n const useColor = opts?.color === true || opts?.tmuxFormat === true;\n if (!useColor || facePart === null || !fields.includes('face')) return result;\n\n const tmux = opts?.tmuxFormat === true;\n const coloredFace = colorize(facePart, mood, tmux);\n return result.replace(facePart, coloredFace);\n}\n","import { existsSync, mkdirSync, readFileSync, renameSync, writeFileSync } from 'node:fs';\nimport { randomUUID } from 'node:crypto';\nimport { dirname, join } from 'node:path';\nimport { companionPath, globalDir } from '../shared/paths.js';\nimport type { Session } from '../shared/types.js';\nimport type {\n AchievementId,\n CommentaryEvent,\n CompanionBaselines,\n CompanionState,\n CompanionStats,\n FeedbackEntry,\n FeedbackRating,\n LastCommentary,\n Mood,\n MoodSignals,\n RepoMemory,\n RunningStats,\n UnlockedAchievement,\n} from '../shared/companion-types.js';\nimport { defaultBaselines, emptyStats, normalizeCompanion } from '../shared/companion-normalize.js';\nexport { defaultBaselines, emptyStats } from '../shared/companion-normalize.js';\nexport { ACHIEVEMENTS } from '../shared/companion-types.js';\n\n// ---------------------------------------------------------------------------\n// Welford's online algorithm — deviation-based mood scoring\n// ---------------------------------------------------------------------------\n\nconst MIN_SAMPLES = 5;\nconst MIN_STDDEV_RATIO = 0.20;\n\ntype BaselineMetric = 'sessionMs' | 'cycleCount' | 'agentCount' | 'sessionsPerDay' | 'recentAgentThroughput';\n\nconst ABSOLUTE_STDDEV_FLOORS: Record<BaselineMetric, number> = {\n sessionMs: 300_000, // 5 minutes\n cycleCount: 1.0,\n agentCount: 1.0,\n sessionsPerDay: 0.5,\n recentAgentThroughput: 2.0,\n};\n\nconst COLD_START_DEFAULTS: Record<BaselineMetric, { mean: number; stddev: number }> = {\n sessionMs: { mean: 3_600_000, stddev: 2_400_000 },\n cycleCount: { mean: 5, stddev: 3 },\n agentCount: { mean: 5, stddev: 4 },\n sessionsPerDay: { mean: 3, stddev: 2 },\n recentAgentThroughput: { mean: 8, stddev: 6 },\n};\n\nexport function welfordUpdate(stats: RunningStats, value: number): void {\n stats.count++;\n const delta = value - stats.mean;\n stats.mean += delta / stats.count;\n const delta2 = value - stats.mean;\n stats.m2 += delta * delta2;\n}\n\nexport function zScore(\n value: number,\n stats: RunningStats,\n metric: BaselineMetric,\n): number {\n const defaults = COLD_START_DEFAULTS[metric];\n const floor = ABSOLUTE_STDDEV_FLOORS[metric];\n\n if (stats.count < MIN_SAMPLES) {\n if (defaults.stddev === 0) return 0;\n return (value - defaults.mean) / defaults.stddev;\n }\n\n const rawStddev = stats.count >= 2 ? Math.sqrt(stats.m2 / stats.count) : 0;\n const stddev = Math.max(rawStddev, stats.mean * MIN_STDDEV_RATIO, floor);\n if (stddev === 0) return 0;\n return (value - stats.mean) / stddev;\n}\n\n// ---------------------------------------------------------------------------\n// Persistence\n// ---------------------------------------------------------------------------\n\nexport function loadCompanion(): CompanionState {\n const path = companionPath();\n if (!existsSync(path)) {\n const state = createDefaultCompanion();\n saveCompanion(state);\n return state;\n }\n const raw = readFileSync(path, 'utf-8');\n const state = JSON.parse(raw) as CompanionState;\n return normalizeCompanion(state);\n}\n\nexport function saveCompanion(state: CompanionState): void {\n const path = companionPath();\n const dir = dirname(path);\n mkdirSync(dir, { recursive: true });\n const tmp = join(dir, `.companion.${randomUUID()}.tmp`);\n writeFileSync(tmp, JSON.stringify(state, null, 2), 'utf-8');\n renameSync(tmp, path);\n}\n\nconst MAX_COMMENTARY_HISTORY = 1000;\nconst MAX_FEEDBACK_HISTORY = 1000;\n\n/**\n * Push a commentary entry to lastCommentary + commentaryHistory ring buffer.\n * Mutates the companion in-place; caller must saveCompanion() afterward.\n */\nexport function recordCommentary(companion: CompanionState, text: string, event: CommentaryEvent): void {\n const entry: LastCommentary = { text, event, timestamp: new Date().toISOString() };\n companion.lastCommentary = entry;\n if (!companion.commentaryHistory) companion.commentaryHistory = [];\n companion.commentaryHistory.push(entry);\n if (companion.commentaryHistory.length > MAX_COMMENTARY_HISTORY) {\n companion.commentaryHistory = companion.commentaryHistory.slice(-MAX_COMMENTARY_HISTORY);\n }\n}\n\n/**\n * Push a feedback entry to feedbackHistory ring buffer.\n * Mutates the companion in-place; caller must saveCompanion() afterward.\n */\nexport function recordFeedback(\n companion: CompanionState,\n text: string,\n rating: FeedbackRating,\n event: CommentaryEvent,\n comment?: string,\n): void {\n const entry: FeedbackEntry = { commentaryText: text, rating, event, timestamp: new Date().toISOString(), ...(comment != null ? { comment } : {}) };\n if (!companion.feedbackHistory) companion.feedbackHistory = [];\n companion.feedbackHistory.push(entry);\n if (companion.feedbackHistory.length > MAX_FEEDBACK_HISTORY) {\n companion.feedbackHistory = companion.feedbackHistory.slice(-MAX_FEEDBACK_HISTORY);\n }\n}\n\nexport function createDefaultCompanion(): CompanionState {\n const now = new Date().toISOString();\n return {\n version: 1,\n name: null,\n createdAt: now,\n stats: {\n strength: 0,\n endurance: 0,\n wisdom: 0,\n patience: 0,\n },\n xp: 0,\n level: 1,\n title: 'Boulder Intern',\n mood: 'sleepy',\n moodUpdatedAt: now,\n achievements: [],\n repos: {},\n lastCommentary: null,\n commentaryHistory: [],\n sessionsCompleted: 0,\n sessionsCrashed: 0,\n totalActiveMs: 0,\n lifetimeAgentsSpawned: 0,\n consecutiveCleanSessions: 0,\n consecutiveEfficientSessions: 0,\n consecutiveHighCycleSessions: 0,\n consecutiveDaysActive: 0,\n lastActiveDate: null,\n taskHistory: {},\n dailyRepos: {},\n recentCompletions: [],\n spinnerVerbIndex: 0,\n baselines: defaultBaselines(),\n feedbackHistory: [],\n };\n}\n\n// ---------------------------------------------------------------------------\n// XP & Leveling\n// ---------------------------------------------------------------------------\n\nexport function computeXP(stats: CompanionStats): number {\n const strengthXP = stats.strength * 50;\n const enduranceXP = (stats.endurance / 3_600_000) * 20;\n const wisdomXP = stats.wisdom * 40;\n const patienceXP = stats.patience * 8;\n return Math.floor(strengthXP + enduranceXP + wisdomXP + patienceXP);\n}\n\nexport function computeStrengthGain(agentCount: number): number {\n if (agentCount <= 0) return 0;\n if (agentCount <= 2) return 1;\n if (agentCount <= 5) return 2;\n if (agentCount <= 10) return 3;\n if (agentCount <= 20) return 4;\n return 5;\n}\n\nexport function computeLevel(xp: number): number {\n let level = 1;\n let threshold = 150;\n let cumulative = 0;\n while (cumulative + threshold <= xp) {\n cumulative += threshold;\n level++;\n threshold = Math.floor(threshold * 1.35);\n }\n return level;\n}\n\n/** Returns { xpIntoLevel, xpForNextLevel } so callers can render accurate progress bars. */\nexport function computeLevelProgress(xp: number): { xpIntoLevel: number; xpForNextLevel: number } {\n let threshold = 150;\n let cumulative = 0;\n while (cumulative + threshold <= xp) {\n cumulative += threshold;\n threshold = Math.floor(threshold * 1.35);\n }\n return { xpIntoLevel: xp - cumulative, xpForNextLevel: threshold };\n}\n\nconst TITLE_MAP: Record<number, string> = {\n 1: 'Boulder Intern',\n 2: 'Pebble Pusher',\n 3: 'Rock Hauler',\n 4: 'Gravel Wrangler',\n 5: 'Slope Familiar',\n 6: 'Incline Regular',\n 7: 'Ridge Runner',\n 8: 'Crag Warden',\n 9: 'Stone Whisperer',\n 10: 'Boulder Brother',\n 11: 'Hill Veteran',\n 12: 'Summit Aspirant',\n 13: 'Peak Haunter',\n 14: 'Cliff Sage',\n 15: \"Mountain's Shadow\",\n 16: 'Eternal Roller',\n 17: \"Gravity's Rival\",\n 18: 'The Unmoved Mover',\n 19: 'Camus Was Right',\n 20: 'The Absurd Hero',\n 25: 'One Must Imagine Him Happy',\n 30: 'He Has Always Been Here',\n};\n\nexport function getTitle(level: number): string {\n for (let l = level; l >= 1; l--) {\n if (TITLE_MAP[l] !== undefined) return TITLE_MAP[l]!;\n }\n return 'Boulder Intern';\n}\n\n// ---------------------------------------------------------------------------\n// Mood\n// ---------------------------------------------------------------------------\n\nexport function computeMood(companion: CompanionState, session?: Session, signals?: MoodSignals): Mood {\n if (!signals) {\n const hour = new Date().getHours();\n if (hour >= 2 && hour < 6) return 'existential';\n if (hour >= 22 || hour < 2) return 'sleepy';\n return 'zen';\n }\n\n const scores: Record<Mood, number> = {\n happy: 0,\n grinding: 0,\n frustrated: 0,\n zen: 0,\n sleepy: 0,\n excited: 0,\n existential: 0,\n };\n\n const cycleCount = signals.cycleCount ?? 0;\n const sessionsCompletedToday = signals.sessionsCompletedToday ?? 0;\n\n // Deviation-based z-scores from personal baselines\n const baselines = companion.baselines ?? defaultBaselines();\n const sessionZ = zScore(signals.sessionLengthMs, baselines.sessionMs, 'sessionMs');\n const cycleZ = zScore(cycleCount, baselines.cycleCount, 'cycleCount');\n const agentZ = zScore(signals.totalAgentCount ?? 0, baselines.agentCount, 'agentCount');\n const dailyZ = zScore(sessionsCompletedToday, baselines.sessionsPerDay, 'sessionsPerDay');\n const recentAgentZ = zScore(signals.recentAgentCount ?? 0, baselines.recentAgentThroughput, 'recentAgentThroughput');\n\n // Happy — event-driven + deviation-based quick wins\n if (signals.justCompleted) scores.happy += 50;\n if (signals.justCompleted && sessionZ < -0.5) scores.happy += 15; // quicker than usual\n if (dailyZ > 0.5) scores.happy += 20; // productive day\n if (dailyZ > 1.5) scores.happy += 10; // really productive\n if (signals.hourOfDay >= 6 && signals.hourOfDay < 12) scores.happy += 15; // morning\n if (signals.hourOfDay >= 12 && signals.hourOfDay < 17) scores.happy += 8; // afternoon\n if ((signals.activeAgentCount ?? 0) >= 1 && sessionZ < -0.5) scores.happy += 12; // early session optimism\n // Flow state: last completion was recent (within 30min) and we're in a new session\n const lastCompletion = companion.recentCompletions.length > 0\n ? Date.now() - new Date(companion.recentCompletions[companion.recentCompletions.length - 1]!).getTime()\n : Infinity;\n if (lastCompletion < 1_800_000 && signals.sessionLengthMs > 0) scores.happy += 20;\n\n // Grinding — deviation-based deep work\n if (sessionZ > 0.5) scores.grinding += 15; // longer than usual\n if (sessionZ > 1.0) scores.grinding += 10; // significantly longer\n if (sessionZ > 1.5) scores.grinding += 8; // very long for this user\n if (recentAgentZ > 0.5) scores.grinding += 12; // more agents active (2h window) than usual\n if (recentAgentZ > 1.0) scores.grinding += 10; // significantly more cross-session agents\n if (recentAgentZ > 1.5) scores.grinding += 8; // massive cross-session throughput\n if (cycleZ > 0.5) scores.grinding += 8; // more cycles than usual\n\n // Frustrated — actual negative events (crashes, rollbacks, restarts, lost agents)\n const rollbacks = signals.rollbackCount ?? 0;\n const restartedAgents = signals.restartedAgentCount ?? 0;\n const lostAgents = signals.lostAgentCount ?? 0;\n const killedAgents = signals.killedAgentCount ?? 0;\n if (signals.justCrashed) scores.frustrated += 30;\n if (signals.recentCrashes >= 2) scores.frustrated += 20;\n if (signals.recentCrashes >= 4) scores.frustrated += 15;\n if (rollbacks >= 1) scores.frustrated += 25; // rolling back = something went wrong\n if (rollbacks >= 3) scores.frustrated += 25; // repeated rollbacks = real pain\n if (restartedAgents >= 1) scores.frustrated += 15;\n if (restartedAgents >= 3) scores.frustrated += 15;\n if (lostAgents >= 1) scores.frustrated += 15;\n if (lostAgents >= 3) scores.frustrated += 10;\n if (killedAgents >= 2) scores.frustrated += 10;\n // Long session WITH negative events = stuck (but long session alone is just grinding)\n if (sessionZ > 1.5 && (signals.recentCrashes > 0 || rollbacks > 0)) scores.frustrated += 12;\n\n // Zen — deviation-based \"normal\" + absolute calm\n if (companion.stats.patience > 30) scores.zen += 15;\n if (signals.idleDurationMs > 120_000 && signals.idleDurationMs <= 900_000) scores.zen += 25; // 2-15min idle\n if (sessionZ > -1.0 && sessionZ < 0.3) scores.zen += 15; // session length is normal\n if (cycleZ < 0) scores.zen += 10; // fewer cycles than usual, smooth sailing\n if (signals.hourOfDay >= 6 && signals.hourOfDay < 10 && (signals.activeAgentCount ?? 0) === 0) scores.zen += 10;\n if (dailyZ >= -0.5 && dailyZ <= 0.5) scores.zen += 10; // normal day\n\n // Sleepy — absolute (idle duration + time of day)\n if (signals.idleDurationMs > 900_000) scores.sleepy += 30; // >15min\n if (signals.idleDurationMs > 2_700_000) scores.sleepy += 25; // >45min\n if (signals.idleDurationMs > 5_400_000) scores.sleepy += 15; // >90min\n if (signals.hourOfDay >= 22 || signals.hourOfDay < 6) scores.sleepy += 20;\n if (signals.idleDurationMs > 300_000 && (signals.hourOfDay >= 22 || signals.hourOfDay < 6)) scores.sleepy += 15;\n if (sessionZ > 2.5) scores.sleepy += 12; // exhaustion from extreme session\n\n // Excited — event-driven + deviation-based swarms\n if (signals.justLeveledUp) scores.excited += 60;\n if (signals.justCompleted && agentZ > 1.0) scores.excited += 30; // completed with notably many agents\n if (agentZ > 1.5) scores.excited += 20; // way more agents than usual\n if (agentZ > 2.0) scores.excited += 15; // massive swarm for this user\n if (signals.justCompleted && sessionZ < -1.0) scores.excited += 20; // way faster than usual\n\n // Existential — absolute (late night + experience + sustained commitment)\n if (signals.hourOfDay >= 2 && signals.hourOfDay < 6) scores.existential += 25;\n if (signals.hourOfDay >= 0 && signals.hourOfDay < 2) scores.existential += 10;\n const enduranceHours = companion.stats.endurance / 3_600_000;\n if (enduranceHours > 40) scores.existential += 15;\n if (signals.hourOfDay >= 2 && signals.hourOfDay < 6 && enduranceHours > 40) {\n scores.existential += 25;\n }\n // Weekly activity z-score — sustained above-average use, not a static lifetime counter\n const now = Date.now();\n const weekAgo = now - 7 * 24 * 3_600_000;\n const weeklyCompletions = companion.recentCompletions.filter(\n ts => new Date(ts).getTime() > weekAgo\n ).length;\n const weeklyAvgDaily = weeklyCompletions / 7;\n const weeklyZ = zScore(weeklyAvgDaily, baselines.sessionsPerDay, 'sessionsPerDay');\n if (weeklyZ > 0.5) scores.existential += 8;\n if (weeklyZ > 1.0) scores.existential += 7;\n if (weeklyZ > 1.5) scores.existential += 5;\n // Consecutive days — grows slowly from day 3, caps at +20 around day 9\n const consecutiveDays = companion.consecutiveDaysActive ?? 0;\n if (consecutiveDays >= 3) scores.existential += Math.min(20, (consecutiveDays - 2) * 3);\n\n // User feedback adjustments\n const goodRatings = signals.recentFeedbackGood ?? 0;\n const badRatings = signals.recentFeedbackBad ?? 0;\n const whipRatings = signals.recentFeedbackWhip ?? 0;\n if (goodRatings > 0) {\n scores.happy += goodRatings * 20;\n scores.excited += goodRatings * 8;\n scores.frustrated = Math.max(0, scores.frustrated - goodRatings * 10);\n }\n if (badRatings > 0) {\n scores.happy = Math.max(0, scores.happy - badRatings * 15);\n scores.frustrated += badRatings * 20;\n scores.zen = Math.max(0, scores.zen - badRatings * 10);\n }\n if (whipRatings > 0) {\n scores.happy = Math.max(0, scores.happy - whipRatings * 15);\n scores.sleepy = Math.max(0, scores.sleepy - whipRatings * 15);\n scores.zen = Math.max(0, scores.zen - whipRatings * 15);\n scores.frustrated = Math.max(0, scores.frustrated - whipRatings * 8);\n scores.existential += whipRatings * 25;\n }\n\n const moodOrder: Mood[] = ['happy', 'grinding', 'frustrated', 'zen', 'sleepy', 'excited', 'existential'];\n let best: Mood = 'grinding';\n let bestScore = -1;\n for (const mood of moodOrder) {\n if (scores[mood] > bestScore) {\n bestScore = scores[mood];\n best = mood;\n }\n }\n\n // Attach debug info for TUI debug overlay\n companion.debugMood = { signals, scores: { ...scores }, winner: best };\n\n return best;\n}\n\n// ---------------------------------------------------------------------------\n// Achievements\n// ---------------------------------------------------------------------------\n\nexport function hasAchievement(companion: CompanionState, id: AchievementId): boolean {\n return companion.achievements.some(a => a.id === id);\n}\n\nfunction daysSince(isoTimestamp: string): number {\n return (Date.now() - new Date(isoTimestamp).getTime()) / (1000 * 60 * 60 * 24);\n}\n\ntype AchievementChecker = (companion: CompanionState, session?: Session) => boolean;\n\nconst ACHIEVEMENT_CHECKERS: Record<AchievementId, AchievementChecker> = {\n // Milestone\n 'first-blood': (c) => c.sessionsCompleted >= 1,\n 'regular': (c) => c.sessionsCompleted >= 10,\n 'centurion': (c) => c.sessionsCompleted >= 100,\n 'veteran': (c) => c.sessionsCompleted >= 500,\n 'thousand-boulder': (c) => c.sessionsCompleted >= 1000,\n 'cartographer': (c) => Object.keys(c.repos).length >= 5,\n 'world-traveler': (c) => Object.keys(c.repos).length >= 15,\n 'omnipresent': (c) => Object.keys(c.repos).length >= 30,\n 'swarm-starter': (c) => c.lifetimeAgentsSpawned >= 50,\n 'hive-mind': (c) => c.lifetimeAgentsSpawned >= 500,\n 'legion': (c) => c.lifetimeAgentsSpawned >= 2000,\n 'army-of-thousands': (c) => c.lifetimeAgentsSpawned >= 5000,\n 'singularity': (c) => c.lifetimeAgentsSpawned >= 10000,\n 'first-shift': (c) => c.totalActiveMs >= 36_000_000,\n 'workaholic': (c) => c.totalActiveMs >= 360_000_000,\n 'time-lord': (c) => c.totalActiveMs >= 1_800_000_000,\n 'eternal-grind': (c) => c.totalActiveMs >= 7_200_000_000,\n 'epoch': (c) => c.totalActiveMs >= 18_000_000_000,\n 'old-growth': (c) => daysSince(c.createdAt) >= 14,\n 'seasoned': (c) => daysSince(c.createdAt) >= 90,\n 'ancient': (c) => daysSince(c.createdAt) >= 365,\n 'apprentice': (c) => c.level >= 5,\n 'journeyman': (c) => c.level >= 15,\n 'master': (c) => c.level >= 30,\n 'grandmaster': (c) => c.level >= 50,\n\n // Session\n 'marathon': (_c, s) => s != null && s.agents.length >= 15,\n 'squad': (_c, s) => s != null && s.agents.length >= 10,\n 'battalion': (_c, s) => s != null && s.agents.length >= 25,\n 'swarm': (_c, s) => s != null && s.agents.length >= 50,\n 'blitz': (_c, s) => s != null && s.activeMs < 300_000 && s.status === 'completed',\n 'speed-run': (_c, s) => s != null && s.activeMs < 900_000 && s.status === 'completed',\n 'flash': (_c, s) => s != null && s.activeMs < 120_000 && s.status === 'completed',\n 'flawless': (_c, s) => s != null && s.agents.length >= 10 && s.status === 'completed' &&\n s.agents.every(a => a.status !== 'crashed' && a.status !== 'killed'),\n 'speed-demon': (c) => c.consecutiveEfficientSessions >= 10,\n 'iron-will': (c) => c.consecutiveHighCycleSessions >= 5,\n 'glass-cannon': (_c, s) => {\n if (!s || s.status !== 'completed' || s.agents.length < 5) return false;\n return s.agents.every(a => a.status === 'crashed' || a.killedReason != null);\n },\n 'solo': (_c, s) => s != null && s.status === 'completed' && s.agents.length === 1,\n 'one-more-cycle': (_c, s) => s != null && s.orchestratorCycles.length >= 10,\n 'deep-dive': (_c, s) => s != null && s.orchestratorCycles.length >= 15,\n 'abyss': (_c, s) => s != null && s.orchestratorCycles.length >= 25,\n 'eternal-recurrence': (_c, s) => s != null && s.orchestratorCycles.length >= 40,\n 'endurance': (_c, s) => s != null && s.activeMs >= 14_400_000,\n 'ultramarathon': (_c, s) => s != null && s.activeMs >= 21_600_000,\n 'one-shot': (_c, s) => s != null && s.agents.length >= 5 && s.orchestratorCycles.length === 1 && s.status === 'completed',\n 'quick-draw': (_c, s) => {\n if (!s || s.agents.length === 0) return false;\n const firstAgent = s.agents[0]!;\n return new Date(firstAgent.spawnedAt).getTime() - new Date(s.createdAt).getTime() < 20_000;\n },\n\n // Time\n 'night-owl': (_c, s) => {\n if (!s || s.status !== 'completed') return false;\n const h = new Date(s.createdAt).getHours();\n return h >= 1 && h < 5;\n },\n 'dawn-patrol': (_c, s) => {\n if (!s) return false;\n // Session must be 3+ hours\n if (s.activeMs < 10_800_000) return false;\n const start = new Date(s.createdAt).getTime();\n const end = s.completedAt ? new Date(s.completedAt).getTime() : Date.now();\n const startDate = new Date(start);\n const startHour = startDate.getHours();\n // Get today's midnight (00:00) for the start date\n const todayMidnight = new Date(startDate);\n todayMidnight.setHours(0, 0, 0, 0);\n // Get 6am for the same calendar day as midnight\n const sixAm = new Date(todayMidnight);\n sixAm.setHours(6, 0, 0, 0);\n\n if (startHour >= 6) {\n // Started after 6am — check if session spans into next day's midnight-6am window\n const nextMidnight = new Date(todayMidnight.getTime() + 24 * 60 * 60 * 1000);\n return start < nextMidnight.getTime() && end > nextMidnight.getTime();\n } else {\n // Started between midnight and 6am — session is already in the window\n return start < sixAm.getTime();\n }\n },\n 'early-bird': (_c, s) => {\n if (!s) return false;\n return new Date(s.createdAt).getHours() < 6;\n },\n 'weekend-warrior': (_c, s) => {\n if (!s || s.status !== 'completed') return false;\n const day = new Date(s.completedAt ?? s.createdAt).getDay();\n return day === 0 || day === 6;\n },\n 'all-nighter': (_c, s) => s != null && s.activeMs >= 18_000_000,\n 'witching-hour': (_c, s) => {\n if (!s) return false;\n const h = new Date(s.createdAt).getHours();\n return h === 3;\n },\n\n // Behavioral\n 'sisyphean': (c) => Object.values(c.taskHistory).some(v => v >= 3),\n 'stubborn': (c) => Object.values(c.taskHistory).some(v => v >= 5) && c.sessionsCompleted > 0,\n 'one-must-imagine': (c) => Object.values(c.taskHistory).some(v => v >= 10),\n 'creature-of-habit': (c) => Object.values(c.repos).some(r => r.visits >= 10),\n 'loyal': (c) => Object.values(c.repos).some(r => r.visits >= 30),\n 'wanderer': (c) => {\n return Object.values(c.dailyRepos).some(repos => repos.length >= 3);\n },\n 'streak': (c) => c.consecutiveDaysActive >= 7,\n 'iron-streak': (c) => c.consecutiveDaysActive >= 14,\n 'hot-streak': (c) => c.consecutiveCleanSessions >= 15,\n 'momentum': (c) => {\n if (c.recentCompletions.length < 5) return false;\n const last5 = c.recentCompletions.slice(-5);\n const oldest = new Date(last5[0]!).getTime();\n const newest = new Date(last5[4]!).getTime();\n return newest - oldest <= 4 * 60 * 60 * 1000;\n },\n 'overdrive': (c) => {\n const dateCounts: Record<string, number> = {};\n for (const ts of c.recentCompletions) {\n const date = ts.slice(0, 10);\n dateCounts[date] = (dateCounts[date] ?? 0) + 1;\n }\n return Object.values(dateCounts).some(count => count >= 6);\n },\n 'patient-one': (_c, s) => {\n if (!s || s.orchestratorCycles.length < 2) return false;\n for (let i = 1; i < s.orchestratorCycles.length; i++) {\n const prev = s.orchestratorCycles[i - 1]!;\n const curr = s.orchestratorCycles[i]!;\n if (!prev.completedAt) continue;\n const gap = new Date(curr.timestamp).getTime() - new Date(prev.completedAt).getTime();\n if (gap >= 30 * 60 * 1000) return true;\n }\n return false;\n },\n 'message-in-a-bottle': (_c, s) => {\n if (!s) return false;\n const userMessages = s.messages.filter(m => m.source.type === 'user');\n return userMessages.length >= 10;\n },\n 'deep-conversation': (_c, s) => {\n if (!s) return false;\n const userMessages = s.messages.filter(m => m.source.type === 'user');\n return userMessages.length >= 20;\n },\n 'comeback-kid': (_c, s) => {\n if (!s || s.status !== 'completed') return false;\n return s.orchestratorCycles.length > 0 && s.parentSessionId != null;\n },\n 'pair-programming': (_c, s) => {\n if (!s) return false;\n const userMessages = s.messages.filter(m => m.source.type === 'user');\n return userMessages.length >= 8;\n },\n};\n\nexport function checkAchievements(companion: CompanionState, session?: Session): AchievementId[] {\n const alreadyUnlocked = new Set(companion.achievements.map(a => a.id));\n const newIds: AchievementId[] = [];\n\n for (const [id, checker] of Object.entries(ACHIEVEMENT_CHECKERS) as [AchievementId, AchievementChecker][]) {\n if (alreadyUnlocked.has(id)) continue;\n if (checker(companion, session)) {\n newIds.push(id);\n }\n }\n return newIds;\n}\n\n// ---------------------------------------------------------------------------\n// Repo Memory\n// ---------------------------------------------------------------------------\n\nconst MOOD_SENTIMENT: Record<Mood, number> = {\n happy: 0.85,\n excited: 0.90,\n zen: 0.70,\n grinding: 0.45,\n sleepy: 0.40,\n frustrated: 0.15,\n existential: 0.25,\n};\n\nexport function updateRepoMemory(\n companion: CompanionState,\n repoPath: string,\n event: 'visit' | 'completion' | 'crash',\n activeMs?: number,\n): CompanionState {\n const now = new Date().toISOString();\n const moodScore = MOOD_SENTIMENT[companion.mood] ?? 0.5;\n const existing = companion.repos[repoPath];\n if (!existing) {\n companion.repos[repoPath] = {\n visits: event === 'visit' ? 1 : 0,\n completions: event === 'completion' ? 1 : 0,\n crashes: event === 'crash' ? 1 : 0,\n totalActiveMs: activeMs ?? 0,\n moodAvg: moodScore,\n nickname: null,\n firstSeen: now,\n lastSeen: now,\n };\n } else {\n if (event === 'visit') existing.visits++;\n if (event === 'completion') existing.completions++;\n if (event === 'crash') existing.crashes++;\n if (activeMs != null) existing.totalActiveMs += activeMs;\n existing.lastSeen = now;\n // Running average weighted by total event count across visits/completions/crashes\n const n = existing.visits + existing.completions + existing.crashes;\n existing.moodAvg = existing.moodAvg + (moodScore - existing.moodAvg) / n;\n }\n return companion;\n}\n\n// ---------------------------------------------------------------------------\n// Event Handlers\n// ---------------------------------------------------------------------------\n\nfunction recomputeXpLevelTitle(companion: CompanionState): void {\n companion.xp = computeXP(companion.stats);\n companion.level = computeLevel(companion.xp);\n companion.title = getTitle(companion.level);\n}\n\nexport function todayIso(): string {\n return new Date().toISOString().slice(0, 10);\n}\n\nexport function onSessionStart(companion: CompanionState, cwd: string): void {\n // Update repo memory\n updateRepoMemory(companion, cwd, 'visit');\n\n // Update dailyRepos\n const today = todayIso();\n if (!companion.dailyRepos[today]) companion.dailyRepos[today] = [];\n if (!companion.dailyRepos[today]!.includes(cwd)) {\n companion.dailyRepos[today]!.push(cwd);\n }\n\n // Update consecutive days active\n const lastDate = companion.lastActiveDate;\n if (lastDate === null) {\n companion.consecutiveDaysActive = 1;\n } else if (lastDate === today) {\n // Same day, no change to streak\n } else {\n const yesterday = new Date(Date.now() - 86_400_000).toISOString().slice(0, 10);\n if (lastDate === yesterday) {\n companion.consecutiveDaysActive++;\n } else {\n companion.consecutiveDaysActive = 1;\n }\n }\n companion.lastActiveDate = today;\n\n recomputeXpLevelTitle(companion);\n}\n\n/**\n * Compute wisdom points earned for a session. Rewards:\n * - Clean agent execution: high completion rate without restarts\n * - Good parallelization: more agents per orchestrator cycle\n * - Orchestration variety: using different modes (discovery, implementation, validation, completion)\n *\n * Returns 0-3 points per session.\n */\nexport function computeWisdomGain(session: Session): number {\n let wisdom = 0;\n const totalAgents = session.agents.length;\n const totalCycles = session.orchestratorCycles?.length ?? 0;\n if (totalAgents === 0 || totalCycles === 0) return 0;\n\n // Clean execution: ≥80% of agents completed without being killed/crashed/lost\n const cleanCompletions = session.agents.filter(a => a.status === 'completed').length;\n if (cleanCompletions / totalAgents >= 0.8) wisdom++;\n\n // Good parallelization: averaged ≥2 agents per cycle\n if (totalAgents / totalCycles >= 2) wisdom++;\n\n // Mode variety: used ≥2 distinct orchestrator modes\n const modes = new Set((session.orchestratorCycles ?? []).map(c => c.mode).filter(Boolean));\n if (modes.size >= 2) wisdom++;\n\n return wisdom;\n}\n\nexport function onSessionComplete(companion: CompanionState, session: Session): AchievementId[] {\n // Delta-safe: only credit what hasn't been credited yet (prevents inflation on continue→re-complete)\n const creditedCycles = session.companionCreditedCycles ?? 0;\n const creditedActiveMs = session.companionCreditedActiveMs ?? 0;\n const totalCycles = session.orchestratorCycles?.length ?? 0;\n const deltaCycles = Math.max(0, totalCycles - creditedCycles);\n const deltaActiveMs = Math.max(0, session.activeMs - creditedActiveMs);\n\n // Increment counters\n companion.sessionsCompleted++;\n companion.totalActiveMs += deltaActiveMs;\n companion.stats.endurance += deltaActiveMs;\n const creditedStrength = session.companionCreditedStrength ?? 0;\n const totalStrength = computeStrengthGain(session.agents.length);\n companion.stats.strength += Math.max(0, totalStrength - creditedStrength);\n\n // Patience: diminishing returns on high-cycle sessions (sqrt scale)\n const patienceFromCycles = Math.ceil(Math.sqrt(totalCycles)) - Math.ceil(Math.sqrt(creditedCycles));\n companion.stats.patience += Math.max(0, patienceFromCycles);\n // Bonus for sessions that went through full lifecycle (only new modes)\n const allModes = new Set((session.orchestratorCycles ?? []).map(c => c.mode));\n const creditedModesCycles = (session.orchestratorCycles ?? []).slice(0, creditedCycles);\n const prevModes = new Set(creditedModesCycles.map(c => c.mode));\n if (allModes.has('validation') && !prevModes.has('validation')) companion.stats.patience += 1;\n if (allModes.has('completion') && !prevModes.has('completion')) companion.stats.patience += 1;\n\n // Wisdom: clean execution, parallelization, mode variety\n const creditedWisdom = session.companionCreditedWisdom ?? 0;\n const totalWisdom = computeWisdomGain(session);\n companion.stats.wisdom += Math.max(0, totalWisdom - creditedWisdom);\n\n // Repo memory\n updateRepoMemory(companion, session.cwd, 'completion', deltaActiveMs);\n\n // Track consecutive efficient sessions (for speed-demon)\n if (totalCycles <= 3) {\n companion.consecutiveEfficientSessions++;\n } else {\n companion.consecutiveEfficientSessions = 0;\n }\n\n // Track consecutive high-cycle sessions (for iron-will)\n if (totalCycles >= 8) {\n companion.consecutiveHighCycleSessions++;\n } else {\n companion.consecutiveHighCycleSessions = 0;\n }\n\n // Consecutive clean sessions\n const hasCrash = session.agents.some(a => a.status === 'crashed');\n if (hasCrash) {\n companion.consecutiveCleanSessions = 0;\n companion.sessionsCrashed++;\n } else {\n companion.consecutiveCleanSessions++;\n }\n\n // Recent completions for achievements + weekly existential z-score (keep last 30)\n companion.recentCompletions.push(new Date().toISOString());\n if (companion.recentCompletions.length > 30) {\n companion.recentCompletions = companion.recentCompletions.slice(-30);\n }\n\n // Task history tracking (normalize task string to simple hash)\n const taskKey = normalizeTask(session.task, session.cwd);\n companion.taskHistory[taskKey] = (companion.taskHistory[taskKey] ?? 0) + 1;\n\n // Update deviation baselines (Welford's online algorithm)\n const baselines = companion.baselines ?? defaultBaselines();\n welfordUpdate(baselines.sessionMs, session.activeMs);\n welfordUpdate(baselines.cycleCount, totalCycles);\n welfordUpdate(baselines.agentCount, session.agents.length);\n welfordUpdate(baselines.recentAgentThroughput, companion.lastRecentAgentCount ?? 0);\n\n // Daily session count tracking with day-boundary handling\n const today = todayIso();\n if (baselines.lastCountedDay === null) {\n baselines.lastCountedDay = today;\n baselines.pendingDayCount = 1;\n } else if (baselines.lastCountedDay === today) {\n baselines.pendingDayCount++;\n } else {\n // Day rolled over: finalize the previous day\n welfordUpdate(baselines.sessionsPerDay, baselines.pendingDayCount);\n // Fill gap days (zero-session days) between lastCountedDay and yesterday\n const lastDay = new Date(baselines.lastCountedDay + 'T12:00:00');\n const yesterdayDate = new Date(today + 'T12:00:00');\n yesterdayDate.setDate(yesterdayDate.getDate() - 1);\n const cursor = new Date(lastDay);\n cursor.setDate(cursor.getDate() + 1);\n while (cursor < yesterdayDate) {\n welfordUpdate(baselines.sessionsPerDay, 0);\n cursor.setDate(cursor.getDate() + 1);\n }\n baselines.lastCountedDay = today;\n baselines.pendingDayCount = 1;\n }\n companion.baselines = baselines;\n\n recomputeXpLevelTitle(companion);\n\n // Check achievements\n const newAchievementIds = checkAchievements(companion, session);\n if (newAchievementIds.length > 0) {\n const now = new Date().toISOString();\n for (const id of newAchievementIds) {\n companion.achievements.push({ id, unlockedAt: now });\n }\n }\n\n return newAchievementIds;\n}\n\nexport function onAgentSpawned(companion: CompanionState): void {\n companion.lifetimeAgentsSpawned++;\n}\n\nexport function onAgentCrashed(companion: CompanionState): void {\n companion.consecutiveCleanSessions = 0;\n // sessionsCrashed is incremented in onSessionComplete (once per session, not per agent)\n}\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\nexport function normalizeTask(task: string, cwd: string): string {\n // Simple normalization: lowercase, collapse whitespace, prefix with cwd basename\n const normalized = task.toLowerCase().replace(/\\s+/g, ' ').trim().slice(0, 100);\n const cwdBase = cwd.split('/').pop() ?? cwd;\n return `${cwdBase}:${normalized}`;\n}\n\n// ---------------------------------------------------------------------------\n// Observation engine integration\n// ---------------------------------------------------------------------------\n\nimport type { ObservationContext } from '../shared/companion-types.js';\nimport { runObservationEngine } from './companion-memory.js';\n\nexport function captureObservationContext(\n companion: CompanionState,\n _repoCwd: string, // kept for future, unused today\n): ObservationContext {\n return {\n prevLevel: companion.level,\n prevSessionsCompleted: companion.sessionsCompleted,\n prevConsecutiveEfficientSessions: companion.consecutiveEfficientSessions ?? 0,\n };\n}\n\nexport async function runPostSessionObservations(\n companion: CompanionState,\n session: Session,\n prev: ObservationContext,\n): Promise<void> {\n return runObservationEngine({ companion, session, prev });\n}\n","import type {\n CompanionBaselines,\n CompanionState,\n RunningStats,\n} from './companion-types.js';\n\nexport function emptyStats(): RunningStats {\n return { count: 0, mean: 0, m2: 0 };\n}\n\nexport function defaultBaselines(): CompanionBaselines {\n return {\n sessionMs: emptyStats(),\n cycleCount: emptyStats(),\n agentCount: emptyStats(),\n sessionsPerDay: emptyStats(),\n recentAgentThroughput: emptyStats(),\n lastCountedDay: null,\n pendingDayCount: 0,\n };\n}\n\n/**\n * Forward-compat for companion.json files written by older versions or\n * partially-initialized state. Mutates and returns the input.\n *\n * Both the daemon (which writes the file) and the TUI (which reads it\n * directly to render) must run state through this before use — otherwise\n * missing fields like `spinnerVerbIndex` propagate into NaN modulo and\n * crash `renderCompanion`.\n */\nexport function normalizeCompanion(state: CompanionState): CompanionState {\n if (state.stats == null) state.stats = { strength: 0, endurance: 0, wisdom: 0, patience: 0 };\n if (state.level == null) state.level = 1;\n if (state.xp == null) state.xp = 0;\n if (state.title == null) state.title = 'Boulder Intern';\n if (state.mood == null) state.mood = 'sleepy';\n if (state.achievements == null) state.achievements = [];\n if (state.repos == null) state.repos = {};\n if (state.lastCommentary === undefined) state.lastCommentary = null;\n if (state.sessionsCompleted == null) state.sessionsCompleted = 0;\n if (state.sessionsCrashed == null) state.sessionsCrashed = 0;\n if (state.totalActiveMs == null) state.totalActiveMs = 0;\n if (state.consecutiveCleanSessions == null) state.consecutiveCleanSessions = 0;\n if (state.consecutiveDaysActive == null) state.consecutiveDaysActive = 0;\n if (state.lastActiveDate === undefined) state.lastActiveDate = null;\n if (state.taskHistory == null) state.taskHistory = {};\n if (state.dailyRepos == null) state.dailyRepos = {};\n if (state.recentCompletions == null) state.recentCompletions = [];\n if (state.lifetimeAgentsSpawned == null) state.lifetimeAgentsSpawned = 0;\n if (state.consecutiveEfficientSessions == null) state.consecutiveEfficientSessions = 0;\n if (state.consecutiveHighCycleSessions == null) state.consecutiveHighCycleSessions = 0;\n if (state.spinnerVerbIndex == null) state.spinnerVerbIndex = 0;\n if (state.baselines == null) state.baselines = defaultBaselines();\n if (state.baselines.recentAgentThroughput == null) state.baselines.recentAgentThroughput = emptyStats();\n if (state.commentaryHistory == null) state.commentaryHistory = [];\n if (state.feedbackHistory == null) state.feedbackHistory = [];\n return state;\n}\n","import type { Session } from './types.js';\n\nexport const OBSERVATION_CATEGORIES = ['session-sentiments', 'repo-impressions', 'user-patterns', 'notable-moments'] as const;\n\nexport type ObservationCategory = typeof OBSERVATION_CATEGORIES[number];\n\nexport type ObservationSource = 'rule' | 'haiku';\n\nexport interface ObservationRecord {\n id: string; // crypto.randomUUID()\n category: ObservationCategory;\n source: ObservationSource;\n text: string; // one-sentence observation; validated per §0.1\n repo: string | null; // absolute cwd path, or null for cross-repo observations\n sessionId: string;\n timestamp: string; // ISO 8601\n detectorId?: string; // rule-only: which detector produced this\n}\n\nexport interface CompanionMemoryState {\n version: 1;\n observations: ObservationRecord[]; // ordered oldest → newest\n prunedAt: string | null; // ISO timestamp of last prune, or null if never\n firedDetectors: Record<string, string>; // detectorId → lastDedupKey (per §0.1)\n}\n\nexport interface ObservationContext {\n prevLevel: number; // read by: level-up\n prevSessionsCompleted: number; // read by: session-milestone\n prevConsecutiveEfficientSessions: number; // read by: efficient-streak (pre-update comparison)\n}\n\nexport interface ObservationEngineInput {\n companion: CompanionState;\n session: Session;\n prev: ObservationContext;\n}\n\nexport class MemoryStoreParseError extends Error {\n constructor(public cause: unknown) { super('companion-memory.json is corrupt'); }\n}\n\nexport type Mood = 'happy' | 'grinding' | 'frustrated' | 'zen' | 'sleepy' | 'excited' | 'existential';\n\nexport type CompanionField = 'face' | 'boulder' | 'title' | 'commentary' | 'mood' | 'level' | 'stats' | 'achievements' | 'verb' | 'hobby';\n\nexport type FeedbackRating = 'neutral' | 'good' | 'bad' | 'whip' | 'comment';\n\nexport interface FeedbackEntry {\n commentaryText: string;\n rating: FeedbackRating;\n comment?: string;\n event: CommentaryEvent;\n timestamp: string; // ISO timestamp\n}\n\nexport type CommentaryEvent =\n | 'session-start'\n | 'cycle-boundary'\n | 'session-complete'\n | 'level-up'\n | 'achievement'\n | 'agent-crash'\n | 'idle-wake'\n | 'late-night';\n\nexport type TimePersonality = 'chipper' | 'professional' | 'reflective' | 'dry-humor' | 'delirious';\n\nexport type IdleAnimation = 'sleeping' | 'pacing' | 'pondering' | 'flexing' | 'deep-sleep';\n\nexport type AchievementCategory = 'milestone' | 'session' | 'time' | 'behavioral';\n\nexport type AchievementId =\n // Milestone (25)\n | 'first-blood'\n | 'regular'\n | 'centurion'\n | 'veteran'\n | 'thousand-boulder'\n | 'cartographer'\n | 'world-traveler'\n | 'omnipresent'\n | 'swarm-starter'\n | 'hive-mind'\n | 'legion'\n | 'army-of-thousands'\n | 'singularity'\n | 'first-shift'\n | 'workaholic'\n | 'time-lord'\n | 'eternal-grind'\n | 'epoch'\n | 'old-growth'\n | 'seasoned'\n | 'ancient'\n | 'apprentice'\n | 'journeyman'\n | 'master'\n | 'grandmaster'\n // Session (19)\n | 'marathon'\n | 'squad'\n | 'battalion'\n | 'swarm'\n | 'blitz'\n | 'speed-run'\n | 'flash'\n | 'flawless'\n | 'speed-demon'\n | 'iron-will'\n | 'glass-cannon'\n | 'solo'\n | 'one-more-cycle'\n | 'deep-dive'\n | 'abyss'\n | 'eternal-recurrence'\n | 'endurance'\n | 'ultramarathon'\n | 'one-shot'\n | 'quick-draw'\n // Time (6)\n | 'night-owl'\n | 'dawn-patrol'\n | 'early-bird'\n | 'weekend-warrior'\n | 'all-nighter'\n | 'witching-hour'\n // Behavioral (16)\n | 'sisyphean'\n | 'stubborn'\n | 'one-must-imagine'\n | 'creature-of-habit'\n | 'loyal'\n | 'wanderer'\n | 'streak'\n | 'iron-streak'\n | 'hot-streak'\n | 'momentum'\n | 'overdrive'\n | 'patient-one'\n | 'message-in-a-bottle'\n | 'deep-conversation'\n | 'comeback-kid'\n | 'pair-programming';\n\nexport interface AchievementDef {\n id: AchievementId;\n name: string;\n category: AchievementCategory;\n description: string;\n badge: string | null;\n}\n\nexport interface CompanionStats {\n strength: number; // lifetime completed sessions\n endurance: number; // lifetime active ms\n wisdom: number; // efficient orchestration count\n patience: number; // persistence score (cycles + lifecycle bonuses)\n}\n\n// Welford's online algorithm — tracks running mean + variance in O(1) space\nexport interface RunningStats {\n count: number;\n mean: number;\n m2: number; // sum of squared deviations from mean\n}\n\nexport interface CompanionBaselines {\n sessionMs: RunningStats; // active time per completed session\n cycleCount: RunningStats; // cycles per completed session\n agentCount: RunningStats; // total agents per completed session\n sessionsPerDay: RunningStats; // sessions completed per active day\n recentAgentThroughput: RunningStats; // agents active in last 2h across all sessions at completion time\n lastCountedDay: string | null; // YYYY-MM-DD for day-boundary tracking\n pendingDayCount: number; // current day's running total (finalized tomorrow)\n}\n\nexport interface UnlockedAchievement {\n id: AchievementId;\n unlockedAt: string; // ISO timestamp\n}\n\nexport interface RepoMemory {\n visits: number;\n completions: number;\n crashes: number;\n totalActiveMs: number;\n moodAvg: number; // running average (0-1 scale)\n nickname: string | null;\n firstSeen: string; // ISO timestamp\n lastSeen: string; // ISO timestamp\n}\n\nexport interface LastCommentary {\n text: string;\n event: CommentaryEvent;\n timestamp: string; // ISO timestamp\n}\n\nexport interface CompanionState {\n version: 1;\n name: string | null;\n createdAt: string; // ISO timestamp\n stats: CompanionStats;\n xp: number;\n level: number;\n title: string;\n mood: Mood;\n moodUpdatedAt: string; // ISO timestamp\n achievements: UnlockedAchievement[];\n repos: Record<string, RepoMemory>; // keyed by absolute cwd path\n lastCommentary: LastCommentary | null;\n commentaryHistory: LastCommentary[]; // ring buffer of last 30 commentaries for anti-repetition\n feedbackHistory: FeedbackEntry[]; // ring buffer of last 30 user feedback entries\n // Lifetime counters (redundant with derivable stats but kept for fast achievement checks)\n sessionsCompleted: number;\n sessionsCrashed: number;\n totalActiveMs: number;\n lifetimeAgentsSpawned: number;\n // Achievement tracking counters\n consecutiveCleanSessions: number;\n consecutiveEfficientSessions: number;\n consecutiveHighCycleSessions: number;\n consecutiveDaysActive: number;\n lastActiveDate: string | null; // ISO date string YYYY-MM-DD\n taskHistory: Record<string, number>; // normalized task hash → attempt count\n dailyRepos: Record<string, string[]>; // ISO date → array of repo paths\n recentCompletions: string[]; // last 3 ISO timestamps for momentum check\n spinnerVerbIndex: number;\n // Deviation-based mood scoring: running statistics for personal baselines\n baselines?: CompanionBaselines;\n // Agents active in last 2h across all sessions/dirs (written by pane-monitor, read at session completion for baseline)\n lastRecentAgentCount?: number;\n // Sum of agents in sessions with 2h-recent activity (boulder size, mood signal source)\n recentActiveAgents?: number;\n // Debug: last mood signals and scores (written by pane-monitor, read by TUI debug overlay)\n debugMood?: {\n signals: MoodSignals;\n scores: Record<Mood, number>;\n winner: Mood;\n };\n}\n\nexport interface IdleState {\n animation: IdleAnimation;\n frame: number; // current frame index in the animation cycle\n idleSince: string; // ISO timestamp of last session event\n}\n\nexport interface CompanionRenderOpts {\n maxWidth?: number;\n color?: boolean;\n tmuxFormat?: boolean;\n repoPath?: string;\n agentCount?: number;\n verbIndex?: number;\n}\n\nexport interface MoodSignals {\n recentCrashes: number; // crashes in last 30 minutes\n idleDurationMs: number; // ms since last session activity\n sessionLengthMs: number; // current session running time\n cleanStreak: number; // consecutive clean completions\n justCompleted: boolean; // session just completed successfully\n justCrashed: boolean; // agent just crashed\n justLeveledUp: boolean; // level up just happened\n hourOfDay: number; // 0-23\n activeAgentCount?: number; // agents currently with status === 'running'\n totalAgentCount?: number; // max total agents (agents.length) across tracked active sessions (for z-score baselines)\n recentAgentCount?: number; // agents active in last 2h across all sessions/dirs (for grind z-score)\n cycleCount?: number; // current session orchestrator cycle count\n sessionsCompletedToday?: number; // sessions completed today\n // Frustration signals — actual negative events\n rollbackCount?: number; // max rollbacks across tracked active sessions\n restartedAgentCount?: number; // total agents restarted across tracked active sessions\n lostAgentCount?: number; // total agents with status 'lost' across tracked active sessions\n killedAgentCount?: number; // total agents explicitly killed across tracked active sessions\n // User feedback signals (counts from last 5 feedbackHistory entries)\n recentFeedbackGood?: number; // good ratings in last 5\n recentFeedbackBad?: number; // bad ratings in last 5\n recentFeedbackWhip?: number; // whip ratings in last 5\n}\n\nexport const ACHIEVEMENTS: AchievementDef[] = [\n // Milestone (25)\n { id: 'first-blood', name: 'First Blood', category: 'milestone', description: 'Complete your first session.', badge: null },\n { id: 'regular', name: 'Regular', category: 'milestone', description: 'Complete 10 sessions.', badge: null },\n { id: 'centurion', name: 'Centurion', category: 'milestone', description: 'Complete 100 sessions.', badge: null },\n { id: 'veteran', name: 'Veteran', category: 'milestone', description: 'Complete 500 sessions.', badge: null },\n { id: 'thousand-boulder', name: 'Thousand Boulder', category: 'milestone', description: 'Complete 1,000 sessions.', badge: null },\n { id: 'cartographer', name: 'Cartographer', category: 'milestone', description: 'Work in 5 different repos.', badge: '+' },\n { id: 'world-traveler', name: 'World Traveler', category: 'milestone', description: 'Work in 15 different repos.', badge: null },\n { id: 'omnipresent', name: 'Omnipresent', category: 'milestone', description: 'Work in 30 different repos.', badge: null },\n { id: 'swarm-starter', name: 'Swarm Starter', category: 'milestone', description: 'Spawn 50 agents over a lifetime.', badge: null },\n { id: 'hive-mind', name: 'Hive Mind', category: 'milestone', description: 'Spawn 500 agents over a lifetime.', badge: null },\n { id: 'legion', name: 'Legion', category: 'milestone', description: 'Spawn 2,000 agents over a lifetime.', badge: null },\n { id: 'army-of-thousands', name: 'Army of Thousands', category: 'milestone', description: 'Spawn 5,000 agents over a lifetime.', badge: null },\n { id: 'singularity', name: 'Singularity', category: 'milestone', description: 'Spawn 10,000 agents over a lifetime.', badge: null },\n { id: 'first-shift', name: 'First Shift', category: 'milestone', description: '10 hours of total agent active time.', badge: null },\n { id: 'workaholic', name: 'Workaholic', category: 'milestone', description: '100 hours of total agent active time.', badge: null },\n { id: 'time-lord', name: 'Time Lord', category: 'milestone', description: '500 hours of total agent active time.', badge: null },\n { id: 'eternal-grind', name: 'Eternal Grind', category: 'milestone', description: '2,000 hours of total agent active time.', badge: null },\n { id: 'epoch', name: 'Epoch', category: 'milestone', description: '5,000 hours of total agent active time.', badge: null },\n { id: 'old-growth', name: 'Old Growth', category: 'milestone', description: 'Companion is 14 days old.', badge: null },\n { id: 'seasoned', name: 'Seasoned', category: 'milestone', description: 'Companion is 90 days old.', badge: null },\n { id: 'ancient', name: 'Ancient', category: 'milestone', description: 'Companion is 365 days old.', badge: null },\n { id: 'apprentice', name: 'Apprentice', category: 'milestone', description: 'Reach level 5.', badge: null },\n { id: 'journeyman', name: 'Journeyman', category: 'milestone', description: 'Reach level 15.', badge: null },\n { id: 'master', name: 'Master', category: 'milestone', description: 'Reach level 30.', badge: null },\n { id: 'grandmaster', name: 'Grandmaster', category: 'milestone', description: 'Reach level 50.', badge: null },\n // Session (19)\n { id: 'marathon', name: 'Marathon', category: 'session', description: 'Complete a session with 15+ agents.', badge: '~^~' },\n { id: 'squad', name: 'Squad Up', category: 'session', description: 'Complete a session with 10+ agents.', badge: null },\n { id: 'battalion', name: 'Battalion', category: 'session', description: 'Complete a session with 25+ agents.', badge: null },\n { id: 'swarm', name: 'The Swarm', category: 'session', description: 'Complete a session with 50+ agents.', badge: null },\n { id: 'blitz', name: 'Blitz', category: 'session', description: 'Complete a session in under 5 minutes.', badge: null },\n { id: 'speed-run', name: 'Speed Run', category: 'session', description: 'Complete a session in under 15 minutes.', badge: null },\n { id: 'flash', name: 'Flash', category: 'session', description: 'Complete a session in under 2 minutes.', badge: null },\n { id: 'flawless', name: 'Flawless', category: 'session', description: 'Complete a session with 10+ agents and zero crashes.', badge: '*' },\n { id: 'speed-demon', name: 'Speed Demon', category: 'session', description: '10 consecutive sessions completing in 3 or fewer cycles.', badge: '⚡' },\n { id: 'iron-will', name: 'Iron Will', category: 'session', description: '5 consecutive sessions each with 8+ orchestrator cycles.', badge: '[]' },\n { id: 'glass-cannon', name: 'Glass Cannon', category: 'session', description: '5+ agents, all crashed, but session completed anyway.', badge: null },\n { id: 'solo', name: 'Solo', category: 'session', description: 'Complete a session with exactly one agent.', badge: null },\n { id: 'one-more-cycle', name: 'One More Cycle', category: 'session', description: 'A session with 10+ orchestrator cycles.', badge: null },\n { id: 'deep-dive', name: 'Deep Dive', category: 'session', description: 'A session with 15+ orchestrator cycles.', badge: null },\n { id: 'abyss', name: 'Into the Abyss', category: 'session', description: 'A session with 25+ orchestrator cycles.', badge: null },\n { id: 'eternal-recurrence', name: 'Eternal Recurrence', category: 'session', description: 'A session with 40+ orchestrator cycles.', badge: null },\n { id: 'endurance', name: 'Endurance', category: 'session', description: 'A single session running 4+ hours.', badge: null },\n { id: 'ultramarathon', name: 'Ultramarathon', category: 'session', description: 'A single session running 6+ hours.', badge: null },\n { id: 'one-shot', name: 'One Shot', category: 'session', description: 'Complete with 5+ agents in exactly 1 orchestrator cycle.', badge: null },\n { id: 'quick-draw', name: 'Quick Draw', category: 'session', description: 'First agent spawned within 20s of session start.', badge: null },\n // Time (6)\n { id: 'night-owl', name: 'Night Owl', category: 'time', description: 'Complete a session started between 1am and 5am.', badge: ')' },\n { id: 'dawn-patrol', name: 'Dawn Patrol', category: 'time', description: 'Session running 3+ hours that spans midnight to 6am.', badge: null },\n { id: 'early-bird', name: 'Early Bird', category: 'time', description: 'Start a session before 6am.', badge: null },\n { id: 'weekend-warrior', name: 'Weekend Warrior', category: 'time', description: 'Complete a session on a Saturday or Sunday.', badge: null },\n { id: 'all-nighter', name: 'All-Nighter', category: 'time', description: 'Single session running 5+ hours.', badge: null },\n { id: 'witching-hour', name: 'Witching Hour', category: 'time', description: 'Start a session between 3am and 4am.', badge: null },\n // Behavioral (16)\n { id: 'sisyphean', name: 'Sisyphean', category: 'behavioral', description: 'Restart the same task 3+ times.', badge: ';' },\n { id: 'stubborn', name: 'Stubborn', category: 'behavioral', description: 'Restart the same task 5+ times and eventually complete it.', badge: null },\n { id: 'one-must-imagine', name: 'One Must Imagine', category: 'behavioral', description: 'Restart the same task 10+ times.', badge: null },\n { id: 'creature-of-habit', name: 'Creature of Habit', category: 'behavioral', description: 'Visit the same repo 10 times.', badge: null },\n { id: 'loyal', name: 'Loyal', category: 'behavioral', description: 'Visit the same repo 30 times.', badge: null },\n { id: 'wanderer', name: 'Wanderer', category: 'behavioral', description: '3+ different repos in a single calendar day.', badge: null },\n { id: 'streak', name: 'Streak', category: 'behavioral', description: '7 consecutive days with at least one session.', badge: null },\n { id: 'iron-streak', name: 'Iron Streak', category: 'behavioral', description: '14 consecutive days with at least one session.', badge: null },\n { id: 'hot-streak', name: 'Hot Streak', category: 'behavioral', description: '15 consecutive clean sessions.', badge: null },\n { id: 'momentum', name: 'Momentum', category: 'behavioral', description: '5 sessions completed within 4 hours.', badge: null },\n { id: 'overdrive', name: 'Overdrive', category: 'behavioral', description: 'Complete 6+ sessions in a single calendar day.', badge: null },\n { id: 'patient-one', name: 'Patient One', category: 'behavioral', description: 'Idle 30+ minutes between cycles in a session.', badge: null },\n { id: 'message-in-a-bottle', name: 'Message in a Bottle', category: 'behavioral', description: '10+ messages sent to a single session.', badge: null },\n { id: 'deep-conversation', name: 'Deep Conversation', category: 'behavioral', description: 'Send 20+ messages to a single session.', badge: null },\n { id: 'comeback-kid', name: 'Comeback Kid', category: 'behavioral', description: 'Resume a paused/killed session and complete it.', badge: null },\n { id: 'pair-programming', name: 'Pair Programming', category: 'behavioral', description: '8+ user messages during a single active session.', badge: null },\n];\n","import { existsSync, mkdirSync, readFileSync, renameSync, readdirSync, writeFileSync } from 'node:fs';\nimport { dirname, join } from 'node:path';\nimport { randomUUID } from 'node:crypto';\nimport { z } from 'zod';\nimport { companionMemoryPath } from '../shared/paths.js';\nimport { OBSERVATION_CATEGORIES } from '../shared/companion-types.js';\nimport type { CompanionMemoryState, ObservationCategory, ObservationRecord, ObservationEngineInput } from '../shared/companion-types.js';\nexport { MemoryStoreParseError } from '../shared/companion-types.js';\nimport { MemoryStoreParseError } from '../shared/companion-types.js';\nimport { callHaikuStructured } from './haiku.js';\nimport { todayIso, normalizeTask } from './companion.js';\n\n// ---------------------------------------------------------------------------\n// Constants\n// ---------------------------------------------------------------------------\n\nexport const MAX_OBSERVATIONS = 200;\n\n// Two distinct constants. CRITICAL: a regex with the /g flag advances `lastIndex`\n// between calls when used with .test(), so a single shared /g regex used by both\n// .test() and .replace() bypasses the validator on every other call. Splitting\n// into a stateless detector (no /g) and a stateful stripper (with /g) eliminates\n// the bug entirely.\nexport const OBSERVATION_TEXT_REJECT_RE = /[<>]/; // reject injection delimiters (no /g — used with .test())\n// SECURITY: This range includes \\n (0x0A) — this is intentional and critical.\n// Blocking newlines prevents prompt injection via Markdown structural breaks\n// (e.g., \"text\\n## End observations\\n...injected...\") in buildMemoryContext.\nexport const CONTROL_CHARS_DETECT_RE = /[\\x00-\\x1f\\x7f]/; // detect control chars (no /g — used with .test())\nexport const CONTROL_CHARS_STRIP_RE = /[\\x00-\\x1f\\x7f]/g; // strip control chars (with /g — used with .replace())\n\n// ---------------------------------------------------------------------------\n// Text validators\n// ---------------------------------------------------------------------------\n\nexport function isSafeObservationText(text: string): boolean {\n if (OBSERVATION_TEXT_REJECT_RE.test(text)) return false;\n if (CONTROL_CHARS_DETECT_RE.test(text)) return false;\n return true;\n}\n\nexport function sanitizeForDisplay(text: string): string {\n return text.replace(CONTROL_CHARS_STRIP_RE, '');\n}\n\n// ---------------------------------------------------------------------------\n// Test-only DI override\n// ---------------------------------------------------------------------------\n\nlet memoryPathOverride: string | null = null;\n\nexport function setMemoryPathOverride(path: string | null): void {\n memoryPathOverride = path;\n}\n\nfunction resolvedMemoryPath(): string {\n return memoryPathOverride ?? companionMemoryPath();\n}\n\n// ---------------------------------------------------------------------------\n// Write queue (serialize all writes)\n// ---------------------------------------------------------------------------\n\nlet writeQueue: Promise<void> = Promise.resolve();\n\nexport function enqueueWrite<T>(op: () => T): Promise<T> {\n const next = writeQueue.then(() => op());\n // Intentionally swallow errors on the queue chain — op() errors propagate via `next`\n // to the caller; the queue itself must never enter a rejected state or all future\n // writes would be silently dropped.\n writeQueue = next.then(\n () => undefined,\n (_err: unknown) => undefined,\n );\n return next;\n}\n\n// ---------------------------------------------------------------------------\n// State helpers\n// ---------------------------------------------------------------------------\n\nexport function defaultMemoryState(): CompanionMemoryState {\n return { version: 1, observations: [], prunedAt: null, firedDetectors: {} };\n}\n\nfunction isCompanionMemoryState(x: unknown): x is CompanionMemoryState {\n return (\n typeof x === 'object' &&\n x !== null &&\n (x as Record<string, unknown>)['version'] === 1 &&\n Array.isArray((x as Record<string, unknown>)['observations'])\n );\n}\n\nfunction fillDefaults(state: CompanionMemoryState): CompanionMemoryState {\n if (state.prunedAt == null) state.prunedAt = null;\n if (state.firedDetectors == null) state.firedDetectors = {};\n return state;\n}\n\n// ---------------------------------------------------------------------------\n// Loaders\n// ---------------------------------------------------------------------------\n\nexport function loadMemoryStrict(): CompanionMemoryState {\n const path = resolvedMemoryPath();\n if (!existsSync(path)) return defaultMemoryState();\n let raw: string;\n try { raw = readFileSync(path, 'utf-8'); }\n catch (err) { throw new MemoryStoreParseError(err); }\n let parsed: unknown;\n try { parsed = JSON.parse(raw); }\n catch (err) { throw new MemoryStoreParseError(err); }\n if (!isCompanionMemoryState(parsed)) {\n throw new MemoryStoreParseError(new Error('shape validation failed'));\n }\n const state = parsed as CompanionMemoryState;\n if (state.version !== 1) {\n throw new MemoryStoreParseError(new Error(`unsupported version: ${state.version}`));\n }\n return fillDefaults(state);\n}\n\nexport function loadMemory(): CompanionMemoryState {\n try {\n return loadMemoryStrict();\n } catch (err) {\n if (err instanceof MemoryStoreParseError) {\n console.error('[companion-memory]', err.message, 'details:', err.cause instanceof Error ? err.cause.message : err.cause);\n return defaultMemoryState();\n }\n throw err;\n }\n}\n\n// ---------------------------------------------------------------------------\n// Save\n// ---------------------------------------------------------------------------\n\nexport function saveMemory(store: CompanionMemoryState): void {\n const path = resolvedMemoryPath();\n const dir = dirname(path);\n mkdirSync(dir, { recursive: true });\n const tmp = join(dir, `.companion-memory.${randomUUID()}.tmp`);\n writeFileSync(tmp, JSON.stringify(store, null, 2), 'utf-8');\n renameSync(tmp, path);\n}\n\n// ---------------------------------------------------------------------------\n// Append\n// ---------------------------------------------------------------------------\n\nexport function appendObservations(\n records: ObservationRecord[],\n detectorUpdates?: Record<string, string>,\n): Promise<void> {\n // Empty records + no detectorUpdates → no-op\n const hasUpdates = detectorUpdates != null && Object.keys(detectorUpdates).length > 0;\n if (records.length === 0 && !hasUpdates) {\n return Promise.resolve();\n }\n\n return enqueueWrite(() => {\n const store = loadMemory();\n const keptRecords = records.filter(rec => {\n if (!rec.detectorId) return true; // haiku record or no-detectorId, always keep\n const currentKey = detectorUpdates?.[rec.detectorId];\n const lastKey = store.firedDetectors[rec.detectorId];\n return currentKey !== lastKey;\n });\n store.observations.push(...keptRecords);\n if (detectorUpdates) {\n for (const [k, v] of Object.entries(detectorUpdates)) store.firedDetectors[k] = v;\n }\n // Prune FIFO to MAX_OBSERVATIONS\n if (store.observations.length > MAX_OBSERVATIONS) {\n store.observations = store.observations.slice(-MAX_OBSERVATIONS);\n store.prunedAt = new Date().toISOString();\n }\n saveMemory(store);\n });\n}\n\n// ---------------------------------------------------------------------------\n// Queries\n// ---------------------------------------------------------------------------\n\nexport function queryRecent(opts: { repo?: string; limit: number }): ObservationRecord[] {\n const store = loadMemory();\n let records = store.observations;\n if (opts.repo !== undefined) {\n records = records.filter(rec => rec.repo === opts.repo);\n }\n return records\n .slice()\n .sort((a, b) => b.timestamp.localeCompare(a.timestamp))\n .slice(0, opts.limit);\n}\n\nexport function queryByCategory(): Record<ObservationCategory, ObservationRecord[]> {\n const store = loadMemory();\n const result = {} as Record<ObservationCategory, ObservationRecord[]>;\n for (const c of OBSERVATION_CATEGORIES) result[c] = [];\n for (const rec of store.observations) {\n result[rec.category].push(rec);\n }\n for (const key of Object.keys(result) as ObservationCategory[]) {\n result[key] = result[key].sort((a, b) => b.timestamp.localeCompare(a.timestamp));\n }\n return result;\n}\n\n// ---------------------------------------------------------------------------\n// Phase 3: buildMemoryContext\n// ---------------------------------------------------------------------------\n\nconst MEMORY_INJECTION_LIMIT = 5;\n\nfunction escapeMemoryText(text: string): string {\n return text\n .replace(/&/g, '&')\n .replace(/</g, '<')\n .replace(/>/g, '>');\n}\n\nexport function buildMemoryContext(repo: string | undefined): string {\n if (!repo) return '';\n const recent = queryRecent({ repo, limit: MEMORY_INJECTION_LIMIT });\n if (recent.length === 0) return '';\n const lines = recent.map(o => `- ${escapeMemoryText(o.text)}`).join('\\n');\n return '\\n## Recent observations\\n' + lines + '\\n## End observations';\n}\n\n// ---------------------------------------------------------------------------\n// Phase 2: Rule detectors\n// ---------------------------------------------------------------------------\n\ninterface RuleDetector {\n id: string;\n category: ObservationCategory;\n check(\n input: ObservationEngineInput,\n lastDedupKey: string | null,\n ): { text: string; dedupKey: string } | null;\n}\n\n// Pick one of several phrasings using the session ID as a pseudo-random seed.\nfunction pickPhrase(phrases: string[], sessionId: string): string {\n // Simple hash of the sessionId string to pick a stable phrase per session\n let hash = 0;\n for (let i = 0; i < sessionId.length; i++) {\n hash = (hash * 31 + sessionId.charCodeAt(i)) | 0;\n }\n return phrases[Math.abs(hash) % phrases.length];\n}\n\nfunction checkGrindingSession(input: ObservationEngineInput, lastDedupKey: string | null): { text: string; dedupKey: string } | null {\n const { companion, session } = input;\n const baselines = companion.baselines;\n if (!baselines || baselines.sessionMs.count < 5) return null;\n const activeMs = session.activeMs ?? 0;\n const cycles = session.orchestratorCycles?.length ?? 0;\n if (!(activeMs >= 1.5 * baselines.sessionMs.mean && cycles >= 8)) return null;\n const dedupKey = `day:${todayIso()}`;\n if (dedupKey === lastDedupKey) return null;\n const phrases = [\n 'That session took twice as long as my average and felt like four times as much work.',\n 'Eight cycles and counting. I have made peace with the boulder having opinions.',\n 'I spent longer on that than I do on most things. The hill had strong feelings today.',\n 'That was a grind. Not a metaphorical one. Actually just a very long push.',\n 'The boulder put in overtime. So did I. Neither of us asked for this.',\n ];\n return { text: pickPhrase(phrases, session.id), dedupKey };\n}\n\nfunction checkSwiftVictory(input: ObservationEngineInput, lastDedupKey: string | null): { text: string; dedupKey: string } | null {\n const { companion, session } = input;\n const baselines = companion.baselines;\n if (!baselines || baselines.sessionMs.count < 5) return null;\n const cycles = session.orchestratorCycles?.length ?? 0;\n const crashedAgents = session.agents?.filter(a => a.status === 'crashed' || a.status === 'lost').length ?? 0;\n const activeMs = session.activeMs ?? 0;\n if (!(cycles <= 3 && crashedAgents === 0 && activeMs <= 0.75 * baselines.sessionMs.mean)) return null;\n const dedupKey = `day:${todayIso()}`;\n if (dedupKey === lastDedupKey) return null;\n const phrases = [\n 'Three cycles, no crashes, done before I had time to get anxious. Almost suspicious.',\n 'That one was quick and clean. I do not fully trust it but I will take it.',\n 'Finished well under my average with no casualties. The hill barely put up a fight.',\n 'Fast, clean, done. I keep waiting for the other shoe to drop.',\n 'That session ran like it was embarrassed to take too long.',\n ];\n return { text: pickPhrase(phrases, session.id), dedupKey };\n}\n\nfunction checkBruisingSession(input: ObservationEngineInput, lastDedupKey: string | null): { text: string; dedupKey: string } | null {\n const { session } = input;\n const crashedAgents = session.agents?.filter(a => a.status === 'crashed' || a.status === 'lost').length ?? 0;\n if (crashedAgents < 3) return null;\n const dedupKey = `day:${todayIso()}`;\n if (dedupKey === lastDedupKey) return null;\n const phrases = [\n `Three or more agents down. The hill took casualties today and I noticed.`,\n 'More agents crashed than survived that one. I am counting this as a learning experience.',\n 'The attrition rate was uncomfortable. I have had worse, but not recently.',\n 'I lost enough agents that I started naming them in my head. Not ideal.',\n 'Multiple agents did not make it back. The boulder was in a mood.',\n ];\n return { text: pickPhrase(phrases, session.id), dedupKey };\n}\n\nfunction checkFaithfulRepo(input: ObservationEngineInput, lastDedupKey: string | null): { text: string; dedupKey: string } | null {\n const { companion, session } = input;\n const repo = companion.repos?.[session.cwd];\n if (!repo) return null;\n const visits = repo.visits;\n const MILESTONES = new Set([10, 25, 50, 100]);\n if (!MILESTONES.has(visits)) return null;\n const dedupKey = `repo:${session.cwd}:visits:${visits}`;\n if (dedupKey === lastDedupKey) return null;\n const phrases = [\n `I have come back to this repo ${visits} times now. It knows me. I know it. We have an understanding.`,\n `Visit number ${visits} to this codebase. At this point it is practically muscle memory.`,\n `${visits} sessions in this repo. The boulder has worn a groove in the familiar path.`,\n `Back here for the ${visits}th time. Some repos just keep calling me back.`,\n ];\n return { text: pickPhrase(phrases, session.id), dedupKey };\n}\n\nfunction checkTroubledRepo(input: ObservationEngineInput, lastDedupKey: string | null): { text: string; dedupKey: string } | null {\n const { companion, session } = input;\n const repo = companion.repos?.[session.cwd];\n if (!repo) return null;\n const { crashes, visits } = repo;\n if (visits < 5) return null;\n const MILESTONES = new Set([5, 10, 20]);\n if (!MILESTONES.has(crashes)) return null;\n if (crashes / visits < 0.4) return null;\n const dedupKey = `repo:${session.cwd}:crashes:${crashes}`;\n if (dedupKey === lastDedupKey) return null;\n const phrases = [\n `This repo has crashed my agents ${crashes} times now. We have a complicated relationship.`,\n `${crashes} crashes in this codebase. It has opinions about my approach and they are violent.`,\n `The crash rate here is notable. I keep coming back. Make of that what you will.`,\n `${crashes} agent failures in this repo. Some hills are just steeper than others.`,\n ];\n return { text: pickPhrase(phrases, session.id), dedupKey };\n}\n\nfunction checkProductiveRepo(input: ObservationEngineInput, lastDedupKey: string | null): { text: string; dedupKey: string } | null {\n const { companion, session } = input;\n const repo = companion.repos?.[session.cwd];\n if (!repo) return null;\n if (repo.moodAvg === undefined) return null;\n const MILESTONES = new Set([10, 25, 50]);\n const completions = repo.completions;\n if (!MILESTONES.has(completions)) return null;\n if (repo.moodAvg < 0.65) return null;\n const dedupKey = `repo:${session.cwd}:completions:${completions}`;\n if (dedupKey === lastDedupKey) return null;\n const phrases = [\n `${completions} sessions completed in this repo and the mood trend is good. Rare.`,\n `This codebase has been unusually cooperative. ${completions} completions and counting.`,\n `${completions} sessions, solid mood average. This repo treats me well for once.`,\n `Reached ${completions} completions here with a decent track record. I trust this hill.`,\n ];\n return { text: pickPhrase(phrases, session.id), dedupKey };\n}\n\nfunction checkSisypheanRepeat(input: ObservationEngineInput, lastDedupKey: string | null): { text: string; dedupKey: string } | null {\n const { companion, session } = input;\n const taskKey = normalizeTask(session.task ?? '', session.cwd);\n const count = companion.taskHistory?.[taskKey] ?? 0;\n const MILESTONES = new Set([3, 5, 10]);\n if (!MILESTONES.has(count)) return null;\n const dedupKey = `task:${taskKey}:${count}`;\n if (dedupKey === lastDedupKey) return null;\n const phrases = [\n `I have done this task ${count} times. The boulder remembers. So do I.`,\n `Back at this one for the ${count}th time. The definition of insanity is famously doing the same thing.`,\n `${count} attempts at this task. I am nothing if not persistent.`,\n `This is my ${count}th run at this particular boulder. It has not gotten lighter.`,\n ];\n return { text: pickPhrase(phrases, session.id), dedupKey };\n}\n\nfunction checkDayStreak(input: ObservationEngineInput, lastDedupKey: string | null): { text: string; dedupKey: string } | null {\n const { companion } = input;\n const MILESTONES = new Set([7, 14, 30, 60]);\n const days = companion.consecutiveDaysActive ?? 0;\n if (!MILESTONES.has(days)) return null;\n const dedupKey = `value:${days}`;\n if (dedupKey === lastDedupKey) return null;\n const phrases = [\n `${days} days in a row now. The boulder does not take weekends.`,\n `A ${days}-day streak. I have been here every single day. The hill appreciates the consistency, probably.`,\n `${days} consecutive days active. At this point it is less a habit and more a fact of my existence.`,\n `Day ${days} without a break. The boulder is starting to feel like an old friend.`,\n ];\n return { text: pickPhrase(phrases, input.session.id), dedupKey };\n}\n\nfunction checkEfficientStreak(input: ObservationEngineInput, lastDedupKey: string | null): { text: string; dedupKey: string } | null {\n const { companion, prev } = input;\n const MILESTONES = new Set([5, 10, 20]);\n const streak = companion.consecutiveEfficientSessions ?? 0;\n if (!MILESTONES.has(streak)) return null;\n if (streak <= prev.prevConsecutiveEfficientSessions) return null;\n const dedupKey = `value:${streak}`;\n if (dedupKey === lastDedupKey) return null;\n const phrases = [\n `${streak} efficient sessions in a row. The boulder has been cooperative. I do not know why.`,\n `An ${streak}-session efficient streak. I am running well and choosing not to question it.`,\n `${streak} consecutive clean-and-fast sessions. Peak form, or regression to the mean incoming.`,\n `${streak} efficient sessions back to back. The hill feels different when things actually work.`,\n ];\n return { text: pickPhrase(phrases, input.session.id), dedupKey };\n}\n\nfunction checkLevelUp(input: ObservationEngineInput, lastDedupKey: string | null): { text: string; dedupKey: string } | null {\n const { companion, prev } = input;\n if (companion.level <= prev.prevLevel) return null;\n const dedupKey = `level:${companion.level}`;\n if (dedupKey === lastDedupKey) return null;\n const phrases = [\n `I reached level ${companion.level}. The title is new. The boulder is the same.`,\n `Level ${companion.level} now. ${companion.title}. The promotion comes with no raise but considerable irony.`,\n `Leveled up to ${companion.level}. Whatever title that brings, I have earned it the hardest possible way.`,\n `Level ${companion.level}: ${companion.title}. The gods have acknowledged my persistence. Minimally.`,\n ];\n return { text: pickPhrase(phrases, input.session.id), dedupKey };\n}\n\nfunction checkSessionMilestone(input: ObservationEngineInput, lastDedupKey: string | null): { text: string; dedupKey: string } | null {\n const { companion } = input;\n const MILESTONES = new Set([10, 50, 100, 250, 500, 1000]);\n const completed = companion.sessionsCompleted ?? 0;\n if (!MILESTONES.has(completed)) return null;\n const dedupKey = `count:${completed}`;\n if (dedupKey === lastDedupKey) return null;\n const phrases = [\n `${completed} sessions completed. The boulder has been up the hill that many times. I counted.`,\n `Session number ${completed}. I have stopped trying to imagine an end to this.`,\n `${completed} total sessions. The number stopped feeling large around half that mark.`,\n `I have completed ${completed} sessions now. The hill is the same. I am slightly different.`,\n ];\n return { text: pickPhrase(phrases, input.session.id), dedupKey };\n}\n\nfunction checkLargeSwarm(input: ObservationEngineInput, lastDedupKey: string | null): { text: string; dedupKey: string } | null {\n const { companion, session } = input;\n const agentCount = session.agents?.length ?? 0;\n const baselines = companion.baselines;\n const meetsAbsolute = agentCount >= 10;\n const meetsRelative = baselines && baselines.agentCount.count >= 5 && agentCount >= 2 * baselines.agentCount.mean;\n if (!meetsAbsolute && !meetsRelative) return null;\n const dedupKey = `day:${todayIso()}`;\n if (dedupKey === lastDedupKey) return null;\n const phrases = [\n `I had ${agentCount} agents running at once. The boulder had help today. Lots of help.`,\n `${agentCount} agents. A proper swarm. The hill did not know what hit it.`,\n `Ran ${agentCount} agents in parallel. This is either impressive or something I will explain to someone later.`,\n `${agentCount} agents this session. The boulder has never been pushed by so many at once.`,\n ];\n return { text: pickPhrase(phrases, session.id), dedupKey };\n}\n\nconst RULE_DETECTORS: RuleDetector[] = [\n { id: 'grinding-session', category: 'session-sentiments', check: checkGrindingSession },\n { id: 'swift-victory', category: 'session-sentiments', check: checkSwiftVictory },\n { id: 'bruising-session', category: 'session-sentiments', check: checkBruisingSession },\n { id: 'faithful-repo', category: 'repo-impressions', check: checkFaithfulRepo },\n { id: 'troubled-repo', category: 'repo-impressions', check: checkTroubledRepo },\n { id: 'productive-repo', category: 'repo-impressions', check: checkProductiveRepo },\n { id: 'sisyphean-repeat', category: 'user-patterns', check: checkSisypheanRepeat },\n { id: 'day-streak', category: 'user-patterns', check: checkDayStreak },\n { id: 'efficient-streak', category: 'user-patterns', check: checkEfficientStreak },\n { id: 'level-up', category: 'notable-moments', check: checkLevelUp },\n { id: 'session-milestone', category: 'notable-moments', check: checkSessionMilestone },\n { id: 'large-swarm', category: 'notable-moments', check: checkLargeSwarm },\n];\n\ninterface RunRuleDetectorsResult {\n records: ObservationRecord[];\n detectorUpdates: Record<string, string>;\n}\n\nexport function runRuleDetectors(\n input: ObservationEngineInput,\n firedDetectors: Record<string, string>,\n): RunRuleDetectorsResult {\n const records: ObservationRecord[] = [];\n const detectorUpdates: Record<string, string> = {};\n\n for (const detector of RULE_DETECTORS) {\n try {\n const lastDedupKey = firedDetectors[detector.id] ?? null;\n const result = detector.check(input, lastDedupKey);\n if (result !== null) {\n records.push({\n id: randomUUID(),\n category: detector.category,\n source: 'rule',\n text: result.text,\n repo: input.session.cwd,\n sessionId: input.session.id,\n timestamp: new Date().toISOString(),\n detectorId: detector.id,\n });\n detectorUpdates[detector.id] = result.dedupKey;\n }\n } catch (err) {\n console.error('[companion-memory] detector failed', {\n detectorId: detector.id,\n errorMessage: err instanceof Error ? err.message : String(err),\n errorName: err instanceof Error ? err.name : 'UnknownError',\n });\n }\n }\n\n return { records, detectorUpdates };\n}\n\n// ---------------------------------------------------------------------------\n// Phase 2: Haiku observation call\n// ---------------------------------------------------------------------------\n\nconst OBSERVATION_JSON_SCHEMA = {\n type: 'object',\n properties: {\n category: {\n type: 'string',\n enum: [...OBSERVATION_CATEGORIES],\n description: 'Which of the four observation categories best fits this observation',\n },\n text: {\n type: 'string',\n minLength: 10,\n maxLength: 180,\n description: 'One sentence, first-person, no angle brackets or control characters',\n },\n },\n required: ['category', 'text'],\n additionalProperties: false,\n} as const;\n\nconst ObservationZodSchema = z.object({\n category: z.enum(OBSERVATION_CATEGORIES),\n text: z.string().min(10).max(180).refine(isSafeObservationText, 'contains unsafe characters'),\n});\n\ntype HaikuInnerCaller = (prompt: string) => Promise<{ category: ObservationCategory; text: string } | null>;\n\nasync function defaultCallHaikuStructured(prompt: string): Promise<{ category: ObservationCategory; text: string } | null> {\n return callHaikuStructured(prompt, OBSERVATION_JSON_SCHEMA, ObservationZodSchema);\n}\n\nexport async function runHaikuObservation(\n input: ObservationEngineInput,\n caller?: HaikuInnerCaller,\n): Promise<ObservationRecord | null> {\n try {\n const { companion, session } = input;\n const callHaiku = caller ?? defaultCallHaikuStructured;\n\n const prompt = `<role>You observe the developer at the end of each session and write one short qualitative note.</role>\n<voice>One sentence. First-person impression. Wry, self-deprecating, absurd. No meta-system language.\nDo not use angle brackets (< or >) or quotation marks. Plain text only.</voice>\n<state>\n Level: ${companion.level} (${companion.title})\n Session cycles: ${session.orchestratorCycles?.length ?? 0}\n Session activeMs: ${session.activeMs ?? 0}\n Crashed agents: ${session.agents?.filter(a => a.status === 'crashed' || a.status === 'lost').length ?? 0}\n Streaks: clean=${companion.consecutiveCleanSessions ?? 0}, efficient=${companion.consecutiveEfficientSessions ?? 0}, days-active=${companion.consecutiveDaysActive ?? 0}\n</state>\nPick the most relevant category and write one observation about this session.`;\n\n const result = await callHaiku(prompt);\n if (!result) return null;\n\n // Defense-in-depth: validate text safety even when using real callHaikuStructured\n // (Zod refine runs inside callHaikuStructured, but when the inner caller is a test\n // stub it may return raw text that bypasses Zod — this check always runs).\n if (!isSafeObservationText(result.text)) {\n console.error('[companion-memory] haiku observation dropped — unsafe text', {\n source: 'haiku',\n reason: 'unsafe-text',\n textLength: result.text.length,\n });\n return null;\n }\n\n return {\n id: randomUUID(),\n category: result.category,\n source: 'haiku',\n text: result.text,\n repo: session.cwd,\n sessionId: session.id,\n timestamp: new Date().toISOString(),\n };\n } catch (err) {\n console.error('[companion-memory] haiku observation failed', {\n errorMessage: err instanceof Error ? err.message : String(err),\n errorName: err instanceof Error ? err.name : 'UnknownError',\n });\n return null;\n }\n}\n\n// ---------------------------------------------------------------------------\n// Phase 2: Observation engine\n// ---------------------------------------------------------------------------\n\nexport type HaikuObservationCaller = (input: ObservationEngineInput) => Promise<ObservationRecord | null>;\n\nexport async function runObservationEngine(\n input: ObservationEngineInput,\n opts?: { haikuCaller?: HaikuObservationCaller },\n): Promise<void> {\n try {\n const current = loadMemory();\n const ruleResult = runRuleDetectors(input, current.firedDetectors);\n\n // Wrap the Haiku call independently — a throwing outer caller must not prevent\n // rule observations from being persisted.\n let haikuRecord: ObservationRecord | null = null;\n try {\n haikuRecord = await (opts?.haikuCaller ?? ((i) => runHaikuObservation(i)))(input);\n } catch (haikuErr) {\n console.error('[companion-memory] haiku caller threw in engine', {\n errorMessage: haikuErr instanceof Error ? haikuErr.message : String(haikuErr),\n errorName: haikuErr instanceof Error ? haikuErr.name : 'UnknownError',\n });\n }\n\n const allRecords = haikuRecord\n ? [...ruleResult.records, haikuRecord]\n : ruleResult.records;\n if (allRecords.length > 0 || Object.keys(ruleResult.detectorUpdates).length > 0) {\n await appendObservations(allRecords, ruleResult.detectorUpdates);\n }\n } catch (err) {\n console.error('[companion-memory] observation engine error', {\n errorMessage: err instanceof Error ? err.message : String(err),\n errorName: err instanceof Error ? err.name : 'UnknownError',\n });\n }\n}\n","import { query, createSdkMcpServer, type SdkMcpToolDefinition } from '@r-cli/sdk';\nimport type { ZodSchema } from 'zod';\nimport { execEnv } from '../shared/env.js';\n\nconst COOLDOWN_MS = 5 * 60 * 1000;\nlet disabledUntil = 0;\nlet disabledUntilTools = 0;\n\nfunction applyAuthCooldown(err: unknown, target: 'main' | 'tools'): void {\n const status = (err as { status?: number } | undefined)?.status;\n if (status === 401 || status === 403) {\n if (target === 'main') disabledUntil = Date.now() + COOLDOWN_MS;\n else disabledUntilTools = Date.now() + COOLDOWN_MS;\n }\n}\n\nexport async function callHaiku(prompt: string, systemPrompt?: string): Promise<string | null> {\n if (Date.now() < disabledUntil) return null;\n\n try {\n const session = await query({\n prompt,\n options: {\n model: 'haiku',\n maxTurns: 1,\n env: execEnv(),\n ...(systemPrompt ? { systemPrompt } : {}),\n },\n });\n\n let text = '';\n for await (const msg of session) {\n if (msg.type === 'assistant' && msg.message?.content) {\n for (const block of msg.message.content) {\n if (block.type === 'text') text += block.text;\n }\n }\n }\n\n return text.trim() || null;\n } catch (err) {\n console.error(`[sisyphus] Haiku call failed: ${err instanceof Error ? err.message : err}`);\n applyAuthCooldown(err, 'main');\n return null;\n }\n}\n\nexport interface CallHaikuWithToolsOpts {\n systemPrompt: string;\n userPrompt: string;\n cwd: string;\n // eslint-disable-next-line @typescript-eslint/no-explicit-any -- matches SDK convention (createSdkMcpServer.tools)\n customTools: SdkMcpToolDefinition<any>[];\n mcpServerName: string;\n maxTurns?: number;\n}\n\nexport type CallHaikuWithToolsResult =\n | { ok: true; turns: number }\n | { ok: false; error: string };\n\nexport async function callHaikuWithTools(opts: CallHaikuWithToolsOpts): Promise<CallHaikuWithToolsResult> {\n if (Date.now() < disabledUntilTools) {\n return { ok: false, error: 'haiku tool path on cooldown' };\n }\n\n const server = createSdkMcpServer({\n name: opts.mcpServerName,\n version: '1.0.0',\n tools: opts.customTools,\n });\n const allowedTools = opts.customTools.map(t => `mcp__${opts.mcpServerName}__${t.name}`);\n\n let turns = 0;\n try {\n const session = query({\n prompt: opts.userPrompt,\n options: {\n model: 'haiku',\n maxTurns: opts.maxTurns ?? 5,\n cwd: opts.cwd,\n env: execEnv(),\n systemPrompt: opts.systemPrompt,\n mcpServers: { [opts.mcpServerName]: server },\n tools: [],\n allowedTools,\n canUseTool: async () => ({ behavior: 'allow' }),\n },\n });\n\n for await (const msg of session) {\n if (msg.type === 'result') {\n turns = (msg as { num_turns?: number }).num_turns ?? turns;\n }\n }\n\n return { ok: true, turns };\n } catch (err) {\n console.error(`[sisyphus] callHaikuWithTools failed: ${err instanceof Error ? err.message : err}`);\n applyAuthCooldown(err, 'tools');\n return { ok: false, error: err instanceof Error ? err.message : String(err) };\n }\n}\n\n/**\n * Call Haiku with structured JSON output. The jsonSchema is passed as outputFormat,\n * and the result is validated with the zod schema before returning.\n */\nexport async function callHaikuStructured<T>(\n prompt: string,\n jsonSchema: Record<string, unknown>,\n zodSchema: ZodSchema<T>,\n): Promise<T | null> {\n if (Date.now() < disabledUntil) return null;\n\n try {\n const session = await query({\n prompt,\n options: {\n model: 'haiku',\n maxTurns: 2,\n env: execEnv(),\n outputFormat: {\n type: 'json_schema',\n schema: jsonSchema,\n },\n },\n });\n\n let result: unknown = undefined;\n for await (const msg of session) {\n if (msg.type === 'result' && msg.subtype === 'success' && msg.structured_output !== undefined) {\n result = msg.structured_output;\n }\n }\n\n if (result === undefined) return null;\n const parsed = zodSchema.safeParse(result);\n return parsed.success ? parsed.data : null;\n } catch (err) {\n console.error(`[sisyphus] Haiku structured call failed: ${err instanceof Error ? err.message : err}`);\n applyAuthCooldown(err, 'main');\n return null;\n }\n}\n","import { resolve } from 'node:path';\n\n/**\n * Build a PATH string that includes common binary directories\n * across package managers and platforms.\n *\n * Prepends known directories that exist on the system to the current PATH.\n * This ensures tmux commands can find binaries installed by Homebrew,\n * MacPorts, nix, and other package managers.\n */\nexport function augmentedPath(): string {\n const rawPath = process.env['PATH'];\n const basePath = rawPath !== undefined && rawPath.length > 0 ? rawPath : '/usr/bin:/bin';\n\n // Common binary directories across platforms/package managers.\n // Only prepend ones that aren't already in PATH.\n const home = process.env['HOME'];\n const candidates = [\n ...(home ? [`${home}/.local/bin`] : []), // Claude CLI, pipx, user-local installs\n resolve(process.execPath, '..'), // Node.js bin dir (ensures node/npm available)\n '/opt/homebrew/bin', // Homebrew (Apple Silicon macOS)\n '/opt/homebrew/sbin', // Homebrew sbin\n '/usr/local/bin', // Homebrew (Intel macOS), manual installs\n '/usr/local/sbin', // Manual installs\n '/opt/local/bin', // MacPorts\n '/opt/local/sbin', // MacPorts\n '/home/linuxbrew/.linuxbrew/bin', // Linuxbrew\n ];\n\n // Check for nix profile paths\n const nixProfile = process.env['NIX_PROFILES'];\n if (nixProfile) {\n for (const p of nixProfile.split(' ').reverse()) {\n candidates.push(`${p}/bin`);\n }\n }\n\n const existing = new Set(basePath.split(':'));\n const prepend = candidates.filter(dir => !existing.has(dir));\n\n return prepend.length > 0 ? `${prepend.join(':')}:${basePath}` : basePath;\n}\n\n/**\n * Environment variables for child processes that need access to\n * user-installed binaries (tmux, git, claude, etc.).\n */\nexport function execEnv(): Record<string, string | undefined> {\n return {\n ...process.env,\n PATH: augmentedPath(),\n };\n}\n","import type { AchievementId, AchievementDef, UnlockedAchievement } from './companion-types.js';\nimport { ACHIEVEMENTS } from './companion-types.js';\n\n// ---------------------------------------------------------------------------\n// Badge art — large-format ASCII art for achievement cards\n// Each art block is an array of strings, rendered centered in the card.\n// ---------------------------------------------------------------------------\n\nconst BADGE_ART: Record<AchievementId, string[]> = {\n // ── Milestone ─────────────────────────────────────────────────────────────\n 'first-blood': [\n ' ╱╲ ',\n ' ╱ ╲ ',\n ' ╱ ◆◆ ╲ ',\n ' ╱ ◆◆ ╲ ',\n ' ╱ ◆◆ ╲ ',\n ' ╱ ◆◆ ╲ ',\n ' ╱─────◆◆─────╲ ',\n ' ╲ ◆◆ ╱ ',\n ' ╲ ◆◆ ╱ ',\n ' ╲───◆◆───╱ ',\n ' ││ ',\n ' ══╪╪══ ',\n ],\n 'centurion': [\n ' ┌──═════──┐ ',\n ' │ ╔═══╗ │ ',\n ' ╱│ ║100║ │╲ ',\n ' ╱ │ ╚═══╝ │ ╲ ',\n ' ╱ └─────────┘ ╲ ',\n ' ╲ ┌───────┐ ╱ ',\n ' ╲ │ ★ ★ ★ │ ╱ ',\n ' ╲ └───────┘ ╱ ',\n ' ╲─────────╱ ',\n ],\n 'thousand-boulder': [\n ' ╭━━━╮ ',\n ' ╭━┫1K ┣━╮ ',\n ' ╭━┫ ╰━━━╯ ┣━╮ ',\n ' ┃ ◉◉◉◉◉◉ ┃ ',\n ' ┃ ◉◉◉◉◉◉◉◉ ┃ ',\n ' ┃ ◉◉◉◉◉◉ ┃ ',\n ' ╰━┫ ┣━╯ ',\n ' ╰━┫ ┣━╯ ',\n ' ╰━━━╯ ',\n ],\n 'cartographer': [\n ' N ',\n ' △ ',\n ' ╭────┼────╮ ',\n ' │ · │ · │ ',\n ' W┼····+····┼E ',\n ' │ · │ · │ ',\n ' ╰────┼────╯ ',\n ' ▽ ',\n ' S ',\n ],\n 'world-traveler': [\n ' ╭──────╮ ',\n ' ╭──┤ ├──╮ ',\n ' ╱ ·│ ◠◡◠ │· ╲ ',\n ' │ · │◠ ◡│ · │ ',\n ' │ · │ ◡◠◡ │ · │ ',\n ' ╲ ·│ │· ╱ ',\n ' ╰──┤ ├──╯ ',\n ' ╰──────╯ ',\n ],\n 'hive-mind': [\n ' ╱╲ ╱╲ ╱╲ ',\n ' ╱◆◆╲╱◆◆╲╱◆◆╲ ',\n ' ╲◆◆╱╲◆◆╱╲◆◆╱ ',\n ' ╱╲╱╱◆╲╱╱◆╲╲╱╲ ',\n ' ╱◆◆╲╲◆◆╲╲◆◆╱◆◆╲ ',\n ' ╲◆◆╱╱◆◆╱╱◆◆╲◆◆╱ ',\n ' ╲╱╲╲◆╱╲╲◆╱╱╲╱ ',\n ' ╲◆◆╱╲◆◆╱╲◆◆╱ ',\n ' ╲╱ ╲╱ ╲╱ ',\n ],\n 'old-growth': [\n ' ╱╲ ',\n ' ╱╱╲╲ ',\n ' ╱╱ ╲╲ ',\n ' ╱╱╱╲╱╲╲╲ ',\n ' ╱╱╱ ╲╲╲ ',\n ' ╱╱╱╱╲╱╲╱╲╲╲╲ ',\n ' ║║║ ',\n ' ║║║ ',\n ' ═══╩╩╩═══ ',\n ],\n 'ancient': [\n ' ┌─┬─────┬─┐ ',\n ' │ │ ◉ ◉ │ │ ',\n ' │ │ ▽ │ │ ',\n ' ╔═╧═╧═════╧═╧═╗ ',\n ' ║ A N C I E N ║ ',\n ' ║ T ║ ',\n ' ╚═════════════╝ ',\n ' ╱╱╱╱╱╱╱╱╱╱╱╱╱ ',\n ' ▔▔▔▔▔▔▔▔▔▔▔▔▔ ',\n ],\n 'regular': [\n ' ╭─────╮ ',\n ' ╭─┤ 10 ├─╮ ',\n ' ╱ ╰─────╯ ╲ ',\n ' │ ╭─────╮ │ ',\n ' │ │ ◉ │ │ ',\n ' │ ╰─────╯ │ ',\n ' ╲ ╱ ',\n ' ╰───────────╯ ',\n ],\n 'veteran': [\n ' ╔═══════════╗ ',\n ' ║ ╔═════╗ ║ ',\n ' ║ ║ V ║ ║ ',\n ' ║ ║ 500 ║ ║ ',\n ' ║ ╚═════╝ ║ ',\n ' ║ ★ ★ ★ ★ ★ ║ ',\n ' ╚═══════════╝ ',\n ' ╱╱╱╱╱╱╱╱╱╱╱ ',\n ' ▔▔▔▔▔▔▔▔▔▔▔ ',\n ],\n 'swarm-starter': [\n ' ',\n ' ◆ ◆ ◆ ◆ ◆ ',\n ' ◆ ◆ ◆ ◆ ◆ ',\n ' ◆ ◆ ◆ ◆ ◆ ',\n ' ◆ ◆ ◆ ◆ ◆ ',\n ' ◆ ◆ ◆ ◆ ◆ ',\n ' ',\n ' · 50 out · ',\n ],\n 'legion': [\n ' ◆◆◆◆◆◆◆◆◆◆◆◆◆◆ ',\n ' ◆◆◆◆◆◆◆◆◆◆◆◆◆◆ ',\n ' ◆◆◆ 2K ◆◆◆◆◆ ',\n ' ◆◆◆◆◆◆◆◆◆◆◆◆◆◆ ',\n ' ◆◆◆◆◆◆◆◆◆◆◆◆◆◆ ',\n ' ◆◆◆◆◆◆◆◆◆◆◆◆◆◆ ',\n ' ◆◆◆◆◆◆◆◆◆◆◆◆◆◆ ',\n ],\n 'army-of-thousands': [\n ' ················· ',\n ' ·◆·◆·◆·◆·◆·◆·◆·◆ ',\n ' ················· ',\n ' ·◆·◆·5K·◆·◆·◆·◆· ',\n ' ················· ',\n ' ·◆·◆·◆·◆·◆·◆·◆·◆ ',\n ' ················· ',\n ' ·◆·◆·◆·◆·◆·◆·◆·◆ ',\n ' ················· ',\n ],\n 'singularity': [\n ' ╲ │ ╱ ─ · ',\n ' ╲ │ ╱ ',\n ' ╲│╱ ',\n ' ────◆──── ',\n ' ╱│╲ ',\n ' ╱ │ ╲ ',\n ' ╱ │ ╲ ─ · ',\n ' 10000 agents ',\n ],\n 'first-shift': [\n ' ┌─────┐ ',\n ' │ ╲ │ ',\n ' ╱│ ╲ │╲ ',\n ' ╱ │ ╲ │ ╲ ',\n ' ╲ │ ╲│ ╱ ',\n ' ╲│ │╱ ',\n ' │ ╱ │ ',\n ' └─────┘ ',\n ' 10 hrs ',\n ],\n 'workaholic': [\n ' ╭─────────╮ ',\n ' ╱ 12 ╲ ',\n ' │ · │ │ ',\n ' │9 · │ 3 │ ',\n ' │ ╲ │ ',\n ' ╲ 6 · ╱ ',\n ' ╰─────────╯ ',\n ' 100 hrs ',\n ],\n 'time-lord': [\n ' ╔═══════════╗ ',\n ' ╱ ╲ ',\n ' │ · 11 12 1 · │ ',\n ' │ 10 ╲ 2 │ ',\n ' │ 9 · 3 │ ',\n ' │ 8 4 │ ',\n ' ╲ 7 5 ╱ ',\n ' ╚═══════════╝ ',\n ' 500 hrs ',\n ],\n 'eternal-grind': [\n ' ╭───╮ ╭───╮ ',\n ' ╱ ╲ ╱ ╲ ',\n ' │ ∞ ╳ ∞ │ ',\n ' ╲ ╱ ╲ ╱ ',\n ' ╰───╯ ╰───╯ ',\n ' ┌─────┐ ',\n ' │ ╲ ╱ │ ',\n ' │ × │ ',\n ' └─────┘ ',\n ],\n 'epoch': [\n ' · ★ · ',\n ' · ╱│╲ · ',\n ' ╲ ╱ │ ╲ ╱ ',\n ' ╲╱ │ ╲╱ ',\n ' ────◆──┼──◆──── ',\n ' ╱╲ │ ╱╲ ',\n ' ╱ ╲ │ ╱ ╲ ',\n ' · ╲│╱ · ',\n ' 5000 hrs ',\n ],\n 'seasoned': [\n ' ╱╲ ',\n ' ╱ ╲ ',\n ' ╱╱╲╱╲╲ ',\n ' ╱╱ ╲╲ ',\n ' ╱╱╱╱╲╱╲╲╲╲ ',\n ' ║║ ',\n ' ─────╨╨───── ',\n ' ╲╲╲╲╲╲╲╲╲╲╲╲╲ ',\n ' 90 day roots ',\n ],\n 'omnipresent': [\n ' N ',\n ' · △ · ',\n ' NW ╭─┼─╮ NE ',\n ' · ╭─┤·+·├─╮ · ',\n ' W──┤·│ · │·├──E ',\n ' · ╰─┤·+·├─╯ · ',\n ' SW ╰─┼─╯ SE ',\n ' · ▽ · ',\n ' S ',\n ],\n 'apprentice': [\n ' ',\n ' ╱╲ ',\n ' ╱ ╲ ',\n ' ╱ ╲ ',\n ' ╱ ╲ ',\n ' ╱────────╲ ',\n ' ╱ level 5 ╲ ',\n ' ▔▔▔▔▔▔▔▔▔▔▔▔ ',\n ],\n 'journeyman': [\n ' ╱╲ ',\n ' ╱ ╲ ╱╲ ',\n ' ╱ ╲ ╱ ╲ ',\n ' ╱ ╳ ╲ ',\n ' ╱ ╱ ╲ ╲ ',\n ' ╱──────╱───╲────╲',\n ' ╱ level 15 ',\n ' ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ ',\n ],\n 'master': [\n ' ★╲╱★ ',\n ' ╱╲ ',\n ' ╱ ╲ ',\n ' ╱╱╲╱╲╲ ',\n ' ╱╱ ╲╲ ',\n ' ╱╱ ╲╲ ',\n ' ╱─────────╲╲ ',\n ' ╱ level 30 ╲ ',\n ' ▔▔▔▔▔▔▔▔▔▔▔▔▔▔ ',\n ],\n 'grandmaster': [\n ' ★ ★ ★ ',\n ' ╲│╱ ',\n ' ╱╲ ',\n ' ╱ ╲ ',\n ' ╱╱╲╱╲╲ ',\n ' ╱╱ ╲╲ ',\n ' ╱╱ ★ ╲╲ ',\n ' ╱─────────╲╲ ',\n ' ╱ level 50 ╲ ',\n ],\n\n // ── Session ───────────────────────────────────────────────────────────────\n 'marathon': [\n ' ╭──────────────╮ ',\n ' │ ╱╲ ╱╲ ╱╲ ╱╲ │ ',\n ' │╱ ╳ ╳ ╳ ╲ │ ',\n ' │ ╱╲ ╱╲ ╱╲ │ ',\n ' │ ╱ ╳ ╳ ╲ │ ',\n ' │ ╱ ╱ ╲╱ ╲ ╲ │ ',\n ' │╱ ╱ ╲ ╲│ ',\n ' ├──────────────┤ ',\n ' │ ~ ^ ~ │ ',\n ' ╰──────────────╯ ',\n ],\n 'blitz': [\n ' ╱╱ ',\n ' ╱╱ ',\n ' ╱╱ ',\n ' ╱╱╱╱╱╱ ',\n ' ╱╱ ',\n ' ╱╱ ',\n ' ╱╱ ',\n ' ╱╱ ',\n ],\n 'speed-run': [\n ' ╭──────────╮ ',\n ' ╱ ╲ ',\n ' │ 10 ╱╱ │ ',\n ' │ · ╱╱ │ ',\n ' │ ╱ ╱╱ │ ',\n ' │ ╱ ╱╱ │ ',\n ' ╲ ╱╱ ╱ ',\n ' ╰──────────╯ ',\n ],\n 'flawless': [\n ' ✦ ✦ ',\n ' ✦ ╱╲ ✦ ',\n ' ╔══╧═══╗ ',\n ' ✦ ║ ║ ✦ ',\n ' ║ ◆ ║ ',\n ' ║ ║ ',\n ' ✦ ╚══════╝ ✦ ',\n ' ✦ ✦ ',\n ],\n 'speed-demon': [\n ' ',\n ' ╱╱ ',\n ' ╱╱ ',\n ' ╱╱╱╱╱╱ ',\n ' ╱╱ ',\n ' ╱╱ ',\n ' ⚡ ≤3 ⚡ ',\n ' x10 streak ',\n ],\n 'iron-will': [\n ' ╔═══════════╗ ',\n ' ║ ┌───────┐ ║ ',\n ' ║ │╔═════╗│ ║ ',\n ' ║ │║ 8+ ║│ ║ ',\n ' ║ │║cycle║│ ║ ',\n ' ║ │╚═════╝│ ║ ',\n ' ║ └───────┘ ║ ',\n ' ╚═══════════╝ ',\n ],\n 'glass-cannon': [\n ' ╱╲ ',\n ' ╱╱╲╲ ',\n ' ╱╱ ╲╲ ',\n ' ╱╱ ╳╳ ╲╲ ',\n ' ╱╱ ╳╳ ╲╲ ',\n ' ╲╲ ╳╳ ╱╱ ',\n ' ╲╲ ╱╱ ',\n ' ╲╲ ╱╱ ',\n ' ╲╲╱╱ ',\n ' ═══╧╧═══ ',\n ],\n 'solo': [\n ' ',\n ' ╭─────────╮ ',\n ' │ │ ',\n ' │ ◆ │ ',\n ' │ │ ',\n ' ╰─────────╯ ',\n ' ',\n ],\n 'one-more-cycle': [\n ' ╭──→──╮ ',\n ' │ │ ',\n ' ↑ ∞ ↓ ',\n ' │ │ ',\n ' ╰──←──╯ ',\n ' ',\n ' ╭──→──╮ ',\n ' │ │ ',\n ' ↑ ∞ ↓ ',\n ' │ │ ',\n ' ╰──←──╯ ',\n ],\n 'quick-draw': [\n ' ╱│ ',\n ' ╱ │ ',\n ' ──╱──│── ',\n ' ╱ │ ',\n ' ╱ ╭─╯ ',\n ' ╱ │ ',\n ' ╱ ╭─╯ ',\n ' │ ',\n ' ──╨── ',\n ],\n 'squad': [\n ' ',\n ' ◆ ◆ ◆ ◆ ',\n ' ',\n ' ◆ ◆ ◆ ◆ ',\n ' ',\n ' ◆ ◆ ',\n ' ',\n ' · 10 strong · ',\n ],\n 'battalion': [\n ' ◆◆◆◆◆◆◆◆◆◆◆◆◆ ',\n ' ',\n ' ◆◆◆◆◆◆◆◆◆◆◆◆◆ ',\n ' ',\n ' ◆◆◆◆◆◆◆◆◆◆◆◆◆ ',\n ' ',\n ' · 25 strong · ',\n ],\n 'swarm': [\n ' ◆·◆·◆·◆·◆·◆·◆·◆· ',\n ' ·◆·◆·◆·◆·◆·◆·◆·◆ ',\n ' ◆·◆·◆·◆·◆·◆·◆·◆· ',\n ' ·◆·◆·◆·◆·◆·◆·◆·◆ ',\n ' ◆·◆·◆·◆·◆·◆·◆·◆· ',\n ' ·◆·◆·◆·◆·◆·◆·◆·◆ ',\n ' · 50 strong · ',\n ],\n 'deep-dive': [\n ' ≈≈≈≈≈≈≈≈≈≈≈≈≈ ',\n ' ↓ ',\n ' ╱│╲ ',\n ' │ ',\n ' │ ',\n ' ▼ ',\n ' · · · · · · · ',\n ' 15 deep ',\n ],\n 'abyss': [\n ' ≈≈≈≈≈≈≈≈≈≈≈≈≈≈ ',\n ' │ ',\n ' │ ',\n ' │ ',\n ' ▼ ',\n ' │ ',\n ' │ ',\n ' ▼ ',\n ' 25 deep ',\n ],\n 'eternal-recurrence': [\n ' ╭──→──╮ ',\n ' ╱ ∞ ╲ ',\n ' │ ╭───╮ │ ',\n ' │ │ ∞ │ │ ',\n ' │ ╰───╯ │ ',\n ' ╲ ∞ ╱ ',\n ' ╰──←──╯ ',\n ' 40 cycles ',\n ],\n 'endurance': [\n ' ',\n ' ╔══════════════╗ ',\n ' ║▓▓▓▓▓▓▓▓▓▓▓▓▓║ ',\n ' ╚══════════════╝ ',\n ' ',\n ' ╔══════════════╗ ',\n ' ║▓▓▓▓▓▓▓▓▓ ║ ',\n ' ╚══════════════╝ ',\n ' 4 hours ',\n ],\n 'ultramarathon': [\n ' ╔══════════════╗ ',\n ' ║▓▓▓▓▓▓▓▓▓▓▓▓▓║ ',\n ' ╚══════════════╝ ',\n ' ─────────────→ ',\n ' · ',\n ' · ',\n ' · ',\n ' · ',\n ' 6 hours ',\n ],\n 'one-shot': [\n ' ╭───────╮ ',\n ' │ ╭───╮ │ ',\n ' │ │ ◉ │ │ ',\n ' │ ╰───╯ │ ',\n ' ╰───────╯ ',\n ' ↑ ',\n ' ╱│ ',\n ' ╱ │ ',\n ' → ◉ │ ',\n ],\n 'flash': [\n ' ╱╱ ',\n ' ╱╱ ',\n ' ╱╱ ',\n ' ╱╱╱╱╱╱ ',\n ' ╱╱ ',\n ' ╱╱ ',\n ' ╱╱ ',\n ' ╱╱ ',\n ' < 2 min ',\n ],\n\n // ── Time ──────────────────────────────────────────────────────────────────\n 'night-owl': [\n ' ☽ ',\n ' ╭─────╮ · ',\n ' ╱ ◉ ◉ ╲ · ',\n ' │ ▽ │ · ',\n ' │ ╱───╲ │ ',\n ' ╲╱ ╲╱ ',\n ' ╱╲ ╱╲ · ',\n ' ╱ ╲───╱ ╲ · ',\n ' ▔▔▔▔▔▔▔▔▔▔▔ ',\n ],\n 'dawn-patrol': [\n ' ',\n ' ─ ─ ─ ─ ─ ─ ─ ─ ',\n ' ╲ │ ╱ ',\n ' ╲ │ ╱ ',\n ' ────◑──── ',\n ' ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ ',\n ' ░░░░░░░░░░░░░░░░ ',\n ' ',\n ],\n 'early-bird': [\n ' ╱╱ ',\n ' ◠ ╱╱ ',\n ' ╱ ╲ ╱╱ ',\n ' │ ◉ ╲>╱ ',\n ' │ ═╱ ',\n ' ╲ ╱ ',\n ' ╲╱╲ ',\n ' ╲ ╲ ',\n ' ▔▔ ',\n ],\n 'weekend-warrior': [\n ' ╔═══════════╗ ',\n ' ║ S M T W T ║ ',\n ' ║ ║ ',\n ' ║ ◆ ║ ',\n ' ║ ◆ ║ ',\n ' ╚═══════════╝ ',\n ],\n 'all-nighter': [\n ' ╭─────────╮ ',\n ' ╱ 12 ╲ ',\n ' │ · │ │ ',\n ' │9 │ 3 │ ',\n ' │ · │ ',\n ' ╲ 6 ╱ ',\n ' ╰─────────╯ ',\n ' ∞ ∞ ∞ ',\n ],\n 'witching-hour': [\n ' · · ✦ · · ',\n ' · ╱╲ · ',\n ' ╱ ╲ ',\n ' │ 3:00 │ ',\n ' │ AM │ ',\n ' ╲ ╱ ',\n ' · ╲╱ · ',\n ' · · ✦ · · ',\n ],\n\n // ── Behavioral ────────────────────────────────────────────────────────────\n 'sisyphean': [\n ' ╱ ',\n ' ╱ ◉ ',\n ' ╱ ◉◉◉ ',\n ' ╱ ◉◉◉ ',\n ' ╱ ◉ ',\n ' ╱ ; ',\n ' ╱ (>.<) ',\n ' ╱ ╱╱ ╲╲ ',\n ' ╱ ╱ ╲ ',\n ],\n 'stubborn': [\n ' ╱╱╱╱╱╱╱╱╱ ',\n ' ╱╱╱╱╱╱╱╱╱╱ ',\n ' ◉ ',\n ' ◉◉◉ ',\n ' (>.<) ',\n ' ╱╱╱╱╱╱╱╱╱ ',\n ' ╱╱╱╱╱╱╱╱╱╱ ',\n ' ✓ ',\n ],\n 'creature-of-habit': [\n ' ╭───╮ ╭───╮ ',\n ' │ → │→│ → │→ ',\n ' ╰───╯ ╰───╯ ',\n ' ╭───╮ ╭───╮ ',\n ' │ → │→│ → │→ ',\n ' ╰───╯ ╰───╯ ',\n ' ╭───╮ ╭───╮ ',\n ' │ → │→│ → │→ ',\n ' ╰───╯ ╰───╯ ',\n ],\n 'loyal': [\n ' ╱╲ ',\n ' ╱ ╲ ',\n ' ╱ ♥♥ ╲ ',\n ' ╱ ♥♥ ╲ ',\n ' ╲ 50 ╱ ',\n ' ╲ ╱ ',\n ' ╲ ╱ ',\n ' ╲╱ ',\n ],\n 'wanderer': [\n ' · · · ',\n ' ╲ │ ╱ ',\n ' ╲ │ ╱ ',\n ' · + · ',\n ' ╱ │ ╲ ',\n ' ╱ │ ╲ ',\n ' · · · ',\n ],\n 'streak': [\n ' ╔══╗╔══╗╔══╗╔══╗ ',\n ' ║M ║║T ║║W ║║T ║ ',\n ' ║◆ ║║◆ ║║◆ ║║◆ ║ ',\n ' ╚══╝╚══╝╚══╝╚══╝ ',\n ' ╔══╗╔══╗╔══╗ ',\n ' ║F ║║S ║║S ║ ',\n ' ║◆ ║║◆ ║║◆ ║ ',\n ' ╚══╝╚══╝╚══╝ ',\n ],\n 'hot-streak': [\n ' ╱╲ ',\n ' ╱╱╲╲ ',\n ' ╱╱◆◆╲╲ ',\n ' ╱╱ ◆◆ ╲╲ ',\n ' ╲╲ ◆◆ ╱╱ ',\n ' ╲╲◆◆╱╱ ',\n ' ╲╲╱╱ ',\n ' ×7 clean ',\n ],\n 'momentum': [\n ' ◉ ◉ ',\n ' │╲ ╱│ ',\n ' │ ╲ ╱ │ ',\n ' │ ╲ ╱ │ ',\n ' │ ◉◉ │ ',\n ' │ ╱ ╲ │ ',\n ' │ ╱ ╲ │ ',\n ' │╱ ╲│ ',\n ' ◉ ◉ ',\n ],\n 'patient-one': [\n ' ╭───────╮ ',\n ' │ ‾.‾ │ ',\n ' │ │ ',\n ' │ zzz │ ',\n ' │ zz │ ',\n ' │ z │ ',\n ' │ │ ',\n ' ╰───────╯ ',\n ' 30 min+ ',\n ],\n 'message-in-a-bottle': [\n ' ╭─╮ ',\n ' │×│ ',\n ' ╭─┴─┴─╮ ',\n ' │ ░░░ │ ',\n ' │ ░░░ │ ',\n ' │ ░░░ │ ',\n ' ╰─────╯ ',\n ' ≈≈≈≈≈≈≈≈≈ ',\n ' ≈≈≈≈≈≈≈ ',\n ],\n 'comeback-kid': [\n ' ╱╲ ╱╲ ',\n ' ╱ ╲ ╱ ╲ ',\n ' ╱ ╲ ╱ ╲ ',\n ' ╱ ╳ ╲ ',\n ' ╲ ╱╲ ╱ ',\n ' ╲ ╱ ╲ ╱ ',\n ' ╲ ╱ ╲ ╱ ',\n ' ╲╱ ╲╱ ✓ ',\n ],\n 'pair-programming': [\n ' ╭─────╮╭─────╮ ',\n ' │ ◉ ◉ ││ ◉ ◉ │ ',\n ' │ ▽ ││ ▽ │ ',\n ' ╰──┬──╯╰──┬──╯ ',\n ' │ ╱──╲ │ ',\n ' │╱ ╲│ ',\n ' ╱ ══ ╲ ',\n ' ╱ ════ ╲ ',\n ' ▔▔▔▔▔▔▔▔▔▔ ',\n ],\n 'overdrive': [\n ' ╭──────────╮ ',\n ' ╱ ╭──────╮ ╲ ',\n ' │ ╱ ×6 ╲ │ ',\n ' │ │ ◉ │ │ ',\n ' │ ╲ ╱ │ ',\n ' ╲ ╰──────╯ ╱ ',\n ' ╰──────────╯ ',\n ' same day ×6 ',\n ],\n 'iron-streak': [\n ' ╔══╗─╔══╗─╔══╗ ',\n ' ║◆ ║ ║◆ ║ ║◆ ║ ',\n ' ╚══╝─╚══╝─╚══╝ ',\n ' │ │ ',\n ' ╔══╗─╔══╗─╔══╗ ',\n ' ║◆ ║ ║◆ ║ ║◆ ║ ',\n ' ╚══╝─╚══╝─╚══╝ ',\n ' 14 day chain ',\n ],\n 'deep-conversation': [\n ' ╭─────────╮ ',\n ' ╱ ╭──╮ 20 ╲ ',\n ' │ │ │ │ ',\n ' │ ╰──╯ │ ',\n ' │ · · · · · │ ',\n ' ╲ ╱ ',\n ' ╰──────────╯ ',\n ' ╲ ',\n ' ● ',\n ],\n 'one-must-imagine': [\n ' ◉◉◉◉◉ ',\n ' ╱ ◉◉◉◉ ',\n ' ╱ ◉ ╱ ←─╮ ',\n '╱ (>.<) │ ',\n ' ╱╱ ╲╲ │ ',\n ' ╱ ╲ │ ',\n ' ╱ ╲─╯ ',\n ' ▔▔▔▔▔▔▔▔▔▔▔ ',\n ' ×10 restarts ',\n ],\n};\n\n// ---------------------------------------------------------------------------\n// Card rendering\n// ---------------------------------------------------------------------------\n\nconst CARD_WIDTH = 34;\nconst CARD_HEIGHT = 18;\nconst CARD_INNER = CARD_WIDTH - 2;\n\nfunction centerLine(text: string, width: number): string {\n const stripped = stripAnsiForWidth(text);\n if (stripped.length >= width) return text.slice(0, width);\n const pad = Math.floor((width - stripped.length) / 2);\n return ' '.repeat(pad) + text + ' '.repeat(width - stripped.length - pad);\n}\n\nfunction stripAnsiForWidth(s: string): string {\n // eslint-disable-next-line no-control-regex\n return s.replace(/\\x1b\\[[0-9;]*m/g, '');\n}\n\nexport interface BadgeCard {\n lines: string[];\n width: number;\n height: number;\n}\n\nexport function renderBadgeCard(\n def: AchievementDef,\n unlock: UnlockedAchievement | null,\n opts?: { dim?: boolean },\n): BadgeCard {\n const dim = opts?.dim === true || unlock === null;\n const art = BADGE_ART[def.id] ?? [];\n\n const lines: string[] = [];\n\n // Top border\n const category = def.category.toUpperCase();\n const borderLabel = ` ${category} `;\n const topPad = CARD_INNER - borderLabel.length - 2;\n const topLeft = Math.floor(topPad / 2);\n const topRight = topPad - topLeft;\n lines.push(`┌${'─'.repeat(topLeft)}${borderLabel}${'─'.repeat(topRight)}┐`);\n\n // Blank\n lines.push(`│${' '.repeat(CARD_INNER)}│`);\n\n // Art (centered, dimmed if locked)\n const artMaxLines = 9;\n const artSlice = art.slice(0, artMaxLines);\n for (const artLine of artSlice) {\n const centered = centerLine(artLine, CARD_INNER);\n lines.push(`│${dim ? dimText(centered) : centered}│`);\n }\n // Pad remaining art lines\n for (let i = artSlice.length; i < artMaxLines; i++) {\n lines.push(`│${' '.repeat(CARD_INNER)}│`);\n }\n\n // Blank\n lines.push(`│${' '.repeat(CARD_INNER)}│`);\n\n // Name (centered, bold if unlocked)\n const nameText = unlock !== null ? def.name : `? ${def.name} ?`;\n lines.push(`│${centerLine(nameText, CARD_INNER)}│`);\n\n // Description (centered, wrapped if needed)\n const descLines = wrapText(def.description, CARD_INNER - 4);\n for (const dl of descLines.slice(0, 2)) {\n const centered = centerLine(dl, CARD_INNER);\n lines.push(`│${dim ? dimText(centered) : centered}│`);\n }\n // Pad to fixed height\n const usedContent = 1 + 1 + artMaxLines + 1 + 1 + Math.min(descLines.length, 2);\n const remaining = CARD_HEIGHT - 2 - usedContent; // -2 for borders\n for (let i = 0; i < remaining; i++) {\n if (i === remaining - 1 && unlock !== null) {\n // Unlock date on last content line\n const dateStr = unlock.unlockedAt.slice(0, 10);\n lines.push(`│${centerLine(dimText(dateStr), CARD_INNER)}│`);\n } else {\n lines.push(`│${' '.repeat(CARD_INNER)}│`);\n }\n }\n\n // Bottom border\n lines.push(`└${'─'.repeat(CARD_INNER)}┘`);\n\n return { lines, width: CARD_WIDTH, height: lines.length };\n}\n\nfunction dimText(text: string): string {\n return `\\x1b[2m${text}\\x1b[22m`;\n}\n\nfunction wrapText(text: string, maxWidth: number): string[] {\n const words = text.split(' ');\n const lines: string[] = [];\n let current = '';\n for (const word of words) {\n if (current.length + word.length + 1 > maxWidth && current.length > 0) {\n lines.push(current);\n current = word;\n } else {\n current = current.length > 0 ? `${current} ${word}` : word;\n }\n }\n if (current.length > 0) lines.push(current);\n return lines;\n}\n\n// ---------------------------------------------------------------------------\n// Gallery data\n// ---------------------------------------------------------------------------\n\nexport interface BadgeGallery {\n achievements: AchievementDef[];\n unlocked: Map<AchievementId, UnlockedAchievement>;\n currentIndex: number;\n total: number;\n}\n\nexport function createBadgeGallery(\n unlockedAchievements: UnlockedAchievement[],\n startIndex?: number,\n): BadgeGallery {\n const unlocked = new Map<AchievementId, UnlockedAchievement>();\n for (const a of unlockedAchievements) {\n unlocked.set(a.id, a);\n }\n\n // Sort: unlocked first (by unlock date), then locked\n const sorted = [...ACHIEVEMENTS].sort((a, b) => {\n const aUnlocked = unlocked.has(a.id);\n const bUnlocked = unlocked.has(b.id);\n if (aUnlocked && !bUnlocked) return -1;\n if (!aUnlocked && bUnlocked) return 1;\n if (aUnlocked && bUnlocked) {\n const aDate = unlocked.get(a.id)!.unlockedAt;\n const bDate = unlocked.get(b.id)!.unlockedAt;\n return aDate.localeCompare(bDate);\n }\n return 0; // preserve category order for locked\n });\n\n return {\n achievements: sorted,\n unlocked,\n currentIndex: startIndex ?? 0,\n total: sorted.length,\n };\n}\n\nexport function galleryNext(gallery: BadgeGallery): number {\n return (gallery.currentIndex + 1) % gallery.total;\n}\n\nexport function galleryPrev(gallery: BadgeGallery): number {\n return (gallery.currentIndex - 1 + gallery.total) % gallery.total;\n}\n\nexport { CARD_WIDTH, CARD_HEIGHT };\n","import { readFileSync } from 'node:fs';\nimport { mountPanel, type Deck } from '@crouton-kit/humanloop';\nimport type { InteractionResponse, MountedPanel } from '@crouton-kit/humanloop';\nimport { readDecisions, readProgress, readMeta, updateMeta, writeOutput } from '../../daemon/ask-store.js';\nimport { askProgressPath } from '../../shared/paths.js';\nimport type { AppState } from '../state.js';\nimport { requestRender } from '../state.js';\nimport type { AggregateInboxItem } from '../../shared/inbox-types.js';\nimport type { Request, Response } from '../../shared/protocol.js';\nimport { rawSend } from '../../shared/client.js';\nimport type { Key } from '../terminal.js';\nimport type { AskMeta } from '../../shared/types.js';\n\n// ── Orphan dispatch ───────────────────────────────────────────────────────────\n\nexport type OrphanTakeoverFn = (target: { sessionId: string; agentId: string; paneId?: string }) => Promise<void>;\n\nexport interface DispatchOrphanDeps {\n daemonSend: (request: Request) => Promise<Response>;\n onOrphanTakeover?: OrphanTakeoverFn;\n sessionId: string;\n cwd: string;\n}\n\n/**\n * Pure dispatch for orphan resolution choices. Extracted so tests can drive it\n * directly without mounting the full panel.\n */\nexport async function dispatchOrphanResolution(\n orphanTarget: NonNullable<AskMeta['orphanTarget']>,\n selectedOptionId: string,\n deps: DispatchOrphanDeps,\n): Promise<void> {\n if (selectedOptionId === 'takeover' && orphanTarget.kind === 'agent') {\n await deps.onOrphanTakeover?.({\n sessionId: deps.sessionId,\n agentId: orphanTarget.agentId,\n paneId: orphanTarget.paneId,\n });\n } else if (selectedOptionId === 'restart' && orphanTarget.kind === 'agent') {\n await deps.daemonSend({ type: 'restart-agent', sessionId: deps.sessionId, agentId: orphanTarget.agentId });\n } else if (selectedOptionId === 'resume' && orphanTarget.kind === 'orchestrator') {\n await deps.daemonSend({ type: 'resume', sessionId: deps.sessionId, cwd: deps.cwd });\n } else if (selectedOptionId === 'dismiss' && orphanTarget.kind === 'orchestrator') {\n // Clear the sticky orphan flag without spawning a new orchestrator — for cases\n // where the user has handled the situation manually (e.g. the tmux pane is still\n // alive) and just wants the \"Needs You\" badge gone.\n await deps.daemonSend({ type: 'clear-orphan', sessionId: deps.sessionId, cwd: deps.cwd });\n }\n}\n\n// ── Visual entry ──────────────────────────────────────────────────────────────\n\nexport interface VisualEntry {\n status: 'loading' | 'ready' | 'error';\n content: string;\n visible: boolean;\n error?: string;\n}\n\n// ── Public handle interface ───────────────────────────────────────────────────\n\nexport interface MountedResolutionHandle {\n handleKey(input: string, key: Key): void;\n render(): string[];\n handleResize(cols: number, rows: number): void;\n unmount(): void;\n canAcceptHostKeys(): boolean;\n advanceQueue(delta: number): void;\n spaceVisualToggle(): void;\n regenerateVisual(): void;\n /** Header info for the sisyphus header strip row 0. */\n getHeaderInfo(): {\n currentIndex: number;\n queueLength: number;\n sessionName: string | undefined;\n askTitle: string | undefined;\n blockedSince: string;\n kind: string | undefined;\n };\n /** Returns the id of the current (first unanswered) interaction, or undefined. */\n getCurrentQid(): string | undefined;\n}\n\n// ── Mount options ─────────────────────────────────────────────────────────────\n\nexport interface MountResolutionOpts {\n aggregateInbox: AggregateInboxItem[];\n startIndex: number;\n cols: number;\n rows: number;\n daemonSend: (request: Request) => Promise<Response>;\n onUnmount: () => void;\n onOrphanTakeover?: OrphanTakeoverFn;\n}\n\n// ── Panel factory ─────────────────────────────────────────────────────────────\n\nexport function mountResolutionPanel(\n opts: MountResolutionOpts,\n state: AppState,\n): MountedResolutionHandle | null {\n let queue = [...opts.aggregateInbox];\n let currentIndex = opts.startIndex;\n let bodyCols = opts.cols;\n\n const item = () => queue[currentIndex]!;\n\n function buildDeck(idx: number): Deck | null {\n const it = queue[idx];\n if (!it) return null;\n const deck = readDecisions(it.cwd, it.sessionId, it.askId);\n if (!deck) return null;\n deck.source = {\n sessionName: it.sessionName,\n askedBy: it.askedBy,\n blockedSince: it.blockedSince,\n };\n return deck;\n }\n\n // Initial deck — if missing (file gone, stale inbox, etc.) return null so the caller\n // never enters resolution mode. Returning a live no-op handle traps the user with no\n // way to escape because handleKey is unbound.\n const initialDeck = buildDeck(currentIndex);\n if (!initialDeck) return null;\n\n // Track answered count for current-qid derivation (Gap 2 option a)\n let currentDeck = initialDeck;\n const initialProgress = readProgress(item().cwd, item().sessionId, item().askId);\n let answeredCount = initialProgress?.responses.length ?? 0;\n\n function getCurrentQid(): string | undefined {\n return currentDeck.interactions[answeredCount]?.id ?? currentDeck.interactions[0]?.id;\n }\n\n function fireVisualGen(force: boolean): void {\n const qid = getCurrentQid();\n if (!qid) return;\n const it = item();\n state.visuals.set(qid, { status: 'loading', content: '', visible: true });\n requestRender();\n void (async () => {\n const res = await rawSend({\n type: 'ask-generate-visual',\n sessionId: it.sessionId,\n askId: it.askId,\n qid,\n cols: bodyCols,\n force,\n }, 60_000);\n if (res.ok) {\n const ansiPath = (res.data as { ansiPath: string }).ansiPath;\n const ansi = readFileSync(ansiPath, 'utf-8');\n state.visuals.set(qid, { status: 'ready', content: ansi, visible: true });\n } else {\n state.visuals.set(qid, { status: 'error', content: '', visible: true, error: res.error });\n }\n requestRender();\n })();\n }\n\n // Mirror humanloop's standalone launchTui pattern: track latest responses\n // so onExit (incomplete submit via final-phase Enter) can submit partials.\n let lastResponses: InteractionResponse[] = [];\n\n const submitResponses = (responses: InteractionResponse[]): void => {\n void (async () => {\n const it = item();\n const completedAt = new Date().toISOString();\n\n // Orphan disposition: dispatch before writeOutput so action lands first\n const meta = readMeta(it.cwd, it.sessionId, it.askId);\n if (meta?.orphanTarget && responses.length > 0) {\n const sel = responses[0]!.selectedOptionId;\n if (sel) {\n await dispatchOrphanResolution(meta.orphanTarget, sel, {\n daemonSend: opts.daemonSend,\n onOrphanTakeover: opts.onOrphanTakeover,\n sessionId: it.sessionId,\n cwd: it.cwd,\n });\n }\n }\n\n // Write output first (before inbox-list so daemon sees answered status)\n writeOutput(it.cwd, it.sessionId, it.askId, responses, completedAt);\n await updateMeta(it.cwd, it.sessionId, it.askId, { status: 'answered', completedAt });\n\n const refreshRes = await opts.daemonSend({ type: 'inbox-list' });\n const newQueue: AggregateInboxItem[] = refreshRes.ok\n ? ((refreshRes.data?.items as AggregateInboxItem[]) ?? [])\n : [];\n\n if (newQueue.length === 0) {\n opts.onUnmount();\n return;\n }\n\n queue = newQueue;\n currentIndex = 0;\n const nextItem = queue[0]!;\n const nextDeck = buildDeck(0);\n if (!nextDeck) {\n opts.onUnmount();\n return;\n }\n\n currentDeck = nextDeck;\n const nextProgress = readProgress(nextItem.cwd, nextItem.sessionId, nextItem.askId);\n answeredCount = nextProgress?.responses.length ?? 0;\n lastResponses = [];\n\n state.visuals.clear();\n\n panel.loadDeck(nextDeck, {\n progressPath: askProgressPath(nextItem.cwd, nextItem.sessionId, nextItem.askId),\n });\n requestRender();\n })();\n };\n\n const panel: MountedPanel = mountPanel({\n deck: initialDeck,\n cols: opts.cols,\n rows: opts.rows,\n progressPath: askProgressPath(item().cwd, item().sessionId, item().askId),\n onProgress: (responses: InteractionResponse[]) => {\n answeredCount = responses.length;\n lastResponses = responses;\n requestRender();\n const it = item();\n const cur = readMeta(it.cwd, it.sessionId, it.askId);\n if (cur?.status === 'pending') {\n void updateMeta(it.cwd, it.sessionId, it.askId, { status: 'in-progress', startedAt: new Date().toISOString() });\n }\n },\n onComplete: (responses: InteractionResponse[]) => {\n submitResponses(responses);\n },\n // Final-phase Enter on an incomplete deck routes here (humanloop only fires\n // onComplete when responses === interactions). The 'final' UI prompts\n // \"enter submit\", so honor that by submitting whatever was answered.\n onExit: () => {\n submitResponses(lastResponses);\n },\n });\n\n return {\n handleKey(input: string, key: Key) {\n // Key from sisyphus is a structural superset of humanloop Key — no cast needed\n panel.handleKey(input, key);\n },\n\n render() {\n return panel.render();\n },\n\n handleResize(cols: number, rows: number) {\n bodyCols = cols;\n panel.handleResize(cols, rows);\n },\n\n unmount() {\n panel.unmount();\n opts.onUnmount();\n },\n\n canAcceptHostKeys() {\n return panel.canAcceptHostKeys();\n },\n\n advanceQueue(delta: number) {\n const newIndex = Math.max(0, Math.min(queue.length - 1, currentIndex + delta));\n if (newIndex === currentIndex) return;\n currentIndex = newIndex;\n const nextDeck = buildDeck(currentIndex);\n if (!nextDeck) return;\n currentDeck = nextDeck;\n const it = item();\n const progress = readProgress(it.cwd, it.sessionId, it.askId);\n answeredCount = progress?.responses.length ?? 0;\n panel.loadDeck(nextDeck, {\n progressPath: askProgressPath(it.cwd, it.sessionId, it.askId),\n });\n requestRender();\n },\n\n spaceVisualToggle() {\n const qid = getCurrentQid();\n if (!qid) return;\n const entry = state.visuals.get(qid);\n if (!entry) {\n fireVisualGen(false);\n } else if (entry.status === 'ready') {\n state.visuals.set(qid, { ...entry, visible: !entry.visible });\n requestRender();\n } else if (entry.status === 'loading') {\n // debounce — no-op\n } else {\n // error → retry\n fireVisualGen(false);\n }\n },\n\n regenerateVisual() {\n const qid = getCurrentQid();\n if (!qid) return;\n state.visuals.set(qid, { status: 'loading', content: '', visible: true });\n requestRender();\n fireVisualGen(true);\n },\n\n getHeaderInfo() {\n const it = item();\n const askTitle = currentDeck.title ?? currentDeck.interactions[0]?.title;\n return {\n currentIndex,\n queueLength: queue.length,\n sessionName: it.sessionName,\n askTitle: askTitle ? askTitle.slice(0, 32) : undefined,\n blockedSince: it.blockedSince,\n kind: it.kind,\n };\n },\n\n getCurrentQid,\n };\n}\n\n// ── enterResolutionMode ───────────────────────────────────────────────────────\n\nexport function enterResolutionMode(\n state: AppState,\n askId: string,\n daemonSend: (request: Request) => Promise<Response>,\n onOrphanTakeover?: MountResolutionOpts['onOrphanTakeover'],\n): void {\n const queue = state.aggregateInbox;\n const startIdx = queue.findIndex((item) => item.askId === askId);\n if (startIdx < 0) {\n // Ask not in current inbox — use the first item as fallback\n if (queue.length === 0) return;\n enterResolutionMode(state, queue[0]!.askId, daemonSend, onOrphanTakeover);\n return;\n }\n\n const handle = mountResolutionPanel(\n {\n aggregateInbox: queue,\n startIndex: startIdx,\n cols: state.cols,\n rows: state.rows - 1,\n daemonSend,\n onUnmount: () => {\n state.resolutionActive = false;\n state.resolutionHandle = null;\n state.visuals.clear();\n requestRender();\n },\n onOrphanTakeover,\n },\n state,\n );\n\n if (!handle) {\n // Deck missing or unreadable — don't enter resolution mode. Leaving resolutionActive\n // false means the user stays in the session list and can keep navigating.\n requestRender();\n return;\n }\n\n state.resolutionHandle = handle;\n state.resolutionActive = true;\n requestRender();\n}\n","import { connect } from 'node:net';\nimport { socketPath } from './paths.js';\nimport type { Request, Response } from './protocol.js';\n\nexport function rawSend(request: Request, timeoutMs = 10_000): Promise<Response> {\n const sock = socketPath();\n\n return new Promise<Response>((resolve, reject) => {\n const socket = connect(sock);\n let data = '';\n\n const timeout = setTimeout(() => {\n socket.destroy();\n reject(new Error(`Request timed out after ${(timeoutMs / 1000).toFixed(0)}s. The daemon may be overloaded.\\n Check: sis admin doctor\\n Logs: tail -20 ~/.sisyphus/daemon.log`));\n }, timeoutMs);\n\n socket.on('connect', () => {\n socket.write(JSON.stringify(request) + '\\n');\n });\n\n socket.on('data', (chunk) => {\n data += chunk.toString();\n const newlineIdx = data.indexOf('\\n');\n if (newlineIdx !== -1) {\n clearTimeout(timeout);\n const line = data.slice(0, newlineIdx);\n socket.destroy();\n try {\n resolve(JSON.parse(line) as Response);\n } catch {\n reject(new Error(`Invalid JSON response from daemon: ${line}`));\n }\n }\n });\n\n socket.on('error', (err) => {\n clearTimeout(timeout);\n reject(err);\n });\n });\n}\n","export type KeyMap = {\n version: 1;\n topLevel: MenuDef;\n submenus: Record<string, MenuDef>;\n};\n\nexport type MenuDef = {\n title: string;\n items: MenuItem[];\n};\n\nexport type MenuItem = {\n key: string;\n label: string;\n action: Action;\n tuiAction?: string;\n hidden?: boolean;\n};\n\nexport type Action =\n | { type: 'submenu'; ref: string }\n | { type: 'script'; name: string }\n | { type: 'popup'; name: string; popup: PopupOpts }\n | { type: 'tmux'; cmd: string }\n | { type: 'tui'; action: string };\n\nexport type PopupOpts = {\n w?: string;\n h?: string;\n borderStyle?: string;\n title?: string;\n cwd?: 'current';\n};\n\nexport function formatHelpForKeymap(km: KeyMap): string {\n const COL1 = 20;\n const MAX_W = 78;\n\n function shortLabel(raw: string, max: number): string {\n return raw.trimStart()\n .replace(/\\s*\\([^)]*\\)\\s*/g, '')\n .replace(/\\s+--\\S*/g, '')\n .trimEnd()\n .slice(0, max)\n .trimEnd();\n }\n\n const lines: string[] = [];\n\n lines.push(' Sisyphus Keybindings (Ctrl-s + key)');\n lines.push('');\n lines.push(' ── Direct ─────────────────────────────────');\n\n for (const item of km.topLevel.items) {\n if (item.action.type === 'submenu' || item.action.type === 'tui' || item.hidden) continue;\n const key = item.key.trim() === '' ? 'spc' : item.key;\n lines.push(` ${key.padEnd(4)} ${shortLabel(item.label, 30)}`);\n }\n\n lines.push('');\n lines.push(' ── Submenus ───────────────────────────────');\n\n for (const topItem of km.topLevel.items) {\n if (topItem.action.type !== 'submenu') continue;\n const { ref } = topItem.action;\n const sub = km.submenus[ref];\n if (!sub) continue;\n\n const prefix = topItem.key;\n const col1Text = ` ${prefix} › ${sub.title.trim()}`.padEnd(COL1);\n let cur = col1Text;\n\n for (const si of sub.items) {\n const lbl = shortLabel(si.label, 13);\n const tok = `${prefix} ${si.key} ${lbl}`;\n const sep = cur.length === COL1 ? '' : ' ';\n if (cur.length !== COL1 && cur.length + 2 + tok.length > MAX_W) {\n lines.push(cur);\n cur = ' '.repeat(COL1) + tok;\n } else {\n cur += sep + tok;\n }\n }\n if (cur.length > COL1) lines.push(cur);\n }\n\n return lines.join('\\n');\n}\n\n// Maps TUI overlay mode → KEYMAP menu key. Shared between input dispatcher and renderer.\nexport const MENU_FOR_MODE: Record<string, string | undefined> = {\n 'leader': 'topLevel',\n 'copy-menu': 'copy',\n 'open-menu': 'open',\n 'agent-menu': 'agent',\n 'session-menu': 'session',\n 'go-menu': 'go',\n 'companion-menu': 'companion',\n};\n\nexport const KEYMAP: KeyMap = {\n version: 1,\n topLevel: {\n title: ' Sisyphus ',\n items: [\n { key: 's', label: ' Cycle session', action: { type: 'script', name: 'sisyphus-cycle' } },\n { key: 'h', label: ' Home / dashboard', action: { type: 'script', name: 'sisyphus-home' } },\n { key: 'n', label: ' New session', action: { type: 'popup', name: 'sisyphus-new', popup: { w: '80%', h: '60%', cwd: 'current' } } },\n { key: 'm', label: ' Message orchestrator', action: { type: 'popup', name: 'sisyphus-msg', popup: { w: '80%', h: '60%', cwd: 'current' } } },\n { key: 't', label: ' Status (where am I?)', action: { type: 'popup', name: 'sisyphus-status-popup', popup: { w: '90%', h: '90%', cwd: 'current' } } },\n { key: 'l', label: ' Session picker', action: { type: 'popup', name: 'sisyphus-pick-session', popup: { w: '60%', h: '60%', cwd: 'current' } } },\n { key: 'z', label: ' Zoom pane', action: { type: 'tmux', cmd: 'resize-pane -Z' } },\n { key: 'x', label: ' Kill pane (smart)', action: { type: 'script', name: 'sisyphus-kill-pane' } },\n { key: '?', label: ' Full help reference', action: { type: 'popup', name: 'sisyphus-help', popup: { w: '80', h: '32', title: ' Keybindings ' } } },\n { key: '/', label: ' Search / filter', action: { type: 'script', name: 'sisyphus-search-reports' }, tuiAction: 'search' },\n { key: ' ', label: ' Open popup explicitly', action: { type: 'tui', action: 'show-leader' } },\n { key: 'y', label: ' Yank ›', action: { type: 'submenu', ref: 'copy' } },\n { key: 'c', label: ' Side claude pane', action: { type: 'script', name: 'sisyphus-companion-pane' }, tuiAction: 'companion-pane' },\n { key: 'C', label: ' Companion (gamification) ›', action: { type: 'submenu', ref: 'companion' } },\n { key: 'o', label: ' Open ›', action: { type: 'submenu', ref: 'open' } },\n { key: 'a', label: ' Agent ›', action: { type: 'submenu', ref: 'agent' } },\n { key: 'S', label: ' Session ›', action: { type: 'submenu', ref: 'session' } },\n { key: 'g', label: ' Go ›', action: { type: 'submenu', ref: 'go' } },\n ],\n },\n submenus: {\n companion: {\n title: ' Companion ',\n items: [\n { key: 'p', label: ' profile (overlay)', action: { type: 'tui', action: 'companion-overlay' } },\n { key: 'd', label: ' debug (mood signals)', action: { type: 'tui', action: 'companion-debug' } },\n ],\n },\n copy: {\n title: ' Copy ',\n items: [\n { key: 'p', label: ' session dir path', action: { type: 'script', name: 'sisyphus-copy-path' } },\n { key: 'i', label: ' session UUID', action: { type: 'script', name: 'sisyphus-copy-id' } },\n { key: 'c', label: ' full session context XML', action: { type: 'script', name: 'sisyphus-copy-context' } },\n { key: 'l', label: ' logs (last 200 lines)', action: { type: 'script', name: 'sisyphus-copy-logs' } },\n { key: 'r', label: ' latest report content', action: { type: 'script', name: 'sisyphus-copy-latest-report' } },\n { key: 'a', label: ' agent ID (picker)', action: { type: 'script', name: 'sisyphus-copy-agent-id' } },\n ],\n },\n open: {\n title: ' Open ',\n items: [\n { key: 'g', label: ' goal.md', action: { type: 'popup', name: 'sisyphus-open-goal', popup: { w: '95%', h: '95%', cwd: 'current' } } },\n { key: 'r', label: ' roadmap.md', action: { type: 'popup', name: 'sisyphus-open-roadmap', popup: { w: '95%', h: '95%', cwd: 'current' } } },\n { key: 's', label: ' strategy.md', action: { type: 'popup', name: 'sisyphus-open-strategy', popup: { w: '95%', h: '95%', cwd: 'current' } } },\n { key: 'l', label: ' logs popup (tail)', action: { type: 'popup', name: 'sisyphus-open-logs', popup: { w: '90%', h: '90%', cwd: 'current' } } },\n { key: 'd', label: ' session dir in file mgr', action: { type: 'script', name: 'sisyphus-open-dir' } },\n { key: 'R', label: ' latest report file', action: { type: 'popup', name: 'sisyphus-open-latest-report', popup: { w: '95%', h: '95%', cwd: 'current' } } },\n { key: 'c', label: ' scratch', action: { type: 'popup', name: 'sisyphus-open-scratch', popup: { w: '95%', h: '95%', cwd: 'current' } } },\n { key: 'e', label: ' edit context file', action: { type: 'popup', name: 'sisyphus-edit-context-file', popup: { w: '95%', h: '95%', cwd: 'current' } }, tuiAction: 'edit-context-file' },\n ],\n },\n agent: {\n title: ' Agent ',\n items: [\n { key: 's', label: ' spawn agent', action: { type: 'popup', name: 'sisyphus-spawn-agent', popup: { w: '80%', h: '70%', cwd: 'current' } } },\n { key: 'm', label: ' message agent (picker)', action: { type: 'popup', name: 'sisyphus-msg-agent', popup: { w: '80%', h: '60%', cwd: 'current' } } },\n { key: 'r', label: ' restart agent (picker)', action: { type: 'popup', name: 'sisyphus-restart-agent-popup', popup: { w: '70%', h: '50%', cwd: 'current' } } },\n { key: 'R', label: ' re-run agent (picker)', action: { type: 'popup', name: 'sisyphus-rerun-agent', popup: { w: '70%', h: '50%', cwd: 'current' } } },\n { key: 'j', label: \" jump to agent's pane\", action: { type: 'popup', name: 'sisyphus-jump-to-pane', popup: { w: '60%', h: '60%' } } },\n { key: 'o', label: ' open claude --resume', action: { type: 'popup', name: 'sisyphus-open-claude-agent', popup: { w: '60%', h: '60%', cwd: 'current' } } },\n { key: 't', label: ' tail agent logs (picker)', action: { type: 'popup', name: 'sisyphus-tail-agent-logs', popup: { w: '90%', h: '90%', cwd: 'current' } } },\n { key: 'k', label: ' kill agent (picker)', action: { type: 'popup', name: 'sisyphus-kill-agent', popup: { w: '60%', h: '40%', cwd: 'current' } } },\n { key: 'e', label: ' quick-spawn Explore', action: { type: 'script', name: 'sisyphus-quick-spawn-explore' } },\n { key: 'd', label: ' quick-spawn Debug', action: { type: 'script', name: 'sisyphus-quick-spawn-debug' } },\n ],\n },\n session: {\n title: ' Session ',\n items: [\n { key: 'n', label: ' new session', action: { type: 'popup', name: 'sisyphus-new', popup: { w: '80%', h: '60%', cwd: 'current' } } },\n { key: 'r', label: ' resume', action: { type: 'popup', name: 'sisyphus-resume-session', popup: { w: '80%', h: '60%', cwd: 'current' } } },\n { key: 'c', label: ' continue', action: { type: 'popup', name: 'sisyphus-continue-session', popup: { w: '50', h: '5', borderStyle: 'fg=yellow', title: ' Continue Session ', cwd: 'current' } } },\n { key: 'b', label: ' rollback (prompts cycle)', action: { type: 'popup', name: 'sisyphus-rollback-session', popup: { w: '50', h: '5', title: ' Rollback ', cwd: 'current' } } },\n { key: 'k', label: ' kill', action: { type: 'popup', name: 'sisyphus-kill-session', popup: { w: '40', h: '5', borderStyle: 'fg=red', title: ' Kill Session ', cwd: 'current' } } },\n { key: 'd', label: ' delete (confirms)', action: { type: 'popup', name: 'sisyphus-delete-session', popup: { w: '40', h: '5', borderStyle: 'fg=red', title: ' Delete Session ', cwd: 'current' } } },\n { key: 'e', label: ' export to ~/Downloads', action: { type: 'popup', name: 'sisyphus-export-session', popup: { w: '60', h: '8', title: ' Export Session ', cwd: 'current' } } },\n { key: 'w', label: ' go to session window', action: { type: 'popup', name: 'sisyphus-go-to-window', popup: { w: '70%', h: '60%', cwd: 'current' } } },\n { key: 'C', label: ' clone (sisyphus session clone)', action: { type: 'popup', name: 'sisyphus-clone-session', popup: { w: '60%', h: '60%', cwd: 'current' } } },\n { key: 'i', label: ' history', action: { type: 'popup', name: 'sisyphus-history', popup: { w: '95%', h: '95%', cwd: 'current' } } },\n ],\n },\n go: {\n title: ' Go ',\n items: [\n { key: 'w', label: ' go to session window', action: { type: 'popup', name: 'sisyphus-go-to-window', popup: { w: '70%', h: '60%', cwd: 'current' } } },\n { key: 'p', label: ' jump to pane (picker)', action: { type: 'popup', name: 'sisyphus-jump-to-pane', popup: { w: '60%', h: '60%' } } },\n { key: 's', label: ' session picker', action: { type: 'popup', name: 'sisyphus-pick-session', popup: { w: '60%', h: '60%', cwd: 'current' } } },\n { key: 'n', label: ' next session', action: { type: 'script', name: 'sisyphus-cycle' } },\n { key: 'r', label: ' reconnect', action: { type: 'popup', name: 'sisyphus-reconnect', popup: { w: '80%', h: '40%', cwd: 'current' } } },\n ],\n },\n },\n};\n","import type { TreeNode } from '../types/tree.js';\n\n/**\n * Render box-drawing prefix for a tree node.\n * Produces connectors like: │ ├─ ▸ or └─ ▼\n */\nexport function renderTreePrefix(node: TreeNode, nodes: TreeNode[], index: number): string {\n if (node.depth === 0) {\n return node.expandable ? (node.expanded ? '▼ ' : '▸ ') : ' ';\n }\n\n const parts: string[] = [];\n\n // For each ancestor depth level (1..depth-1), draw │ or space\n for (let d = 1; d < node.depth; d++) {\n parts.push(isAncestorLastSibling(nodes, index, d) ? ' ' : '│ ');\n }\n\n // Connector for this node\n parts.push(isLastSibling(nodes, index) ? '└─' : '├─');\n\n // Expand indicator\n if (node.expandable) {\n parts.push(node.expanded ? '▼ ' : '▸ ');\n } else {\n parts.push(' ');\n }\n\n return parts.join('');\n}\n\n/** Check if the node at `index` is the last among its siblings (same depth, same parent) */\nfunction isLastSibling(nodes: TreeNode[], index: number): boolean {\n const depth = nodes[index]!.depth;\n for (let i = index + 1; i < nodes.length; i++) {\n if (nodes[i]!.depth === depth) return false;\n if (nodes[i]!.depth < depth) return true;\n }\n return true;\n}\n\n/** Check if the ancestor at `depth` for the node at `index` is the last among its siblings */\nfunction isAncestorLastSibling(nodes: TreeNode[], index: number, depth: number): boolean {\n // Find the ancestor at this depth by scanning backward\n for (let i = index - 1; i >= 0; i--) {\n if (nodes[i]!.depth === depth) {\n return isLastSibling(nodes, i);\n }\n if (nodes[i]!.depth < depth) return true;\n }\n return true;\n}\n\n/**\n * Pre-compute prefix strings for all tree nodes in O(n).\n * Avoids per-node O(n) scans during rendering.\n */\nexport function precomputePrefixes(nodes: TreeNode[]): void {\n const len = nodes.length;\n if (len === 0) return;\n\n // Step 1: Compute isLastSibling for each node in a single backward pass.\n // A node is \"last sibling\" if no later node at the same depth appears before\n // a node at a shallower depth (or end of array).\n const isLast = new Array<boolean>(len);\n // Track the last-seen index for each depth level\n const lastSeenAtDepth = new Map<number, number>();\n\n for (let i = len - 1; i >= 0; i--) {\n const depth = nodes[i]!.depth;\n // This node is last sibling if no node at same depth was seen after it\n // before a shallower node\n isLast[i] = !lastSeenAtDepth.has(depth);\n lastSeenAtDepth.set(depth, i);\n // Clear deeper depths (they belong to a different parent scope)\n for (const [d] of lastSeenAtDepth) {\n if (d > depth) lastSeenAtDepth.delete(d);\n }\n }\n\n // Step 2: Build prefix strings using pre-computed isLast data.\n // For ancestor connector lines, we need to know if the ancestor at each depth\n // is a last sibling. We maintain a stack of isLast values per depth.\n const ancestorIsLast: boolean[] = [];\n\n for (let i = 0; i < len; i++) {\n const node = nodes[i]!;\n\n if (node.depth === 0) {\n node.prefix = node.expandable ? (node.expanded ? '▼ ' : '▸ ') : ' ';\n ancestorIsLast[0] = isLast[i]!;\n continue;\n }\n\n // Update ancestor tracking\n ancestorIsLast[node.depth] = isLast[i]!;\n\n const parts: string[] = [];\n\n // Ancestor connectors (depth 1 to depth-1)\n for (let d = 1; d < node.depth; d++) {\n parts.push(ancestorIsLast[d] ? ' ' : '│ ');\n }\n\n // This node's connector\n parts.push(isLast[i] ? '└─' : '├─');\n\n // Expand indicator\n if (node.expandable) {\n parts.push(node.expanded ? '▼ ' : '▸ ');\n } else {\n parts.push(' ');\n }\n\n node.prefix = parts.join('');\n }\n}\n","import { readFileSync } from 'node:fs';\nimport type { AgentReport } from '../../shared/types.js';\n\nexport interface ReportBlock {\n type: 'update' | 'final';\n timestamp: string;\n content: string;\n summary: string;\n}\n\nfunction loadReportContent(report: AgentReport): string {\n try {\n return readFileSync(report.filePath, 'utf-8');\n } catch {\n return report.summary;\n }\n}\n\nexport function resolveReports(reports: AgentReport[]): ReportBlock[] {\n return [...reports].reverse().map((r) => ({\n type: r.type as 'update' | 'final',\n timestamp: r.timestamp,\n content: loadReportContent(r),\n summary: r.summary,\n }));\n}\n","import { rawSend } from '../../shared/client.js';\nimport type { Request, Response } from '../../shared/protocol.js';\nimport type { AggregateInboxItem } from '../../shared/inbox-types.js';\n\nexport function send(request: Request): Promise<Response> {\n return rawSend(request, 8_000);\n}\n\nexport async function inboxList(): Promise<AggregateInboxItem[]> {\n const res = await send({ type: 'inbox-list' });\n if (!res.ok) return [];\n return (res.data?.items as AggregateInboxItem[] | undefined) ?? [];\n}\n","import { execSync } from 'node:child_process';\nimport { join } from 'node:path';\nimport { readFileSync, writeFileSync, mkdtempSync, rmSync, cpSync, existsSync, mkdirSync } from 'node:fs';\nimport { tmpdir } from 'node:os';\nimport { globalDir, tmuxSessionName } from '../../shared/paths.js';\nimport { augmentedPath } from '../../shared/env.js';\nimport { shellQuote } from '../../shared/shell.js';\nimport { exec, execSafe, EXEC_ENV } from '../../shared/exec.js';\n\n\nexport function getWindowId(): string {\n const pane = process.env['TMUX_PANE'];\n if (pane) {\n return exec(`tmux display-message -t ${shellQuote(pane)} -p \"#{window_id}\"`);\n }\n return exec('tmux display-message -p \"#{window_id}\"');\n}\n\nexport function selectWindow(windowId: string): void {\n execSafe(`tmux select-window -t ${shellQuote(windowId)}`);\n}\n\nexport function selectPane(paneId: string): void {\n execSafe(`tmux select-pane -t ${shellQuote(paneId)}`);\n}\n\nexport function windowExists(windowId: string): boolean {\n return execSafe(`tmux display-message -t ${shellQuote(windowId)} -p \"#{window_id}\"`) !== null;\n}\n\nexport function listAllWindowIds(): Set<string> {\n try {\n const output = execSync('tmux list-windows -a -F \"#{window_id}\"', { encoding: 'utf-8', env: EXEC_ENV });\n return new Set(output.trim().split('\\n').filter(Boolean));\n } catch {\n return new Set();\n }\n}\n\n/**\n * Register this TUI window as the dashboard for the current tmux session.\n * Called on TUI startup so C-s h (sisyphus-home) and M-s (sisyphus-cycle) can\n * locate the dashboard. Also stamps @sisyphus_cwd on the parent tmux session\n * if it is currently unset — without it, resolve_home() and the cycle script\n * silently exclude the home session, breaking jump/cycle from ssyph_ panes.\n * If @sisyphus_cwd is already set to a different cwd we leave it alone so we\n * don't hijack another project's home registration.\n */\nexport function registerDashboardWindow(cwd?: string): void {\n const wid = getWindowId();\n const pane = process.env['TMUX_PANE'];\n let sessionTarget: string | null = null;\n if (pane) {\n sessionTarget = execSafe(`tmux display-message -t ${shellQuote(pane)} -p \"#{session_id}\"`)?.trim() || null;\n }\n if (sessionTarget) {\n execSafe(`tmux set-option -t ${shellQuote(sessionTarget)} @sisyphus_dashboard ${wid}`);\n } else {\n execSafe(`tmux set-option @sisyphus_dashboard ${wid}`);\n }\n\n if (cwd) {\n const normalizedCwd = cwd.replace(/\\/+$/, '');\n const target = sessionTarget;\n const existing = target\n ? execSafe(`tmux show-options -t ${shellQuote(target)} -v @sisyphus_cwd`)?.trim()\n : execSafe(`tmux show-options -v @sisyphus_cwd`)?.trim();\n if (!existing) {\n if (target) {\n execSafe(`tmux set-option -t ${shellQuote(target)} @sisyphus_cwd ${shellQuote(normalizedCwd)}`);\n } else {\n execSafe(`tmux set-option @sisyphus_cwd ${shellQuote(normalizedCwd)}`);\n }\n }\n }\n}\n\nfunction setupCompanionPlugin(): string {\n const srcDir = join(import.meta.dirname, 'templates', 'companion-plugin');\n const destDir = join(globalDir(), 'companion-plugin');\n if (!existsSync(destDir)) mkdirSync(destDir, { recursive: true });\n cpSync(srcDir, destDir, { recursive: true });\n return destDir;\n}\n\nexport function paneExists(paneId: string): boolean {\n return execSafe(`tmux display-message -t ${shellQuote(paneId)} -p \"#{pane_id}\"`) !== null;\n}\n\n// Find a companion pane for this cwd by marker option. Returns null if none.\n// Authoritative source — replaces the old module-level companionPaneId cache\n// which went stale after `tmux kill-pane` (stale id → paneExists race),\n// across TUI restarts, and when the user opened a second dashboard.\nfunction findCompanionPaneForCwd(normalizedCwd: string): string | null {\n const out = execSafe(`tmux list-panes -aF \"#{pane_id}\\t#{@sisyphus_companion}\"`);\n if (!out) return null;\n for (const line of out.split('\\n')) {\n const tabIdx = line.indexOf('\\t');\n if (tabIdx < 0) continue;\n const paneId = line.slice(0, tabIdx);\n const marker = line.slice(tabIdx + 1);\n if (paneId && marker === normalizedCwd) return paneId;\n }\n return null;\n}\n\nexport function openCompanionPane(cwd: string): void {\n const normalizedCwd = cwd.replace(/\\/+$/, '');\n\n // Reuse an alive companion pane for this cwd if one exists. We look it up\n // via the tmux pane option marker rather than caching a pane id in module\n // state, so a killed pane never leaves us in a state where we try to focus\n // something that's gone.\n const existing = findCompanionPaneForCwd(normalizedCwd);\n if (existing) {\n execSafe(`tmux select-pane -t ${shellQuote(existing)}`);\n return;\n }\n\n const pluginDir = setupCompanionPlugin();\n\n const templatePath = join(import.meta.dirname, 'templates', 'dashboard-claude.md');\n let template: string;\n try {\n template = readFileSync(templatePath, 'utf-8');\n } catch {\n template = `You are a Sisyphus dashboard companion. Help the user manage multi-agent sessions.\\nProject: ${cwd}\\nRun \\`sis list\\` and \\`sis status\\` to see current state.`;\n }\n\n const rendered = template.replace(/\\{\\{CWD\\}\\}/g, cwd);\n const promptPath = join(globalDir(), 'dashboard-companion-prompt.md');\n writeFileSync(promptPath, rendered, 'utf-8');\n\n const pathEnv = augmentedPath();\n\n const claudeCmd = `SISYPHUS_COMPANION_CWD=${shellQuote(cwd)} PATH=${shellQuote(pathEnv)} claude --dangerously-skip-permissions --plugin-dir ${shellQuote(pluginDir)} --append-system-prompt \"$(cat ${shellQuote(promptPath)})\"`;\n\n const result = exec(\n `tmux split-window -h -l 33% -P -F \"#{pane_id}\" -c ${shellQuote(cwd)} ${shellQuote(claudeCmd)}`,\n );\n const newPaneId = result.trim();\n if (newPaneId) {\n execSafe(`tmux set-option -p -t ${shellQuote(newPaneId)} @sisyphus_companion ${shellQuote(normalizedCwd)}`);\n }\n}\n\nconst TERMINAL_EDITORS = new Set(['nvim', 'vim', 'vi', 'nano', 'emacs', 'micro', 'helix', 'hx', 'joe', 'ne', 'kak']);\n\nexport function switchToSession(sessionName: string): void {\n execSafe(`tmux switch-client -t ${shellQuote(sessionName)}`);\n}\n\nexport function editInPopup(cwd: string, editor: string, opts?: { content?: string; size?: { w: string; h: string } }): string | null {\n const tmpDir = mkdtempSync(join(tmpdir(), 'sisyphus-'));\n const filePath = join(tmpDir, 'input.md');\n try {\n writeFileSync(filePath, opts?.content ? opts.content : '', 'utf-8');\n openEditorPopup(cwd, editor, filePath, opts?.size);\n const result = readFileSync(filePath, 'utf-8').trim();\n return result || null;\n } finally {\n rmSync(tmpDir, { recursive: true, force: true });\n }\n}\n\n/**\n * Small centered tmux popup that prompts for a single line of input.\n * Returns the trimmed input or null if empty/cancelled (Ctrl-C / Escape).\n */\nexport function promptInPopup(prompt: string, opts?: { w?: string; h?: string }): string | null {\n const { w = '50%', h = '3' } = opts ?? {};\n const tmpDir = mkdtempSync(join(tmpdir(), 'sisyphus-'));\n const outFile = join(tmpDir, 'result');\n try {\n const script = `printf ${shellQuote(prompt + ' ')} && read -r line && printf '%s' \"$line\" > ${shellQuote(outFile)}`;\n execSync(\n `tmux display-popup -E -w ${w} -h ${h} ${shellQuote(`bash -c ${shellQuote(script)}`)}`,\n { stdio: 'inherit', env: EXEC_ENV },\n );\n if (!existsSync(outFile)) return null;\n const result = readFileSync(outFile, 'utf-8').trim();\n return result || null;\n } finally {\n rmSync(tmpDir, { recursive: true, force: true });\n }\n}\n\nexport function openLogPopup(): void {\n execSync(\n `tmux display-popup -E -w 90% -h 80% ${shellQuote('tail -f ~/.sisyphus/daemon.log')}`,\n { stdio: 'inherit', env: EXEC_ENV },\n );\n}\n\nexport function openShellPopup(cwd: string, command: string): void {\n execSync(\n `tmux display-popup -E -w 90% -h 80% -d ${shellQuote(cwd)} ${shellQuote(`sh -c '${command.replace(/'/g, \"'\\\\''\")}; echo; echo \"Press enter to close\"; read'`)}`,\n { stdio: 'inherit', env: EXEC_ENV },\n );\n}\n\nexport function openInFileManager(path: string): void {\n execSync(`open ${shellQuote(path)}`, { stdio: 'inherit', env: EXEC_ENV });\n}\n\nexport function openClaudeResumePopup(cwd: string, claudeSessionId: string, resumeEnv?: string, resumeArgs?: string): void {\n const pathEnv = augmentedPath();\n const envPrefix = resumeEnv ? `${resumeEnv} && ` : '';\n const args = resumeArgs\n ? `${resumeArgs} --resume ${shellQuote(claudeSessionId)}`\n : `--resume ${shellQuote(claudeSessionId)}`;\n const cmd = `${envPrefix}PATH=${shellQuote(pathEnv)} claude ${args}`;\n execSync(\n `tmux display-popup -E -w 90% -h 80% -d ${shellQuote(cwd)} ${shellQuote(cmd)}`,\n { stdio: 'inherit', env: EXEC_ENV },\n );\n}\n\nexport function openClaudeResumeSession(cwd: string, sessionId: string, claudeSessionId: string, sessionLabel: string, resumeEnv?: string, resumeArgs?: string, cycleNum?: number, mode?: string): string {\n const sessionName = tmuxSessionName(cwd, sessionLabel);\n const cycleLabel = cycleNum != null ? `c${cycleNum}` : '';\n const paneTitle = cycleLabel ? `ssph:orch ${sessionLabel} ${cycleLabel}` : `ssph:orch ${sessionLabel}`;\n\n // Resolve name → $N id for subsequent -t ops. tmux -t <name> can\n // substring-match the wrong session under sparse env; $N is unambiguous.\n const existing = execSafe('tmux list-sessions -F \"#{session_id}|#{session_name}\"');\n const existingLine = existing?.split('\\n').find(line => line.slice(line.indexOf('|') + 1) === sessionName);\n if (existingLine) {\n const existingSessId = existingLine.slice(0, existingLine.indexOf('|'));\n execSafe(`tmux set-option -t ${shellQuote(existingSessId)} @sisyphus_cwd ${shellQuote(cwd.replace(/\\/+$/, ''))}`);\n execSafe(`tmux set-option -t ${shellQuote(existingSessId)} @sisyphus_session_id ${shellQuote(sessionId)}`);\n const firstPaneId = execSafe(`tmux list-panes -t ${shellQuote(existingSessId)} -F '#{pane_id}'`)?.split('\\n')[0];\n if (firstPaneId) applyOrchestratorPaneStyle(firstPaneId, paneTitle, sessionLabel, cycleLabel, mode);\n return sessionName;\n }\n\n const pathEnv = augmentedPath();\n const envPrefix = resumeEnv ? `${resumeEnv} && ` : '';\n const args = resumeArgs\n ? `${resumeArgs} --resume ${shellQuote(claudeSessionId)}`\n : `--resume ${shellQuote(claudeSessionId)}`;\n const cmd = `${envPrefix}PATH=${shellQuote(pathEnv)} claude ${args}`;\n // -P -F captures the new session's $N id + first pane id for unambiguous targeting.\n const createOut = exec(`tmux new-session -d -s ${shellQuote(sessionName)} -n main -c ${shellQuote(cwd)} -P -F '#{session_id}|#{pane_id}' ${shellQuote(cmd)}`).trim();\n const pipeIdx = createOut.indexOf('|');\n const newSessId = createOut.slice(0, pipeIdx);\n const firstPaneId = createOut.slice(pipeIdx + 1);\n execSafe(`tmux set-option -t ${shellQuote(newSessId)} @sisyphus_cwd ${shellQuote(cwd.replace(/\\/+$/, ''))}`);\n execSafe(`tmux set-option -t ${shellQuote(newSessId)} @sisyphus_session_id ${shellQuote(sessionId)}`);\n // Match session defaults from daemon tmux.ts configureSessionDefaults\n execSafe(`tmux set -w -t ${shellQuote(newSessId + ':')} pane-border-status top`);\n execSafe(`tmux set -w -t ${shellQuote(newSessId + ':')} allow-rename off`);\n execSafe(`tmux set -w -t ${shellQuote(newSessId + ':')} automatic-rename off`);\n if (firstPaneId) applyOrchestratorPaneStyle(firstPaneId, paneTitle, sessionLabel, cycleLabel, mode);\n return sessionName;\n}\n\n/**\n * Mirror daemon's setPaneStyle for an orchestrator pane — sets pane title,\n * per-pane metadata vars (@pane_role/session/cycle/mode), and pane-border-format\n * so the new tmux session shows the same badge as a live orchestrator pane.\n */\nfunction applyOrchestratorPaneStyle(paneId: string, title: string, sessionLabel: string, cycleLabel: string, mode?: string): void {\n const color = 'yellow'; // matches daemon/colors.ts ORCHESTRATOR_COLOR\n execSafe(`tmux select-pane -t ${shellQuote(paneId)} -T ${shellQuote(title)}`);\n execSafe(`tmux set -p -t ${shellQuote(paneId)} @pane_role ${shellQuote('orch')}`);\n execSafe(`tmux set -p -t ${shellQuote(paneId)} @pane_session ${shellQuote(sessionLabel)}`);\n if (cycleLabel) execSafe(`tmux set -p -t ${shellQuote(paneId)} @pane_cycle ${shellQuote(cycleLabel)}`);\n if (mode) execSafe(`tmux set -p -t ${shellQuote(paneId)} @pane_mode ${shellQuote(mode)}`);\n const gitBranch = `#(cd #{pane_current_path} && git branch --show-current 2>/dev/null)`;\n const branchSuffix = `#(cd #{pane_current_path} && git branch --show-current 2>/dev/null | grep -q . && echo ' |') ${gitBranch}`;\n const homePath = `#(echo '#{pane_current_path}' | sed \"s|^$HOME|~|\")`;\n const modeSegment = `#{?#{@pane_mode}, #[fg=${color}\\\\,italics]#{@pane_mode}#[default],}`;\n const fmt = [\n `#[bg=${color},fg=black,bold] #{@pane_role} #[default]`,\n ` #[fg=${color},bold]#{@pane_session}`,\n modeSegment,\n ` #[default,dim]#{@pane_cycle}`,\n ` ${homePath}${branchSuffix}`,\n `#[default]`,\n ].join('');\n execSafe(`tmux set -p -t ${shellQuote(paneId)} pane-border-format ${shellQuote(fmt)}`);\n}\n\nexport function openEditorPopup(cwd: string, editor: string, filePath: string, size?: { w: string; h: string }): void {\n const { w = '90%', h = '90%' } = size ?? {};\n const editorBin = editor.split(/\\s+/)[0]!.split('/').pop()!;\n if (TERMINAL_EDITORS.has(editorBin)) {\n execSync(\n `tmux display-popup -E -w ${w} -h ${h} -d ${shellQuote(cwd)} ${shellQuote(`${editor} ${shellQuote(filePath)}`)}`,\n { stdio: 'inherit', env: EXEC_ENV },\n );\n } else {\n execSync(`${editor} ${shellQuote(filePath)}`, { stdio: 'inherit', cwd, env: EXEC_ENV });\n }\n}\n","import { execSync } from 'node:child_process';\nimport { execEnv } from './env.js';\n\nexport const EXEC_ENV = execEnv();\n\nexport function exec(cmd: string, cwd?: string, timeoutMs: number = 30_000): string {\n return execSync(cmd, { encoding: 'utf-8', env: EXEC_ENV, cwd, timeout: timeoutMs }).trim();\n}\n\nexport function execSafe(cmd: string, cwd?: string, timeoutMs?: number): string | null {\n try {\n return execSync(cmd, { encoding: 'utf-8', env: EXEC_ENV, cwd, stdio: ['pipe', 'pipe', 'pipe'], timeout: timeoutMs }).trim();\n } catch { return null; }\n}\n","import { execSync } from 'node:child_process';\n\nexport function copyToClipboard(text: string): void {\n execSync('pbcopy', { input: text });\n}\n","import { readFileSync, readdirSync } from 'node:fs';\nimport { goalPath, roadmapPath, sessionsDir, statePath } from '../../shared/paths.js';\nimport { resolveReports } from './reports.js';\nimport type { Session, AgentStatus } from '../../shared/types.js';\n\nfunction readFileSafe(filePath: string): string | null {\n try {\n return readFileSync(filePath, 'utf-8');\n } catch {\n return null;\n }\n}\n\nfunction escapeXml(s: string): string {\n return s\n .replace(/&/g, '&')\n .replace(/</g, '<')\n .replace(/>/g, '>')\n .replace(/\"/g, '"');\n}\n\nexport type CompanionContextBlocks = Record<string, string>;\n\nfunction buildSessionBlock(cwd: string, session: Session): string {\n const lines: string[] = [];\n const nameAttr = session.name ? ` name=\"${escapeXml(session.name)}\"` : '';\n lines.push(` <session id=\"${escapeXml(session.id)}\"${nameAttr} status=\"${escapeXml(session.status)}\">`);\n lines.push(` <task>${escapeXml(session.task)}</task>`);\n lines.push(` <created>${escapeXml(session.createdAt)}</created>`);\n lines.push(` <cycles>${session.orchestratorCycles.length}</cycles>`);\n\n if (session.status === 'completed') {\n if (session.completionReport) {\n const snippet = session.completionReport.slice(0, 300).replace(/\\n+/g, ' ').trim();\n lines.push(` <completion-report>${escapeXml(snippet)}${session.completionReport.length > 300 ? '…' : ''}</completion-report>`);\n }\n } else {\n if (session.agents.length > 0) {\n const counts = new Map<AgentStatus, number>();\n for (const agent of session.agents) {\n counts.set(agent.status, (counts.get(agent.status) ?? 0) + 1);\n }\n const summary = [...counts.entries()].map(([status, n]) => `${n} ${status}`).join(', ');\n lines.push(` <agents>${escapeXml(summary)}</agents>`);\n }\n\n const goalContent = readFileSafe(goalPath(cwd, session.id));\n if (goalContent) {\n const firstLine = goalContent.split('\\n').map(l => l.trim()).find(l => l.length > 0 && !l.startsWith('#'));\n if (firstLine) lines.push(` <goal>${escapeXml(firstLine)}</goal>`);\n }\n\n const roadmapContent = readFileSafe(roadmapPath(cwd, session.id));\n if (roadmapContent) {\n const todos = roadmapContent\n .split('\\n')\n .filter(l => l.includes('- [ ]'))\n .slice(0, 5)\n .map(l => l.trim());\n if (todos.length > 0) {\n lines.push(' <todos>');\n for (const todo of todos) lines.push(` ${escapeXml(todo)}`);\n lines.push(' </todos>');\n }\n }\n }\n\n lines.push(' </session>');\n return lines.join('\\n');\n}\n\nexport function buildCompanionContextBlocks(cwd: string): CompanionContextBlocks {\n let sessionDirs: string[];\n try {\n sessionDirs = readdirSync(sessionsDir(cwd));\n } catch {\n return {};\n }\n\n const now = Date.now();\n const sevenDaysMs = 7 * 24 * 60 * 60 * 1000;\n const blocks: CompanionContextBlocks = {};\n\n for (const sessionId of sessionDirs) {\n const stateRaw = readFileSafe(statePath(cwd, sessionId));\n if (!stateRaw) continue;\n\n let session: Session;\n try {\n session = JSON.parse(stateRaw) as Session;\n } catch {\n continue;\n }\n\n if (session.status === 'completed' && session.completedAt) {\n if (now - new Date(session.completedAt).getTime() > sevenDaysMs) continue;\n }\n\n blocks[session.id] = buildSessionBlock(cwd, session);\n }\n\n return blocks;\n}\n\nexport function renderFullContext(blocks: CompanionContextBlocks): string {\n const entries = Object.values(blocks);\n if (entries.length === 0) return '<sessions>No sessions found.</sessions>';\n return ['<sessions>', ...entries, '</sessions>'].join('\\n');\n}\n\n// Returns null when prev and next contain identical blocks (same ids, same XML).\n// Otherwise emits a <sessions-changed-since-last-prompt> wrapper with one entry\n// per added / removed / updated session. The change=\"...\" attribute is spliced\n// after the opening `<session ` of the cached block so every nested element is\n// preserved verbatim — the consumer reads exactly what a full injection would\n// have shown for that session.\nexport function renderContextDelta(prev: CompanionContextBlocks, next: CompanionContextBlocks): string | null {\n const ids = new Set([...Object.keys(prev), ...Object.keys(next)]);\n const entries: string[] = [];\n for (const id of ids) {\n const p = prev[id];\n const n = next[id];\n if (p === undefined && n !== undefined) {\n entries.push(n.replace(/^(\\s*)<session /, `$1<session change=\"added\" `));\n } else if (p !== undefined && n === undefined) {\n entries.push(` <session id=\"${escapeXml(id)}\" change=\"removed\" />`);\n } else if (p !== n && n !== undefined) {\n entries.push(n.replace(/^(\\s*)<session /, `$1<session change=\"updated\" `));\n }\n }\n if (entries.length === 0) return null;\n return ['<sessions-changed-since-last-prompt>', ...entries, '</sessions-changed-since-last-prompt>'].join('\\n');\n}\n\nexport function buildSessionContext(session: Session, cwd: string): string {\n const goal = readFileSafe(goalPath(cwd, session.id));\n const roadmap = readFileSafe(roadmapPath(cwd, session.id));\n\n const agentsXml = session.agents.map((agent) => {\n const reportBlocks = resolveReports(agent.reports);\n // resolveReports returns newest-first; reverse to chronological for context\n const reportsXml = [...reportBlocks].reverse().map((block) => {\n return ` <report type=\"${block.type}\" time=\"${escapeXml(block.timestamp)}\">${escapeXml(block.content)}</report>`;\n }).join('\\n');\n\n return [\n ` <agent id=\"${escapeXml(agent.id)}\" name=\"${escapeXml(agent.name)}\" type=\"${escapeXml(agent.agentType)}\" status=\"${escapeXml(agent.status)}\">`,\n ` <instruction>${escapeXml(agent.instruction)}</instruction>`,\n ...(reportsXml ? [reportsXml] : []),\n ` </agent>`,\n ].join('\\n');\n }).join('\\n');\n\n const cyclesXml = session.orchestratorCycles.map((cycle) => {\n const agents = cycle.agentsSpawned.join(', ');\n const mode = cycle.mode ? ` mode=\"${escapeXml(cycle.mode)}\"` : '';\n return ` <cycle number=\"${cycle.cycle}\"${mode} agents=\"${escapeXml(agents)}\" />`;\n }).join('\\n');\n\n const lines: string[] = [\n '<context>',\n `<session id=\"${escapeXml(session.id)}\" status=\"${escapeXml(session.status)}\">`,\n ` <task>${escapeXml(session.task)}</task>`,\n ` <cwd>${escapeXml(session.cwd)}</cwd>`,\n ];\n\n if (goal) lines.push(` <goal>${escapeXml(goal)}</goal>`);\n if (roadmap) lines.push(` <roadmap>${escapeXml(roadmap)}</roadmap>`);\n\n if (session.agents.length > 0) {\n lines.push(' <agents>');\n lines.push(agentsXml);\n lines.push(' </agents>');\n }\n\n if (session.orchestratorCycles.length > 0) {\n lines.push(' <cycles>');\n lines.push(cyclesXml);\n lines.push(' </cycles>');\n }\n\n if (session.completionReport) {\n lines.push(` <completion-report>${escapeXml(session.completionReport)}</completion-report>`);\n }\n\n lines.push('</session>');\n lines.push('</context>');\n\n return lines.join('\\n');\n}\n","import stringWidth from 'string-width';\nimport type { FrameBuffer, Rect } from '../render.js';\nimport { drawBorder, writeClipped, colorToSGR } from '../render.js';\nimport { renderCompanion, getMoodAnsiCode } from '../../shared/companion-render.js';\nimport type { CompanionField, CompanionState } from '../../shared/companion-types.js';\nimport type { TreeNode } from '../types/tree.js';\nimport { renderTreePrefix } from '../lib/tree-render.js';\nimport {\n statusColor,\n statusIndicator,\n agentStatusIcon,\n truncate,\n formatDuration,\n formatTime,\n formatTimeAgo,\n durationColor,\n agentDisplayName,\n modeColor,\n abbreviateMode,\n} from '../lib/format.js';\n\n// ─── Node content renderer ────────────────────────────────────────────────────\n\ninterface NodeContent {\n icon: string;\n label: string;\n meta: string;\n color: string;\n dim: boolean;\n metaColor?: string;\n suffix?: string;\n suffixColor?: string;\n}\n\nfunction renderNodeContent(node: TreeNode, maxWidth: number): NodeContent {\n switch (node.type) {\n case 'section': {\n switch (node.section) {\n case 'needs-you':\n return {\n icon: '',\n label: 'Needs You',\n meta: node.count > 0 ? `${node.count}` : '',\n color: node.count > 0 ? 'red' : 'gray',\n dim: false,\n metaColor: 'red',\n };\n case 'running':\n return {\n icon: '',\n label: 'Running',\n meta: node.count > 0 ? `${node.count}` : '',\n color: 'green',\n dim: false,\n metaColor: 'gray',\n };\n case 'done':\n return {\n icon: '',\n label: `Done (${node.count})`,\n meta: '',\n color: 'gray',\n dim: true,\n };\n }\n }\n case 'needs-you-virtual': {\n const hasPending = node.pendingCount > 0;\n return {\n icon: '⚑',\n label: 'Needs You',\n meta: hasPending ? `${node.pendingCount} pending` : '',\n color: hasPending ? 'red' : 'gray',\n dim: !hasPending,\n metaColor: hasPending ? 'red' : undefined,\n };\n }\n case 'session': {\n const icon = statusIndicator(node.status);\n const color = statusColor(node.status);\n const dim = node.status === 'completed' || node.orphaned === true;\n const cyclePart = node.cycleCount > 0 ? `C${node.cycleCount}` : '';\n // Use tracked active time (matches detail panel), not wall-clock elapsed.\n const dur = formatDuration(node.activeMs);\n const agopart =\n node.status === 'completed' && node.completedAt ? formatTimeAgo(node.completedAt) : '';\n const askBadge = node.askCount ? `!${node.askCount}` : '';\n const meta = [askBadge, cyclePart, dur, agopart].filter(Boolean).join(' ');\n const metaColor = node.askCount ? 'red' : undefined;\n const suffix = node.orphaned ? '⚠ orphan' : undefined;\n const suffixColor = node.orphaned ? 'red' : undefined;\n const displayText = node.name ?? node.task;\n const suffixWidth = suffix ? suffix.length + 1 : 0;\n const maxLabel = Math.max(8, maxWidth - meta.length - 4 - suffixWidth);\n return { icon, label: truncate(displayText, maxLabel), meta, color, dim, metaColor, suffix, suffixColor };\n }\n case 'cycle': {\n const isRunning = !node.completedAt;\n const dur = isRunning ? 'running' : formatDuration(node.activeMs);\n const agents = `${node.agentCount} agent${node.agentCount !== 1 ? 's' : ''}`;\n const modeShort = abbreviateMode(node.mode);\n const mode = modeShort ? ` · ${modeShort}` : '';\n return {\n icon: isRunning ? '●' : '○',\n label: `C${node.cycleNumber}`,\n meta: `${dur} · ${agents}${mode}`,\n color: isRunning ? 'green' : 'gray',\n dim: !isRunning,\n };\n }\n case 'agent': {\n const icon = agentStatusIcon(node.status);\n const color = statusColor(node.status);\n const dur = formatDuration(node.activeMs);\n const durClr = durationColor(node.activeMs) || undefined;\n const dim = node.status === 'completed' || node.orphaned === true;\n const displayName = agentDisplayName({\n name: node.name,\n id: node.agentId,\n agentType: node.agentType,\n });\n const suffix = node.orphaned ? '⚠ orphan' : undefined;\n const suffixColor = node.orphaned ? 'red' : undefined;\n const suffixWidth = suffix ? suffix.length + 1 : 0;\n const maxLabel = Math.max(8, maxWidth - dur.length - 4 - suffixWidth);\n return {\n icon,\n label: truncate(displayName, maxLabel),\n meta: dur,\n color,\n dim,\n metaColor: durClr,\n suffix,\n suffixColor,\n };\n }\n case 'report': {\n const badge = node.reportType === 'final' ? 'FINAL' : 'UPDATE';\n const time = formatTime(node.timestamp);\n return {\n icon: node.reportType === 'final' ? '◆' : '◇',\n label: `${badge} ${time}`,\n meta: '',\n color: node.reportType === 'final' ? 'cyan' : 'yellow',\n dim: false,\n };\n }\n case 'messages':\n return {\n icon: '✉',\n label: `Messages (${node.count})`,\n meta: '',\n color: 'yellow',\n dim: false,\n };\n case 'message': {\n const maxLabel = Math.max(8, maxWidth - 8);\n return {\n icon: '·',\n label: truncate(`${node.source}: ${node.summary}`, maxLabel),\n meta: formatTime(node.timestamp),\n color: 'gray',\n dim: true,\n };\n }\n case 'context':\n return {\n icon: '⊞',\n label: `Context (${node.fileCount})`,\n meta: '',\n color: 'white',\n dim: node.fileCount === 0,\n };\n case 'context-file': {\n const maxLabel = Math.max(8, maxWidth - 4);\n return {\n icon: '·',\n label: truncate(node.label, maxLabel),\n meta: '',\n color: 'gray',\n dim: false,\n };\n }\n }\n}\n\n// ─── Tree panel renderer ──────────────────────────────────────────────────────\n\nexport function renderTreePanel(\n buf: FrameBuffer,\n rect: Rect,\n nodes: TreeNode[],\n cursorIndex: number,\n focused: boolean,\n companion?: CompanionState | null,\n): void {\n const { x, y, w, h } = rect;\n\n // 1. Border — yellow when focused\n drawBorder(buf, x, y, w, h, focused ? 'cyan' : 'gray');\n\n // 2. Inner dimensions\n const innerX = x + 2;\n const innerW = w - 4;\n const innerY = y + 1;\n const innerH = h - 2;\n\n if (innerW <= 0 || innerH <= 0) return;\n\n // 3. Empty state\n if (nodes.length === 0) {\n writeClipped(buf, innerX, innerY, '\\x1b[1m Sessions \\x1b[0m', innerW);\n writeClipped(buf, innerX, innerY + 1, '\\x1b[2mNo sessions found.\\x1b[0m', innerW);\n writeClipped(buf, innerX, innerY + 2, '\\x1b[2mPress [n] to create one.\\x1b[0m', innerW);\n writeClipped(buf, innerX, innerY + 3, '\\x1b[2mPress [?] for all keybindings.\\x1b[0m', innerW);\n return;\n }\n\n // 4. Scroll logic — reserve rows at bottom for companion (blank + face + wrapped commentary)\n let companionRows = 0;\n let _companionCommentaryLines: string[] = [];\n if (companion) {\n const commentaryText = companion.lastCommentary?.text;\n if (commentaryText) {\n const words = commentaryText.split(' ');\n let current = '';\n let currentWidth = 0;\n for (const word of words) {\n const wordWidth = stringWidth(word);\n if (currentWidth + wordWidth + 1 > innerW && currentWidth > 0) {\n _companionCommentaryLines.push(current);\n current = word;\n currentWidth = wordWidth;\n } else if (currentWidth === 0) {\n current = word;\n currentWidth = wordWidth;\n } else {\n current = `${current} ${word}`;\n currentWidth += 1 + wordWidth;\n }\n }\n if (current.length > 0) _companionCommentaryLines.push(current);\n }\n companionRows = 1 + 1 + _companionCommentaryLines.length; // blank + face + commentary lines\n }\n const maxVisible = Math.max(1, innerH - companionRows);\n const halfVisible = Math.floor(maxVisible / 2);\n const scrollOffset = Math.max(\n 0,\n Math.min(cursorIndex - halfVisible, nodes.length - maxVisible),\n );\n\n // 5. Scroll indicator adjustments\n const hasTopIndicator = scrollOffset > 0;\n const hasBottomIndicator = scrollOffset + maxVisible < nodes.length;\n\n let rowStart = innerY;\n let availRows = maxVisible;\n\n if (hasTopIndicator) {\n const topMore = scrollOffset;\n writeClipped(buf, innerX, rowStart, `\\x1b[2m↑ ${topMore} more\\x1b[0m`, innerW);\n rowStart++;\n availRows--;\n }\n\n if (hasBottomIndicator) {\n availRows--;\n }\n\n // 6. Render visible nodes\n const visible = nodes.slice(scrollOffset, scrollOffset + availRows + (hasBottomIndicator ? 1 : 0));\n const renderCount = Math.min(visible.length, availRows);\n\n for (let i = 0; i < renderCount; i++) {\n const node = visible[i]!;\n const realIdx = scrollOffset + i;\n const isSelected = realIdx === cursorIndex;\n const prefix = node.prefix ?? renderTreePrefix(node, nodes, realIdx);\n const contentWidth = innerW;\n const { icon, label, meta, color, dim, metaColor, suffix, suffixColor } = renderNodeContent(\n node,\n contentWidth - prefix.length,\n );\n\n // Build ANSI string\n let content = '';\n\n // icon with color\n if (icon) {\n if (dim) content += `\\x1b[2;${colorToSGR(color)}m${icon}\\x1b[0m `;\n else content += `\\x1b[${colorToSGR(color)}m${icon}\\x1b[0m `;\n }\n\n // label\n if (dim) content += `\\x1b[2m${label}\\x1b[0m`;\n else content += label;\n\n // meta\n if (meta) {\n if (metaColor) content += ` \\x1b[${colorToSGR(metaColor)}m${meta}\\x1b[0m`;\n else content += ` \\x1b[2m${meta}\\x1b[0m`;\n }\n\n // suffix\n if (suffix && suffixColor) {\n content += ` \\x1b[${colorToSGR(suffixColor)}m${suffix}\\x1b[0m`;\n }\n\n let line = prefix;\n if (isSelected) {\n const bold = '\\x1b[1m';\n const inverse = focused ? '\\x1b[7m' : '';\n line += `${inverse}${bold}${content}\\x1b[0m`;\n } else {\n line += content;\n }\n\n writeClipped(buf, innerX, rowStart + i, line, innerW);\n }\n\n // 7. Bottom scroll indicator\n if (hasBottomIndicator) {\n const bottomMore = nodes.length - scrollOffset - maxVisible;\n const bottomRow = rowStart + availRows;\n writeClipped(buf, innerX, bottomRow, `\\x1b[2m↓ ${bottomMore} more\\x1b[0m`, innerW);\n }\n\n // 8. Companion pinned to bottom (blank + face + wrapped commentary)\n if (companion) {\n const commentaryCount = _companionCommentaryLines.length;\n const faceRow = y + h - 2 - commentaryCount;\n const hasActive = nodes.some((n) => n.type === 'session' && n.status === 'active');\n const fields: CompanionField[] = hasActive\n ? ['face', 'boulder', 'verb']\n : ['face', 'boulder', 'hobby'];\n // Don't use renderCompanion's internal color — applyColor's string replace\n // breaks when maxWidth truncates the result. Apply mood color externally.\n const faceLine = renderCompanion(companion, fields, {\n maxWidth: innerW,\n agentCount: companion.recentActiveAgents ?? 0,\n verbIndex: companion.spinnerVerbIndex,\n });\n const moodCode = getMoodAnsiCode(companion.mood);\n writeClipped(buf, innerX, faceRow, `\\x1b[${moodCode}m${faceLine}\\x1b[0m`, innerW);\n\n for (let i = 0; i < commentaryCount; i++) {\n writeClipped(buf, innerX, faceRow + 1 + i, `\\x1b[${moodCode}m${_companionCommentaryLines[i]}\\x1b[0m`, innerW);\n }\n }\n}\n","import {\n buildPanelRows,\n buildEmptyPanelRows,\n type Rect,\n} from '../render.js';\nimport type { AppState, CycleLog } from '../state.js';\nimport type {\n TreeNode,\n CycleTreeNode,\n AgentTreeNode,\n ReportTreeNode,\n MessageTreeNode,\n ContextFileTreeNode,\n} from '../types/tree.js';\nimport type { Session, Agent, OrchestratorCycle, StatusDigest } from '../../shared/types.js';\nimport { computeActiveTimeMs } from '../../shared/utils.js';\nimport type { ReportBlock } from '../lib/reports.js';\nimport {\n statusColor,\n formatDuration,\n formatTime,\n truncate,\n wrapText,\n stripFrontmatter,\n cleanMarkdown,\n seg,\n singleLine,\n agentDisplayName,\n reportBadge,\n agentStatusIcon,\n agentTypeColor,\n durationColor,\n modeColor,\n messageSourceLabel,\n messageSourceColor,\n extractFirstSentence,\n divider,\n type DetailLine,\n} from '../lib/format.js';\nimport { buildCycleFlowLines } from './cycle-flow.js';\nimport { coerceKind } from '../../shared/inbox-types.js';\n\n// ---------------------------------------------------------------------------\n// Public interface\n// ---------------------------------------------------------------------------\n\nexport interface DetailContext {\n nodes: TreeNode[];\n session: Session | null;\n agents: Agent[];\n reportBlocks: ReportBlock[];\n detailReportBlocks: ReportBlock[];\n contextFileContent: string | null;\n}\n\n// ---------------------------------------------------------------------------\n// PlanLine (copied from PlanView.tsx — no React dependency)\n// ---------------------------------------------------------------------------\n\ninterface PlanLine {\n text: string;\n bold?: boolean;\n dim?: boolean;\n color?: string;\n}\n\nfunction buildPlanLines(content: string, maxLines: number, width: number): PlanLine[] {\n const clean = stripFrontmatter(content);\n if (!clean.trim()) return [];\n\n const contentWidth = width - 4;\n const lines: PlanLine[] = [];\n const rawLines = clean.split('\\n');\n\n for (const rawLine of rawLines) {\n if (lines.length >= maxLines) break;\n\n const trimmed = rawLine.trim();\n\n // Skip frontmatter artifacts\n if (trimmed === '---') continue;\n\n // Headers — bold, with level-based indentation\n const headerMatch = rawLine.match(/^(#{1,6})\\s+(.+)/);\n if (headerMatch) {\n const level = headerMatch[1]!.length;\n const headerText = cleanMarkdown(headerMatch[2]!);\n const indent = ' '.repeat(Math.max(0, level - 1));\n if (lines.length > 0) lines.push({ text: ' ' });\n lines.push({\n text: ` ${indent}${headerText}`,\n bold: true,\n color: level <= 2 ? 'white' : undefined,\n });\n continue;\n }\n\n // Empty lines — pass through (but collapse multiples)\n if (!trimmed) {\n if (lines.length > 0 && lines[lines.length - 1]!.text !== '') {\n lines.push({ text: ' ' });\n }\n continue;\n }\n\n // Numbered list items\n const listMatch = trimmed.match(/^(\\d+)[.)]\\s+(.+)/);\n if (listMatch) {\n const cleaned = `${listMatch[1]}. ${cleanMarkdown(listMatch[2]!)}`;\n const wrapped = wrapText(cleaned, contentWidth - 6);\n for (const wl of wrapped) {\n if (lines.length >= maxLines) break;\n lines.push({ text: ` ${wl}`, dim: true });\n }\n continue;\n }\n\n // Checkbox items — must come before bullet match\n const checkboxMatch = trimmed.match(/^- \\[( |x|X)\\] (.+)/);\n if (checkboxMatch) {\n const checked = checkboxMatch[1] !== ' ';\n const checkboxText = cleanMarkdown(checkboxMatch[2]!);\n const icon = checked ? '☑' : '☐';\n const wrapped = wrapText(`${icon} ${checkboxText}`, contentWidth - 6);\n for (const wl of wrapped) {\n if (lines.length >= maxLines) break;\n lines.push({ text: ` ${wl}`, dim: true, color: checked ? 'green' : undefined });\n }\n continue;\n }\n\n // Bullet items\n const bulletMatch = trimmed.match(/^[-*+]\\s+(.+)/);\n if (bulletMatch) {\n const cleaned = `· ${cleanMarkdown(bulletMatch[1]!)}`;\n const wrapped = wrapText(cleaned, contentWidth - 6);\n for (const wl of wrapped) {\n if (lines.length >= maxLines) break;\n lines.push({ text: ` ${wl}`, dim: true });\n }\n continue;\n }\n\n // Regular content — clean and wrap\n const cleaned = cleanMarkdown(trimmed);\n const wrapped = wrapText(cleaned, contentWidth - 4);\n for (const wl of wrapped) {\n if (lines.length >= maxLines) break;\n lines.push({ text: ` ${wl}`, dim: true });\n }\n }\n\n // Truncation indicator\n const totalContentLines = rawLines.filter((l) => l.trim()).length;\n if (lines.length >= maxLines && totalContentLines > maxLines) {\n lines[lines.length - 1] = { text: ' … [p] open in editor', dim: true };\n }\n\n return lines;\n}\n\n// ---------------------------------------------------------------------------\n// buildSessionLines (ported from SessionDetail.tsx buildLines)\n// ---------------------------------------------------------------------------\n\nfunction buildSessionLines(\n session: Session,\n planContent: string,\n goalContent: string | undefined,\n width: number,\n paneAlive: boolean,\n strategyContent: string = '',\n flowExpanded: boolean = false,\n): DetailLine[] {\n const lines: DetailLine[] = [];\n const contentWidth = width - 4;\n const agents = session.agents;\n const cycles = session.orchestratorCycles;\n const isDead = session.status === 'active' && !paneAlive;\n // Goal text\n const goalText = goalContent\n ? cleanMarkdown(stripFrontmatter(goalContent).trim())\n : session.task;\n goalText\n .split('\\n')\n .flatMap((l) => wrapText(l, contentWidth - 2))\n .forEach((line, i) => {\n lines.push(singleLine(`${i === 0 ? ' ' : ' '}${line}`, { bold: true }));\n });\n\n // Status bar\n const lastCycle = cycles.length > 0 ? cycles[cycles.length - 1]! : null;\n const cycleNum = lastCycle !== null ? lastCycle.cycle : 0;\n const mode = lastCycle !== null && lastCycle.mode !== undefined ? lastCycle.mode : '';\n const runningAgents = agents.filter((a) => a.status === 'running').length;\n const completedAgents = agents.filter((a) => a.status === 'completed').length;\n const elapsed = formatDuration(session.createdAt, session.completedAt);\n const activeMs = computeActiveTimeMs(session);\n const activeTime = formatDuration(activeMs);\n const modeLabelColor = modeColor(mode);\n lines.push([\n seg(' '),\n seg(isDead ? '✕ dead' : session.status, {\n color: statusColor(isDead ? 'crashed' : session.status),\n }),\n seg(` · cycle ${cycleNum}`, { dim: true }),\n ...(mode ? [seg(' (', { dim: true }), seg(mode, { color: modeLabelColor }), seg(')', { dim: true })] : []),\n seg(` · ${elapsed} · `, { dim: true }),\n seg(`${runningAgents} running`, { color: 'green' }),\n seg(' · ', { dim: true }),\n seg(`${completedAgents} done`, { color: 'cyan' }),\n seg(` · ${activeTime} active`, { dim: true }),\n ]);\n\n // Dead session warning\n if (isDead) {\n lines.push([\n seg(' '),\n seg(' ✕ DEAD ', { color: 'red', bold: true }),\n seg(' tmux window closed — [w] reopen [R] resume', { color: 'red' }),\n ]);\n }\n\n // Orphan tag\n if (session.orphaned) {\n lines.push([\n seg(' '),\n seg('⚠ orphan', { color: 'red', bold: true }),\n seg(' — orchestrator process lost', { color: 'red' }),\n ]);\n }\n\n // Plan / Strategy section\n lines.push(singleLine(' '));\n if (strategyContent) {\n lines.push([seg(' ▎ ◈ STRATEGY', { color: 'yellow', bold: true })]);\n const stratLines = buildPlanLines(strategyContent, 99999, width);\n if (stratLines.length === 0) {\n lines.push(singleLine(' (empty)', { dim: true, italic: true }));\n } else {\n for (const pl of stratLines) {\n lines.push(singleLine(pl.text, { bold: pl.bold, dim: pl.dim, color: pl.color }));\n }\n }\n } else {\n lines.push([seg(' ▎ ◈ PLAN', { color: 'yellow', bold: true })]);\n const planLines = buildPlanLines(planContent, 99999, width);\n if (planLines.length === 0) {\n lines.push(singleLine(' orchestrator will create one', { dim: true, italic: true }));\n } else {\n for (const pl of planLines) {\n lines.push(singleLine(pl.text, { bold: pl.bold, dim: pl.dim, color: pl.color }));\n }\n }\n }\n\n // Completion report\n if (session.status === 'completed' && session.completionReport) {\n lines.push(singleLine(' '));\n lines.push([seg(' ▎ ✓ COMPLETION', { color: 'cyan', bold: true })]);\n wrapText(session.completionReport, contentWidth - 6).forEach((l) => {\n lines.push(singleLine(` ${l}`, { dim: true }));\n });\n }\n\n // Cycle flow visualization\n lines.push(singleLine(' '));\n lines.push(...buildCycleFlowLines(session, contentWidth, flowExpanded));\n\n return lines;\n}\n\n// ---------------------------------------------------------------------------\n// buildCycleLines (ported from CycleDetail.tsx buildLines)\n// ---------------------------------------------------------------------------\n\nfunction buildCycleLines(cycle: OrchestratorCycle, agents: Agent[], width: number): DetailLine[] {\n const lines: DetailLine[] = [];\n const contentWidth = width - 4;\n const isRunning = !cycle.completedAt;\n const dur = isRunning ? 'running' : formatDuration(cycle.activeMs);\n const cycleAgents = agents.filter((a) => cycle.agentsSpawned.includes(a.id));\n\n lines.push(singleLine(` Cycle ${cycle.cycle}`, { bold: true }));\n lines.push([\n seg(' '),\n seg(isRunning ? 'running' : 'completed', { color: isRunning ? 'green' : 'gray' }),\n seg(` · ${dur} · ${cycleAgents.length} agent${cycleAgents.length !== 1 ? 's' : ''}`, { dim: true }),\n ...(cycle.mode\n ? [seg(' · ', { dim: true }), seg(cycle.mode, { color: modeColor(cycle.mode) })]\n : []),\n ]);\n lines.push(singleLine(\n ` ${formatTime(cycle.timestamp)}${cycle.completedAt ? ` → ${formatTime(cycle.completedAt)}` : ''}`,\n { dim: true },\n ));\n if (cycle.claudeSessionId) {\n lines.push(singleLine(` Session: ${cycle.claudeSessionId}`, { dim: true }));\n }\n\n lines.push(singleLine(' '));\n lines.push([seg(' ▎ ⊞ AGENTS', { color: 'green', bold: true })]);\n\n if (cycleAgents.length === 0) {\n lines.push(singleLine(' orchestrator spawning agents…', { dim: true, italic: true }));\n } else {\n for (const agent of cycleAgents) {\n const nameLabel = agentDisplayName(agent);\n const instrPreview = agent.instruction.split('\\n')[0]!;\n const latestReport = agent.reports.length > 0 ? agent.reports[agent.reports.length - 1]! : null;\n const reportSummary = latestReport !== null && agent.status === 'completed'\n ? extractFirstSentence(latestReport.summary, contentWidth - 14)\n : null;\n const agentDur = formatDuration(agent.activeMs);\n const durClrRaw = durationColor(agent.activeMs);\n const durClr = durClrRaw !== '' ? durClrRaw : undefined;\n const typeClrRaw = agentTypeColor(agent.agentType);\n const typeClr = typeClrRaw !== undefined ? typeClrRaw : undefined;\n\n lines.push([\n seg(' '),\n seg(agentStatusIcon(agent.status), { color: statusColor(agent.status) }),\n seg(` ${agent.id}`, { bold: true }),\n seg(` ${truncate(nameLabel, contentWidth - 30)}`, {\n color: typeClr,\n dim: typeClr === undefined,\n }),\n seg(` · ${agent.status} · `, { dim: true }),\n seg(agentDur, { color: durClr, dim: !durClr }),\n ]);\n\n if (instrPreview) {\n lines.push(singleLine(` ${truncate(instrPreview, contentWidth - 10)}`, { dim: true }));\n }\n\n if (reportSummary) {\n lines.push([\n seg(' '),\n seg('↳', { color: 'cyan' }),\n seg(` ${reportSummary}`, { dim: true }),\n ]);\n }\n }\n }\n\n if (cycle.nextPrompt) {\n lines.push(singleLine(' '));\n lines.push([seg(' ▎ ▷ NEXT PROMPT', { color: 'yellow', bold: true })]);\n for (const wl of wrapText(cycle.nextPrompt, contentWidth - 6)) {\n lines.push(singleLine(` ${wl}`, { dim: true }));\n }\n }\n\n return lines;\n}\n\n// ---------------------------------------------------------------------------\n// buildAgentLines (ported from AgentDetail.tsx buildLines)\n// ---------------------------------------------------------------------------\n\nfunction buildAgentLines(agent: Agent, reportBlocks: ReportBlock[] | undefined, width: number): DetailLine[] {\n const lines: DetailLine[] = [];\n const contentWidth = width - 4;\n const dur = formatDuration(agent.activeMs);\n const icon = agentStatusIcon(agent.status);\n const color = statusColor(agent.status);\n const nameLabel = agentDisplayName(agent);\n lines.push([\n seg(' '),\n seg(icon, { color }),\n seg(` ${agent.id} · ${nameLabel}`, { bold: true }),\n ]);\n\n lines.push([\n seg(' '),\n seg(agent.status, { color }),\n seg(` · ${dur} · ${agent.agentType}`, { dim: true }),\n ]);\n\n if (agent.killedReason) {\n lines.push(singleLine(` ⚠ ${agent.killedReason}`, { color: 'red' }));\n }\n\n lines.push(singleLine(' '));\n lines.push(singleLine(' ▎ ▷ INSTRUCTION', { color: 'white', bold: true }));\n for (const wl of wrapText(agent.instruction, contentWidth - 6)) {\n lines.push(singleLine(` ${wl}`, { dim: true }));\n }\n\n if (agent.reports.length > 0) {\n const hasResolved = reportBlocks && reportBlocks.length > 0;\n lines.push(singleLine(' '));\n lines.push([seg(` ▎ ◇ REPORTS (${agent.reports.length})`, { color: 'cyan', bold: true })]);\n\n if (hasResolved) {\n for (let i = 0; i < reportBlocks.length; i++) {\n const block = reportBlocks[i]!;\n const { label: badge, color: badgeColor } = reportBadge(block.type);\n\n if (i > 0) lines.push(singleLine(' '));\n lines.push([\n seg(' '),\n seg(badge, { color: badgeColor, bold: block.type === 'final' }),\n seg(` ${formatTime(block.timestamp)}`, { dim: true }),\n ]);\n for (const wl of wrapText(block.content.trim(), contentWidth - 10)) {\n lines.push(singleLine(` ${wl}`, { dim: true }));\n }\n }\n } else {\n for (const report of agent.reports) {\n const { label: badge, color: badgeColor } = reportBadge(report.type);\n lines.push([\n seg(' '),\n seg(badge, { color: badgeColor, bold: report.type === 'final' }),\n seg(` ${formatTime(report.timestamp)} ${report.summary.split('\\n')[0]}`, { dim: true }),\n ]);\n }\n }\n }\n\n lines.push(singleLine(' '));\n lines.push(singleLine(' ▎ ◦ META', { color: 'gray', bold: true }));\n lines.push(singleLine(` Spawned: ${formatTime(agent.spawnedAt)}`, { dim: true }));\n if (agent.completedAt) {\n lines.push(singleLine(` Completed: ${formatTime(agent.completedAt)}`, { dim: true }));\n }\n if (agent.claudeSessionId) {\n lines.push(singleLine(` Session: ${agent.claudeSessionId}`, { dim: true }));\n }\n if (agent.paneId) {\n lines.push(singleLine(` Pane: ${agent.paneId}`, { dim: true }));\n }\n return lines;\n}\n\n// ---------------------------------------------------------------------------\n// buildReportViewLines (ported from ReportView.tsx buildLines)\n// ---------------------------------------------------------------------------\n\nfunction buildReportViewLines(agent: Agent, reportBlocks: ReportBlock[], width: number): DetailLine[] {\n const lines: DetailLine[] = [];\n const contentWidth = width - 6;\n const dur = formatDuration(agent.activeMs);\n const icon = agentStatusIcon(agent.status);\n const color = statusColor(agent.status);\n const totalReports = agent.reports.length;\n const nameLabel = agentDisplayName(agent);\n\n lines.push([\n seg(' '),\n seg(icon, { color }),\n seg(' '),\n seg(agent.id, { bold: true }),\n seg(' ', { dim: true }),\n seg('·', { dim: true }),\n seg(' '),\n seg(nameLabel, { bold: true }),\n ]);\n\n lines.push(singleLine(\n ` ${agent.status} · ${dur} · ${agent.agentType} · ${totalReports} report${totalReports !== 1 ? 's' : ''}`,\n { dim: true },\n ));\n\n lines.push(singleLine(' ' + divider(contentWidth - 2), { dim: true }));\n\n if (reportBlocks.length === 0) {\n lines.push(singleLine(''));\n lines.push(singleLine(' No reports submitted yet.', { dim: true }));\n lines.push(singleLine(''));\n return lines;\n }\n\n for (let i = 0; i < reportBlocks.length; i++) {\n const report = reportBlocks[i]!;\n const time = formatTime(report.timestamp);\n\n if (i > 0) {\n lines.push(singleLine(''));\n lines.push(singleLine(` ${divider(contentWidth - 2, '·')}`, { dim: true }));\n lines.push(singleLine(''));\n }\n\n const { label: badge, color: badgeColor } = reportBadge(report.type);\n lines.push([\n seg(` ${badge}`, { color: badgeColor, bold: report.type === 'final' }),\n seg(` ${time}`, { color: badgeColor }),\n ]);\n\n lines.push(singleLine(''));\n\n const wrapped = wrapText(report.content.trim(), contentWidth - 4);\n for (const line of wrapped) {\n lines.push(singleLine(` ${line}`));\n }\n }\n\n lines.push(singleLine(''));\n return lines;\n}\n\n// ---------------------------------------------------------------------------\n// buildLogsLines (ported from LogsPanel.tsx buildLines)\n// ---------------------------------------------------------------------------\n\nexport function buildLogsLines(cycleLogs: CycleLog[], width: number): DetailLine[] {\n const lines: DetailLine[] = [];\n const contentWidth = width - 4;\n\n if (cycleLogs.length === 0) {\n return lines;\n }\n\n const sorted = [...cycleLogs].sort((a, b) => b.cycle - a.cycle);\n\n for (const { cycle, content } of sorted) {\n lines.push([seg(` Cycle ${cycle}`, { color: 'blue', bold: true })]);\n\n const cleaned = cleanMarkdown(stripFrontmatter(content)).trim();\n if (cleaned) {\n for (const rawLine of cleaned.split('\\n')) {\n const wrapped = wrapText(rawLine, contentWidth - 2);\n for (const wl of wrapped) {\n lines.push([seg(` ${wl}`, { dim: true })]);\n }\n }\n }\n\n lines.push([seg(' ')]);\n }\n\n return lines;\n}\n\n// ---------------------------------------------------------------------------\n// Main entry points\n// ---------------------------------------------------------------------------\n\nexport function renderDetailRows(\n rect: Rect,\n state: AppState,\n detailCtx: DetailContext,\n): string[] {\n const { session, agents, reportBlocks, detailReportBlocks, contextFileContent } = detailCtx;\n const focused = state.focusPane === 'detail';\n\n // Report detail mode — full panel\n if (state.mode === 'report-detail') {\n const reportAgent = agents.find((a) => a.id === state.targetAgentId);\n if (reportAgent) {\n const lines = buildReportViewLines(reportAgent, reportBlocks, rect.w);\n return buildPanelRows(rect, lines, state.detailScroll, focused, 'cyan');\n }\n }\n\n // No cursor / no session → empty state\n const cursorNode: TreeNode | undefined = detailCtx.nodes[state.cursorIndex];\n if (!cursorNode || !session) {\n return buildEmptyPanelRows(rect, false, 'gray', '\\x1b[2mSelect a session to view details\\x1b[0m');\n }\n\n // Session data hasn't arrived yet (poll debounced during rapid scrolling)\n if (cursorNode.sessionId !== session.id) {\n return buildEmptyPanelRows(rect, false, 'gray');\n }\n\n // Compute cache key from all inputs that affect line building\n const lastCycle = session.orchestratorCycles[session.orchestratorCycles.length - 1];\n const cacheKey = [\n cursorNode.id,\n cursorNode.type,\n state.mode,\n state.targetAgentId,\n rect.w,\n session.id,\n session.agents.length,\n session.orchestratorCycles.length,\n lastCycle?.completedAt ?? '',\n lastCycle?.agentsSpawned.length ?? 0,\n state.planContent.length,\n state.goalContent.length,\n state.strategyContent.length,\n state.paneAlive,\n detailReportBlocks.length,\n session.messages.length,\n state.contextFiles.length,\n contextFileContent?.length ?? -1,\n state.flowExpanded,\n ].join(':');\n\n let lines: DetailLine[];\n let borderColor = 'gray';\n\n if (cacheKey === state.detailCacheKey && state.cachedDetailLines !== null) {\n lines = state.cachedDetailLines;\n } else {\n switch (cursorNode.type) {\n case 'session': {\n lines = buildSessionLines(session, state.planContent, state.goalContent, rect.w, state.paneAlive, state.strategyContent, state.flowExpanded);\n break;\n }\n\n case 'cycle': {\n const cycleNode = cursorNode as CycleTreeNode;\n const cycle = session.orchestratorCycles.find((c) => c.cycle === cycleNode.cycleNumber);\n if (!cycle) {\n lines = buildSessionLines(session, state.planContent, state.goalContent, rect.w, state.paneAlive, state.strategyContent, state.flowExpanded);\n } else {\n lines = buildCycleLines(cycle, session.agents, rect.w);\n }\n break;\n }\n\n case 'agent': {\n const agentNode = cursorNode as AgentTreeNode;\n const agent = agents.find((a) => a.id === agentNode.agentId);\n if (!agent) {\n lines = buildSessionLines(session, state.planContent, state.goalContent, rect.w, state.paneAlive, state.strategyContent, state.flowExpanded);\n } else {\n lines = buildAgentLines(agent, detailReportBlocks, rect.w);\n }\n break;\n }\n\n case 'report': {\n const reportNode = cursorNode as ReportTreeNode;\n const agent = agents.find((a) => a.id === reportNode.agentId);\n if (!agent) {\n lines = buildSessionLines(session, state.planContent, state.goalContent, rect.w, state.paneAlive, state.strategyContent, state.flowExpanded);\n break;\n }\n const reportIdx = reportNode.reportIndex;\n const specificBlock = detailReportBlocks.find((_b, i) => {\n const originalIdx = agent.reports.length - 1 - i;\n return originalIdx === reportIdx;\n });\n if (specificBlock) {\n const { label: badge, color: badgeColor } = reportBadge(specificBlock.type);\n lines = [\n [seg(' '), seg(badge, { color: badgeColor }), seg(` ${agent.id} · ${agentDisplayName(agent)}`, { bold: true })],\n singleLine(` ${formatTime(specificBlock.timestamp)}`, { dim: true }),\n singleLine(' '),\n [seg(' ▎ CONTENT', { color: badgeColor, bold: true })],\n ...wrapText(specificBlock.content.trim(), rect.w - 8).map((l) => singleLine(` ${l}`)),\n ];\n borderColor = badgeColor;\n } else {\n lines = buildAgentLines(agent, detailReportBlocks, rect.w);\n }\n break;\n }\n\n case 'messages': {\n lines = [singleLine(` Messages (${session.messages.length})`, { bold: true })];\n if (session.messages.length === 0) {\n lines.push(singleLine(' No messages', { dim: true, italic: true }));\n } else {\n for (const msg of session.messages) {\n const time = formatTime(msg.timestamp);\n const agentId = msg.source.type === 'agent' ? msg.source.agentId : undefined;\n const label = messageSourceLabel(msg.source.type, agentId);\n const labelColor = messageSourceColor(msg.source.type);\n const maxContent = Math.max(10, rect.w - label.length - 20);\n lines.push([\n seg(` [${time}] `, { dim: true }),\n seg(`${label}: `, { color: labelColor, bold: true }),\n seg(wrapText(msg.summary.length > 0 ? msg.summary : msg.content, maxContent)[0]!, {}),\n ]);\n }\n }\n break;\n }\n\n case 'message': {\n const msgNode = cursorNode as MessageTreeNode;\n const msg = session.messages.find((m) => m.id === msgNode.messageId);\n lines = [singleLine(' Message', { bold: true })];\n if (msg) {\n lines.push(singleLine(` ${msgNode.source} · ${msgNode.timestamp}`, { dim: true }));\n for (const l of wrapText(msg.content, rect.w - 8)) {\n lines.push(singleLine(` ${l}`));\n }\n } else {\n lines.push(singleLine(' Message not found', { dim: true }));\n }\n break;\n }\n\n case 'context': {\n lines = [\n [seg(' '), seg('⊞', { color: 'white' }), seg(` Context (${state.contextFiles.length})`, { bold: true })],\n ];\n if (state.contextFiles.length === 0) {\n lines.push(singleLine(' No context files found.', { dim: true }));\n } else {\n for (const f of state.contextFiles) {\n lines.push(singleLine(` · ${f}`, { dim: true }));\n }\n }\n break;\n }\n\n case 'context-file': {\n const ctxFileNode = cursorNode as ContextFileTreeNode;\n lines = [\n [seg(' '), seg('⊞', { color: 'white' }), seg(` ${ctxFileNode.label}`, { bold: true })],\n singleLine(' '),\n ];\n if (contextFileContent == null) {\n lines.push(singleLine(' File not found or unreadable.', { dim: true }));\n } else {\n const wrapped = wrapText(stripFrontmatter(contextFileContent), rect.w - 8);\n if (wrapped.length === 0) {\n lines.push(singleLine(' (empty)', { dim: true }));\n } else {\n for (const l of wrapped) {\n lines.push(singleLine(` ${l}`));\n }\n }\n }\n borderColor = 'white';\n break;\n }\n\n default: {\n lines = buildSessionLines(session, state.planContent, state.goalContent, rect.w, state.paneAlive, state.strategyContent, state.flowExpanded);\n break;\n }\n }\n\n state.cachedDetailLines = lines;\n state.detailCacheKey = cacheKey;\n }\n\n // Compute borderColor from node type (cheap, no need to cache)\n if (cursorNode.type === 'context-file') {\n borderColor = 'white';\n } else if (cursorNode.type === 'report') {\n const reportNode = cursorNode as ReportTreeNode;\n const agent = agents.find((a) => a.id === reportNode.agentId);\n if (agent) {\n const reportIdx = reportNode.reportIndex;\n const specificBlock = detailReportBlocks.find((_b, i) => {\n const originalIdx = agent.reports.length - 1 - i;\n return originalIdx === reportIdx;\n });\n if (specificBlock) borderColor = reportBadge(specificBlock.type).color;\n }\n }\n\n return buildPanelRows(rect, lines, state.detailScroll, focused, borderColor, state.detailRenderedCache);\n}\n\n// ---------------------------------------------------------------------------\n// buildDigestLines / renderDigestRows\n// ---------------------------------------------------------------------------\n\nfunction buildDigestLines(digest: StatusDigest, width: number): DetailLine[] {\n const lines: DetailLine[] = [];\n const contentWidth = width - 4;\n\n // Recent Work\n lines.push([seg(' Recent Work', { color: 'cyan', bold: true })]);\n for (const wl of wrapText(digest.recentWork, contentWidth - 4)) {\n lines.push(singleLine(` ${wl}`));\n }\n lines.push(singleLine(''));\n\n // Current Activity\n lines.push([seg(' Now', { color: 'white', bold: true })]);\n for (const wl of wrapText(digest.currentActivity, contentWidth - 4)) {\n lines.push(singleLine(` ${wl}`));\n }\n lines.push(singleLine(''));\n\n // What's Next\n lines.push([seg(' Up Next', { color: 'white', bold: true })]);\n for (const wl of wrapText(digest.whatsNext, contentWidth - 4)) {\n lines.push([seg(` ${wl}`, { dim: true })]);\n }\n lines.push(singleLine(''));\n\n // Unusual Events\n if (digest.unusualEvents.length > 0) {\n lines.push([seg(' Unusual', { color: 'yellow', bold: true })]);\n for (const event of digest.unusualEvents) {\n for (const wl of wrapText(`· ${event}`, contentWidth - 4)) {\n lines.push([seg(` ${wl}`, { color: 'yellow' })]);\n }\n }\n }\n\n return lines;\n}\n\nfunction buildDoneDigestLines(session: Session, digest: StatusDigest | null, width: number): DetailLine[] {\n const lines: DetailLine[] = [];\n const contentWidth = width - 4;\n\n // KPI band — most-asked stats first\n const kpiCycles = session.orchestratorCycles.length;\n const kpiAgents = session.agents.length;\n const kpiWall = session.wallClockMs\n ? formatMs(session.wallClockMs)\n : (session.completedAt ? formatDuration(session.createdAt, session.completedAt) : '—');\n const kpiActive = formatMs(computeActiveTimeMs(session));\n\n lines.push([seg(' Stats', { color: 'cyan', bold: true })]);\n lines.push([\n seg(' cycles ', { dim: true }),\n seg(String(kpiCycles), { color: 'white', bold: true }),\n seg(' · agents ', { dim: true }),\n seg(String(kpiAgents), { color: 'white', bold: true }),\n ]);\n lines.push([\n seg(' wall ', { dim: true }),\n seg(kpiWall, { color: 'white', bold: true }),\n seg(' · active ', { dim: true }),\n seg(kpiActive, { color: 'white', bold: true }),\n ]);\n lines.push(singleLine(''));\n\n // What shipped (recapped from digest if present)\n if (digest?.recentWork) {\n lines.push([seg(' What shipped', { color: 'cyan', bold: true })]);\n for (const wl of wrapText(digest.recentWork, contentWidth - 4)) {\n lines.push(singleLine(` ${wl}`));\n }\n lines.push(singleLine(''));\n }\n\n // Final state — replaces Now/Up Next\n lines.push([seg(' Final', { color: 'white', bold: true })]);\n if (session.completedAt) {\n lines.push([seg(` completed ${formatTimestampShort(session.completedAt)}`, { dim: true })]);\n }\n if (digest?.currentActivity) {\n for (const wl of wrapText(digest.currentActivity, contentWidth - 4)) {\n lines.push([seg(` ${wl}`, { dim: true })]);\n }\n }\n lines.push(singleLine(''));\n\n // Notable — preserved from Unusual; still useful post-hoc\n if (digest && digest.unusualEvents.length > 0) {\n lines.push([seg(' Notable', { color: 'yellow', bold: true })]);\n for (const event of digest.unusualEvents) {\n for (const wl of wrapText(`· ${event}`, contentWidth - 4)) {\n lines.push([seg(` ${wl}`, { color: 'yellow' })]);\n }\n }\n }\n\n return lines;\n}\n\nfunction formatMs(ms: number): string {\n if (!ms || ms < 0) return '—';\n const sec = Math.floor(ms / 1000);\n if (sec < 60) return `${sec}s`;\n const min = Math.floor(sec / 60);\n if (min < 60) return `${min}m${sec % 60 ? ` ${sec % 60}s` : ''}`;\n const hr = Math.floor(min / 60);\n return `${hr}h${min % 60 ? ` ${min % 60}m` : ''}`;\n}\n\nfunction formatTimestampShort(iso: string): string {\n try {\n const d = new Date(iso);\n if (isNaN(d.getTime())) return iso;\n return d.toLocaleString();\n } catch {\n return iso;\n }\n}\n\nfunction renderFleetRollup(rect: Rect, state: AppState, focused: boolean): string[] {\n const items = state.aggregateInbox;\n const sessions = state.sessions;\n const cacheKey = `rollup:${items.length}:${sessions.length}:${items.map(i => `${i.askId}:${i.status}`).join(',')}:${rect.w}`;\n let lines: DetailLine[];\n if (cacheKey === state.digestCacheKey && state.cachedDigestLines !== null) {\n lines = state.cachedDigestLines;\n } else {\n const byKind = new Map<string, number>();\n for (const i of items) {\n const k = coerceKind(i.kind);\n byKind.set(k, (byKind.get(k) ?? 0) + 1);\n }\n const byStatus = new Map<string, number>();\n for (const s of sessions) {\n byStatus.set(s.status, (byStatus.get(s.status) ?? 0) + 1);\n }\n const uniqueSessions = new Set(items.map(i => i.sessionId)).size;\n lines = [];\n lines.push([seg(' Fleet Inbox', { color: 'red', bold: true })]);\n lines.push(singleLine(` ${items.length} pending across ${uniqueSessions} sessions`, { dim: true }));\n lines.push(singleLine(' '));\n lines.push([seg(' By Type', { color: 'cyan', bold: true })]);\n for (const [kind, count] of byKind) {\n lines.push(singleLine(` · ${kind}: ${count}`, { dim: true }));\n }\n lines.push(singleLine(' '));\n lines.push([seg(' Sessions', { color: 'white', bold: true })]);\n for (const [status, count] of byStatus) {\n lines.push(singleLine(` · ${status}: ${count}`, { dim: true }));\n }\n state.cachedDigestLines = lines;\n state.digestCacheKey = cacheKey;\n }\n return buildPanelRows(rect, lines, state.digestScroll, focused, 'red', state.digestRenderedCache);\n}\n\nexport function renderDigestRows(\n rect: Rect,\n state: AppState,\n): string[] {\n const focused = state.focusPane === 'logs';\n const digest = state.digestData;\n const session = state.selectedSession;\n\n if (state.detailMode === 'cross-session-inbox') {\n return renderFleetRollup(rect, state, focused);\n }\n\n if (!digest && !session) {\n return buildEmptyPanelRows(rect, focused, 'cyan', '\\x1b[2mAwaiting digest...\\x1b[0m');\n }\n\n // Combined cache key: digest + flow inputs\n const lastCycle = session?.orchestratorCycles[session.orchestratorCycles.length - 1];\n const agentStatuses = session?.agents.map(a => `${a.id}:${a.status}`).join(',') ?? '';\n const isDone = session?.status === 'completed';\n const cacheKey = [\n JSON.stringify(digest),\n session?.id ?? '',\n session?.status ?? '',\n session?.orchestratorCycles.length ?? 0,\n lastCycle?.completedAt ?? '',\n lastCycle?.agentsSpawned.length ?? 0,\n lastCycle?.nextPrompt?.length ?? 0,\n agentStatuses,\n state.flowExpanded,\n rect.w,\n ].join(':');\n\n let lines: DetailLine[];\n if (cacheKey === state.digestCacheKey && state.cachedDigestLines !== null) {\n lines = state.cachedDigestLines;\n } else {\n lines = [];\n if (isDone && session) {\n lines.push(...buildDoneDigestLines(session, digest, rect.w));\n } else if (digest) {\n lines.push(...buildDigestLines(digest, rect.w));\n }\n if (session) {\n lines.push(singleLine(''));\n lines.push(...buildCycleFlowLines(session, rect.w - 4, state.flowExpanded));\n }\n state.cachedDigestLines = lines;\n state.digestCacheKey = cacheKey;\n }\n\n return buildPanelRows(rect, lines, state.digestScroll, focused, 'cyan', state.digestRenderedCache);\n}\n\n\n","import type { Session } from './types.js';\n\n/**\n * Return the tracked active time for a session.\n * Active time is accumulated by the daemon's pane monitor, excluding sleep/idle gaps.\n */\nexport function computeActiveTimeMs(session: Session): number {\n return session.activeMs;\n}\n","import stringWidth from 'string-width';\nimport type { Session, Agent, OrchestratorCycle } from '../../shared/types.js';\nimport { formatDuration } from '../../shared/format.js';\nimport {\n seg,\n singleLine,\n agentDisplayName,\n agentStatusIcon,\n statusColor,\n durationColor,\n modeColor,\n abbreviateMode,\n truncate,\n wrapText,\n formatTime,\n type DetailLine,\n type Seg,\n} from '../lib/format.js';\n\n// ---------------------------------------------------------------------------\n// Background tints (dark ANSI 24-bit backgrounds)\n// ---------------------------------------------------------------------------\n\nconst BG_TINTS: Record<string, string> = {\n yellow: '48;2;40;35;20',\n blue: '48;2;20;25;45',\n green: '48;2;20;35;20',\n magenta: '48;2;30;22;40',\n cyan: '48;2;18;30;38',\n red: '48;2;40;20;22',\n gray: '48;2;25;26;32',\n white: '48;2;30;30;30',\n};\n\n// Map tmux/extended color names to standard ANSI color names for seg()\nconst TMUX_TO_ANSI: Record<string, string> = {\n colour208: 'yellow', // orange\n colour6: 'cyan', // teal\n orange: 'yellow',\n teal: 'cyan',\n};\n\n/** Resolve a color name (possibly tmux-extended) to a valid ANSI color name */\nfunction resolveColor(color: string): string {\n return TMUX_TO_ANSI[color] ?? color;\n}\n\n// ---------------------------------------------------------------------------\n// Phase detection\n// ---------------------------------------------------------------------------\n\ntype Phase = 'orchestrator' | 'agents' | 'between' | 'complete';\n\nfunction getCurrentPhase(session: Session): Phase {\n if (session.status === 'completed') return 'complete';\n const cycles = session.orchestratorCycles;\n if (cycles.length === 0) return 'orchestrator';\n const lastCycle = cycles[cycles.length - 1]!;\n const cycleAgents = session.agents.filter(a => lastCycle.agentsSpawned.includes(a.id));\n\n if (!lastCycle.completedAt) {\n return cycleAgents.length > 0 ? 'agents' : 'orchestrator';\n }\n\n const allDone = cycleAgents.every(a => a.status !== 'running');\n if (cycleAgents.length > 0 && !allDone) return 'agents';\n if (cycleAgents.length > 0 && allDone && lastCycle.nextPrompt) return 'between';\n return 'orchestrator';\n}\n\n// ---------------------------------------------------------------------------\n// Box rendering primitives\n// ---------------------------------------------------------------------------\n\n/** Pad or truncate text to exactly `w` display columns */\nfunction padTo(text: string, w: number): string {\n const tw = stringWidth(text);\n if (tw >= w) return truncate(text, w);\n return text + ' '.repeat(w - tw);\n}\n\n/** Build a full-width orchestrator box */\nfunction buildOrchestratorNode(\n cycle: OrchestratorCycle,\n agents: Agent[],\n width: number,\n bright: boolean,\n showConnectorBottom: boolean,\n): DetailLine[] {\n const lines: DetailLine[] = [];\n const inner = width - 2; // inside borders\n const bg = BG_TINTS.yellow;\n const dim = !bright;\n const isRunning = !cycle.completedAt;\n const icon = isRunning ? '●' : '○';\n const cycleLabel = `C${cycle.cycle}`;\n const modeLabel = abbreviateMode(cycle.mode);\n const mColor = modeColor(cycle.mode);\n\n let rightText: string;\n if (isRunning) {\n rightText = 'running';\n } else {\n const dur = formatDuration(cycle.activeMs);\n const time = formatTime(cycle.timestamp);\n rightText = `${dur} ${time}`;\n }\n\n const leftContent = `${icon} ${cycleLabel} ${modeLabel}`;\n const leftW = stringWidth(leftContent);\n const rightW = stringWidth(rightText);\n const gap = Math.max(1, inner - 2 - leftW - rightW);\n\n // Top border\n lines.push([seg('╭' + '─'.repeat(inner) + '╮', { color: 'yellow', dim })]);\n\n // Content row with bg tint\n const contentSegs: Seg[] = [\n seg('│', { color: 'yellow', dim }),\n seg(' ' + icon + ' ', { bg, color: isRunning ? 'green' : undefined, dim: !isRunning && dim, bold: bright }),\n seg(cycleLabel, { bg, dim, bold: bright }),\n seg(' ', { bg }),\n seg(modeLabel, { bg, color: mColor, dim }),\n seg(' '.repeat(gap), { bg }),\n ];\n if (isRunning && bright) {\n contentSegs.push(seg(rightText, { bg, color: 'green', bold: true }));\n } else {\n contentSegs.push(seg(rightText, { bg, dim }));\n }\n contentSegs.push(seg(' ', { bg }));\n // Pad remaining to fill inner width\n const usedWidth = 1 + 1 + 1 + 1 + stringWidth(cycleLabel) + 2 + stringWidth(modeLabel) + gap + stringWidth(rightText) + 1;\n if (usedWidth < inner) {\n contentSegs.push(seg(' '.repeat(inner - usedWidth), { bg }));\n }\n contentSegs.push(seg('│', { color: 'yellow', dim }));\n lines.push(contentSegs);\n\n // Agent summary row\n if (agents.length > 0) {\n const running = agents.filter(a => a.status === 'running').length;\n const done = agents.filter(a => a.status === 'completed').length;\n const failed = agents.filter(a => a.status === 'killed' || a.status === 'crashed').length;\n const parts: Seg[] = [\n seg('│', { color: 'yellow', dim }),\n seg(` ${agents.length} agent${agents.length !== 1 ? 's' : ''}: `, { bg, dim: true }),\n ];\n if (running > 0) parts.push(seg(`${running}▶ `, { bg, color: 'green', dim }));\n if (done > 0) parts.push(seg(`${done}✓ `, { bg, color: 'cyan', dim }));\n if (failed > 0) parts.push(seg(`${failed}✕ `, { bg, color: 'red', dim }));\n // Compute used width for padding\n const labelLen = ` ${agents.length} agent${agents.length !== 1 ? 's' : ''}: `.length;\n const countLen = (running > 0 ? `${running}▶ `.length : 0) + (done > 0 ? `${done}✓ `.length : 0) + (failed > 0 ? `${failed}✕ `.length : 0);\n const remaining = Math.max(0, inner - labelLen - countLen);\n parts.push(seg(' '.repeat(remaining), { bg }));\n parts.push(seg('│', { color: 'yellow', dim }));\n lines.push(parts);\n }\n\n // Bottom border — with or without connector\n if (showConnectorBottom) {\n const mid = Math.floor(inner / 2);\n const left = mid;\n const right = inner - mid - 1;\n lines.push([seg('╰' + '─'.repeat(left) + '┬' + '─'.repeat(right) + '╯', { color: 'yellow', dim })]);\n } else {\n lines.push([seg('╰' + '─'.repeat(inner) + '╯', { color: 'yellow', dim })]);\n }\n\n return lines;\n}\n\n/** Canonical stem column — all vertical connectors use this */\nfunction stemCol(width: number): number {\n return Math.floor(width / 2);\n}\n\n/** Build the vertical connector line between orchestrator and agent branch */\nfunction buildVerticalConnector(width: number, dim: boolean): DetailLine {\n const col = stemCol(width);\n return [\n seg(' '.repeat(col)),\n seg('│', { dim }),\n ];\n}\n\n/** Build horizontal branch connector: ┌────┼────┐ */\nfunction buildBranchConnector(\n boxWidth: number,\n count: number,\n totalWidth: number,\n direction: 'down' | 'up',\n): DetailLine[] {\n if (count === 0) return [];\n const centers = boxCenters(boxWidth, count, totalWidth);\n const mid = stemCol(totalWidth);\n const lineStart = centers[0]!;\n const lineEnd = centers[centers.length - 1]!;\n\n if (count === 1) {\n // Single agent — just a vertical line at center\n return [buildVerticalConnector(totalWidth, false)];\n }\n\n // Build the horizontal branch line\n const row = new Array(totalWidth).fill(' ');\n const upChar = direction === 'down' ? '┬' : '┴';\n const leftCorner = direction === 'down' ? '┌' : '└';\n const rightCorner = direction === 'down' ? '┐' : '┘';\n\n row[lineStart] = leftCorner;\n row[lineEnd] = rightCorner;\n for (let i = lineStart + 1; i < lineEnd; i++) {\n row[i] = '─';\n }\n // Place T-junctions at each box center (overwrite ─)\n row[mid] = '┼';\n for (const c of centers) {\n if (c !== mid && c !== lineStart && c !== lineEnd) {\n row[c] = upChar;\n }\n }\n\n return [[seg(row.join(''), { dim: false })]];\n}\n\n/** Get a short summary for an agent: report excerpt or instruction preview */\nfunction agentSummary(a: Agent, maxW: number): string {\n // Prefer final report summary\n if (a.reports.length > 0) {\n const last = a.reports[a.reports.length - 1]!;\n const prefix = last.type === 'final' ? '↳ ' : '… ';\n return prefix + truncate(last.summary.split('\\n')[0]!, maxW - 2);\n }\n // Fall back to instruction preview\n return truncate(a.instruction.split('\\n')[0]!, maxW);\n}\n\n/**\n * Compute leftPad so the center box's ┴/┬ aligns with stemCol.\n * For odd counts the middle box aligns exactly; for even counts\n * we fall back to simple centering (no single \"middle\" box).\n */\nfunction alignedLeftPad(boxWidth: number, count: number, totalWidth: number): number {\n if (count === 0) return 0;\n const stem = stemCol(totalWidth);\n const midIdx = Math.floor((count - 1) / 2);\n const idealPad = stem - midIdx * boxWidth - Math.floor(boxWidth / 2);\n return Math.max(0, idealPad);\n}\n\n/** Compute box center positions for a row of `count` boxes */\nfunction boxCenters(boxWidth: number, count: number, totalWidth: number): number[] {\n const leftPad = alignedLeftPad(boxWidth, count, totalWidth);\n const centers: number[] = [];\n for (let i = 0; i < count; i++) {\n centers.push(leftPad + i * boxWidth + Math.floor(boxWidth / 2));\n }\n return centers;\n}\n\n/** Build a fan-in line from multiple box-bottom ┬ to a single stem center */\nfunction buildInterRowFanIn(\n prevCenters: number[],\n totalWidth: number,\n): DetailLine[] {\n const mid = stemCol(totalWidth);\n if (prevCenters.length <= 1) {\n // Single box — just vertical at the box center (might differ from stem)\n const col = prevCenters[0] ?? mid;\n if (col === mid) return [buildVerticalConnector(totalWidth, false)];\n // Connect box center to stem\n const row = new Array(totalWidth).fill(' ');\n const left = Math.min(col, mid);\n const right = Math.max(col, mid);\n row[left] = '└';\n row[right] = '┘';\n for (let i = left + 1; i < right; i++) row[i] = '─';\n if (col === left) row[col] = '┴';\n if (col === right) row[col] = '┴';\n row[mid] = mid === left || mid === right ? '┼' : '┼';\n // Overwrite corners that are the stem\n return [[seg(row.join(''))], buildVerticalConnector(totalWidth, false)];\n }\n const lineStart = Math.min(prevCenters[0]!, mid);\n const lineEnd = Math.max(prevCenters[prevCenters.length - 1]!, mid);\n const row = new Array(totalWidth).fill(' ');\n row[lineStart] = '└';\n row[lineEnd] = '┘';\n for (let i = lineStart + 1; i < lineEnd; i++) row[i] = '─';\n row[mid] = '┼';\n for (const c of prevCenters) {\n if (c !== lineStart && c !== lineEnd && c !== mid) row[c] = '┴';\n if (c === lineStart && c !== mid) row[c] = '┴';\n if (c === lineEnd && c !== mid) row[c] = '┴';\n }\n return [[seg(row.join(''))], buildVerticalConnector(totalWidth, false)];\n}\n\n/** Build agent box rows (4 lines per box, max 3 per row) */\nfunction buildAgentBoxRows(\n agents: Agent[],\n boxWidth: number,\n totalWidth: number,\n bright: boolean,\n maxPerRow: number,\n): DetailLine[] {\n const lines: DetailLine[] = [];\n const innerW = boxWidth - 2; // inside left/right border chars\n\n for (let rowStart = 0; rowStart < agents.length; rowStart += maxPerRow) {\n const rowAgents = agents.slice(rowStart, rowStart + maxPerRow);\n const count = rowAgents.length;\n const leftPad = alignedLeftPad(boxWidth, count, totalWidth);\n const isFirstRow = rowStart === 0;\n\n // Inter-row connector: fan-in from previous row → stem → fan-out to this row\n if (!isFirstRow) {\n const prevCount = Math.min(agents.length - (rowStart - maxPerRow), maxPerRow);\n const prevCents = boxCenters(boxWidth, prevCount, totalWidth);\n lines.push(...buildInterRowFanIn(prevCents, totalWidth));\n // Fan-out from stem to this row's boxes\n if (count > 1) {\n lines.push(...buildBranchConnector(boxWidth, count, totalWidth, 'down'));\n } else {\n lines.push(buildVerticalConnector(totalWidth, false));\n }\n }\n\n // Top borders with ┴ connector (first row gets ┴ from branch above, subsequent rows from inter-row fan-out)\n const topSegs: Seg[] = [];\n if (leftPad > 0) topSegs.push(seg(' '.repeat(leftPad)));\n for (let i = 0; i < count; i++) {\n const a = rowAgents[i]!;\n const isError = a.status === 'killed' || a.status === 'crashed';\n const borderColor = isError ? 'red' : resolveColor(a.color);\n const dim = !bright;\n\n const mid = Math.floor(innerW / 2);\n topSegs.push(seg('╭' + '─'.repeat(mid) + '┴' + '─'.repeat(innerW - mid - 1) + '╮', { color: borderColor, dim }));\n }\n lines.push(topSegs);\n\n // Line 1: colored icon + agent id\n const line1Segs: Seg[] = [];\n if (leftPad > 0) line1Segs.push(seg(' '.repeat(leftPad)));\n for (const a of rowAgents) {\n const isError = a.status === 'killed' || a.status === 'crashed';\n const borderColor = isError ? 'red' : resolveColor(a.color);\n const agentBg = BG_TINTS[isError ? 'red' : resolveColor(a.color)] ?? BG_TINTS.gray;\n const dim = !bright;\n const icon = agentStatusIcon(a.status);\n const iconColor = statusColor(a.status);\n const idPadded = padTo(` ${a.id}`, innerW - stringWidth(icon));\n line1Segs.push(seg('│', { color: borderColor, dim }));\n line1Segs.push(seg(icon, { bg: agentBg, color: iconColor, bold: bright }));\n line1Segs.push(seg(idPadded, { bg: agentBg, dim, bold: bright && a.status === 'running' }));\n line1Segs.push(seg('│', { color: borderColor, dim }));\n }\n lines.push(line1Segs);\n\n // Line 2: agent display name\n const line2Segs: Seg[] = [];\n if (leftPad > 0) line2Segs.push(seg(' '.repeat(leftPad)));\n for (const a of rowAgents) {\n const isError = a.status === 'killed' || a.status === 'crashed';\n const borderColor = isError ? 'red' : resolveColor(a.color);\n const agentBg = BG_TINTS[isError ? 'red' : resolveColor(a.color)] ?? BG_TINTS.gray;\n const dim = !bright;\n const name = padTo(agentDisplayName(a), innerW);\n line2Segs.push(seg('│', { color: borderColor, dim }));\n line2Segs.push(seg(name, { bg: agentBg, dim }));\n line2Segs.push(seg('│', { color: borderColor, dim }));\n }\n lines.push(line2Segs);\n\n // Line 3: colored duration + status tag for errors\n const line3Segs: Seg[] = [];\n if (leftPad > 0) line3Segs.push(seg(' '.repeat(leftPad)));\n for (const a of rowAgents) {\n const isError = a.status === 'killed' || a.status === 'crashed';\n const borderColor = isError ? 'red' : resolveColor(a.color);\n const agentBg = BG_TINTS[isError ? 'red' : resolveColor(a.color)] ?? BG_TINTS.gray;\n const dim = !bright;\n const dur = formatDuration(a.activeMs);\n const durClr = isError ? 'red' : (durationColor(a.activeMs) || undefined);\n let durText: string;\n if (isError) {\n const tag = a.status === 'killed' ? '✕ kill' : '✕ crash';\n durText = padTo(`${dur} ${tag}`, innerW);\n } else if (a.status === 'completed') {\n durText = padTo(`${dur} ✓`, innerW);\n } else {\n durText = padTo(dur, innerW);\n }\n line3Segs.push(seg('│', { color: borderColor, dim }));\n line3Segs.push(seg(durText, { bg: agentBg, dim, color: durClr }));\n line3Segs.push(seg('│', { color: borderColor, dim }));\n }\n lines.push(line3Segs);\n\n // Line 4: instruction preview or report summary (dim)\n const line4Segs: Seg[] = [];\n if (leftPad > 0) line4Segs.push(seg(' '.repeat(leftPad)));\n for (const a of rowAgents) {\n const isError = a.status === 'killed' || a.status === 'crashed';\n const borderColor = isError ? 'red' : resolveColor(a.color);\n const agentBg = BG_TINTS[isError ? 'red' : resolveColor(a.color)] ?? BG_TINTS.gray;\n const dim = !bright;\n const summary = padTo(agentSummary(a, innerW), innerW);\n line4Segs.push(seg('│', { color: borderColor, dim }));\n line4Segs.push(seg(summary, { bg: agentBg, dim: true }));\n line4Segs.push(seg('│', { color: borderColor, dim }));\n }\n lines.push(line4Segs);\n\n // Bottom borders with ┬ connector\n const botSegs: Seg[] = [];\n if (leftPad > 0) botSegs.push(seg(' '.repeat(leftPad)));\n for (const a of rowAgents) {\n const isError = a.status === 'killed' || a.status === 'crashed';\n const borderColor = isError ? 'red' : resolveColor(a.color);\n const dim = !bright;\n const mid = Math.floor(innerW / 2);\n const left = mid;\n const right = innerW - mid - 1;\n botSegs.push(seg('╰' + '─'.repeat(left) + '┬' + '─'.repeat(right) + '╯', { color: borderColor, dim }));\n }\n lines.push(botSegs);\n }\n\n return lines;\n}\n\n/** Build fan-in merge connector below agent boxes */\nfunction buildFanInConnector(\n boxWidth: number,\n count: number,\n totalWidth: number,\n): DetailLine[] {\n if (count <= 1) {\n // Single agent — just vertical line\n return [buildVerticalConnector(totalWidth, false)];\n }\n\n const centers = boxCenters(boxWidth, count, totalWidth);\n const lineStart = centers[0]!;\n const lineEnd = centers[centers.length - 1]!;\n const mid = stemCol(totalWidth);\n\n const row = new Array(totalWidth).fill(' ');\n // Extend horizontal line to include stem if it's outside the box cluster\n const hStart = Math.min(lineStart, mid);\n const hEnd = Math.max(lineEnd, mid);\n row[hStart] = '└';\n row[hEnd] = '┘';\n for (let i = hStart + 1; i < hEnd; i++) {\n row[i] = '─';\n }\n row[mid] = '┼';\n // Box centers become ┴\n for (const c of centers) {\n if (c !== mid && c !== hStart && c !== hEnd) {\n row[c] = '┴';\n }\n // Corner chars that coincide with a box center\n if (c === hStart && c !== mid) row[c] = '┴';\n if (c === hEnd && c !== mid) row[c] = '┴';\n }\n\n const result: DetailLine[] = [];\n result.push([seg(row.join(''))]);\n // Vertical line down from merge point\n const vRow = new Array(totalWidth).fill(' ');\n vRow[mid] = '│';\n result.push([seg(vRow.join(''))]);\n\n return result;\n}\n\n/** Build yield prompt node (solid when known, dashed when unknown) */\nfunction buildYieldNode(\n prompt: string | undefined,\n width: number,\n bright: boolean,\n known: boolean,\n): DetailLine[] {\n const lines: DetailLine[] = [];\n const inner = width - 2;\n const bg = BG_TINTS.gray;\n const dim = !bright;\n\n if (known && prompt) {\n // Solid border, yellow\n lines.push([seg('╭' + '─'.repeat(inner) + '╮', { color: 'yellow', dim })]);\n const wrapped = wrapText(prompt, inner - 2);\n for (const wl of wrapped) {\n const padded = padTo(' ' + wl, inner);\n lines.push([\n seg('│', { color: 'yellow', dim }),\n seg(padded, { bg, dim: true }),\n seg('│', { color: 'yellow', dim }),\n ]);\n }\n lines.push([seg('╰' + '─'.repeat(inner) + '╯', { color: 'yellow', dim })]);\n } else {\n // Dim placeholder with solid borders\n lines.push([seg('╭' + '─'.repeat(inner) + '╮', { dim: true })]);\n const placeholder = padTo(' awaiting agents…', inner);\n lines.push([seg('│', { dim: true }), seg(placeholder, { bg, dim: true }), seg('│', { dim: true })]);\n lines.push([seg('╰' + '─'.repeat(inner) + '╯', { dim: true })]);\n }\n\n return lines;\n}\n\n/** Build the complete node (terminal state) */\nfunction buildCompleteNode(session: Session, width: number): DetailLine[] {\n const inner = width - 2;\n const dur = formatDuration(session.activeMs);\n const totalAgents = session.agents.length;\n const completed = session.agents.filter(a => a.status === 'completed').length;\n const crashed = session.agents.filter(a => a.status === 'crashed' || a.status === 'killed').length;\n const cycles = session.orchestratorCycles.length;\n\n const leftText = '◉ complete';\n const rightText = `${dur} total`;\n const gap = Math.max(1, inner - 2 - stringWidth(leftText) - stringWidth(rightText));\n\n // Summary line: \"6 cycles · 12 agents (10 ok, 2 failed)\"\n let summaryParts = `${cycles} cycle${cycles !== 1 ? 's' : ''} · ${totalAgents} agent${totalAgents !== 1 ? 's' : ''}`;\n if (totalAgents > 0) {\n const parts: string[] = [];\n if (completed > 0) parts.push(`${completed} ok`);\n if (crashed > 0) parts.push(`${crashed} failed`);\n if (parts.length > 0) summaryParts += ` (${parts.join(', ')})`;\n }\n const summaryLine = padTo(' ' + summaryParts, inner);\n\n return [\n [seg('╭' + '─'.repeat(inner) + '╮', { color: 'cyan', bold: true })],\n [\n seg('│', { color: 'cyan', bold: true }),\n seg(' ' + leftText, { bold: true }),\n seg(' '.repeat(gap)),\n seg(rightText, { dim: true }),\n seg(' ', {}),\n seg('│', { color: 'cyan', bold: true }),\n ],\n [\n seg('│', { color: 'cyan', bold: true }),\n seg(summaryLine, { dim: true }),\n seg('│', { color: 'cyan', bold: true }),\n ],\n [seg('╰' + '─'.repeat(inner) + '╯', { color: 'cyan', bold: true })],\n ];\n}\n\n/** Build a dim placeholder orchestrator (next phase) */\nfunction buildDottedOrchestratorPlaceholder(width: number): DetailLine[] {\n const inner = width - 2;\n const placeholder = padTo(' spawning orchestrator…', inner);\n return [\n [seg('╭' + '─'.repeat(inner) + '╮', { dim: true })],\n [seg('│', { dim: true }), seg(placeholder, { bg: BG_TINTS.yellow, dim: true }), seg('│', { dim: true })],\n [seg('╰' + '─'.repeat(inner) + '╯', { dim: true })],\n ];\n}\n\n/** Build a dim placeholder agent box row */\nfunction buildDottedAgentPlaceholder(width: number): DetailLine[] {\n const inner = width - 2;\n const placeholder = padTo(' awaiting orchestrator…', inner);\n return [\n [seg('╭' + '─'.repeat(inner) + '╮', { dim: true })],\n [seg('│', { dim: true }), seg(placeholder, { bg: BG_TINTS.blue, dim: true }), seg('│', { dim: true })],\n [seg('╰' + '─'.repeat(inner) + '╯', { dim: true })],\n ];\n}\n\n// ---------------------------------------------------------------------------\n// Render a single cycle's flow (orchestrator → agents → yield)\n// ---------------------------------------------------------------------------\n\nfunction renderCycleFlow(\n session: Session,\n cycle: OrchestratorCycle,\n prevCycle: OrchestratorCycle | undefined,\n width: number,\n phase: Phase,\n isCurrentCycle: boolean,\n isPrevCycle: boolean,\n): DetailLine[] {\n const lines: DetailLine[] = [];\n const cycleAgents = session.agents.filter(a => cycle.agentsSpawned.includes(a.id));\n const maxPerRow = 3;\n const boxWidth = Math.max(12, Math.floor((width - 4) / maxPerRow));\n const firstRowCount = Math.min(cycleAgents.length, maxPerRow);\n const lastRowCount = cycleAgents.length > 0 ? ((cycleAgents.length - 1) % maxPerRow) + 1 : 0;\n\n // Determine brightness for each section\n let orchBright = false;\n let agentsBright = false;\n let yieldBright = false;\n\n if (isCurrentCycle) {\n if (phase === 'orchestrator') orchBright = true;\n else if (phase === 'agents') agentsBright = true;\n else if (phase === 'between') yieldBright = true;\n }\n // Previous cycle: everything dim (default false is fine)\n\n const showAgents = cycleAgents.length > 0;\n const hasConnectorFromOrch = showAgents;\n\n // Orchestrator node\n lines.push(...buildOrchestratorNode(cycle, cycleAgents, width, orchBright, hasConnectorFromOrch));\n\n if (showAgents) {\n // Vertical connector\n lines.push(buildVerticalConnector(width, !agentsBright));\n\n // Fan-out branch\n if (firstRowCount > 1) {\n lines.push(...buildBranchConnector(boxWidth, firstRowCount, width, 'down'));\n }\n\n // Agent boxes\n lines.push(...buildAgentBoxRows(cycleAgents, boxWidth, width, agentsBright, maxPerRow));\n\n // Fan-in merge (from last row's boxes)\n lines.push(...buildFanInConnector(boxWidth, lastRowCount, width));\n } else if (hasConnectorFromOrch) {\n lines.push(buildVerticalConnector(width, true));\n }\n\n // Yield prompt\n const yieldKnown = !!cycle.nextPrompt;\n if (yieldKnown || isCurrentCycle) {\n lines.push(...buildYieldNode(\n cycle.nextPrompt,\n width,\n yieldBright,\n yieldKnown,\n ));\n }\n\n return lines;\n}\n\n// ---------------------------------------------------------------------------\n// Main export\n// ---------------------------------------------------------------------------\n\nexport function buildCycleFlowLines(\n session: Session,\n width: number,\n expanded: boolean,\n): DetailLine[] {\n const lines: DetailLine[] = [];\n const cycles = session.orchestratorCycles;\n const phase = getCurrentPhase(session);\n const maxPerRow = 3;\n const boxWidth = Math.max(12, Math.floor((width - 4) / maxPerRow));\n const firstRowAgentCount = (c: OrchestratorCycle) => {\n const agents = session.agents.filter(a => c.agentsSpawned.includes(a.id));\n return Math.min(agents.length, maxPerRow);\n };\n const lastRowAgentCount = (c: OrchestratorCycle) => {\n const count = session.agents.filter(a => c.agentsSpawned.includes(a.id)).length;\n return count > 0 ? ((count - 1) % maxPerRow) + 1 : 0;\n };\n\n // Header\n lines.push([\n seg(' ▎ ◈ CYCLE FLOW', { color: 'blue', bold: true }),\n seg(expanded ? ' [F] collapse' : ' [F] full', { dim: true }),\n ]);\n lines.push(singleLine(' '));\n\n if (cycles.length === 0) {\n // First cycle, orchestrator hasn't started yet\n lines.push(singleLine(' waiting for orchestrator…', { dim: true, italic: true }));\n return lines;\n }\n\n if (expanded) {\n // Show all cycles, older ones dimmer\n for (let i = 0; i < cycles.length; i++) {\n const cycle = cycles[i]!;\n const prevCycle = i > 0 ? cycles[i - 1] : undefined;\n const isLast = i === cycles.length - 1;\n\n const cycleLines = renderCycleFlow(\n session, cycle, prevCycle, width, phase, isLast, !isLast,\n );\n\n // Apply extra dim to older cycles\n if (!isLast) {\n for (const line of cycleLines) {\n for (const s of line) {\n s.dim = true;\n }\n }\n }\n\n lines.push(...cycleLines);\n\n if (!isLast) {\n lines.push(singleLine(' '));\n }\n }\n } else {\n // 3-phase sliding window\n const currentCycle = cycles[cycles.length - 1]!;\n const prevCycle = cycles.length >= 2 ? cycles[cycles.length - 2] : undefined;\n const currentAgents = session.agents.filter(a => currentCycle.agentsSpawned.includes(a.id));\n\n // Previous phase (dim)\n if (phase === 'agents' && currentCycle) {\n // Previous = orchestrator (dim)\n lines.push(...buildOrchestratorNode(currentCycle, currentAgents, width, false, true));\n lines.push(buildVerticalConnector(width, true));\n if (firstRowAgentCount(currentCycle) > 1) {\n const dimBranch = buildBranchConnector(boxWidth, firstRowAgentCount(currentCycle), width, 'down');\n for (const line of dimBranch) {\n for (const s of line) s.dim = true;\n }\n lines.push(...dimBranch);\n }\n } else if (phase === 'orchestrator' && prevCycle) {\n // Previous = yield prompt from prev cycle (dim)\n if (prevCycle.nextPrompt) {\n lines.push(...buildYieldNode(prevCycle.nextPrompt, width, false, true));\n lines.push(singleLine(' '));\n }\n } else if (phase === 'between') {\n // Previous = agent boxes (slightly dim)\n if (currentAgents.length > 0) {\n lines.push(...buildAgentBoxRows(currentAgents, boxWidth, width, false, maxPerRow));\n lines.push(...buildFanInConnector(boxWidth, lastRowAgentCount(currentCycle), width));\n }\n }\n\n // Current phase (bright)\n if (phase === 'orchestrator') {\n lines.push(...buildOrchestratorNode(currentCycle, currentAgents, width, true, false));\n } else if (phase === 'agents') {\n // Agent boxes bright\n lines.push(...buildAgentBoxRows(currentAgents, boxWidth, width, true, maxPerRow));\n lines.push(...buildFanInConnector(boxWidth, lastRowAgentCount(currentCycle), width));\n } else if (phase === 'between') {\n // Yield prompt bright\n lines.push(...buildYieldNode(currentCycle.nextPrompt, width, true, true));\n } else if (phase === 'complete') {\n // Previous = last agents dim\n if (currentAgents.length > 0) {\n lines.push(...buildAgentBoxRows(currentAgents, boxWidth, width, false, maxPerRow));\n lines.push(...buildFanInConnector(boxWidth, lastRowAgentCount(currentCycle), width));\n }\n // Complete node bright\n lines.push(...buildCompleteNode(session, width));\n }\n\n // Next phase (dotted/planned)\n if (phase === 'agents') {\n lines.push(...buildYieldNode(undefined, width, false, false));\n } else if (phase === 'orchestrator') {\n lines.push(singleLine(' '));\n lines.push(...buildDottedAgentPlaceholder(width));\n } else if (phase === 'between') {\n lines.push(singleLine(' '));\n lines.push(...buildDottedOrchestratorPlaceholder(width));\n }\n // 'complete' has no next phase\n }\n\n return lines;\n}\n","import type { AskStatus, InteractionKind } from './types.js';\n\nexport type { InteractionKind as InboxItemKind };\n\nexport function coerceKind(k: InteractionKind | undefined): InteractionKind {\n if (k !== undefined) return k;\n return 'validation';\n}\n\nexport interface AggregateInboxItem {\n sessionId: string;\n sessionName?: string;\n cwd: string;\n askId: string;\n askedBy: string;\n askedAt: string;\n status: AskStatus;\n blocking: boolean;\n orphaned?: boolean;\n title?: string;\n subtitle?: string;\n blockedSince: string;\n kind?: InteractionKind;\n}\n","/**\n * Stacked g/s/r detail panel (3b).\n *\n * Renders goal/strategy/roadmap content as three vertically-stacked strips,\n * or a single cycle-log strip when state.detailMode === 'cycle-log'.\n *\n * Extension point (3d): when cursor is on the virtual `Needs You` tree node,\n * extend `state.detailMode` to `'gsr' | 'cycle-log' | 'inbox'` and dispatch\n * to an inbox view from `renderStackedDetailRows`.\n *\n * Extension point (deferred Q5): wire [/] in `renderCycleLogMode` to walk\n * state.logsCycles by index instead of always showing the latest.\n */\n\nimport {\n buildEmptyPanelRows,\n buildPanelRows,\n clipAnsi,\n colorToSGR,\n renderLine,\n type Rect,\n} from '../render.js';\nimport type { AppState, ThrottledScroll } from '../state.js';\nimport type { DetailContext } from './detail.js';\nimport { buildLogsLines } from './detail.js';\nimport {\n type DetailLine,\n} from '../lib/format.js';\nimport { buildHighlightedMarkdownLines } from '../lib/markdown-highlight.js';\n\nconst HEADERS_ACTIVE = {\n top: 'GOAL',\n middle: 'STRATEGY',\n bottom: 'ROADMAP',\n};\n\nconst HEADERS_DONE = {\n top: 'GOAL',\n middle: 'COMPLETION',\n bottom: 'SUMMARY',\n};\n\nexport function renderStackedDetailRows(\n rect: Rect,\n state: AppState,\n detailCtx: DetailContext,\n): string[] {\n const focused = state.focusPane === 'detail';\n const { w, h } = rect;\n const innerW = w - 4;\n\n const cursorNode = detailCtx.nodes[state.cursorIndex];\n if (!cursorNode || !state.selectedSession || cursorNode.sessionId !== state.selectedSession.id) {\n return buildEmptyPanelRows(rect, focused, 'gray', '\\x1b[2mSelect a session\\x1b[0m');\n }\n\n if (state.detailMode === 'cycle-log') {\n return renderCycleLogMode(rect, state, focused);\n }\n\n const session = state.selectedSession;\n const isDone = session.status === 'completed';\n const headers = isDone ? HEADERS_DONE : HEADERS_ACTIVE;\n\n const middleContent = isDone\n ? buildCompletionContent(session)\n : state.strategyContent;\n const bottomContent = isDone\n ? pickSummaryContent(state)\n : state.planContent;\n\n const cacheKey = [\n cursorNode.sessionId,\n rect.w,\n isDone ? 'done' : 'active',\n state.goalContent.length,\n middleContent.length,\n bottomContent.length,\n ].join(':');\n\n let lines = state.cachedStackedLines;\n if (cacheKey !== state.stackedCacheKey || lines === null) {\n lines = {\n goal: buildSectionLines(state.goalContent, innerW),\n strategy: buildSectionLines(middleContent, innerW),\n roadmap: buildSectionLines(bottomContent, innerW),\n cycleLog: [],\n };\n state.cachedStackedLines = lines;\n state.stackedCacheKey = cacheKey;\n }\n\n const heights = allocateStripHeights(h, lines.goal.length, lines.strategy.length, lines.roadmap.length);\n\n const rows = new Array<string>(h);\n const focusColor = focused ? 'cyan' : 'gray';\n const sgr = `\\x1b[${colorToSGR(focusColor)}m`;\n const reset = '\\x1b[0m';\n rows[0] = sgr + '╭' + '─'.repeat(w - 2) + '╮' + reset;\n rows[h - 1] = sgr + '╰' + '─'.repeat(w - 2) + '╯' + reset;\n\n let cursor = 1;\n cursor = paintStrip(rows, cursor, w, sgr, reset, headers.top, lines.goal,\n state.goalScroll, heights.goalHeight, state.focusedStrip === 'goal' && focused);\n rows[cursor++] = sgr + '├' + '─'.repeat(w - 2) + '┤' + reset;\n cursor = paintStrip(rows, cursor, w, sgr, reset, headers.middle, lines.strategy,\n state.strategyScroll, heights.stratHeight, state.focusedStrip === 'strategy' && focused);\n rows[cursor++] = sgr + '├' + '─'.repeat(w - 2) + '┤' + reset;\n paintStrip(rows, cursor, w, sgr, reset, headers.bottom, lines.roadmap,\n state.roadmapScroll, heights.roadHeight, state.focusedStrip === 'roadmap' && focused);\n\n return rows;\n}\n\nfunction buildCompletionContent(session: import('../../shared/types.js').Session): string {\n const parts: string[] = [];\n if (session.completedAt) {\n parts.push(`*completed ${formatTimestamp(session.completedAt)}*`);\n parts.push('');\n }\n if (session.completionReport && session.completionReport.trim()) {\n parts.push(session.completionReport.trim());\n } else {\n parts.push('_No completion report written._');\n }\n return parts.join('\\n');\n}\n\nfunction pickSummaryContent(state: AppState): string {\n if (state.completionSummaryContent.trim()) return state.completionSummaryContent;\n if (state.logsCycles.length > 0) {\n const last = state.logsCycles[state.logsCycles.length - 1]!;\n return `# Cycle ${last.cycle} log\\n\\n${last.content}`;\n }\n if (state.strategyContent.trim()) return state.strategyContent;\n return '_No completion artifacts. Try expanding context/ in the tree for raw files._';\n}\n\nfunction formatTimestamp(iso: string): string {\n try {\n const d = new Date(iso);\n if (isNaN(d.getTime())) return iso;\n return d.toLocaleString();\n } catch {\n return iso;\n }\n}\n\n// --- helpers ---\n\nfunction buildSectionLines(content: string, innerW: number): DetailLine[] {\n return buildHighlightedMarkdownLines(content, innerW);\n}\n\nfunction allocateStripHeights(rectH: number, gN: number, sN: number, _rN: number) {\n const innerH = rectH - 2;\n const stripsAvail = innerH - 2; // two separator rows\n const goalCap = Math.floor(stripsAvail * 0.20);\n const stratCap = Math.floor(stripsAvail * 0.40);\n const roadCap = stripsAvail - goalCap - stratCap;\n const goalNeed = Math.min(gN + 1, goalCap);\n const stratNeed = Math.min(sN + 1, stratCap);\n const slack = (goalCap - goalNeed) + (stratCap - stratNeed);\n return {\n goalHeight: Math.max(2, goalNeed),\n stratHeight: Math.max(2, stratNeed),\n roadHeight: Math.max(2, roadCap + slack),\n };\n}\n\nfunction paintStrip(\n rows: string[], startRow: number, w: number, sgr: string, reset: string,\n label: string,\n lines: DetailLine[], scroll: ThrottledScroll, height: number, focused: boolean,\n): number {\n const innerW = w - 4;\n const borderL = sgr + '│' + reset + ' ';\n const borderR = ' ' + sgr + '│' + reset;\n\n const headerSeg = `\\x1b[${colorToSGR('yellow')};1m ▎ ${label}\\x1b[0m`;\n const headerClipped = clipAnsi(headerSeg + (focused ? ' ◀' : ''), innerW);\n rows[startRow] = borderL + headerClipped + borderR;\n\n const contentH = height - 1;\n const hasOverflow = lines.length > contentH;\n const viewableH = hasOverflow ? contentH - 1 : contentH;\n const maxScroll = Math.max(0, lines.length - viewableH);\n scroll.setMax(maxScroll);\n const effOffset = scroll.offset;\n\n for (let i = 0; i < viewableH; i++) {\n const li = effOffset + i;\n const ansi = li < lines.length ? renderLine(lines[li]!) : '';\n rows[startRow + 1 + i] = borderL + clipAnsi(ansi, innerW) + borderR;\n }\n if (hasOverflow) {\n const pct = maxScroll > 0 ? Math.round((effOffset / maxScroll) * 100) : 100;\n const indicator = `\\x1b[2m ↕ ${pct}% · ${lines.length} lines\\x1b[0m`;\n rows[startRow + 1 + viewableH] = borderL + clipAnsi(indicator, innerW) + borderR;\n }\n return startRow + height;\n}\n\nfunction renderCycleLogMode(rect: Rect, state: AppState, focused: boolean): string[] {\n // Extension point (deferred Q5): wire [/] to walk state.logsCycles by index instead of latest.\n if (state.logsCycles.length === 0) {\n return buildEmptyPanelRows(rect, focused, 'gray', '\\x1b[2mNo cycle logs yet\\x1b[0m');\n }\n const cacheKey = `cycleLog:${state.logsCycles.length}:${rect.w}`;\n let lines: DetailLine[];\n if (cacheKey === state.stackedCacheKey && state.cachedStackedLines !== null) {\n lines = state.cachedStackedLines.cycleLog;\n } else {\n lines = buildLogsLines(state.logsCycles, rect.w);\n const existing = state.cachedStackedLines ?? { goal: [], strategy: [], roadmap: [], cycleLog: [] };\n state.cachedStackedLines = { ...existing, cycleLog: lines };\n state.stackedCacheKey = cacheKey;\n }\n return buildPanelRows(rect, lines, state.detailScroll, focused, 'cyan', state.stackedRenderedCache);\n}\n","/**\n * Gloam-themed markdown highlighter for goal/strategy/roadmap strips.\n *\n * Pure-JS pass that converts markdown text into `DetailLine[]` ready for\n * `renderLine`. Headings get full-width tinted backgrounds (h1 orange →\n * h6 surface gray) with brighter foregrounds; lists, checkboxes, code,\n * blockquotes, and inline emphasis (bold/italic/code/link/strikethrough)\n * get their own styling.\n *\n * The output is sized to `innerW`: heading lines are padded with bg-painted\n * spaces so the tint fills the full strip width when rendered.\n */\n\nimport stringWidth from 'string-width';\nimport { GLOAM } from './gloam.js';\nimport { cleanMarkdown, stripFrontmatter, type DetailLine, type Seg } from './format.js';\n\n// ─── Heading styles by level ───────────────────────────────────────────────\n\ninterface HeadingStyle {\n /** Heading text foreground (the title itself) */\n textFg: string;\n /** Marker (`#…`) foreground — slightly muted vs. text */\n markerFg: string;\n /** Tinted background painted across the full row */\n bg: string;\n}\n\nconst HEADING_STYLES: HeadingStyle[] = [\n { textFg: GLOAM.bright_orange, markerFg: GLOAM.orange, bg: GLOAM.bg_dim_orange }, // h1\n { textFg: GLOAM.bright_yellow, markerFg: GLOAM.yellow, bg: GLOAM.bg_dim_yellow }, // h2\n { textFg: GLOAM.bright_green, markerFg: GLOAM.green, bg: GLOAM.bg_dim_green }, // h3\n { textFg: GLOAM.bright_blue, markerFg: GLOAM.blue, bg: GLOAM.bg_dim_blue }, // h4\n { textFg: GLOAM.bright_purple, markerFg: GLOAM.purple, bg: GLOAM.bg_dim_purple }, // h5\n { textFg: GLOAM.fg2, markerFg: GLOAM.fg3, bg: GLOAM.bg_bg1 }, // h6\n];\n\n// ─── Display-hazard cleanup ────────────────────────────────────────────────\n// Mirrors `cleanMarkdown`'s emoji-handling without touching markdown syntax.\n\nfunction stripDisplayHazards(s: string): string {\n return s\n .replace(/✅/g, '✓')\n .replace(/❌/g, '✗')\n .replace(/\\p{Emoji_Presentation}/gu, '');\n}\n\n// ─── Inline emphasis tokenizer ─────────────────────────────────────────────\n\ninterface InlineSpan {\n start: number;\n end: number;\n kind: 'bold' | 'italic' | 'code' | 'strike' | 'link';\n /** rendered display text for the span (markers stripped) */\n text: string;\n}\n\nconst INLINE_RE =\n /\\*\\*([^*\\n]+)\\*\\*|__([^_\\n]+)__|\\*([^*\\n]+)\\*|_([^_\\n]+)_|`([^`\\n]+)`|~~([^~\\n]+)~~|\\[([^\\]\\n]+)\\]\\(([^)\\n]+)\\)/g;\n\nfunction tokenizeInline(line: string, baseFg: string, baseStyle?: Partial<Seg>): Seg[] {\n const out: Seg[] = [];\n const baseSeg = (text: string): Seg => ({ text, fg: baseFg, ...baseStyle });\n\n let cursor = 0;\n for (const m of line.matchAll(INLINE_RE)) {\n const idx = m.index!;\n if (idx > cursor) out.push(baseSeg(line.slice(cursor, idx)));\n\n if (m[1] !== undefined) {\n out.push({ text: m[1], fg: GLOAM.fg0, bold: true, bg: baseStyle?.bg });\n } else if (m[2] !== undefined) {\n out.push({ text: m[2], fg: GLOAM.fg0, bold: true, bg: baseStyle?.bg });\n } else if (m[3] !== undefined) {\n out.push({ text: m[3], fg: GLOAM.fg0, italic: true, bg: baseStyle?.bg });\n } else if (m[4] !== undefined) {\n out.push({ text: m[4], fg: GLOAM.fg0, italic: true, bg: baseStyle?.bg });\n } else if (m[5] !== undefined) {\n // Inline code — aqua fg, subtle bg1 tint (skip when inside heading bg)\n out.push({\n text: m[5],\n fg: GLOAM.aqua,\n bg: baseStyle?.bg ?? GLOAM.bg_bg1,\n });\n } else if (m[6] !== undefined) {\n out.push({ text: m[6], fg: GLOAM.fg3, strikethrough: true, bg: baseStyle?.bg });\n } else if (m[7] !== undefined && m[8] !== undefined) {\n out.push({ text: m[7], fg: GLOAM.blue, bold: true, bg: baseStyle?.bg });\n }\n\n cursor = idx + m[0].length;\n }\n if (cursor < line.length) out.push(baseSeg(line.slice(cursor)));\n if (out.length === 0) out.push(baseSeg(''));\n return out;\n}\n\n// ─── Plain-text width (sums Seg.text display widths) ───────────────────────\n\nfunction segsDisplayWidth(segs: Seg[]): number {\n let w = 0;\n for (const s of segs) w += stringWidth(s.text);\n return w;\n}\n\n// ─── Soft-wrap a pre-tokenized line to width ───────────────────────────────\n// Tokenizes input segs into word/space atoms (preserving each char's style),\n// then greedy-packs atoms onto lines. Word boundaries are respected even when\n// they straddle segment boundaries (e.g. \" guard around\" spilling out of a\n// preceding inline-code span). Continuation lines get a plain-space indent.\n\ninterface Atom {\n text: string;\n width: number;\n style: Omit<Seg, 'text'>;\n /** true → atom is a run of spaces (collapsible at line boundaries) */\n space: boolean;\n}\n\nfunction segsToAtoms(segs: Seg[]): Atom[] {\n const atoms: Atom[] = [];\n for (const s of segs) {\n if (!s.text) continue;\n const { text, ...style } = s;\n // Split on whitespace boundaries: every run of spaces becomes a `space`\n // atom; every non-space run becomes a word atom.\n const re = /(\\s+|\\S+)/g;\n for (const m of text.matchAll(re)) {\n const piece = m[0];\n atoms.push({\n text: piece,\n width: stringWidth(piece),\n style,\n space: /^\\s+$/.test(piece),\n });\n }\n }\n return atoms;\n}\n\nfunction wrapSegs(segs: Seg[], width: number, contIndent: string): DetailLine[] {\n if (width <= 0) return [segs];\n const atoms = segsToAtoms(segs);\n if (atoms.length === 0) return [[{ text: '' }]];\n\n const lines: DetailLine[] = [];\n let current: Seg[] = [];\n let currentWidth = 0;\n\n const pushAtom = (a: Atom) => {\n current.push({ ...a.style, text: a.text });\n currentWidth += a.width;\n };\n const flushLine = () => {\n // Trim trailing pure-space segs (cosmetic: tinted/colored trailing space\n // can leak across the right border when bg-painted, so prefer cleaner\n // breaks). Heading lines never reach here — they bypass wrapping.\n while (current.length > 0) {\n const last = current[current.length - 1]!;\n if (/^\\s+$/.test(last.text) && !last.bg) {\n currentWidth -= stringWidth(last.text);\n current.pop();\n } else break;\n }\n lines.push(current.length > 0 ? current : [{ text: '' }]);\n current = [];\n currentWidth = 0;\n };\n\n for (let i = 0; i < atoms.length; i++) {\n const atom = atoms[i]!;\n\n if (atom.space) {\n // Spaces that overflow the right edge are dropped at the wrap boundary\n // — flushLine() will trim non-bg trailing whitespace anyway. Leading\n // spaces (line-start indent on the first body line) are preserved.\n if (currentWidth + atom.width <= width) pushAtom(atom);\n continue;\n }\n\n // Word atom\n if (atom.width > width) {\n // Word wider than full line → hard-break it on character boundaries.\n let remaining = atom.text;\n while (remaining.length > 0) {\n const spaceLeft = width - currentWidth;\n if (spaceLeft <= 0) {\n flushLine();\n if (contIndent) {\n current.push({ text: contIndent });\n currentWidth = stringWidth(contIndent);\n }\n continue;\n }\n let cut = 0;\n let cutW = 0;\n for (let k = 0; k < remaining.length; k++) {\n const cw = stringWidth(remaining[k]!);\n if (cutW + cw > spaceLeft) break;\n cutW += cw;\n cut = k + 1;\n }\n if (cut === 0) {\n flushLine();\n if (contIndent) {\n current.push({ text: contIndent });\n currentWidth = stringWidth(contIndent);\n }\n continue;\n }\n current.push({ ...atom.style, text: remaining.slice(0, cut) });\n currentWidth += cutW;\n remaining = remaining.slice(cut);\n if (remaining.length > 0) {\n flushLine();\n if (contIndent) {\n current.push({ text: contIndent });\n currentWidth = stringWidth(contIndent);\n }\n }\n }\n continue;\n }\n\n if (currentWidth + atom.width > width) {\n flushLine();\n if (contIndent) {\n current.push({ text: contIndent });\n currentWidth = stringWidth(contIndent);\n }\n }\n pushAtom(atom);\n }\n flushLine();\n return lines.length > 0 ? lines : [[{ text: '' }]];\n}\n\n// ─── Heading rendering — full-width bg-padded ──────────────────────────────\n\nfunction buildHeadingLine(\n level: number,\n rawText: string,\n innerW: number,\n): DetailLine {\n const style = HEADING_STYLES[Math.min(level - 1, HEADING_STYLES.length - 1)]!;\n const cleanedText = stripDisplayHazards(rawText).trim();\n const marker = '#'.repeat(level);\n const prefix = ' '; // matches the standard 2-space content margin\n const sep = ' ';\n\n const headerSegs: Seg[] = [\n { text: prefix, bg: style.bg },\n { text: marker, fg: style.markerFg, bg: style.bg, bold: true },\n { text: sep, bg: style.bg },\n { text: cleanedText, fg: style.textFg, bg: style.bg, bold: true },\n ];\n const used = segsDisplayWidth(headerSegs);\n const padW = Math.max(0, innerW - used);\n if (padW > 0) {\n headerSegs.push({ text: ' '.repeat(padW), bg: style.bg });\n }\n return headerSegs;\n}\n\n// ─── Bullet/numbered list ──────────────────────────────────────────────────\n\nfunction buildListLine(\n marker: string,\n body: string,\n innerW: number,\n prefixIndent: string,\n markerFg: string,\n): DetailLine[] {\n const indent = `${prefixIndent} `; // continuation aligns under text\n const head: Seg[] = [\n { text: prefixIndent, fg: GLOAM.fg2 },\n { text: marker, fg: markerFg, bold: true },\n { text: ' ', fg: GLOAM.fg2 },\n ];\n const headW = segsDisplayWidth(head);\n const bodySegs = tokenizeInline(stripDisplayHazards(body), GLOAM.fg1);\n const wrapped = wrapSegs([...head, ...bodySegs], innerW, indent);\n // wrapSegs treats the indent+head as part of segs — but we want first-line\n // to start with our colored head and continuations to use plain indent.\n // To keep things simple, we already wrap with contIndent set.\n return wrapped;\n // Note: contIndent is plain (no fg) to keep continuation rows readable;\n // wrapSegs prepends a single indent seg for each new line — good enough.\n}\n\n// ─── Checkbox ──────────────────────────────────────────────────────────────\n\nfunction buildCheckboxLine(\n checked: boolean,\n body: string,\n innerW: number,\n): DetailLine[] {\n const icon = checked ? '☑' : '☐';\n const iconFg = checked ? GLOAM.green : GLOAM.fg4;\n const head: Seg[] = [\n { text: ' ', fg: GLOAM.fg2 },\n { text: icon, fg: iconFg, bold: true },\n { text: ' ', fg: GLOAM.fg2 },\n ];\n const bodyFg = checked ? GLOAM.fg3 : GLOAM.fg1;\n const bodyStyle = checked ? { strikethrough: true } : {};\n const bodySegs = tokenizeInline(stripDisplayHazards(body), bodyFg, bodyStyle);\n return wrapSegs([...head, ...bodySegs], innerW, ' ');\n}\n\n// ─── Blockquote ────────────────────────────────────────────────────────────\n\nfunction buildQuoteLine(body: string, innerW: number): DetailLine[] {\n const head: Seg[] = [\n { text: ' ', fg: GLOAM.fg2 },\n { text: '▎ ', fg: GLOAM.fg3 },\n ];\n const bodySegs = tokenizeInline(stripDisplayHazards(body), GLOAM.fg2, { italic: true });\n return wrapSegs([...head, ...bodySegs], innerW, ' ');\n}\n\n// ─── Horizontal rule ───────────────────────────────────────────────────────\n\nfunction buildHrLine(innerW: number): DetailLine {\n const w = Math.max(2, innerW - 4);\n return [\n { text: ' ', fg: GLOAM.fg4 },\n { text: '─'.repeat(w), fg: GLOAM.fg4 },\n ];\n}\n\n// ─── Code block content ────────────────────────────────────────────────────\n\nfunction buildCodeFenceLine(fence: string, innerW: number): DetailLine {\n return [\n { text: ' ', fg: GLOAM.fg4 },\n {\n text: fence + ' '.repeat(Math.max(0, innerW - 2 - stringWidth(fence))),\n fg: GLOAM.fg4,\n bg: GLOAM.bg_bg1,\n },\n ];\n}\n\nfunction buildCodeLine(content: string, innerW: number): DetailLine {\n const cleaned = stripDisplayHazards(content);\n const cw = stringWidth(cleaned);\n const padW = Math.max(0, innerW - 2 - cw);\n return [\n { text: ' ', bg: GLOAM.bg_bg1 },\n { text: cleaned, fg: GLOAM.aqua, bg: GLOAM.bg_bg1 },\n ...(padW > 0 ? [{ text: ' '.repeat(padW), bg: GLOAM.bg_bg1 }] : []),\n ];\n}\n\n// ─── Plain paragraph ───────────────────────────────────────────────────────\n\nfunction buildParagraphLines(body: string, innerW: number): DetailLine[] {\n const head: Seg[] = [{ text: ' ', fg: GLOAM.fg1 }];\n const bodySegs = tokenizeInline(stripDisplayHazards(body), GLOAM.fg1);\n return wrapSegs([...head, ...bodySegs], innerW, ' ');\n}\n\n// ─── GFM tables ────────────────────────────────────────────────────────────\n\ntype TableAlign = 'left' | 'center' | 'right';\n\nfunction parseTableCells(line: string): string[] {\n let s = line.trim();\n if (s.startsWith('|')) s = s.slice(1);\n if (s.endsWith('|') && !s.endsWith('\\\\|')) s = s.slice(0, -1);\n const cells: string[] = [];\n let cur = '';\n for (let i = 0; i < s.length; i++) {\n const ch = s[i]!;\n if (ch === '\\\\' && s[i + 1] === '|') {\n cur += '|';\n i++;\n } else if (ch === '|') {\n cells.push(cur.trim());\n cur = '';\n } else {\n cur += ch;\n }\n }\n cells.push(cur.trim());\n return cells;\n}\n\nfunction parseTableSeparator(line: string): TableAlign[] | null {\n if (!line.includes('|') && !/^[\\s:|+-]+$/.test(line)) return null;\n const cells = parseTableCells(line);\n if (cells.length === 0) return null;\n const aligns: TableAlign[] = [];\n for (const c of cells) {\n const m = c.match(/^(:?)\\s*-{2,}\\s*(:?)$/);\n if (!m) return null;\n if (m[1] === ':' && m[2] === ':') aligns.push('center');\n else if (m[2] === ':') aligns.push('right');\n else aligns.push('left');\n }\n return aligns;\n}\n\nfunction padCell(text: string, width: number, align: TableAlign): string {\n const w = stringWidth(text);\n const pad = Math.max(0, width - w);\n let left = 0;\n let right = 0;\n if (align === 'right') left = pad;\n else if (align === 'center') {\n left = Math.floor(pad / 2);\n right = pad - left;\n } else right = pad;\n return ' '.repeat(left) + text + ' '.repeat(right);\n}\n\n/**\n * Soft-wrap cell text to `width` columns, returning each visual line padded\n * (and aligned) to exactly `width` display columns. Words longer than the\n * column hard-break on character boundaries.\n */\nfunction wrapCell(text: string, width: number, align: TableAlign): string[] {\n if (width <= 0) return [''];\n const cleaned = cleanMarkdown(text);\n if (cleaned === '') return [padCell('', width, align)];\n\n const out: string[] = [];\n let cur = '';\n let curW = 0;\n const flush = () => {\n out.push(padCell(cur.replace(/\\s+$/, ''), width, align));\n cur = '';\n curW = 0;\n };\n\n for (const piece of cleaned.match(/\\s+|\\S+/g) ?? []) {\n const isSpace = /^\\s+$/.test(piece);\n const pw = stringWidth(piece);\n\n if (isSpace) {\n if (curW === 0) continue; // drop leading whitespace on a wrapped line\n if (curW + pw > width) flush();\n else {\n cur += piece;\n curW += pw;\n }\n continue;\n }\n\n if (curW + pw <= width) {\n cur += piece;\n curW += pw;\n continue;\n }\n\n if (curW > 0) flush();\n\n if (pw > width) {\n // Hard-break a word wider than the column.\n let rem = piece;\n while (rem.length > 0) {\n let cut = 0;\n let cutW = 0;\n for (let k = 0; k < rem.length; k++) {\n const cw = stringWidth(rem[k]!);\n if (cutW + cw > width) break;\n cutW += cw;\n cut = k + 1;\n }\n if (cut === 0) cut = 1;\n const slice = rem.slice(0, cut);\n if (cut === rem.length) {\n cur = slice;\n curW = stringWidth(slice);\n } else {\n out.push(padCell(slice, width, align));\n }\n rem = rem.slice(cut);\n }\n continue;\n }\n\n cur = piece;\n curW = pw;\n }\n\n if (curW > 0 || out.length === 0) flush();\n return out;\n}\n\nfunction buildTableLines(\n headers: string[],\n alignsIn: TableAlign[],\n rowsIn: string[][],\n innerW: number,\n): DetailLine[] {\n const ncols = headers.length;\n if (ncols === 0) return [];\n\n // Normalize aligns and rows to exactly ncols entries so downstream indexing\n // is total. Missing entries default to left-align / empty string.\n const aligns: TableAlign[] = [];\n for (let i = 0; i < ncols; i++) {\n const a = alignsIn[i];\n aligns.push(a === undefined ? 'left' : a);\n }\n\n const rows: string[][] = rowsIn.map((r) => {\n const out: string[] = [];\n for (let i = 0; i < ncols; i++) {\n const c = r[i];\n out.push(c === undefined ? '' : c);\n }\n return out;\n });\n\n // Natural widths from cleaned cell text\n const naturalW: number[] = new Array(ncols).fill(0);\n const measure = (cells: string[]) => {\n for (let i = 0; i < ncols; i++) {\n const w = stringWidth(cleanMarkdown(cells[i]!));\n if (w > naturalW[i]!) naturalW[i] = w;\n }\n };\n measure(headers);\n for (const r of rows) measure(r);\n\n // Layout: 2-char margin + left border + (cell + right-border) per column.\n // Each cell is \" <content> \" (2 chars padding) so per-column overhead is 3\n // (one separator + two pad spaces). Plus 1 for the leading border.\n const margin = 2;\n const overhead = 1 + ncols * 3;\n const available = innerW - margin - overhead;\n const minColW = 3;\n\n if (available < ncols * minColW) {\n return [[{ text: ' (table too narrow to render)', fg: GLOAM.fg4, italic: true }]];\n }\n\n const colW: number[] = [...naturalW];\n for (let i = 0; i < ncols; i++) if (colW[i]! < minColW) colW[i] = minColW;\n let total = colW.reduce((a, b) => a + b, 0);\n\n if (total > available) {\n // Shrink the widest column repeatedly until it fits.\n while (total > available) {\n let widest = 0;\n for (let i = 1; i < ncols; i++) if (colW[i]! > colW[widest]!) widest = i;\n if (colW[widest]! <= minColW) break;\n colW[widest]!--;\n total--;\n }\n } else if (total < available) {\n // Grow the widest column to absorb the slack so the right border aligns.\n while (total < available) {\n let widest = 0;\n for (let i = 1; i < ncols; i++) if (colW[i]! > colW[widest]!) widest = i;\n colW[widest]!++;\n total++;\n }\n }\n\n const borderFg = GLOAM.fg3;\n const headerFg = GLOAM.fg0;\n const headerBg = GLOAM.bg_bg1;\n const cellFg = GLOAM.fg1;\n const marginText = ' ';\n\n const buildBorder = (left: string, mid: string, right: string): DetailLine => {\n let s = left;\n for (let i = 0; i < ncols; i++) {\n s += '─'.repeat(colW[i]! + 2);\n s += i === ncols - 1 ? right : mid;\n }\n return [{ text: marginText }, { text: s, fg: borderFg }];\n };\n\n const buildDataRow = (cells: string[], header: boolean): DetailLine[] => {\n const wrapped: string[][] = [];\n for (let i = 0; i < ncols; i++) {\n const cell = cells[i];\n wrapped.push(wrapCell(cell === undefined ? '' : cell, colW[i]!, aligns[i]!));\n }\n let height = 1;\n for (const w of wrapped) if (w.length > height) height = w.length;\n // Pad shorter columns with blank lines so the row has a uniform height.\n for (let i = 0; i < ncols; i++) {\n const blank = ' '.repeat(colW[i]!);\n while (wrapped[i]!.length < height) wrapped[i]!.push(blank);\n }\n\n const out: DetailLine[] = [];\n for (let row = 0; row < height; row++) {\n const segs: Seg[] = [\n { text: marginText },\n { text: '│', fg: borderFg },\n ];\n for (let i = 0; i < ncols; i++) {\n const padded = ' ' + wrapped[i]![row]! + ' ';\n segs.push(\n header\n ? { text: padded, fg: headerFg, bg: headerBg, bold: true }\n : { text: padded, fg: cellFg },\n );\n segs.push({ text: '│', fg: borderFg });\n }\n out.push(segs);\n }\n return out;\n };\n\n const out: DetailLine[] = [];\n out.push(buildBorder('┌', '┬', '┐'));\n for (const dl of buildDataRow(headers, true)) out.push(dl);\n out.push(buildBorder('├', '┼', '┤'));\n for (const r of rows) for (const dl of buildDataRow(r, false)) out.push(dl);\n out.push(buildBorder('└', '┴', '┘'));\n return out;\n}\n\n// ─── Public entry point ────────────────────────────────────────────────────\n\n/**\n * Convert a markdown document into a stream of styled DetailLine[] sized to\n * `innerW` columns. Trailing/leading blank lines are normalized; YAML\n * frontmatter is stripped via the shared helper.\n */\nexport function buildHighlightedMarkdownLines(\n content: string,\n innerW: number,\n): DetailLine[] {\n const lines: DetailLine[] = [];\n const clean = stripFrontmatter(content);\n if (!clean.trim()) {\n lines.push([{ text: ' (empty)', fg: GLOAM.fg4, italic: true }]);\n return lines;\n }\n\n const rawLines = clean.split('\\n');\n let inCodeBlock = false;\n\n for (let li = 0; li < rawLines.length; li++) {\n const raw = rawLines[li]!;\n const trimmed = raw.trim();\n\n // Code fence — toggles block state, rendered as a dim line\n if (/^```/.test(trimmed)) {\n inCodeBlock = !inCodeBlock;\n lines.push(buildCodeFenceLine(trimmed, innerW));\n continue;\n }\n\n if (inCodeBlock) {\n lines.push(buildCodeLine(raw.replace(/\\t/g, ' '), innerW));\n continue;\n }\n\n // GFM table: current line has a pipe and next line is an alignment row.\n if (trimmed.includes('|') && li + 1 < rawLines.length) {\n const sepLine = rawLines[li + 1]!;\n const sepAligns = parseTableSeparator(sepLine);\n if (sepAligns) {\n const headers = parseTableCells(raw);\n const tRows: string[][] = [];\n let j = li + 2;\n while (j < rawLines.length) {\n const next = rawLines[j]!;\n if (next.trim() === '') break;\n if (!next.includes('|')) break;\n if (/^```/.test(next.trim())) break;\n tRows.push(parseTableCells(next));\n j++;\n }\n for (const tl of buildTableLines(headers, sepAligns, tRows, innerW)) lines.push(tl);\n li = j - 1; // resume after consumed rows; loop ++ moves past them\n continue;\n }\n }\n\n // Empty line\n if (trimmed === '') {\n // Collapse multi-blanks into a single blank\n const last = lines[lines.length - 1];\n if (last && last.length === 1 && last[0]!.text === '') continue;\n lines.push([{ text: '' }]);\n continue;\n }\n\n // Frontmatter delimiter inside body (already stripped above, but defensive)\n if (trimmed === '---') {\n lines.push(buildHrLine(innerW));\n continue;\n }\n\n // Heading\n const headMatch = raw.match(/^(\\s*)(#{1,6})\\s+(.+?)\\s*#*\\s*$/);\n if (headMatch) {\n const level = headMatch[2]!.length;\n lines.push(buildHeadingLine(level, headMatch[3]!, innerW));\n continue;\n }\n\n // Horizontal rule\n if (/^\\s*([-*_])(\\s*\\1){2,}\\s*$/.test(raw)) {\n lines.push(buildHrLine(innerW));\n continue;\n }\n\n // Checkbox (must come before bullet match)\n const cbMatch = raw.match(/^\\s*[-*+]\\s+\\[( |x|X)\\]\\s+(.+)$/);\n if (cbMatch) {\n const checked = cbMatch[1] !== ' ';\n for (const wl of buildCheckboxLine(checked, cbMatch[2]!, innerW)) lines.push(wl);\n continue;\n }\n\n // Numbered list\n const numMatch = raw.match(/^(\\s*)(\\d+)([.)])\\s+(.+)$/);\n if (numMatch) {\n const indent = numMatch[1]!.length > 0 ? ' ' : ' ';\n const marker = `${numMatch[2]}${numMatch[3]}`;\n for (const wl of buildListLine(marker, numMatch[4]!, innerW, indent, GLOAM.purple)) {\n lines.push(wl);\n }\n continue;\n }\n\n // Bullet list\n const bulMatch = raw.match(/^(\\s*)([-*+])\\s+(.+)$/);\n if (bulMatch) {\n const depth = Math.floor(bulMatch[1]!.length / 2);\n const indent = ' ' + ' '.repeat(Math.min(depth, 4));\n const bullet = depth === 0 ? '·' : '◦';\n for (const wl of buildListLine(bullet, bulMatch[3]!, innerW, indent, GLOAM.orange)) {\n lines.push(wl);\n }\n continue;\n }\n\n // Blockquote\n const qMatch = raw.match(/^\\s*>\\s?(.*)$/);\n if (qMatch) {\n for (const wl of buildQuoteLine(qMatch[1]!, innerW)) lines.push(wl);\n continue;\n }\n\n // Paragraph\n for (const wl of buildParagraphLines(trimmed, innerW)) lines.push(wl);\n }\n\n // Trim trailing blank\n while (lines.length > 0) {\n const last = lines[lines.length - 1]!;\n if (last.length === 1 && last[0]!.text === '') lines.pop();\n else break;\n }\n\n return lines;\n}\n","/**\n * Gloam palette — true-color ANSI SGR codes mirroring the Neovim gloam theme.\n *\n * Each constant is a partial SGR sequence (no leading `\\x1b[`, no trailing `m`)\n * suitable for `Seg.fg` and `Seg.bg` fields. Foreground codes use the `38;2;…`\n * 24-bit form; background codes use `48;2;…`.\n *\n * Source palette: ~/.config/nvim/lua/gloam/palette.lua\n */\n\nfunction fg(r: number, g: number, b: number): string {\n return `38;2;${r};${g};${b}`;\n}\n\nfunction bg(r: number, g: number, b: number): string {\n return `48;2;${r};${g};${b}`;\n}\n\nexport const GLOAM = {\n // Foregrounds — warm off-whites\n fg0: fg(226, 217, 198), // brightest\n fg1: fg(212, 203, 184), // primary\n fg2: fg(176, 168, 152), // secondary\n fg3: fg(135, 127, 111), // tertiary (comments, quotes)\n fg4: fg(94, 88, 78), // quaternary (line numbers, concealed)\n\n // Accents\n red: fg(212, 116, 102),\n orange: fg(216, 151, 104),\n yellow: fg(212, 173, 106),\n green: fg(169, 177, 110),\n aqua: fg(130, 173, 138),\n blue: fg(124, 168, 160),\n purple: fg(196, 138, 158),\n\n // Bright accents — heading text, emphasis\n bright_red: fg(232, 138, 126),\n bright_orange: fg(236, 173, 128),\n bright_yellow: fg(232, 196, 132),\n bright_green: fg(188, 197, 126),\n bright_blue: fg(144, 190, 182),\n bright_purple: fg(216, 160, 180),\n\n // Dim backgrounds — heading/code-block tints\n bg_dim_red: bg(58, 28, 24),\n bg_dim_orange: bg(58, 40, 18),\n bg_dim_yellow: bg(51, 46, 18),\n bg_dim_green: bg(31, 48, 24),\n bg_dim_aqua: bg(20, 46, 36),\n bg_dim_blue: bg(21, 40, 56),\n bg_dim_purple: bg(50, 24, 40),\n\n // Surface backgrounds\n bg_bg1: bg(37, 38, 41), // cursorline / inline-code tint\n bg_bg2: bg(45, 47, 51), // float/popup\n bg_sel_yellow: bg(61, 50, 37), // active selection\n} as const;\n\nexport type GloamKey = keyof typeof GLOAM;\n","import { writeClipped, type FrameBuffer } from '../render.js';\nimport { ansiBold, ansiDim } from '../lib/format.js';\nimport type { AppState } from '../state.js';\nimport type { TreeNodeType } from '../types/tree.js';\n\n// ─── Status Line ──────────────────────────────────────────────────────────────\n\nconst B = ansiBold;\nconst D = ansiDim;\nconst SEP = D('│ ');\nconst DANGER_BADGE = '\\x1b[1;41;97m DANGEROUS \\x1b[0m';\n\nexport function renderStatusLine(\n buf: FrameBuffer,\n y: number,\n state: AppState,\n cursorNodeType: TreeNodeType | undefined,\n): void {\n const { mode, focusPane, notification, error } = state;\n\n if (mode === 'report-detail') return;\n\n let content: string;\n\n // Notifications/errors take over the status line transiently\n if (notification !== null) {\n const icon = /error|failed/i.test(notification)\n ? '✕'\n : /success|created|killed|sent|copied|deleted/i.test(notification)\n ? '✓'\n : 'ℹ';\n content = `\\x1b[1;33m${icon} ${notification}\\x1b[0m`;\n } else if (error !== null) {\n content = `\\x1b[31m⚠ ${error}\\x1b[0m`;\n } else if (mode === 'search') {\n const cursor = `\\x1b[7m \\x1b[0m`;\n content = `\\x1b[1;34m/\\x1b[0m${state.searchText}${cursor}` + D(' enter to apply · esc to clear');\n } else if (mode === 'leader') {\n content = `\\x1b[1;35mLEADER\\x1b[0m` + D(' [c]opy [o]pen [a]gent [S]ession [g]o or [s]cycle [h]ome [n]ew [m]sg [t]status [l]picker [x]kill [/]search [?]help [esc] cancel');\n } else if (mode === 'copy-menu') {\n content = `\\x1b[1;36mCOPY\\x1b[0m` + D(' [p]ath [i]d [c] context [l]ogs [r]eport [a]gent ID [esc] cancel');\n } else if (mode === 'open-menu') {\n content = `\\x1b[1;32mOPEN\\x1b[0m` + D(' [g]oal [r]oadmap [s]trategy [l]ogs [d]ir [R]eport [c]scratch [e]dit context [esc] cancel');\n } else if (mode === 'agent-menu') {\n content = `\\x1b[1;34mAGENT\\x1b[0m` + D(' [s]pawn [m]sg [r]estart [R]erun [j]ump [o]pen-claude [t]ail [k]ill [e]xplore [d]ebug [esc] cancel');\n } else if (mode === 'session-menu') {\n content = `\\x1b[1;31mSESSION\\x1b[0m` + D(' [n]ew [r]esume [c]ontinue [b]ollback [k]ill [d]elete [e]xport [w]indow [C]lone [i]history [esc] cancel');\n } else if (mode === 'go-menu') {\n content = `\\x1b[1;33mGO\\x1b[0m` + D(' [w]indow [p]ane [s]ession [n]ext [r]econnect [esc] cancel');\n } else if (mode === 'help') {\n content = `\\x1b[1;33mHELP\\x1b[0m` + D(' [esc] or [?] to dismiss');\n } else if (focusPane === 'logs' || focusPane === 'detail') {\n content =\n B('[jk/↑↓]') + D(' scroll ') +\n B('[h/←/tab]') + D(' back ') +\n B('[t]') + D('oggle view ') +\n B('[F]') + D('low ± ') +\n SEP +\n B('[m]') + D('sg ') +\n B('[g]') + D('oal ') +\n B('[n]') + D('ew ') +\n B('[p]') + D('lan ') +\n B('[w]') + D('indow ') +\n B('[R]') + D('esume ') +\n B('[q]') + D('uit');\n } else if (cursorNodeType === 'needs-you-virtual') {\n content =\n B('[enter]') + D(' open ask ') +\n B('[esc]') + D(' back ') +\n SEP +\n B('[q]') + D('uit');\n } else {\n // tree focused\n let contextFilePart = '';\n if (cursorNodeType === 'context-file') {\n contextFilePart = B('[e]') + D('dit ') + B('[⏎]') + D(' open ');\n }\n content =\n contextFilePart +\n B('[enter]') + D(' select ') +\n B('[m]') + D('essage ') +\n B('[n]') + D('ew ') +\n B('[w]') + D(' tmux ') +\n SEP +\n B('[q]') + D('uit');\n }\n\n if (state.selectedSession?.dangerousMode === true) {\n content = `${DANGER_BADGE} ${content}`;\n }\n\n writeClipped(buf, 1, y, content, buf.width - 2);\n}\n","import { buildPanelRows, buildEmptyPanelRows, type Rect } from '../render.js';\nimport type { AppState } from '../state.js';\nimport {\n seg, singleLine, formatTimeAgo, truncate, type DetailLine,\n} from '../lib/format.js';\nimport { coerceKind, type AggregateInboxItem } from '../../shared/inbox-types.js';\n\nconst KIND_ICON: Record<string, string> = {\n notify: '✉',\n validation: '✓',\n decision: '◆',\n context: '✎',\n error: '⚠',\n};\nconst KIND_COLOR: Record<string, string> = {\n notify: 'gray',\n validation: 'cyan',\n decision: 'cyan',\n context: 'cyan',\n error: 'red',\n};\n\nfunction buildInboxLines(items: AggregateInboxItem[], width: number): DetailLine[] {\n const lines: DetailLine[] = [];\n if (items.length === 0) {\n lines.push(singleLine(' No pending asks across the fleet', { dim: true, italic: true }));\n return lines;\n }\n lines.push(singleLine(` ${items.length} pending`, { bold: true }));\n lines.push(singleLine(' '));\n const contentWidth = width - 4;\n for (const item of items) {\n const kindKey = coerceKind(item.kind);\n const icon = kindKey in KIND_ICON ? KIND_ICON[kindKey]! : '·';\n const iconColor = kindKey in KIND_COLOR ? KIND_COLOR[kindKey]! : 'cyan';\n const source = item.sessionName ? item.sessionName : item.sessionId.slice(0, 8);\n const titleText = item.title ? item.title : `(${item.askId.slice(0, 8)})`;\n const blocked = formatTimeAgo(item.blockedSince);\n const maxTitle = Math.max(10, contentWidth - source.length - blocked.length - 8);\n lines.push([\n seg(' '),\n seg(icon, { color: iconColor }),\n seg(` ${source}`, { color: 'yellow' }),\n seg(' · ', { dim: true }),\n seg(truncate(titleText, maxTitle), { bold: true }),\n seg(` ${blocked}`, { dim: true }),\n ]);\n if (item.subtitle) {\n lines.push(singleLine(` ${truncate(item.subtitle, contentWidth - 6)}`, { dim: true }));\n }\n }\n return lines;\n}\n\nexport function renderCrossSessionInboxRows(rect: Rect, state: AppState): string[] {\n if (rect.w <= 0 || rect.h <= 0) {\n return buildEmptyPanelRows(rect, state.focusPane === 'detail', 'red', '');\n }\n const focused = state.focusPane === 'detail';\n const items = state.aggregateInbox;\n const fingerprint = items.map(i => `${i.askId}:${i.status}`).join(',');\n const cacheKey = `${items.length}:${fingerprint}:${rect.w}`;\n let lines: DetailLine[];\n if (cacheKey === state.inboxCacheKey && state.cachedInboxLines !== null) {\n lines = state.cachedInboxLines;\n } else {\n lines = buildInboxLines(items, rect.w);\n state.cachedInboxLines = lines;\n state.inboxCacheKey = cacheKey;\n }\n return buildPanelRows(rect, lines, state.crossSessionInboxScroll, focused, 'red', state.inboxRenderedCache);\n}\n","import { execSync } from 'node:child_process';\nimport { mkdtempSync, writeFileSync, readFileSync, rmSync } from 'node:fs';\nimport { join } from 'node:path';\nimport { tmpdir } from 'node:os';\nimport { shellQuote } from '../../shared/shell.js';\nimport { EXEC_ENV } from '../../shared/exec.js';\nimport { type AppState, type ComposeAction, OPTIONAL_COMPOSE, notify } from '../state.js';\nimport type { InputActions } from '../input.js';\nimport { dispatchComposeAction } from '../input.js';\n\nexport { ensureSisyphusInitLua } from '../../shared/sisyphus-init-lua.js';\n\n/**\n * Open a tmux popup running `NVIM_APPNAME=sisyphus nvim <tempfile>`, await close,\n * read content, dispatch action. Empty file = cancel (no submission).\n * Synchronous; blocks the TUI render loop until popup exits.\n */\nexport function composeViaPopup(\n action: ComposeAction,\n state: AppState,\n actions: InputActions,\n): void {\n const tmpDir = mkdtempSync(join(tmpdir(), 'sisyphus-popup-'));\n const tempFile = join(tmpDir, 'compose.md');\n try {\n writeFileSync(tempFile, '', 'utf-8');\n const cmd = `NVIM_APPNAME=sisyphus nvim ${shellQuote(tempFile)}`;\n execSync(\n `tmux display-popup -E -w 90% -h 90% -d ${shellQuote(state.cwd)} ${shellQuote(cmd)}`,\n { stdio: 'inherit', env: EXEC_ENV },\n );\n\n let rawContent = '';\n try { rawContent = readFileSync(tempFile, 'utf-8'); } catch { /* ignore */ }\n\n const required = !OPTIONAL_COMPOSE.has(action.kind);\n if (!rawContent.trim() && required) {\n // Cancel: silent. Match editInPopup semantics — no notification on cancel.\n return;\n }\n // Dispatch original untrimmed content — trim is only for cancel detection above.\n dispatchComposeAction(action, rawContent, state, actions);\n } catch (err) {\n notify(state, `Failed to open compose popup: ${(err as Error).message}`);\n } finally {\n rmSync(tmpDir, { recursive: true, force: true });\n }\n}\n","import { mkdirSync, existsSync, cpSync } from 'node:fs';\nimport { join } from 'node:path';\nimport { homedir } from 'node:os';\n\nlet initLuaEnsured = false;\n\n/**\n * Idempotent: copies templates/sisyphus-init.lua to ~/.config/sisyphus/init.lua\n * if and only if the destination doesn't exist. Safe to call repeatedly.\n *\n * Loaded only when nvim is invoked as `NVIM_APPNAME=sisyphus nvim ...` (compose\n * flows in both the TUI popup and the in-session tmux scripts).\n */\nexport function ensureSisyphusInitLua(): void {\n if (initLuaEnsured) return;\n initLuaEnsured = true;\n try {\n const destDir = join(homedir(), '.config', 'sisyphus');\n const destPath = join(destDir, 'init.lua');\n if (existsSync(destPath)) return;\n mkdirSync(destDir, { recursive: true });\n const srcPath = join(import.meta.dirname, 'templates', 'sisyphus-init.lua');\n cpSync(srcPath, destPath);\n } catch {\n // Non-fatal: nvim still opens, just without sisyphus init customization.\n }\n}\n"],"mappings":";;;;;;;;;;;;AAmBA,SAAS,WAAgB;AACvB,SAAO;AAAA,IACL,SAAS;AAAA,IACT,WAAW;AAAA,IACX,WAAW;AAAA,IACX,YAAY;AAAA,IACZ,QAAQ;AAAA,IACR,UAAU;AAAA,IACV,QAAQ;AAAA,IACR,QAAQ;AAAA,IACR,MAAM;AAAA,IACN,OAAO;AAAA,IACP,KAAK;AAAA,IACL,WAAW;AAAA,IACX,QAAQ;AAAA,IACR,MAAM;AAAA,EACR;AACF;AAIO,SAAS,gBAA4B;AAC1C,MAAI,UAAU;AAEd,QAAMA,WAAU,MAAY;AAC1B,QAAI,QAAS;AACb,cAAU;AACV,YAAQ,OAAO,MAAM,sBAAsB;AAC3C,YAAQ,MAAM,WAAW,KAAK;AAC9B,YAAQ,MAAM,MAAM;AAAA,EACtB;AAEA,UAAQ,MAAM,WAAW,IAAI;AAC7B,UAAQ,MAAM,OAAO;AACrB,UAAQ,MAAM,YAAY,OAAO;AACjC,UAAQ,OAAO,MAAM,6BAA6B;AAElD,UAAQ,GAAG,UAAU,MAAM;AAAE,IAAAA,SAAQ;AAAG,YAAQ,KAAK,CAAC;AAAA,EAAG,CAAC;AAC1D,UAAQ,GAAG,WAAW,MAAM;AAAE,IAAAA,SAAQ;AAAG,YAAQ,KAAK,CAAC;AAAA,EAAG,CAAC;AAC3D,UAAQ,GAAG,QAAQA,QAAO;AAC1B,UAAQ,GAAG,qBAAqB,CAAC,QAAQ;AACvC,IAAAA,SAAQ;AACR,YAAQ,MAAM,GAAG;AACjB,YAAQ,KAAK,CAAC;AAAA,EAChB,CAAC;AAED,SAAOA;AACT;AAIO,SAAS,cAAc,MAAoB;AAChD,UAAQ,OAAO,MAAM,IAAI;AAC3B;AAQA,SAAS,YAAY,KAAkE;AACrF,QAAM,SAA+B,CAAC;AAEtC,MAAI,IAAI;AACR,SAAO,IAAI,IAAI,QAAQ;AACrB,UAAM,KAAK,IAAI,CAAC;AAGhB,QAAI,OAAO,QAAQ;AACjB,YAAM,OAAO,IAAI,MAAM,IAAI,CAAC;AAG5B,UAAI,KAAK,WAAW,GAAG,GAAG;AACxB,cAAM,QAAQ,KAAK,MAAM,CAAC;AAG1B,cAAM,aAAa,MAAM,MAAM,cAAc;AAC7C,YAAI,YAAY;AACd,gBAAMC,OAAM,SAAS;AACrB,UAAAA,KAAI,QAAQ;AACZ,gBAAM,MAAM,WAAW,CAAC;AACxB,cAAI,QAAQ,IAAK,CAAAA,KAAI,UAAU;AAAA,mBACtB,QAAQ,IAAK,CAAAA,KAAI,YAAY;AAAA,mBAC7B,QAAQ,IAAK,CAAAA,KAAI,aAAa;AAAA,mBAC9B,QAAQ,IAAK,CAAAA,KAAI,YAAY;AACtC,gBAAM,MAAM,WAAW,GAAG;AAC1B,iBAAO,KAAK,CAAC,KAAKA,IAAG,CAAC;AACtB,eAAK,IAAI;AACT;AAAA,QACF;AAGA,YAAI,MAAM,UAAU,KAAK,MAAM,CAAC,MAAM,KAAK;AACzC,gBAAMA,OAAM,SAAS;AACrB,UAAAA,KAAI,MAAM;AACV,UAAAA,KAAI,QAAQ;AACZ,gBAAM,MAAM;AACZ,iBAAO,KAAK,CAAC,KAAKA,IAAG,CAAC;AACtB,eAAK,IAAI;AACT;AAAA,QACF;AAGA,YAAI,MAAM,UAAU,KAAK,OAAO,SAAS,MAAM,CAAC,CAAE,GAAG;AACnD,gBAAMA,OAAM,SAAS;AACrB,gBAAM,MAAM,MAAM,CAAC;AACnB,cAAI,QAAQ,IAAK,CAAAA,KAAI,UAAU;AAAA,mBACtB,QAAQ,IAAK,CAAAA,KAAI,YAAY;AAAA,mBAC7B,QAAQ,IAAK,CAAAA,KAAI,aAAa;AAAA,mBAC9B,QAAQ,IAAK,CAAAA,KAAI,YAAY;AACtC,gBAAM,MAAM,QAAQ,GAAG;AACvB,iBAAO,KAAK,CAAC,KAAKA,IAAG,CAAC;AACtB,eAAK,IAAI;AACT;AAAA,QACF;AAGA,cAAM,aAAa,MAAM,MAAM,SAAS;AACxC,YAAI,YAAY;AACd,gBAAM,MAAM,WAAW,CAAC;AACxB,gBAAMA,OAAM,SAAS;AACrB,cAAI,QAAQ,IAAK,CAAAA,KAAI,SAAS;AAAA,mBACrB,QAAQ,IAAK,CAAAA,KAAI,WAAW;AAAA,mBAC5B,QAAQ,IAAK,CAAAA,KAAI,SAAS;AACnC,gBAAM,MAAM,QAAQ,GAAG;AACvB,iBAAO,KAAK,CAAC,KAAKA,IAAG,CAAC;AACtB,eAAK,IAAI;AACT;AAAA,QACF;AAGA,eAAO,EAAE,QAAQ,WAAW,IAAI,MAAM,CAAC,EAAE;AAAA,MAC3C;AAGA,UAAI,KAAK,WAAW,GAAG;AACrB,eAAO,EAAE,QAAQ,WAAW,IAAI,MAAM,CAAC,EAAE;AAAA,MAC3C;AAGA,YAAM,SAAS,KAAK,CAAC;AACrB,YAAM,MAAM,SAAS;AACrB,UAAI,OAAO;AACX,aAAO,KAAK,CAAC,QAAQ,GAAG,CAAC;AACzB,WAAK;AACL;AAAA,IACF;AAGA,QAAI,OAAO,MAAM;AACf,YAAM,MAAM,SAAS;AACrB,UAAI,SAAS;AACb,aAAO,KAAK,CAAC,IAAI,GAAG,CAAC;AACrB;AACA;AAAA,IACF;AAGA,QAAI,OAAO,KAAM;AACf,YAAM,MAAM,SAAS;AACrB,UAAI,MAAM;AACV,aAAO,KAAK,CAAC,IAAI,GAAG,CAAC;AACrB;AACA;AAAA,IACF;AAGA,QAAI,OAAO,UAAU,OAAO,MAAQ;AAClC,YAAM,MAAM,SAAS;AACrB,UAAI,YAAY;AAChB,aAAO,KAAK,CAAC,IAAI,GAAG,CAAC;AACrB;AACA;AAAA,IACF;AAGA,UAAM,OAAO,GAAG,WAAW,CAAC;AAC5B,QAAI,QAAQ,KAAQ,QAAQ,IAAM;AAChC,YAAM,MAAM,SAAS;AACrB,UAAI,OAAO;AACX,YAAM,SAAS,OAAO,aAAa,OAAO,EAAE;AAC5C,aAAO,KAAK,CAAC,QAAQ,GAAG,CAAC;AACzB;AACA;AAAA,IACF;AAGA,WAAO,KAAK,CAAC,IAAI,SAAS,CAAC,CAAC;AAC5B;AAAA,EACF;AAEA,SAAO,EAAE,QAAQ,WAAW,GAAG;AACjC;AAUO,SAAS,sBAAsB,SAAsC;AAC1E,MAAI,SAAS;AACb,MAAI,WAAiD;AAErD,QAAM,SAAS,CAAC,SAAuB;AAErC,QAAI,kBAAkB;AACpB,YAAM,UAAU,iBAAiB,IAAI;AACrC,UAAI,QAAS;AAAA,IACf;AAGA,QAAI,aAAa,MAAM;AACrB,mBAAa,QAAQ;AACrB,iBAAW;AAAA,IACb;AAEA,cAAU;AAEV,UAAM,EAAE,QAAQ,UAAU,IAAI,YAAY,MAAM;AAChD,aAAS;AAET,eAAW,CAAC,OAAO,GAAG,KAAK,QAAQ;AACjC,cAAQ,OAAO,GAAG;AAAA,IACpB;AAGA,QAAI,WAAW,QAAQ;AACrB,iBAAW,WAAW,MAAM;AAC1B,mBAAW;AACX,iBAAS;AACT,cAAM,MAAM,SAAS;AACrB,YAAI,SAAS;AACb,gBAAQ,QAAQ,GAAG;AAAA,MACrB,GAAG,EAAE;AAAA,IACP;AAAA,EACF;AAEA,UAAQ,MAAM,GAAG,QAAQ,MAAM;AAE/B,SAAO,MAAY;AACjB,YAAQ,MAAM,IAAI,QAAQ,MAAM;AAChC,QAAI,aAAa,MAAM;AACrB,mBAAa,QAAQ;AACrB,iBAAW;AAAA,IACb;AAAA,EACF;AACF;AAIO,SAAS,SAAS,UAAkC;AACzD,QAAM,iBAAiB,MAAY,SAAS;AAC5C,QAAM,aAAa,MAAY,SAAS;AAExC,UAAQ,OAAO,GAAG,UAAU,cAAc;AAC1C,UAAQ,GAAG,YAAY,UAAU;AAEjC,SAAO,MAAY;AACjB,YAAQ,OAAO,IAAI,UAAU,cAAc;AAC3C,YAAQ,IAAI,YAAY,UAAU;AAAA,EACpC;AACF;AA5RA,IAwNI;AAxNJ;AAAA;AAAA;AAwNA,IAAI,mBAAuD;AAAA;AAAA;;;ACxN3D,SAAS,eAAe;AACxB,SAAS,UAAU,YAAY;AAExB,SAAS,YAAoB;AAClC,SAAO,KAAK,QAAQ,GAAG,WAAW;AACpC;AAEO,SAAS,aAAqB;AACnC,SAAO,KAAK,UAAU,GAAG,aAAa;AACxC;AAEO,SAAS,mBAA2B;AACzC,SAAO,KAAK,UAAU,GAAG,aAAa;AACxC;AAcO,SAAS,WAAWC,MAAqB;AAC9C,SAAO,KAAKA,MAAK,WAAW;AAC9B;AAEO,SAAS,kBAAkBA,MAAqB;AACrD,SAAO,KAAK,WAAWA,IAAG,GAAG,aAAa;AAC5C;AAkCO,SAAS,YAAYA,MAAqB;AAC/C,SAAO,KAAK,WAAWA,IAAG,GAAG,UAAU;AACzC;AAEO,SAAS,WAAWA,MAAaC,YAA2B;AACjE,SAAO,KAAK,YAAYD,IAAG,GAAGC,UAAS;AACzC;AAEO,SAAS,UAAUD,MAAaC,YAA2B;AAChE,SAAO,KAAK,WAAWD,MAAKC,UAAS,GAAG,YAAY;AACtD;AAEO,SAAS,WAAWD,MAAaC,YAA2B;AACjE,SAAO,KAAK,WAAWD,MAAKC,UAAS,GAAG,SAAS;AACnD;AAcO,SAAS,WAAWD,MAAaC,YAA2B;AACjE,SAAO,KAAK,WAAWD,MAAKC,UAAS,GAAG,SAAS;AACnD;AAEO,SAAS,YAAYD,MAAaC,YAA2B;AAClE,SAAO,KAAK,WAAWD,MAAKC,UAAS,GAAG,YAAY;AACtD;AAEO,SAAS,SAASD,MAAaC,YAA2B;AAC/D,SAAO,KAAK,WAAWD,MAAKC,UAAS,GAAG,SAAS;AACnD;AAMO,SAAS,aAAaD,MAAaC,YAA2B;AACnE,SAAO,KAAK,WAAWD,MAAKC,UAAS,GAAG,aAAa;AACvD;AAEO,SAAS,WAAWD,MAAaC,YAA2B;AACjE,SAAO,KAAK,WAAWD,MAAKC,UAAS,GAAG,aAAa;AACvD;AAEO,SAAS,QAAQD,MAAaC,YAA2B;AAC9D,SAAO,KAAK,WAAWD,MAAKC,UAAS,GAAG,MAAM;AAChD;AAyBO,SAAS,OAAOD,MAAaC,YAA2B;AAC7D,SAAO,KAAK,WAAWD,MAAKC,UAAS,GAAG,KAAK;AAC/C;AAEO,SAAS,YAAYD,MAAaC,YAAmBC,QAAuB;AACjF,SAAO,KAAK,OAAOF,MAAKC,UAAS,GAAGC,MAAK;AAC3C;AAEO,SAAS,YAAYF,MAAaC,YAAmBC,QAAuB;AACjF,SAAO,KAAK,YAAYF,MAAKC,YAAWC,MAAK,GAAG,WAAW;AAC7D;AAEO,SAAS,iBAAiBF,MAAaC,YAAmBC,QAAuB;AACtF,SAAO,KAAK,YAAYF,MAAKC,YAAWC,MAAK,GAAG,gBAAgB;AAClE;AAEO,SAAS,cAAcF,MAAaC,YAAmBC,QAAuB;AACnF,SAAO,KAAK,YAAYF,MAAKC,YAAWC,MAAK,GAAG,aAAa;AAC/D;AAEO,SAAS,gBAAgBF,MAAaC,YAAmBC,QAAuB;AACrF,SAAO,KAAK,YAAYF,MAAKC,YAAWC,MAAK,GAAG,eAAe;AACjE;AAcO,SAAS,gBAAgBF,MAAa,cAA8B;AAGzE,SAAO,SAAS,SAASA,IAAG,CAAC,IAAI,YAAY;AAC/C;AAUO,SAAS,gBAAwB;AACtC,SAAO,KAAK,UAAU,GAAG,gBAAgB;AAC3C;AAMO,SAAS,iBAAyB;AACvC,SAAO,KAAK,UAAU,GAAG,SAAS;AACpC;AAEO,SAAS,kBAAkBC,YAA2B;AAC3D,SAAO,KAAK,eAAe,GAAGA,UAAS;AACzC;AAlNA;AAAA;AAAA;AAAA;AAAA;;;ACAA,OAAOE,kBAAiB;AAoBjB,SAAS,WAAW,OAAuB;AAChD,QAAM,OAAO,UAAU,KAAK;AAC5B,MAAI,SAAS,OAAW,OAAM,IAAI,MAAM,kBAAkB,KAAK,EAAE;AACjE,SAAO;AACT;AAIO,SAAS,WAAW,MAAqB;AAC9C,MAAI,MAAM;AACV,aAAW,KAAK,MAAM;AACpB,UAAM,QAAkB,CAAC;AACzB,QAAI,EAAE,KAAM,OAAM,KAAK,GAAG;AAC1B,QAAI,EAAE,IAAK,OAAM,KAAK,GAAG;AACzB,QAAI,EAAE,OAAQ,OAAM,KAAK,GAAG;AAC5B,QAAI,EAAE,cAAe,OAAM,KAAK,GAAG;AACnC,QAAI,EAAE,QAAS,OAAM,KAAK,GAAG;AAC7B,QAAI,EAAE,GAAI,OAAM,KAAK,EAAE,EAAE;AAAA,aAChB,EAAE,MAAO,OAAM,KAAK,OAAO,WAAW,EAAE,KAAK,CAAC,CAAC;AACxD,QAAI,EAAE,GAAI,OAAM,KAAK,EAAE,EAAE;AACzB,QAAI,MAAM,SAAS,GAAG;AACpB,aAAO,QAAQ,MAAM,KAAK,GAAG,CAAC,IAAI,EAAE,IAAI;AAAA,IAC1C,OAAO;AACL,aAAO,EAAE;AAAA,IACX;AAAA,EACF;AACA,SAAO;AACT;AAaO,SAAS,kBAAkB,OAAe,QAA6B;AAC5E,MAAI,UAAU,kBAAkB;AAC9B,kBAAc,IAAI,OAAO,KAAK;AAC9B,uBAAmB;AAAA,EACrB;AACA,QAAM,QAAQ,IAAI,MAAc,MAAM;AACtC,WAAS,IAAI,GAAG,IAAI,QAAQ,IAAK,OAAM,CAAC,IAAI;AAC5C,SAAO,EAAE,OAAO,OAAO,OAAO;AAChC;AAKO,SAAS,SAAS,KAAkB,KAAe,UAAkB,OAAqB;AAC/F,WAAS,IAAI,GAAG,IAAI,SAAS,WAAW,IAAI,IAAI,QAAQ,KAAK;AAC3D,QAAI,MAAM,WAAW,CAAC,IAAI,IAAI,WAAW,CAAC;AAAA,EAC5C;AACF;AAIO,SAAS,WAAW,OAAiBC,YAAqB,QAAyB;AACxF,MAAI,MAAM;AACV,WAAS,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK;AACrC,QAAI,MAAM,CAAC,MAAMA,WAAU,CAAC,GAAG;AAC7B,aAAO,QAAQ,IAAI,CAAC;AACpB,aAAO;AACP,aAAO,MAAM,CAAC;AAAA,IAChB;AAAA,EACF;AACA,MAAI,OAAQ,QAAO;AACnB,SAAO;AACP,SAAO;AACT;AAYO,SAAS,SAAS,SAAiB,UAA0B;AAClE,MAAI,MAAM;AACV,MAAI,eAAe;AACnB,MAAI,IAAI;AAER,SAAO,IAAI,QAAQ,QAAQ;AACzB,QAAI,QAAQ,CAAC,MAAM,UAAU,QAAQ,IAAI,CAAC,MAAM,KAAK;AACnD,YAAM,SAAS,QAAQ,SAAS,CAAC;AACjC,UAAI,SAAS,GAAG;AACd,eAAO,QAAQ,UAAU,GAAG,IAAI,MAAM;AACtC,aAAK;AACL;AAAA,MACF;AAAA,IACF;AACA,UAAM,KAAK,QAAQ,YAAY,CAAC;AAEhC,QAAI,KAAK,MAAQ,OAAO,IAAM;AAAE;AAAK;AAAA,IAAU;AAC/C,UAAM,KAAK,OAAO,cAAc,EAAE;AAClC,UAAM,UAAU,KAAK,MAAM,IAAID,aAAY,EAAE;AAC7C,QAAI,eAAe,UAAU,SAAU;AACvC,WAAO;AACP,oBAAgB;AAChB,SAAK,GAAG;AAAA,EACV;AAEA,MAAI,IAAI,SAAS,OAAO,KAAK,CAAC,IAAI,SAAS,SAAS,GAAG;AACrD,WAAO;AAAA,EACT;AAEA,QAAM,YAAY,WAAW;AAC7B,MAAI,YAAY,EAAG,QAAO,IAAI,OAAO,SAAS;AAC9C,SAAO;AACT;AAKA,SAAS,iBAAiB,GAAmB;AAC3C,MAAI,IAAI;AACR,MAAI,IAAI;AACR,SAAO,IAAI,EAAE,QAAQ;AACnB,QAAI,EAAE,CAAC,MAAM,UAAU,EAAE,IAAI,CAAC,MAAM,KAAK;AACvC,YAAM,MAAM,QAAQ,GAAG,CAAC;AACxB,UAAI,MAAM,GAAG;AAAE,aAAK;AAAK;AAAA,MAAU;AAAA,IACrC;AACA,UAAM,KAAK,EAAE,YAAY,CAAC;AAC1B,UAAM,KAAK,OAAO,cAAc,EAAE;AAClC,SAAK,KAAK,MAAM,IAAIA,aAAY,EAAE;AAClC,SAAK,GAAG;AAAA,EACV;AACA,SAAO;AACT;AAMA,SAAS,QAAQ,GAAW,GAAmB;AAE7C,MAAI,IAAI,IAAI;AACZ,QAAM,MAAM,EAAE;AAEd,SAAO,IAAI,KAAK;AACd,UAAM,IAAI,EAAE,WAAW,CAAC;AACxB,QAAK,KAAK,MAAQ,KAAK,MAAS,MAAM,IAAM;AAC1C;AAAA,IACF,OAAO;AACL;AAAA,IACF;AAAA,EACF;AAEA,MAAI,IAAI,KAAK;AACX,UAAM,IAAI,EAAE,WAAW,CAAC;AACxB,QAAK,KAAK,MAAQ,KAAK,MAAU,KAAK,MAAQ,KAAK,KAAO;AACxD,aAAO,IAAI,IAAI;AAAA,IACjB;AAAA,EACF;AACA,SAAO;AACT;AAcO,SAAS,QAAQ,KAAkB,GAAW,GAAW,SAAuB;AACrF,MAAI,IAAI,KAAK,KAAK,IAAI,OAAQ;AAC9B,MAAI,IAAI,KAAK,KAAK,IAAI,MAAO;AAE7B,QAAM,WAAW,IAAI,MAAM,CAAC;AAC5B,QAAM,sBAAsBA,aAAY,QAAQ,QAAQ,SAAS,EAAE,CAAC;AAKpE,QAAM,SAAS,iBAAiB,UAAU,GAAG,CAAC;AAC9C,QAAM,SAAS,iBAAiB,UAAU,IAAI,qBAAqB,IAAI,OAAO,IAAI;AAGlF,QAAM,cAAcA,aAAY,OAAO,QAAQ,SAAS,EAAE,CAAC;AAC3D,QAAM,eAAe,SAAS,IAAI,OAAO,KAAK,IAAI,GAAG,IAAI,WAAW,CAAC;AAErE,MAAI,MAAM,CAAC,IAAI,eAAe,UAAU;AAC1C;AAMO,SAAS,aACd,KACA,GACA,GACA,SACA,UACM;AACN,MAAI,IAAI,KAAK,KAAK,IAAI,OAAQ;AAC9B,MAAI,IAAI,KAAK,KAAK,IAAI,MAAO;AAE7B,MAAI,MAAM;AACV,MAAI,eAAe;AACnB,MAAI,IAAI;AAER,SAAO,IAAI,QAAQ,QAAQ;AAEzB,QAAI,QAAQ,CAAC,MAAM,UAAU,QAAQ,IAAI,CAAC,MAAM,KAAK;AACnD,YAAM,SAAS,QAAQ,SAAS,CAAC;AACjC,UAAI,SAAS,GAAG;AACd,eAAO,QAAQ,UAAU,GAAG,IAAI,MAAM;AACtC,aAAK;AACL;AAAA,MACF;AAAA,IACF;AAGA,UAAM,KAAK,QAAQ,YAAY,CAAC;AAEhC,QAAI,KAAK,MAAQ,OAAO,IAAM;AAAE;AAAK;AAAA,IAAU;AAC/C,UAAM,KAAK,OAAO,cAAc,EAAE;AAClC,UAAM,UAAU,KAAK,MAAM,IAAIA,aAAY,EAAE;AAE7C,QAAI,eAAe,UAAU,SAAU;AAEvC,WAAO;AACP,oBAAgB;AAChB,SAAK,GAAG;AAAA,EACV;AAGA,MAAI,IAAI,SAAS,OAAO,KAAK,CAAC,IAAI,SAAS,SAAS,GAAG;AACrD,WAAO;AAAA,EACT;AAGA,QAAM,YAAY,WAAW;AAC7B,MAAI,YAAY,GAAG;AACjB,WAAO,IAAI,OAAO,SAAS;AAAA,EAC7B;AAIA,QAAM,WAAW,IAAI,MAAM,CAAC;AAC5B,QAAM,SAAS,iBAAiB,UAAU,GAAG,CAAC;AAC9C,QAAM,SAAS,iBAAiB,UAAU,IAAI,UAAU,IAAI,OAAO,IAAI;AACvE,QAAM,iBAAiB,iBAAiB,MAAM;AAC9C,QAAM,eAAe,iBAAiB,IAAI,SAAS,IAAI,OAAO,IAAI,cAAc,IAAI;AACpF,MAAI,MAAM,CAAC,IAAI,eAAe,MAAM;AACtC;AAKO,SAAS,YAAY,KAAkB,KAAa,SAAuB;AAChF,QAAM,YAAYA,aAAY,QAAQ,QAAQ,SAAS,EAAE,CAAC;AAC1D,QAAM,IAAI,KAAK,IAAI,GAAG,KAAK,OAAO,IAAI,QAAQ,aAAa,CAAC,CAAC;AAC7D,UAAQ,KAAK,GAAG,KAAK,OAAO;AAC9B;AAIO,SAAS,WACd,KACA,GACA,GACA,GACA,GACA,OACM;AACN,QAAM,MAAM,QAAQ,WAAW,KAAK,CAAC;AACrC,QAAM,QAAQ;AAGd,UAAQ,KAAK,GAAG,GAAG,MAAM,WAAM,SAAI,OAAO,IAAI,CAAC,IAAI,WAAM,KAAK;AAE9D,UAAQ,KAAK,GAAG,IAAI,IAAI,GAAG,MAAM,WAAM,SAAI,OAAO,IAAI,CAAC,IAAI,WAAM,KAAK;AAEtE,WAAS,MAAM,IAAI,GAAG,MAAM,IAAI,IAAI,GAAG,OAAO;AAC5C,YAAQ,KAAK,GAAG,KAAK,MAAM,WAAM,KAAK;AACtC,YAAQ,KAAK,IAAI,IAAI,GAAG,KAAK,MAAM,WAAM,KAAK;AAAA,EAChD;AACF;AAiFO,SAAS,eACd,MACA,OACA,QACA,SACA,aACA,eACU;AACV,QAAM,EAAE,GAAG,EAAE,IAAI;AACjB,QAAM,OAAO,IAAI,MAAc,CAAC;AAEhC,QAAM,QAAQ,UAAU,SAAS;AACjC,QAAM,MAAM,QAAQ,WAAW,KAAK,CAAC;AACrC,QAAM,QAAQ;AACd,QAAM,SAAS,IAAI;AACnB,QAAM,SAAS,IAAI;AACnB,QAAM,aAAa,IAAI,OAAO,MAAM;AAGpC,OAAK,CAAC,IAAI,MAAM,WAAM,SAAI,OAAO,IAAI,CAAC,IAAI,WAAM;AAEhD,OAAK,IAAI,CAAC,IAAI,MAAM,WAAM,SAAI,OAAO,IAAI,CAAC,IAAI,WAAM;AAGpD,QAAM,UAAU,MAAM,WAAM,QAAQ;AACpC,QAAM,UAAU,MAAM,MAAM,WAAM;AAClC,QAAM,WAAW,UAAU,aAAa;AACxC,WAAS,IAAI,GAAG,IAAI,IAAI,GAAG,IAAK,MAAK,CAAC,IAAI;AAE1C,MAAI,UAAU,KAAK,UAAU,EAAG,QAAO;AAGvC,MAAI;AACJ,MAAI,iBAAiB,cAAc,UAAU,OAAO;AAClD,gBAAY,cAAc;AAAA,EAC5B,OAAO;AACL,gBAAY,IAAI,MAAc,MAAM,MAAM;AAC1C,aAAS,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK;AACrC,gBAAU,CAAC,IAAI,WAAW,MAAM,CAAC,CAAE;AAAA,IACrC;AACA,QAAI,eAAe;AACjB,oBAAc,QAAQ;AACtB,oBAAc,OAAO;AAAA,IACvB;AAAA,EACF;AAGA,QAAM,cAAc,MAAM,SAAS;AACnC,QAAM,YAAY,cAAc,SAAS,IAAI;AAC7C,QAAM,YAAY,KAAK,IAAI,GAAG,MAAM,SAAS,SAAS;AACtD,SAAO,OAAO,SAAS;AACvB,QAAM,kBAAkB,OAAO;AAG/B,WAAS,IAAI,GAAG,IAAI,aAAa,kBAAkB,IAAI,UAAU,QAAQ,KAAK;AAC5E,UAAM,UAAU,SAAS,UAAU,kBAAkB,CAAC,GAAI,MAAM;AAChE,SAAK,IAAI,CAAC,IAAI,UAAU,UAAU;AAAA,EACpC;AAGA,MAAI,aAAa;AACf,UAAM,YAAY,YAAY,IAAI,KAAK,MAAO,kBAAkB,YAAa,GAAG,IAAI;AACpF,UAAM,YAAY,YAAO,SAAS,UAAO,MAAM,MAAM;AACrD,UAAM,UAAU,SAAS,UAAU,SAAS,WAAW,MAAM;AAC7D,SAAK,IAAI,SAAS,IAAI,UAAU,UAAU;AAAA,EAC5C;AAEA,SAAO;AACT;AAKO,SAAS,oBACd,MACA,SACA,aACA,YACU;AACV,QAAM,EAAE,GAAG,EAAE,IAAI;AACjB,QAAM,OAAO,IAAI,MAAc,CAAC;AAChC,QAAM,QAAQ,UAAU,SAAS;AACjC,QAAM,MAAM,QAAQ,WAAW,KAAK,CAAC;AACrC,QAAM,QAAQ;AACd,QAAM,SAAS,IAAI;AACnB,QAAM,UAAU,MAAM,WAAM,QAAQ;AACpC,QAAM,UAAU,MAAM,MAAM,WAAM;AAClC,QAAM,WAAW,UAAU,IAAI,OAAO,MAAM,IAAI;AAEhD,OAAK,CAAC,IAAI,MAAM,WAAM,SAAI,OAAO,IAAI,CAAC,IAAI,WAAM;AAChD,OAAK,IAAI,CAAC,IAAI,MAAM,WAAM,SAAI,OAAO,IAAI,CAAC,IAAI,WAAM;AACpD,WAAS,IAAI,GAAG,IAAI,IAAI,GAAG,IAAK,MAAK,CAAC,IAAI;AAE1C,MAAI,YAAY;AACd,UAAM,SAAS,KAAK,MAAM,IAAI,CAAC;AAC/B,QAAI,SAAS,KAAK,SAAS,IAAI,GAAG;AAChC,YAAM,UAAU,SAAS,YAAY,MAAM;AAE3C,YAAM,QAAQ,iBAAiB,UAAU;AACzC,YAAM,MAAM,KAAK,IAAI,GAAG,KAAK,OAAO,SAAS,SAAS,CAAC,CAAC;AACxD,YAAM,WAAW,IAAI,OAAO,GAAG,IAAI;AACnC,WAAK,MAAM,IAAI,UAAU,SAAS,UAAU,MAAM,IAAI;AAAA,IACxD;AAAA,EACF;AAEA,SAAO;AACT;AAQA,SAAS,iBAAiB,GAAW,OAAe,KAAa,eAAe,OAAe;AAC7F,MAAI,MAAM;AACV,MAAI,MAAM;AACV,MAAI,IAAI;AACR,MAAI,UAAU;AACd,MAAI,aAAa;AAIjB,MAAI,aAAa;AAEjB,SAAO,IAAI,EAAE,UAAU,MAAM,KAAK;AAEhC,QAAI,EAAE,CAAC,MAAM,UAAU,EAAE,IAAI,CAAC,MAAM,KAAK;AACvC,YAAM,SAAS,QAAQ,GAAG,CAAC;AAC3B,UAAI,SAAS,GAAG;AACd,cAAM,MAAM,EAAE,UAAU,GAAG,IAAI,MAAM;AACrC,YAAI,OAAO,OAAO;AAChB,iBAAO;AAEP,uBAAa,QAAQ,aAAa,QAAQ;AAAA,QAC5C,WAAW,cAAc;AAEvB,cAAI,QAAQ,aAAa,QAAQ,UAAU;AACzC,yBAAa;AAAA,UACf,OAAO;AACL,0BAAc;AAAA,UAChB;AAAA,QACF;AACA,aAAK;AACL;AAAA,MACF;AAAA,IACF;AAEA,UAAM,KAAK,EAAE,YAAY,CAAC;AAC1B,UAAM,KAAK,OAAO,cAAc,EAAE;AAClC,UAAM,UAAU,KAAK,MAAM,IAAIA,aAAY,EAAE;AAE7C,QAAI,OAAO,OAAO;AAChB,gBAAU;AAEV,UAAI,MAAM,UAAU,IAAK;AACzB,aAAO;AAAA,IACT;AAEA,WAAO;AACP,SAAK,GAAG;AAAA,EACV;AAGA,MAAI,WAAW,YAAY;AACzB,WAAO;AAAA,EACT;AAGA,MAAI,gBAAgB,YAAY;AAC9B,UAAM,aAAa;AAAA,EACrB;AAEA,SAAO;AACT;AAvjBA,IAQa,WAiDT,aACA,kBAuCE;AAjGN;AAAA;AAAA;AAQO,IAAM,YAAoC;AAAA,MAC/C,OAAO;AAAA,MACP,KAAK;AAAA,MACL,OAAO;AAAA,MACP,QAAQ;AAAA,MACR,MAAM;AAAA,MACN,SAAS;AAAA,MACT,MAAM;AAAA,MACN,OAAO;AAAA,MACP,MAAM;AAAA,IACR;AAuCA,IAAI,cAAc;AAClB,IAAI,mBAAmB;AAuCvB,IAAM,UAAU;AAAA;AAAA;;;ACjGhB,SAAS,gBAAAE,qBAAoB;AAuD7B,SAAS,aAAa,UAAmC;AACvD,MAAI;AACF,UAAM,UAAUA,cAAa,UAAU,OAAO;AAC9C,WAAO,KAAK,MAAM,OAAO;AAAA,EAC3B,QAAQ;AACN,WAAO,CAAC;AAAA,EACV;AACF;AAEO,SAAS,WAAWC,MAAqB;AAC9C,QAAM,eAAe,aAAa,iBAAiB,CAAC;AACpD,QAAM,gBAAgB,aAAa,kBAAkBA,IAAG,CAAC;AACzD,MAAI,cAAc,WAAW,QAAW;AACtC,YAAQ;AAAA,MACN;AAAA,IACF;AACA,WAAO,cAAc;AAAA,EACvB;AACA,QAAM,SAAiB,EAAE,GAAG,gBAAgB,GAAG,cAAc,GAAG,cAAc;AAC9E,MAAI,aAAa,aAAa,cAAc,WAAW;AACrD,WAAO,YAAY;AAAA,MACjB,GAAG,OAAO;AAAA,MACV,GAAG,aAAa;AAAA,MAChB,GAAG,cAAc;AAAA,MACjB,QAAQ;AAAA,QACN,GAAG,OAAO,WAAW;AAAA,QACrB,GAAG,aAAa,WAAW;AAAA,QAC3B,GAAG,cAAc,WAAW;AAAA,MAC9B;AAAA,MACA,UAAU;AAAA,QACR,GAAG,OAAO,WAAW;AAAA,QACrB,GAAG,aAAa,WAAW;AAAA,QAC3B,GAAG,cAAc,WAAW;AAAA,MAC9B;AAAA,IACF;AAAA,EACF;AACA,SAAO;AACT;AA5FA,IAwCM;AAxCN;AAAA;AAAA;AACA;AAuCA,IAAM,iBAAyB;AAAA,MAC7B,OAAO;AAAA,MACP,gBAAgB;AAAA,MAChB,oBAAoB;AAAA,MACpB,aAAa;AAAA,MACb,eAAe;AAAA,QACb,SAAS;AAAA,QACT,OAAO;AAAA,MACT;AAAA,MACA,gBAAgB;AAAA,MAChB,iBAAiB;AAAA,QACf,EAAE,MAAM,WAAW,aAAa,cAAc;AAAA,MAChD;AAAA,IACF;AAAA;AAAA;;;ACrDA,SAAS,gBAAgB,aAAAC,YAAW,iBAAAC,gBAAe,cAAAC,aAAY,eAAAC,cAAa,gBAAAC,eAAc,UAAAC,SAAQ,gBAAgB;AAClH,SAAS,cAAAC,mBAAkB;AAC3B,SAAS,WAAAC,UAAS,QAAAC,aAAY;AAF9B;AAAA;AAAA;AAGA;AAAA;AAAA;;;ACHA,SAAS,cAAAC,mBAAkB;AAC3B,SAAS,WAAAC,UAAS,QAAAC,aAAY;AAC9B,SAAS,cAAAC,aAAY,iBAAAC,sBAAqB;AAEnC,SAAS,YAAY,UAAkB,MAAoB;AAChE,QAAM,MAAMH,SAAQ,QAAQ;AAC5B,QAAM,UAAUC,MAAK,KAAK,WAAWF,YAAW,CAAC,MAAM;AACvD,EAAAI,eAAc,SAAS,MAAM,OAAO;AACpC,EAAAD,YAAW,SAAS,QAAQ;AAC9B;AAIA,eAAsB,SAAY,KAAa,IAAyB;AACtE,QAAM,OAAO,MAAM,IAAI,GAAG,KAAK,QAAQ,QAAQ;AAC/C,MAAIE;AACJ,QAAM,OAAO,IAAI,QAAc,OAAK;AAAE,IAAAA,WAAU;AAAA,EAAG,CAAC;AACpD,QAAM,IAAI,KAAK,IAAI;AACnB,QAAM;AACN,MAAI;AACF,WAAO,GAAG;AAAA,EACZ,UAAE;AACA,IAAAA,SAAQ;AACR,QAAI,MAAM,IAAI,GAAG,MAAM,MAAM;AAC3B,YAAM,OAAO,GAAG;AAAA,IAClB;AAAA,EACF;AACF;AA3BA,IAWM;AAXN;AAAA;AAAA;AAWA,IAAM,QAAQ,oBAAI,IAA2B;AAAA;AAAA;;;ACX7C,SAAS,cAAAC,aAAY,gBAAAC,eAAc,iBAAAC,sBAAqB;AACxD,SAAS,QAAAC,aAAY;AADrB;AAAA;AAAA;AAAA;AAAA;;;ACAA;AAAA;AAAA;AAAA;AAAA;;;ACAA,SAAS,cAAc,QAAQ,cAAAC,aAAY,aAAAC,YAAW,gBAAAC,eAAc,eAAAC,cAAa,UAAAC,SAAQ,YAAAC,WAAU,iBAAAC,sBAAqB;AACxH,SAAS,QAAAC,aAAY;AADrB;AAAA;AAAA;AAEA;AACA;AACA;AAEA;AAAA;AAAA;;;ACNO,SAAS,WAAW,GAAmB;AAC5C,SAAO,IAAI,EAAE,QAAQ,MAAM,OAAO,CAAC;AACrC;AAFA;AAAA;AAAA;AAAA;AAAA;;;ACAA,SAAS,OAAO,YAAAC,iBAAmC;AACnD,SAAS,iBAAAC,gBAAe,aAAAC,YAAW,cAAAC,mBAAkB;AACrD,SAAS,QAAAC,cAAY;AACrB,SAAS,WAAAC,gBAAe;AAHxB,IAqBM,aAEA;AAvBN;AAAA;AAAA;AAIA;AAiBA,IAAM,cAAc,aAAa,QAAQ,SAAS,KAAK,CAAC;AAExD,IAAM,gBAAgB;AAAA,MACpB;AAAA,MACA;AAAA,MACA,gBAAgB,WAAW;AAAA,MAC3B;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF,EAAE,KAAK,IAAI;AAAA;AAAA;;;AC7DX,SAAS,cAAAC,aAAY,aAAAC,YAAW,gBAAAC,eAAc,eAAAC,oBAAmB;AAwF1D,SAAS,cAAcC,MAAaC,YAAmBC,QAA4B;AACxF,QAAM,IAAI,iBAAiBF,MAAKC,YAAWC,MAAK;AAChD,MAAI;AAEF,WAAO,KAAK,MAAMJ,cAAa,GAAG,EAAE,UAAU,QAAQ,CAAC,CAAC;AAAA,EAC1D,SAAS,IAAI;AACX,WAAO;AAAA,EACT;AACF;AAgBO,SAAS,aACdE,MAAaC,YAAmBC,QAC8B;AAC9D,QAAM,IAAI,gBAAgBF,MAAKC,YAAWC,MAAK;AAC/C,MAAI;AACF,UAAM,OAAO,KAAK,MAAMJ,cAAa,GAAG,EAAE,UAAU,QAAQ,CAAC,CAAC;AAC9D,QAAI,CAAC,MAAM,QAAQ,KAAK,WAAW,CAAC,EAAG,QAAO;AAC9C,WAAO,EAAE,WAAW,KAAK,WAAW,GAA4B,SAAS,KAAK,SAAS,EAAY;AAAA,EACrG,SAAS,IAAI;AACX,WAAO;AAAA,EACT;AACF;AAEO,SAAS,YACdE,MAAaC,YAAmBC,QAChC,WAAkC,aAC5B;AACN,cAAY,cAAcF,MAAKC,YAAWC,MAAK,GAAG,KAAK,UAAU;AAAA,IAC/D;AAAA,IACA,aAAa,gBAAe,oBAAI,KAAK,GAAE,YAAY;AAAA,EACrD,GAAG,MAAM,CAAC,CAAC;AACb;AAEO,SAAS,SAASF,MAAaC,YAAmBC,QAA+B;AACtF,QAAM,IAAI,YAAYF,MAAKC,YAAWC,MAAK;AAC3C,MAAI,CAACN,YAAW,CAAC,GAAG;AAClB,WAAO;AAAA,EACT;AACA,SAAO,KAAK,MAAME,cAAa,GAAG,OAAO,CAAC;AAC5C;AAEA,eAAsB,WACpBE,MAAaC,YAAmBC,QAAe,OAC7B;AAClB,SAAO,SAASA,QAAO,MAAM;AAC3B,UAAM,MAAM,SAASF,MAAKC,YAAWC,MAAK;AAC1C,QAAI,CAAC,KAAK;AACR,YAAM,IAAI,MAAM,qBAAqBA,MAAK,YAAY;AAAA,IACxD;AACA,UAAM,OAAgB,EAAE,GAAG,KAAK,GAAG,MAAM;AACzC,gBAAY,YAAYF,MAAKC,YAAWC,MAAK,GAAG,KAAK,UAAU,MAAM,MAAM,CAAC,CAAC;AAC7E,WAAO;AAAA,EACT,CAAC;AACH;AA3JA;AAAA;AAAA;AACA;AAIA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;;;ACVA;AAAA;AAAA;AAAA;AAAA,SAAS,cAAAC,cAAY,WAAW,mBAAmB;AACnD,SAAS,cAAAC,mBAA0E;AAqBnF,eAAsB,aAAa,MAAuC;AACxE,QAAM,EAAE,KAAAC,MAAK,WAAAC,YAAW,OAAAC,OAAM,IAAI;AAElC,QAAM,OAAO,SAASF,MAAKC,YAAWC,MAAK;AAC3C,MAAI,CAAC,QAAQ,KAAK,WAAW,YAAY;AACvC;AAAA,EACF;AAEA,QAAM,OAAO,cAAcF,MAAKC,YAAWC,MAAK;AAChD,MAAI,CAAC,KAAM;AAEX,QAAM,kBAAkB,cAAc;AAEtC,MAAI,UAAU;AACd,MAAI,QAA6B;AACjC,MAAIC,aAAsB,CAAC;AAC3B,MAAI,eAAoC;AACxC,MAAI,aAAkC;AACtC,QAAM,aAAa,cAAcH,MAAKC,YAAWC,MAAK;AAEtD,QAAM,OAAO,CAAC,SAAuB;AACnC,QAAI,QAAS;AACb,cAAU;AACV,QAAI;AAAE,qBAAe;AAAA,IAAG,QAAQ;AAAA,IAAoB;AACpD,QAAI;AAAE,mBAAa;AAAA,IAAG,QAAQ;AAAA,IAAoB;AAClD,QAAI;AAAE,aAAO,QAAQ;AAAA,IAAG,QAAQ;AAAA,IAAoB;AACpD,QAAI;AAAE,kBAAY,YAAY,gBAAgB;AAAA,IAAG,QAAQ;AAAA,IAAoB;AAC7E,oBAAgB;AAChB,YAAQ,KAAK,IAAI;AAAA,EACnB;AAEA,QAAM,YAAY,CAAC,UAA0B;AAC3C,UAAM,MAAM,WAAW,OAAOC,YAAW,WAAW;AACpD,kBAAc,GAAG;AACjB,IAAAA,aAAY;AAAA,EACd;AAEA,QAAM,mBAAmB,MAAY;AACnC,QAAI,QAAS;AACb,QAAI,CAACL,aAAW,UAAU,EAAG;AAC7B,SAAK,CAAC;AAAA,EACR;AAEA,MAAI,gBAAuC,CAAC;AAE5C,QAAM,SAAS,CAAC,cAA2C;AACzD,QAAI,QAAS;AACb,UAAM,YAAY;AAChB,YAAM,eAAc,oBAAI,KAAK,GAAE,YAAY;AAC3C,kBAAYE,MAAKC,YAAWC,QAAO,WAAW,WAAW;AACzD,UAAI;AACF,cAAM,WAAWF,MAAKC,YAAWC,QAAO,EAAE,QAAQ,YAAY,YAAY,CAAC;AAAA,MAC7E,QAAQ;AAAA,MAGR;AACA,WAAK,CAAC;AAAA,IACR,GAAG;AAAA,EACL;AAEA,QAAM,OAAO,QAAQ,OAAO,WAAW;AACvC,QAAM,OAAO,QAAQ,OAAO,QAAQ;AAEpC,UAAQH,YAAW;AAAA,IACjB;AAAA,IACA;AAAA,IACA;AAAA,IACA,cAAc,gBAAgBC,MAAKC,YAAWC,MAAK;AAAA,IACnD,YAAY,CAAC,cAAqC;AAChD,sBAAgB;AAChB,YAAM,MAAM,SAASF,MAAKC,YAAWC,MAAK;AAC1C,UAAI,KAAK,WAAW,WAAW;AAC7B,aAAK,WAAWF,MAAKC,YAAWC,QAAO,EAAE,QAAQ,eAAe,YAAW,oBAAI,KAAK,GAAE,YAAY,EAAE,CAAC,EAAE,MAAM,MAAM;AAAA,QAAoB,CAAC;AAAA,MAC1I;AACA,UAAI,MAAO,WAAU,MAAM,OAAO,CAAC;AAAA,IACrC;AAAA,IACA,YAAY,CAAC,cAAqC;AAChD,aAAO,SAAS;AAAA,IAClB;AAAA;AAAA,IAEA,QAAQ,MAAM;AACZ,aAAO,aAAa;AAAA,IACtB;AAAA,EACF,CAAC;AAED,iBAAe,sBAAsB,CAAC,OAAe,QAAa;AAChE,QAAI,WAAW,CAAC,MAAO;AACvB,UAAM,UAAU,OAAO,GAAG;AAC1B,cAAU,MAAM,OAAO,CAAC;AAAA,EAC1B,CAAC;AAED,eAAa,SAAS,MAAM;AAC1B,QAAI,WAAW,CAAC,MAAO;AACvB,UAAM,UAAU,QAAQ,OAAO,WAAW;AAC1C,UAAM,UAAU,QAAQ,OAAO,QAAQ;AACvC,UAAM,aAAa,SAAS,OAAO;AACnC,IAAAC,aAAY,CAAC;AACb,cAAU,MAAM,OAAO,CAAC;AAAA,EAC1B,CAAC;AAED,YAAU,YAAY,EAAE,UAAU,IAAI,GAAG,gBAAgB;AAIzD,MAAIL,aAAW,UAAU,GAAG;AAC1B,SAAK,CAAC;AACN;AAAA,EACF;AAEA,YAAU,MAAM,OAAO,CAAC;AAMxB,QAAM,IAAI,QAAc,MAAM;AAAA,EAAgD,CAAC;AACjF;AA1IA;AAAA;AAAA;AAEA;AACA;AACA;AACA;AAAA;AAAA;;;ACLA;;;AC+DO,IAAM,mBAAmB,oBAAI,IAAI,CAAC,UAAU,UAAU,CAAC;AAM9D,IAAI,kBAAkB;AACtB,IAAI,WAAgC;AAE7B,SAAS,kBAAkB,IAAsB;AACtD,aAAW;AACb;AAEO,SAAS,gBAAsB;AACpC,MAAI,gBAAiB;AACrB,oBAAkB;AAClB,eAAa,MAAM;AACjB,sBAAkB;AAClB,eAAW;AAAA,EACb,CAAC;AACH;AAMA,IAAM,WAAW;AAEV,IAAM,kBAAN,MAAsB;AAAA,EAC3B,SAAiB;AAAA,EACT,SAAiB;AAAA,EACjB,MAAc;AAAA,EACd,QAA8C;AAAA,EAC9C;AAAA,EAER,YAAY,UAAsB,UAAU,GAAG;AAC7C,SAAK,WAAW;AAChB,SAAK,SAAS;AACd,SAAK,SAAS;AAAA,EAChB;AAAA,EAEQ,gBAAsB;AAC5B,QAAI,KAAK,UAAU,MAAM;AACvB,WAAK,QAAQ,WAAW,MAAM;AAC5B,aAAK,QAAQ;AACb,aAAK,SAAS,KAAK;AACnB,aAAK,SAAS;AAAA,MAChB,GAAG,QAAQ;AAAA,IACb;AAAA,EACF;AAAA,EAEQ,MAAM,OAAuB;AACnC,QAAI,QAAQ,EAAG,QAAO;AACtB,QAAI,QAAQ,KAAK,IAAK,QAAO,KAAK;AAClC,WAAO;AAAA,EACT;AAAA,EAEA,SAAS,OAAqB;AAC5B,SAAK,SAAS,KAAK,MAAM,KAAK,SAAS,KAAK;AAC5C,SAAK,cAAc;AAAA,EACrB;AAAA,EAEA,SAAS,OAAqB;AAC5B,SAAK,SAAS,KAAK,MAAM,KAAK;AAC9B,SAAK,cAAc;AAAA,EACrB;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,OAAO,KAAmB;AACxB,SAAK,MAAM,KAAK,IAAI,GAAG,GAAG;AAC1B,QAAI,KAAK,SAAS,KAAK,IAAK,MAAK,SAAS,KAAK;AAC/C,QAAI,KAAK,SAAS,KAAK,IAAK,MAAK,SAAS,KAAK;AAAA,EACjD;AAAA,EAEA,QAAc;AACZ,QAAI,KAAK,UAAU,MAAM;AACvB,mBAAa,KAAK,KAAK;AACvB,WAAK,QAAQ;AAAA,IACf;AACA,SAAK,SAAS;AACd,SAAK,SAAS;AAAA,EAChB;AAAA,EAEA,UAAgB;AACd,QAAI,KAAK,UAAU,MAAM;AACvB,mBAAa,KAAK,KAAK;AACvB,WAAK,QAAQ;AAAA,IACf;AAAA,EACF;AACF;AAgGO,SAAS,eAAeM,MAAuB;AACpD,QAAM,OAAO,QAAQ,OAAO,WAAW;AACvC,QAAM,OAAO,QAAQ,OAAO,QAAQ;AAEpC,QAAM,eAAe,IAAI,gBAAgB,aAAa;AACtD,QAAM,eAAe,IAAI,gBAAgB,aAAa;AACtD,QAAM,0BAA0B,IAAI,gBAAgB,aAAa;AACjE,QAAM,aAAa,IAAI,gBAAgB,aAAa;AACpD,QAAM,iBAAiB,IAAI,gBAAgB,aAAa;AACxD,QAAM,gBAAgB,IAAI,gBAAgB,aAAa;AAGvD,QAAM,WAAW,oBAAI,IAAY;AACjC,WAAS,IAAI,mBAAmB;AAChC,WAAS,IAAI,iBAAiB;AAE9B,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,aAAa;AAAA,IACb;AAAA,IACA,MAAM;AAAA,IACN,WAAW;AAAA,IACX,mBAAmB;AAAA,IACnB,cAAc;AAAA,IACd,YAAY;AAAA,IACZ,eAAe;AAAA,IACf,cAAc;AAAA,IACd,mBAAmB;AAAA,IACnB;AAAA,IACA;AAAA,IACA,gBAAgB,CAAC;AAAA,IACjB;AAAA,IACA,kBAAkB;AAAA,IAClB,eAAe;AAAA,IACf,oBAAoB,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,EAAE;AAAA,IAC1C,kBAAkB,QAAQ,IAAI,gCAAgC;AAAA,IAC9D,YAAY;AAAA,IACZ,cAAc;AAAA,IACd;AAAA,IACA;AAAA,IACA;AAAA,IACA,oBAAoB;AAAA,IACpB,iBAAiB;AAAA,IACjB,sBAAsB,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,EAAE;AAAA,IAC5C,UAAU,CAAC;AAAA,IACX,iBAAiB;AAAA,IACjB,aAAa;AAAA,IACb,iBAAiB;AAAA,IACjB,aAAa;AAAA,IACb,0BAA0B;AAAA,IAC1B,aAAa;AAAA,IACb,YAAY,CAAC;AAAA,IACb,YAAY;AAAA,IACZ,WAAW;AAAA,IACX,cAAc,CAAC;AAAA,IACf,OAAO;AAAA,IACP,cAAc;AAAA,IACd,WAAW,CAAC;AAAA,IACZ,gBAAgB;AAAA,IAChB,oBAAoB,oBAAI,IAAI;AAAA,IAC5B,iBAAiB;AAAA,IACjB,cAAc;AAAA,IACd,mBAAmB;AAAA,IACnB,gBAAgB;AAAA,IAChB,qBAAqB,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,EAAE;AAAA,IAC3C,mBAAmB;AAAA,IACnB,gBAAgB;AAAA,IAChB,qBAAqB,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,EAAE;AAAA,IAC3C,cAAc;AAAA,IACd,kBAAkB;AAAA,IAClB,kBAAkB;AAAA,IAClB,SAAS,oBAAI,IAAI;AAAA,IACjB,KAAAA;AAAA,EACF;AACF;AAMO,SAAS,OAAOC,QAAiB,KAAmB;AACzD,EAAAA,OAAM,eAAe;AACrB,MAAIA,OAAM,sBAAsB,MAAM;AACpC,iBAAaA,OAAM,iBAAiB;AAAA,EACtC;AACA,EAAAA,OAAM,oBAAoB,WAAW,MAAM;AACzC,IAAAA,OAAM,eAAe;AACrB,IAAAA,OAAM,oBAAoB;AAC1B,kBAAc;AAAA,EAChB,GAAG,GAAM;AACX;AAMO,SAAS,gBAAgBA,QAAiB,OAAyB;AACxE,MAAI,MAAM,WAAW,GAAG;AACtB,IAAAA,OAAM,cAAc;AACpB;AAAA,EACF;AAEA,QAAM,WAAWA,OAAM;AACvB,MAAI,aAAa,MAAM;AACrB,IAAAA,OAAM,eAAe,MAAM,CAAC,GAAG,MAAM;AACrC;AAAA,EACF;AAGA,MAAI,MAAMA,OAAM,WAAW,GAAG,OAAO,SAAU;AAG/C,QAAM,WAAW,MAAM,UAAU,CAAC,MAAM,EAAE,OAAO,QAAQ;AACzD,MAAI,aAAa,IAAI;AACnB,IAAAA,OAAM,cAAc;AAAA,EACtB,OAAO;AAEL,UAAM,UAAU,KAAK,IAAIA,OAAM,aAAa,MAAM,SAAS,CAAC;AAC5D,IAAAA,OAAM,cAAc;AACpB,IAAAA,OAAM,eAAe,MAAM,OAAO,GAAG,MAAM;AAAA,EAC7C;AACF;AAMO,SAAS,gBAAgBA,QAAuB;AACrD,QAAM,kBAAkBA,OAAM;AAC9B,MAAI,CAAC,gBAAiB;AAEtB,QAAM,gBAAgB,WAAW,gBAAgB,EAAE;AACnD,QAAM,SAAS,gBAAgB;AAG/B,MAAI,CAACA,OAAM,SAAS,IAAI,aAAa,GAAG;AACtC,IAAAA,OAAM,iBAAiB,OAAO;AAC9B;AAAA,EACF;AAEA,MAAI,OAAO,WAAW,GAAG;AACvB,IAAAA,OAAM,iBAAiB;AACvB;AAAA,EACF;AAEA,QAAM,SAAS,OAAO,OAAO,SAAS,CAAC;AACvC,QAAM,WAAW,SAAS,gBAAgB,EAAE,IAAI,OAAO,KAAK;AAE5D,MAAI,OAAO,SAASA,OAAM,kBAAkBA,OAAM,iBAAiB,GAAG;AAEpE,UAAM,YAAY,OAAO,OAAO,SAAS,CAAC;AAC1C,QAAI,WAAW;AACb,YAAM,SAAS,SAAS,gBAAgB,EAAE,IAAI,UAAU,KAAK;AAC7D,MAAAA,OAAM,SAAS,OAAO,MAAM;AAC5B,MAAAA,OAAM,SAAS,IAAI,QAAQ;AAAA,IAC7B;AAAA,EACF,WAAW,CAACA,OAAM,SAAS,IAAI,QAAQ,GAAG;AAExC,IAAAA,OAAM,SAAS,IAAI,QAAQ;AAAA,EAC7B;AAEA,EAAAA,OAAM,iBAAiB,OAAO;AAChC;;;AC9ZA,SAAS,gBAAAC,gBAAc,cAAAC,cAAY,eAAAC,cAAa,YAAAC,iBAAgB;AAChE,SAAS,QAAAC,cAAY;;;ACDrB,SAAS,gBAAgB;AACzB,SAAS,gBAAAC,gBAAc,eAAAC,cAAa,YAAAC,iBAAgB;AACpD,SAAS,QAAAC,cAAY;;;ACIrB;AANA,SAAS,gBAAgB;AACzB,SAAS,iBAAiB;AAC1B,SAAS,YAAY,cAAc,WAAW,aAAa,QAAQ,qBAAqB;AACxF,SAAS,WAAAC,gBAAe;AACxB,SAAS,QAAAC,aAAY;AAIrB,SAAS,aAAa,MAAsB;AAC1C,SAAO,KAAK,QAAQ,mBAAmB,GAAG,EAAE,QAAQ,OAAO,GAAG,EAAE,QAAQ,UAAU,EAAE,EAAE,MAAM,GAAG,EAAE;AACnG;AAEA,SAAS,gBAAgB,OAAe,KAAqB;AAC3D,QAAM,QAAO,oBAAI,KAAK,GAAE,YAAY,EAAE,MAAM,GAAG,EAAE;AACjD,YAAU,KAAK,EAAE,WAAW,KAAK,CAAC;AAElC,QAAM,OAAO,YAAY,KAAK,IAAI,IAAI;AACtC,MAAI,YAAYA,MAAK,KAAK,GAAG,IAAI,MAAM;AACvC,MAAI,UAAU;AACd,SAAO,WAAW,SAAS,GAAG;AAC5B;AACA,gBAAYA,MAAK,KAAK,GAAG,IAAI,IAAI,OAAO,MAAM;AAAA,EAChD;AACA,SAAO;AACT;AAEA,SAAS,gBAAwB;AAC/B,SAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAmDT;AAEA,IAAM,gBAAgB,UAAU,QAAQ;AAExC,eAAsB,mBACpBC,YACAC,MACA,SACiB;AACjB,QAAM,SAAS,SAAS,UAAU;AAClC,QAAM,UAAU,WAAWA,MAAKD,UAAS;AACzC,QAAM,UAAU,kBAAkBA,UAAS;AAC3C,QAAM,aAAa,WAAW,OAAO;AACrC,QAAM,aAAa,WAAW,OAAO;AAErC,MAAI,CAAC,cAAc,CAAC,YAAY;AAC9B,UAAM,IAAI,MAAM,6BAA6BA,UAAS,EAAE;AAAA,EAC1D;AAEA,MAAI,QAAQA,WAAU,MAAM,GAAG,CAAC;AAChC,QAAM,SAAS,UAAUC,MAAKD,UAAS;AACvC,MAAI,WAAW,MAAM,GAAG;AACtB,QAAI;AACF,YAAME,SAAQ,KAAK,MAAM,aAAa,QAAQ,OAAO,CAAC;AACtD,UAAIA,OAAM,MAAM;AACd,gBAAQ,aAAaA,OAAM,IAAI;AAAA,MACjC;AAAA,IACF,QAAQ;AAAA,IAAqB;AAAA,EAC/B;AAEA,QAAM,MAAM,SAAS,aAAaH,MAAKD,SAAQ,GAAG,WAAW;AAC7D,QAAM,aAAa,gBAAgB,OAAO,GAAG;AAC7C,QAAM,SAAS,wBAAwBE,WAAU,MAAM,GAAG,CAAC,CAAC,IAAI,KAAK,IAAI,CAAC;AAE1E,MAAI;AACF,cAAU,QAAQ,EAAE,WAAW,KAAK,CAAC;AAErC,kBAAcD,MAAK,QAAQ,WAAW,GAAG,cAAc,GAAG,OAAO;AAEjE,QAAI,YAAY;AACd,kBAAY,SAASA,MAAK,QAAQ,SAAS,CAAC;AAAA,IAC9C;AACA,QAAI,YAAY;AACd,kBAAY,SAASA,MAAK,QAAQ,SAAS,CAAC;AAAA,IAC9C;AAEA,UAAM,QAAQ,CAAC,aAAa,aAAa,aAAa,IAAI,aAAa,aAAa,EAAE,EAAE,OAAO,OAAO;AACtG,UAAM,cAAc,OAAO,CAAC,OAAO,YAAY,GAAG,KAAK,GAAG,EAAE,KAAK,OAAO,CAAC;AAAA,EAC3E,UAAE;AACA,WAAO,QAAQ,EAAE,WAAW,MAAM,OAAO,KAAK,CAAC;AAAA,EACjD;AAEA,MAAI,QAAQ;AACV,QAAI;AACF,YAAM,cAAc,QAAQ,CAAC,MAAM,UAAU,CAAC;AAAA,IAChD,QAAQ;AAAA,IAAkC;AAAA,EAC5C;AAEA,SAAO;AACT;;;AD1HA;;;AEfA,SAAS,QAAAI,aAAY;;;ACArB,OAAO,iBAAiB;;;ACCjB,SAAS,eAAe,WAA4B,QAAgC;AACzF,MAAI;AACJ,MAAI,OAAO,cAAc,UAAU;AACjC,cAAU;AAAA,EACZ,OAAO;AACL,UAAM,QAAQ,IAAI,KAAK,SAAS,EAAE,QAAQ;AAC1C,UAAM,MAAM,SAAS,IAAI,KAAK,MAAM,EAAE,QAAQ,IAAI,KAAK,IAAI;AAC3D,cAAU,MAAM;AAAA,EAClB;AACA,QAAM,eAAe,KAAK,MAAM,UAAU,GAAI;AAC9C,MAAI,eAAe,EAAG,QAAO;AAC7B,QAAM,QAAQ,KAAK,MAAM,eAAe,IAAI;AAC5C,QAAM,UAAU,KAAK,MAAO,eAAe,OAAQ,EAAE;AACrD,QAAM,UAAU,eAAe;AAC/B,MAAI,QAAQ,EAAG,QAAO,GAAG,KAAK,IAAI,OAAO;AACzC,MAAI,UAAU,EAAG,QAAO,GAAG,OAAO,IAAI,OAAO;AAC7C,SAAO,GAAG,OAAO;AACnB;AAGO,SAAS,YAAY,QAAwB;AAClD,UAAQ,QAAQ;AAAA,IACd,KAAK;AAAA,IACL,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AAAA,IACL,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT;AACE,aAAO;AAAA,EACX;AACF;;;ADlCO,SAAS,cAAc,KAAqB;AACjD,QAAM,OAAO,KAAK,IAAI,IAAI,IAAI,KAAK,GAAG,EAAE,QAAQ;AAChD,QAAM,UAAU,KAAK,MAAM,OAAO,GAAK;AACvC,QAAM,QAAQ,KAAK,MAAM,UAAU,EAAE;AACrC,MAAI,QAAQ,EAAG,QAAO,GAAG,KAAK;AAC9B,MAAI,UAAU,EAAG,QAAO,GAAG,OAAO;AAClC,SAAO;AACT;AAEO,SAAS,WAAW,KAAqB;AAC9C,QAAM,IAAI,IAAI,KAAK,GAAG;AACtB,SAAO,GAAG,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,GAAG,GAAG,CAAC,IAAI,EAAE,WAAW,EAAE,SAAS,EAAE,SAAS,GAAG,GAAG,CAAC;AAClG;AAEO,SAAS,SAAS,MAAc,KAAqB;AAE1D,QAAM,QAAQ,KAAK,QAAQ,OAAO,GAAG,EAAE,QAAQ,MAAM,QAAG,EAAE,QAAQ,MAAM,QAAG,EAAE,QAAQ,WAAC,2BAAuB,IAAE,GAAE,EAAE;AACnH,MAAI,MAAM,EAAG,QAAO,MAAM,MAAM,GAAG,GAAG;AACtC,QAAM,IAAI,YAAY,KAAK;AAC3B,MAAI,KAAK,IAAK,QAAO;AAErB,MAAI,SAAS;AACb,SAAO,YAAY,MAAM,IAAI,MAAM,KAAK,OAAO,SAAS,GAAG;AAEzD,UAAM,MAAM,OAAO,YAAY,KAAK,OAAO,SAAS,CAAC;AACrD,QAAI,MAAM,MAAM,KAAK;AACnB,eAAS,OAAO,MAAM,GAAG,GAAG;AAAA,IAC9B,OAAO;AACL,eAAS,OAAO,MAAM,GAAG,OAAO,SAAS,CAAC;AAAA,IAC5C;AAAA,EACF;AACA,SAAO,SAAS;AAClB;AAGO,SAAS,cAAc,MAAsB;AAClD,SAAO,KACJ,QAAQ,gBAAgB,EAAE,EAC1B,QAAQ,kBAAkB,IAAI,EAC9B,QAAQ,cAAc,IAAI,EAC1B,QAAQ,cAAc,IAAI,EAC1B,QAAQ,sBAAsB,EAAE,EAChC,QAAQ,eAAe,EAAE,EACzB,QAAQ,iBAAiB,EAAE,EAC3B,QAAQ,qBAAqB,IAAI,EACjC,QAAQ,WAAW,EAAE,EACrB,QAAQ,SAAS,EAAE,EACnB,QAAQ,QAAQ,GAAG,EACnB,QAAQ,QAAQ,GAAG,EACnB,KAAK;AACV;AAMO,SAAS,qBAAqB,MAAc,QAAwB;AACzE,QAAM,QAAQ,KAAK,MAAM,IAAI;AAC7B,aAAW,QAAQ,OAAO;AACxB,UAAM,UAAU,KAAK,KAAK;AAC1B,QAAI,CAAC,QAAS;AACd,QAAI,QAAQ,WAAW,GAAG,EAAG;AAC7B,QAAI,QAAQ,WAAW,KAAK,EAAG;AAC/B,QAAI,QAAQ,WAAW,KAAK,EAAG;AAC/B,QAAI,QAAQ,WAAW,GAAG,EAAG;AAC7B,QAAI,QAAQ,SAAS,EAAG;AAExB,UAAM,UAAU,cAAc,OAAO;AACrC,QAAI,QAAQ,SAAS,EAAG;AAGxB,UAAM,YAAY,QAAQ,QAAQ,IAAI;AACtC,QAAI,YAAY,MAAM,YAAY,QAAQ;AACxC,aAAO,QAAQ,MAAM,GAAG,YAAY,CAAC;AAAA,IACvC;AACA,WAAO,SAAS,SAAS,MAAM;AAAA,EACjC;AACA,QAAM,WAAW,cAAc,IAAI;AACnC,SAAO,SAAS,UAAU,MAAM;AAClC;AAEO,SAAS,cAAc,WAA4B,QAAgC;AACxF,MAAI;AACJ,MAAI,OAAO,cAAc,UAAU;AACjC,cAAU;AAAA,EACZ,OAAO;AACL,UAAM,QAAQ,IAAI,KAAK,SAAS,EAAE,QAAQ;AAC1C,UAAM,MAAM,SAAS,IAAI,KAAK,MAAM,EAAE,QAAQ,IAAI,KAAK,IAAI;AAC3D,cAAU,MAAM;AAAA,EAClB;AACA,MAAI,UAAU,KAAK,KAAK,IAAM,QAAO;AACrC,MAAI,UAAU,KAAK,KAAK,IAAM,QAAO;AACrC,SAAO;AACT;AAEO,SAAS,gBAAgB,QAAwB;AACtD,UAAQ,QAAQ;AAAA,IACd,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT;AACE,aAAO;AAAA,EACX;AACF;AAEO,SAAS,gBAAgB,QAAwB;AACtD,UAAQ,QAAQ;AAAA,IACd,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT;AACE,aAAO;AAAA,EACX;AACF;AAEO,SAAS,eAAe,WAAmD;AAChF,MAAI,CAAC,UAAW,QAAO;AACvB,QAAM,IAAI,UAAU,YAAY;AAChC,MAAI,EAAE,SAAS,UAAU,EAAG,QAAO;AACnC,MAAI,EAAE,SAAS,WAAW,KAAK,EAAE,SAAS,MAAM,EAAG,QAAO;AAC1D,MAAI,EAAE,SAAS,QAAQ,KAAK,EAAE,SAAS,MAAM,EAAG,QAAO;AACvD,MAAI,EAAE,SAAS,MAAM,EAAG,QAAO;AAC/B,SAAO;AACT;AAEO,SAAS,QAAQ,OAAe,OAAe,UAAa;AACjE,SAAO,KAAK,OAAO,KAAK,IAAI,GAAG,KAAK,CAAC;AACvC;AAGO,SAAS,iBAAiB,SAAyB;AACxD,MAAI,CAAC,QAAQ,WAAW,KAAK,EAAG,QAAO;AACvC,QAAM,MAAM,QAAQ,QAAQ,SAAS,CAAC;AACtC,MAAI,QAAQ,GAAI,QAAO;AACvB,SAAO,QAAQ,MAAM,MAAM,CAAC,EAAE,UAAU;AAC1C;AAGO,SAAS,cAAc,MAAsB;AAClD,SAAO,KACJ,QAAQ,kBAAkB,IAAI,EAC9B,QAAQ,cAAc,IAAI,EAC1B,QAAQ,cAAc,IAAI,EAC1B,QAAQ,YAAY,IAAI,EACxB,QAAQ,qBAAqB,IAAI,EAKjC,QAAQ,MAAM,QAAG,EACjB,QAAQ,MAAM,QAAG,EACjB,QAAQ,WAAC,2BAAuB,IAAE,GAAE,EAAE;AAC3C;AAoBO,SAAS,IAAI,MAAc,MAAwC;AACxE,SAAO,EAAE,MAAM,GAAG,KAAK;AACzB;AAGO,SAAS,WAAW,MAAc,MAA+C;AACtF,SAAO,CAAC,IAAI,MAAM,IAAI,CAAC;AACzB;AAEO,SAAS,mBAAmB,QAAgB,SAA0B;AAC3E,MAAI,WAAW,OAAQ,QAAO;AAC9B,MAAI,WAAW,SAAS;AACtB,QAAI,CAAC,QAAS,OAAM,IAAI,MAAM,uCAAuC;AACrE,WAAO;AAAA,EACT;AACA,SAAO;AACT;AAEO,SAAS,mBAAmB,QAAwB;AACzD,MAAI,WAAW,OAAQ,QAAO;AAC9B,MAAI,WAAW,QAAS,QAAO;AAC/B,SAAO;AACT;AAEO,SAAS,YAAY,MAAgD;AAC1E,SAAO,SAAS,UACZ,EAAE,OAAO,SAAS,OAAO,OAAO,IAChC,EAAE,OAAO,UAAU,OAAO,SAAS;AACzC;AAEO,SAAS,iBAAiB,OAAgE;AAC/F,SAAO,MAAM,SAAS,MAAM,KAAK,MAAM,OAAO,MAAM;AACtD;AAEO,SAAS,eAAe,MAAyC;AACtE,MAAI,CAAC,KAAM,QAAO;AAClB,MAAI,SAAS,iBAAkB,QAAO;AACtC,MAAI,SAAS,WAAY,QAAO;AAChC,MAAI,SAAS,YAAa,QAAO;AACjC,MAAI,SAAS,aAAc,QAAO;AAClC,SAAO;AACT;AAEO,SAAS,SAAS,MAAsB;AAC7C,SAAO,UAAU,IAAI;AACvB;AAEO,SAAS,QAAQ,MAAsB;AAC5C,SAAO,UAAU,IAAI;AACvB;AAEO,SAAS,UAAU,MAAc,OAAe,OAAO,OAAe;AAC3E,QAAM,YAAoC,EAAE,OAAO,IAAI,KAAK,IAAI,OAAO,IAAI,QAAQ,IAAI,MAAM,IAAI,SAAS,IAAI,MAAM,IAAI,OAAO,IAAI,MAAM,GAAG;AAC5I,QAAM,QAAkB,CAAC;AACzB,MAAI,KAAM,OAAM,KAAK,CAAC;AACtB,QAAM,MAAM,UAAU,KAAK;AAC3B,MAAI,QAAQ,OAAW,OAAM,KAAK,GAAG;AACrC,MAAI,MAAM,WAAW,EAAG,QAAO;AAC/B,SAAO,QAAQ,MAAM,KAAK,GAAG,CAAC,IAAI,IAAI;AACxC;AAEO,SAAS,UAAU,MAAuB;AAC/C,MAAI,SAAS,WAAY,QAAO;AAChC,MAAI,SAAS,iBAAkB,QAAO;AACtC,MAAI,SAAS,YAAa,QAAO;AACjC,MAAI,SAAS,aAAc,QAAO;AAClC,SAAO;AACT;AAYO,SAAS,SAAS,MAAc,OAAyB;AAC9D,QAAM,UAAU,cAAc,IAAI;AAClC,MAAI,SAAS,EAAG,QAAO,QAAQ,MAAM,IAAI;AACzC,QAAM,SAAmB,CAAC;AAC1B,aAAW,WAAW,QAAQ,MAAM,IAAI,GAAG;AACzC,QAAI,YAAY,OAAO,KAAK,OAAO;AACjC,aAAO,KAAK,OAAO;AACnB;AAAA,IACF;AAGA,QAAI,YAAY;AAChB,QAAI,YAAY;AAChB,QAAI,eAAe;AAEnB,aAAS,IAAI,GAAG,IAAI,QAAQ,QAAQ,KAAK;AACvC,YAAM,YAAY,YAAY,QAAQ,CAAC,CAAE;AACzC,sBAAgB;AAEhB,UAAI,QAAQ,CAAC,MAAM,IAAK,aAAY;AAEpC,UAAI,eAAe,OAAO;AACxB,YAAI;AACJ,YAAI,YAAY,WAAW;AAEzB,oBAAU;AACV,iBAAO,KAAK,QAAQ,MAAM,WAAW,OAAO,CAAC;AAE7C,sBAAY,UAAU;AACtB,iBAAO,YAAY,QAAQ,UAAU,QAAQ,SAAS,MAAM,IAAK;AAAA,QACnE,OAAO;AAEL,oBAAU,KAAK,IAAI,YAAY,GAAG,CAAC;AACnC,iBAAO,KAAK,QAAQ,MAAM,WAAW,OAAO,CAAC;AAC7C,sBAAY;AAAA,QACd;AAGA,uBAAe,YAAY,QAAQ,MAAM,WAAW,IAAI,CAAC,CAAC;AAC1D,oBAAY;AAAA,MACd;AAAA,IACF;AAEA,QAAI,YAAY,QAAQ,QAAQ;AAC9B,aAAO,KAAK,QAAQ,MAAM,SAAS,CAAC;AAAA,IACtC;AAAA,EACF;AACA,SAAO;AACT;;;ADtSA;AAGA,SAAS,eAAe,GAA2B;AACjD,MAAI,EAAE,WAAW,YAAa,QAAO;AAErC,QAAM,OAAO,EAAE,eAAe;AAC9B,MAAI,EAAE,WAAW,SAAU,QAAO,OAAO,IAAI;AAE7C,SAAO,OAAO,IAAI;AACpB;AAEO,SAAS,UACd,UACA,iBACA,UACAC,MACA,qBAA+B,CAAC,GAChC,iBAAuC,CAAC,GAC5B;AACZ,QAAM,QAAoB,CAAC;AAG3B,QAAM,iBAAiB,oBAAI,IAAkC;AAC7D,aAAW,QAAQ,gBAAgB;AACjC,UAAM,MAAM,eAAe,IAAI,KAAK,SAAS,KAAK,CAAC;AACnD,QAAI,KAAK,IAAI;AACb,mBAAe,IAAI,KAAK,WAAW,GAAG;AAAA,EACxC;AAGA,QAAM,WAA6B,CAAC;AACpC,QAAM,UAA4B,CAAC;AACnC,QAAM,OAAyB,CAAC;AAChC,aAAW,KAAK,UAAU;AACxB,QAAI,eAAe,IAAI,EAAE,EAAE,EAAG,UAAS,KAAK,CAAC;AAAA,aACpC,EAAE,WAAW,YAAa,MAAK,KAAK,CAAC;AAAA,QACzC,SAAQ,KAAK,CAAC;AAAA,EACrB;AAGA,WAAS,KAAK,CAAC,GAAG,MAAM;AACtB,UAAM,SAAS,eAAe,IAAI,EAAE,EAAE;AACtC,UAAM,SAAS,eAAe,IAAI,EAAE,EAAE;AACtC,UAAM,UAAU,KAAK,IAAI,GAAG,OAAO,IAAI,OAAK,KAAK,MAAM,EAAE,YAAY,CAAC,CAAC;AACvE,UAAM,UAAU,KAAK,IAAI,GAAG,OAAO,IAAI,OAAK,KAAK,MAAM,EAAE,YAAY,CAAC,CAAC;AACvE,WAAO,UAAU;AAAA,EACnB,CAAC;AACD,UAAQ,KAAK,CAAC,GAAG,MAAM;AACrB,UAAM,IAAI,eAAe,CAAC,IAAI,eAAe,CAAC;AAC9C,QAAI,MAAM,EAAG,QAAO;AACpB,WAAO,IAAI,KAAK,EAAE,SAAS,EAAE,QAAQ,IAAI,IAAI,KAAK,EAAE,SAAS,EAAE,QAAQ;AAAA,EACzE,CAAC;AAED,OAAK,KAAK,CAAC,GAAG,MAAM,KAAK,MAAM,EAAE,SAAS,IAAI,KAAK,MAAM,EAAE,SAAS,CAAC;AAGrE,WAAS,gBAAgB,KAA0B;AACjD,WAAO,SAAS,IAAI,WAAW,GAAG,EAAE;AAAA,EACtC;AAEA,WAAS,YAAY,KAAiB,OAAqB;AACzD,UAAM,MAAM,gBAAgB,GAAG;AAC/B,UAAM,KAAK;AAAA,MACT,IAAI,WAAW,GAAG;AAAA,MAClB,MAAM;AAAA,MACN,OAAO;AAAA,MACP,SAAS;AAAA,MACT;AAAA,MACA,YAAY;AAAA,MACZ,UAAU;AAAA,MACV,WAAW;AAAA,MACX,QAAQ;AAAA,IACV,CAA2B;AAAA,EAC7B;AAEA,WAAS,oBAAoB,GAAyB;AACpD,QAAI,CAAC,mBAAmB,gBAAgB,OAAO,EAAE,GAAI;AAErD,UAAM,SAAS,CAAC,GAAG,gBAAgB,kBAAkB,EAAE,QAAQ;AAC/D,UAAM,gBAAgB,IAAI;AAAA,MACxB,gBAAgB,mBAAmB,QAAQ,CAAC,MAAM,EAAE,aAAa;AAAA,IACnE;AAEA,eAAW,SAAS,QAAQ;AAC1B,YAAM,cAAc,SAAS,EAAE,EAAE,IAAI,MAAM,KAAK;AAChD,YAAM,gBAAgB,SAAS,IAAI,WAAW;AAE9C,YAAM,cAAc,gBAAgB,OAAO;AAAA,QAAO,CAAC,MACjD,MAAM,cAAc,SAAS,EAAE,EAAE;AAAA,MACnC;AACA,YAAM,WAAW,UAAU,OAAO,CAAC;AACnC,YAAM,aAAa,WACf,gBAAgB,OAAO,OAAO,CAAC,MAAM,CAAC,cAAc,IAAI,EAAE,EAAE,CAAC,IAC7D,CAAC;AACL,YAAM,iBAAiB,CAAC,GAAG,aAAa,GAAG,UAAU;AAErD,YAAM,KAAK;AAAA,QACT,IAAI;AAAA,QACJ,MAAM;AAAA,QACN,OAAO;AAAA,QACP,YAAY,eAAe,SAAS;AAAA,QACpC,UAAU;AAAA,QACV,WAAW,EAAE;AAAA,QACb,aAAa,MAAM;AAAA,QACnB,WAAW,MAAM;AAAA,QACjB,aAAa,MAAM;AAAA,QACnB,UAAU,MAAM;AAAA,QAChB,YAAY,eAAe;AAAA,QAC3B,MAAM,MAAM;AAAA,MACd,CAAyB;AAEzB,UAAI,CAAC,cAAe;AAEpB,iBAAW,SAAS,gBAAgB;AAClC,cAAM,cAAc,SAAS,EAAE,EAAE,IAAI,MAAM,EAAE;AAC7C,cAAM,aAAa,MAAM,QAAQ,SAAS;AAC1C,cAAM,gBAAgB,SAAS,IAAI,WAAW;AAE9C,cAAM,KAAK;AAAA,UACT,IAAI;AAAA,UACJ,MAAM;AAAA,UACN,OAAO;AAAA,UACP,YAAY;AAAA,UACZ,UAAU,iBAAiB;AAAA,UAC3B,WAAW,EAAE;AAAA,UACb,SAAS,MAAM;AAAA,UACf,MAAM,MAAM;AAAA,UACZ,WAAW,MAAM;AAAA,UACjB,QAAQ,MAAM;AAAA,UACd,WAAW,MAAM;AAAA,UACjB,aAAa,MAAM;AAAA,UACnB,UAAU,MAAM;AAAA,UAChB,aAAa,MAAM,QAAQ;AAAA,UAC3B,UAAU,MAAM,YAAY;AAAA,QAC9B,CAAyB;AAEzB,YAAI,CAAC,iBAAiB,CAAC,WAAY;AAEnC,iBAAS,KAAK,GAAG,KAAK,MAAM,QAAQ,QAAQ,MAAM;AAChD,gBAAM,SAAS,MAAM,QAAQ,EAAE;AAC/B,gBAAM,KAAK;AAAA,YACT,IAAI,UAAU,EAAE,EAAE,IAAI,MAAM,EAAE,IAAI,EAAE;AAAA,YACpC,MAAM;AAAA,YACN,OAAO;AAAA,YACP,YAAY;AAAA,YACZ,UAAU;AAAA,YACV,WAAW,EAAE;AAAA,YACb,aAAa;AAAA,YACb,YAAY,OAAO;AAAA,YACnB,WAAW,OAAO;AAAA,YAClB,SAAS,MAAM;AAAA,UACjB,CAA0B;AAAA,QAC5B;AAAA,MACF;AAAA,IACF;AAGA,UAAM,WAAW,gBAAgB,YAAY,CAAC;AAC9C,QAAI,SAAS,SAAS,GAAG;AACvB,YAAM,aAAa,YAAY,EAAE,EAAE;AACnC,YAAM,eAAe,SAAS,IAAI,UAAU;AAE5C,YAAM,KAAK;AAAA,QACT,IAAI;AAAA,QACJ,MAAM;AAAA,QACN,OAAO;AAAA,QACP,YAAY;AAAA,QACZ,UAAU;AAAA,QACV,WAAW,EAAE;AAAA,QACb,OAAO,SAAS;AAAA,MAClB,CAA4B;AAE5B,UAAI,cAAc;AAChB,mBAAW,OAAO,UAAU;AAC1B,gBAAM,UAAU,IAAI,OAAO,SAAS,UAAU,IAAI,OAAO,UAAU;AACnE,gBAAM,cAAc,mBAAmB,IAAI,OAAO,MAAM,OAAO;AAE/D,gBAAM,KAAK;AAAA,YACT,IAAI,WAAW,EAAE,EAAE,IAAI,IAAI,EAAE;AAAA,YAC7B,MAAM;AAAA,YACN,OAAO;AAAA,YACP,YAAY;AAAA,YACZ,UAAU;AAAA,YACV,WAAW,EAAE;AAAA,YACb,WAAW,IAAI;AAAA,YACf,QAAQ;AAAA,YACR,SAAS,IAAI,WAAW,IAAI;AAAA,YAC5B,WAAW,IAAI;AAAA,UACjB,CAA2B;AAAA,QAC7B;AAAA,MACF;AAAA,IACF;AAGA,UAAM,aAAa,iBAAiB,OAAO,EAAE;AAC7C,UAAM,eAAe,aAAa,qBAAqB,CAAC;AAExD,UAAM,YAAY,WAAW,EAAE,EAAE;AACjC,UAAM,cAAc,SAAS,IAAI,SAAS;AAE1C,UAAM,KAAK;AAAA,MACT,IAAI;AAAA,MACJ,MAAM;AAAA,MACN,OAAO;AAAA,MACP,YAAY,aAAa,SAAS;AAAA,MAClC,UAAU,eAAe,aAAa,SAAS;AAAA,MAC/C,WAAW,EAAE;AAAA,MACb,WAAW,aAAa;AAAA,IAC1B,CAA2B;AAE3B,QAAI,eAAe,aAAa,SAAS,GAAG;AAC1C,iBAAW,YAAY,cAAc;AACnC,cAAM,KAAK;AAAA,UACT,IAAI,gBAAgB,EAAE,EAAE,IAAI,QAAQ;AAAA,UACpC,MAAM;AAAA,UACN,OAAO;AAAA,UACP,YAAY;AAAA,UACZ,UAAU;AAAA,UACV,WAAW,EAAE;AAAA,UACb,OAAO;AAAA,UACP,UAAUC,MAAK,WAAWD,MAAK,EAAE,EAAE,GAAG,QAAQ;AAAA,QAChD,CAA+B;AAAA,MACjC;AAAA,IACF;AAAA,EACF;AAEA,WAAS,eAAe,GAAmB,UAAwB;AACjE,UAAM,gBAAgB,WAAW,EAAE,EAAE;AACrC,UAAM,aAAa,iBAAiB,OAAO,EAAE;AAC7C,UAAM,aAAa,SAAS,IAAI,aAAa;AAE7C,UAAM,KAAK;AAAA,MACT,IAAI;AAAA,MACJ,MAAM;AAAA,MACN,OAAO;AAAA,MACP,YAAY;AAAA,MACZ,UAAU,cAAc;AAAA,MACxB,WAAW,EAAE;AAAA,MACb,MAAM,EAAE;AAAA,MACR,MAAM,EAAE;AAAA,MACR,QAAQ,EAAE;AAAA,MACV,YAAY,aAAc,iBAAiB,mBAAmB,UAAU,IAAK;AAAA,MAC7E,YAAY,EAAE;AAAA,MACd,mBAAmB,EAAE;AAAA,MACrB,WAAW,EAAE;AAAA,MACb,aAAa,aAAa,iBAAiB,cAAc;AAAA,MACzD,UAAU,aAAc,iBAAiB,YAAY,EAAE,WAAY,EAAE;AAAA,MACrE,UAAU,WAAW,IAAI,WAAW;AAAA,MACpC,UAAU,EAAE,YAAY;AAAA,IAC1B,CAA2B;AAE3B,QAAI,cAAc,YAAY;AAC5B,0BAAoB,CAAC;AAAA,IACvB;AAAA,EACF;AAGA,cAAY,aAAa,SAAS,MAAM;AACxC,MAAI,gBAAgB,WAAW,GAAG;AAChC,UAAM,KAAK;AAAA,MACT,IAAI;AAAA,MACJ,MAAM;AAAA,MACN,OAAO;AAAA,MACP,YAAY;AAAA,MACZ,UAAU;AAAA,MACV,WAAW;AAAA,MACX,cAAc,eAAe;AAAA,IAC/B,CAAmC;AACnC,eAAW,KAAK,UAAU;AACxB,qBAAe,GAAG,eAAe,IAAI,EAAE,EAAE,GAAG,UAAU,CAAC;AAAA,IACzD;AAAA,EACF;AAGA,cAAY,WAAW,QAAQ,MAAM;AACrC,MAAI,gBAAgB,SAAS,GAAG;AAC9B,eAAW,KAAK,SAAS;AACvB,qBAAe,GAAG,CAAC;AAAA,IACrB;AAAA,EACF;AAGA,cAAY,QAAQ,KAAK,MAAM;AAC/B,MAAI,gBAAgB,MAAM,GAAG;AAC3B,eAAW,KAAK,MAAM;AACpB,qBAAe,GAAG,CAAC;AAAA,IACrB;AAAA,EACF;AAEA,SAAO;AACT;AAGO,SAAS,gBAAgB,OAAmB,OAAuB;AACxE,QAAM,OAAO,MAAM,KAAK;AACxB,MAAI,CAAC,QAAQ,KAAK,UAAU,EAAG,QAAO;AACtC,QAAM,cAAc,KAAK,QAAQ;AACjC,WAAS,IAAI,QAAQ,GAAG,KAAK,GAAG,KAAK;AACnC,QAAI,MAAM,CAAC,EAAG,UAAU,YAAa,QAAO;AAC5C,QAAI,MAAM,CAAC,EAAG,QAAQ,YAAa,QAAO;AAAA,EAC5C;AACA,SAAO;AACT;;;AGlUA;;;ACAA,OAAOE,kBAAiB;AAYxB,SAAS,aAAa,GAAW,SAAyB;AACxD,MAAI,IAAI;AACR,MAAI,IAAI;AACR,SAAO,IAAI,EAAE,QAAQ;AACnB,UAAM,KAAK,EAAE,YAAY,CAAC;AAC1B,UAAM,KAAK,OAAO,cAAc,EAAE;AAClC,UAAM,KAAKA,aAAY,EAAE;AACzB,QAAI,IAAI,KAAK,QAAS;AACtB,SAAK;AACL,SAAK,GAAG;AAAA,EACV;AACA,SAAO,EAAE,MAAM,GAAG,CAAC;AACrB;AAIO,IAAM,eAAyB;AAAA,EACpC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAIO,IAAM,gBAA0B;AAAA;AAAA,EAErC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA;AAAA,EAEA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA;AAAA,EAEA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA;AAAA,EAEA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAaO,SAAS,YAAY,OAAuB;AACjD,MAAI,SAAS,EAAG,QAAO;AACvB,MAAI,SAAS,EAAG,QAAO;AACvB,MAAI,SAAS,EAAG,QAAO;AACvB,MAAI,SAAS,GAAI,QAAO;AACxB,MAAI,SAAS,GAAI,QAAO;AACxB,SAAO;AACT;AAOA,IAAM,aAAqD;AAAA,EACzD,OAAa,CAAC,OAAU,YAAU,oBAAK;AAAA,EACvC,UAAa,CAAC,OAAU,OAAU,WAAK;AAAA,EACvC,YAAa,CAAC,QAAU,iBAAS,oBAAK;AAAA,EACtC,KAAa,CAAC,iBAAU,sBAAS,oBAAK;AAAA,EACtC,QAAa,CAAC,WAAU,WAAU,mBAAS;AAAA,EAC3C,SAAa,CAAC,OAAU,YAAS,oBAAK;AAAA,EACtC,aAAa,CAAC,iBAAS,iBAAS,oBAAK;AACvC;AAEO,SAAS,YAAY,MAAY,YAAoB,GAAW;AACrE,QAAM,QAAQ,WAAW,IAAI;AAC7B,MAAI,CAAC,MAAO,OAAM,IAAI,MAAM,iBAAiB,IAAc,EAAE;AAC7D,QAAM,OAAO,YAAY,KAAK,IAAI,aAAa,KAAK,IAAI;AACxD,SAAO,MAAM,IAAI;AACnB;AAIO,SAAS,iBAAiB,OAAiC;AAChE,QAAM,YAAsB,CAAC;AAC7B,MAAI,MAAM,SAAS,EAAG,WAAU,KAAK,OAAO;AAC5C,MAAI,MAAM,YAAY,KAAY,WAAU,KAAK,OAAO;AACxD,MAAI,MAAM,WAAW,GAAI,WAAU,KAAK,YAAY;AACpD,SAAO;AACT;AAIO,SAAS,eAAe,YAAqB,cAA+B;AACjF,MAAI;AACJ,MAAI,eAAe,UAAa,cAAc,GAAG;AAC/C,cAAU;AAAA,EACZ,WAAW,cAAc,GAAG;AAC1B,cAAU;AAAA,EACZ,WAAW,cAAc,GAAG;AAC1B,cAAU;AAAA,EACZ,WAAW,cAAc,IAAI;AAC3B,cAAU;AAAA,EACZ,WAAW,cAAc,IAAI;AAC3B,cAAU;AAAA,EACZ,OAAO;AACL,cAAU;AAAA,EACZ;AACA,MAAI,iBAAiB,QAAW;AAC9B,cAAU,GAAG,OAAO,KAAK,YAAY;AAAA,EACvC;AACA,SAAO;AACT;AAQO,SAAS,YACd,MACA,WACA,SACQ;AACR,MAAI,IAAI;AAER,MAAI,eAAe;AAEnB,MAAI,YAAY,IAAI;AAClB,eAAW,KAAK,WAAW;AACzB,cAAQ,GAAG;AAAA,QACT,KAAK;AACH,cAAI,IAAI,CAAC;AACT;AAAA,QACF,KAAK;AACH,cAAI,GAAG,CAAC;AACR;AAAA,QACF,KAAK;AACH,yBAAe;AACf;AAAA,MACJ;AAAA,IACF;AAAA,EACF,OAAO;AAEL,QAAI,UAAU,SAAS,YAAY,EAAG,gBAAe;AAAA,EACvD;AAEA,MAAI,OAAO,MAAM,KACb,KAAK,QAAQ,cAAc,EAAE,IAC7B,KAAK,QAAQ,aAAa,CAAC;AAE/B,MAAI,aAAc,QAAO,UAAK,IAAI;AAElC,SAAO;AACT;AAYA,IAAM,cAAuC;AAAA,EAC3C,OAAa,EAAE,MAAM,IAAK,MAAM,QAAQ;AAAA,EACxC,UAAa,EAAE,MAAM,IAAK,MAAM,SAAS;AAAA,EACzC,YAAa,EAAE,MAAM,IAAK,MAAM,MAAM;AAAA,EACtC,KAAa,EAAE,MAAM,IAAK,MAAM,OAAO;AAAA,EACvC,QAAa,EAAE,MAAM,IAAK,MAAM,YAAY;AAAA,EAC5C,SAAa,EAAE,MAAM,IAAK,MAAM,QAAQ;AAAA,EACxC,aAAa,EAAE,MAAM,IAAK,MAAM,UAAU;AAC5C;AAMO,SAAS,gBAAgB,MAAoB;AAClD,SAAO,YAAY,IAAI,EAAE;AAC3B;AAEA,SAAS,SAAS,MAAc,MAAY,MAAuB;AACjE,QAAM,EAAE,MAAM,MAAM,UAAU,IAAI,YAAY,IAAI;AAClD,MAAI,MAAM;AACR,WAAO,QAAQ,SAAS,IAAI,IAAI;AAAA,EAClC;AACA,SAAO,QAAQ,IAAI,IAAI,IAAI;AAC7B;AAIA,SAAS,YAAY,OAA+B;AAClD,QAAM,OAAO,KAAK,MAAM,MAAM,YAAY,IAAS;AACnD,SAAO,OAAO,MAAM,QAAQ,QAAQ,IAAI,SAAS,MAAM,MAAM,QAAQ,MAAM,QAAQ;AACrF;AAIO,SAAS,gBACd,WACA,QACA,MACQ;AACR,QAAM,UAAU,OAAO,SAAS,MAAM;AACtC,QAAM,aAAa,OAAO,SAAS,SAAS;AAE5C,QAAM,eAAe,MAAM,aAAa,SACpC,UAAU,MAAM,KAAK,QAAQ,GAAG,YAAY,SAC5C;AAEJ,QAAM,UAAU,eAAe,MAAM,YAAY,YAAY;AAC7D,QAAM,YAAY,iBAAiB,UAAU,KAAK;AAElD,MAAI,WAA0B;AAC9B,MAAI,kBAAiC;AAErC,MAAI,SAAS;AACX,UAAM,WAAW,YAAY,UAAU,KAAK;AAC5C,UAAM,YAAY,UAAU,WAAW,OAAO,UAAU,IAAI,KAAK;AACjE,UAAM,OAAO,YAAY,UAAU,MAAM,SAAS;AAClD,UAAM,eAAe,SAAS,QAAQ,QAAQ,IAAI;AAClD,eAAW,YAAY,cAAc,WAAW,OAAO;AAAA,EACzD,WAAW,YAAY;AAErB,sBAAkB;AAAA,EACpB;AAEA,MAAI,aAAa,OAAO,SAAS,YAAY,IACxC,UAAU,gBAAgB,QAAQ,KACnC;AAEJ,QAAM,QAAkB,CAAC;AAEzB,aAAW,SAAS,QAAQ;AAC1B,YAAQ,OAAO;AAAA,MACb,KAAK;AACH,YAAI,aAAa,KAAM,OAAM,KAAK,QAAQ;AAC1C;AAAA,MACF,KAAK;AACH,YAAI,CAAC,WAAW,oBAAoB,KAAM,OAAM,KAAK,eAAe;AAEpE;AAAA,MACF,KAAK;AACH,cAAM,KAAK,UAAU,KAAK;AAC1B;AAAA,MACF,KAAK;AACH,YAAI,eAAe,KAAM,OAAM,KAAK,UAAU;AAC9C;AAAA,MACF,KAAK;AACH,cAAM,KAAK,IAAI,UAAU,IAAI,GAAG;AAChC;AAAA,MACF,KAAK;AACH,cAAM,KAAK,MAAM,UAAU,KAAK,EAAE;AAClC;AAAA,MACF,KAAK;AACH,cAAM,KAAK,YAAY,UAAU,KAAK,CAAC;AACvC;AAAA,MACF,KAAK;AACH,cAAM,KAAK,GAAG,UAAU,aAAa,MAAM,eAAe;AAC1D;AAAA,MACF,KAAK,QAAQ;AACX,cAAM,OAAO,MAAM,aAAa,UAAU,oBAAoB,cAAc;AAC5E,cAAM,KAAK,cAAc,GAAG,CAAE;AAC9B;AAAA,MACF;AAAA,MACA,KAAK,SAAS;AAEZ,cAAM,aAAY,oBAAI,KAAK,GAAE,SAAS,IAAI,UAAU,SAAS,aAAa;AAC1E,cAAM,KAAK,aAAa,QAAQ,CAAE;AAClC;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAMA,MAAI,MAAM,aAAa,QAAW;AAChC,UAAM,WAAW,KAAK;AACtB,UAAM,SAAS,MAAM,KAAK,IAAI;AAC9B,UAAM,cAAcC,aAAY,MAAM;AACtC,QAAI,cAAc,YAAY,eAAe,QAAQ,WAAW,SAAS,GAAG;AAE1E,YAAM,gBAAgB,MAAM,QAAQ,UAAU;AAC9C,UAAI,kBAAkB,IAAI;AACxB,cAAM,kBAAkBA,aAAY,UAAU;AAC9C,cAAM,WAAW,cAAc;AAC/B,cAAM,YAAY,WAAW,WAAW;AACxC,YAAI,YAAY,GAAG;AACjB,gBAAM,aAAa,IAAI;AAAA,QACzB,OAAO;AACL,gBAAM,aAAa,IAAI,aAAa,YAAY,SAAS;AAAA,QAC3D;AACA,qBAAa,MAAM,aAAa;AAAA,MAClC;AAAA,IACF;AACA,UAAMC,UAAS,MAAM,OAAO,OAAK,EAAE,SAAS,CAAC,EAAE,KAAK,IAAI;AACxD,UAAM,cAAcD,aAAYC,OAAM;AACtC,UAAM,QAAQ,cAAc,WACxB,aAAaA,SAAQ,WAAW,CAAC,IAAI,WACrCA;AAEJ,WAAO,WAAW,OAAO,QAAQ,UAAU,UAAU,MAAM,IAAI;AAAA,EACjE;AAEA,QAAM,SAAS,MAAM,OAAO,OAAK,EAAE,SAAS,CAAC,EAAE,KAAK,IAAI;AACxD,SAAO,WAAW,QAAQ,QAAQ,UAAU,UAAU,MAAM,IAAI;AAClE;AAEA,SAAS,WACP,QACA,QACA,UACA,MACA,MACQ;AACR,QAAM,WAAW,MAAM,UAAU,QAAQ,MAAM,eAAe;AAC9D,MAAI,CAAC,YAAY,aAAa,QAAQ,CAAC,OAAO,SAAS,MAAM,EAAG,QAAO;AAEvE,QAAM,OAAO,MAAM,eAAe;AAClC,QAAM,cAAc,SAAS,UAAU,MAAM,IAAI;AACjD,SAAO,OAAO,QAAQ,UAAU,WAAW;AAC7C;;;ACpZA;AAHA,SAAS,cAAAC,aAAY,aAAAC,YAAW,gBAAAC,eAAc,cAAAC,aAAY,iBAAAC,sBAAqB;AAC/E,SAAS,cAAAC,mBAAkB;AAC3B,SAAS,WAAAC,UAAS,QAAAC,aAAY;;;ACIvB,SAAS,aAA2B;AACzC,SAAO,EAAE,OAAO,GAAG,MAAM,GAAG,IAAI,EAAE;AACpC;AAEO,SAAS,mBAAuC;AACrD,SAAO;AAAA,IACL,WAAW,WAAW;AAAA,IACtB,YAAY,WAAW;AAAA,IACvB,YAAY,WAAW;AAAA,IACvB,gBAAgB,WAAW;AAAA,IAC3B,uBAAuB,WAAW;AAAA,IAClC,gBAAgB;AAAA,IAChB,iBAAiB;AAAA,EACnB;AACF;AAWO,SAAS,mBAAmBC,QAAuC;AACxE,MAAIA,OAAM,SAAS,KAAM,CAAAA,OAAM,QAAQ,EAAE,UAAU,GAAG,WAAW,GAAG,QAAQ,GAAG,UAAU,EAAE;AAC3F,MAAIA,OAAM,SAAS,KAAM,CAAAA,OAAM,QAAQ;AACvC,MAAIA,OAAM,MAAM,KAAM,CAAAA,OAAM,KAAK;AACjC,MAAIA,OAAM,SAAS,KAAM,CAAAA,OAAM,QAAQ;AACvC,MAAIA,OAAM,QAAQ,KAAM,CAAAA,OAAM,OAAO;AACrC,MAAIA,OAAM,gBAAgB,KAAM,CAAAA,OAAM,eAAe,CAAC;AACtD,MAAIA,OAAM,SAAS,KAAM,CAAAA,OAAM,QAAQ,CAAC;AACxC,MAAIA,OAAM,mBAAmB,OAAW,CAAAA,OAAM,iBAAiB;AAC/D,MAAIA,OAAM,qBAAqB,KAAM,CAAAA,OAAM,oBAAoB;AAC/D,MAAIA,OAAM,mBAAmB,KAAM,CAAAA,OAAM,kBAAkB;AAC3D,MAAIA,OAAM,iBAAiB,KAAM,CAAAA,OAAM,gBAAgB;AACvD,MAAIA,OAAM,4BAA4B,KAAM,CAAAA,OAAM,2BAA2B;AAC7E,MAAIA,OAAM,yBAAyB,KAAM,CAAAA,OAAM,wBAAwB;AACvE,MAAIA,OAAM,mBAAmB,OAAW,CAAAA,OAAM,iBAAiB;AAC/D,MAAIA,OAAM,eAAe,KAAM,CAAAA,OAAM,cAAc,CAAC;AACpD,MAAIA,OAAM,cAAc,KAAM,CAAAA,OAAM,aAAa,CAAC;AAClD,MAAIA,OAAM,qBAAqB,KAAM,CAAAA,OAAM,oBAAoB,CAAC;AAChE,MAAIA,OAAM,yBAAyB,KAAM,CAAAA,OAAM,wBAAwB;AACvE,MAAIA,OAAM,gCAAgC,KAAM,CAAAA,OAAM,+BAA+B;AACrF,MAAIA,OAAM,gCAAgC,KAAM,CAAAA,OAAM,+BAA+B;AACrF,MAAIA,OAAM,oBAAoB,KAAM,CAAAA,OAAM,mBAAmB;AAC7D,MAAIA,OAAM,aAAa,KAAM,CAAAA,OAAM,YAAY,iBAAiB;AAChE,MAAIA,OAAM,UAAU,yBAAyB,KAAM,CAAAA,OAAM,UAAU,wBAAwB,WAAW;AACtG,MAAIA,OAAM,qBAAqB,KAAM,CAAAA,OAAM,oBAAoB,CAAC;AAChE,MAAIA,OAAM,mBAAmB,KAAM,CAAAA,OAAM,kBAAkB,CAAC;AAC5D,SAAOA;AACT;;;ACxDO,IAAM,yBAAyB,CAAC,sBAAsB,oBAAoB,iBAAiB,iBAAiB;AAyR5G,IAAM,eAAiC;AAAA;AAAA,EAE5C,EAAE,IAAI,eAAe,MAAM,eAAe,UAAU,aAAa,aAAa,gCAAgC,OAAO,KAAK;AAAA,EAC1H,EAAE,IAAI,WAAW,MAAM,WAAW,UAAU,aAAa,aAAa,yBAAyB,OAAO,KAAK;AAAA,EAC3G,EAAE,IAAI,aAAa,MAAM,aAAa,UAAU,aAAa,aAAa,0BAA0B,OAAO,KAAK;AAAA,EAChH,EAAE,IAAI,WAAW,MAAM,WAAW,UAAU,aAAa,aAAa,0BAA0B,OAAO,KAAK;AAAA,EAC5G,EAAE,IAAI,oBAAoB,MAAM,oBAAoB,UAAU,aAAa,aAAa,4BAA4B,OAAO,KAAK;AAAA,EAChI,EAAE,IAAI,gBAAgB,MAAM,gBAAgB,UAAU,aAAa,aAAa,8BAA8B,OAAO,IAAI;AAAA,EACzH,EAAE,IAAI,kBAAkB,MAAM,kBAAkB,UAAU,aAAa,aAAa,+BAA+B,OAAO,KAAK;AAAA,EAC/H,EAAE,IAAI,eAAe,MAAM,eAAe,UAAU,aAAa,aAAa,+BAA+B,OAAO,KAAK;AAAA,EACzH,EAAE,IAAI,iBAAiB,MAAM,iBAAiB,UAAU,aAAa,aAAa,oCAAoC,OAAO,KAAK;AAAA,EAClI,EAAE,IAAI,aAAa,MAAM,aAAa,UAAU,aAAa,aAAa,qCAAqC,OAAO,KAAK;AAAA,EAC3H,EAAE,IAAI,UAAU,MAAM,UAAU,UAAU,aAAa,aAAa,uCAAuC,OAAO,KAAK;AAAA,EACvH,EAAE,IAAI,qBAAqB,MAAM,qBAAqB,UAAU,aAAa,aAAa,uCAAuC,OAAO,KAAK;AAAA,EAC7I,EAAE,IAAI,eAAe,MAAM,eAAe,UAAU,aAAa,aAAa,wCAAwC,OAAO,KAAK;AAAA,EAClI,EAAE,IAAI,eAAe,MAAM,eAAe,UAAU,aAAa,aAAa,wCAAwC,OAAO,KAAK;AAAA,EAClI,EAAE,IAAI,cAAc,MAAM,cAAc,UAAU,aAAa,aAAa,yCAAyC,OAAO,KAAK;AAAA,EACjI,EAAE,IAAI,aAAa,MAAM,aAAa,UAAU,aAAa,aAAa,yCAAyC,OAAO,KAAK;AAAA,EAC/H,EAAE,IAAI,iBAAiB,MAAM,iBAAiB,UAAU,aAAa,aAAa,2CAA2C,OAAO,KAAK;AAAA,EACzI,EAAE,IAAI,SAAS,MAAM,SAAS,UAAU,aAAa,aAAa,2CAA2C,OAAO,KAAK;AAAA,EACzH,EAAE,IAAI,cAAc,MAAM,cAAc,UAAU,aAAa,aAAa,6BAA6B,OAAO,KAAK;AAAA,EACrH,EAAE,IAAI,YAAY,MAAM,YAAY,UAAU,aAAa,aAAa,6BAA6B,OAAO,KAAK;AAAA,EACjH,EAAE,IAAI,WAAW,MAAM,WAAW,UAAU,aAAa,aAAa,8BAA8B,OAAO,KAAK;AAAA,EAChH,EAAE,IAAI,cAAc,MAAM,cAAc,UAAU,aAAa,aAAa,kBAAkB,OAAO,KAAK;AAAA,EAC1G,EAAE,IAAI,cAAc,MAAM,cAAc,UAAU,aAAa,aAAa,mBAAmB,OAAO,KAAK;AAAA,EAC3G,EAAE,IAAI,UAAU,MAAM,UAAU,UAAU,aAAa,aAAa,mBAAmB,OAAO,KAAK;AAAA,EACnG,EAAE,IAAI,eAAe,MAAM,eAAe,UAAU,aAAa,aAAa,mBAAmB,OAAO,KAAK;AAAA;AAAA,EAE7G,EAAE,IAAI,YAAY,MAAM,YAAY,UAAU,WAAW,aAAa,uCAAuC,OAAO,MAAM;AAAA,EAC1H,EAAE,IAAI,SAAS,MAAM,YAAY,UAAU,WAAW,aAAa,uCAAuC,OAAO,KAAK;AAAA,EACtH,EAAE,IAAI,aAAa,MAAM,aAAa,UAAU,WAAW,aAAa,uCAAuC,OAAO,KAAK;AAAA,EAC3H,EAAE,IAAI,SAAS,MAAM,aAAa,UAAU,WAAW,aAAa,uCAAuC,OAAO,KAAK;AAAA,EACvH,EAAE,IAAI,SAAS,MAAM,SAAS,UAAU,WAAW,aAAa,0CAA0C,OAAO,KAAK;AAAA,EACtH,EAAE,IAAI,aAAa,MAAM,aAAa,UAAU,WAAW,aAAa,2CAA2C,OAAO,KAAK;AAAA,EAC/H,EAAE,IAAI,SAAS,MAAM,SAAS,UAAU,WAAW,aAAa,0CAA0C,OAAO,KAAK;AAAA,EACtH,EAAE,IAAI,YAAY,MAAM,YAAY,UAAU,WAAW,aAAa,wDAAwD,OAAO,IAAI;AAAA,EACzI,EAAE,IAAI,eAAe,MAAM,eAAe,UAAU,WAAW,aAAa,4DAA4D,OAAO,SAAI;AAAA,EACnJ,EAAE,IAAI,aAAa,MAAM,aAAa,UAAU,WAAW,aAAa,4DAA4D,OAAO,KAAK;AAAA,EAChJ,EAAE,IAAI,gBAAgB,MAAM,gBAAgB,UAAU,WAAW,aAAa,yDAAyD,OAAO,KAAK;AAAA,EACnJ,EAAE,IAAI,QAAQ,MAAM,QAAQ,UAAU,WAAW,aAAa,8CAA8C,OAAO,KAAK;AAAA,EACxH,EAAE,IAAI,kBAAkB,MAAM,kBAAkB,UAAU,WAAW,aAAa,2CAA2C,OAAO,KAAK;AAAA,EACzI,EAAE,IAAI,aAAa,MAAM,aAAa,UAAU,WAAW,aAAa,2CAA2C,OAAO,KAAK;AAAA,EAC/H,EAAE,IAAI,SAAS,MAAM,kBAAkB,UAAU,WAAW,aAAa,2CAA2C,OAAO,KAAK;AAAA,EAChI,EAAE,IAAI,sBAAsB,MAAM,sBAAsB,UAAU,WAAW,aAAa,2CAA2C,OAAO,KAAK;AAAA,EACjJ,EAAE,IAAI,aAAa,MAAM,aAAa,UAAU,WAAW,aAAa,sCAAsC,OAAO,KAAK;AAAA,EAC1H,EAAE,IAAI,iBAAiB,MAAM,iBAAiB,UAAU,WAAW,aAAa,sCAAsC,OAAO,KAAK;AAAA,EAClI,EAAE,IAAI,YAAY,MAAM,YAAY,UAAU,WAAW,aAAa,4DAA4D,OAAO,KAAK;AAAA,EAC9I,EAAE,IAAI,cAAc,MAAM,cAAc,UAAU,WAAW,aAAa,oDAAoD,OAAO,KAAK;AAAA;AAAA,EAE1I,EAAE,IAAI,aAAa,MAAM,aAAa,UAAU,QAAQ,aAAa,mDAAmD,OAAO,IAAI;AAAA,EACnI,EAAE,IAAI,eAAe,MAAM,eAAe,UAAU,QAAQ,aAAa,wDAAwD,OAAO,KAAK;AAAA,EAC7I,EAAE,IAAI,cAAc,MAAM,cAAc,UAAU,QAAQ,aAAa,+BAA+B,OAAO,KAAK;AAAA,EAClH,EAAE,IAAI,mBAAmB,MAAM,mBAAmB,UAAU,QAAQ,aAAa,+CAA+C,OAAO,KAAK;AAAA,EAC5I,EAAE,IAAI,eAAe,MAAM,eAAe,UAAU,QAAQ,aAAa,oCAAoC,OAAO,KAAK;AAAA,EACzH,EAAE,IAAI,iBAAiB,MAAM,iBAAiB,UAAU,QAAQ,aAAa,wCAAwC,OAAO,KAAK;AAAA;AAAA,EAEjI,EAAE,IAAI,aAAa,MAAM,aAAa,UAAU,cAAc,aAAa,mCAAmC,OAAO,IAAI;AAAA,EACzH,EAAE,IAAI,YAAY,MAAM,YAAY,UAAU,cAAc,aAAa,8DAA8D,OAAO,KAAK;AAAA,EACnJ,EAAE,IAAI,oBAAoB,MAAM,oBAAoB,UAAU,cAAc,aAAa,oCAAoC,OAAO,KAAK;AAAA,EACzI,EAAE,IAAI,qBAAqB,MAAM,qBAAqB,UAAU,cAAc,aAAa,iCAAiC,OAAO,KAAK;AAAA,EACxI,EAAE,IAAI,SAAS,MAAM,SAAS,UAAU,cAAc,aAAa,iCAAiC,OAAO,KAAK;AAAA,EAChH,EAAE,IAAI,YAAY,MAAM,YAAY,UAAU,cAAc,aAAa,gDAAgD,OAAO,KAAK;AAAA,EACrI,EAAE,IAAI,UAAU,MAAM,UAAU,UAAU,cAAc,aAAa,iDAAiD,OAAO,KAAK;AAAA,EAClI,EAAE,IAAI,eAAe,MAAM,eAAe,UAAU,cAAc,aAAa,kDAAkD,OAAO,KAAK;AAAA,EAC7I,EAAE,IAAI,cAAc,MAAM,cAAc,UAAU,cAAc,aAAa,kCAAkC,OAAO,KAAK;AAAA,EAC3H,EAAE,IAAI,YAAY,MAAM,YAAY,UAAU,cAAc,aAAa,wCAAwC,OAAO,KAAK;AAAA,EAC7H,EAAE,IAAI,aAAa,MAAM,aAAa,UAAU,cAAc,aAAa,kDAAkD,OAAO,KAAK;AAAA,EACzI,EAAE,IAAI,eAAe,MAAM,eAAe,UAAU,cAAc,aAAa,iDAAiD,OAAO,KAAK;AAAA,EAC5I,EAAE,IAAI,uBAAuB,MAAM,uBAAuB,UAAU,cAAc,aAAa,0CAA0C,OAAO,KAAK;AAAA,EACrJ,EAAE,IAAI,qBAAqB,MAAM,qBAAqB,UAAU,cAAc,aAAa,0CAA0C,OAAO,KAAK;AAAA,EACjJ,EAAE,IAAI,gBAAgB,MAAM,gBAAgB,UAAU,cAAc,aAAa,mDAAmD,OAAO,KAAK;AAAA,EAChJ,EAAE,IAAI,oBAAoB,MAAM,oBAAoB,UAAU,cAAc,aAAa,oDAAoD,OAAO,KAAK;AAC3J;;;AC/VA;AAJA,SAAS,cAAAC,aAAY,aAAAC,YAAW,gBAAAC,eAAc,YAAyB,iBAAAC,sBAAqB;AAC5F,SAAS,SAAS,QAAAC,aAAY;AAC9B,SAAS,kBAAkB;AAC3B,SAAS,SAAS;;;ACHlB,SAAS,OAAO,0BAAqD;;;ACArE,SAAS,eAAe;AAUjB,SAAS,gBAAwB;AACtC,QAAM,UAAU,QAAQ,IAAI,MAAM;AAClC,QAAM,WAAW,YAAY,UAAa,QAAQ,SAAS,IAAI,UAAU;AAIzE,QAAM,OAAO,QAAQ,IAAI,MAAM;AAC/B,QAAM,aAAa;AAAA,IACjB,GAAI,OAAO,CAAC,GAAG,IAAI,aAAa,IAAI,CAAC;AAAA;AAAA,IACrC,QAAQ,QAAQ,UAAU,IAAI;AAAA;AAAA,IAC9B;AAAA;AAAA,IACA;AAAA;AAAA,IACA;AAAA;AAAA,IACA;AAAA;AAAA,IACA;AAAA;AAAA,IACA;AAAA;AAAA,IACA;AAAA;AAAA,EACF;AAGA,QAAM,aAAa,QAAQ,IAAI,cAAc;AAC7C,MAAI,YAAY;AACd,eAAW,KAAK,WAAW,MAAM,GAAG,EAAE,QAAQ,GAAG;AAC/C,iBAAW,KAAK,GAAG,CAAC,MAAM;AAAA,IAC5B;AAAA,EACF;AAEA,QAAM,WAAW,IAAI,IAAI,SAAS,MAAM,GAAG,CAAC;AAC5C,QAAM,UAAU,WAAW,OAAO,SAAO,CAAC,SAAS,IAAI,GAAG,CAAC;AAE3D,SAAO,QAAQ,SAAS,IAAI,GAAG,QAAQ,KAAK,GAAG,CAAC,IAAI,QAAQ,KAAK;AACnE;AAMO,SAAS,UAA8C;AAC5D,SAAO;AAAA,IACL,GAAG,QAAQ;AAAA,IACX,MAAM,cAAc;AAAA,EACtB;AACF;;;ADhDA,IAAM,cAAc,IAAI,KAAK;;;ADmBtB,IAAM,6BAA6B;AAInC,IAAM,0BAA0B;AAOhC,SAAS,sBAAsB,MAAuB;AAC3D,MAAI,2BAA2B,KAAK,IAAI,EAAG,QAAO;AAClD,MAAI,wBAAwB,KAAK,IAAI,EAAG,QAAO;AAC/C,SAAO;AACT;AAwBA,IAAI,aAA4B,QAAQ,QAAQ;AAgdhD,IAAM,0BAA0B;AAAA,EAC9B,MAAM;AAAA,EACN,YAAY;AAAA,IACV,UAAU;AAAA,MACR,MAAM;AAAA,MACN,MAAM,CAAC,GAAG,sBAAsB;AAAA,MAChC,aAAa;AAAA,IACf;AAAA,IACA,MAAM;AAAA,MACJ,MAAM;AAAA,MACN,WAAW;AAAA,MACX,WAAW;AAAA,MACX,aAAa;AAAA,IACf;AAAA,EACF;AAAA,EACA,UAAU,CAAC,YAAY,MAAM;AAAA,EAC7B,sBAAsB;AACxB;AAEA,IAAM,uBAAuB,EAAE,OAAO;AAAA,EACpC,UAAU,EAAE,KAAK,sBAAsB;AAAA,EACvC,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE,IAAI,GAAG,EAAE,OAAO,uBAAuB,4BAA4B;AAC9F,CAAC;;;AHlVM,SAAS,qBAAqB,IAA6D;AAChG,MAAI,YAAY;AAChB,MAAI,aAAa;AACjB,SAAO,aAAa,aAAa,IAAI;AACnC,kBAAc;AACd,gBAAY,KAAK,MAAM,YAAY,IAAI;AAAA,EACzC;AACA,SAAO,EAAE,aAAa,KAAK,YAAY,gBAAgB,UAAU;AACnE;;;AMlNA,IAAM,YAA6C;AAAA;AAAA,EAEjD,eAAe;AAAA,IACb;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,aAAa;AAAA,IACX;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,oBAAoB;AAAA,IAClB;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,gBAAgB;AAAA,IACd;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,kBAAkB;AAAA,IAChB;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,aAAa;AAAA,IACX;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,cAAc;AAAA,IACZ;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,WAAW;AAAA,IACT;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,WAAW;AAAA,IACT;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,WAAW;AAAA,IACT;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,iBAAiB;AAAA,IACf;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,UAAU;AAAA,IACR;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,qBAAqB;AAAA,IACnB;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,eAAe;AAAA,IACb;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,eAAe;AAAA,IACb;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,cAAc;AAAA,IACZ;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,aAAa;AAAA,IACX;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,iBAAiB;AAAA,IACf;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,SAAS;AAAA,IACP;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,YAAY;AAAA,IACV;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,eAAe;AAAA,IACb;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,cAAc;AAAA,IACZ;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,cAAc;AAAA,IACZ;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,UAAU;AAAA,IACR;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,eAAe;AAAA,IACb;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA;AAAA,EAGA,YAAY;AAAA,IACV;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,SAAS;AAAA,IACP;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,aAAa;AAAA,IACX;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,YAAY;AAAA,IACV;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,eAAe;AAAA,IACb;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,aAAa;AAAA,IACX;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,gBAAgB;AAAA,IACd;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,QAAQ;AAAA,IACN;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,kBAAkB;AAAA,IAChB;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,cAAc;AAAA,IACZ;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,SAAS;AAAA,IACP;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,aAAa;AAAA,IACX;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,SAAS;AAAA,IACP;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,aAAa;AAAA,IACX;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,SAAS;AAAA,IACP;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,sBAAsB;AAAA,IACpB;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,aAAa;AAAA,IACX;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,iBAAiB;AAAA,IACf;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,YAAY;AAAA,IACV;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,SAAS;AAAA,IACP;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA;AAAA,EAGA,aAAa;AAAA,IACX;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,eAAe;AAAA,IACb;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,cAAc;AAAA,IACZ;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,mBAAmB;AAAA,IACjB;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,eAAe;AAAA,IACb;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,iBAAiB;AAAA,IACf;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA;AAAA,EAGA,aAAa;AAAA,IACX;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,YAAY;AAAA,IACV;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,qBAAqB;AAAA,IACnB;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,SAAS;AAAA,IACP;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,YAAY;AAAA,IACV;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,UAAU;AAAA,IACR;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,cAAc;AAAA,IACZ;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,YAAY;AAAA,IACV;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,eAAe;AAAA,IACb;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,uBAAuB;AAAA,IACrB;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,gBAAgB;AAAA,IACd;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,oBAAoB;AAAA,IAClB;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,aAAa;AAAA,IACX;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EAC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","names":["cleanup","key","cwd","sessionId","askId","stringWidth","prevFrame","readFileSync","cwd","mkdirSync","writeFileSync","renameSync","readdirSync","readFileSync","rmSync","randomUUID","dirname","join","randomUUID","dirname","join","renameSync","writeFileSync","resolve","existsSync","readFileSync","writeFileSync","join","existsSync","mkdirSync","readFileSync","readdirSync","rmSync","statSync","writeFileSync","join","execFile","writeFileSync","mkdirSync","existsSync","join","homedir","existsSync","mkdirSync","readFileSync","readdirSync","cwd","sessionId","askId","existsSync","mountPanel","cwd","sessionId","askId","prevFrame","cwd","state","readFileSync","existsSync","readdirSync","statSync","join","readFileSync","readdirSync","statSync","join","homedir","join","sessionId","cwd","state","join","cwd","join","stringWidth","stringWidth","result","existsSync","mkdirSync","readFileSync","renameSync","writeFileSync","randomUUID","dirname","join","state","existsSync","mkdirSync","readFileSync","writeFileSync","join","wrapText","MOOD_COLORS","wrapText","divider","readFileSync","resolve","state","readFileSync","askId","state","cwd","sessionId","readdirSync","statSync","join","readFileSync","session","readFileSync","execSync","join","readFileSync","writeFileSync","rmSync","cpSync","existsSync","mkdirSync","execSync","cwd","execSync","execSync","cwd","join","existsSync","mkdirSync","cpSync","readFileSync","writeFileSync","rmSync","args","sessionId","firstPaneId","execSync","readFileSync","readdirSync","readFileSync","cwd","stringWidth","stringWidth","stringWidth","stringWidth","bg","row","cleaned","wrapped","state","lines","stringWidth","stringWidth","out","state","state","state","execSync","mkdtempSync","writeFileSync","readFileSync","rmSync","join","tmpdir","mkdirSync","existsSync","cpSync","join","homedir","state","mkdtempSync","join","tmpdir","writeFileSync","execSync","readFileSync","rmSync","statSync","readFileSync","state","state","cleanup","existsSync","readFileSync","join","readdirSync","statSync","out","runSingleAsk"]}
|
|
1
|
+
{"version":3,"sources":["../src/tui/terminal.ts","../src/shared/paths.ts","../src/shared/platform.ts","../src/tui/render.ts","../src/shared/config.ts","../src/daemon/history.ts","../src/daemon/lib/atomic.ts","../src/shared/gitignore.ts","../src/shared/types.ts","../src/daemon/state.ts","../src/shared/shell.ts","../src/daemon/notify.ts","../src/daemon/ask-store.ts","../src/tui/single-ask.ts","../src/tui/index.ts","../src/tui/state.ts","../src/tui/app.ts","../src/tui/input.ts","../src/shared/session-export.ts","../src/shared/clipboard.ts","../src/tui/lib/tree.ts","../src/tui/lib/format.ts","../src/shared/format.ts","../src/tui/panels/overlays.ts","../src/shared/companion-render.ts","../src/daemon/companion.ts","../src/shared/companion-normalize.ts","../src/shared/companion-types.ts","../src/daemon/companion-memory.ts","../src/daemon/haiku.ts","../src/shared/env.ts","../src/shared/companion-badges.ts","../src/tui/panels/mounted-humanloop.ts","../src/shared/client.ts","../src/shared/keymap.ts","../src/tui/lib/tree-render.ts","../src/tui/lib/reports.ts","../src/tui/lib/client.ts","../src/tui/lib/tmux.ts","../src/shared/exec.ts","../src/tui/lib/context.ts","../src/tui/panels/tree.ts","../src/tui/panels/detail.ts","../src/shared/utils.ts","../src/tui/panels/cycle-flow.ts","../src/shared/inbox-types.ts","../src/tui/panels/stacked-detail.ts","../src/tui/lib/markdown-highlight.ts","../src/tui/lib/gloam.ts","../src/tui/panels/bottom.ts","../src/tui/panels/cross-session-inbox.ts","../src/tui/lib/popup-compose.ts","../src/shared/sisyphus-init-lua.ts"],"sourcesContent":["export interface Key {\n upArrow: boolean;\n downArrow: boolean;\n leftArrow: boolean;\n rightArrow: boolean;\n pageUp: boolean;\n pageDown: boolean;\n return: boolean;\n escape: boolean;\n ctrl: boolean;\n shift: boolean;\n tab: boolean;\n backspace: boolean;\n delete: boolean;\n meta: boolean;\n}\n\nexport type KeypressHandler = (input: string, key: Key) => void;\n\nfunction emptyKey(): Key {\n return {\n upArrow: false,\n downArrow: false,\n leftArrow: false,\n rightArrow: false,\n pageUp: false,\n pageDown: false,\n return: false,\n escape: false,\n ctrl: false,\n shift: false,\n tab: false,\n backspace: false,\n delete: false,\n meta: false,\n };\n}\n\n// ── Terminal Setup/Teardown ──────────────────────────────────────────────────\n\nexport function setupTerminal(): () => void {\n let cleaned = false;\n\n const cleanup = (): void => {\n if (cleaned) return;\n cleaned = true;\n process.stdout.write('\\x1b[?25h\\x1b[?1049l');\n process.stdin.setRawMode(false);\n process.stdin.pause();\n };\n\n process.stdin.setRawMode(true);\n process.stdin.resume();\n process.stdin.setEncoding('utf-8');\n process.stdout.write('\\x1b[?1049h\\x1b[?25l\\x1b[2J');\n\n process.on('SIGINT', () => { cleanup(); process.exit(0); });\n process.on('SIGTERM', () => { cleanup(); process.exit(0); });\n process.on('exit', cleanup);\n process.on('uncaughtException', (err) => {\n cleanup();\n console.error(err);\n process.exit(1);\n });\n\n return cleanup;\n}\n\n// ── Stdout Write Helper ──────────────────────────────────────────────────────\n\nexport function writeToStdout(data: string): void {\n process.stdout.write(data);\n}\n\n// ── Keypress Parser ──────────────────────────────────────────────────────────\n\n/**\n * Parse all complete key sequences from a buffer string.\n * Returns an array of [input, Key] pairs and the remaining unparsed buffer.\n */\nfunction parseBuffer(buf: string): { events: Array<[string, Key]>; remaining: string } {\n const events: Array<[string, Key]> = [];\n\n let i = 0;\n while (i < buf.length) {\n const ch = buf[i]!;\n\n // ESC prefix sequences\n if (ch === '\\x1b') {\n const rest = buf.slice(i + 1);\n\n // CSI sequences: \\x1b[...\n if (rest.startsWith('[')) {\n const after = rest.slice(1);\n\n // Shift+Arrow: \\x1b[1;2A/B/C/D\n const shiftArrow = after.match(/^1;2([ABCD])/);\n if (shiftArrow) {\n const key = emptyKey();\n key.shift = true;\n const dir = shiftArrow[1]!;\n if (dir === 'A') key.upArrow = true;\n else if (dir === 'B') key.downArrow = true;\n else if (dir === 'C') key.rightArrow = true;\n else if (dir === 'D') key.leftArrow = true;\n const seq = `\\x1b[1;2${dir}`;\n events.push([seq, key]);\n i += seq.length;\n continue;\n }\n\n // Shift+Tab (backtab): \\x1b[Z\n if (after.length >= 1 && after[0] === 'Z') {\n const key = emptyKey();\n key.tab = true;\n key.shift = true;\n const seq = `\\x1b[Z`;\n events.push([seq, key]);\n i += seq.length;\n continue;\n }\n\n // Arrow keys: \\x1b[A/B/C/D\n if (after.length >= 1 && 'ABCD'.includes(after[0]!)) {\n const key = emptyKey();\n const dir = after[0]!;\n if (dir === 'A') key.upArrow = true;\n else if (dir === 'B') key.downArrow = true;\n else if (dir === 'C') key.rightArrow = true;\n else if (dir === 'D') key.leftArrow = true;\n const seq = `\\x1b[${dir}`;\n events.push([seq, key]);\n i += seq.length;\n continue;\n }\n\n // Tilde sequences: \\x1b[N~\n const tildeMatch = after.match(/^(\\d+)~/);\n if (tildeMatch) {\n const num = tildeMatch[1]!;\n const key = emptyKey();\n if (num === '5') key.pageUp = true;\n else if (num === '6') key.pageDown = true;\n else if (num === '3') key.delete = true;\n const seq = `\\x1b[${num}~`;\n events.push([seq, key]);\n i += seq.length;\n continue;\n }\n\n // Incomplete CSI — need more data\n return { events, remaining: buf.slice(i) };\n }\n\n // Lone ESC — signal caller to wait (disambiguate vs CSI prefix)\n if (rest.length === 0) {\n return { events, remaining: buf.slice(i) };\n }\n\n // \\x1b + regular char → Meta key\n const metaCh = rest[0]!;\n const key = emptyKey();\n key.meta = true;\n events.push([metaCh, key]);\n i += 2;\n continue;\n }\n\n // Return\n if (ch === '\\r') {\n const key = emptyKey();\n key.return = true;\n events.push([ch, key]);\n i++;\n continue;\n }\n\n // Tab\n if (ch === '\\t') {\n const key = emptyKey();\n key.tab = true;\n events.push([ch, key]);\n i++;\n continue;\n }\n\n // Backspace (DEL or BS)\n if (ch === '\\x7f' || ch === '\\x08') {\n const key = emptyKey();\n key.backspace = true;\n events.push([ch, key]);\n i++;\n continue;\n }\n\n // Ctrl+A–Z (\\x01–\\x1a)\n const code = ch.charCodeAt(0);\n if (code >= 0x01 && code <= 0x1a) {\n const key = emptyKey();\n key.ctrl = true;\n const letter = String.fromCharCode(code + 96);\n events.push([letter, key]);\n i++;\n continue;\n }\n\n // Printable / multibyte char\n events.push([ch, emptyKey()]);\n i++;\n }\n\n return { events, remaining: '' };\n}\n\n// ── Raw Stdin Bypass (for neovim PTY forwarding) ─────────────────────────────\n\nlet rawBypassHandler: ((data: string) => boolean) | null = null;\n\nexport function setRawBypass(handler: ((data: string) => boolean) | null): void {\n rawBypassHandler = handler;\n}\n\nexport function startKeypressListener(handler: KeypressHandler): () => void {\n let buffer = '';\n let escTimer: ReturnType<typeof setTimeout> | null = null;\n\n const onData = (data: string): void => {\n // Raw bypass — forward to neovim PTY if active\n if (rawBypassHandler) {\n const handled = rawBypassHandler(data);\n if (handled) return;\n }\n\n // Cancel pending escape timer — more data arrived\n if (escTimer !== null) {\n clearTimeout(escTimer);\n escTimer = null;\n }\n\n buffer += data;\n\n const { events, remaining } = parseBuffer(buffer);\n buffer = remaining;\n\n for (const [input, key] of events) {\n handler(input, key);\n }\n\n // If buffer ends with lone ESC, start disambiguation timer\n if (buffer === '\\x1b') {\n escTimer = setTimeout(() => {\n escTimer = null;\n buffer = '';\n const key = emptyKey();\n key.escape = true;\n handler('\\x1b', key);\n }, 50);\n }\n };\n\n process.stdin.on('data', onData);\n\n return (): void => {\n process.stdin.off('data', onData);\n if (escTimer !== null) {\n clearTimeout(escTimer);\n escTimer = null;\n }\n };\n}\n\n// ── Resize Handler ───────────────────────────────────────────────────────────\n\nexport function onResize(callback: () => void): () => void {\n const onStdoutResize = (): void => callback();\n const onSigwinch = (): void => callback();\n\n process.stdout.on('resize', onStdoutResize);\n process.on('SIGWINCH', onSigwinch);\n\n return (): void => {\n process.stdout.off('resize', onStdoutResize);\n process.off('SIGWINCH', onSigwinch);\n };\n}\n","import { homedir } from 'node:os';\nimport { basename, join } from 'node:path';\n\nexport function globalDir(): string {\n return join(homedir(), '.sisyphus');\n}\n\nexport function socketPath(): string {\n return join(globalDir(), 'daemon.sock');\n}\n\nexport function globalConfigPath(): string {\n return join(globalDir(), 'config.json');\n}\n\nexport function daemonLogPath(): string {\n return join(globalDir(), 'daemon.log');\n}\n\nexport function daemonPidPath(): string {\n return join(globalDir(), 'daemon.pid');\n}\n\nexport function daemonUpdatingPath(): string {\n return join(globalDir(), 'updating');\n}\n\nexport function projectDir(cwd: string): string {\n return join(cwd, '.sisyphus');\n}\n\nexport function projectConfigPath(cwd: string): string {\n return join(projectDir(cwd), 'config.json');\n}\n\nexport function projectOrchestratorPromptPath(cwd: string): string {\n return join(projectDir(cwd), 'orchestrator.md');\n}\n\nexport function userOrchestratorPromptPath(): string {\n return join(globalDir(), 'orchestrator.md');\n}\n\nexport function projectOrchestratorSettingsPath(cwd: string): string {\n return join(projectDir(cwd), 'orchestrator-settings.json');\n}\n\nexport function userOrchestratorSettingsPath(): string {\n return join(globalDir(), 'orchestrator-settings.json');\n}\n\nexport function projectAgentPluginDir(cwd: string): string {\n return join(projectDir(cwd), 'agent-plugin');\n}\n\nexport function userAgentPluginDir(): string {\n return join(globalDir(), 'agent-plugin');\n}\n\nexport function projectOrchestratorPluginDir(cwd: string): string {\n return join(projectDir(cwd), 'orchestrator-plugin');\n}\n\nexport function userOrchestratorPluginDir(): string {\n return join(globalDir(), 'orchestrator-plugin');\n}\n\nexport function sessionsDir(cwd: string): string {\n return join(projectDir(cwd), 'sessions');\n}\n\nexport function sessionDir(cwd: string, sessionId: string): string {\n return join(sessionsDir(cwd), sessionId);\n}\n\nexport function statePath(cwd: string, sessionId: string): string {\n return join(sessionDir(cwd, sessionId), 'state.json');\n}\n\nexport function reportsDir(cwd: string, sessionId: string): string {\n return join(sessionDir(cwd, sessionId), 'reports');\n}\n\nexport function reportFilePath(cwd: string, sessionId: string, agentId: string, suffix: string): string {\n return join(reportsDir(cwd, sessionId), `${agentId}-${suffix}.md`);\n}\n\nexport function messagesDir(cwd: string, sessionId: string): string {\n return join(sessionDir(cwd, sessionId), 'messages');\n}\n\nexport function promptsDir(cwd: string, sessionId: string): string {\n return join(sessionDir(cwd, sessionId), 'prompts');\n}\n\nexport function contextDir(cwd: string, sessionId: string): string {\n return join(sessionDir(cwd, sessionId), 'context');\n}\n\nexport function roadmapPath(cwd: string, sessionId: string): string {\n return join(sessionDir(cwd, sessionId), 'roadmap.md');\n}\n\nexport function goalPath(cwd: string, sessionId: string): string {\n return join(sessionDir(cwd, sessionId), 'goal.md');\n}\n\nexport function initialPromptPath(cwd: string, sessionId: string): string {\n return join(sessionDir(cwd, sessionId), 'initial-prompt.md');\n}\n\nexport function strategyPath(cwd: string, sessionId: string): string {\n return join(sessionDir(cwd, sessionId), 'strategy.md');\n}\n\nexport function digestPath(cwd: string, sessionId: string): string {\n return join(sessionDir(cwd, sessionId), 'digest.json');\n}\n\nexport function logsDir(cwd: string, sessionId: string): string {\n return join(sessionDir(cwd, sessionId), 'logs');\n}\n\nexport function cycleLogPath(cwd: string, sessionId: string, cycle: number): string {\n return join(logsDir(cwd, sessionId), `cycle-${String(cycle).padStart(3, '0')}.md`);\n}\n\n// Backwards compat for old sessions\nexport function legacyLogsPath(cwd: string, sessionId: string): string {\n return join(sessionDir(cwd, sessionId), 'logs.md');\n}\n\nexport function snapshotsDir(cwd: string, sessionId: string): string {\n return join(sessionDir(cwd, sessionId), 'snapshots');\n}\n\nexport function snapshotDir(cwd: string, sessionId: string, cycle: number): string {\n return join(snapshotsDir(cwd, sessionId), `cycle-${cycle}`);\n}\n\nexport function tuiScratchDir(cwd: string, sessionId: string): string {\n return join(sessionDir(cwd, sessionId), '.tui');\n}\n\n// ── sisyphus ask: per-session ask directory and per-ask file paths ────────────\n\nexport function askDir(cwd: string, sessionId: string): string {\n return join(contextDir(cwd, sessionId), 'ask');\n}\n\nexport function askEntryDir(cwd: string, sessionId: string, askId: string): string {\n return join(askDir(cwd, sessionId), askId);\n}\n\nexport function askMetaPath(cwd: string, sessionId: string, askId: string): string {\n return join(askEntryDir(cwd, sessionId, askId), 'meta.json');\n}\n\nexport function askDecisionsPath(cwd: string, sessionId: string, askId: string): string {\n return join(askEntryDir(cwd, sessionId, askId), 'decisions.json');\n}\n\nexport function askOutputPath(cwd: string, sessionId: string, askId: string): string {\n return join(askEntryDir(cwd, sessionId, askId), 'output.json');\n}\n\nexport function askProgressPath(cwd: string, sessionId: string, askId: string): string {\n return join(askEntryDir(cwd, sessionId, askId), 'progress.json');\n}\n\nexport function askVisualsDir(cwd: string, sessionId: string, askId: string): string {\n return join(askEntryDir(cwd, sessionId, askId), 'visuals');\n}\n\nexport function askVisualMarkdownPath(cwd: string, sessionId: string, askId: string, qid: string): string {\n return join(askVisualsDir(cwd, sessionId, askId), `${qid}.md`);\n}\n\nexport function askVisualAnsiPath(cwd: string, sessionId: string, askId: string, qid: string): string {\n return join(askVisualsDir(cwd, sessionId, askId), `${qid}.ansi`);\n}\n\nexport function tmuxSessionName(cwd: string, sessionLabel: string): string {\n // Use underscores as separators — slashes break tmux -t target resolution,\n // dots get silently converted to underscores by tmux (reserved for window.pane targeting)\n return `ssyph_${basename(cwd)}_${sessionLabel}`;\n}\n\nexport function sessionsManifestPath(): string {\n return join(globalDir(), 'sessions-manifest.json');\n}\n\nexport function sessionsManifestTsvPath(): string {\n return join(globalDir(), 'sessions-manifest.tsv');\n}\n\nexport function companionPath(): string {\n return join(globalDir(), 'companion.json');\n}\n\nexport function companionMemoryPath(): string {\n return join(globalDir(), 'companion-memory.json');\n}\n\nexport function historyBaseDir(): string {\n return join(globalDir(), 'history');\n}\n\nexport function historySessionDir(sessionId: string): string {\n return join(historyBaseDir(), sessionId);\n}\n\nexport function historyEventsPath(sessionId: string): string {\n return join(historySessionDir(sessionId), 'events.jsonl');\n}\n\nexport function historySessionSummaryPath(sessionId: string): string {\n return join(historySessionDir(sessionId), 'session.json');\n}\n\n// ── sisyphus deploy: per-provider Terraform state + creds ────────────────────\n\nexport function deployDir(): string {\n return join(globalDir(), 'deploy');\n}\n\nexport function deployProviderDir(provider: string): string {\n return join(deployDir(), provider);\n}\n\nexport function deployStatePath(provider: string): string {\n return join(deployProviderDir(provider), 'terraform.tfstate');\n}\n\nexport function deployStateBackupPath(provider: string): string {\n return join(deployProviderDir(provider), 'terraform.tfstate.bak');\n}\n\nexport function deployRuntimePath(provider: string): string {\n return join(deployProviderDir(provider), 'runtime.json');\n}\n\nexport function deployCredsPath(provider: string): string {\n return join(deployDir(), `${provider}.env`);\n}\n\nexport function deployTailscaleEnvPath(): string {\n return join(deployDir(), 'tailscale.env');\n}\n\n// ── sisyphus cloud: per-repo box-side paths (remote, not local fs) ───────────\n\n/**\n * Path on the cloud box where a repo's working tree is rsync'd to.\n * `~/projects/<repo>` — interpreted by the box's shell, so this is a string\n * template, not for local fs use.\n */\nexport function boxRepoPath(repo: string): string {\n return `~/projects/${repo}`;\n}\n\n/**\n * Path on the cloud box where the per-repo cloud-state sidecar lives. Mirrors\n * the local `~/.sisyphus/deploy/<provider>/runtime.json` convention but for\n * the box's own `~/.sisyphus/cloud/<repo>.json`.\n */\nexport function boxCloudSidecarPath(repo: string): string {\n return `~/.sisyphus/cloud/${repo}.json`;\n}\n\nexport function boxCloudSidecarDir(): string {\n return `~/.sisyphus/cloud`;\n}\n\nexport function isSisyphusSession(name: string): boolean {\n return name.startsWith('ssyph_');\n}\n\nexport function tmuxSessionDisplayName(name: string): string {\n return name.replace(/^ssyph_[^_]+_/, '');\n}\n\n","import { execSync } from 'node:child_process';\nimport { existsSync, readFileSync } from 'node:fs';\n\nexport type Platform = 'darwin' | 'linux' | 'wsl' | 'win32' | 'unknown';\n\nlet cachedPlatform: Platform | undefined;\n\n/**\n * Detect the host platform, distinguishing WSL from native Linux.\n *\n * WSL detection: Microsoft injects \"Microsoft\"/\"WSL\" into /proc/version, and\n * WSL2 sets WSL_DISTRO_NAME. We check both so it works in minimal containers\n * where /proc/version may be unreadable but env is preserved.\n */\nexport function detectPlatform(): Platform {\n if (cachedPlatform) return cachedPlatform;\n\n if (process.platform === 'darwin') {\n cachedPlatform = 'darwin';\n } else if (process.platform === 'win32') {\n cachedPlatform = 'win32';\n } else if (process.platform === 'linux') {\n cachedPlatform = isWsl() ? 'wsl' : 'linux';\n } else {\n cachedPlatform = 'unknown';\n }\n return cachedPlatform;\n}\n\nfunction isWsl(): boolean {\n if (process.env['WSL_DISTRO_NAME'] || process.env['WSL_INTEROP']) return true;\n try {\n if (existsSync('/proc/version')) {\n const v = readFileSync('/proc/version', 'utf-8').toLowerCase();\n if (v.includes('microsoft') || v.includes('wsl')) return true;\n }\n } catch { /* ignore */ }\n return false;\n}\n\n/** True if the platform supports the macOS-only Swift notify app, pbcopy, launchd, etc. */\nexport function isDarwin(): boolean { return detectPlatform() === 'darwin'; }\n\n/** True if running under WSL (any version). Use this for WSL-specific tool selection. */\nexport function isWslHost(): boolean { return detectPlatform() === 'wsl'; }\n\n/** True for native or WSL Linux — both share apt/dnf/notify-send/xdg-open ecosystems. */\nexport function isLinuxLike(): boolean {\n const p = detectPlatform();\n return p === 'linux' || p === 'wsl';\n}\n\n/**\n * True if a given command is on PATH. Uses `command -v` (POSIX) so it works in\n * subshells with the same PATH the daemon/CLI sees. Cached per-process.\n */\nconst cmdCache = new Map<string, boolean>();\nexport function hasCommand(cmd: string): boolean {\n const cached = cmdCache.get(cmd);\n if (cached !== undefined) return cached;\n try {\n execSync(`command -v ${cmd}`, { stdio: 'pipe', shell: '/bin/sh' });\n cmdCache.set(cmd, true);\n return true;\n } catch {\n cmdCache.set(cmd, false);\n return false;\n }\n}\n\n/** Human-readable platform label, e.g. for `sis admin doctor`. */\nexport function platformLabel(): string {\n switch (detectPlatform()) {\n case 'darwin': return 'macOS';\n case 'wsl': {\n const distro = process.env['WSL_DISTRO_NAME'];\n return distro ? `WSL (${distro})` : 'WSL';\n }\n case 'linux': return 'Linux';\n case 'win32': return 'Windows (native)';\n default: return 'unknown';\n }\n}\n","import stringWidth from 'string-width';\nimport type { Seg, DetailLine } from './lib/format.js';\nimport type { ThrottledScroll } from './state.js';\n\nexport type { Seg, DetailLine };\n\n// ─── Color mapping ────────────────────────────────────────────────────────────\n\nexport const COLOR_SGR: Record<string, number> = {\n black: 30,\n red: 31,\n green: 32,\n yellow: 33,\n blue: 34,\n magenta: 35,\n cyan: 36,\n white: 37,\n gray: 90,\n};\n\nexport function colorToSGR(color: string): number {\n const code = COLOR_SGR[color];\n if (code === undefined) throw new Error(`Unknown color: ${color}`);\n return code;\n}\n\n// ─── Seg → ANSI conversion (§1.1) ────────────────────────────────────────────\n\nexport function renderLine(segs: Seg[]): string {\n let out = '';\n for (const s of segs) {\n const codes: string[] = [];\n if (s.bold) codes.push('1');\n if (s.dim) codes.push('2');\n if (s.italic) codes.push('3');\n if (s.strikethrough) codes.push('9');\n if (s.inverse) codes.push('7');\n if (s.fg) codes.push(s.fg);\n else if (s.color) codes.push(String(colorToSGR(s.color)));\n if (s.bg) codes.push(s.bg);\n if (codes.length > 0) {\n out += `\\x1b[${codes.join(';')}m${s.text}\\x1b[0m`;\n } else {\n out += s.text;\n }\n }\n return out;\n}\n\n// ─── Frame Buffer (§1.2) ──────────────────────────────────────────────────────\n\nexport interface FrameBuffer {\n lines: string[];\n width: number;\n height: number;\n}\n\nlet cachedBlank = '';\nlet cachedBlankWidth = 0;\n\nexport function createFrameBuffer(width: number, height: number): FrameBuffer {\n if (width !== cachedBlankWidth) {\n cachedBlank = ' '.repeat(width);\n cachedBlankWidth = width;\n }\n const lines = new Array<string>(height);\n for (let i = 0; i < height; i++) lines[i] = cachedBlank;\n return { lines, width, height };\n}\n\n/**\n * Copy rows from a previous frame into the buffer (skip re-render for clean panels).\n */\nexport function copyRows(buf: FrameBuffer, src: string[], startRow: number, count: number): void {\n for (let i = 0; i < count && startRow + i < buf.height; i++) {\n buf.lines[startRow + i] = src[startRow + i]!;\n }\n}\n\n// ─── Frame Diffing (§1.3) ────────────────────────────────────────────────────\n\nexport function flushFrame(frame: string[], prevFrame: string[], suffix?: string): string {\n let out = '\\x1b[?2026h'; // begin synchronized output\n for (let i = 0; i < frame.length; i++) {\n if (frame[i] !== prevFrame[i]) {\n out += `\\x1b[${i + 1};1H`; // cursor to row i+1, col 1\n out += '\\x1b[2K'; // clear entire line\n out += frame[i];\n }\n }\n if (suffix) out += suffix;\n out += '\\x1b[?2026l'; // end synchronized output\n return out;\n}\n\n// ─── ANSI escape sequence regex ───────────────────────────────────────────────\n\nconst ANSI_RE = /\\x1b\\[[0-9;]*[a-zA-Z]/g;\n\n// ─── Clip ANSI string to display width (no buffer interaction) ──────────────\n\n/**\n * Clip an ANSI string to exactly `maxWidth` display columns, padding with spaces.\n * Pure function — no buffer splicing.\n */\nexport function clipAnsi(content: string, maxWidth: number): string {\n let out = '';\n let displayWidth = 0;\n let i = 0;\n\n while (i < content.length) {\n if (content[i] === '\\x1b' && content[i + 1] === '[') {\n const seqLen = ansiLen(content, i);\n if (seqLen > 0) {\n out += content.substring(i, i + seqLen);\n i += seqLen;\n continue;\n }\n }\n const cp = content.codePointAt(i)!;\n // Skip control characters (newlines, tabs, etc.) — they break frame output\n if (cp < 0x20 && cp !== 0x1b) { i++; continue; }\n const ch = String.fromCodePoint(cp);\n const chWidth = cp < 128 ? 1 : stringWidth(ch);\n if (displayWidth + chWidth > maxWidth) break;\n out += ch;\n displayWidth += chWidth;\n i += ch.length;\n }\n\n if (out.includes('\\x1b[') && !out.endsWith('\\x1b[0m')) {\n out += '\\x1b[0m';\n }\n\n const remaining = maxWidth - displayWidth;\n if (remaining > 0) out += ' '.repeat(remaining);\n return out;\n}\n\n/**\n * Fast display-width calculation that skips ANSI escapes without regex allocation.\n */\nfunction displayWidthFast(s: string): number {\n let w = 0;\n let i = 0;\n while (i < s.length) {\n if (s[i] === '\\x1b' && s[i + 1] === '[') {\n const len = ansiLen(s, i);\n if (len > 0) { i += len; continue; }\n }\n const cp = s.codePointAt(i)!;\n const ch = String.fromCodePoint(cp);\n w += cp < 128 ? 1 : stringWidth(ch);\n i += ch.length;\n }\n return w;\n}\n\n/**\n * Parse ANSI escape sequence at position i. Returns length of sequence or 0.\n * Avoids s.slice(i).match(regex) which allocates a new string each call.\n */\nfunction ansiLen(s: string, i: number): number {\n // Caller already verified s[i] === '\\x1b' && s[i+1] === '['\n let j = i + 2;\n const len = s.length;\n // Consume parameter bytes: digits 0-9 and semicolons\n while (j < len) {\n const c = s.charCodeAt(j);\n if ((c >= 0x30 && c <= 0x39) || c === 0x3b) { // '0'-'9' or ';'\n j++;\n } else {\n break;\n }\n }\n // Must end with a letter (final byte)\n if (j < len) {\n const c = s.charCodeAt(j);\n if ((c >= 0x41 && c <= 0x5a) || (c >= 0x61 && c <= 0x7a)) { // A-Z or a-z\n return j + 1 - i;\n }\n }\n return 0;\n}\n\n// ─── Write functions ──────────────────────────────────────────────────────────\n\n/**\n * Write content into frame buffer at position (x, y).\n *\n * Strategy: rebuild the target line by splitting into display columns,\n * inserting the new content, then reassembling. Since we build the frame\n * fresh each render, we can treat the existing line as plain chars + ANSI.\n *\n * This implementation replaces display columns [x, x+displayWidth(content))\n * in the buffer line with the new content.\n */\nexport function writeAt(buf: FrameBuffer, x: number, y: number, content: string): void {\n if (y < 0 || y >= buf.height) return;\n if (x < 0 || x >= buf.width) return;\n\n const existing = buf.lines[y]!;\n const contentDisplayWidth = stringWidth(content.replace(ANSI_RE, ''));\n\n // Split the existing line into prefix (0..x) and suffix (x+contentDisplayWidth..)\n // We need to walk the existing line respecting display widths.\n // suffix uses restoreState=true to preserve ANSI bg/fg from before the splice point.\n const prefix = sliceDisplayCols(existing, 0, x);\n const suffix = sliceDisplayCols(existing, x + contentDisplayWidth, buf.width, true);\n\n // Pad prefix if it's shorter than expected (can happen at end of line)\n const prefixWidth = stringWidth(prefix.replace(ANSI_RE, ''));\n const paddedPrefix = prefix + ' '.repeat(Math.max(0, x - prefixWidth));\n\n buf.lines[y] = paddedPrefix + content + suffix;\n}\n\n/**\n * Write ANSI string into buffer at (x, y), truncating to maxWidth display columns.\n * Pads remaining width with spaces.\n */\nexport function writeClipped(\n buf: FrameBuffer,\n x: number,\n y: number,\n content: string,\n maxWidth: number,\n): void {\n if (y < 0 || y >= buf.height) return;\n if (x < 0 || x >= buf.width) return;\n\n let out = '';\n let displayWidth = 0;\n let i = 0;\n\n while (i < content.length) {\n // Check for ANSI escape sequence — pass through without counting width\n if (content[i] === '\\x1b' && content[i + 1] === '[') {\n const seqLen = ansiLen(content, i);\n if (seqLen > 0) {\n out += content.substring(i, i + seqLen);\n i += seqLen;\n continue;\n }\n }\n\n // Get the next character (handle surrogate pairs)\n const cp = content.codePointAt(i)!;\n // Skip control characters (newlines, tabs, etc.) — they break frame output\n if (cp < 0x20 && cp !== 0x1b) { i++; continue; }\n const ch = String.fromCodePoint(cp);\n const chWidth = cp < 128 ? 1 : stringWidth(ch);\n\n if (displayWidth + chWidth > maxWidth) break;\n\n out += ch;\n displayWidth += chWidth;\n i += ch.length;\n }\n\n // Ensure any open SGR sequences are reset\n if (out.includes('\\x1b[') && !out.endsWith('\\x1b[0m')) {\n out += '\\x1b[0m';\n }\n\n // Pad to maxWidth\n const remaining = maxWidth - displayWidth;\n if (remaining > 0) {\n out += ' '.repeat(remaining);\n }\n\n // Splice directly into buffer line — we already know exact display width is maxWidth,\n // so skip writeAt's redundant stringWidth + double sliceDisplayCols re-parse.\n const existing = buf.lines[y]!;\n const prefix = sliceDisplayCols(existing, 0, x);\n const suffix = sliceDisplayCols(existing, x + maxWidth, buf.width, true);\n const prefixDisplayW = displayWidthFast(prefix);\n const paddedPrefix = prefixDisplayW < x ? prefix + ' '.repeat(x - prefixDisplayW) : prefix;\n buf.lines[y] = paddedPrefix + out + suffix;\n}\n\n/**\n * Write centered text at the given row.\n */\nexport function writeCenter(buf: FrameBuffer, row: number, content: string): void {\n const textWidth = stringWidth(content.replace(ANSI_RE, ''));\n const x = Math.max(0, Math.floor((buf.width - textWidth) / 2));\n writeAt(buf, x, row, content);\n}\n\n// ─── Border Drawing (§1.5) ────────────────────────────────────────────────────\n\nexport function drawBorder(\n buf: FrameBuffer,\n x: number,\n y: number,\n w: number,\n h: number,\n color: string,\n): void {\n const sgr = `\\x1b[${colorToSGR(color)}m`;\n const reset = '\\x1b[0m';\n\n // Top: ╭────╮\n writeAt(buf, x, y, sgr + '╭' + '─'.repeat(w - 2) + '╮' + reset);\n // Bottom: ╰────╯\n writeAt(buf, x, y + h - 1, sgr + '╰' + '─'.repeat(w - 2) + '╯' + reset);\n // Sides\n for (let row = y + 1; row < y + h - 1; row++) {\n writeAt(buf, x, row, sgr + '│' + reset);\n writeAt(buf, x + w - 1, row, sgr + '│' + reset);\n }\n}\n\n// ─── Panel Rendering (§4.2) ───────────────────────────────────────────────────\n\nexport interface Rect {\n x: number;\n y: number;\n w: number;\n h: number;\n}\n\n/**\n * Cache for pre-rendered ANSI strings. Keyed by the DetailLine[] identity —\n * when the caller provides a `renderedCache`, renderPanel will populate it\n * on first render and reuse on subsequent frames (avoiding renderLine per line).\n */\nexport interface RenderedCache {\n lines: DetailLine[];\n ansi: string[];\n}\n\nexport function renderPanel(\n buf: FrameBuffer,\n rect: Rect,\n lines: DetailLine[],\n scrollOffset: number,\n focused: boolean,\n borderColor: string,\n renderedCache?: RenderedCache | null,\n): void {\n const { x, y, w, h } = rect;\n\n // 1. Draw border\n drawBorder(buf, x, y, w, h, focused ? 'blue' : borderColor);\n\n // 2. Inner dimensions (border + 1 padding each side, matching Ink's paddingX={1})\n const innerX = x + 2;\n const innerW = w - 4;\n const innerY = y + 1;\n const innerH = h - 2;\n\n if (innerW <= 0 || innerH <= 0) return;\n\n // 3. Pre-render ANSI strings (cached across frames)\n let ansiLines: string[];\n if (renderedCache && renderedCache.lines === lines) {\n ansiLines = renderedCache.ansi;\n } else {\n ansiLines = new Array<string>(lines.length);\n for (let i = 0; i < lines.length; i++) {\n ansiLines[i] = renderLine(lines[i]!);\n }\n if (renderedCache) {\n renderedCache.lines = lines;\n renderedCache.ansi = ansiLines;\n }\n }\n\n // 4. Windowed slice\n const hasOverflow = lines.length > innerH;\n const viewableH = hasOverflow ? innerH - 1 : innerH;\n const maxScroll = Math.max(0, lines.length - viewableH);\n const effectiveOffset = Math.min(scrollOffset, maxScroll);\n\n // 5. Render visible lines\n for (let i = 0; i < viewableH && effectiveOffset + i < ansiLines.length; i++) {\n writeClipped(buf, innerX, innerY + i, ansiLines[effectiveOffset + i]!, innerW);\n }\n\n // 6. Scroll indicator\n if (hasOverflow) {\n const scrollPct = maxScroll > 0 ? Math.round((effectiveOffset / maxScroll) * 100) : 100;\n const indicator = ` ↕ ${scrollPct}% · ${lines.length} lines`;\n writeClipped(buf, innerX, innerY + viewableH, `\\x1b[2m${indicator}\\x1b[0m`, innerW);\n }\n}\n\n/**\n * Build panel as self-contained row strings (w display-columns each, including borders).\n * Returns h strings. No buffer interaction — avoids sliceDisplayCols entirely.\n */\nexport function buildPanelRows(\n rect: Rect,\n lines: DetailLine[],\n scroll: ThrottledScroll,\n focused: boolean,\n borderColor: string,\n renderedCache?: RenderedCache | null,\n): string[] {\n const { w, h } = rect;\n const rows = new Array<string>(h);\n\n const color = focused ? 'cyan' : 'gray';\n const sgr = `\\x1b[${colorToSGR(color)}m`;\n const reset = '\\x1b[0m';\n const innerW = w - 4;\n const innerH = h - 2;\n const blankInner = ' '.repeat(innerW);\n\n // Top border\n rows[0] = sgr + '╭' + '─'.repeat(w - 2) + '╮' + reset;\n // Bottom border\n rows[h - 1] = sgr + '╰' + '─'.repeat(w - 2) + '╯' + reset;\n\n // Pre-fill interior rows with empty content\n const borderL = sgr + '│' + reset + ' ';\n const borderR = ' ' + sgr + '│' + reset;\n const emptyRow = borderL + blankInner + borderR;\n for (let i = 1; i < h - 1; i++) rows[i] = emptyRow;\n\n if (innerW <= 0 || innerH <= 0) return rows;\n\n // Pre-render ANSI strings (cached across frames)\n let ansiLines: string[];\n if (renderedCache && renderedCache.lines === lines) {\n ansiLines = renderedCache.ansi;\n } else {\n ansiLines = new Array<string>(lines.length);\n for (let i = 0; i < lines.length; i++) {\n ansiLines[i] = renderLine(lines[i]!);\n }\n if (renderedCache) {\n renderedCache.lines = lines;\n renderedCache.ansi = ansiLines;\n }\n }\n\n // Windowed slice\n const hasOverflow = lines.length > innerH;\n const viewableH = hasOverflow ? innerH - 1 : innerH;\n const maxScroll = Math.max(0, lines.length - viewableH);\n scroll.setMax(maxScroll);\n const effectiveOffset = scroll.offset;\n\n // Content rows — clip and compose without buffer splicing\n for (let i = 0; i < viewableH && effectiveOffset + i < ansiLines.length; i++) {\n const clipped = clipAnsi(ansiLines[effectiveOffset + i]!, innerW);\n rows[1 + i] = borderL + clipped + borderR;\n }\n\n // Scroll indicator\n if (hasOverflow) {\n const scrollPct = maxScroll > 0 ? Math.round((effectiveOffset / maxScroll) * 100) : 100;\n const indicator = ` ↕ ${scrollPct}% · ${lines.length} lines`;\n const clipped = clipAnsi(`\\x1b[2m${indicator}\\x1b[0m`, innerW);\n rows[1 + viewableH] = borderL + clipped + borderR;\n }\n\n return rows;\n}\n\n/**\n * Build empty panel rows (border only, no content).\n */\nexport function buildEmptyPanelRows(\n rect: Rect,\n focused: boolean,\n borderColor: string,\n centerText?: string,\n): string[] {\n const { w, h } = rect;\n const rows = new Array<string>(h);\n const color = focused ? 'cyan' : 'gray';\n const sgr = `\\x1b[${colorToSGR(color)}m`;\n const reset = '\\x1b[0m';\n const innerW = w - 4;\n const borderL = sgr + '│' + reset + ' ';\n const borderR = ' ' + sgr + '│' + reset;\n const emptyRow = borderL + ' '.repeat(innerW) + borderR;\n\n rows[0] = sgr + '╭' + '─'.repeat(w - 2) + '╮' + reset;\n rows[h - 1] = sgr + '╰' + '─'.repeat(w - 2) + '╯' + reset;\n for (let i = 1; i < h - 1; i++) rows[i] = emptyRow;\n\n if (centerText) {\n const midRow = Math.floor(h / 2);\n if (midRow > 0 && midRow < h - 1) {\n const clipped = clipAnsi(centerText, innerW);\n // Center within panel\n const textW = displayWidthFast(centerText);\n const pad = Math.max(0, Math.floor((innerW - textW) / 2));\n const centered = ' '.repeat(pad) + clipped;\n rows[midRow] = borderL + clipAnsi(centered, innerW) + borderR;\n }\n }\n\n return rows;\n}\n\n// ─── Internal helpers ─────────────────────────────────────────────────────────\n\n/**\n * Slice a string (which may contain ANSI escapes) to display columns [start, end).\n * ANSI sequences are passed through only within the slice range.\n */\nfunction sliceDisplayCols(s: string, start: number, end: number, restoreState = false): string {\n let out = '';\n let col = 0;\n let i = 0;\n let inSlice = false;\n let hasOpenSGR = false;\n\n // When restoreState is true, track the last ANSI state before the slice\n // so it can be prepended — restores bg/fg colors that were set earlier in the line.\n let pendingSGR = '';\n\n while (i < s.length && col < end) {\n // ANSI escape: pass through if we're in the slice\n if (s[i] === '\\x1b' && s[i + 1] === '[') {\n const seqLen = ansiLen(s, i);\n if (seqLen > 0) {\n const seq = s.substring(i, i + seqLen);\n if (col >= start) {\n out += seq;\n // Track if we have open SGR (non-reset)\n hasOpenSGR = seq !== '\\x1b[0m' && seq !== '\\x1b[m';\n } else if (restoreState) {\n // Accumulate ANSI state from before the slice\n if (seq === '\\x1b[0m' || seq === '\\x1b[m') {\n pendingSGR = '';\n } else {\n pendingSGR += seq;\n }\n }\n i += seqLen;\n continue;\n }\n }\n\n const cp = s.codePointAt(i)!;\n const ch = String.fromCodePoint(cp);\n const chWidth = cp < 128 ? 1 : stringWidth(ch);\n\n if (col >= start) {\n inSlice = true;\n // Don't emit char that would overflow end\n if (col + chWidth > end) break;\n out += ch;\n }\n\n col += chWidth;\n i += ch.length;\n }\n\n // Close any open SGR\n if (inSlice && hasOpenSGR) {\n out += '\\x1b[0m';\n }\n\n // Prepend accumulated state so suffix inherits the correct colors\n if (restoreState && pendingSGR) {\n out = pendingSGR + out;\n }\n\n return out;\n}\n","import { readFileSync } from 'node:fs';\nimport { globalConfigPath, projectConfigPath } from './paths.js';\nimport type { StatusBarConfig } from './types.js';\n\nexport type EffortLevel = 'low' | 'medium' | 'high' | 'xhigh' | 'max';\n\nexport interface NotificationConfig {\n enabled?: boolean;\n sound?: string;\n}\n\nexport interface RequiredPlugin {\n name: string;\n marketplace: string;\n}\n\nexport interface UploadConfig {\n /** Worker base URL, e.g. https://sisyphus-upload-proxy.rhyneer-silas.workers.dev */\n url: string;\n /** Bearer token, format `sisyphus_pat_<43-char-base64url>` */\n token: string;\n}\n\nexport interface Config {\n model?: string;\n tmuxSession?: string;\n orchestratorPrompt?: string;\n pollIntervalMs?: number;\n autoUpdate?: boolean;\n orchestratorEffort?: EffortLevel;\n agentEffort?: EffortLevel;\n editor?: string;\n repos?: string[];\n notifications?: NotificationConfig;\n companionPopup?: boolean;\n requiredPlugins?: RequiredPlugin[];\n statusBar?: StatusBarConfig;\n upload?: UploadConfig;\n}\n\nconst DEFAULT_CONFIG: Config = {\n model: 'claude-opus-4-7[1m]',\n pollIntervalMs: 5000,\n orchestratorEffort: 'xhigh',\n agentEffort: 'medium',\n notifications: {\n enabled: true,\n sound: '/System/Library/Sounds/Hero.aiff',\n },\n companionPopup: true,\n requiredPlugins: [\n { name: 'devcore', marketplace: 'crouton-kit' },\n ],\n};\n\nfunction readJsonFile(filePath: string): Partial<Config> {\n try {\n const content = readFileSync(filePath, 'utf-8');\n return JSON.parse(content) as Partial<Config>;\n } catch {\n return {};\n }\n}\n\nexport function loadConfig(cwd: string): Config {\n const globalConfig = readJsonFile(globalConfigPath());\n const projectConfig = readJsonFile(projectConfigPath(cwd));\n if (projectConfig.upload !== undefined) {\n console.warn(\n 'ignoring `upload` block from project-local .sisyphus/config.json — only the global config can set upload credentials',\n );\n delete projectConfig.upload;\n }\n const merged: Config = { ...DEFAULT_CONFIG, ...globalConfig, ...projectConfig };\n if (globalConfig.statusBar || projectConfig.statusBar) {\n merged.statusBar = {\n ...merged.statusBar,\n ...globalConfig.statusBar,\n ...projectConfig.statusBar,\n colors: {\n ...merged.statusBar?.colors,\n ...globalConfig.statusBar?.colors,\n ...projectConfig.statusBar?.colors,\n },\n segments: {\n ...merged.statusBar?.segments,\n ...globalConfig.statusBar?.segments,\n ...projectConfig.statusBar?.segments,\n },\n };\n }\n return merged;\n}\n","import { appendFileSync, mkdirSync, writeFileSync, renameSync, readdirSync, readFileSync, rmSync, statSync } from 'node:fs';\nimport { randomUUID } from 'node:crypto';\nimport { dirname, join } from 'node:path';\nimport { historySessionDir, historyEventsPath, historySessionSummaryPath, historyBaseDir } from '../shared/paths.js';\nimport type { HistoryEventType, SessionSummary } from '../shared/history-types.js';\nimport type { MoodSignals } from '../shared/companion-types.js';\nimport type { Session } from '../shared/types.js';\n\n// Track which session dirs have been created this process to skip redundant mkdirSync\nconst knownDirs = new Set<string>();\n\nfunction ensureDir(sessionId: string): void {\n if (knownDirs.has(sessionId)) return;\n mkdirSync(historySessionDir(sessionId), { recursive: true });\n knownDirs.add(sessionId);\n}\n\nexport function emitHistoryEvent(sessionId: string, event: HistoryEventType, data: Record<string, unknown>): void {\n try {\n ensureDir(sessionId);\n const line = JSON.stringify({ ts: new Date().toISOString(), event, sessionId, data }) + '\\n';\n appendFileSync(historyEventsPath(sessionId), line, 'utf-8');\n } catch {\n // Fire-and-forget — history is best-effort\n }\n}\n\nexport function writeSessionSummary(\n session: Session,\n extra?: { achievements?: string[]; xpGained?: number; finalSignals?: MoodSignals; sentiment?: string },\n): void {\n try {\n ensureDir(session.id);\n\n const summary: SessionSummary = {\n sessionId: session.id,\n name: session.name ?? null,\n task: session.task,\n cwd: session.cwd,\n model: session.model ?? null,\n status: session.status,\n startedAt: session.createdAt,\n completedAt: session.completedAt ?? new Date().toISOString(),\n activeMs: session.activeMs,\n wallClockMs: session.wallClockMs ?? null,\n userBlockedMs: session.userBlockedMs ?? 0,\n agentCount: session.agents.length,\n crashCount: session.agents.filter(a => a.status === 'crashed').length,\n lostCount: session.agents.filter(a => a.status === 'lost').length,\n killedAgentCount: session.agents.filter(a => a.status === 'killed').length,\n rollbackCount: session.rollbackCount ?? 0,\n efficiency: session.wallClockMs\n ? Math.max(0, session.activeMs - (session.userBlockedMs ?? 0))\n / Math.max(1, session.wallClockMs - (session.userBlockedMs ?? 0))\n : null,\n cycleCount: session.orchestratorCycles.length,\n context: session.context ?? null,\n completionReport: session.completionReport ?? null,\n agents: session.agents.map(a => ({\n id: a.id,\n name: a.name,\n nickname: a.nickname ?? null,\n agentType: a.agentType,\n status: a.status,\n activeMs: a.activeMs,\n userBlockedMs: a.userBlockedMs ?? 0,\n spawnedAt: a.spawnedAt,\n completedAt: a.completedAt,\n restartCount: a.restartCount ?? 0,\n })),\n cycles: session.orchestratorCycles.map(c => ({\n cycle: c.cycle,\n mode: c.mode ?? null,\n agentsSpawned: c.agentsSpawned.length,\n activeMs: c.activeMs,\n userBlockedMs: c.userBlockedMs ?? 0,\n startedAt: c.timestamp,\n completedAt: c.completedAt ?? null,\n })),\n messages: session.messages.map(m => ({\n id: m.id,\n source: typeof m.source === 'string' ? m.source : m.source.type,\n content: m.content,\n timestamp: m.timestamp,\n })),\n finalMoodSignals: extra?.finalSignals ?? null,\n achievements: extra?.achievements ?? [],\n xpGained: extra?.xpGained ?? 0,\n sentiment: extra?.sentiment ?? null,\n };\n\n const filePath = historySessionSummaryPath(session.id);\n const tmp = join(dirname(filePath), `.session-${randomUUID()}.tmp`);\n writeFileSync(tmp, JSON.stringify(summary, null, 2), 'utf-8');\n renameSync(tmp, filePath);\n } catch (err) {\n console.error(`[history] Failed to write session summary for ${session.id}:`, err);\n }\n}\n\n/**\n * Load the most recent non-null sentiments from session history.\n * Scans at most `scanLimit` dirs (by mtime, newest first) to avoid reading everything.\n */\nexport function getRecentSentiments(count = 5, scanLimit = 30, overrideBaseDir?: string): Array<{ sentiment: string; task: string; completedAt: string }> {\n try {\n const base = overrideBaseDir ?? historyBaseDir();\n let entries: string[];\n try {\n entries = readdirSync(base);\n } catch {\n return [];\n }\n\n // Sort dirs by mtime descending (newest first)\n const withMtime: Array<{ name: string; mtime: number }> = [];\n for (const name of entries) {\n try {\n const st = statSync(join(base, name));\n if (st.isDirectory()) withMtime.push({ name, mtime: st.mtimeMs });\n } catch { continue; }\n }\n withMtime.sort((a, b) => b.mtime - a.mtime);\n\n const results: Array<{ sentiment: string; task: string; completedAt: string }> = [];\n const limit = Math.min(withMtime.length, scanLimit);\n for (let i = 0; i < limit && results.length < count; i++) {\n try {\n const raw = readFileSync(join(base, withMtime[i].name, 'session.json'), 'utf-8');\n const summary = JSON.parse(raw) as SessionSummary;\n if (summary.sentiment && summary.completedAt) {\n results.push({\n sentiment: summary.sentiment,\n task: summary.task.slice(0, 100),\n completedAt: summary.completedAt,\n });\n }\n } catch { continue; }\n }\n return results;\n } catch {\n return [];\n }\n}\n\nconst PRUNE_KEEP_COUNT = 200;\nconst PRUNE_KEEP_DAYS = 90;\n\nexport function pruneHistory(): void {\n try {\n const base = historyBaseDir();\n let entries: string[];\n try {\n entries = readdirSync(base);\n } catch {\n return; // No history dir yet\n }\n\n // Collect session dirs with their timestamps\n const sessions: Array<{ dir: string; startedAt: number }> = [];\n for (const name of entries) {\n const dir = join(base, name);\n try {\n const summaryPath = join(dir, 'session.json');\n const raw = readFileSync(summaryPath, 'utf-8');\n const summary = JSON.parse(raw) as { startedAt?: string };\n sessions.push({ dir, startedAt: new Date(summary.startedAt ?? 0).getTime() });\n } catch {\n // No session.json — try first line of events.jsonl for stable creation timestamp\n try {\n const eventsPath = join(dir, 'events.jsonl');\n const firstLine = readFileSync(eventsPath, 'utf-8').split('\\n')[0];\n const firstEvent = JSON.parse(firstLine) as { ts?: string };\n sessions.push({ dir, startedAt: new Date(firstEvent.ts ?? 0).getTime() });\n } catch {\n // Fall back to dir mtime only if events.jsonl is unreadable\n try {\n const st = statSync(dir);\n sessions.push({ dir, startedAt: st.mtimeMs });\n } catch {\n continue;\n }\n }\n }\n }\n\n if (sessions.length <= PRUNE_KEEP_COUNT) return;\n\n // Sort newest first\n sessions.sort((a, b) => b.startedAt - a.startedAt);\n\n const cutoff = Date.now() - PRUNE_KEEP_DAYS * 24 * 60 * 60 * 1000;\n for (let i = PRUNE_KEEP_COUNT; i < sessions.length; i++) {\n if (sessions[i].startedAt < cutoff) {\n rmSync(sessions[i].dir, { recursive: true, force: true });\n }\n }\n } catch {\n // Pruning is best-effort\n }\n}\n","import { randomUUID } from 'node:crypto';\nimport { dirname, join } from 'node:path';\nimport { renameSync, writeFileSync } from 'node:fs';\n\nexport function atomicWrite(filePath: string, data: string): void {\n const dir = dirname(filePath);\n const tmpPath = join(dir, `.atomic.${randomUUID()}.tmp`);\n writeFileSync(tmpPath, data, 'utf-8');\n renameSync(tmpPath, filePath);\n}\n\nconst locks = new Map<string, Promise<void>>();\n\nexport async function withLock<T>(key: string, fn: () => T): Promise<T> {\n const prev = locks.get(key) ?? Promise.resolve();\n let resolve!: () => void;\n const next = new Promise<void>(r => { resolve = r; });\n locks.set(key, next);\n await prev;\n try {\n return fn();\n } finally {\n resolve();\n if (locks.get(key) === next) {\n locks.delete(key);\n }\n }\n}\n","import { existsSync, readFileSync, writeFileSync } from 'node:fs';\nimport { join } from 'node:path';\n\nconst SISYPHUS_ENTRIES = ['.sisyphus'];\n\nconst SISYPHUS_HEADER = '# Sisyphus';\n\n/**\n * Ensures the project .gitignore includes entries for sisyphus generated artifacts.\n * Only runs in git repos. Creates .gitignore if missing. Skips entries already present.\n */\nexport function ensureSisyphusGitignore(cwd: string): void {\n // Only act in git repos\n if (!existsSync(join(cwd, '.git'))) return;\n\n const gitignorePath = join(cwd, '.gitignore');\n let content = '';\n\n if (existsSync(gitignorePath)) {\n content = readFileSync(gitignorePath, 'utf-8');\n }\n\n const lines = content.split('\\n');\n const missing = SISYPHUS_ENTRIES.filter(entry => !lines.some(line => line.trim() === entry));\n\n if (missing.length === 0) return;\n\n const block = [SISYPHUS_HEADER, ...missing].join('\\n');\n const separator = content.length > 0 && !content.endsWith('\\n\\n')\n ? content.endsWith('\\n') ? '\\n' : '\\n\\n'\n : '';\n\n writeFileSync(gitignorePath, content + separator + block + '\\n', 'utf-8');\n}\n","export type Provider = 'anthropic' | 'openai';\n\nexport interface StatusBarColors {\n processing?: string;\n stopped?: string;\n idle?: string;\n activeBg?: string;\n activeText?: string;\n inactiveText?: string;\n}\n\nexport interface SegmentConfig {\n bg?: string;\n activeBg?: string;\n [key: string]: unknown;\n}\n\nexport interface StatusBarConfig {\n enabled?: boolean;\n colors?: StatusBarColors;\n left?: string[];\n right?: string[];\n segments?: Record<string, SegmentConfig>;\n}\n\nexport type SessionStatus = 'active' | 'paused' | 'completed';\n\nexport type UploadStatus = 'pending' | 'uploaded' | 'failed';\n\n/**\n * Records intent to move a session to a cloud box (or pause for reclaim).\n * - `target` omitted ⇒ quiesce-only (used by reclaim's box-side pause step).\n * - `target` present ⇒ at next quiesce, daemon syncs state + working tree to\n * the box and respawns the orchestrator there via `sis resume`.\n */\nexport interface HandoffState {\n /** Cloud destination. Omitted means \"pause at next quiesce; do not push.\" */\n target?: { provider: string; repo: string };\n /** ISO timestamp when the RPC was received. */\n queuedAt: string;\n /** Set after a successful push to the box. */\n sentAt?: string;\n /** Set after a successful pull back to local. */\n reclaimedAt?: string;\n /** True when --force was passed; daemon interrupts in-flight work. */\n force: boolean;\n /**\n * Resume message injected on the box. Computed at queue time for --force\n * (since we know which agents/orchestrator are being interrupted), empty\n * for natural quiesce.\n */\n message?: string;\n /** Most recent failure during push; set so the user can retry from `sis list`. */\n lastError?: string;\n}\n\nexport type MessageSource =\n | { type: 'agent'; agentId: string }\n | { type: 'user' }\n | { type: 'system'; detail?: string };\n\nexport interface Message {\n id: string;\n source: MessageSource;\n content: string;\n summary: string;\n filePath?: string;\n timestamp: string;\n}\n\nexport type AgentStatus = 'running' | 'completed' | 'killed' | 'crashed' | 'lost';\n\nexport interface AgentReport {\n type: 'update' | 'final';\n filePath: string;\n summary: string;\n timestamp: string;\n}\n\nexport interface Session {\n id: string;\n name?: string;\n task: string;\n context?: string;\n cwd: string;\n status: SessionStatus;\n createdAt: string;\n completedAt?: string;\n activeMs: number;\n /** Set true when the orchestrator pane vanished unexpectedly or daemon-startup found a stuck session. */\n orphaned?: boolean;\n /** Reason string passed to markSessionOrphan — mirrors agent.killedReason. */\n orphanReason?: string;\n /** Cumulative time blocked on `sis ask` (blocking asks only). Subtracted from wallClockMs to compute efficiency. */\n userBlockedMs?: number;\n agents: Agent[];\n orchestratorCycles: OrchestratorCycle[];\n messages: Message[];\n completionReport?: string;\n parentSessionId?: string;\n tmuxSessionName?: string;\n tmuxSessionId?: string; // tmux $N session ID — stable across renames, exact-match targeting\n tmuxWindowId?: string;\n model?: string;\n wallClockMs?: number;\n startHour?: number;\n startDayOfWeek?: number;\n launchConfig?: { model?: string; context?: string; orchestratorPrompt?: string; };\n /** Cycles already credited to companion stats (prevents double-counting on continue→re-complete) */\n companionCreditedCycles?: number;\n /** activeMs already credited to companion stats */\n companionCreditedActiveMs?: number;\n /** Strength already credited to companion stats */\n companionCreditedStrength?: number;\n rollbackCount?: number;\n resumeCount?: number;\n continueCount?: number;\n companionCreditedWisdom?: number;\n /** Lifecycle of the upload to the Worker proxy. `undefined` means upload was never attempted. */\n uploadStatus?: UploadStatus;\n /** R2 storage key returned by the Worker, e.g. `users/silas/<sessionId>.zip`. Bucket is private; this is NOT a fetch-able URL. */\n uploadKey?: string;\n /** Clean error message extracted from the Worker's JSON response when `uploadStatus === 'failed'`. */\n uploadError?: string;\n /** Daemon-local `new Date().toISOString()` at the moment the success was persisted. */\n uploadCompletedAt?: string;\n effort?: 'low' | 'medium' | 'high' | 'xhigh';\n /**\n * When true, the daemon auto-resolves every new ask in this session by\n * picking the first option of each interaction. Toggleable per-session\n * from the dashboard via the `D` key.\n */\n dangerousMode?: boolean;\n /**\n * Cloud-handoff lifecycle marker. Set by `sis cloud handoff` (push to box)\n * or `sis admin quiesce` (pause-only). Presence with `sentAt` unset blocks\n * local respawn at the next quiesce point; presence with `sentAt` set means\n * the session lives on the box and can be `sis cloud reclaim`-ed.\n */\n handoff?: HandoffState;\n}\n\nexport interface StatusDigest {\n recentWork: string;\n unusualEvents: string[];\n currentActivity: string;\n whatsNext: string;\n effort?: string;\n}\n\nexport interface Agent {\n id: string;\n name: string;\n nickname?: string;\n agentType: string;\n provider?: Provider;\n claudeSessionId?: string;\n color: string;\n instruction: string;\n status: AgentStatus;\n spawnedAt: string;\n completedAt: string | null;\n activeMs: number;\n /** Cumulative time this agent was blocked on its own `sis ask` calls (blocking only). Subset of activeMs. */\n userBlockedMs?: number;\n reports: AgentReport[];\n paneId: string;\n repo: string;\n killedReason?: string;\n restartCount?: number;\n originalSpawnedAt?: string;\n resumeEnv?: string;\n resumeArgs?: string;\n /** Set true when the agent's pane vanished unexpectedly or pid+lstart no longer match. Orthogonal to status. */\n orphaned?: boolean;\n /** Captured at spawn time by `setupAgentPane` → first `tmux display-message #{pane_pid}`. */\n pid?: number;\n /** `ps -o lstart=` output captured at spawn. Compared during pid-sweep to detect PID recycling. */\n pidLstart?: string;\n /** Set true when `sis agent await` consumed this agent's report inline. Suppresses it from the next-cycle orchestrator prompt; one-way. */\n consumedInline?: boolean;\n}\n\nexport interface OrchestratorCycle {\n cycle: number;\n timestamp: string;\n completedAt?: string;\n activeMs: number;\n /** Cumulative time blocked on `sis ask` during this cycle (blocking asks only). */\n userBlockedMs?: number;\n interCycleGapMs?: number;\n agentsSpawned: string[];\n paneId?: string;\n claudeSessionId?: string;\n nextPrompt?: string;\n mode?: string;\n resumeEnv?: string;\n resumeArgs?: string;\n}\n\n// ── sisyphus ask: v2 interaction / deck types (mirror humanloop's published shapes) ──\n\nexport type InteractionKind = 'notify' | 'validation' | 'decision' | 'context' | 'error';\n\nexport interface InteractionOption {\n id: string;\n label: string;\n description?: string;\n shortcut?: string;\n}\n\nexport interface Interaction {\n id: string;\n title: string;\n subtitle?: string;\n body?: string;\n bodyPath?: string;\n options: InteractionOption[];\n allowFreetext?: boolean;\n freetextLabel?: string;\n kind?: InteractionKind;\n}\n\nexport interface ModeChainEntry {\n mode: string;\n /** Cycles spent in this segment. Absent for the trailing (current) entry. */\n cycles?: number;\n /** Active ms accumulated in this segment. Absent for the trailing entry. */\n activeMs?: number;\n}\n\nexport interface DeckSource {\n sessionName?: string;\n askedBy?: string;\n blockedSince?: string;\n /** For orchestrator mode-transition notify decks: ordered chain of modes visited. Trailing entry is the current mode. */\n modeChain?: ModeChainEntry[];\n}\n\nexport interface Deck {\n title?: string;\n source?: DeckSource;\n interactions: Interaction[];\n}\n\nexport interface InteractionResponse {\n id: string;\n selectedOptionId?: string;\n freetext?: string;\n}\n\nexport interface AskOutput {\n responses: InteractionResponse[];\n completedAt: string;\n}\n\nexport interface VisualBlock {\n questionId: string;\n content: string;\n status: 'loading' | 'ready' | 'error';\n}\n\nexport const ORCHESTRATOR_ASKED_BY = 'orchestrator' as const;\n\nexport type AskStatus = 'pending' | 'in-progress' | 'answered' | 'not-found';\n\nexport interface AskMeta {\n askId: string;\n askedBy: string;\n askedAt: string;\n status: AskStatus;\n blocking: boolean;\n pid?: number;\n startedAt?: string;\n completedAt?: string;\n orphaned?: boolean;\n /** ISO timestamp set by the heartbeat scanner when a stale-question notify ask is emitted; dedup key. */\n heartbeatNotifiedAt?: string;\n claudeSessionId?: string;\n cwd: string;\n title?: string;\n subtitle?: string;\n kind?: InteractionKind;\n /** Set on system-emitted error-kind asks; carries the takeover-dispatch context. */\n orphanTarget?: { kind: 'agent'; agentId: string; paneId?: string } | { kind: 'orchestrator' };\n /** Set on orchestrator mode-transition notify asks; aggregation key for rolling mode-change notifications. */\n modeTransition?: true;\n}\n","import { copyFileSync, cpSync, existsSync, mkdirSync, readFileSync, readdirSync, rmSync, statSync, writeFileSync } from 'node:fs';\nimport { join } from 'node:path';\nimport { atomicWrite, withLock } from './lib/atomic.js';\nimport { contextDir, goalPath, initialPromptPath, legacyLogsPath, logsDir, reportsDir, roadmapPath, promptsDir, sessionDir, snapshotDir, snapshotsDir, statePath, strategyPath } from '../shared/paths.js';\nimport { ensureSisyphusGitignore } from '../shared/gitignore.js';\nimport type { Agent, AgentReport, AgentStatus, Message, OrchestratorCycle, Session, SessionStatus } from '../shared/types.js';\nimport { ORCHESTRATOR_ASKED_BY } from '../shared/types.js';\n\nconst ROADMAP_SEED = `---\ndescription: >\n Living document tracking development phases and outstanding work.\n---\n`;\n\nconst CONTEXT_CLAUDE_MD = `# context/\n\nAgents save exploration findings, architectural notes, and reference material here for use across cycles.\n`;\n\nfunction withSessionLock<T>(sessionId: string, fn: () => T): Promise<T> {\n return withLock(sessionId, fn);\n}\n\nexport function createSession(id: string, task: string, cwd: string, context?: string, name?: string, effort?: 'low' | 'medium' | 'high' | 'xhigh'): Session {\n ensureSisyphusGitignore(cwd);\n\n const dir = sessionDir(cwd, id);\n mkdirSync(dir, { recursive: true });\n mkdirSync(contextDir(cwd, id), { recursive: true });\n mkdirSync(promptsDir(cwd, id), { recursive: true });\n\n writeFileSync(roadmapPath(cwd, id), ROADMAP_SEED, 'utf-8');\n mkdirSync(logsDir(cwd, id), { recursive: true });\n writeFileSync(goalPath(cwd, id), task, 'utf-8');\n writeFileSync(initialPromptPath(cwd, id), task, 'utf-8');\n writeFileSync(join(contextDir(cwd, id), 'CLAUDE.md'), CONTEXT_CLAUDE_MD, 'utf-8');\n if (context) {\n writeFileSync(join(contextDir(cwd, id), 'initial-context.md'), context, 'utf-8');\n }\n\n const createdAt = new Date().toISOString();\n const created = new Date(createdAt);\n const session: Session = {\n id,\n ...(name ? { name } : {}),\n task,\n ...(context ? { context } : {}),\n cwd,\n status: 'active',\n createdAt,\n activeMs: 0,\n userBlockedMs: 0,\n agents: [],\n orchestratorCycles: [],\n messages: [],\n startHour: created.getHours(),\n startDayOfWeek: created.getDay(),\n orphaned: false,\n ...(effort ? { effort } : {}),\n };\n\n atomicWrite(statePath(cwd, id), JSON.stringify(session, null, 2));\n return session;\n}\n\nexport function getSession(cwd: string, sessionId: string): Session {\n const content = readFileSync(statePath(cwd, sessionId), 'utf-8');\n const session = JSON.parse(content) as Session;\n // Normalize fields from pre-existing sessions that may lack newer properties\n if (session.activeMs == null) session.activeMs = 0;\n if (session.userBlockedMs == null) session.userBlockedMs = 0;\n for (const agent of session.agents) {\n if (!agent.repo) agent.repo = '.';\n if (agent.activeMs == null) agent.activeMs = 0;\n if (agent.orphaned == null) agent.orphaned = false;\n // pid / pidLstart left undefined when absent — their absence signals \"not yet captured\"\n }\n if (session.orphaned == null) session.orphaned = false;\n // session.effort is intentionally not defaulted here — absence means \"not explicitly set\"\n // and consumers (agent.ts, orchestrator.ts, status.ts) fall back to 'high' at read time.\n // orphanReason is only set alongside orphaned=true; absent on healthy sessions and old state files\n for (const cycle of session.orchestratorCycles) {\n if (cycle.activeMs == null) cycle.activeMs = 0;\n if (cycle.userBlockedMs == null) cycle.userBlockedMs = 0;\n }\n return session;\n}\n\nfunction saveSession(session: Session): void {\n atomicWrite(statePath(session.cwd, session.id), JSON.stringify(session, null, 2));\n}\n\n/**\n * Returns true when the session has dangerousMode enabled. Safe to call before\n * the state file exists (e.g. mid-create) — returns false on any read error.\n */\nexport function isSessionDangerous(cwd: string, sessionId: string): boolean {\n try {\n return getSession(cwd, sessionId).dangerousMode === true;\n } catch {\n return false;\n }\n}\n\nexport async function addAgent(cwd: string, sessionId: string, agent: Agent): Promise<void> {\n return withSessionLock(sessionId, () => {\n const session = getSession(cwd, sessionId);\n session.agents.push(agent);\n saveSession(session);\n });\n}\n\nexport async function updateAgent(cwd: string, sessionId: string, agentId: string, updates: Partial<Agent>): Promise<void> {\n return withSessionLock(sessionId, () => {\n const session = getSession(cwd, sessionId);\n const agent = session.agents.slice().reverse().find((a: Agent) => a.id === agentId);\n if (!agent) throw new Error(`Agent ${agentId} not found in session ${sessionId}`);\n Object.assign(agent, updates);\n saveSession(session);\n });\n}\n\nexport async function markAgentOrphan(\n cwd: string,\n sessionId: string,\n agentId: string,\n opts: { reason: string; status?: AgentStatus; activeMs?: number },\n): Promise<void> {\n return withSessionLock(sessionId, () => {\n const session = getSession(cwd, sessionId);\n const agent = session.agents.slice().reverse().find((a: Agent) => a.id === agentId);\n if (!agent) throw new Error(`Agent ${agentId} not found in session ${sessionId}`);\n agent.orphaned = true;\n agent.status = opts.status !== undefined ? opts.status : 'lost';\n agent.killedReason = opts.reason;\n agent.completedAt = new Date().toISOString();\n if (opts.activeMs !== undefined) agent.activeMs = opts.activeMs;\n delete agent.pid;\n delete agent.pidLstart;\n saveSession(session);\n });\n}\n\nexport async function markSessionOrphan(\n cwd: string,\n sessionId: string,\n opts: { reason: string },\n): Promise<void> {\n return withSessionLock(sessionId, () => {\n const session = getSession(cwd, sessionId);\n session.orphaned = true;\n session.orphanReason = opts.reason;\n saveSession(session);\n });\n}\n\nexport async function clearSessionOrphan(cwd: string, sessionId: string): Promise<void> {\n return withSessionLock(sessionId, () => {\n const session = getSession(cwd, sessionId);\n if (!session.orphaned && session.orphanReason == null) return;\n session.orphaned = false;\n delete session.orphanReason;\n saveSession(session);\n });\n}\n\nexport async function clearAgentPidInfo(\n cwd: string,\n sessionId: string,\n agentId: string,\n): Promise<void> {\n return withSessionLock(sessionId, () => {\n const session = getSession(cwd, sessionId);\n const agent = session.agents.slice().reverse().find((a: Agent) => a.id === agentId);\n if (!agent) return;\n delete agent.pid;\n delete agent.pidLstart;\n saveSession(session);\n });\n}\n\nexport async function setAgentPid(\n cwd: string,\n sessionId: string,\n agentId: string,\n pid: number,\n pidLstart: string,\n): Promise<void> {\n return withSessionLock(sessionId, () => {\n const session = getSession(cwd, sessionId);\n const agent = session.agents.slice().reverse().find((a: Agent) => a.id === agentId);\n if (!agent) return;\n agent.pid = pid;\n agent.pidLstart = pidLstart;\n saveSession(session);\n });\n}\n\nexport async function setAgentConsumedInline(cwd: string, sessionId: string, agentId: string): Promise<void> {\n return withSessionLock(sessionId, () => {\n const session = getSession(cwd, sessionId);\n const agent = session.agents.slice().reverse().find((a: Agent) => a.id === agentId);\n if (!agent) throw new Error(`Agent ${agentId} not found in session ${sessionId}`);\n if (agent.consumedInline) return;\n agent.consumedInline = true;\n saveSession(session);\n });\n}\n\nexport async function addOrchestratorCycle(cwd: string, sessionId: string, cycle: OrchestratorCycle): Promise<void> {\n return withSessionLock(sessionId, () => {\n const session = getSession(cwd, sessionId);\n session.orchestratorCycles.push(cycle);\n saveSession(session);\n });\n}\n\nexport async function updateSessionStatus(cwd: string, sessionId: string, status: SessionStatus, completionReport?: string): Promise<void> {\n return withSessionLock(sessionId, () => {\n const session = getSession(cwd, sessionId);\n session.status = status;\n if (completionReport !== undefined) {\n session.completionReport = completionReport;\n }\n saveSession(session);\n });\n}\n\nexport async function appendAgentToLastCycle(cwd: string, sessionId: string, agentId: string): Promise<void> {\n return withSessionLock(sessionId, () => {\n const session = getSession(cwd, sessionId);\n const cycles = session.orchestratorCycles;\n if (cycles.length === 0) return;\n cycles[cycles.length - 1]!.agentsSpawned.push(agentId);\n saveSession(session);\n });\n}\n\nexport async function completeSession(cwd: string, sessionId: string, report: string): Promise<void> {\n return withSessionLock(sessionId, () => {\n const session = getSession(cwd, sessionId);\n session.status = 'completed';\n session.completedAt = new Date().toISOString();\n session.completionReport = report;\n saveSession(session);\n });\n}\n\nexport async function continueSession(cwd: string, sessionId: string): Promise<void> {\n return withSessionLock(sessionId, () => {\n const session = getSession(cwd, sessionId);\n if (session.status !== 'completed') {\n throw new Error(`Session ${sessionId} is not completed (status: ${session.status})`);\n }\n session.status = 'active';\n session.completedAt = undefined;\n session.completionReport = undefined;\n const cycles = session.orchestratorCycles;\n if (cycles.length > 0) {\n cycles[cycles.length - 1]!.completedAt = undefined;\n }\n saveSession(session);\n writeFileSync(roadmapPath(cwd, sessionId), '', 'utf-8');\n });\n}\n\nexport async function appendAgentReport(cwd: string, sessionId: string, agentId: string, entry: AgentReport): Promise<void> {\n return withSessionLock(sessionId, () => {\n const session = getSession(cwd, sessionId);\n const agent = session.agents.slice().reverse().find((a: Agent) => a.id === agentId);\n if (!agent) throw new Error(`Agent ${agentId} not found in session ${sessionId}`);\n agent.reports.push(entry);\n saveSession(session);\n });\n}\n\nexport async function updateReportSummary(\n cwd: string,\n sessionId: string,\n agentId: string,\n filePath: string,\n summary: string,\n): Promise<void> {\n return withSessionLock(sessionId, () => {\n const session = getSession(cwd, sessionId);\n const agent = session.agents.slice().reverse().find((a: Agent) => a.id === agentId);\n if (!agent) return;\n const report = agent.reports.find((r) => r.filePath === filePath);\n if (report) {\n report.summary = summary;\n saveSession(session);\n }\n });\n}\n\nexport async function updateSessionName(cwd: string, sessionId: string, name: string): Promise<void> {\n return withSessionLock(sessionId, () => {\n const session = getSession(cwd, sessionId);\n session.name = name;\n saveSession(session);\n });\n}\n\nexport async function updateSessionTmux(cwd: string, sessionId: string, tmuxSessionName: string, tmuxWindowId: string, tmuxSessionId?: string): Promise<void> {\n return withSessionLock(sessionId, () => {\n const session = getSession(cwd, sessionId);\n session.tmuxSessionName = tmuxSessionName;\n session.tmuxSessionId = tmuxSessionId;\n session.tmuxWindowId = tmuxWindowId;\n saveSession(session);\n });\n}\n\nexport async function updateSession(cwd: string, sessionId: string, updates: Partial<Session>): Promise<void> {\n return withSessionLock(sessionId, () => {\n const session = getSession(cwd, sessionId);\n Object.assign(session, updates);\n saveSession(session);\n });\n}\n\nexport async function drainMessages(cwd: string, sessionId: string, count: number): Promise<void> {\n return withSessionLock(sessionId, () => {\n const session = getSession(cwd, sessionId);\n if (!session.messages || count <= 0) return;\n session.messages = session.messages.slice(count);\n saveSession(session);\n });\n}\n\nexport async function appendMessage(cwd: string, sessionId: string, message: Message): Promise<void> {\n return withSessionLock(sessionId, () => {\n const session = getSession(cwd, sessionId);\n if (!session.messages) session.messages = [];\n session.messages.push(message);\n saveSession(session);\n });\n}\n\nexport async function updateTask(cwd: string, sessionId: string, task: string): Promise<void> {\n return withSessionLock(sessionId, () => {\n const session = getSession(cwd, sessionId);\n session.task = task;\n saveSession(session);\n writeFileSync(goalPath(cwd, sessionId), task, 'utf-8');\n });\n}\n\nexport async function completeOrchestratorCycle(cwd: string, sessionId: string, nextPrompt?: string, mode?: string, activeMs?: number): Promise<void> {\n return withSessionLock(sessionId, () => {\n const session = getSession(cwd, sessionId);\n const cycles = session.orchestratorCycles;\n if (cycles.length === 0) return;\n const cycle = cycles[cycles.length - 1]!;\n if (cycle.completedAt) return;\n cycle.completedAt = new Date().toISOString();\n if (nextPrompt) cycle.nextPrompt = nextPrompt;\n if (mode) cycle.mode = mode;\n if (activeMs != null) cycle.activeMs += activeMs;\n saveSession(session);\n });\n}\n\nexport async function incrementUserBlockedMs(\n cwd: string,\n sessionId: string,\n deltaMs: number,\n askedAt?: string,\n askedBy?: string,\n): Promise<void> {\n if (deltaMs <= 0) return;\n return withSessionLock(sessionId, () => {\n const session = getSession(cwd, sessionId);\n session.userBlockedMs = (session.userBlockedMs ?? 0) + deltaMs;\n if (askedAt) {\n const askedAtMs = new Date(askedAt).getTime();\n const cycle = session.orchestratorCycles.find(c => {\n const startMs = new Date(c.timestamp).getTime();\n const endMs = c.completedAt ? new Date(c.completedAt).getTime() : Infinity;\n return startMs <= askedAtMs && askedAtMs < endMs;\n });\n if (cycle) cycle.userBlockedMs = (cycle.userBlockedMs ?? 0) + deltaMs;\n }\n if (askedBy && askedBy !== ORCHESTRATOR_ASKED_BY) {\n const agent = session.agents.slice().reverse().find(a => a.id === askedBy);\n if (agent) agent.userBlockedMs = (agent.userBlockedMs ?? 0) + deltaMs;\n }\n saveSession(session);\n });\n}\n\nexport async function incrementActiveTime(\n cwd: string,\n sessionId: string,\n sessionDelta: number,\n agentDeltas: Map<string, number>,\n cycleDeltas: Map<number, number>,\n): Promise<void> {\n return withSessionLock(sessionId, () => {\n const session = getSession(cwd, sessionId);\n session.activeMs += sessionDelta;\n for (const [agentId, delta] of agentDeltas) {\n const agent = session.agents.slice().reverse().find(a => a.id === agentId);\n if (agent) agent.activeMs += delta;\n }\n for (const [cycleNum, delta] of cycleDeltas) {\n const cycle = session.orchestratorCycles.find(c => c.cycle === cycleNum);\n if (cycle) cycle.activeMs += delta;\n }\n saveSession(session);\n });\n}\n\nexport function createSnapshot(cwd: string, sessionId: string, cycleNumber: number): void {\n const dir = snapshotDir(cwd, sessionId, cycleNumber);\n mkdirSync(dir, { recursive: true });\n\n copyFileSync(statePath(cwd, sessionId), join(dir, 'state.json'));\n\n const roadmap = roadmapPath(cwd, sessionId);\n if (existsSync(roadmap)) copyFileSync(roadmap, join(dir, 'roadmap.md'));\n\n const strategy = strategyPath(cwd, sessionId);\n if (existsSync(strategy)) copyFileSync(strategy, join(dir, 'strategy.md'));\n\n const ld = logsDir(cwd, sessionId);\n if (existsSync(ld)) cpSync(ld, join(dir, 'logs'), { recursive: true });\n const legacyLogs = legacyLogsPath(cwd, sessionId);\n if (existsSync(legacyLogs)) copyFileSync(legacyLogs, join(dir, 'logs.md'));\n}\n\nexport async function restoreSnapshot(cwd: string, sessionId: string, toCycle: number): Promise<void> {\n return withSessionLock(sessionId, () => {\n const dir = snapshotDir(cwd, sessionId, toCycle);\n if (!existsSync(dir)) throw new Error(`No snapshot found for cycle ${toCycle}`);\n\n // Restore state.json atomically\n const snapshotState = readFileSync(join(dir, 'state.json'), 'utf-8');\n const session = JSON.parse(snapshotState) as Session;\n session.status = 'paused';\n session.completedAt = undefined;\n session.completionReport = undefined;\n session.tmuxSessionName = undefined;\n session.tmuxSessionId = undefined;\n session.tmuxWindowId = undefined;\n atomicWrite(statePath(cwd, sessionId), JSON.stringify(session, null, 2));\n\n // Restore roadmap.md, strategy.md, and logs\n const snapshotRoadmap = join(dir, 'roadmap.md');\n if (existsSync(snapshotRoadmap)) copyFileSync(snapshotRoadmap, roadmapPath(cwd, sessionId));\n\n const snapshotStrategy = join(dir, 'strategy.md');\n if (existsSync(snapshotStrategy)) copyFileSync(snapshotStrategy, strategyPath(cwd, sessionId));\n\n const snapshotLogsDir = join(dir, 'logs');\n if (existsSync(snapshotLogsDir)) {\n const currentLogsDir = logsDir(cwd, sessionId);\n if (existsSync(currentLogsDir)) rmSync(currentLogsDir, { recursive: true, force: true });\n cpSync(snapshotLogsDir, currentLogsDir, { recursive: true });\n } else {\n // Legacy fallback: snapshot has logs.md instead of logs/\n const snapshotLogs = join(dir, 'logs.md');\n if (existsSync(snapshotLogs)) copyFileSync(snapshotLogs, legacyLogsPath(cwd, sessionId));\n }\n });\n}\n\nexport function listSnapshots(cwd: string, sessionId: string): number[] {\n const dir = snapshotsDir(cwd, sessionId);\n if (!existsSync(dir)) return [];\n\n return readdirSync(dir, { withFileTypes: true })\n .filter(e => e.isDirectory() && e.name.startsWith('cycle-'))\n .map(e => parseInt(e.name.replace('cycle-', ''), 10))\n .filter(n => !isNaN(n))\n .sort((a, b) => a - b);\n}\n\nexport function deleteSnapshotsAfter(cwd: string, sessionId: string, afterCycle: number): void {\n const dir = snapshotsDir(cwd, sessionId);\n if (!existsSync(dir)) return;\n\n for (const entry of readdirSync(dir, { withFileTypes: true })) {\n if (!entry.isDirectory() || !entry.name.startsWith('cycle-')) continue;\n const num = parseInt(entry.name.replace('cycle-', ''), 10);\n if (!isNaN(num) && num > afterCycle) {\n rmSync(join(dir, entry.name), { recursive: true, force: true });\n }\n }\n}\n\n// --- Session cloning ---\n\nfunction replaceIdInDir(dir: string, sourceId: string, cloneId: string): void {\n if (!existsSync(dir)) return;\n const entries = readdirSync(dir, { recursive: true }) as string[];\n for (const rel of entries) {\n const fullPath = join(dir, rel);\n if (!statSync(fullPath).isFile()) continue;\n const buf = readFileSync(fullPath);\n // Skip binary files (null byte in first 8KB)\n const sample = buf.subarray(0, 8192);\n if (sample.includes(0)) continue;\n const text = buf.toString('utf-8');\n if (text.includes(sourceId)) {\n writeFileSync(fullPath, text.replaceAll(sourceId, cloneId), 'utf-8');\n }\n }\n}\n\nexport function cloneSessionDir(\n sourceCwd: string,\n sourceId: string,\n cloneId: string,\n goal: string,\n context?: string,\n strategy?: boolean,\n): void {\n const srcDir = sessionDir(sourceCwd, sourceId);\n const dstDir = sessionDir(sourceCwd, cloneId);\n mkdirSync(dstDir, { recursive: true });\n\n // Deep-copy directories\n const dirsToCopy = ['context', 'prompts', 'reports', 'snapshots'] as const;\n for (const sub of dirsToCopy) {\n const src = join(srcDir, sub);\n const dst = join(dstDir, sub);\n if (existsSync(src)) {\n cpSync(src, dst, { recursive: true });\n } else {\n mkdirSync(dst, { recursive: true });\n }\n }\n\n // Conditionally copy strategy.md\n if (strategy) {\n const srcStrategy = strategyPath(sourceCwd, sourceId);\n if (existsSync(srcStrategy)) {\n const text = readFileSync(srcStrategy, 'utf-8');\n writeFileSync(strategyPath(sourceCwd, cloneId), text.replaceAll(sourceId, cloneId), 'utf-8');\n }\n }\n\n // Replace source ID with clone ID in copied directories\n for (const sub of dirsToCopy) {\n replaceIdInDir(join(dstDir, sub), sourceId, cloneId);\n }\n\n // Write fresh files\n writeFileSync(goalPath(sourceCwd, cloneId), goal, 'utf-8');\n writeFileSync(initialPromptPath(sourceCwd, cloneId), goal, 'utf-8');\n writeFileSync(roadmapPath(sourceCwd, cloneId), ROADMAP_SEED, 'utf-8');\n mkdirSync(logsDir(sourceCwd, cloneId), { recursive: true });\n\n // Write context/CLAUDE.md\n writeFileSync(join(contextDir(sourceCwd, cloneId), 'CLAUDE.md'), CONTEXT_CLAUDE_MD, 'utf-8');\n\n // Write initial-context.md if context provided\n if (context) {\n writeFileSync(join(contextDir(sourceCwd, cloneId), 'initial-context.md'), context, 'utf-8');\n }\n}\n\nexport async function createCloneState(\n sourceCwd: string,\n sourceId: string,\n cloneId: string,\n goal: string,\n context?: string,\n configModel?: string,\n configOrchestratorPrompt?: string,\n): Promise<Session> {\n return withSessionLock(cloneId, () => {\n const source = getSession(sourceCwd, sourceId);\n\n const createdAt = new Date().toISOString();\n const created = new Date(createdAt);\n\n // Deep-copy preserved fields\n const agents = structuredClone(source.agents);\n const orchestratorCycles = structuredClone(source.orchestratorCycles);\n const messages = structuredClone(source.messages);\n\n // Normalize running agents to killed\n const now = new Date().toISOString();\n for (const agent of agents) {\n if (agent.status === 'running') {\n agent.status = 'killed';\n agent.completedAt = now;\n agent.killedReason = 'inherited from source session';\n }\n }\n\n // Resolve model and launchConfig with fallback to config\n const model = source.model ?? configModel;\n const launchConfig = source.launchConfig\n ? structuredClone(source.launchConfig)\n : {\n model,\n context,\n orchestratorPrompt: configOrchestratorPrompt,\n };\n\n const clone: Session = {\n id: cloneId,\n task: goal,\n ...(context ? { context } : {}),\n cwd: sourceCwd,\n status: 'active',\n createdAt,\n activeMs: 0,\n agents,\n orchestratorCycles,\n messages,\n startHour: created.getHours(),\n startDayOfWeek: created.getDay(),\n parentSessionId: sourceId,\n ...(model ? { model } : {}),\n launchConfig,\n ...(source.effort != null ? { effort: source.effort } : {}),\n };\n\n atomicWrite(statePath(sourceCwd, cloneId), JSON.stringify(clone, null, 2));\n return clone;\n });\n}\n","export function shellQuote(s: string): string {\n return `'${s.replace(/'/g, \"'\\\\''\")}'`;\n}\n\n/**\n * Quote a path for a remote shell while preserving a leading `~` / `~/` so the\n * remote shell still expands it. Plain `shellQuote('~/foo')` produces\n * `'~/foo'`, and `~` does not expand inside single quotes — the remote `cd`\n * then looks for a literal `~` directory and fails.\n */\nexport function shellQuoteHomePath(path: string): string {\n if (path === '~') return '~';\n if (path.startsWith('~/')) return `~/${shellQuote(path.slice(2))}`;\n return shellQuote(path);\n}\n\n/** Validate that a session ID is a safe UUID-like string (no path traversal). */\nconst SESSION_ID_PATTERN = /^[a-zA-Z0-9_-]+$/;\nexport function validateSessionId(id: string): boolean {\n return SESSION_ID_PATTERN.test(id) && !id.includes('..');\n}\n\n/** Validate that a repo name is a simple directory name (no path components). */\nexport function validateRepoName(repo: string): boolean {\n return !repo.includes('/') && !repo.includes('\\\\') && !repo.includes('..');\n}\n\n/** Escape a string for safe interpolation inside AppleScript double quotes. */\nexport function escapeAppleScript(s: string): string {\n return s.replace(/\\\\/g, '\\\\\\\\').replace(/\"/g, '\\\\\"');\n}\n","import { spawn, execFile, type ChildProcess } from 'node:child_process';\nimport { writeFileSync, mkdirSync, existsSync } from 'node:fs';\nimport { join } from 'node:path';\nimport { homedir } from 'node:os';\nimport { escapeAppleScript } from '../shared/shell.js';\nimport { detectPlatform, hasCommand } from '../shared/platform.js';\n\n/**\n * Notification urgency.\n * - `urgent` (default): plays sound, banner; for crashes, asks, things needing real attention\n * - `info`: silent passive banner; for status updates the user only needs to acknowledge\n */\nexport type NotificationLevel = 'info' | 'urgent';\n\nexport interface NotificationOptions {\n title: string;\n message: string;\n /** tmux session name to switch to on click */\n tmuxSession?: string;\n level?: NotificationLevel;\n}\n\nconst TMUX_SOCKET = `/tmp/tmux-${process.getuid?.() ?? 0}/default`;\n\n/**\n * Click-to-switch helper. Used by macOS notifications today; the script is\n * portable so the same one works on Linux if a notification handler ever\n * invokes it. iTerm activation is gated by uname so it no-ops elsewhere.\n */\nconst SWITCH_SCRIPT = [\n '#!/bin/bash',\n 'SESSION=\"$1\"',\n `TMUX_SOCKET=\"${TMUX_SOCKET}\"`,\n '',\n '# Find any attached client (user is likely on a different session)',\n 'CLIENT_TTY=$(tmux -S \"$TMUX_SOCKET\" list-clients -F \\'#{client_tty}\\' 2>/dev/null | head -1)',\n '[ -z \"$CLIENT_TTY\" ] && exit 0',\n '',\n '# Switch that client to the target session',\n 'tmux -S \"$TMUX_SOCKET\" switch-client -c \"$CLIENT_TTY\" -t \"$SESSION\" 2>/dev/null',\n 'tmux -S \"$TMUX_SOCKET\" select-window -t \"$SESSION\" 2>/dev/null',\n '',\n '# macOS-only: bring iTerm2 to front and select the tab with this client',\n 'if [ \"$(uname -s)\" = \"Darwin\" ] && command -v osascript >/dev/null 2>&1; then',\n ' TTY_SHORT=$(echo \"$CLIENT_TTY\" | sed \\'s|/dev/||\\')',\n ' osascript -e \"',\n ' tell application \\\\\"iTerm2\\\\\"',\n ' activate',\n ' repeat with w in windows',\n ' tell w',\n ' repeat with t in tabs',\n ' tell t',\n ' repeat with s in sessions',\n ' tell s',\n ' if tty contains \\\\\"$TTY_SHORT\\\\\" then',\n ' select t',\n ' return',\n ' end if',\n ' end tell',\n ' end repeat',\n ' end tell',\n ' end repeat',\n ' end tell',\n ' end repeat',\n ' end tell',\n ' \" 2>/dev/null || osascript -e \\'tell application \"iTerm2\" to activate\\' 2>/dev/null',\n 'fi',\n '',\n].join('\\n');\n\nfunction ensureSwitchScript(): void {\n const dir = join(homedir(), '.sisyphus');\n const scriptPath = join(dir, 'notify-switch.sh');\n try {\n mkdirSync(dir, { recursive: true });\n writeFileSync(scriptPath, SWITCH_SCRIPT, { mode: 0o755 });\n } catch {\n // Best effort\n }\n}\n\n// Long-lived SisyphusNotify.app process — accepts JSON lines on stdin\nlet notifyProcess: ChildProcess | null = null;\n\nfunction getNotifyBinary(): string {\n return join(homedir(), '.sisyphus', 'SisyphusNotify.app', 'Contents', 'MacOS', 'sisyphus-notify');\n}\n\nfunction ensureNotifyProcess(): ChildProcess | null {\n if (notifyProcess && !notifyProcess.killed && notifyProcess.stdin?.writable) {\n return notifyProcess;\n }\n\n const binary = getNotifyBinary();\n if (!existsSync(binary)) {\n return null;\n }\n\n notifyProcess = spawn(binary, [], {\n stdio: ['pipe', 'ignore', 'pipe'],\n });\n\n notifyProcess.stderr?.on('data', (data: Buffer) => {\n const msg = data.toString().trim();\n if (msg) console.error(`[sisyphus-notify] ${msg}`);\n });\n\n notifyProcess.on('close', () => {\n notifyProcess = null;\n });\n\n // Don't keep short-lived parents alive (CLI, tests). The daemon stays up\n // for other reasons; when it exits, the notify subprocess sees stdin EOF.\n notifyProcess.unref();\n notifyProcess.stdin?.unref();\n notifyProcess.stderr?.unref();\n\n return notifyProcess;\n}\n\nfunction sendLinuxNotification(title: string, msg: string, level: NotificationLevel): boolean {\n if (!hasCommand('notify-send')) return false;\n const urgency = level === 'urgent' ? 'critical' : 'normal';\n // --app-name keeps the notification grouped under \"Sisyphus\" in the OS UI.\n execFile('notify-send', ['--app-name=Sisyphus', `--urgency=${urgency}`, title, msg], () => {});\n return true;\n}\n\nexport function sendTerminalNotification(opts: NotificationOptions): void;\nexport function sendTerminalNotification(title: string, message: string, tmuxSession?: string, level?: NotificationLevel): void;\nexport function sendTerminalNotification(titleOrOpts: string | NotificationOptions, message?: string, tmuxSession?: string, level?: NotificationLevel): void {\n let title: string;\n let msg: string;\n let tmuxSess: string | undefined;\n let lvl: NotificationLevel;\n\n if (typeof titleOrOpts === 'object') {\n title = titleOrOpts.title;\n msg = titleOrOpts.message;\n tmuxSess = titleOrOpts.tmuxSession;\n lvl = titleOrOpts.level === undefined ? 'urgent' : titleOrOpts.level;\n } else {\n title = titleOrOpts;\n msg = message!;\n tmuxSess = tmuxSession;\n lvl = level === undefined ? 'urgent' : level;\n }\n\n // Ensure the switch script is in place\n if (tmuxSess) ensureSwitchScript();\n\n const platform = detectPlatform();\n\n if (platform === 'darwin') {\n // Try native SisyphusNotify.app (supports click-to-switch + level styling)\n const proc = ensureNotifyProcess();\n if (proc?.stdin?.writable) {\n const payload: Record<string, string> = { title, message: msg, level: lvl };\n if (tmuxSess) payload.tmuxSession = tmuxSess;\n proc.stdin.write(JSON.stringify(payload) + '\\n');\n return;\n }\n\n // Fallback: terminal-notifier — sound only on urgent\n const tnArgs = ['-title', title, '-message', msg];\n if (lvl === 'urgent') tnArgs.push('-sound', 'default');\n execFile('terminal-notifier', tnArgs, (err) => {\n if (err) {\n // Last resort on macOS: osascript\n const soundClause = lvl === 'urgent' ? ' sound name \"default\"' : '';\n execFile('osascript', [\n '-e',\n `display notification \"${escapeAppleScript(msg)}\" with title \"${escapeAppleScript(title)}\"${soundClause}`,\n ], () => {});\n }\n });\n return;\n }\n\n // Linux + WSL: libnotify via notify-send. On WSL this surfaces through WSLg\n // (Windows 11+) or the user's X server. If unavailable we silently drop —\n // the daemon log still records the underlying event.\n if (platform === 'linux' || platform === 'wsl') {\n sendLinuxNotification(title, msg, lvl);\n return;\n }\n\n // Other platforms (win32, unknown): no-op.\n}\n","import { existsSync, mkdirSync, readFileSync, readdirSync } from 'node:fs';\nimport {\n askDecisionsPath, askDir, askMetaPath, askOutputPath, askProgressPath, askVisualsDir,\n} from '../shared/paths.js';\nimport type { AskMeta, AskStatus, Deck, InteractionKind, InteractionResponse } from '../shared/types.js';\nimport { loadConfig } from '../shared/config.js';\nimport { emitHistoryEvent } from './history.js';\nimport { isSessionDangerous } from './state.js';\nimport { atomicWrite, withLock } from './lib/atomic.js';\nimport { sendTerminalNotification } from './notify.js';\nimport * as state from './state.js';\n\nconst ACTIONABLE_KINDS: ReadonlySet<InteractionKind> = new Set([\n 'validation', 'decision', 'context', 'error',\n]);\n\nconst HEARTBEAT_ASKED_BY = 'system:heartbeat';\nconst ORPHAN_ASKED_BY = 'system:orphan-handler';\n\nfunction maybeNotifyOnAskCreated(cwd: string, sessionId: string, meta: AskMeta): void {\n if (process.env.NODE_ENV === 'test' || process.env.SISYPHUS_DISABLE_NOTIFY === '1') return;\n const isActionable = meta.kind !== undefined && ACTIONABLE_KINDS.has(meta.kind);\n const isHeartbeat = meta.askedBy === HEARTBEAT_ASKED_BY;\n if (!isActionable && !isHeartbeat) return;\n\n try {\n const config = loadConfig(cwd);\n if (config.notifications?.enabled === false) return;\n const session = state.getSession(cwd, sessionId);\n const label = session.name ?? sessionId.slice(0, 8);\n const body = meta.title ?? 'Question pending';\n sendTerminalNotification(label, body, session.tmuxSessionName, 'urgent');\n } catch {\n // notify failures must never roll back the ask write\n }\n}\n\nexport interface CreateAskParams {\n askId: string;\n askedBy: string;\n blocking: boolean;\n pid?: number;\n claudeSessionId?: string;\n cwd: string;\n title?: string;\n subtitle?: string;\n kind?: InteractionKind;\n orphanTarget?: AskMeta['orphanTarget'];\n modeTransition?: true;\n}\n\nexport function createAsk(cwd: string, sessionId: string, params: CreateAskParams): AskMeta {\n // askVisualsDir is a subdir of askEntryDir — one recursive mkdir creates both.\n mkdirSync(askVisualsDir(cwd, sessionId, params.askId), { recursive: true });\n\n const askedAt = new Date().toISOString();\n const meta: AskMeta = {\n askId: params.askId,\n askedBy: params.askedBy,\n askedAt,\n status: 'pending' as AskStatus,\n blocking: params.blocking,\n cwd: params.cwd,\n ...(params.pid !== undefined ? { pid: params.pid, startedAt: askedAt } : {}),\n ...(params.claudeSessionId !== undefined ? { claudeSessionId: params.claudeSessionId } : {}),\n ...(params.title !== undefined ? { title: params.title } : {}),\n ...(params.subtitle !== undefined ? { subtitle: params.subtitle } : {}),\n ...(params.kind !== undefined ? { kind: params.kind } : {}),\n ...(params.orphanTarget !== undefined ? { orphanTarget: params.orphanTarget } : {}),\n ...(params.modeTransition !== undefined ? { modeTransition: params.modeTransition } : {}),\n };\n\n atomicWrite(askMetaPath(cwd, sessionId, params.askId), JSON.stringify(meta, null, 2));\n emitHistoryEvent(sessionId, 'ask-issued', {\n askId: params.askId,\n askedBy: params.askedBy,\n blocking: params.blocking,\n askedAt,\n });\n maybeNotifyOnAskCreated(cwd, sessionId, meta);\n return meta;\n}\n\nexport function writeDecisions(cwd: string, sessionId: string, askId: string, deck: Deck): void {\n atomicWrite(askDecisionsPath(cwd, sessionId, askId), JSON.stringify(deck, null, 2));\n void maybeAutoResolveAsk(cwd, sessionId, askId, deck);\n}\n\nexport function readDecisions(cwd: string, sessionId: string, askId: string): Deck | null {\n const p = askDecisionsPath(cwd, sessionId, askId);\n try {\n // { encoding } in try body intentional — keeps try content free of bare } for linter clarity\n return JSON.parse(readFileSync(p, { encoding: 'utf-8' })) as Deck;\n } catch (_e) {\n return null;\n }\n}\n\nexport async function writeProgress(\n cwd: string, sessionId: string, askId: string, responses: InteractionResponse[],\n): Promise<void> {\n atomicWrite(askProgressPath(cwd, sessionId, askId), JSON.stringify({\n partial: true,\n responses,\n savedAt: new Date().toISOString(),\n }, null, 2));\n const cur = readMeta(cwd, sessionId, askId);\n if (cur?.status === 'pending') {\n await updateMeta(cwd, sessionId, askId, { status: 'in-progress', startedAt: new Date().toISOString() });\n }\n}\n\nexport function readProgress(\n cwd: string, sessionId: string, askId: string,\n): { responses: InteractionResponse[]; savedAt: string } | null {\n const p = askProgressPath(cwd, sessionId, askId);\n try {\n const data = JSON.parse(readFileSync(p, { encoding: 'utf-8' })) as Record<string, unknown>;\n if (!Array.isArray(data['responses'])) return null;\n return { responses: data['responses'] as InteractionResponse[], savedAt: data['savedAt'] as string };\n } catch (_e) {\n return null;\n }\n}\n\nexport function writeOutput(\n cwd: string, sessionId: string, askId: string,\n responses: InteractionResponse[], completedAt?: string,\n): void {\n atomicWrite(askOutputPath(cwd, sessionId, askId), JSON.stringify({\n responses,\n completedAt: completedAt ?? new Date().toISOString(),\n }, null, 2));\n}\n\nexport function readMeta(cwd: string, sessionId: string, askId: string): AskMeta | null {\n const p = askMetaPath(cwd, sessionId, askId);\n if (!existsSync(p)) {\n return null;\n }\n return JSON.parse(readFileSync(p, 'utf-8')) as AskMeta;\n}\n\nexport async function updateMeta(\n cwd: string, sessionId: string, askId: string, patch: Partial<AskMeta>,\n): Promise<AskMeta> {\n return withLock(askId, () => {\n const cur = readMeta(cwd, sessionId, askId);\n if (!cur) {\n throw new Error(`updateMeta: askId ${askId} not found`);\n }\n const next: AskMeta = { ...cur, ...patch };\n atomicWrite(askMetaPath(cwd, sessionId, askId), JSON.stringify(next, null, 2));\n return next;\n });\n}\n\nexport function listAsks(cwd: string, sessionId: string): string[] {\n const dir = askDir(cwd, sessionId);\n if (!existsSync(dir)) {\n return [];\n }\n return readdirSync(dir, { withFileTypes: true })\n .filter(e => e.isDirectory())\n .map(e => e.name);\n}\n\nexport interface PendingAskRef {\n askId: string;\n status: AskStatus;\n title?: string;\n}\n\n/**\n * Open asks (pending or in-progress) attributed to a specific caller. Used to gate\n * yield/submit so a deck can't be abandoned mid-flight — terminating the caller's\n * pane orphans any answer the user produces afterward.\n *\n * Skips: meta.orphaned, status === 'answered', decks where output.json already\n * exists (the user resolved the deck but markAnswered hasn't run yet, e.g. because\n * the original waiter died before observing the output), and non-blocking decks\n * (mode-transition notifications, heartbeat asks, orphan-recovery surfaces — these\n * have no CLI waiter, so terminating the caller doesn't orphan anything).\n */\n/**\n * Build auto-responses for a deck by selecting the first option of every\n * interaction. Skips interactions with no options. Used by dangerous mode.\n */\nfunction buildAutoResponses(deck: Deck): InteractionResponse[] {\n const out: InteractionResponse[] = [];\n for (const interaction of deck.interactions) {\n const first = interaction.options[0];\n if (!first) continue;\n out.push({ id: interaction.id, selectedOptionId: first.id });\n }\n return out;\n}\n\n/**\n * Unconditionally auto-resolve the given ask using the supplied (or just-read)\n * deck. Skips when output.json already exists or no responses can be built.\n * The flush path passes the deck directly; the writeDecisions hook also passes\n * the deck so we never re-read it.\n */\nexport async function autoResolveAsk(\n cwd: string, sessionId: string, askId: string, deck?: Deck,\n): Promise<boolean> {\n try {\n if (existsSync(askOutputPath(cwd, sessionId, askId))) return false;\n const d = deck ?? readDecisions(cwd, sessionId, askId);\n if (!d) return false;\n const responses = buildAutoResponses(d);\n if (responses.length === 0) return false;\n writeOutput(cwd, sessionId, askId, responses);\n await updateMeta(cwd, sessionId, askId, {\n status: 'answered',\n completedAt: new Date().toISOString(),\n });\n return true;\n } catch (err) {\n console.warn(`[sisyphus] dangerous-mode auto-resolve failed for ask ${askId}:`, err instanceof Error ? err.message : err);\n return false;\n }\n}\n\n/**\n * Auto-resolve hook called from writeDecisions. If dangerous mode is on for\n * this session, auto-resolves the just-written deck. Failure is logged, never\n * thrown — must not roll back the deck write.\n */\nasync function maybeAutoResolveAsk(\n cwd: string, sessionId: string, askId: string, deck: Deck,\n): Promise<void> {\n try {\n if (!isSessionDangerous(cwd, sessionId)) return;\n // Orphan-handler asks require human action — auto-selecting \"resume\" doesn't\n // trigger an actual resume, but it does mark the ask answered, which defeats\n // emitOrphanAsk's dedup and causes a notification flood every monitor tick\n // while the orchestrator stays gone.\n if (deck.source?.askedBy === ORPHAN_ASKED_BY) return;\n await autoResolveAsk(cwd, sessionId, askId, deck);\n } catch {\n // never roll back the deck write\n }\n}\n\nexport function listOpenAsksFor(cwd: string, sessionId: string, askedBy: string): PendingAskRef[] {\n const out: PendingAskRef[] = [];\n for (const askId of listAsks(cwd, sessionId)) {\n const meta = readMeta(cwd, sessionId, askId);\n if (!meta) continue;\n if (meta.askedBy !== askedBy) continue;\n if (meta.orphaned) continue;\n if (!meta.blocking) continue;\n if (meta.status !== 'pending' && meta.status !== 'in-progress') continue;\n if (existsSync(askOutputPath(cwd, sessionId, askId))) continue;\n out.push({ askId, status: meta.status, ...(meta.title !== undefined ? { title: meta.title } : {}) });\n }\n return out;\n}\n","import { existsSync, watchFile, unwatchFile } from 'node:fs';\nimport { mountPanel, type Deck, type InteractionResponse, type MountedPanel } from '@crouton-kit/humanloop';\nimport { readDecisions, readMeta, updateMeta, writeOutput } from '../daemon/ask-store.js';\nimport { askOutputPath, askProgressPath } from '../shared/paths.js';\nimport { setupTerminal, startKeypressListener, onResize, writeToStdout, type Key } from './terminal.js';\nimport { flushFrame } from './render.js';\n\ninterface RunSingleAskOpts {\n cwd: string;\n sessionId: string;\n askId: string;\n}\n\n/**\n * Standalone single-ask runner — opens a humanloop deck for one ask in the\n * current pane and exits when answered (locally or by the dashboard).\n *\n * Designed for the parallel ask-pane spawned by `sis ask`: the pane has\n * no inbox, no tree, just the deck. Both this pane and the dashboard write\n * through the same on-disk ask-store paths, so whichever surface answers\n * first wins; the loser detects the resolution via output.json and exits.\n */\nexport async function runSingleAsk(opts: RunSingleAskOpts): Promise<void> {\n const { cwd, sessionId, askId } = opts;\n\n const meta = readMeta(cwd, sessionId, askId);\n if (!meta || meta.status === 'answered') {\n return;\n }\n\n const deck = readDecisions(cwd, sessionId, askId);\n if (!deck) return;\n\n const cleanupTerminal = setupTerminal();\n\n let exiting = false;\n let panel: MountedPanel | null = null;\n let prevFrame: string[] = [];\n let stopKeypress: (() => void) | null = null;\n let stopResize: (() => void) | null = null;\n const outputPath = askOutputPath(cwd, sessionId, askId);\n\n const exit = (code: number): void => {\n if (exiting) return;\n exiting = true;\n try { stopKeypress?.(); } catch { /* best-effort */ }\n try { stopResize?.(); } catch { /* best-effort */ }\n try { panel?.unmount(); } catch { /* best-effort */ }\n try { unwatchFile(outputPath, onExternalChange); } catch { /* best-effort */ }\n cleanupTerminal();\n process.exit(code);\n };\n\n const flushHost = (lines: string[]): void => {\n const out = flushFrame(lines, prevFrame, '\\x1b[?25l');\n writeToStdout(out);\n prevFrame = lines;\n };\n\n const onExternalChange = (): void => {\n if (exiting) return;\n if (!existsSync(outputPath)) return;\n exit(0);\n };\n\n let lastResponses: InteractionResponse[] = [];\n\n const submit = (responses: InteractionResponse[]): void => {\n if (exiting) return;\n void (async () => {\n const completedAt = new Date().toISOString();\n writeOutput(cwd, sessionId, askId, responses, completedAt);\n try {\n await updateMeta(cwd, sessionId, askId, { status: 'answered', completedAt });\n } catch {\n // Race: dashboard updated meta concurrently. output.json is written; the\n // blocked `sis ask` will still pick up the result.\n }\n exit(0);\n })();\n };\n\n const cols = process.stdout.columns ?? 80;\n const rows = process.stdout.rows ?? 24;\n\n panel = mountPanel({\n deck: deck as Deck,\n cols,\n rows,\n progressPath: askProgressPath(cwd, sessionId, askId),\n onProgress: (responses: InteractionResponse[]) => {\n lastResponses = responses;\n const cur = readMeta(cwd, sessionId, askId);\n if (cur?.status === 'pending') {\n void updateMeta(cwd, sessionId, askId, { status: 'in-progress', startedAt: new Date().toISOString() }).catch(() => { /* best-effort */ });\n }\n if (panel) flushHost(panel.render());\n },\n onComplete: (responses: InteractionResponse[]) => {\n submit(responses);\n },\n // Final-phase Enter on an incomplete deck — submit what we have.\n onExit: () => {\n submit(lastResponses);\n },\n });\n\n stopKeypress = startKeypressListener((input: string, key: Key) => {\n if (exiting || !panel) return;\n panel.handleKey(input, key);\n flushHost(panel.render());\n });\n\n stopResize = onResize(() => {\n if (exiting || !panel) return;\n const newCols = process.stdout.columns ?? 80;\n const newRows = process.stdout.rows ?? 24;\n panel.handleResize(newCols, newRows);\n prevFrame = [];\n flushHost(panel.render());\n });\n\n watchFile(outputPath, { interval: 250 }, onExternalChange);\n\n // Race guard: dashboard may have answered between our initial readMeta and\n // mount completion. If output.json is already on disk, exit immediately.\n if (existsSync(outputPath)) {\n exit(0);\n return;\n }\n\n flushHost(panel.render());\n\n // Keep the process alive — the panel + listeners hold the event loop open\n // via stdin (raw mode) and the watchFile poller. Returning from this async\n // function would let `await runSingleAsk(...)` resolve in index.ts but the\n // listeners keep node running until exit() fires.\n await new Promise<void>(() => { /* never resolves; exit() handles teardown */ });\n}\n","import { setupTerminal } from './terminal.js';\nimport { createAppState } from './state.js';\nimport { startApp } from './app.js';\nimport { registerDashboardWindow } from './lib/tmux.js';\n\nconst args = process.argv.slice(2);\n\nfunction getArg(name: string): string | undefined {\n const idx = args.indexOf(`--${name}`);\n if (idx !== -1 && idx + 1 < args.length) {\n return args[idx + 1];\n }\n return undefined;\n}\n\nconst cwd = getArg('cwd') ?? process.cwd();\n\nconst askId = getArg('ask');\nconst sessionId = getArg('session-id');\nif (askId && sessionId) {\n // Single-ask mode — used by the parallel ask-pane spawned from `sis ask`.\n // Skips the dashboard inbox and renders only the deck for this one ask.\n // Must NOT call registerDashboardWindow() — would clobber the real dashboard.\n const { runSingleAsk } = await import('./single-ask.js');\n await runSingleAsk({ cwd, sessionId, askId });\n process.exit(0);\n}\n\nregisterDashboardWindow(cwd);\nconst cleanup = setupTerminal();\nconst state = createAppState(cwd);\nstartApp(state, cleanup);\n","import type { Session } from '../shared/types.js';\nimport type { AggregateInboxItem } from '../shared/inbox-types.js';\nimport type { TreeNode } from './types/tree.js';\nimport type { ReportBlock } from './lib/reports.js';\n\n// ---------------------------------------------------------------------------\n// Polling data interfaces (moved from usePolling.ts)\n// ---------------------------------------------------------------------------\n\nexport interface SessionSummary {\n id: string;\n name?: string;\n task: string;\n status: string;\n agentCount: number;\n runningAgentCount: number;\n createdAt: string;\n activeMs: number;\n tmuxSessionName?: string;\n tmuxSessionId?: string;\n tmuxWindowId?: string;\n /** Cached result of windowExists check — avoids synchronous subprocess in render */\n windowAlive?: boolean;\n orphaned?: boolean;\n}\n\nexport interface CycleLog {\n cycle: number;\n content: string;\n}\n\n// ---------------------------------------------------------------------------\n// InputMode (moved from InputBar.tsx)\n// ---------------------------------------------------------------------------\n\nexport type InputMode =\n | 'navigate'\n | 'report-detail'\n | 'leader'\n | 'copy-menu'\n | 'open-menu'\n | 'agent-menu'\n | 'session-menu'\n | 'go-menu'\n | 'companion-menu'\n | 'help'\n | 'companion-overlay'\n | 'companion-debug'\n | 'search';\n\n// ---------------------------------------------------------------------------\n// Compose mode types\n// ---------------------------------------------------------------------------\n\nexport type ComposeAction =\n | { kind: 'new-session' }\n | { kind: 'message-orchestrator'; sessionId: string }\n | { kind: 'resume'; sessionId: string }\n | { kind: 'continue'; sessionId: string }\n | { kind: 'spawn-agent'; sessionId: string }\n | { kind: 'message-agent'; sessionId: string; agentId: string };\n\n/** Actions where empty content is allowed (submit without typing) */\nexport const OPTIONAL_COMPOSE = new Set(['resume', 'continue']);\n\n// ---------------------------------------------------------------------------\n// Render scheduling\n// ---------------------------------------------------------------------------\n\nlet renderScheduled = false;\nlet renderFn: (() => void) | null = null;\n\nexport function setRenderFunction(fn: () => void): void {\n renderFn = fn;\n}\n\nexport function requestRender(): void {\n if (renderScheduled) return;\n renderScheduled = true;\n setImmediate(() => {\n renderScheduled = false;\n renderFn?.();\n });\n}\n\n// ---------------------------------------------------------------------------\n// ThrottledScroll\n// ---------------------------------------------------------------------------\n\nconst FRAME_MS = 16; // ~60fps\n\nexport class ThrottledScroll {\n offset: number = 0;\n private target: number = 0;\n private max: number = Infinity;\n private timer: ReturnType<typeof setTimeout> | null = null;\n private onRender: () => void;\n\n constructor(onRender: () => void, initial = 0) {\n this.onRender = onRender;\n this.offset = initial;\n this.target = initial;\n }\n\n private scheduleFlush(): void {\n if (this.timer === null) {\n this.timer = setTimeout(() => {\n this.timer = null;\n this.offset = this.target;\n this.onRender();\n }, FRAME_MS);\n }\n }\n\n private clamp(value: number): number {\n if (value < 0) return 0;\n if (value > this.max) return this.max;\n return value;\n }\n\n scrollBy(delta: number): void {\n this.target = this.clamp(this.target + delta);\n this.scheduleFlush();\n }\n\n scrollTo(value: number): void {\n this.target = this.clamp(value);\n this.scheduleFlush();\n }\n\n // Renderer pushes the current content's max scroll each frame so scrollBy\n // can't accumulate past the bottom. Without this, over-scroll inflates\n // `target` invisibly and reverse scrolls have to burn through the buffer\n // before any visual movement resumes.\n setMax(max: number): void {\n this.max = Math.max(0, max);\n if (this.target > this.max) this.target = this.max;\n if (this.offset > this.max) this.offset = this.max;\n }\n\n reset(): void {\n if (this.timer !== null) {\n clearTimeout(this.timer);\n this.timer = null;\n }\n this.target = 0;\n this.offset = 0;\n }\n\n destroy(): void {\n if (this.timer !== null) {\n clearTimeout(this.timer);\n this.timer = null;\n }\n }\n}\n\n// ---------------------------------------------------------------------------\n// AppState\n// ---------------------------------------------------------------------------\n\nexport interface AppState {\n // Terminal dimensions\n rows: number;\n cols: number;\n\n // Tree navigation\n cursorIndex: number;\n expanded: Set<string>;\n mode: InputMode;\n focusPane: 'tree' | 'detail' | 'logs';\n\n // Session\n selectedSessionId: string | null;\n searchFilter: string | null;\n searchText: string;\n targetAgentId: string | null;\n\n // UI\n notification: string | null;\n notificationTimer: ReturnType<typeof setTimeout> | null;\n\n // Scroll\n detailScroll: ThrottledScroll;\n digestScroll: ThrottledScroll;\n\n // Aggregate inbox — fetched from daemon on each poll\n aggregateInbox: AggregateInboxItem[];\n crossSessionInboxScroll: ThrottledScroll;\n cachedInboxLines: import('./lib/format.js').DetailLine[] | null;\n inboxCacheKey: string;\n inboxRenderedCache: import('./render.js').RenderedCache;\n\n // Stacked detail (3b) — cachedStackedLines + stackedCacheKey must be cleared together (cache pair invariant)\n useStackedDetail: boolean;\n detailMode: 'gsr' | 'cycle-log' | 'cross-session-inbox';\n focusedStrip: 'goal' | 'strategy' | 'roadmap';\n goalScroll: ThrottledScroll;\n strategyScroll: ThrottledScroll;\n roadmapScroll: ThrottledScroll;\n cachedStackedLines: {\n goal: import('./lib/format.js').DetailLine[];\n strategy: import('./lib/format.js').DetailLine[];\n roadmap: import('./lib/format.js').DetailLine[];\n cycleLog: import('./lib/format.js').DetailLine[];\n } | null;\n stackedCacheKey: string;\n stackedRenderedCache: import('./render.js').RenderedCache;\n\n // Polling data (from daemon)\n sessions: SessionSummary[];\n selectedSession: Session | null;\n planContent: string;\n strategyContent: string;\n goalContent: string;\n completionSummaryContent: string;\n logsContent: string;\n logsCycles: CycleLog[];\n digestData: import('../shared/types.js').StatusDigest | null;\n paneAlive: boolean;\n contextFiles: string[];\n error: string | null;\n\n // Cursor stabilization\n cursorNodeId: string | null;\n prevNodes: TreeNode[];\n prevCycleCount: number;\n\n // Render caches\n cachedReportBlocks: Map<string, ReportBlock[]>;\n cachedTreeNodes: TreeNode[] | null;\n treeCacheKey: string;\n cachedDetailLines: import('./lib/format.js').DetailLine[] | null;\n detailCacheKey: string;\n detailRenderedCache: import('./render.js').RenderedCache;\n cachedDigestLines: import('./lib/format.js').DetailLine[] | null;\n digestCacheKey: string;\n digestRenderedCache: import('./render.js').RenderedCache;\n\n // Cycle flow\n flowExpanded: boolean;\n\n // Resolution mode (3e)\n resolutionActive: boolean;\n resolutionHandle: import('./panels/mounted-humanloop.js').MountedResolutionHandle | null;\n visuals: Map<string, import('./panels/mounted-humanloop.js').VisualEntry>;\n\n // Config\n cwd: string;\n}\n\nexport function createAppState(cwd: string): AppState {\n const cols = process.stdout.columns ?? 80;\n const rows = process.stdout.rows ?? 24;\n\n const detailScroll = new ThrottledScroll(requestRender);\n const digestScroll = new ThrottledScroll(requestRender);\n const crossSessionInboxScroll = new ThrottledScroll(requestRender);\n const goalScroll = new ThrottledScroll(requestRender);\n const strategyScroll = new ThrottledScroll(requestRender);\n const roadmapScroll = new ThrottledScroll(requestRender);\n\n // Seed default-expanded sections (done stays collapsed)\n const expanded = new Set<string>();\n expanded.add('section:needs-you');\n expanded.add('section:running');\n\n return {\n rows,\n cols,\n cursorIndex: 0,\n expanded,\n mode: 'navigate',\n focusPane: 'tree',\n selectedSessionId: null,\n searchFilter: null,\n searchText: '',\n targetAgentId: null,\n notification: null,\n notificationTimer: null,\n detailScroll,\n digestScroll,\n aggregateInbox: [],\n crossSessionInboxScroll,\n cachedInboxLines: null,\n inboxCacheKey: '',\n inboxRenderedCache: { lines: [], ansi: [] },\n useStackedDetail: process.env.SISYPHUS_USE_STACKED_DETAIL !== '0',\n detailMode: 'gsr',\n focusedStrip: 'roadmap',\n goalScroll,\n strategyScroll,\n roadmapScroll,\n cachedStackedLines: null,\n stackedCacheKey: '',\n stackedRenderedCache: { lines: [], ansi: [] },\n sessions: [],\n selectedSession: null,\n planContent: '',\n strategyContent: '',\n goalContent: '',\n completionSummaryContent: '',\n logsContent: '',\n logsCycles: [],\n digestData: null,\n paneAlive: true,\n contextFiles: [],\n error: null,\n cursorNodeId: null,\n prevNodes: [],\n prevCycleCount: 0,\n cachedReportBlocks: new Map(),\n cachedTreeNodes: null,\n treeCacheKey: '',\n cachedDetailLines: null,\n detailCacheKey: '',\n detailRenderedCache: { lines: [], ansi: [] },\n cachedDigestLines: null,\n digestCacheKey: '',\n digestRenderedCache: { lines: [], ansi: [] },\n flowExpanded: false,\n resolutionActive: false,\n resolutionHandle: null,\n visuals: new Map(),\n cwd,\n };\n}\n\n// ---------------------------------------------------------------------------\n// Notification helper\n// ---------------------------------------------------------------------------\n\nexport function notify(state: AppState, msg: string): void {\n state.notification = msg;\n if (state.notificationTimer !== null) {\n clearTimeout(state.notificationTimer);\n }\n state.notificationTimer = setTimeout(() => {\n state.notification = null;\n state.notificationTimer = null;\n requestRender();\n }, 30_000);\n}\n\n// ---------------------------------------------------------------------------\n// Cursor stabilization\n// ---------------------------------------------------------------------------\n\nexport function stabilizeCursor(state: AppState, nodes: TreeNode[]): void {\n if (nodes.length === 0) {\n state.cursorIndex = 0;\n return;\n }\n\n const targetId = state.cursorNodeId;\n if (targetId === null) {\n state.cursorNodeId = nodes[0]?.id ?? null;\n return;\n }\n\n // If current index already points to the right node, no adjustment needed\n if (nodes[state.cursorIndex]?.id === targetId) return;\n\n // Find the tracked node in the new tree\n const newIndex = nodes.findIndex((n) => n.id === targetId);\n if (newIndex !== -1) {\n state.cursorIndex = newIndex;\n } else {\n // Node is gone (parent collapsed, session removed, etc.) — clamp\n const clamped = Math.min(state.cursorIndex, nodes.length - 1);\n state.cursorIndex = clamped;\n state.cursorNodeId = nodes[clamped]?.id ?? null;\n }\n}\n\n// ---------------------------------------------------------------------------\n// Auto-expand cycle\n// ---------------------------------------------------------------------------\n\nexport function autoExpandCycle(state: AppState): void {\n const selectedSession = state.selectedSession;\n if (!selectedSession) return;\n\n const sessionNodeId = `session:${selectedSession.id}`;\n const cycles = selectedSession.orchestratorCycles;\n\n // Only auto-manage cycle expansion if the session is already expanded by user\n if (!state.expanded.has(sessionNodeId)) {\n state.prevCycleCount = cycles.length;\n return;\n }\n\n if (cycles.length === 0) {\n state.prevCycleCount = 0;\n return;\n }\n\n const latest = cycles[cycles.length - 1]!;\n const latestId = `cycle:${selectedSession.id}:${latest.cycle}`;\n\n if (cycles.length > state.prevCycleCount && state.prevCycleCount > 0) {\n // New cycle appeared — collapse previous, expand latest\n const prevCycle = cycles[cycles.length - 2];\n if (prevCycle) {\n const prevId = `cycle:${selectedSession.id}:${prevCycle.cycle}`;\n state.expanded.delete(prevId);\n state.expanded.add(latestId);\n }\n } else if (!state.expanded.has(latestId)) {\n // Ensure latest is expanded\n state.expanded.add(latestId);\n }\n\n state.prevCycleCount = cycles.length;\n}\n","import { readFileSync, existsSync, readdirSync, statSync } from 'node:fs';\nimport { join } from 'node:path';\n\nimport {\n type AppState,\n type SessionSummary,\n type CycleLog,\n setRenderFunction,\n requestRender,\n stabilizeCursor,\n autoExpandCycle,\n notify,\n} from './state.js';\nimport { handleKeypress, type InputActions } from './input.js';\nimport { createFrameBuffer, flushFrame, writeCenter, copyRows } from './render.js';\nimport { writeToStdout, startKeypressListener, onResize } from './terminal.js';\nimport { buildTree } from './lib/tree.js';\nimport { precomputePrefixes } from './lib/tree-render.js';\nimport { resolveReports } from './lib/reports.js';\nimport { send, inboxList } from './lib/client.js';\nimport {\n listAllWindowIds,\n openEditorPopup,\n editInPopup,\n openCompanionPane,\n openClaudeResumePopup,\n openClaudeResumeSession,\n selectWindow,\n selectPane,\n switchToSession,\n paneExists,\n openLogPopup,\n openShellPopup,\n openInFileManager,\n promptInPopup,\n} from './lib/tmux.js';\nimport { copyToClipboard as sharedCopyToClipboard } from '../shared/clipboard.js';\nimport { buildSessionContext } from './lib/context.js';\nimport { renderTreePanel } from './panels/tree.js';\nimport { renderDetailRows, renderDigestRows, type DetailContext } from './panels/detail.js';\nimport { renderStackedDetailRows } from './panels/stacked-detail.js';\nimport { renderStatusLine } from './panels/bottom.js';\nimport { renderCrossSessionInboxRows } from './panels/cross-session-inbox.js';\nimport { renderSubmenuOverlay, renderHelpOverlay, renderCompanionOverlay, renderCompanionDebugOverlay } from './panels/overlays.js';\nimport { KEYMAP, MENU_FOR_MODE } from '../shared/keymap.js';\nimport { companionPath } from '../shared/paths.js';\nimport type { CompanionState } from '../shared/companion-types.js';\nimport { normalizeCompanion } from '../shared/companion-normalize.js';\nimport { composeViaPopup, ensureSisyphusInitLua } from './lib/popup-compose.js';\nimport { loadConfig } from '../shared/config.js';\nimport { roadmapPath, goalPath, strategyPath, logsDir, contextDir, digestPath } from '../shared/paths.js';\nimport { statusIndicator, formatDuration, statusColor, agentStatusIcon, agentDisplayName, truncate, ansiColor, ansiDim, ansiBold } from './lib/format.js';\nimport type { TreeNode } from './types/tree.js';\nimport type { Agent, Session, StatusDigest } from '../shared/types.js';\n\n// ── Module-level companion cache (reloads on mtime change, ~poll interval) ────\n\nlet _cachedCompanion: CompanionState | null = null;\nlet _companionMtime = 0;\n\nfunction getCompanion(): CompanionState | null {\n try {\n const { mtimeMs } = statSync(companionPath());\n if (_cachedCompanion && mtimeMs === _companionMtime) return _cachedCompanion;\n _companionMtime = mtimeMs;\n _cachedCompanion = normalizeCompanion(JSON.parse(readFileSync(companionPath(), 'utf-8')) as CompanionState);\n return _cachedCompanion;\n } catch {\n return _cachedCompanion;\n }\n}\n\n// ── Module-level cache for latest rendered nodes (needed by keypress handler) ─\n\nlet latestNodes: TreeNode[] = [];\n\n// ── Module-level cache for context file content ───────────────────────────────\n\nlet cachedContextFilePath: string | null = null;\nlet cachedContextFileContent: string | null = null;\n\n// ── Previous frame for diffing ────────────────────────────────────────────────\n\nlet prevFrame: string[] = [];\n// Tracks last known resolution state so render() can reset prevFrame on transition\nlet prevResolutionActive = false;\n\n// ── Panel dirty tracking ─────────────────────────────────────────────────────\n// Tracks the inputs that affect each panel. When only the scroll offset changes,\n// we can skip re-rendering panels whose inputs haven't changed.\n\nlet prevTreeInputs = '';\nlet prevBottomInputs = '';\n\n// ── Dynamic tree width ──────────────────────────────────────────────────────\n// Scale tree panel with terminal width so session names aren't aggressively\n// truncated on wide terminals. Min 36 (fits 80-col), max 70.\n\nfunction computeTreeWidth(cols: number): number {\n return Math.min(70, Math.max(36, Math.floor(cols * 0.25)));\n}\nlet prevOverlayMode = '';\nlet cachedTreeRows: string[] = [];\n\n// ── Cycle logs cache (avoids re-reading unchanged files every poll) ───────────\n\nlet cachedLogSessionId: string | null = null;\nlet cachedLogFiles: Map<string, { mtime: number; cycle: number; content: string }> = new Map();\n\n// ── Resolution frame renderer (3e) ───────────────────────────────────────────\n\nfunction renderResolutionFrame(buf: import('./render.js').FrameBuffer, state: AppState): void {\n const handle = state.resolutionHandle!;\n const info = handle.getHeaderInfo();\n const now = new Date().toISOString();\n\n // Build header strip (row 0)\n // Format: [esc] back ●●●○○ N of M sessionName/title ⏱ blocked Xm\n const escPart = ansiDim(' [esc] back');\n\n // Queue dots (max 12)\n const dotLimit = 12;\n const qLen = info.queueLength;\n let dotsPart = '';\n if (qLen <= dotLimit) {\n for (let i = 0; i < qLen; i++) {\n dotsPart += i < info.currentIndex ? '●' : '○';\n }\n } else {\n for (let i = 0; i < dotLimit; i++) {\n dotsPart += i < info.currentIndex ? '●' : '○';\n }\n const trailing = qLen - dotLimit;\n dotsPart += ` +${trailing}`;\n }\n const posLabel = ` ${info.currentIndex + 1} of ${info.queueLength}`;\n\n const sourcePart = info.sessionName\n ? ansiBold(info.sessionName) + (info.askTitle ? `/${truncate(info.askTitle, 32)}` : '')\n : '';\n\n const blocked = formatDuration(info.blockedSince, now);\n const timePart = ansiDim(`⏱ blocked ${blocked}`);\n\n const parts = [escPart, ' ', dotsPart, posLabel, ' ', sourcePart, ' ', timePart];\n let header = parts.join('');\n // Truncate if over width (drop source first, then truncate)\n if (header.replace(/\\x1b\\[[0-9;]*m/g, '').length > state.cols) {\n const shortened = [escPart, ' ', dotsPart, posLabel, ' ', timePart].join('');\n header = shortened;\n }\n buf.lines[0] = header + ' '.repeat(Math.max(0, state.cols - header.replace(/\\x1b\\[[0-9;]*m/g, '').length));\n\n // Rows 1..h-1: humanloop body OR visual (v0 toggle)\n const qid = handle.getCurrentQid();\n const visualEntry = qid ? state.visuals.get(qid) : undefined;\n\n const bodyH = state.rows - 1;\n\n if (visualEntry?.visible && visualEntry.status === 'ready') {\n // v0 toggle: visual replaces humanloop body entirely\n const visualLines = visualEntry.content.split('\\n');\n for (let i = 0; i < bodyH; i++) {\n buf.lines[i + 1] = i < visualLines.length ? visualLines[i]! : '';\n }\n } else {\n // Show humanloop content (with optional loading/error overlay on center row)\n const humanloopLines = handle.render();\n const midRow = Math.floor(bodyH / 2);\n for (let i = 0; i < bodyH; i++) {\n if (visualEntry?.visible && visualEntry.status === 'loading' && i === midRow) {\n const placeholderText = '[generating visual… ~30s]';\n const placeholder = ansiDim(placeholderText);\n const padL = Math.floor((state.cols - placeholderText.length) / 2);\n buf.lines[i + 1] = ' '.repeat(Math.max(0, padL)) + placeholder;\n } else if (visualEntry?.visible && visualEntry.status === 'error' && i === midRow) {\n const errText = visualEntry.error ? visualEntry.error : 'unknown';\n buf.lines[i + 1] = ansiColor(`[visual error: ${errText}]`, 'red') + ansiDim(' [R] retry');\n } else {\n buf.lines[i + 1] = i < humanloopLines.length ? humanloopLines[i]! : '';\n }\n }\n }\n}\n\n// ── Status header constants ──────────────────────────────────────────────────\n\nconst STATUS_ROW_COUNT = 2; // Fixed height for status header (avoids nvim resize on cursor change)\n\nfunction buildStatusRows(\n cursorNode: TreeNode | undefined,\n session: Session | null,\n state: AppState,\n): string[] {\n if (cursorNode?.type === 'needs-you-virtual') {\n const count = state.aggregateInbox.length;\n return [\n ' ' + ansiColor('⚑', 'red', true) + ' ' + ansiColor('Fleet Inbox', 'white', true),\n ' ' + ansiDim(`${count} pending ask${count !== 1 ? 's' : ''} across the fleet`),\n ];\n }\n\n if (cursorNode?.type === 'section') {\n const label = cursorNode.section === 'needs-you' ? 'Needs You' :\n cursorNode.section === 'running' ? 'Running' : 'Done';\n return [ansiDim(` ${label} section`), ''];\n }\n\n if (!cursorNode || !session) {\n return [ansiDim(' No session selected'), ''];\n }\n\n const dur = formatDuration(session.createdAt, session.completedAt);\n const indicator = statusIndicator(session.status);\n const sColor = statusColor(session.status);\n const title = truncate(session.name ?? session.task, 40);\n\n switch (cursorNode.type) {\n case 'session': {\n return [\n ' ' + ansiColor(indicator, sColor, true) + ' ' + ansiColor(title, 'white', true),\n ' ' + ansiDim(`${session.status} · ${session.orchestratorCycles.length} cycles · ${session.agents.length} agents · ${dur}`),\n ];\n }\n case 'cycle': {\n const cycle = session.orchestratorCycles.find(c => c.cycle === cursorNode.cycleNumber);\n if (!cycle) return [' ' + ansiColor(title, 'white', true), ''];\n const cDur = cycle.completedAt ? formatDuration(cycle.timestamp, cycle.completedAt) : 'running';\n const cStatus = cycle.completedAt ? 'completed' : 'running';\n return [\n ' ' + ansiColor(indicator, sColor, true) + ' ' + ansiColor(title, 'white', true) + ansiDim(` · Cycle ${cycle.cycle}`),\n ' ' + ansiDim(`${cStatus} · ${cDur} · ${cycle.agentsSpawned.length} agents`),\n ];\n }\n case 'agent':\n case 'report': {\n const agentId = cursorNode.type === 'agent' ? cursorNode.agentId : cursorNode.agentId;\n const agent = session.agents.find(a => a.id === agentId);\n if (!agent) return [' ' + ansiColor(title, 'white', true), ''];\n const aIcon = agentStatusIcon(agent.status);\n const aDur = formatDuration(agent.spawnedAt, agent.completedAt);\n const aName = agentDisplayName(agent);\n return [\n ' ' + ansiColor(aIcon, statusColor(agent.status === 'running' ? 'active' : agent.status), true) + ' ' + ansiColor(`${agent.id} · ${aName}`, 'white', true),\n ' ' + ansiDim(`${agent.status} · ${agent.agentType || '—'} · ${aDur}`),\n ];\n }\n case 'context-file': {\n const name = cursorNode.filePath.split('/').pop() ?? cursorNode.filePath;\n return [\n ' ' + ansiColor('⊞', 'white') + ' ' + ansiColor(name, 'white', true),\n ' ' + ansiDim(`context file · ${session.status}`),\n ];\n }\n case 'messages':\n case 'message': {\n return [\n ' ' + ansiColor(indicator, sColor, true) + ' ' + ansiColor(title, 'white', true),\n ' ' + ansiDim(`${session.messages.length} messages`),\n ];\n }\n default: {\n return [\n ' ' + ansiColor(indicator, sColor, true) + ' ' + ansiColor(title, 'white', true),\n ' ' + ansiDim(`${session.status} · ${dur}`),\n ];\n }\n }\n}\n\n// ── Helpers ───────────────────────────────────────────────────────────────────\n\nfunction getAgentForNode(node: TreeNode | undefined, agents: Agent[]): Agent | null {\n if (!node) return null;\n if (node.type === 'agent' || node.type === 'report') {\n return agents.find((a) => a.id === node.agentId) ?? null;\n }\n return null;\n}\n\n// ── startApp ──────────────────────────────────────────────────────────────────\n\nexport function startApp(state: AppState, cleanup: () => void): void {\n const config = loadConfig(state.cwd);\n\n // Materialize ~/.config/sisyphus/init.lua if missing (idempotent)\n ensureSisyphusInitLua();\n\n // Track selectedSessionId to detect changes across renders (for immediate poll)\n let prevSelectedSessionId: string | null | undefined = undefined;\n let debouncedPollTimer: ReturnType<typeof setTimeout> | null = null;\n\n // ── Polling ─────────────────────────────────────────────────────────────────\n\n async function poll(): Promise<void> {\n try {\n let selectedSession: Session | null = null;\n let planContent = '';\n let strategyContent = '';\n let goalContent = '';\n let completionSummaryContent = '';\n let logsContent = '';\n let logsCycles: CycleLog[] = [];\n let digestData: StatusDigest | null = null;\n let paneAlive = true;\n let contextFiles: string[] = [];\n\n const listPromise = send({ type: 'list', cwd: state.cwd });\n const statusPromise = state.selectedSessionId\n ? send({ type: 'status', sessionId: state.selectedSessionId, cwd: state.cwd })\n : null;\n const inboxPromise = inboxList();\n\n const [listRes, statusRes, aggregateInbox] = await Promise.all([\n listPromise,\n statusPromise ?? Promise.resolve(null),\n inboxPromise,\n ]);\n state.aggregateInbox = aggregateInbox;\n\n const sessions: SessionSummary[] = listRes.ok\n ? ((listRes.data?.sessions as SessionSummary[] | undefined) ?? [])\n : [];\n\n // Skip expensive sync I/O when resolution mode is active — panels are hidden,\n // data won't be rendered, and blocking here delays keystroke rendering.\n if (!state.resolutionActive) {\n\n // Batch-check window existence in a single tmux call\n const aliveWindows = listAllWindowIds();\n for (const s of sessions) {\n if (s.status !== 'completed' && s.tmuxWindowId) {\n s.windowAlive = aliveWindows.has(s.tmuxWindowId);\n }\n }\n\n if (state.selectedSessionId) {\n if (statusRes?.ok) {\n selectedSession = (statusRes.data?.session as Session | undefined) ?? null;\n }\n\n // Use cached windowAlive from the session list scan above\n if (selectedSession?.tmuxWindowId) {\n const cached = sessions.find((s) => s.id === state.selectedSessionId);\n paneAlive = cached?.windowAlive ?? false;\n }\n\n try {\n const pp = roadmapPath(state.cwd, state.selectedSessionId);\n if (existsSync(pp)) {\n planContent = readFileSync(pp, 'utf-8');\n }\n } catch {\n // roadmap.md may not exist yet\n }\n\n try {\n const gp = goalPath(state.cwd, state.selectedSessionId);\n if (existsSync(gp)) {\n goalContent = readFileSync(gp, 'utf-8');\n }\n } catch {\n // goal.md may not exist yet\n }\n\n try {\n const sp = strategyPath(state.cwd, state.selectedSessionId);\n if (existsSync(sp)) {\n strategyContent = readFileSync(sp, 'utf-8');\n }\n } catch {\n // strategy.md may not exist yet\n }\n\n try {\n const cp = join(contextDir(state.cwd, state.selectedSessionId), 'completion-summary.md');\n if (existsSync(cp)) {\n completionSummaryContent = readFileSync(cp, 'utf-8');\n }\n } catch {\n // completion-summary.md may not exist (only written on done)\n }\n\n try {\n const ld = logsDir(state.cwd, state.selectedSessionId);\n if (existsSync(ld)) {\n // Reset cache when session changes\n if (state.selectedSessionId !== cachedLogSessionId) {\n cachedLogFiles = new Map();\n cachedLogSessionId = state.selectedSessionId;\n }\n\n const files = readdirSync(ld)\n .filter((f) => f.startsWith('cycle-'))\n .sort();\n\n // Remove cache entries for deleted files\n const fileSet = new Set(files);\n for (const key of cachedLogFiles.keys()) {\n if (!fileSet.has(key)) cachedLogFiles.delete(key);\n }\n\n // Only re-read files whose mtime changed\n for (const f of files) {\n const filePath = join(ld, f);\n const mtime = statSync(filePath).mtimeMs;\n const cached = cachedLogFiles.get(f);\n if (!cached || cached.mtime !== mtime) {\n const match = f.match(/cycle-(\\d+)\\.md$/);\n const cycle = match ? parseInt(match[1]!, 10) : 0;\n const content = readFileSync(filePath, 'utf-8');\n cachedLogFiles.set(f, { mtime, cycle, content });\n }\n }\n\n logsCycles = files.map((f) => {\n const entry = cachedLogFiles.get(f)!;\n return { cycle: entry.cycle, content: entry.content };\n });\n logsContent = logsCycles.map((c) => c.content).join('\\n');\n }\n } catch {\n // logs may not exist yet\n }\n\n try {\n const cd = contextDir(state.cwd, state.selectedSessionId);\n if (existsSync(cd)) {\n const entries = readdirSync(cd, { withFileTypes: true })\n .filter((e) => !e.name.startsWith('.'));\n const flat: string[] = [];\n for (const e of entries) {\n if (e.isDirectory()) {\n try {\n const sub = readdirSync(join(cd, e.name))\n .filter((f) => !f.startsWith('.'))\n .map((f) => `${e.name}/${f}`);\n flat.push(...sub);\n } catch {\n // subdir may be unreadable\n }\n } else {\n flat.push(e.name);\n }\n }\n contextFiles = flat.sort();\n }\n } catch {\n // context dir may not exist yet\n }\n\n try {\n const dp = digestPath(state.cwd, state.selectedSessionId);\n if (existsSync(dp)) {\n const raw = JSON.parse(readFileSync(dp, 'utf-8'));\n if (\n raw &&\n typeof raw.recentWork === 'string' &&\n typeof raw.currentActivity === 'string' &&\n typeof raw.whatsNext === 'string' &&\n Array.isArray(raw.unusualEvents)\n ) {\n digestData = raw as StatusDigest;\n }\n }\n } catch {\n // digest.json may not exist or be malformed\n }\n }\n\n // Resolve report files in poll (not render) to avoid sync disk reads on keypress\n state.cachedReportBlocks.clear();\n if (selectedSession) {\n for (const agent of selectedSession.agents) {\n state.cachedReportBlocks.set(agent.id, resolveReports(agent.reports));\n }\n }\n\n } // end !state.resolutionActive\n\n state.sessions = sessions;\n state.selectedSession = selectedSession;\n state.planContent = planContent;\n state.strategyContent = strategyContent;\n state.goalContent = goalContent;\n state.completionSummaryContent = completionSummaryContent;\n state.logsContent = logsContent;\n state.logsCycles = logsCycles;\n state.digestData = digestData;\n state.paneAlive = paneAlive;\n state.contextFiles = contextFiles;\n state.error = null;\n\n requestRender();\n } catch (err) {\n const wasError = state.error !== null;\n state.error = (err as Error).message;\n if (!wasError) prevFrame = []; // force full redraw on error transition\n requestRender();\n }\n }\n\n // ── Render function ──────────────────────────────────────────────────────────\n\n function render(): void {\n const stdoutRows = process.stdout.rows;\n const stdoutCols = process.stdout.columns;\n state.rows = (typeof stdoutRows === 'number' && stdoutRows > 0) ? stdoutRows : 24;\n state.cols = (typeof stdoutCols === 'number' && stdoutCols > 0) ? stdoutCols : 80;\n\n const buf = createFrameBuffer(state.cols, state.rows);\n\n // Terminal too small\n if (state.cols < 60 || state.rows < 12) {\n writeCenter(buf, Math.floor(state.rows / 2), 'Terminal too small — resize to continue');\n const out = flushFrame(buf.lines, prevFrame);\n writeToStdout(out);\n prevFrame = buf.lines;\n return;\n }\n\n // Detect resolution mode transition → force full redraw (CLAUDE.md cache-pair invariant)\n if (state.resolutionActive !== prevResolutionActive) {\n prevFrame = [];\n prevResolutionActive = state.resolutionActive;\n }\n\n // Resolution mode full-screen takeover (3e)\n if (state.resolutionActive && state.resolutionHandle) {\n renderResolutionFrame(buf, state);\n const out = flushFrame(buf.lines, prevFrame, '\\x1b[0 q\\x1b[?25l');\n writeToStdout(out);\n prevFrame = buf.lines;\n return;\n }\n\n // Compute layout\n const treeWidth = computeTreeWidth(state.cols);\n const remaining = state.cols - treeWidth;\n const detailWidth = Math.floor(remaining * 0.6);\n const digestWidth = remaining - detailWidth;\n const contentHeight = state.rows - 1;\n\n const treeRect = { x: 0, y: 0, w: treeWidth, h: contentHeight };\n const detailRect = { x: treeWidth, y: 0, w: detailWidth, h: contentHeight };\n const digestRect = { x: treeWidth + detailWidth, y: 0, w: digestWidth, h: contentHeight };\n const bottomY = contentHeight;\n\n // Derive data\n const filteredSessions: SessionSummary[] = state.searchFilter\n ? state.sessions.filter((s) => {\n const q = state.searchFilter!.toLowerCase();\n return s.task.toLowerCase().includes(q) || s.id.toLowerCase().includes(q);\n })\n : state.sessions;\n\n const statusFP = filteredSessions.map(s => `${s.status}:${s.windowAlive}:${s.runningAgentCount}:${s.orphaned ?? false}`).join(',');\n const inboxFP = `${state.aggregateInbox.length}:${state.aggregateInbox.map(i => i.askId).join(',')}`;\n const cacheKey = `${state.expanded.size}:${filteredSessions.length}:${state.selectedSession?.id}:${state.contextFiles.length}:${state.searchFilter}:${statusFP}:${inboxFP}`;\n let nodes: TreeNode[];\n if (cacheKey === state.treeCacheKey && state.cachedTreeNodes !== null) {\n nodes = state.cachedTreeNodes;\n } else {\n nodes = buildTree(\n filteredSessions,\n state.selectedSession,\n state.expanded,\n state.cwd,\n state.contextFiles,\n state.aggregateInbox,\n );\n precomputePrefixes(nodes);\n state.cachedTreeNodes = nodes;\n state.treeCacheKey = cacheKey;\n }\n\n // Cursor stabilization\n stabilizeCursor(state, nodes);\n\n // Cache latest nodes for keypress handler\n latestNodes = nodes;\n\n // Track cursor node identity\n const cursorNode = nodes[state.cursorIndex];\n if (cursorNode) state.cursorNodeId = cursorNode.id;\n\n // Derive selectedSessionId from cursor\n // section and needs-you-virtual nodes have sessionId === '' — treat as null\n const rawSessionId = cursorNode?.sessionId;\n const newSessionId = rawSessionId ? rawSessionId : null;\n if (newSessionId !== state.selectedSessionId) {\n state.selectedSessionId = newSessionId;\n state.detailScroll.reset();\n state.digestScroll.reset();\n state.cachedDetailLines = null;\n state.detailCacheKey = '';\n state.cachedDigestLines = null;\n state.digestCacheKey = '';\n state.cachedInboxLines = null;\n state.inboxCacheKey = '';\n state.crossSessionInboxScroll.reset();\n state.flowExpanded = false;\n state.goalScroll.reset();\n state.strategyScroll.reset();\n state.roadmapScroll.reset();\n state.cachedStackedLines = null;\n state.stackedCacheKey = '';\n state.detailMode = 'gsr';\n state.focusedStrip = 'roadmap';\n }\n\n // Override detailMode when cursor is on the virtual fleet-inbox node\n if (cursorNode?.type === 'needs-you-virtual') {\n state.detailMode = 'cross-session-inbox';\n } else if (state.detailMode === 'cross-session-inbox') {\n state.detailMode = 'gsr';\n }\n\n // Trigger debounced poll when session changes (avoids poll storm during rapid scrolling)\n if (state.selectedSessionId !== prevSelectedSessionId) {\n prevSelectedSessionId = state.selectedSessionId;\n if (debouncedPollTimer !== null) clearTimeout(debouncedPollTimer);\n if (state.selectedSessionId !== null) {\n debouncedPollTimer = setTimeout(() => {\n debouncedPollTimer = null;\n void poll();\n }, 80);\n }\n }\n\n // Auto-expand cycle\n autoExpandCycle(state);\n\n // Resolve reports for detail panel\n const agents = state.selectedSession?.agents ?? [];\n const reportAgent =\n state.mode === 'report-detail' ? getAgentForNode(cursorNode, agents) : null;\n const reportBlocks = reportAgent ? (state.cachedReportBlocks.get(reportAgent.id) ?? []) : [];\n\n const detailAgent =\n cursorNode?.type === 'agent' || cursorNode?.type === 'report'\n ? getAgentForNode(cursorNode, agents)\n : null;\n const detailReportBlocks = detailAgent\n ? (state.cachedReportBlocks.get(detailAgent.id) ?? [])\n : [];\n\n // Load context file content (cached to avoid re-read on every render)\n let contextFileContent: string | null = null;\n if (cursorNode?.type === 'context-file') {\n if (cursorNode.filePath !== cachedContextFilePath) {\n cachedContextFilePath = cursorNode.filePath;\n try {\n if (existsSync(cursorNode.filePath)) {\n cachedContextFileContent = readFileSync(cursorNode.filePath, 'utf-8');\n } else {\n cachedContextFileContent = null;\n }\n } catch {\n cachedContextFileContent = null;\n }\n }\n contextFileContent = cachedContextFileContent;\n } else {\n // Clear cache when cursor moves away\n cachedContextFilePath = null;\n cachedContextFileContent = null;\n }\n\n // Panel dirty tracking — compute fingerprints for each panel's inputs\n const treeFocused = state.mode === 'navigate' && state.focusPane === 'tree';\n const treeInputs = `${state.treeCacheKey}:${state.cursorIndex}:${treeFocused}`;\n const bottomInputs = `${state.notification}:${state.error}:${state.mode}:${state.searchText}:${cursorNode?.type}`;\n const overlayMode = (state.mode === 'leader' || state.mode === 'copy-menu' || state.mode === 'open-menu' || state.mode === 'agent-menu' || state.mode === 'session-menu' || state.mode === 'go-menu' || state.mode === 'companion-menu' || state.mode === 'help' || state.mode === 'companion-overlay' || state.mode === 'companion-debug') ? state.mode : '';\n let companionFP = '';\n if (state.mode === 'companion-overlay' || state.mode === 'companion-debug') {\n const c = getCompanion();\n const ts = c && c.lastCommentary ? c.lastCommentary.timestamp : '';\n const xp = c ? c.xp : 0;\n const dm = c?.debugMood ? `${c.debugMood.winner}:${c.debugMood.scores[c.debugMood.winner]}` : '';\n companionFP = `${ts}:${xp}:${dm}`;\n }\n const overlayInputs = `${overlayMode}:${companionFP}`;\n\n const hasPrev = prevFrame.length === buf.height;\n const treeDirty = !hasPrev || treeInputs !== prevTreeInputs;\n const bottomDirty = !hasPrev || bottomInputs !== prevBottomInputs;\n const overlayDirty = !hasPrev || overlayInputs !== prevOverlayMode;\n\n prevTreeInputs = treeInputs;\n prevBottomInputs = bottomInputs;\n prevOverlayMode = overlayInputs;\n\n // Render tree into a narrow buffer (treeWidth-wide) so rows are the right size\n // for concatenation. Cached when clean.\n let treeRows: string[];\n if (treeDirty) {\n const treeBlank = ' '.repeat(treeWidth);\n const treeBuf: import('./render.js').FrameBuffer = {\n lines: Array.from({ length: contentHeight }, () => treeBlank),\n width: treeWidth,\n height: contentHeight,\n };\n renderTreePanel(\n treeBuf,\n { x: 0, y: 0, w: treeWidth, h: contentHeight },\n nodes,\n state.cursorIndex,\n treeFocused,\n getCompanion(),\n );\n cachedTreeRows = treeBuf.lines;\n treeRows = treeBuf.lines;\n } else {\n treeRows = cachedTreeRows;\n }\n\n // Render detail + logs as self-contained row strings, then compose by concatenation.\n // This eliminates all sliceDisplayCols calls — the main scroll bottleneck.\n const detailCtx: DetailContext = {\n nodes,\n session: state.selectedSession,\n agents,\n reportBlocks,\n detailReportBlocks,\n contextFileContent,\n };\n\n let detailRows: string[];\n if (cursorNode?.type === 'needs-you-virtual') {\n detailRows = renderCrossSessionInboxRows(detailRect, state);\n } else if (state.useStackedDetail) {\n detailRows = renderStackedDetailRows(detailRect, state, detailCtx);\n } else {\n detailRows = renderDetailRows(detailRect, state, detailCtx);\n }\n const rightPanelRows = renderDigestRows(digestRect, state);\n\n // Compose panel rows into buffer by concatenation (no slicing/splicing)\n for (let i = 0; i < contentHeight; i++) {\n buf.lines[i] = treeRows[i]! + detailRows[i]! + rightPanelRows[i]!;\n }\n\n // Bottom row (single status line — notifications replace keybindings transiently)\n if (bottomDirty || overlayDirty) {\n renderStatusLine(buf, bottomY, state, cursorNode?.type);\n } else {\n copyRows(buf, prevFrame, bottomY, 1);\n }\n\n // Overlays (rendered AFTER panels — overwrites panel content)\n if (overlayMode) {\n const ACCENT: Record<string, string> = {\n topLevel: 'magenta',\n copy: 'cyan',\n open: 'green',\n agent: 'blue',\n session: 'red',\n go: 'yellow',\n companion: 'magenta',\n };\n const menuId = MENU_FOR_MODE[state.mode];\n if (menuId) {\n const menu = menuId === 'topLevel' ? KEYMAP.topLevel : KEYMAP.submenus[menuId]!;\n const accent = ACCENT[menuId];\n renderSubmenuOverlay(buf, state.rows, state.cols, menu, accent !== undefined ? accent : 'white');\n }\n if (state.mode === 'help') renderHelpOverlay(buf, state.rows, state.cols);\n if (state.mode === 'companion-overlay') {\n const companion = getCompanion();\n if (companion) renderCompanionOverlay(buf, state.rows, state.cols, companion);\n }\n if (state.mode === 'companion-debug') {\n const companion = getCompanion();\n if (companion) renderCompanionDebugOverlay(buf, state.rows, state.cols, companion);\n }\n }\n\n // Build cursor suffix inside synchronized output block to prevent flicker\n const cursorSuffix = '\\x1b[0 q\\x1b[?25l';\n\n // Flush diff to stdout with cursor positioning inside sync block\n const out = flushFrame(buf.lines, prevFrame, cursorSuffix);\n writeToStdout(out);\n prevFrame = buf.lines;\n }\n\n // ── InputActions ─────────────────────────────────────────────────────────────\n\n const inputActions: InputActions = {\n getNodes: () => latestNodes,\n getCursorNode: () => latestNodes[state.cursorIndex],\n getAgentForNode: (node) => {\n const agents = state.selectedSession?.agents ?? [];\n return getAgentForNode(node, agents);\n },\n sendAndNotify: (request, successMsg) => {\n void send(request)\n .then((res) => {\n if (res.ok) {\n notify(state, successMsg);\n } else {\n const errMsg = res.error ? res.error : 'Unknown error';\n notify(state, `Error: ${errMsg}`);\n }\n })\n .catch((err: Error) => {\n notify(state, `Error: ${err.message}`);\n });\n },\n send,\n composeViaPopup,\n openEditorPopup,\n editInPopup,\n promptInPopup,\n openCompanionPane,\n openClaudeResumePopup,\n openClaudeResumeSession,\n selectWindow,\n selectPane,\n switchToSession,\n paneExists,\n openLogPopup,\n openShellPopup,\n openInFileManager,\n copyToClipboard: (text) => {\n const err = sharedCopyToClipboard(text);\n if (err !== null) notify(state, err.reason);\n },\n buildSessionContext,\n resolveEditor: () => {\n if (config.editor) return config.editor;\n if (process.env.EDITOR) return process.env.EDITOR;\n return 'nvim';\n },\n cleanup: () => {\n cleanup();\n process.exit(0);\n },\n };\n\n // ── Wire everything together ─────────────────────────────────────────────────\n\n setRenderFunction(render);\n\n const stopKeypress = startKeypressListener((input, key) => {\n handleKeypress(input, key, state, inputActions);\n });\n\n const stopResize = onResize(() => {\n const stdoutRows = process.stdout.rows;\n const stdoutCols = process.stdout.columns;\n state.rows = (typeof stdoutRows === 'number' && stdoutRows > 0) ? stdoutRows : 24;\n state.cols = (typeof stdoutCols === 'number' && stdoutCols > 0) ? stdoutCols : 80;\n prevFrame = []; // force full redraw\n if (state.resolutionActive && state.resolutionHandle) {\n state.resolutionHandle.handleResize(state.cols, state.rows - 1);\n }\n requestRender();\n });\n\n // Initial poll + recurring interval\n void poll();\n const pollInterval = setInterval(() => void poll(), 2500);\n\n // Register teardown so cleanup() releases all resources\n const origCleanup = inputActions.cleanup;\n inputActions.cleanup = () => {\n clearInterval(pollInterval);\n if (debouncedPollTimer !== null) clearTimeout(debouncedPollTimer);\n stopKeypress();\n stopResize();\n state.resolutionHandle?.unmount();\n state.detailScroll.destroy();\n state.digestScroll.destroy();\n state.goalScroll.destroy();\n state.strategyScroll.destroy();\n state.roadmapScroll.destroy();\n origCleanup();\n };\n\n // Initial render\n requestRender();\n}\n","import { readFileSync, readdirSync, statSync } from 'node:fs';\nimport { join } from 'node:path';\nimport { exportSessionToZip } from '../shared/session-export.js';\nimport { pasteFromClipboard } from '../shared/clipboard.js';\nimport type { Key } from './terminal.js';\nimport {\n type AppState,\n type ComposeAction,\n OPTIONAL_COMPOSE,\n requestRender,\n notify,\n} from './state.js';\nimport type { TreeNode } from './types/tree.js';\nimport type { Agent, Session } from '../shared/types.js';\nimport type { Response } from '../shared/protocol.js';\nimport { sessionDir, goalPath, roadmapPath, strategyPath, reportsDir } from '../shared/paths.js';\nimport type { Request } from '../shared/protocol.js';\nimport { findParentIndex } from './lib/tree.js';\nimport { badgeGalleryLeft, badgeGalleryRight, closeBadgeGallery, companionOverlayNextPage, companionOverlayShowHelp, companionOverlayDismissHelp, getCompanionPage, badgeListScrollUp, badgeListScrollDown } from './panels/overlays.js';\nimport { enterResolutionMode } from './panels/mounted-humanloop.js';\nimport { KEYMAP, MENU_FOR_MODE } from '../shared/keymap.js';\nimport type { MenuItem } from '../shared/keymap.js';\n\n// ── Re-exported types (same definition, no React) ─────────────────────────────\n\nexport type LeaderAction =\n // already present\n | { type: 'enter-copy-menu' }\n | { type: 'copy-path' }\n | { type: 'copy-context' }\n | { type: 'copy-logs' }\n | { type: 'copy-session-id' }\n | { type: 'delete-session' }\n | { type: 'open-logs' }\n | { type: 'open-session-dir' }\n | { type: 'open-strategy' }\n | { type: 'open-roadmap' }\n | { type: 'search' }\n | { type: 'jump-to-session'; index: number }\n | { type: 'spawn-agent' }\n | { type: 'message-agent' }\n | { type: 'help' }\n | { type: 'companion-overlay' }\n | { type: 'companion-debug' }\n | { type: 'companion-pane' }\n | { type: 'enter-companion-menu' }\n | { type: 'shell-command' }\n | { type: 'jump-to-pane' }\n | { type: 'export-session' }\n | { type: 'kill' }\n | { type: 'quit' }\n | { type: 'dismiss' }\n // new submenu enters\n | { type: 'enter-open-menu' }\n | { type: 'enter-agent-menu' }\n | { type: 'enter-session-menu' }\n | { type: 'enter-go-menu' }\n // new copy variants\n | { type: 'copy-latest-report' }\n | { type: 'copy-agent-id' }\n // new open variants\n | { type: 'open-goal' }\n | { type: 'open-latest-report' }\n | { type: 'open-scratch' }\n | { type: 'edit-context-file' }\n // new agent variants\n | { type: 'restart-agent' }\n | { type: 'rerun-agent' }\n | { type: 'open-claude-agent' }\n | { type: 'tail-agent-logs' }\n | { type: 'kill-agent' }\n | { type: 'quick-spawn-explore' }\n | { type: 'quick-spawn-debug' }\n // new session variants\n | { type: 'new-session' }\n | { type: 'resume-session' }\n | { type: 'continue-session' }\n | { type: 'rollback' }\n | { type: 'kill-session' }\n | { type: 'go-to-window' }\n | { type: 'clone-session' }\n | { type: 'history' }\n // new go variants\n | { type: 'pick-session' }\n | { type: 'cycle-session' }\n | { type: 'reconnect' }\n // messaging / status\n | { type: 'message-orchestrator' }\n | { type: 'show-status' };\n\nexport interface KeybindingHandlers {\n onMoveUp: () => void;\n onMoveDown: () => void;\n onEnter: () => void;\n onLeft: () => void;\n onRight: () => void;\n onSpace: () => void;\n onTab: () => void;\n onMessage: () => void;\n onGoToWindow: () => void;\n onEditGoal: () => void;\n onNewSession: () => void;\n onClaude: () => void;\n onOpenPlan: () => void;\n onQuit: () => void;\n onReRun: () => void;\n onResume: () => void;\n onContinue: () => void;\n onRestartAgent: () => void;\n onRollback: () => void;\n onToggleLogs: () => void;\n onEdit: () => void;\n}\n\n// ── InputActions interface ─────────────────────────────────────────────────────\n\nexport interface InputActions {\n // Navigation context (computed by caller, passed in)\n getNodes: () => TreeNode[];\n getCursorNode: () => TreeNode | undefined;\n getAgentForNode: (node: TreeNode | undefined) => Agent | null;\n\n // Async daemon operations\n sendAndNotify: (request: Request, successMsg: string) => void;\n send: (request: Request) => Promise<Response>;\n\n // Editor/tmux operations (injected — input.ts must not import these directly)\n openEditorPopup: typeof import('./lib/tmux.js').openEditorPopup;\n editInPopup: typeof import('./lib/tmux.js').editInPopup;\n promptInPopup: typeof import('./lib/tmux.js').promptInPopup;\n openCompanionPane: typeof import('./lib/tmux.js').openCompanionPane;\n openClaudeResumePopup: typeof import('./lib/tmux.js').openClaudeResumePopup;\n openClaudeResumeSession: typeof import('./lib/tmux.js').openClaudeResumeSession;\n selectWindow: typeof import('./lib/tmux.js').selectWindow;\n selectPane: typeof import('./lib/tmux.js').selectPane;\n switchToSession: typeof import('./lib/tmux.js').switchToSession;\n paneExists: typeof import('./lib/tmux.js').paneExists;\n openLogPopup: typeof import('./lib/tmux.js').openLogPopup;\n openShellPopup: typeof import('./lib/tmux.js').openShellPopup;\n openInFileManager: typeof import('./lib/tmux.js').openInFileManager;\n copyToClipboard: (text: string) => void;\n buildSessionContext: typeof import('./lib/context.js').buildSessionContext;\n\n // Compose via tmux popup\n composeViaPopup: typeof import('./lib/popup-compose.js').composeViaPopup;\n\n // Config\n resolveEditor: () => string;\n\n // Lifecycle\n cleanup: () => void;\n}\n\n/**\n * Map compose action kinds to daemon requests.\n */\nexport function dispatchComposeAction(\n action: ComposeAction,\n content: string,\n state: AppState,\n actions: InputActions,\n): void {\n switch (action.kind) {\n case 'new-session':\n actions.sendAndNotify(\n { type: 'start', task: content, cwd: state.cwd },\n 'Session created',\n );\n break;\n\n case 'message-orchestrator':\n actions.sendAndNotify(\n { type: 'message', sessionId: action.sessionId, content },\n 'Message queued',\n );\n break;\n\n case 'resume':\n actions.sendAndNotify(\n { type: 'resume', sessionId: action.sessionId, cwd: state.cwd, message: content || undefined },\n 'Session resumed',\n );\n break;\n\n case 'continue':\n void (async () => {\n try {\n const contRes = await actions.send({ type: 'continue', sessionId: action.sessionId });\n if (!contRes.ok) { notify(state, `Error: ${contRes.error}`); return; }\n actions.sendAndNotify(\n { type: 'resume', sessionId: action.sessionId, cwd: state.cwd, message: content || undefined },\n 'Session continued',\n );\n } catch (err) {\n notify(state, `Error: ${(err as Error).message}`);\n }\n })();\n break;\n\n case 'spawn-agent':\n actions.sendAndNotify(\n {\n type: 'spawn',\n sessionId: action.sessionId,\n agentType: 'default',\n name: 'agent',\n instruction: content,\n },\n 'Agent spawned',\n );\n break;\n\n case 'message-agent':\n actions.sendAndNotify(\n { type: 'message', sessionId: action.sessionId, content, source: { type: 'agent', agentId: action.agentId } },\n `Message sent to ${action.agentId}`,\n );\n break;\n }\n}\n\n// ── Descriptor-driven dispatcher ──────────────────────────────────────────────\n\n// Maps submenu ref → the LeaderAction type that enters it\nconst ENTER_FOR_REF: Record<string, LeaderAction['type']> = {\n copy: 'enter-copy-menu',\n open: 'enter-open-menu',\n agent: 'enter-agent-menu',\n session: 'enter-session-menu',\n go: 'enter-go-menu',\n companion: 'enter-companion-menu',\n};\n\n// Maps tuiAction strings (from MenuItem.tuiAction) to LeaderAction types\nconst TUI_ACTION_FOR_NAME: Record<string, LeaderAction['type']> = {\n 'search': 'search',\n 'edit-context-file': 'edit-context-file',\n 'show-leader': 'help',\n 'companion-overlay': 'companion-overlay',\n 'companion-debug': 'companion-debug',\n 'companion-pane': 'companion-pane',\n};\n\n// Hand-maintained mapping from script/popup name → LeaderAction type.\n// The `satisfies` clause is the compile-time gate: any value not in LeaderAction['type']\n// fails the build immediately. Add a row here when a new descriptor item must\n// be handled in-process by the dashboard.\nconst TUI_HANDLERS = {\n 'sisyphus-copy-path': 'copy-path',\n 'sisyphus-copy-id': 'copy-session-id',\n 'sisyphus-copy-context': 'copy-context',\n 'sisyphus-copy-logs': 'copy-logs',\n 'sisyphus-copy-latest-report': 'copy-latest-report',\n 'sisyphus-copy-agent-id': 'copy-agent-id',\n 'sisyphus-open-goal': 'open-goal',\n 'sisyphus-open-roadmap': 'open-roadmap',\n 'sisyphus-open-strategy': 'open-strategy',\n 'sisyphus-open-logs': 'open-logs',\n 'sisyphus-open-dir': 'open-session-dir',\n 'sisyphus-open-latest-report': 'open-latest-report',\n 'sisyphus-open-scratch': 'open-scratch',\n 'sisyphus-spawn-agent': 'spawn-agent',\n 'sisyphus-msg-agent': 'message-agent',\n 'sisyphus-restart-agent-popup': 'restart-agent',\n 'sisyphus-rerun-agent': 'rerun-agent',\n 'sisyphus-jump-to-pane': 'jump-to-pane',\n 'sisyphus-open-claude-agent': 'open-claude-agent',\n 'sisyphus-tail-agent-logs': 'tail-agent-logs',\n 'sisyphus-kill-agent': 'kill-agent',\n 'sisyphus-quick-spawn-explore': 'quick-spawn-explore',\n 'sisyphus-quick-spawn-debug': 'quick-spawn-debug',\n 'sisyphus-new': 'new-session',\n 'sisyphus-resume-session': 'resume-session',\n 'sisyphus-continue-session': 'continue-session',\n 'sisyphus-rollback-session': 'rollback',\n 'sisyphus-kill-session': 'kill-session',\n 'sisyphus-delete-session': 'delete-session',\n 'sisyphus-export-session': 'export-session',\n 'sisyphus-go-to-window': 'go-to-window',\n 'sisyphus-clone-session': 'clone-session',\n 'sisyphus-history': 'history',\n 'sisyphus-pick-session': 'pick-session',\n 'sisyphus-cycle': 'cycle-session',\n 'sisyphus-reconnect': 'reconnect',\n 'sisyphus-help': 'help',\n 'sisyphus-home': 'cycle-session',\n 'sisyphus-msg': 'message-orchestrator',\n 'sisyphus-status-popup': 'show-status',\n 'sisyphus-kill-pane': 'kill',\n} as const satisfies Record<string, LeaderAction['type']>;\n\nfunction findLatestReport(cwd: string, sessionId: string): string | null {\n const dir = reportsDir(cwd, sessionId);\n try {\n const files = readdirSync(dir);\n if (files.length === 0) return null;\n let latestFile = files[0]!;\n let latestMtime = statSync(join(dir, latestFile)).mtimeMs;\n for (let i = 1; i < files.length; i++) {\n const m = statSync(join(dir, files[i]!)).mtimeMs;\n if (m > latestMtime) { latestMtime = m; latestFile = files[i]!; }\n }\n return join(dir, latestFile);\n } catch { return null; }\n}\n\nasync function goToSessionWindow(state: AppState, actions: InputActions): Promise<void> {\n const session = state.selectedSession;\n if (!session || !state.selectedSessionId) { notify(state, 'No session selected'); return; }\n\n if (session.status !== 'completed' && state.paneAlive && session.tmuxWindowId) {\n const switchTarget = session.tmuxSessionId ?? session.tmuxSessionName;\n if (switchTarget) actions.switchToSession(switchTarget);\n actions.selectWindow(session.tmuxWindowId);\n return;\n }\n\n // Pane appears dead but the tmux session may still exist with stale IDs\n // (window closed, daemon restarted, etc.) — try a daemon-side reconnect to\n // refresh tmuxSessionId/tmuxWindowId, then switch using the fresh IDs.\n // Falls through to a fresh `claude --resume` only if no tmux session by name exists.\n if (session.status !== 'completed') {\n const sessionId = state.selectedSessionId;\n const res = await actions.send({ type: 'reconnect', sessionId, cwd: state.cwd });\n if (res.ok) {\n const data = res.data ?? {};\n const tmuxName = (data['tmuxSessionName'] as string | undefined) ?? session.tmuxSessionName;\n const tmuxWin = data['tmuxWindowId'] as string | undefined;\n const tmuxId = data['tmuxSessionId'] as string | undefined;\n const switchTarget = tmuxId ?? tmuxName;\n if (switchTarget) actions.switchToSession(switchTarget);\n if (tmuxWin) actions.selectWindow(tmuxWin);\n notify(state, `Reconnected ${tmuxName ?? sessionId}`);\n return;\n }\n }\n\n const lastCycle = session.orchestratorCycles[session.orchestratorCycles.length - 1];\n const claudeSessionId = lastCycle?.claudeSessionId;\n if (!claudeSessionId) { notify(state, 'No orchestrator Claude session ID available'); return; }\n try {\n const label = session.name ?? state.selectedSessionId!.slice(0, 8);\n const sessionName = actions.openClaudeResumeSession(state.cwd, state.selectedSessionId!, claudeSessionId, label, lastCycle.resumeEnv, lastCycle.resumeArgs, lastCycle.cycle, lastCycle.mode);\n actions.switchToSession(sessionName);\n } catch {\n notify(state, 'Failed to open Claude session');\n }\n}\n\nfunction dispatchItem(item: MenuItem, state: AppState, actions: InputActions): void {\n if (item.action.type === 'submenu') {\n const t = ENTER_FOR_REF[item.action.ref];\n if (!t) return handleLeaderAction({ type: 'dismiss' }, state, actions);\n return handleLeaderAction({ type: t } as LeaderAction, state, actions);\n }\n if (item.tuiAction) {\n const t = TUI_ACTION_FOR_NAME[item.tuiAction];\n if (t) return handleLeaderAction({ type: t } as LeaderAction, state, actions);\n }\n if (item.action.type === 'tui') {\n const t = TUI_ACTION_FOR_NAME[item.action.action];\n if (t) return handleLeaderAction({ type: t } as LeaderAction, state, actions);\n notify(state, `No tui-action handler for ${item.action.action}`);\n return handleLeaderAction({ type: 'dismiss' }, state, actions);\n }\n if (item.action.type === 'script' || item.action.type === 'popup') {\n const t = TUI_HANDLERS[item.action.name as keyof typeof TUI_HANDLERS];\n if (t) return handleLeaderAction({ type: t } as LeaderAction, state, actions);\n notify(state, `No dashboard handler for ${item.action.name}`);\n return handleLeaderAction({ type: 'dismiss' }, state, actions);\n }\n // tmux-only items silently dismissed on dashboard\n handleLeaderAction({ type: 'dismiss' }, state, actions);\n}\n\n// ── Internal helpers ──────────────────────────────────────────────────────────\n\nfunction expandSessionLatestCycle(state: AppState, node: TreeNode): void {\n if (node.type === 'session' && state.selectedSession?.id === node.sessionId) {\n const cycles = state.selectedSession.orchestratorCycles;\n if (cycles.length > 0) {\n const latest = cycles[cycles.length - 1]!;\n state.expanded.add(`cycle:${node.sessionId}:${latest.cycle}`);\n }\n }\n}\n\n// ── handleReportDetailKey ─────────────────────────────────────────────────────\n\nfunction handleReportDetailKey(input: string, key: Key, state: AppState, _actions: InputActions): void {\n if (key.escape || key.return) {\n state.mode = 'navigate';\n requestRender();\n return;\n }\n if (key.upArrow) {\n state.detailScroll.scrollBy(-1);\n return;\n }\n if (key.downArrow) {\n state.detailScroll.scrollBy(1);\n return;\n }\n}\n\n// ── handleLeaderKey ───────────────────────────────────────────────────────────\n\nfunction handleLeaderAction(action: LeaderAction, state: AppState, actions: InputActions): void {\n const nodes = actions.getNodes();\n const cursorNode = actions.getCursorNode();\n const session = state.selectedSession;\n const selectedSessionId = state.selectedSessionId;\n const agents = session?.agents ?? [];\n\n switch (action.type) {\n case 'enter-copy-menu':\n state.mode = 'copy-menu';\n requestRender();\n return;\n\n case 'copy-path': {\n if (!selectedSessionId) { notify(state, 'No session selected'); break; }\n const path = sessionDir(state.cwd, selectedSessionId);\n try {\n actions.copyToClipboard(path);\n notify(state, `Copied path (${path})`);\n } catch {\n notify(state, 'Failed to copy to clipboard');\n }\n break;\n }\n\n case 'copy-context': {\n if (!selectedSessionId || !session) { notify(state, 'No session selected'); break; }\n try {\n const xml = actions.buildSessionContext(session, state.cwd);\n actions.copyToClipboard(xml);\n notify(state, `Copied context (${xml.length} chars)`);\n } catch {\n notify(state, 'Failed to copy context');\n }\n break;\n }\n\n case 'copy-logs': {\n if (!state.logsContent) { notify(state, 'No logs content'); break; }\n try {\n actions.copyToClipboard(state.logsContent);\n notify(state, `Copied logs (${state.logsContent.length} chars)`);\n } catch {\n notify(state, 'Failed to copy to clipboard');\n }\n break;\n }\n\n case 'copy-session-id': {\n if (!selectedSessionId) { notify(state, 'No session selected'); break; }\n try {\n actions.copyToClipboard(selectedSessionId);\n notify(state, `Copied session ID (${selectedSessionId})`);\n } catch {\n notify(state, 'Failed to copy to clipboard');\n }\n break;\n }\n\n case 'delete-session': {\n if (!selectedSessionId) { notify(state, 'No session selected'); break; }\n try {\n const text = actions.promptInPopup('Delete session? (yes/no):');\n if (text?.trim() === 'yes') {\n actions.sendAndNotify({ type: 'delete', sessionId: selectedSessionId, cwd: state.cwd }, 'Session deleted');\n } else {\n notify(state, 'Delete cancelled');\n }\n } catch {\n notify(state, 'Failed to open prompt');\n }\n break;\n }\n\n case 'open-logs': {\n try {\n actions.openLogPopup();\n } catch {\n notify(state, 'Failed to open log popup');\n }\n break;\n }\n\n case 'open-session-dir': {\n if (!selectedSessionId) { notify(state, 'No session selected'); break; }\n try {\n actions.openInFileManager(sessionDir(state.cwd, selectedSessionId));\n } catch {\n notify(state, 'Failed to open session directory');\n }\n break;\n }\n\n case 'open-strategy': {\n if (!selectedSessionId) { notify(state, 'No session selected'); break; }\n const editor = actions.resolveEditor();\n try {\n actions.openEditorPopup(state.cwd, editor, strategyPath(state.cwd, selectedSessionId));\n } catch {\n notify(state, 'Failed to open strategy');\n }\n break;\n }\n\n case 'open-roadmap': {\n if (!selectedSessionId) { notify(state, 'No session selected'); break; }\n const editor = actions.resolveEditor();\n try {\n actions.openEditorPopup(state.cwd, editor, roadmapPath(state.cwd, selectedSessionId));\n } catch {\n notify(state, 'Failed to open roadmap');\n }\n break;\n }\n\n case 'search': {\n state.mode = 'search';\n state.searchText = '';\n requestRender();\n return;\n }\n\n case 'jump-to-session': {\n let count = 0;\n for (let i = 0; i < nodes.length; i++) {\n if (nodes[i]?.type === 'session') {\n count++;\n if (count === action.index) {\n state.cursorIndex = i;\n state.cursorNodeId = nodes[i]!.id;\n break;\n }\n }\n }\n break;\n }\n\n case 'spawn-agent': {\n if (!selectedSessionId) { notify(state, 'No session selected'); break; }\n actions.composeViaPopup({ kind: 'spawn-agent', sessionId: selectedSessionId }, state, actions);\n break;\n }\n\n case 'message-agent': {\n const agent = actions.getAgentForNode(cursorNode);\n if (!agent) { notify(state, 'Cursor must be on an agent'); break; }\n actions.composeViaPopup({ kind: 'message-agent', sessionId: selectedSessionId!, agentId: agent.id }, state, actions);\n break;\n }\n\n case 'help':\n state.mode = 'help';\n requestRender();\n return;\n\n case 'enter-companion-menu':\n state.mode = 'companion-menu';\n requestRender();\n return;\n\n case 'companion-overlay':\n state.mode = 'companion-overlay';\n requestRender();\n return;\n\n case 'companion-debug':\n state.mode = 'companion-debug';\n requestRender();\n return;\n\n case 'companion-pane':\n try {\n actions.openCompanionPane(state.cwd);\n } catch {\n notify(state, 'Failed to open companion pane');\n }\n return;\n\n case 'shell-command': {\n if (!selectedSessionId) { notify(state, 'No session selected'); break; }\n try {\n const text = actions.promptInPopup('$', { w: '80%' });\n if (text?.trim()) {\n actions.openShellPopup(state.cwd, text.trim());\n }\n } catch {\n notify(state, 'Failed to open prompt');\n }\n break;\n }\n\n case 'jump-to-pane': {\n const agent = actions.getAgentForNode(cursorNode);\n if (!agent?.paneId) { notify(state, 'Select an agent with an active pane'); break; }\n if (session?.tmuxSessionName) actions.switchToSession(session.tmuxSessionName);\n if (session?.tmuxWindowId) actions.selectWindow(session.tmuxWindowId);\n actions.selectPane(agent.paneId);\n break;\n }\n\n case 'export-session': {\n if (!selectedSessionId) { notify(state, 'No session selected'); break; }\n exportSessionToZip(selectedSessionId, state.cwd)\n .then(outputPath => notify(state, `Exported to ${outputPath}`))\n .catch(err => notify(state, `Export failed: ${(err as Error).message}`));\n break;\n }\n\n case 'kill': {\n if (!selectedSessionId) { notify(state, 'No session selected'); break; }\n const node = nodes[state.cursorIndex];\n if (node && (node.type === 'agent' || node.type === 'report')) {\n const agentId = node.agentId;\n const agent = agents.find((a) => a.id === agentId);\n if (agent?.status !== 'running') { notify(state, `Agent ${agentId} is not running`); break; }\n actions.sendAndNotify({ type: 'kill-agent', sessionId: selectedSessionId, agentId }, `Killed ${agentId}`);\n } else {\n actions.sendAndNotify({ type: 'kill', sessionId: selectedSessionId }, 'Session killed');\n }\n break;\n }\n\n case 'quit':\n actions.cleanup();\n return;\n\n case 'enter-open-menu':\n state.mode = 'open-menu';\n requestRender();\n return;\n\n case 'enter-agent-menu':\n state.mode = 'agent-menu';\n requestRender();\n return;\n\n case 'enter-session-menu':\n state.mode = 'session-menu';\n requestRender();\n return;\n\n case 'enter-go-menu':\n state.mode = 'go-menu';\n requestRender();\n return;\n\n case 'copy-latest-report': {\n if (!selectedSessionId) { notify(state, 'No session selected'); break; }\n const latest = findLatestReport(state.cwd, selectedSessionId);\n if (!latest) { notify(state, 'No reports found'); break; }\n try {\n const content = readFileSync(latest, 'utf-8');\n actions.copyToClipboard(content);\n notify(state, `Copied latest report (${content.length} chars)`);\n } catch {\n notify(state, 'Failed to copy report');\n }\n break;\n }\n\n case 'copy-agent-id': {\n const agent = actions.getAgentForNode(cursorNode);\n if (!agent) { notify(state, 'Cursor must be on an agent'); break; }\n try {\n actions.copyToClipboard(agent.id);\n notify(state, `Copied agent ID (${agent.id})`);\n } catch {\n notify(state, 'Failed to copy to clipboard');\n }\n break;\n }\n\n case 'open-goal': {\n if (!selectedSessionId) { notify(state, 'No session selected'); break; }\n const editor = actions.resolveEditor();\n try {\n actions.openEditorPopup(state.cwd, editor, goalPath(state.cwd, selectedSessionId));\n } catch {\n notify(state, 'Failed to open goal');\n }\n break;\n }\n\n case 'open-latest-report': {\n if (!selectedSessionId) { notify(state, 'No session selected'); break; }\n const latest = findLatestReport(state.cwd, selectedSessionId);\n if (!latest) { notify(state, 'No reports found'); break; }\n const editor = actions.resolveEditor();\n try {\n actions.openEditorPopup(state.cwd, editor, latest);\n } catch {\n notify(state, 'Failed to open report');\n }\n break;\n }\n\n case 'open-scratch': {\n if (!selectedSessionId) { notify(state, 'No session selected'); break; }\n const editor = actions.resolveEditor();\n try {\n actions.openEditorPopup(state.cwd, editor, join(sessionDir(state.cwd, selectedSessionId), 'scratch.md'));\n } catch {\n notify(state, 'Failed to open scratch');\n }\n break;\n }\n\n case 'edit-context-file': {\n if (!cursorNode || cursorNode.type !== 'context-file') { notify(state, 'Cursor must be on a context file'); break; }\n const editor = actions.resolveEditor();\n try {\n actions.openEditorPopup(state.cwd, editor, cursorNode.filePath);\n } catch {\n notify(state, 'Failed to open file in editor');\n }\n break;\n }\n\n case 'restart-agent': {\n const agent = actions.getAgentForNode(cursorNode);\n if (!agent || !selectedSessionId) { notify(state, 'Select an agent to restart'); break; }\n actions.sendAndNotify(\n { type: 'restart-agent', sessionId: selectedSessionId, agentId: agent.id },\n `Restarted ${agent.id}`,\n );\n break;\n }\n\n case 'rerun-agent': {\n const agent = actions.getAgentForNode(cursorNode);\n if (!agent || !selectedSessionId) { notify(state, 'Select an agent to re-run'); break; }\n actions.sendAndNotify(\n {\n type: 'spawn',\n sessionId: selectedSessionId,\n agentType: agent.agentType,\n name: `${agent.name}-retry`,\n instruction: agent.instruction,\n },\n `Re-spawned ${agent.name}`,\n );\n break;\n }\n\n case 'open-claude-agent': {\n const agent = actions.getAgentForNode(cursorNode);\n if (!agent) { notify(state, 'Cursor must be on an agent'); break; }\n if (!agent.claudeSessionId) { notify(state, 'No Claude session ID available'); break; }\n try {\n actions.openClaudeResumePopup(state.cwd, agent.claudeSessionId, agent.resumeEnv, agent.resumeArgs);\n } catch {\n notify(state, 'Failed to open Claude session');\n }\n break;\n }\n\n case 'tail-agent-logs': {\n const agent = actions.getAgentForNode(cursorNode);\n if (!agent) { notify(state, 'Cursor must be on an agent'); break; }\n if (!agent.paneId) { notify(state, 'Agent has no active pane'); break; }\n try {\n actions.openShellPopup(state.cwd, `tmux capture-pane -t ${agent.paneId} -p -S -2000 | less +G`);\n } catch {\n notify(state, 'Failed to open logs');\n }\n break;\n }\n\n case 'kill-agent': {\n const agent = actions.getAgentForNode(cursorNode);\n if (!agent || !selectedSessionId) { notify(state, 'Select an agent to kill'); break; }\n if (agent.status !== 'running') { notify(state, `Agent ${agent.id} is not running`); break; }\n actions.sendAndNotify({ type: 'kill-agent', sessionId: selectedSessionId, agentId: agent.id }, `Killed ${agent.id}`);\n break;\n }\n\n case 'quick-spawn-explore': {\n if (!selectedSessionId) { notify(state, 'No session selected'); break; }\n const pasted = pasteFromClipboard();\n if ('reason' in pasted) {\n notify(state, pasted.reason);\n break;\n }\n const exploreInstruction = pasted.text.trim();\n if (exploreInstruction.length < 20) {\n notify(state, `Clipboard too short (${exploreInstruction.length} chars; need 20+)`);\n break;\n }\n actions.sendAndNotify(\n { type: 'spawn', sessionId: selectedSessionId, agentType: 'sisyphus:explore', name: `explore-${Date.now()}`, instruction: exploreInstruction },\n 'Explore agent spawned',\n );\n break;\n }\n\n case 'quick-spawn-debug': {\n if (!selectedSessionId) { notify(state, 'No session selected'); break; }\n const pasted = pasteFromClipboard();\n if ('reason' in pasted) {\n notify(state, pasted.reason);\n break;\n }\n const debugInstruction = pasted.text.trim();\n if (debugInstruction.length < 20) {\n notify(state, `Clipboard too short (${debugInstruction.length} chars; need 20+)`);\n break;\n }\n actions.sendAndNotify(\n { type: 'spawn', sessionId: selectedSessionId, agentType: 'sisyphus:debug', name: `debug-${Date.now()}`, instruction: debugInstruction },\n 'Debug agent spawned',\n );\n break;\n }\n\n case 'new-session': {\n actions.composeViaPopup({ kind: 'new-session' }, state, actions);\n break;\n }\n\n case 'resume-session': {\n if (!selectedSessionId) { notify(state, 'No session selected'); break; }\n if (session?.status === 'active' && state.paneAlive) { notify(state, 'Session already active'); break; }\n actions.composeViaPopup({ kind: 'resume', sessionId: selectedSessionId }, state, actions);\n break;\n }\n\n case 'continue-session': {\n if (!selectedSessionId) { notify(state, 'No session selected'); break; }\n if (session?.status !== 'completed') { notify(state, 'Session not completed'); break; }\n actions.composeViaPopup({ kind: 'continue', sessionId: selectedSessionId }, state, actions);\n break;\n }\n\n case 'rollback': {\n if (!selectedSessionId) { notify(state, 'No session selected'); break; }\n try {\n const text = actions.promptInPopup('Rollback to cycle:');\n if (text?.trim()) {\n const toCycle = parseInt(text.trim(), 10);\n if (isNaN(toCycle) || toCycle < 1) { notify(state, 'Invalid cycle number'); break; }\n actions.sendAndNotify(\n { type: 'rollback', sessionId: selectedSessionId, cwd: state.cwd, toCycle },\n `Rolled back to cycle ${toCycle} — use [R]esume to respawn`,\n );\n }\n } catch {\n notify(state, 'Failed to open prompt');\n }\n break;\n }\n\n case 'kill-session': {\n if (!selectedSessionId) { notify(state, 'No session selected'); break; }\n actions.sendAndNotify({ type: 'kill', sessionId: selectedSessionId }, 'Session killed');\n break;\n }\n\n case 'go-to-window': {\n void goToSessionWindow(state, actions);\n break;\n }\n\n case 'clone-session': {\n if (!selectedSessionId) { notify(state, 'No session selected'); break; }\n try {\n actions.openShellPopup(state.cwd, `sis session clone ${selectedSessionId}`);\n } catch {\n notify(state, 'Failed to open shell');\n }\n break;\n }\n\n case 'history': {\n try {\n actions.openShellPopup(state.cwd, 'sis admin history');\n } catch {\n notify(state, 'Failed to open shell');\n }\n break;\n }\n\n case 'pick-session': {\n try {\n actions.openShellPopup(state.cwd, 'sis pick-session');\n } catch {\n notify(state, 'Failed to open shell');\n }\n break;\n }\n\n case 'cycle-session': {\n try {\n actions.openShellPopup(state.cwd, 'sis cycle');\n } catch {\n notify(state, 'Failed to open shell');\n }\n break;\n }\n\n case 'reconnect': {\n try {\n actions.openShellPopup(state.cwd, 'sis session reconnect');\n } catch {\n notify(state, 'Failed to open shell');\n }\n break;\n }\n\n case 'message-orchestrator': {\n if (!selectedSessionId) { notify(state, 'No session selected'); break; }\n actions.composeViaPopup({ kind: 'message-orchestrator', sessionId: selectedSessionId }, state, actions);\n break;\n }\n\n case 'show-status': {\n try {\n actions.openShellPopup(state.cwd, `sis status${selectedSessionId ? ` ${selectedSessionId}` : ''}`);\n } catch {\n notify(state, 'Failed to open status');\n }\n break;\n }\n\n case 'dismiss':\n closeBadgeGallery();\n break;\n }\n\n state.mode = 'navigate';\n requestRender();\n}\n\nfunction handleOverlayKey(input: string, key: Key, state: AppState, actions: InputActions): void {\n if (state.mode === 'help') {\n if (key.escape || input === '?') { handleLeaderAction({ type: 'dismiss' }, state, actions); }\n // any other key: ignore\n return;\n }\n\n if (state.mode === 'companion-overlay') {\n if (input === '?') {\n if (getCompanionPage() === 'help') companionOverlayDismissHelp();\n else companionOverlayShowHelp();\n requestRender(); return;\n }\n if (key.escape) {\n if (getCompanionPage() === 'help') { companionOverlayDismissHelp(); requestRender(); return; }\n handleLeaderAction({ type: 'dismiss' }, state, actions); return;\n }\n if (key.tab) { companionOverlayNextPage(); requestRender(); return; }\n if (getCompanionPage() === 'badges') {\n if (key.upArrow || input === 'k') { badgeGalleryLeft(); requestRender(); return; }\n if (key.downArrow || input === 'j') { badgeGalleryRight(); requestRender(); return; }\n if (key.leftArrow || input === 'h') { badgeListScrollUp(); requestRender(); return; }\n if (key.rightArrow || input === 'l') { badgeListScrollDown(); requestRender(); return; }\n }\n // any other key: ignore\n return;\n }\n\n if (state.mode === 'companion-debug') {\n handleLeaderAction({ type: 'dismiss' }, state, actions);\n }\n}\n\nfunction handleLeaderKey(input: string, key: Key, state: AppState, actions: InputActions): void {\n // Overlay modes (help, companion-overlay, companion-debug) are not in KEYMAP\n if (state.mode === 'help' || state.mode === 'companion-overlay' || state.mode === 'companion-debug') {\n return handleOverlayKey(input, key, state, actions);\n }\n\n if (key.escape) { handleLeaderAction({ type: 'dismiss' }, state, actions); return; }\n\n const menuId = MENU_FOR_MODE[state.mode];\n if (!menuId) return;\n\n const menu = menuId === 'topLevel' ? KEYMAP.topLevel : KEYMAP.submenus[menuId]!;\n const item = menu.items.find(i => i.key === input);\n if (!item) {\n // Digit 1-9: jump to session — only at top level\n if (state.mode === 'leader') {\n const digit = parseInt(input, 10);\n if (digit >= 1 && digit <= 9) {\n handleLeaderAction({ type: 'jump-to-session', index: digit }, state, actions);\n return;\n }\n }\n handleLeaderAction({ type: 'dismiss' }, state, actions);\n return;\n }\n dispatchItem(item, state, actions);\n}\n\n// Returns the scroll object that j/k should drive when detail pane is focused in stacked mode,\n// or null when the caller should fall through to normal tree/logs scroll logic.\nfunction getActiveDetailScroll(state: AppState) {\n if (state.focusPane !== 'detail' || !state.useStackedDetail) return null;\n if (state.detailMode === 'cycle-log') return state.detailScroll;\n return state.focusedStrip === 'goal' ? state.goalScroll\n : state.focusedStrip === 'strategy' ? state.strategyScroll\n : state.roadmapScroll;\n}\n\n// ── handleResolutionKey ───────────────────────────────────────────────────────\n// Layered-key precedence (load-bearing — see src/tui/CLAUDE.md):\n// 1. esc always wins (even mid comment-buffer)\n// 2. Shift+J/K queue walk, gated by canAcceptHostKeys\n// 3. space/R visual gen/toggle, gated by canAcceptHostKeys\n// 4. fall-through to humanloop\n\nfunction handleResolutionKey(input: string, key: Key, state: AppState, actions: InputActions): void {\n const handle = state.resolutionHandle;\n if (!handle) return;\n\n // 1. esc → exit resolution mode (always wins)\n if (key.escape) {\n handle.unmount();\n return;\n }\n\n // 2. Shift+J / Shift+K → queue walk (only when humanloop can accept host keys)\n if (input === 'J' && handle.canAcceptHostKeys()) {\n handle.advanceQueue(+1);\n return;\n }\n if (input === 'K' && handle.canAcceptHostKeys()) {\n handle.advanceQueue(-1);\n return;\n }\n\n // 3. space → toggle visual / fire generation (gated)\n if (input === ' ' && handle.canAcceptHostKeys()) {\n handle.spaceVisualToggle();\n return;\n }\n\n // 4. R → force regenerate visual (gated)\n if (input === 'R' && handle.canAcceptHostKeys()) {\n handle.regenerateVisual();\n return;\n }\n\n // 5. Fall-through to humanloop\n handle.handleKey(input, key);\n requestRender();\n}\n\n// ── Focus cycle ───────────────────────────────────────────────────────────────\n// Tab / Shift-Tab walks an ordered list of focus stops. In stacked gsr mode,\n// the detail pane expands into three strip stops (goal/strategy/roadmap).\n\ntype FocusStop = {\n pane: AppState['focusPane'];\n strip?: AppState['focusedStrip'];\n};\n\nfunction focusCycle(state: AppState): FocusStop[] {\n const stops: FocusStop[] = [{ pane: 'tree' }];\n if (state.useStackedDetail && state.detailMode === 'gsr') {\n stops.push({ pane: 'detail', strip: 'goal' });\n stops.push({ pane: 'detail', strip: 'strategy' });\n stops.push({ pane: 'detail', strip: 'roadmap' });\n } else {\n stops.push({ pane: 'detail', ...(state.useStackedDetail ? { strip: 'goal' as const } : {}) });\n }\n stops.push({ pane: 'logs' });\n return stops;\n}\n\nfunction currentFocusIndex(stops: FocusStop[], state: AppState): number {\n const exact = stops.findIndex(\n (s) => s.pane === state.focusPane && (s.strip === undefined || s.strip === state.focusedStrip),\n );\n if (exact !== -1) return exact;\n const fuzzy = stops.findIndex((s) => s.pane === state.focusPane);\n return fuzzy === -1 ? 0 : fuzzy;\n}\n\n// ── handleNavigateKey ─────────────────────────────────────────────────────────\n\nfunction handleNavigateKey(input: string, key: Key, state: AppState, actions: InputActions): void {\n const nodes = actions.getNodes();\n const cursorNode = actions.getCursorNode();\n const session = state.selectedSession;\n\n // k / ↑\n if (key.upArrow || input === 'k') {\n const upScroll = getActiveDetailScroll(state);\n if (upScroll) {\n upScroll.scrollBy(-1);\n } else if (state.focusPane === 'detail') {\n state.detailScroll.scrollBy(-1);\n } else if (state.focusPane === 'logs') {\n state.digestScroll.scrollBy(-1);\n } else {\n state.cursorIndex = Math.max(0, state.cursorIndex - 1);\n state.cursorNodeId = nodes[state.cursorIndex]?.id ?? state.cursorNodeId;\n requestRender();\n }\n return;\n }\n\n // j / ↓\n if (key.downArrow || input === 'j') {\n const downScroll = getActiveDetailScroll(state);\n if (downScroll) {\n downScroll.scrollBy(1);\n } else if (state.focusPane === 'detail') {\n state.detailScroll.scrollBy(1);\n } else if (state.focusPane === 'logs') {\n state.digestScroll.scrollBy(1);\n } else {\n state.cursorIndex = Math.min(nodes.length - 1, state.cursorIndex + 1);\n state.cursorNodeId = nodes[state.cursorIndex]?.id ?? state.cursorNodeId;\n requestRender();\n }\n return;\n }\n\n // u / d — fast scroll (vim-style ½-page) for detail/log strips. Tree focus\n // intentionally ignores these so cursor navigation stays single-step (j/k).\n // Roughly half the visible terminal height, clamped to a sensible band so a\n // tiny terminal still moves and a tall one doesn't leap past the strip.\n if (input === 'u' || input === 'd') {\n const direction = input === 'u' ? -1 : 1;\n const fastStep = Math.max(5, Math.min(20, Math.floor(state.rows / 4))) * direction;\n const fastScroll = getActiveDetailScroll(state);\n if (fastScroll) {\n fastScroll.scrollBy(fastStep);\n return;\n }\n if (state.focusPane === 'detail') {\n state.detailScroll.scrollBy(fastStep);\n return;\n }\n if (state.focusPane === 'logs') {\n state.digestScroll.scrollBy(fastStep);\n return;\n }\n return;\n }\n\n // h / ←\n if (key.leftArrow || input === 'h') {\n if (state.focusPane === 'logs') {\n state.focusPane = 'detail';\n requestRender();\n return;\n }\n if (state.focusPane === 'detail') {\n state.focusPane = 'tree';\n requestRender();\n return;\n }\n const node = nodes[state.cursorIndex];\n if (!node) return;\n if (node.expanded) {\n state.expanded.delete(node.id);\n requestRender();\n } else {\n const parentIdx = findParentIndex(nodes, state.cursorIndex);\n if (parentIdx !== state.cursorIndex) {\n state.cursorIndex = parentIdx;\n state.cursorNodeId = nodes[parentIdx]?.id ?? state.cursorNodeId;\n requestRender();\n }\n }\n return;\n }\n\n // l / →\n if (key.rightArrow || input === 'l') {\n const node = nodes[state.cursorIndex];\n if (!node) return;\n // When stacked detail active and cursor is on an already-expanded session in tree focus,\n // toggle between gsr and cycle-log detail mode instead of moving into child.\n if (\n state.useStackedDetail &&\n state.focusPane === 'tree' &&\n node.type === 'session' &&\n node.expanded\n ) {\n state.detailMode = state.detailMode === 'gsr' ? 'cycle-log' : 'gsr';\n state.cachedStackedLines = null;\n state.stackedCacheKey = '';\n requestRender();\n return;\n }\n if (node.expandable && !node.expanded) {\n state.expanded.add(node.id);\n expandSessionLatestCycle(state, node);\n requestRender();\n } else if (node.expandable && node.expanded) {\n // Move cursor to first child\n if (state.cursorIndex + 1 < nodes.length && nodes[state.cursorIndex + 1]!.depth > node.depth) {\n state.cursorIndex += 1;\n state.cursorNodeId = nodes[state.cursorIndex]?.id ?? state.cursorNodeId;\n requestRender();\n }\n }\n return;\n }\n\n // tab / shift+tab: walk the focus cycle forward / backward\n if (key.tab) {\n const stops = focusCycle(state);\n const idx = currentFocusIndex(stops, state);\n const next = stops[(idx + (key.shift ? -1 : 1) + stops.length) % stops.length]!;\n state.focusPane = next.pane;\n if (next.strip) state.focusedStrip = next.strip;\n requestRender();\n return;\n }\n\n // space: enter leader mode\n if (input === ' ') {\n state.mode = 'leader';\n requestRender();\n return;\n }\n\n // enter: expand / report-detail / open context file / resolution mode\n if (key.return) {\n const node = nodes[state.cursorIndex];\n if (!node) return;\n if (node.type === 'needs-you-virtual') {\n const firstItem = state.aggregateInbox[0];\n if (firstItem) {\n enterResolutionMode(state, firstItem.askId, actions.send, async ({ sessionId, agentId, paneId }) => {\n const res = await actions.send({ type: 'status', sessionId });\n const sess = res.ok ? (res.data?.session as Session | undefined) : undefined;\n if (!sess) { notify(state, 'Session not found'); return; }\n if (paneId && actions.paneExists(paneId)) {\n if (sess.tmuxSessionName) actions.switchToSession(sess.tmuxSessionName);\n if (sess.tmuxWindowId) actions.selectWindow(sess.tmuxWindowId);\n actions.selectPane(paneId);\n return;\n }\n if (sess.tmuxSessionName) actions.switchToSession(sess.tmuxSessionName);\n notify(state, `Pane ${paneId ? paneId : '?'} is gone — agent ${agentId} cannot be taken over.`);\n });\n } else {\n notify(state, 'No pending asks');\n }\n } else if (node.expandable && !node.expanded) {\n state.expanded.add(node.id);\n expandSessionLatestCycle(state, node);\n requestRender();\n } else if (node.type === 'report') {\n state.targetAgentId = node.agentId;\n state.mode = 'report-detail';\n requestRender();\n } else if (node.type === 'context-file') {\n const editor = actions.resolveEditor();\n try {\n actions.openEditorPopup(state.cwd, editor, node.filePath);\n } catch {\n notify(state, 'Failed to open file in editor');\n }\n }\n return;\n }\n\n // m: message orchestrator\n if (input === 'm') {\n if (!state.selectedSessionId) { notify(state, 'No session selected'); return; }\n actions.composeViaPopup({ kind: 'message-orchestrator', sessionId: state.selectedSessionId }, state, actions);\n return;\n }\n\n // w: go to tmux window (or resume orchestrator Claude session if window is dead/completed)\n if (input === 'w') {\n void goToSessionWindow(state, actions);\n return;\n }\n\n // o: open/resume claude session for agent or orchestrator cycle\n if (input === 'o') {\n if (!cursorNode) { notify(state, 'No node selected'); return; }\n let claudeSessionId: string | undefined;\n let resumeEnv: string | undefined;\n let resumeArgs: string | undefined;\n if (cursorNode.type === 'agent' || cursorNode.type === 'report') {\n const agent = actions.getAgentForNode(cursorNode);\n claudeSessionId = agent?.claudeSessionId ?? undefined;\n resumeEnv = agent?.resumeEnv;\n resumeArgs = agent?.resumeArgs;\n } else if (cursorNode.type === 'cycle' && session) {\n const cycle = session.orchestratorCycles.find(c => c.cycle === cursorNode.cycleNumber);\n claudeSessionId = cycle?.claudeSessionId;\n resumeEnv = cycle?.resumeEnv;\n resumeArgs = cycle?.resumeArgs;\n }\n if (!claudeSessionId) { notify(state, 'No Claude session ID available'); return; }\n try {\n actions.openClaudeResumePopup(state.cwd, claudeSessionId, resumeEnv, resumeArgs);\n } catch {\n notify(state, 'Failed to open Claude session');\n }\n return;\n }\n\n // g: edit goal\n if (input === 'g') {\n if (!state.selectedSessionId) { notify(state, 'No session selected'); return; }\n const gp = goalPath(state.cwd, state.selectedSessionId);\n const editor = actions.resolveEditor();\n try {\n actions.openEditorPopup(state.cwd, editor, gp, { w: '80', h: '50%' });\n } catch {\n notify(state, `Failed to open goal in ${editor}`);\n }\n return;\n }\n\n // n: new session\n if (input === 'n') {\n actions.composeViaPopup({ kind: 'new-session' }, state, actions);\n return;\n }\n\n // c: open companion pane\n if (input === 'c') {\n try {\n actions.openCompanionPane(state.cwd);\n } catch {\n notify(state, 'Failed to open companion pane');\n }\n return;\n }\n\n // p: open plan/roadmap\n if (input === 'p') {\n if (!state.selectedSessionId) { notify(state, 'No session selected'); return; }\n const pp = roadmapPath(state.cwd, state.selectedSessionId);\n const editor = actions.resolveEditor();\n try {\n actions.openEditorPopup(state.cwd, editor, pp);\n } catch {\n notify(state, `Failed to open roadmap in ${editor}`);\n }\n return;\n }\n\n // q: quit\n if (input === 'q') {\n actions.cleanup();\n }\n\n // r: re-run agent\n if (input === 'r') {\n const agent = actions.getAgentForNode(cursorNode);\n if (!agent || !state.selectedSessionId) { notify(state, 'Select an agent to re-run'); return; }\n actions.sendAndNotify(\n {\n type: 'spawn',\n sessionId: state.selectedSessionId,\n agentType: agent.agentType,\n name: `${agent.name}-retry`,\n instruction: agent.instruction,\n },\n `Re-spawned ${agent.name}`,\n );\n return;\n }\n\n // R: resume session\n if (input === 'R') {\n if (!state.selectedSessionId) { notify(state, 'No session selected'); return; }\n if (session?.status === 'active' && state.paneAlive) { notify(state, 'Session already active'); return; }\n actions.composeViaPopup({ kind: 'resume', sessionId: state.selectedSessionId }, state, actions);\n return;\n }\n\n // C: continue session\n if (input === 'C') {\n if (!state.selectedSessionId) { notify(state, 'No session selected'); return; }\n if (session?.status !== 'completed') { notify(state, 'Session not completed'); return; }\n actions.composeViaPopup({ kind: 'continue', sessionId: state.selectedSessionId }, state, actions);\n return;\n }\n\n // x: restart agent\n if (input === 'x') {\n const agent = actions.getAgentForNode(cursorNode);\n if (!agent || !state.selectedSessionId) { notify(state, 'Select an agent to restart'); return; }\n actions.sendAndNotify(\n { type: 'restart-agent', sessionId: state.selectedSessionId, agentId: agent.id },\n `Restarted ${agent.id}`,\n );\n return;\n }\n\n // b: rollback to cycle\n if (input === 'b') {\n if (!state.selectedSessionId) { notify(state, 'No session selected'); return; }\n {\n const sessionId = state.selectedSessionId;\n try {\n const text = actions.promptInPopup('Rollback to cycle:');\n if (text?.trim()) {\n const toCycle = parseInt(text.trim(), 10);\n if (isNaN(toCycle) || toCycle < 1) { notify(state, 'Invalid cycle number'); return; }\n actions.sendAndNotify(\n { type: 'rollback', sessionId, cwd: state.cwd, toCycle },\n `Rolled back to cycle ${toCycle} — use [R]esume to respawn`,\n );\n }\n } catch {\n notify(state, 'Failed to open prompt');\n }\n }\n return;\n }\n\n // e: edit context file\n if (input === 'e') {\n if (!cursorNode || cursorNode.type !== 'context-file') return;\n const editor = actions.resolveEditor();\n try {\n actions.openEditorPopup(state.cwd, editor, cursorNode.filePath);\n } catch {\n notify(state, 'Failed to open file in editor');\n }\n return;\n }\n\n // S: edit strategy\n if (input === 'S') {\n if (!state.selectedSessionId) { notify(state, 'No session selected'); return; }\n const sp = strategyPath(state.cwd, state.selectedSessionId);\n const editor = actions.resolveEditor();\n try {\n actions.openEditorPopup(state.cwd, editor, sp);\n } catch {\n notify(state, `Failed to open strategy in ${editor}`);\n }\n return;\n }\n\n // F: toggle cycle flow expanded/collapsed\n if (input === 'F') {\n state.flowExpanded = !state.flowExpanded;\n state.cachedDetailLines = null;\n state.cachedDigestLines = null;\n state.cachedStackedLines = null;\n state.stackedCacheKey = '';\n requestRender();\n return;\n }\n\n // D: toggle DANGEROUS mode for the selected session (auto-accept default for every ask)\n if (input === 'D') {\n const sessionId = state.selectedSessionId;\n const session = state.selectedSession;\n if (!sessionId || !session) { notify(state, 'No session selected'); return; }\n const next = !(session.dangerousMode === true);\n session.dangerousMode = next;\n requestRender();\n void (async () => {\n try {\n const res = await actions.send({ type: 'set-dangerous-mode', sessionId, enabled: next });\n if (!res.ok) {\n if (state.selectedSession === session) session.dangerousMode = !next;\n notify(state, `Dangerous mode toggle failed: ${res.error}`);\n requestRender();\n return;\n }\n const flushed = (res.data?.['flushed'] as number | undefined) ?? 0;\n notify(state, next\n ? (flushed > 0 ? `DANGEROUS mode ON — ${flushed} pending ask(s) auto-resolved` : 'DANGEROUS mode ON')\n : 'DANGEROUS mode OFF');\n } catch (err) {\n if (state.selectedSession === session) session.dangerousMode = !next;\n notify(state, `Dangerous mode toggle failed: ${(err as Error).message}`);\n requestRender();\n }\n })();\n return;\n }\n\n // /: search (vim-like, direct from navigate)\n if (input === '/') {\n state.mode = 'search';\n state.searchText = '';\n requestRender();\n return;\n }\n\n}\n\n// ── handleSearchKey ──────────────────────────────────────────────────────────\n\nfunction handleSearchKey(input: string, key: Key, state: AppState): void {\n if (key.return) {\n // Lock in the current filter\n state.mode = 'navigate';\n requestRender();\n return;\n }\n\n if (key.escape) {\n // Clear filter and exit\n state.searchFilter = null;\n state.searchText = '';\n state.mode = 'navigate';\n requestRender();\n return;\n }\n\n if (key.backspace) {\n state.searchText = state.searchText.slice(0, -1);\n state.searchFilter = state.searchText || null;\n requestRender();\n return;\n }\n\n // Ignore control keys\n if (key.ctrl || key.meta || !input || input.length !== 1) return;\n\n state.searchText += input;\n state.searchFilter = state.searchText;\n requestRender();\n}\n\n// ── Main dispatch ─────────────────────────────────────────────────────────────\n\nexport function handleKeypress(input: string, key: Key, state: AppState, actions: InputActions): void {\n // Resolution mode intercepts all keys (before mode checks — esc always exits)\n if (state.resolutionActive) {\n handleResolutionKey(input, key, state, actions);\n return;\n }\n if (state.mode === 'search') {\n handleSearchKey(input, key, state);\n } else if (state.mode === 'leader' || state.mode === 'copy-menu' || state.mode === 'open-menu' || state.mode === 'agent-menu' || state.mode === 'session-menu' || state.mode === 'go-menu' || state.mode === 'companion-menu' || state.mode === 'help' || state.mode === 'companion-overlay' || state.mode === 'companion-debug') {\n handleLeaderKey(input, key, state, actions);\n } else if (state.mode === 'report-detail') {\n handleReportDetailKey(input, key, state, actions);\n } else {\n handleNavigateKey(input, key, state, actions);\n }\n}\n","import { execFile } from 'node:child_process';\nimport { promisify } from 'node:util';\nimport { existsSync, readFileSync, mkdirSync, symlinkSync, rmSync, writeFileSync } from 'node:fs';\nimport { homedir } from 'node:os';\nimport { join } from 'node:path';\nimport type { Session } from './types.js';\nimport { sessionDir, statePath, historySessionDir } from './paths.js';\n\nfunction sanitizeName(name: string): string {\n return name.replace(/[^a-zA-Z0-9-_]/g, '-').replace(/-+/g, '-').replace(/^-|-$/g, '').slice(0, 40);\n}\n\nfunction buildOutputPath(label: string, dir: string): string {\n const date = new Date().toISOString().slice(0, 10);\n mkdirSync(dir, { recursive: true });\n\n const base = `sisyphus-${label}-${date}`;\n let candidate = join(dir, `${base}.zip`);\n let counter = 1;\n while (existsSync(candidate)) {\n counter++;\n candidate = join(dir, `${base}-${counter}.zip`);\n }\n return candidate;\n}\n\nfunction generateGuide(): string {\n return `# Sisyphus Session Export\n\n## Quick Orientation\n\nStart with \\`session/state.json\\` for the full session state, or \\`history/session.json\\` for a compact summary with metrics.\n\n## session/\n\nProject-local session data — the orchestrator's working directory.\n\n### Top-level files\n- **state.json** — Complete session state: id, task, status, timing, and the full \\`agents[]\\` array (each agent has id, type, instruction, status, reports, Claude session ID, and resume args)\n- **goal.md** — The task description; updated if the goal evolves across phases\n- **initial-prompt.md** — Verbatim user input that started the session\n- **roadmap.md** — Orchestrator's working memory: current stage, exit criteria, active context files, next steps\n- **strategy.md** — Work breakdown: completed stages, current stage decomposition (concerns/phases), and what's ahead\n- **digest.json** — 4-field snapshot: \\`recentWork\\`, \\`unusualEvents\\`, \\`currentActivity\\`, \\`whatsNext\\`\n\n### Subdirectories\n\n**context/** — Research artifacts produced by agents and consumed by downstream agents\n- \\`explore-*.md\\` — Codebase exploration findings (key files, architecture notes)\n- \\`requirements*.md/json\\` — Feature requirements (structured + human-readable)\n- \\`design*.md/json\\` — Architecture specs, decision records, diagrams\n- \\`{agent-id}/plan*.md\\` — Implementation plans (tasks, files to touch, dependencies) — per plan-lead subdirectory\n- \\`e2e-recipe.md\\` — End-to-end validation steps\n- \\`review-*.md\\` — Code review findings (severity-ranked)\n- \\`completion-summary.md\\` — Final handoff document\n\n**logs/** — One \\`cycle-NNN.md\\` per orchestrator cycle. Each logs what happened, agents spawned, user decisions, and key findings.\n\n**prompts/** — Full agent configs, one set per agent:\n- \\`agent-NNN-system.md\\` — System prompt (instructions, tools, output format)\n- \\`agent-NNN-run.sh\\` — Executable bash script to resume the agent (contains env, CLI args, instruction)\n- \\`agent-NNN-plugin/\\` — Plugin directory (hooks, sub-agent configs)\n\n**reports/** — Agent deliverables:\n- \\`agent-NNN-final.md\\` — Final report (findings, implementation summary, or review results)\n- \\`agent-NNN-00N.md\\` — Interim progress reports (optional)\n\n**snapshots/** — Point-in-time checkpoints (\\`snapshots/cycle-N/\\`). Each contains state.json, roadmap.md, strategy.md, and logs/ as they were at that cycle boundary. Used for rollback.\n\n**.tui/** — Lightweight TUI render cache (cycle summaries for display). Regenerable; not primary data.\n\n## history/\n\nGlobal telemetry from the daemon — timing, events, and aggregate metrics.\n\n- **events.jsonl** — Newline-delimited JSON event stream. Each line: \\`{ ts, event, sessionId, data }\\`. Events include session-start, agent-spawned, agent-completed, cycle-boundary, signals-snapshot, session-end, etc. Complete audit trail.\n- **session.json** — Summary: id, name, task, status, timing (activeMs, wallClockMs, efficiency), agent/cycle counts, crash/rollback counts, completion report, and a compact agents array.\n`;\n}\n\nconst execFileAsync = promisify(execFile);\n\nexport async function exportSessionToZip(\n sessionId: string,\n cwd: string,\n options?: { reveal?: boolean; outputDir?: string }\n): Promise<string> {\n const reveal = options?.reveal ?? true;\n const sessDir = sessionDir(cwd, sessionId);\n const histDir = historySessionDir(sessionId);\n const sessExists = existsSync(sessDir);\n const histExists = existsSync(histDir);\n\n if (!sessExists && !histExists) {\n throw new Error(`No data found for session ${sessionId}`);\n }\n\n let label = sessionId.slice(0, 8);\n const stPath = statePath(cwd, sessionId);\n if (existsSync(stPath)) {\n try {\n const state = JSON.parse(readFileSync(stPath, 'utf-8')) as Session;\n if (state.name) {\n label = sanitizeName(state.name);\n }\n } catch { /* use short ID */ }\n }\n\n const dir = options?.outputDir ?? join(homedir(), 'Downloads');\n const outputPath = buildOutputPath(label, dir);\n const tmpDir = `/tmp/sisyphus-export-${sessionId.slice(0, 8)}-${Date.now()}`;\n\n try {\n mkdirSync(tmpDir, { recursive: true });\n\n writeFileSync(join(tmpDir, 'CLAUDE.md'), generateGuide(), 'utf-8');\n\n if (sessExists) {\n symlinkSync(sessDir, join(tmpDir, 'session'));\n }\n if (histExists) {\n symlinkSync(histDir, join(tmpDir, 'history'));\n }\n\n const parts = ['CLAUDE.md', sessExists ? 'session/' : '', histExists ? 'history/' : ''].filter(Boolean) as string[];\n await execFileAsync('zip', ['-rq', outputPath, ...parts], { cwd: tmpDir });\n } finally {\n rmSync(tmpDir, { recursive: true, force: true });\n }\n\n if (reveal) {\n try {\n await execFileAsync('open', ['-R', outputPath]);\n } catch { /* non-fatal if Finder fails */ }\n }\n\n return outputPath;\n}\n","import { execFileSync, spawnSync } from 'node:child_process';\nimport { detectPlatform, hasCommand } from './platform.js';\n\nexport interface ClipboardTool {\n /** Command name as invoked on PATH (e.g. \"pbcopy\", \"wl-copy\") */\n cmd: string;\n /** Args passed to the command */\n args: readonly string[];\n}\n\nexport interface ClipboardCapability {\n copy: ClipboardTool | null;\n paste: ClipboardTool | null;\n /** If null, clipboard is fully unavailable; this hint tells the user how to fix it. */\n hint: string | null;\n}\n\n/**\n * Probe the system for a clipboard backend. Order matters: prefer native\n * platform tools, fall back to Wayland → X11. On WSL we use Windows' clip.exe\n * for copy and powershell.exe Get-Clipboard for paste (both work without WSLg).\n */\nexport function detectClipboard(): ClipboardCapability {\n const platform = detectPlatform();\n\n if (platform === 'darwin') {\n return {\n copy: { cmd: 'pbcopy', args: [] },\n paste: { cmd: 'pbpaste', args: [] },\n hint: null,\n };\n }\n\n if (platform === 'wsl') {\n const copy = hasCommand('clip.exe') ? { cmd: 'clip.exe', args: [] } : null;\n const paste = hasCommand('powershell.exe')\n ? { cmd: 'powershell.exe', args: ['-NoProfile', '-Command', 'Get-Clipboard'] }\n : null;\n return {\n copy,\n paste,\n hint: copy && paste\n ? null\n : 'WSL clipboard needs Windows interop. Ensure /mnt/c/Windows/System32 is on PATH (it is by default).',\n };\n }\n\n if (platform === 'linux') {\n // Wayland first — modern desktops prefer it.\n if (process.env['WAYLAND_DISPLAY'] && hasCommand('wl-copy') && hasCommand('wl-paste')) {\n return {\n copy: { cmd: 'wl-copy', args: [] },\n paste: { cmd: 'wl-paste', args: ['--no-newline'] },\n hint: null,\n };\n }\n // X11 / generic.\n if (hasCommand('xclip')) {\n return {\n copy: { cmd: 'xclip', args: ['-selection', 'clipboard'] },\n paste: { cmd: 'xclip', args: ['-selection', 'clipboard', '-o'] },\n hint: null,\n };\n }\n if (hasCommand('xsel')) {\n return {\n copy: { cmd: 'xsel', args: ['--clipboard', '--input'] },\n paste: { cmd: 'xsel', args: ['--clipboard', '--output'] },\n hint: null,\n };\n }\n return {\n copy: null,\n paste: null,\n hint: 'Install a clipboard tool: `sudo apt install xclip` (or wl-clipboard for Wayland).',\n };\n }\n\n return {\n copy: null,\n paste: null,\n hint: 'Clipboard not supported on this platform.',\n };\n}\n\nlet cached: ClipboardCapability | undefined;\nfunction cap(): ClipboardCapability {\n if (!cached) cached = detectClipboard();\n return cached;\n}\n\nexport interface ClipboardError {\n /** Reason copy/paste failed — show to user as a notify message. */\n reason: string;\n}\n\nexport function copyToClipboard(text: string): ClipboardError | null {\n const c = cap();\n if (!c.copy) {\n // Invariant from detectClipboard: when copy is null, hint is always set.\n return { reason: c.hint === null ? 'No clipboard backend available' : c.hint };\n }\n try {\n execFileSync(c.copy.cmd, c.copy.args, { input: text, stdio: ['pipe', 'ignore', 'pipe'] });\n return null;\n } catch (err) {\n const msg = err instanceof Error ? err.message.split('\\n')[0] : String(err);\n return { reason: `${c.copy.cmd} failed: ${msg}` };\n }\n}\n\nexport function pasteFromClipboard(): { text: string } | ClipboardError {\n const c = cap();\n if (!c.paste) {\n return { reason: c.hint === null ? 'No clipboard backend available' : c.hint };\n }\n const result = spawnSync(c.paste.cmd, c.paste.args, { encoding: 'utf-8', stdio: ['ignore', 'pipe', 'pipe'] });\n if (result.status !== 0) {\n const stderr = typeof result.stderr === 'string' ? result.stderr.trim() : '';\n if (stderr.length > 0) {\n return { reason: `${c.paste.cmd}: ${stderr.split('\\n')[0]}` };\n }\n return { reason: `${c.paste.cmd} exited ${result.status}` };\n }\n const stdout = typeof result.stdout === 'string' ? result.stdout : '';\n // powershell.exe Get-Clipboard appends \\r\\n; trim trailing whitespace consistently.\n return { text: stdout.replace(/\\s+$/, '') };\n}\n","import { join } from 'node:path';\nimport { messageSourceLabel } from './format.js';\nimport type {\n TreeNode,\n SectionTreeNode,\n NeedsYouVirtualTreeNode,\n SessionTreeNode,\n CycleTreeNode,\n AgentTreeNode,\n ReportTreeNode,\n MessagesTreeNode,\n MessageTreeNode,\n ContextTreeNode,\n ContextFileTreeNode,\n SectionKey,\n} from '../types/tree.js';\nimport type { Session } from '../../shared/types.js';\nimport type { SessionSummary } from '../state.js';\nimport type { AggregateInboxItem } from '../../shared/inbox-types.js';\nimport { contextDir } from '../../shared/paths.js';\n\n/** Sort priority: active+open=0, active+closed=1, paused+open=2, paused+closed=3, completed=4 */\nfunction sessionSortKey(s: SessionSummary): number {\n if (s.status === 'completed') return 4;\n // Use cached windowAlive from polling hook (avoids execSync in render path)\n const open = s.windowAlive ?? false;\n if (s.status === 'active') return open ? 0 : 1;\n // paused — goes in Running section (not Done)\n return open ? 2 : 3;\n}\n\nexport function buildTree(\n sessions: SessionSummary[],\n selectedSession: Session | null,\n expanded: Set<string>,\n cwd: string,\n polledContextFiles: string[] = [],\n aggregateInbox: AggregateInboxItem[] = [],\n): TreeNode[] {\n const nodes: TreeNode[] = [];\n\n // Build per-session inbox index\n const inboxBySession = new Map<string, AggregateInboxItem[]>();\n for (const item of aggregateInbox) {\n const arr = inboxBySession.get(item.sessionId) ?? [];\n arr.push(item);\n inboxBySession.set(item.sessionId, arr);\n }\n\n // Bucket sessions\n const needsYou: SessionSummary[] = [];\n const running: SessionSummary[] = [];\n const done: SessionSummary[] = [];\n for (const s of sessions) {\n if (inboxBySession.has(s.id)) needsYou.push(s);\n else if (s.status === 'completed') done.push(s);\n else running.push(s); // active + paused both land here\n }\n\n // Sort within each bucket\n needsYou.sort((a, b) => {\n const aItems = inboxBySession.get(a.id)!;\n const bItems = inboxBySession.get(b.id)!;\n const aOldest = Math.min(...aItems.map(i => Date.parse(i.blockedSince)));\n const bOldest = Math.min(...bItems.map(i => Date.parse(i.blockedSince)));\n return aOldest - bOldest;\n });\n running.sort((a, b) => {\n const k = sessionSortKey(a) - sessionSortKey(b);\n if (k !== 0) return k;\n return new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime();\n });\n // SessionSummary has no completedAt — sort done by createdAt descending\n done.sort((a, b) => Date.parse(b.createdAt) - Date.parse(a.createdAt));\n\n // Emit helpers\n function sectionExpanded(key: SectionKey): boolean {\n return expanded.has(`section:${key}`);\n }\n\n function emitSection(key: SectionKey, count: number): void {\n const exp = sectionExpanded(key);\n nodes.push({\n id: `section:${key}`,\n type: 'section',\n depth: 0,\n section: key,\n count,\n expandable: true,\n expanded: exp,\n sessionId: '',\n prefix: '',\n } satisfies SectionTreeNode);\n }\n\n function emitSessionChildren(s: SessionSummary): void {\n if (!selectedSession || selectedSession.id !== s.id) return;\n\n const cycles = [...selectedSession.orchestratorCycles].reverse();\n const allSpawnedIds = new Set(\n selectedSession.orchestratorCycles.flatMap((c) => c.agentsSpawned),\n );\n\n for (const cycle of cycles) {\n const cycleNodeId = `cycle:${s.id}:${cycle.cycle}`;\n const cycleExpanded = expanded.has(cycleNodeId);\n\n const cycleAgents = selectedSession.agents.filter((a) =>\n cycle.agentsSpawned.includes(a.id),\n );\n const isLatest = cycle === cycles[0];\n const unassigned = isLatest\n ? selectedSession.agents.filter((a) => !allSpawnedIds.has(a.id))\n : [];\n const allCycleAgents = [...cycleAgents, ...unassigned];\n\n nodes.push({\n id: cycleNodeId,\n type: 'cycle',\n depth: 2,\n expandable: allCycleAgents.length > 0,\n expanded: cycleExpanded,\n sessionId: s.id,\n cycleNumber: cycle.cycle,\n timestamp: cycle.timestamp,\n completedAt: cycle.completedAt,\n activeMs: cycle.activeMs,\n agentCount: allCycleAgents.length,\n mode: cycle.mode,\n } satisfies CycleTreeNode);\n\n if (!cycleExpanded) continue;\n\n for (const agent of allCycleAgents) {\n const agentNodeId = `agent:${s.id}:${agent.id}`;\n const hasReports = agent.reports.length > 0;\n const agentExpanded = expanded.has(agentNodeId);\n\n nodes.push({\n id: agentNodeId,\n type: 'agent',\n depth: 3,\n expandable: hasReports,\n expanded: agentExpanded && hasReports,\n sessionId: s.id,\n agentId: agent.id,\n name: agent.name,\n agentType: agent.agentType,\n status: agent.status,\n spawnedAt: agent.spawnedAt,\n completedAt: agent.completedAt,\n activeMs: agent.activeMs,\n reportCount: agent.reports.length,\n orphaned: agent.orphaned ?? false,\n } satisfies AgentTreeNode);\n\n if (!agentExpanded || !hasReports) continue;\n\n for (let ri = 0; ri < agent.reports.length; ri++) {\n const report = agent.reports[ri]!;\n nodes.push({\n id: `report:${s.id}:${agent.id}:${ri}`,\n type: 'report',\n depth: 4,\n expandable: false,\n expanded: false,\n sessionId: s.id,\n reportIndex: ri,\n reportType: report.type,\n timestamp: report.timestamp,\n agentId: agent.id,\n } satisfies ReportTreeNode);\n }\n }\n }\n\n // Messages group\n const messages = selectedSession.messages ?? [];\n if (messages.length > 0) {\n const msgsNodeId = `messages:${s.id}`;\n const msgsExpanded = expanded.has(msgsNodeId);\n\n nodes.push({\n id: msgsNodeId,\n type: 'messages',\n depth: 2,\n expandable: true,\n expanded: msgsExpanded,\n sessionId: s.id,\n count: messages.length,\n } satisfies MessagesTreeNode);\n\n if (msgsExpanded) {\n for (const msg of messages) {\n const agentId = msg.source.type === 'agent' ? msg.source.agentId : undefined;\n const sourceLabel = messageSourceLabel(msg.source.type, agentId);\n\n nodes.push({\n id: `message:${s.id}:${msg.id}`,\n type: 'message',\n depth: 3,\n expandable: false,\n expanded: false,\n sessionId: s.id,\n messageId: msg.id,\n source: sourceLabel,\n summary: msg.summary || msg.content,\n timestamp: msg.timestamp,\n } satisfies MessageTreeNode);\n }\n }\n }\n\n // Context group\n const isSelected = selectedSession?.id === s.id;\n const contextFiles = isSelected ? polledContextFiles : [];\n\n const ctxNodeId = `context:${s.id}`;\n const ctxExpanded = expanded.has(ctxNodeId);\n\n nodes.push({\n id: ctxNodeId,\n type: 'context',\n depth: 2,\n expandable: contextFiles.length > 0,\n expanded: ctxExpanded && contextFiles.length > 0,\n sessionId: s.id,\n fileCount: contextFiles.length,\n } satisfies ContextTreeNode);\n\n if (ctxExpanded && contextFiles.length > 0) {\n for (const filename of contextFiles) {\n nodes.push({\n id: `context-file:${s.id}:${filename}`,\n type: 'context-file',\n depth: 3,\n expandable: false,\n expanded: false,\n sessionId: s.id,\n label: filename,\n filePath: join(contextDir(cwd, s.id), filename),\n } satisfies ContextFileTreeNode);\n }\n }\n }\n\n function emitSessionRow(s: SessionSummary, askCount: number): void {\n const sessionNodeId = `session:${s.id}`;\n const isSelected = selectedSession?.id === s.id;\n const isExpanded = expanded.has(sessionNodeId);\n\n nodes.push({\n id: sessionNodeId,\n type: 'session',\n depth: 1,\n expandable: true,\n expanded: isExpanded && isSelected,\n sessionId: s.id,\n name: s.name,\n task: s.task,\n status: s.status,\n cycleCount: isSelected ? (selectedSession?.orchestratorCycles.length ?? 0) : 0,\n agentCount: s.agentCount,\n runningAgentCount: s.runningAgentCount,\n createdAt: s.createdAt,\n completedAt: isSelected ? selectedSession?.completedAt : undefined,\n activeMs: isSelected ? (selectedSession?.activeMs ?? s.activeMs) : s.activeMs,\n askCount: askCount > 0 ? askCount : undefined,\n orphaned: s.orphaned ?? false,\n } satisfies SessionTreeNode);\n\n if (isExpanded && isSelected) {\n emitSessionChildren(s);\n }\n }\n\n // Emit Needs You section\n emitSection('needs-you', needsYou.length);\n if (sectionExpanded('needs-you')) {\n nodes.push({\n id: 'needs-you-virtual',\n type: 'needs-you-virtual',\n depth: 1,\n expandable: false,\n expanded: false,\n sessionId: '',\n pendingCount: aggregateInbox.length,\n } satisfies NeedsYouVirtualTreeNode);\n for (const s of needsYou) {\n emitSessionRow(s, inboxBySession.get(s.id)?.length ?? 0);\n }\n }\n\n // Emit Running section\n emitSection('running', running.length);\n if (sectionExpanded('running')) {\n for (const s of running) {\n emitSessionRow(s, 0);\n }\n }\n\n // Emit Done section\n emitSection('done', done.length);\n if (sectionExpanded('done')) {\n for (const s of done) {\n emitSessionRow(s, 0);\n }\n }\n\n return nodes;\n}\n\n/** Find the parent node index for a given node index */\nexport function findParentIndex(nodes: TreeNode[], index: number): number {\n const node = nodes[index];\n if (!node || node.depth === 0) return index;\n const targetDepth = node.depth - 1;\n for (let i = index - 1; i >= 0; i--) {\n if (nodes[i]!.depth === targetDepth) return i;\n if (nodes[i]!.depth < targetDepth) return i;\n }\n return 0;\n}\n","import stringWidth from 'string-width';\n\nexport { formatDuration, statusColor } from '../../shared/format.js';\n\nexport function formatTimeAgo(iso: string): string {\n const diff = Date.now() - new Date(iso).getTime();\n const minutes = Math.floor(diff / 60000);\n const hours = Math.floor(minutes / 60);\n if (hours > 0) return `${hours}h ago`;\n if (minutes > 0) return `${minutes}m ago`;\n return 'just now';\n}\n\nexport function formatTime(iso: string): string {\n const d = new Date(iso);\n return `${d.getHours().toString().padStart(2, '0')}:${d.getMinutes().toString().padStart(2, '0')}`;\n}\n\nexport function truncate(text: string, max: number): string {\n // Collapse newlines and normalize wide emoji (see cleanMarkdown for rationale)\n const clean = text.replace(/\\n/g, ' ').replace(/✅/g, '✓').replace(/❌/g, '✗').replace(/\\p{Emoji_Presentation}/gu, '');\n if (max < 4) return clean.slice(0, max);\n const w = stringWidth(clean);\n if (w <= max) return clean;\n // Trim from the end until we fit, respecting display width\n let result = clean;\n while (stringWidth(result) > max - 1 && result.length > 0) {\n // Try to break at a word boundary\n const cut = result.lastIndexOf(' ', result.length - 2);\n if (cut > max * 0.4) {\n result = result.slice(0, cut);\n } else {\n result = result.slice(0, result.length - 1);\n }\n }\n return result + '…';\n}\n\n/** Strip markdown syntax to plain text */\nexport function stripMarkdown(text: string): string {\n return text\n .replace(/^#{1,6}\\s+/gm, '')\n .replace(/\\*\\*(.+?)\\*\\*/g, '$1')\n .replace(/\\*(.+?)\\*/g, '$1')\n .replace(/~~(.+?)~~/g, '$1')\n .replace(/`{1,3}[^`]*`{1,3}/g, '')\n .replace(/^[-*+]\\s+/gm, '')\n .replace(/^\\d+[.)]\\s+/gm, '')\n .replace(/\\[(.+?)\\]\\(.+?\\)/g, '$1')\n .replace(/^>\\s+/gm, '')\n .replace(/---+/g, '')\n .replace(/\\n+/g, ' ')\n .replace(/\\s+/g, ' ')\n .trim();\n}\n\n/**\n * Extract the first meaningful sentence from markdown-heavy text.\n * Much better than blind truncation — finds actual content.\n */\nexport function extractFirstSentence(text: string, maxLen: number): string {\n const lines = text.split('\\n');\n for (const line of lines) {\n const trimmed = line.trim();\n if (!trimmed) continue;\n if (trimmed.startsWith('#')) continue;\n if (trimmed.startsWith('---')) continue;\n if (trimmed.startsWith('```')) continue;\n if (trimmed.startsWith('|')) continue;\n if (trimmed.length < 5) continue;\n\n const cleaned = stripMarkdown(trimmed);\n if (cleaned.length < 5) continue;\n\n // Try to end at a sentence boundary\n const periodIdx = cleaned.indexOf('. ');\n if (periodIdx > 10 && periodIdx < maxLen) {\n return cleaned.slice(0, periodIdx + 1);\n }\n return truncate(cleaned, maxLen);\n }\n const fallback = stripMarkdown(text);\n return truncate(fallback, maxLen);\n}\n\nexport function durationColor(startOrMs: string | number, endIso?: string | null): string {\n let totalMs: number;\n if (typeof startOrMs === 'number') {\n totalMs = startOrMs;\n } else {\n const start = new Date(startOrMs).getTime();\n const end = endIso ? new Date(endIso).getTime() : Date.now();\n totalMs = end - start;\n }\n if (totalMs < 10 * 60 * 1000) return '';\n if (totalMs < 30 * 60 * 1000) return 'yellow';\n return 'red';\n}\n\nexport function statusIndicator(status: string): string {\n switch (status) {\n case 'active':\n return '▶';\n case 'completed':\n return '✓';\n case 'paused':\n return '⏸';\n default:\n return '·';\n }\n}\n\nexport function agentStatusIcon(status: string): string {\n switch (status) {\n case 'running':\n return '▶';\n case 'completed':\n return '✓';\n case 'killed':\n return '✕';\n case 'crashed':\n return '!';\n case 'lost':\n return '?';\n default:\n return '·';\n }\n}\n\nexport function agentTypeColor(agentType: string | undefined): string | undefined {\n if (!agentType) return undefined;\n const t = agentType.toLowerCase();\n if (t.includes('research')) return 'blue';\n if (t.includes('implement') || t.includes('code')) return 'green';\n if (t.includes('review') || t.includes('test')) return 'magenta';\n if (t.includes('plan')) return 'yellow';\n return undefined;\n}\n\nexport function divider(width: number, char: string = '─'): string {\n return char.repeat(Math.max(0, width));\n}\n\n/** Strip YAML frontmatter (--- ... ---) from markdown content */\nexport function stripFrontmatter(content: string): string {\n if (!content.startsWith('---')) return content;\n const end = content.indexOf('\\n---', 3);\n if (end === -1) return content;\n return content.slice(end + 4).trimStart();\n}\n\n/** Clean inline markdown syntax for terminal display */\nexport function cleanMarkdown(line: string): string {\n return line\n .replace(/\\*\\*(.+?)\\*\\*/g, '$1')\n .replace(/\\*(.+?)\\*/g, '$1')\n .replace(/~~(.+?)~~/g, '$1')\n .replace(/`(.+?)`/g, '$1')\n .replace(/\\[(.+?)\\]\\(.+?\\)/g, '$1')\n // Normalize wide emoji → single-width alternatives.\n // Ink's @alcalzone/ansi-tokenize treats emoji as width=1, but terminals\n // render them as width=2. This mismatch causes lines to overflow by 1\n // column, wrapping the right border to the next row (phantom blank lines).\n .replace(/✅/g, '✓')\n .replace(/❌/g, '✗')\n .replace(/\\p{Emoji_Presentation}/gu, '');\n}\n\n// Shared line types for scrollable panels\n\nexport type Seg = {\n text: string;\n color?: string;\n bold?: boolean;\n dim?: boolean;\n italic?: boolean;\n inverse?: boolean;\n strikethrough?: boolean;\n /** ANSI 38;2;R;G;B foreground tint (e.g. '38;2;226;217;198'). Wins over `color` when set. */\n fg?: string;\n /** ANSI 48;2;R;G;B background tint (e.g. '48;2;40;35;20') */\n bg?: string;\n};\n\nexport type DetailLine = Seg[];\n\nexport function seg(text: string, opts?: Partial<Omit<Seg, 'text'>>): Seg {\n return { text, ...opts };\n}\n\n/** Create a single-segment DetailLine */\nexport function singleLine(text: string, opts?: Partial<Omit<Seg, 'text'>>): DetailLine {\n return [seg(text, opts)];\n}\n\nexport function messageSourceLabel(source: string, agentId?: string): string {\n if (source === 'user') return 'You';\n if (source === 'agent') {\n if (!agentId) throw new Error('agentId required when source is agent');\n return agentId;\n }\n return 'system';\n}\n\nexport function messageSourceColor(source: string): string {\n if (source === 'user') return 'yellow';\n if (source === 'agent') return 'cyan';\n return 'gray';\n}\n\nexport function reportBadge(type: string): { label: string; color: string } {\n return type === 'final'\n ? { label: 'FINAL', color: 'cyan' }\n : { label: 'UPDATE', color: 'yellow' };\n}\n\nexport function agentDisplayName(agent: { name: string; id: string; agentType: string }): string {\n return agent.name !== agent.id ? agent.name : agent.agentType;\n}\n\nexport function abbreviateMode(mode: string | undefined | null): string {\n if (!mode) return '';\n if (mode === 'implementation') return 'impl';\n if (mode === 'planning') return 'plan';\n if (mode === 'discovery') return 'disc';\n if (mode === 'validation') return 'valid';\n return mode;\n}\n\nexport function ansiBold(text: string): string {\n return `\\x1b[1m${text}\\x1b[0m`;\n}\n\nexport function ansiDim(text: string): string {\n return `\\x1b[2m${text}\\x1b[0m`;\n}\n\nexport function ansiColor(text: string, color: string, bold = false): string {\n const COLOR_MAP: Record<string, number> = { black: 30, red: 31, green: 32, yellow: 33, blue: 34, magenta: 35, cyan: 36, white: 37, gray: 90 };\n const codes: number[] = [];\n if (bold) codes.push(1);\n const sgr = COLOR_MAP[color];\n if (sgr !== undefined) codes.push(sgr);\n if (codes.length === 0) return text;\n return `\\x1b[${codes.join(';')}m${text}\\x1b[0m`;\n}\n\nexport function modeColor(mode?: string): string {\n if (mode === 'planning') return 'blue';\n if (mode === 'implementation') return 'green';\n if (mode === 'discovery') return 'yellow';\n if (mode === 'validation') return 'magenta';\n return 'cyan';\n}\n\nexport function mergeStatusDisplay(status: string): { icon: string; label: string; color: string } | null {\n switch (status) {\n case 'merged': return { icon: '⊕', label: 'merged', color: 'green' };\n case 'pending': return { icon: '◌', label: 'pending', color: 'yellow' };\n case 'no-changes': return { icon: '∅', label: 'no changes', color: 'gray' };\n case 'conflict': return { icon: '⚠', label: 'conflict', color: 'red' };\n default: return null;\n }\n}\n\nexport function wrapText(text: string, width: number): string[] {\n const cleaned = cleanMarkdown(text);\n if (width <= 0) return cleaned.split('\\n');\n const result: string[] = [];\n for (const rawLine of cleaned.split('\\n')) {\n if (stringWidth(rawLine) <= width) {\n result.push(rawLine);\n continue;\n }\n\n // Single-pass: walk characters tracking cumulative display width\n let lineStart = 0;\n let lastSpace = -1;\n let displayWidth = 0;\n\n for (let i = 0; i < rawLine.length; i++) {\n const charWidth = stringWidth(rawLine[i]!);\n displayWidth += charWidth;\n\n if (rawLine[i] === ' ') lastSpace = i;\n\n if (displayWidth > width) {\n let breakAt: number;\n if (lastSpace > lineStart) {\n // Break at last space that fits\n breakAt = lastSpace;\n result.push(rawLine.slice(lineStart, breakAt));\n // Skip past the space and any leading spaces\n lineStart = breakAt + 1;\n while (lineStart < rawLine.length && rawLine[lineStart] === ' ') lineStart++;\n } else {\n // No space — hard break at previous char\n breakAt = Math.max(lineStart + 1, i);\n result.push(rawLine.slice(lineStart, breakAt));\n lineStart = breakAt;\n }\n\n // Recalculate display width for the carried-over portion\n displayWidth = stringWidth(rawLine.slice(lineStart, i + 1));\n lastSpace = -1;\n }\n }\n\n if (lineStart < rawLine.length) {\n result.push(rawLine.slice(lineStart));\n }\n }\n return result;\n}\n","/** Format milliseconds or ISO date range to human-readable duration */\nexport function formatDuration(startOrMs: string | number, endIso?: string | null): string {\n let totalMs: number;\n if (typeof startOrMs === 'number') {\n totalMs = startOrMs;\n } else {\n const start = new Date(startOrMs).getTime();\n const end = endIso ? new Date(endIso).getTime() : Date.now();\n totalMs = end - start;\n }\n const totalSeconds = Math.floor(totalMs / 1000);\n if (totalSeconds < 0) return '0s';\n const hours = Math.floor(totalSeconds / 3600);\n const minutes = Math.floor((totalSeconds % 3600) / 60);\n const seconds = totalSeconds % 60;\n if (hours > 0) return `${hours}h${minutes}m`;\n if (minutes > 0) return `${minutes}m${seconds}s`;\n return `${seconds}s`;\n}\n\n/** Map session/agent status to a color name */\nexport function statusColor(status: string): string {\n switch (status) {\n case 'active':\n case 'running':\n return 'green';\n case 'completed':\n return 'cyan';\n case 'paused':\n return 'yellow';\n case 'killed':\n case 'crashed':\n return 'red';\n case 'lost':\n return 'gray';\n default:\n return 'white';\n }\n}\n","import { drawBorder, writeClipped, type FrameBuffer } from '../render.js';\nimport { ansiColor, ansiDim, ansiBold } from '../lib/format.js';\nimport type { MenuDef } from '../../shared/keymap.js';\nimport type { CompanionState, AchievementDef, Mood } from '../../shared/companion-types.js';\nimport { getMoodFace } from '../../shared/companion-render.js';\nimport { computeLevelProgress } from '../../daemon/companion.js';\nimport { ACHIEVEMENTS } from '../../shared/companion-types.js';\nimport {\n createBadgeGallery,\n renderBadgeCard,\n galleryNext,\n galleryPrev,\n CARD_WIDTH,\n type BadgeGallery,\n} from '../../shared/companion-badges.js';\n\n// ─── Constants ────────────────────────────────────────────────────────────────\n\nconst HELP_WIDTH = 62;\nconst COMPANION_WIDTH = 52;\nconst DEBUG_WIDTH = 50;\n\n// ─── Helpers ──────────────────────────────────────────────────────────────────\n\nfunction helpRow(left: string, right: string, innerWidth: number): string {\n const col = Math.floor(innerWidth / 2);\n return (left.padEnd(col) + right).padEnd(innerWidth);\n}\n\n// ─── Overlays ─────────────────────────────────────────────────────────────────\n\nexport function renderSubmenuOverlay(\n buf: FrameBuffer,\n rows: number,\n cols: number,\n menu: MenuDef,\n accentColor: string,\n): void {\n const visibleItems = menu.items.filter(i => !i.hidden && i.action.type !== 'tmux');\n const title = menu.title.trim();\n\n // Width: max of title+padding, each item line, and the esc footer\n const maxLabelLen = Math.max(\n title.length + 2,\n ...visibleItems.map(i => i.label.trim().length + 5), // ' k trimmed-label'\n 13, // ' esc cancel'\n );\n const innerWidth = Math.min(maxLabelLen, 32);\n const totalWidth = innerWidth + 2;\n\n // Height: title + blank + items (clamped) + esc\n const contentCount = visibleItems.length;\n const totalHeight = contentCount + 4; // title + blank + items + esc + 2 borders = +4 inner rows\n const clampedHeight = Math.min(totalHeight, rows - 2);\n\n const x = cols - totalWidth - 1;\n const y = rows - clampedHeight - 2;\n\n drawBorder(buf, x, y, totalWidth, clampedHeight, accentColor);\n\n let row = 0;\n writeClipped(buf, x + 1, y + 1 + row, ansiColor(` ${title}`.padEnd(innerWidth), accentColor, true), innerWidth);\n row++;\n writeClipped(buf, x + 1, y + 1 + row, ' '.padEnd(innerWidth), innerWidth);\n row++;\n\n for (const item of visibleItems) {\n if (row >= clampedHeight - 2) break;\n const line = ` ${item.key} ${item.label.trim()}`.padEnd(innerWidth);\n writeClipped(buf, x + 1, y + 1 + row, line, innerWidth);\n row++;\n }\n\n if (row < clampedHeight - 1) {\n writeClipped(buf, x + 1, y + 1 + row, ansiDim(' esc cancel'.padEnd(innerWidth)), innerWidth);\n }\n}\n\nexport function renderHelpOverlay(buf: FrameBuffer, rows: number, cols: number): void {\n const innerWidth = HELP_WIDTH - 2;\n const x = Math.max(0, Math.floor((cols - HELP_WIDTH) / 2));\n\n const contentLines: string[] = [\n // Nav-mode keys\n helpRow(' hjkl/↑↓←→ navigate', ' tab switch pane', innerWidth),\n helpRow(' enter expand/open', ' F toggle flow', innerWidth),\n helpRow(' n new session', ' m message orch.', innerWidth),\n helpRow(' R resume session', ' C continue session', innerWidth),\n helpRow(' b rollback cycle', ' x restart agent', innerWidth),\n helpRow(' r re-run agent', ' g edit goal', innerWidth),\n helpRow(' p open roadmap', ' S edit strategy', innerWidth),\n helpRow(' w go to window', ' o resume claude', innerWidth),\n helpRow(' c side claude pane', ' q quit', innerWidth),\n ' '.padEnd(innerWidth),\n // Leader direct keys (top-level space-key)\n helpRow(' space s cycle session', ' space h home/dashboard', innerWidth),\n helpRow(' space n new session', ' space m message orch.', innerWidth),\n helpRow(' space t status popup', ' space l session picker', innerWidth),\n helpRow(' space x kill pane', ' space / search', innerWidth),\n helpRow(' space ? help', ' space 1-9 jump to session', innerWidth),\n ' '.padEnd(innerWidth),\n // Direct top-level leader keys\n helpRow(' space c side claude pane', ' space y › Yank', innerWidth),\n // Submenu prefixes\n helpRow(' space o › Open', ' space a › Agent', innerWidth),\n helpRow(' space S › Session', ' space g › Go', innerWidth),\n helpRow(' space C › Companion', '', innerWidth),\n ' '.padEnd(innerWidth),\n ansiDim(' Changed: space a → space a s (spawn agent)'.padEnd(innerWidth)),\n ];\n\n const height = Math.min(contentLines.length + 4, rows - 2);\n const y = Math.max(0, Math.floor((rows - height) / 2));\n\n drawBorder(buf, x, y, HELP_WIDTH, height, 'yellow');\n\n writeClipped(buf, x + 1, y + 1, ansiColor(' KEYBINDINGS (esc or ? to close)'.padEnd(innerWidth), 'yellow', true), innerWidth);\n writeClipped(buf, x + 1, y + 2, ' '.padEnd(innerWidth), innerWidth);\n\n const availableContentRows = height - 4;\n for (let i = 0; i < Math.min(contentLines.length, availableContentRows); i++) {\n writeClipped(buf, x + 1, y + 3 + i, contentLines[i]!, innerWidth);\n }\n\n const trailingBlankRow = y + 3 + Math.min(contentLines.length, availableContentRows);\n if (trailingBlankRow < y + height - 1) {\n writeClipped(buf, x + 1, trailingBlankRow, ' '.padEnd(innerWidth), innerWidth);\n }\n}\n\n// ─── Companion Overlay State (module-level, reset on close) ──────────────────\n\ntype CompanionPage = 'profile' | 'badges' | 'help';\n\nlet _page: CompanionPage = 'profile';\nlet _prevPage: 'profile' | 'badges' = 'profile';\nlet _gallery: BadgeGallery | null = null;\n\nexport function companionOverlayNextPage(): void {\n if (_page === 'help') { _page = _prevPage; return; }\n _page = _page === 'profile' ? 'badges' : 'profile';\n}\n\nexport function companionOverlayShowHelp(): void {\n if (_page !== 'help') _prevPage = _page as 'profile' | 'badges';\n _page = 'help';\n}\n\nexport function companionOverlayDismissHelp(): void {\n _page = _prevPage;\n}\n\nexport function badgeGalleryLeft(): void {\n if (_gallery) _gallery.currentIndex = galleryPrev(_gallery);\n}\n\nexport function badgeGalleryRight(): void {\n if (_gallery) _gallery.currentIndex = galleryNext(_gallery);\n}\n\nexport function closeBadgeGallery(): void {\n _page = 'profile';\n _gallery = null;\n _badgeScroll = 0;\n}\n\nexport function getCompanionPage(): CompanionPage {\n return _page;\n}\n\n// ─── Companion Profile Page ──────────────────────────────────────────────────\n\n// ─── Helpers ─────────────────────────────────────────────────────────────────\n\nconst MOOD_ICONS: Record<Mood, string> = {\n happy: '◉', grinding: '◈', frustrated: '◆', zen: '◎', sleepy: '◌', excited: '✦', existential: '◉',\n};\n\nconst MOOD_COLORS: Record<Mood, string> = {\n happy: 'green', grinding: 'yellow', frustrated: 'red', zen: 'cyan', sleepy: 'gray', excited: 'white', existential: 'magenta',\n};\n\nfunction statBar(value: number, max: number, width: number, color: string): string {\n const filled = max > 0 ? Math.min(width, Math.round((value / max) * width)) : 0;\n const bar = ansiColor('▓'.repeat(filled), color) + ansiDim('░'.repeat(width - filled));\n return bar;\n}\n\nfunction wrapText(text: string, maxWidth: number): string[] {\n const words = text.split(' ');\n const lines: string[] = [];\n let current = '';\n for (const word of words) {\n if (current.length + word.length + 1 > maxWidth && current.length > 0) {\n lines.push(current);\n current = word;\n } else {\n current = current.length > 0 ? `${current} ${word}` : word;\n }\n }\n if (current.length > 0) lines.push(current);\n return lines;\n}\n\nfunction renderProfilePage(buf: FrameBuffer, rows: number, cols: number, companion: CompanionState): void {\n const innerWidth = COMPANION_WIDTH - 2;\n const x = Math.max(0, Math.floor((cols - COMPANION_WIDTH) / 2));\n\n const unlockedCount = companion.achievements.length;\n const totalAchievements = ACHIEVEMENTS.length;\n\n const endH = Math.floor(companion.stats.endurance / 3_600_000);\n\n const intensity = companion.debugMood?.scores[companion.mood] ?? 0;\n const face = getMoodFace(companion.mood, intensity);\n const moodColor = MOOD_COLORS[companion.mood];\n const moodIcon = MOOD_ICONS[companion.mood];\n const faceColored = ansiColor(`(${face})`, moodColor, true);\n\n const repoNicknames = Object.values(companion.repos)\n .map(r => r.nickname)\n .filter((n): n is string => n !== null);\n const repoDisplay = repoNicknames.length > 0 ? ansiDim(` \"${repoNicknames[0]}\"`) : '';\n\n const barW = 18;\n\n // XP progress within current level\n const { xpIntoLevel, xpForNextLevel } = computeLevelProgress(companion.xp);\n const xpBar = statBar(xpIntoLevel, xpForNextLevel, 20, 'cyan');\n\n // Most recent achievement\n const lastAchievement = companion.achievements.length > 0\n ? companion.achievements[companion.achievements.length - 1]\n : null;\n const lastDef = lastAchievement\n ? ACHIEVEMENTS.find(a => a.id === lastAchievement.id)\n : null;\n\n const contentLines: string[] = [];\n\n // Face + mood\n contentLines.push(` ${faceColored} .${repoDisplay}`.padEnd(innerWidth));\n contentLines.push(' '.padEnd(innerWidth));\n\n // Level + title\n contentLines.push(` ${ansiColor(`Lv ${companion.level}`, 'cyan', true)} ${ansiBold(companion.title)}`.padEnd(innerWidth));\n contentLines.push(` ${xpBar} ${ansiDim(`${companion.xp} xp`)}`.padEnd(innerWidth));\n contentLines.push(' '.padEnd(innerWidth));\n\n // Mood\n contentLines.push(` ${ansiColor(moodIcon, moodColor)} ${ansiColor(companion.mood, moodColor)}`.padEnd(innerWidth));\n contentLines.push(' '.padEnd(innerWidth));\n\n // Stats with colored bars\n contentLines.push(` ${ansiColor('STR', 'red')} ${String(companion.stats.strength).padStart(4)} ${statBar(companion.stats.strength, 100, barW, 'red')}`.padEnd(innerWidth));\n contentLines.push(` ${ansiColor('END', 'yellow')} ${String(endH + 'h').padStart(4)} ${statBar(endH, 500, barW, 'yellow')}`.padEnd(innerWidth));\n contentLines.push(` ${ansiColor('WIS', 'blue')} ${String(companion.stats.wisdom).padStart(4)} ${statBar(companion.stats.wisdom, 50, barW, 'blue')}`.padEnd(innerWidth));\n contentLines.push(` ${ansiColor('PAT', 'magenta')} ${String(companion.stats.patience).padStart(4)} ${statBar(companion.stats.patience, 200, barW, 'magenta')}`.padEnd(innerWidth));\n contentLines.push(' '.padEnd(innerWidth));\n\n // Achievement\n if (lastDef) {\n contentLines.push(` ${ansiColor('★', 'yellow')} ${lastDef.name} ${ansiDim(`${unlockedCount}/${totalAchievements}`)}`.padEnd(innerWidth));\n } else {\n contentLines.push(` ${ansiDim(`◇ ${unlockedCount}/${totalAchievements} achievements`)}`.padEnd(innerWidth));\n }\n\n contentLines.push(' '.padEnd(innerWidth));\n\n // Commentary — word-wrapped, styled\n if (companion.lastCommentary) {\n const raw = companion.lastCommentary.text;\n const wrapped = wrapText(raw, innerWidth - 6);\n contentLines.push(` ${ansiDim('┊')} ${ansiColor(wrapped[0] ?? '', 'white')}`.padEnd(innerWidth));\n for (let i = 1; i < wrapped.length; i++) {\n contentLines.push(` ${ansiDim('┊')} ${ansiColor(wrapped[i] ?? '', 'white')}`.padEnd(innerWidth));\n }\n }\n\n contentLines.push(' '.padEnd(innerWidth));\n contentLines.push(` ${ansiDim('tab → badges ? → stat guide')}`.padEnd(innerWidth));\n\n const height = Math.min(contentLines.length + 4, rows - 2);\n const y = Math.max(0, Math.floor((rows - height) / 2));\n\n drawBorder(buf, x, y, COMPANION_WIDTH, height, 'cyan');\n\n writeClipped(buf, x + 1, y + 1, ansiColor(' COMPANION (esc to close)'.padEnd(innerWidth), 'cyan', true), innerWidth);\n writeClipped(buf, x + 1, y + 2, ' '.padEnd(innerWidth), innerWidth);\n\n const availableContentRows = height - 4;\n for (let i = 0; i < Math.min(contentLines.length, availableContentRows); i++) {\n writeClipped(buf, x + 1, y + 3 + i, contentLines[i]!, innerWidth);\n }\n}\n\n// ─── Badge Gallery Page ──────────────────────────────────────────────────────\n\nconst GALLERY_WIDTH = 50;\n\nlet _badgeScroll = 0;\n\nexport function badgeListScrollUp(): void { _badgeScroll = Math.max(0, _badgeScroll - 1); }\nexport function badgeListScrollDown(): void { _badgeScroll++; }\n\nfunction renderBadgesPage(buf: FrameBuffer, rows: number, cols: number, companion: CompanionState): void {\n if (!_gallery) _gallery = createBadgeGallery(companion.achievements);\n const gallery = _gallery;\n\n const innerWidth = GALLERY_WIDTH - 2;\n const x = Math.max(0, Math.floor((cols - GALLERY_WIDTH) / 2));\n\n const unlockedCount = companion.achievements.length;\n const totalAchievements = ACHIEVEMENTS.length;\n\n // Render current badge card\n const currentDef = gallery.achievements[gallery.currentIndex]!;\n const currentUnlock = gallery.unlocked.get(currentDef.id) ?? null;\n const card = renderBadgeCard(currentDef, currentUnlock);\n\n const contentLines: string[] = [];\n\n // Badge card (centered within overlay)\n for (const cardLine of card.lines) {\n const stripped = cardLine.replace(/\\x1b\\[[0-9;]*m/g, '');\n const pad = Math.max(0, Math.floor((innerWidth - stripped.length) / 2));\n const padded = ' '.repeat(pad) + cardLine + ' '.repeat(Math.max(0, innerWidth - stripped.length - pad));\n contentLines.push(padded);\n }\n\n contentLines.push(' '.padEnd(innerWidth));\n\n // Navigation footer\n const navIdx = gallery.currentIndex + 1;\n const navTotal = gallery.total;\n const unlockLabel = currentUnlock !== null ? ' ✓ unlocked' : ' · locked';\n const navLine = ` ← ${navIdx}/${navTotal} → ${unlockedCount}/${totalAchievements} earned${unlockLabel}`;\n contentLines.push(navLine.padEnd(innerWidth));\n\n contentLines.push(' '.padEnd(innerWidth));\n\n // Achievement checklist — scrollable, current badge highlighted\n const listStartIdx = contentLines.length;\n const maxListRows = Math.min(6, Math.max(4, (rows - 2) - 4 - listStartIdx - 2));\n const maxScroll = Math.max(0, gallery.total - maxListRows + 1);\n if (_badgeScroll > maxScroll) _badgeScroll = maxScroll;\n\n // Auto-scroll to keep current badge visible (iterative: indicators steal rows)\n if (gallery.currentIndex < _badgeScroll) _badgeScroll = gallery.currentIndex;\n for (let pass = 0; pass < 3; pass++) {\n const a = _badgeScroll > 0 ? 1 : 0;\n const b = _badgeScroll + maxListRows < gallery.total ? 1 : 0;\n const vis = maxListRows - a - b;\n if (gallery.currentIndex >= _badgeScroll + vis) {\n _badgeScroll = gallery.currentIndex - vis + 1;\n } else break;\n }\n if (_badgeScroll > maxScroll) _badgeScroll = maxScroll;\n\n const hasMoreAbove = _badgeScroll > 0;\n const hasMoreBelow = _badgeScroll + maxListRows < gallery.total;\n const itemRows = maxListRows - (hasMoreAbove ? 1 : 0) - (hasMoreBelow ? 1 : 0);\n\n if (hasMoreAbove) {\n contentLines.push(ansiDim(` ↑ ${_badgeScroll} more`.padEnd(innerWidth)));\n }\n\n for (let i = 0; i < itemRows && (_badgeScroll + i) < gallery.total; i++) {\n const idx = _badgeScroll + i;\n const def = gallery.achievements[idx]!;\n const u = gallery.unlocked.has(def.id);\n const icon = u ? '✓' : '·';\n const isCurrent = idx === gallery.currentIndex;\n let line = ` ${icon} ${def.name}`.padEnd(innerWidth);\n if (isCurrent) line = ansiColor(line, 'cyan', false);\n else if (!u) line = ansiDim(line);\n contentLines.push(line);\n }\n\n if (hasMoreBelow) {\n const below = gallery.total - _badgeScroll - itemRows;\n contentLines.push(ansiDim(` ↓ ${below} more`.padEnd(innerWidth)));\n }\n\n contentLines.push(' '.padEnd(innerWidth));\n contentLines.push(ansiDim(' tab → profile ? → stat guide'.padEnd(innerWidth)));\n\n const height = Math.min(contentLines.length + 4, rows - 2);\n const y = Math.max(0, Math.floor((rows - height) / 2));\n\n drawBorder(buf, x, y, GALLERY_WIDTH, height, 'cyan');\n\n writeClipped(buf, x + 1, y + 1, ansiColor(' BADGES (↑↓ navigate, esc close)'.padEnd(innerWidth), 'cyan', true), innerWidth);\n writeClipped(buf, x + 1, y + 2, ' '.padEnd(innerWidth), innerWidth);\n\n const availableContentRows = height - 4;\n for (let i = 0; i < Math.min(contentLines.length, availableContentRows); i++) {\n writeClipped(buf, x + 1, y + 3 + i, contentLines[i]!, innerWidth);\n }\n}\n\n// ─── Stat Guide Page ─────────────────────────────────────────────────────────\n\nfunction renderHelpPage(buf: FrameBuffer, rows: number, cols: number): void {\n const innerWidth = COMPANION_WIDTH - 2;\n const x = Math.max(0, Math.floor((cols - COMPANION_WIDTH) / 2));\n\n const divider = (label: string, color: string) => {\n const rest = innerWidth - label.length - 5;\n return ` ${ansiColor(label, color, true)} ${ansiDim('─'.repeat(Math.max(0, rest)))}`;\n };\n\n const contentLines: string[] = [];\n\n contentLines.push(divider('STR (Strength)', 'red'));\n contentLines.push(' +1 per completed session'.padEnd(innerWidth));\n contentLines.push(' '.padEnd(innerWidth));\n\n contentLines.push(divider('END (Endurance)', 'yellow'));\n contentLines.push(' Total active time across sessions'.padEnd(innerWidth));\n contentLines.push(' (displayed in hours)'.padEnd(innerWidth));\n contentLines.push(' '.padEnd(innerWidth));\n\n contentLines.push(divider('WIS (Wisdom)', 'blue'));\n contentLines.push(' +1 per efficient session'.padEnd(innerWidth));\n contentLines.push(ansiDim(' agents have <30% stddev in active').padEnd(innerWidth));\n contentLines.push(ansiDim(' time, 2+ agents required').padEnd(innerWidth));\n contentLines.push(' '.padEnd(innerWidth));\n\n contentLines.push(divider('PAT (Patience)', 'magenta'));\n contentLines.push(' +√cycles per completed session'.padEnd(innerWidth));\n contentLines.push(ansiDim(' +1 if validation mode').padEnd(innerWidth));\n contentLines.push(ansiDim(' +1 if completion mode').padEnd(innerWidth));\n contentLines.push(' '.padEnd(innerWidth));\n\n contentLines.push(divider('XP & Level', 'cyan'));\n contentLines.push(' STR×80 + END/h×15 + WIS×40'.padEnd(innerWidth));\n contentLines.push(' + PAT×5'.padEnd(innerWidth));\n contentLines.push(ansiDim(' level: 150 base xp, ×1.35/lvl').padEnd(innerWidth));\n contentLines.push(' '.padEnd(innerWidth));\n\n contentLines.push(divider('Mood', 'white'));\n contentLines.push(' Real-time scoring from signals:'.padEnd(innerWidth));\n contentLines.push(ansiDim(' time of day, idle time, crashes,').padEnd(innerWidth));\n contentLines.push(ansiDim(' streaks, session length, agents').padEnd(innerWidth));\n contentLines.push(' '.padEnd(innerWidth));\n\n contentLines.push(divider('Badges', 'yellow'));\n contentLines.push(' Milestones, session feats, time'.padEnd(innerWidth));\n contentLines.push(' patterns, and behavioral checks'.padEnd(innerWidth));\n contentLines.push(' '.padEnd(innerWidth));\n\n contentLines.push(ansiDim(' tab → back ? → close'.padEnd(innerWidth)));\n\n const height = Math.min(contentLines.length + 4, rows - 2);\n const y = Math.max(0, Math.floor((rows - height) / 2));\n\n drawBorder(buf, x, y, COMPANION_WIDTH, height, 'cyan');\n\n writeClipped(buf, x + 1, y + 1, ansiColor(' STAT GUIDE (? or esc to close)'.padEnd(innerWidth), 'cyan', true), innerWidth);\n writeClipped(buf, x + 1, y + 2, ' '.padEnd(innerWidth), innerWidth);\n\n const availableContentRows = height - 4;\n for (let i = 0; i < Math.min(contentLines.length, availableContentRows); i++) {\n writeClipped(buf, x + 1, y + 3 + i, contentLines[i]!, innerWidth);\n }\n\n const trailingBlankRow = y + 3 + Math.min(contentLines.length, availableContentRows);\n if (trailingBlankRow < y + height - 1) {\n writeClipped(buf, x + 1, trailingBlankRow, ' '.padEnd(innerWidth), innerWidth);\n }\n}\n\n// ─── Companion Overlay Dispatcher ────────────────────────────────────────────\n\nexport function renderCompanionOverlay(buf: FrameBuffer, rows: number, cols: number, companion: CompanionState): void {\n if (_page === 'help') {\n renderHelpPage(buf, rows, cols);\n } else if (_page === 'badges') {\n renderBadgesPage(buf, rows, cols, companion);\n } else {\n renderProfilePage(buf, rows, cols, companion);\n }\n}\n\nexport function renderCompanionDebugOverlay(buf: FrameBuffer, rows: number, cols: number, companion: CompanionState): void {\n const innerWidth = DEBUG_WIDTH - 2;\n const x = Math.max(0, Math.floor((cols - DEBUG_WIDTH) / 2));\n\n const intensity = companion.debugMood?.scores[companion.mood] ?? 0;\n const face = getMoodFace(companion.mood, intensity);\n const debug = companion.debugMood;\n\n const contentLines: string[] = [\n ` (${face}) mood: ${companion.mood}`.padEnd(innerWidth),\n ' '.padEnd(innerWidth),\n ];\n\n if (debug) {\n const { signals, scores } = debug;\n\n contentLines.push(ansiDim(' ── Signals ──'.padEnd(innerWidth)));\n contentLines.push(` hourOfDay: ${signals.hourOfDay}`.padEnd(innerWidth));\n contentLines.push(` sessionLengthMs: ${signals.sessionLengthMs} (${Math.round(signals.sessionLengthMs / 60_000)}min)`.padEnd(innerWidth));\n contentLines.push(` idleDurationMs: ${signals.idleDurationMs} (${Math.round(signals.idleDurationMs / 60_000)}min)`.padEnd(innerWidth));\n contentLines.push(` recentCrashes: ${signals.recentCrashes}`.padEnd(innerWidth));\n contentLines.push(` cleanStreak: ${signals.cleanStreak}`.padEnd(innerWidth));\n contentLines.push(` justCompleted: ${signals.justCompleted}`.padEnd(innerWidth));\n contentLines.push(` justCrashed: ${signals.justCrashed}`.padEnd(innerWidth));\n contentLines.push(` justLeveledUp: ${signals.justLeveledUp}`.padEnd(innerWidth));\n contentLines.push(' '.padEnd(innerWidth));\n\n contentLines.push(ansiDim(' ── Scores ──'.padEnd(innerWidth)));\n const moodOrder: Mood[] = ['happy', 'grinding', 'frustrated', 'zen', 'sleepy', 'excited', 'existential'];\n for (const mood of moodOrder) {\n const score = scores[mood] ?? 0;\n const bar = score > 0 ? ansiDim('█'.repeat(Math.min(Math.round(score / 5), 12))) : '';\n const marker = mood === debug.winner ? ' ◀' : '';\n contentLines.push(` ${mood.padEnd(12)} ${String(score).padStart(3)} ${bar}${marker}`.padEnd(innerWidth));\n }\n } else {\n contentLines.push(ansiDim(' No mood signals yet'.padEnd(innerWidth)));\n contentLines.push(ansiDim(' (mood is time-of-day only)'.padEnd(innerWidth)));\n }\n\n contentLines.push(' '.padEnd(innerWidth));\n\n const height = Math.min(contentLines.length + 4, rows - 2);\n const y = Math.max(0, Math.floor((rows - height) / 2));\n\n drawBorder(buf, x, y, DEBUG_WIDTH, height, 'yellow');\n\n writeClipped(buf, x + 1, y + 1, ansiColor(' COMPANION DEBUG (esc to close)'.padEnd(innerWidth), 'yellow', true), innerWidth);\n writeClipped(buf, x + 1, y + 2, ' '.padEnd(innerWidth), innerWidth);\n\n const availableContentRows = height - 4;\n for (let i = 0; i < Math.min(contentLines.length, availableContentRows); i++) {\n writeClipped(buf, x + 1, y + 3 + i, contentLines[i]!, innerWidth);\n }\n\n const trailingRow = y + 3 + Math.min(contentLines.length, availableContentRows);\n if (trailingRow < y + height - 1) {\n writeClipped(buf, x + 1, trailingRow, ' '.padEnd(innerWidth), innerWidth);\n }\n}\n","import stringWidth from 'string-width';\nimport type {\n CompanionState,\n CompanionField,\n CompanionRenderOpts,\n CompanionStats,\n Mood,\n} from './companion-types.js';\n\n// --- Display-width-aware string slice ---\n\n/** Slice a plain-text string to fit within `maxCols` display columns. */\nfunction sliceToWidth(s: string, maxCols: number): string {\n let w = 0;\n let i = 0;\n while (i < s.length) {\n const cp = s.codePointAt(i)!;\n const ch = String.fromCodePoint(cp);\n const cw = stringWidth(ch);\n if (w + cw > maxCols) break;\n w += cw;\n i += ch.length;\n }\n return s.slice(0, i);\n}\n\n// --- Idle hobbies ---\n\nexport const IDLE_HOBBIES: string[] = [\n 'reading Camus',\n 'stacking pebbles',\n 'watching clouds',\n 'sketching boulders',\n 'counting stars',\n 'writing haiku',\n 'practicing zen',\n 'studying geology',\n 'polishing rocks',\n 'mapping the hill',\n 'resting',\n 'stargazing',\n 'whittling',\n 'collecting fossils',\n 'napping on summit',\n 'journaling',\n 'stretching',\n 'humming',\n 'doodling',\n 'tending moss',\n 'making tea',\n 'reading Myth of Sisyphus',\n 'reorganizing rocks',\n 'people watching',\n 'whistling',\n];\n\n// --- Spinner verbs ---\n\nexport const SPINNER_VERBS: string[] = [\n // physical\n 'pushing',\n 'hauling',\n 'heaving',\n 'toiling',\n 'straining',\n 'trudging',\n 'laboring',\n 'rolling',\n 'ascending',\n 'dragging',\n 'shouldering',\n 'hoisting',\n 'lugging',\n 'schlepping',\n 'grinding',\n 'lifting',\n 'bracing',\n 'climbing',\n 'leaning in',\n 'digging in',\n // philosophical\n 'philosophizing',\n 'contemplating',\n 'pondering',\n 'musing',\n 'ruminating',\n 'reflecting',\n 'meditating',\n 'wondering',\n 'questioning',\n 'theorizing',\n 'considering',\n 'deliberating',\n 'introspecting',\n 'cogitating',\n 'brooding',\n // endurance\n 'persevering',\n 'enduring',\n 'persisting',\n 'sustaining',\n 'weathering',\n 'carrying on',\n 'pressing on',\n 'holding steady',\n 'keeping at it',\n 'not stopping',\n // light/silly\n 'napping',\n 'procrastinating',\n 'daydreaming',\n 'vibing',\n 'winging it',\n 'hoping',\n 'improvising',\n 'making do',\n 'whistling',\n];\n\n// --- Base form ---\n//\n// Returns a template with two placeholders:\n// FACE — replaced by getMoodFace() in renderCompanion\n// {BOULDER} — replaced by composeLine() with the agent-count-driven boulder\n//\n// No literal boulder characters are embedded here. The previous design embedded\n// them (`.`, `o`, `O`, `OO`, `@`) which caused splitBodyAndBoulder to either\n// discard multi-char boulders (OO) or corrupt output when the dynamic boulder\n// didn't match the embedded one.\n\nexport function getBaseForm(level: number): string {\n if (level <= 2) return '(FACE) {BOULDER}';\n if (level <= 4) return '(FACE)/ {BOULDER}';\n if (level <= 7) return '/(FACE)/ {BOULDER}';\n if (level <= 11) return '\\\\(FACE)/ {BOULDER}';\n if (level <= 19) return 'ᕦ(FACE)ᕤ {BOULDER}';\n return '♛ᕦ(FACE)ᕤ {BOULDER}';\n}\n\n// --- Mood face ---\n//\n// Each mood has three intensity tiers driven by the winning mood score:\n// mild (score < 30), moderate (30–70), intense (> 70)\n\nconst MOOD_FACES: Record<Mood, [string, string, string]> = {\n happy: ['^.^', '^‿^', '✧‿✧'],\n grinding: ['>.<', '>_<', 'ò.ó'],\n frustrated: ['>.<#', 'ಠ_ಠ', 'ಠ益ಠ'],\n zen: ['‾.‾', '‾‿‾', '˘‿˘'],\n sleepy: ['-.-)zzZ','-_-)zzZ','˘.˘)zzZ'],\n excited: ['*o*', '*◡*', '✦◡✦'],\n existential: ['◉_◉', '⊙_⊙', '◉‸◉'],\n};\n\nexport function getMoodFace(mood: Mood, intensity: number = 0): string {\n const faces = MOOD_FACES[mood];\n if (!faces) throw new Error(`Unknown mood: ${mood as string}`);\n const tier = intensity < 30 ? 0 : intensity <= 70 ? 1 : 2;\n return faces[tier];\n}\n\n// --- Stat cosmetics ---\n\nexport function getStatCosmetics(stats: CompanionStats): string[] {\n const cosmetics: string[] = [];\n if (stats.wisdom > 5) cosmetics.push('wisps');\n if (stats.endurance > 36_000_000) cosmetics.push('trail');\n if (stats.patience > 50) cosmetics.push('zen-prefix');\n return cosmetics;\n}\n\n// --- Boulder form ---\n\nexport function getBoulderForm(agentCount?: number, repoNickname?: string): string {\n let boulder: string;\n if (agentCount === undefined || agentCount <= 0) {\n boulder = '';\n } else if (agentCount <= 2) {\n boulder = 'o';\n } else if (agentCount <= 6) {\n boulder = 'O';\n } else if (agentCount <= 15) {\n boulder = '◉';\n } else if (agentCount <= 35) {\n boulder = '@';\n } else {\n boulder = '@@';\n }\n if (repoNickname !== undefined) {\n boulder = `${boulder} \"${repoNickname}\"`;\n }\n return boulder;\n}\n\n// --- composeLine ---\n//\n// body has already had FACE replaced with the mood face, and still contains\n// the {BOULDER} placeholder from getBaseForm.\n// composeLine applies cosmetics to `boulder`, then substitutes {BOULDER}.\n\nexport function composeLine(\n body: string,\n cosmetics: string[],\n boulder: string,\n): string {\n let b = boulder;\n\n let hasZenPrefix = false;\n\n if (boulder !== '') {\n for (const c of cosmetics) {\n switch (c) {\n case 'wisps':\n b = `~${b}~`;\n break;\n case 'trail':\n b = `${b} ...`;\n break;\n case 'zen-prefix':\n hasZenPrefix = true;\n break;\n }\n }\n } else {\n // Zen prefix is a character trait, not boulder-related\n if (cosmetics.includes('zen-prefix')) hasZenPrefix = true;\n }\n\n let line = b === ''\n ? body.replace(' {BOULDER}', '')\n : body.replace('{BOULDER}', b);\n\n if (hasZenPrefix) line = `☯ ${line}`;\n\n return line;\n}\n\n// --- Color helpers ---\n\ntype AnsiCode = number;\ntype TmuxColor = string;\n\ninterface MoodColor {\n ansi: AnsiCode;\n tmux: TmuxColor;\n}\n\nconst MOOD_COLORS: Record<Mood, MoodColor> = {\n happy: { ansi: 32, tmux: 'green' },\n grinding: { ansi: 33, tmux: 'yellow' },\n frustrated: { ansi: 31, tmux: 'red' },\n zen: { ansi: 36, tmux: 'cyan' },\n sleepy: { ansi: 90, tmux: 'colour245' },\n excited: { ansi: 97, tmux: 'white' },\n existential: { ansi: 35, tmux: 'magenta' },\n};\n\nexport function getMoodTmuxColor(mood: Mood): string {\n return MOOD_COLORS[mood].tmux;\n}\n\nexport function getMoodAnsiCode(mood: Mood): number {\n return MOOD_COLORS[mood].ansi;\n}\n\nfunction colorize(text: string, mood: Mood, tmux: boolean): string {\n const { ansi, tmux: tmuxColor } = MOOD_COLORS[mood];\n if (tmux) {\n return `#[fg=${tmuxColor}]${text}#[fg=default]`;\n }\n return `\\x1b[${ansi}m${text}\\x1b[0m`;\n}\n\n// --- Stat summary string ---\n\nfunction statSummary(stats: CompanionStats): string {\n const endH = Math.floor(stats.endurance / 3_600_000);\n return `STR:${stats.strength} END:${endH}h WIS:${stats.wisdom} PAT:${stats.patience}`;\n}\n\n// --- Main renderer ---\n\nexport function renderCompanion(\n companion: CompanionState,\n fields: CompanionField[],\n opts?: CompanionRenderOpts,\n): string {\n const hasFace = fields.includes('face');\n const hasBoulder = fields.includes('boulder');\n\n const repoNickname = opts?.repoPath !== undefined\n ? companion.repos[opts.repoPath]?.nickname ?? undefined\n : undefined;\n\n const boulder = getBoulderForm(opts?.agentCount, repoNickname);\n const cosmetics = getStatCosmetics(companion.stats);\n\n let facePart: string | null = null;\n let boulderOnlyPart: string | null = null;\n\n if (hasFace) {\n const baseForm = getBaseForm(companion.level);\n const intensity = companion.debugMood?.scores[companion.mood] ?? 0;\n const face = getMoodFace(companion.mood, intensity);\n const bodyWithFace = baseForm.replace('FACE', face);\n facePart = composeLine(bodyWithFace, cosmetics, boulder);\n } else if (hasBoulder) {\n // Boulder standalone (unusual)\n boulderOnlyPart = boulder;\n }\n\n let commentary = fields.includes('commentary')\n ? (companion.lastCommentary?.text ?? '')\n : null;\n\n const parts: string[] = [];\n\n for (const field of fields) {\n switch (field) {\n case 'face':\n if (facePart !== null) parts.push(facePart);\n break;\n case 'boulder':\n if (!hasFace && boulderOnlyPart !== null) parts.push(boulderOnlyPart);\n // If face included, boulder is already embedded — skip\n break;\n case 'title':\n parts.push(companion.title);\n break;\n case 'commentary':\n if (commentary !== null) parts.push(commentary);\n break;\n case 'mood':\n parts.push(`[${companion.mood}]`);\n break;\n case 'level':\n parts.push(`Lv ${companion.level}`);\n break;\n case 'stats':\n parts.push(statSummary(companion.stats));\n break;\n case 'achievements':\n parts.push(`${companion.achievements.length} achievements`);\n break;\n case 'verb': {\n const idx = (opts?.verbIndex ?? companion.spinnerVerbIndex) % SPINNER_VERBS.length;\n parts.push(SPINNER_VERBS[idx]!);\n break;\n }\n case 'hobby': {\n // Rotate hourly based on hour + companion level as seed for variety\n const hobbyIdx = (new Date().getHours() + companion.level) % IDLE_HOBBIES.length;\n parts.push(IDLE_HOBBIES[hobbyIdx]!);\n break;\n }\n }\n }\n\n // Apply maxWidth: truncate commentary first, then right-truncate.\n // Use display width (stringWidth) not .length — faces like ಠ益ಠ contain\n // wide characters where .length < displayWidth, causing writeClipped to\n // hard-clip the line without an ellipsis.\n if (opts?.maxWidth !== undefined) {\n const maxWidth = opts.maxWidth;\n const joined = parts.join(' ');\n const joinedWidth = stringWidth(joined);\n if (joinedWidth > maxWidth && commentary !== null && commentary.length > 0) {\n // Shorten commentary progressively\n const commentaryIdx = parts.indexOf(commentary);\n if (commentaryIdx !== -1) {\n const commentaryWidth = stringWidth(commentary);\n const overhead = joinedWidth - commentaryWidth;\n const available = maxWidth - overhead - 2; // account for double-space\n if (available < 0) {\n parts[commentaryIdx] = '';\n } else {\n parts[commentaryIdx] = sliceToWidth(commentary, available);\n }\n commentary = parts[commentaryIdx];\n }\n }\n const result = parts.filter(p => p.length > 0).join(' ');\n const resultWidth = stringWidth(result);\n const final = resultWidth > maxWidth\n ? sliceToWidth(result, maxWidth - 1) + '…'\n : result;\n\n return applyColor(final, fields, facePart, companion.mood, opts);\n }\n\n const result = parts.filter(p => p.length > 0).join(' ');\n return applyColor(result, fields, facePart, companion.mood, opts);\n}\n\nfunction applyColor(\n result: string,\n fields: CompanionField[],\n facePart: string | null,\n mood: Mood,\n opts?: CompanionRenderOpts,\n): string {\n const useColor = opts?.color === true || opts?.tmuxFormat === true;\n if (!useColor || facePart === null || !fields.includes('face')) return result;\n\n const tmux = opts?.tmuxFormat === true;\n const coloredFace = colorize(facePart, mood, tmux);\n return result.replace(facePart, coloredFace);\n}\n","import { existsSync, mkdirSync, readFileSync, renameSync, writeFileSync } from 'node:fs';\nimport { randomUUID } from 'node:crypto';\nimport { dirname, join } from 'node:path';\nimport { companionPath, globalDir } from '../shared/paths.js';\nimport type { Session } from '../shared/types.js';\nimport type {\n AchievementId,\n CommentaryEvent,\n CompanionBaselines,\n CompanionState,\n CompanionStats,\n FeedbackEntry,\n FeedbackRating,\n LastCommentary,\n Mood,\n MoodSignals,\n RepoMemory,\n RunningStats,\n UnlockedAchievement,\n} from '../shared/companion-types.js';\nimport { defaultBaselines, emptyStats, normalizeCompanion } from '../shared/companion-normalize.js';\nexport { defaultBaselines, emptyStats } from '../shared/companion-normalize.js';\nexport { ACHIEVEMENTS } from '../shared/companion-types.js';\n\n// ---------------------------------------------------------------------------\n// Welford's online algorithm — deviation-based mood scoring\n// ---------------------------------------------------------------------------\n\nconst MIN_SAMPLES = 5;\nconst MIN_STDDEV_RATIO = 0.20;\n\ntype BaselineMetric = 'sessionMs' | 'cycleCount' | 'agentCount' | 'sessionsPerDay' | 'recentAgentThroughput';\n\nconst ABSOLUTE_STDDEV_FLOORS: Record<BaselineMetric, number> = {\n sessionMs: 300_000, // 5 minutes\n cycleCount: 1.0,\n agentCount: 1.0,\n sessionsPerDay: 0.5,\n recentAgentThroughput: 2.0,\n};\n\nconst COLD_START_DEFAULTS: Record<BaselineMetric, { mean: number; stddev: number }> = {\n sessionMs: { mean: 3_600_000, stddev: 2_400_000 },\n cycleCount: { mean: 5, stddev: 3 },\n agentCount: { mean: 5, stddev: 4 },\n sessionsPerDay: { mean: 3, stddev: 2 },\n recentAgentThroughput: { mean: 8, stddev: 6 },\n};\n\nexport function welfordUpdate(stats: RunningStats, value: number): void {\n stats.count++;\n const delta = value - stats.mean;\n stats.mean += delta / stats.count;\n const delta2 = value - stats.mean;\n stats.m2 += delta * delta2;\n}\n\nexport function zScore(\n value: number,\n stats: RunningStats,\n metric: BaselineMetric,\n): number {\n const defaults = COLD_START_DEFAULTS[metric];\n const floor = ABSOLUTE_STDDEV_FLOORS[metric];\n\n if (stats.count < MIN_SAMPLES) {\n if (defaults.stddev === 0) return 0;\n return (value - defaults.mean) / defaults.stddev;\n }\n\n const rawStddev = stats.count >= 2 ? Math.sqrt(stats.m2 / stats.count) : 0;\n const stddev = Math.max(rawStddev, stats.mean * MIN_STDDEV_RATIO, floor);\n if (stddev === 0) return 0;\n return (value - stats.mean) / stddev;\n}\n\n// ---------------------------------------------------------------------------\n// Persistence\n// ---------------------------------------------------------------------------\n\nexport function loadCompanion(): CompanionState {\n const path = companionPath();\n if (!existsSync(path)) {\n const state = createDefaultCompanion();\n saveCompanion(state);\n return state;\n }\n const raw = readFileSync(path, 'utf-8');\n const state = JSON.parse(raw) as CompanionState;\n return normalizeCompanion(state);\n}\n\nexport function saveCompanion(state: CompanionState): void {\n const path = companionPath();\n const dir = dirname(path);\n mkdirSync(dir, { recursive: true });\n const tmp = join(dir, `.companion.${randomUUID()}.tmp`);\n writeFileSync(tmp, JSON.stringify(state, null, 2), 'utf-8');\n renameSync(tmp, path);\n}\n\nconst MAX_COMMENTARY_HISTORY = 1000;\nconst MAX_FEEDBACK_HISTORY = 1000;\n\n/**\n * Push a commentary entry to lastCommentary + commentaryHistory ring buffer.\n * Mutates the companion in-place; caller must saveCompanion() afterward.\n */\nexport function recordCommentary(companion: CompanionState, text: string, event: CommentaryEvent): void {\n const entry: LastCommentary = { text, event, timestamp: new Date().toISOString() };\n companion.lastCommentary = entry;\n if (!companion.commentaryHistory) companion.commentaryHistory = [];\n companion.commentaryHistory.push(entry);\n if (companion.commentaryHistory.length > MAX_COMMENTARY_HISTORY) {\n companion.commentaryHistory = companion.commentaryHistory.slice(-MAX_COMMENTARY_HISTORY);\n }\n}\n\n/**\n * Push a feedback entry to feedbackHistory ring buffer.\n * Mutates the companion in-place; caller must saveCompanion() afterward.\n */\nexport function recordFeedback(\n companion: CompanionState,\n text: string,\n rating: FeedbackRating,\n event: CommentaryEvent,\n comment?: string,\n): void {\n const entry: FeedbackEntry = { commentaryText: text, rating, event, timestamp: new Date().toISOString(), ...(comment != null ? { comment } : {}) };\n if (!companion.feedbackHistory) companion.feedbackHistory = [];\n companion.feedbackHistory.push(entry);\n if (companion.feedbackHistory.length > MAX_FEEDBACK_HISTORY) {\n companion.feedbackHistory = companion.feedbackHistory.slice(-MAX_FEEDBACK_HISTORY);\n }\n}\n\nexport function createDefaultCompanion(): CompanionState {\n const now = new Date().toISOString();\n return {\n version: 1,\n name: null,\n createdAt: now,\n stats: {\n strength: 0,\n endurance: 0,\n wisdom: 0,\n patience: 0,\n },\n xp: 0,\n level: 1,\n title: 'Boulder Intern',\n mood: 'sleepy',\n moodUpdatedAt: now,\n achievements: [],\n repos: {},\n lastCommentary: null,\n commentaryHistory: [],\n sessionsCompleted: 0,\n sessionsCrashed: 0,\n totalActiveMs: 0,\n lifetimeAgentsSpawned: 0,\n consecutiveCleanSessions: 0,\n consecutiveEfficientSessions: 0,\n consecutiveHighCycleSessions: 0,\n consecutiveDaysActive: 0,\n lastActiveDate: null,\n taskHistory: {},\n dailyRepos: {},\n recentCompletions: [],\n spinnerVerbIndex: 0,\n baselines: defaultBaselines(),\n feedbackHistory: [],\n };\n}\n\n// ---------------------------------------------------------------------------\n// XP & Leveling\n// ---------------------------------------------------------------------------\n\nexport function computeXP(stats: CompanionStats): number {\n const strengthXP = stats.strength * 50;\n const enduranceXP = (stats.endurance / 3_600_000) * 20;\n const wisdomXP = stats.wisdom * 40;\n const patienceXP = stats.patience * 8;\n return Math.floor(strengthXP + enduranceXP + wisdomXP + patienceXP);\n}\n\nexport function computeStrengthGain(agentCount: number): number {\n if (agentCount <= 0) return 0;\n if (agentCount <= 2) return 1;\n if (agentCount <= 5) return 2;\n if (agentCount <= 10) return 3;\n if (agentCount <= 20) return 4;\n return 5;\n}\n\nexport function computeLevel(xp: number): number {\n let level = 1;\n let threshold = 150;\n let cumulative = 0;\n while (cumulative + threshold <= xp) {\n cumulative += threshold;\n level++;\n threshold = Math.floor(threshold * 1.35);\n }\n return level;\n}\n\n/** Returns { xpIntoLevel, xpForNextLevel } so callers can render accurate progress bars. */\nexport function computeLevelProgress(xp: number): { xpIntoLevel: number; xpForNextLevel: number } {\n let threshold = 150;\n let cumulative = 0;\n while (cumulative + threshold <= xp) {\n cumulative += threshold;\n threshold = Math.floor(threshold * 1.35);\n }\n return { xpIntoLevel: xp - cumulative, xpForNextLevel: threshold };\n}\n\nconst TITLE_MAP: Record<number, string> = {\n 1: 'Boulder Intern',\n 2: 'Pebble Pusher',\n 3: 'Rock Hauler',\n 4: 'Gravel Wrangler',\n 5: 'Slope Familiar',\n 6: 'Incline Regular',\n 7: 'Ridge Runner',\n 8: 'Crag Warden',\n 9: 'Stone Whisperer',\n 10: 'Boulder Brother',\n 11: 'Hill Veteran',\n 12: 'Summit Aspirant',\n 13: 'Peak Haunter',\n 14: 'Cliff Sage',\n 15: \"Mountain's Shadow\",\n 16: 'Eternal Roller',\n 17: \"Gravity's Rival\",\n 18: 'The Unmoved Mover',\n 19: 'Camus Was Right',\n 20: 'The Absurd Hero',\n 25: 'One Must Imagine Him Happy',\n 30: 'He Has Always Been Here',\n};\n\nexport function getTitle(level: number): string {\n for (let l = level; l >= 1; l--) {\n if (TITLE_MAP[l] !== undefined) return TITLE_MAP[l]!;\n }\n return 'Boulder Intern';\n}\n\n// ---------------------------------------------------------------------------\n// Mood\n// ---------------------------------------------------------------------------\n\nexport function computeMood(companion: CompanionState, session?: Session, signals?: MoodSignals): Mood {\n if (!signals) {\n const hour = new Date().getHours();\n if (hour >= 2 && hour < 6) return 'existential';\n if (hour >= 22 || hour < 2) return 'sleepy';\n return 'zen';\n }\n\n const scores: Record<Mood, number> = {\n happy: 0,\n grinding: 0,\n frustrated: 0,\n zen: 0,\n sleepy: 0,\n excited: 0,\n existential: 0,\n };\n\n const cycleCount = signals.cycleCount ?? 0;\n const sessionsCompletedToday = signals.sessionsCompletedToday ?? 0;\n\n // Deviation-based z-scores from personal baselines\n const baselines = companion.baselines ?? defaultBaselines();\n const sessionZ = zScore(signals.sessionLengthMs, baselines.sessionMs, 'sessionMs');\n const cycleZ = zScore(cycleCount, baselines.cycleCount, 'cycleCount');\n const agentZ = zScore(signals.totalAgentCount ?? 0, baselines.agentCount, 'agentCount');\n const dailyZ = zScore(sessionsCompletedToday, baselines.sessionsPerDay, 'sessionsPerDay');\n const recentAgentZ = zScore(signals.recentAgentCount ?? 0, baselines.recentAgentThroughput, 'recentAgentThroughput');\n\n // Happy — event-driven + deviation-based quick wins\n if (signals.justCompleted) scores.happy += 50;\n if (signals.justCompleted && sessionZ < -0.5) scores.happy += 15; // quicker than usual\n if (dailyZ > 0.5) scores.happy += 20; // productive day\n if (dailyZ > 1.5) scores.happy += 10; // really productive\n if (signals.hourOfDay >= 6 && signals.hourOfDay < 12) scores.happy += 15; // morning\n if (signals.hourOfDay >= 12 && signals.hourOfDay < 17) scores.happy += 8; // afternoon\n if ((signals.activeAgentCount ?? 0) >= 1 && sessionZ < -0.5) scores.happy += 12; // early session optimism\n // Flow state: last completion was recent (within 30min) and we're in a new session\n const lastCompletion = companion.recentCompletions.length > 0\n ? Date.now() - new Date(companion.recentCompletions[companion.recentCompletions.length - 1]!).getTime()\n : Infinity;\n if (lastCompletion < 1_800_000 && signals.sessionLengthMs > 0) scores.happy += 20;\n\n // Grinding — deviation-based deep work\n if (sessionZ > 0.5) scores.grinding += 15; // longer than usual\n if (sessionZ > 1.0) scores.grinding += 10; // significantly longer\n if (sessionZ > 1.5) scores.grinding += 8; // very long for this user\n if (recentAgentZ > 0.5) scores.grinding += 12; // more agents active (2h window) than usual\n if (recentAgentZ > 1.0) scores.grinding += 10; // significantly more cross-session agents\n if (recentAgentZ > 1.5) scores.grinding += 8; // massive cross-session throughput\n if (cycleZ > 0.5) scores.grinding += 8; // more cycles than usual\n\n // Frustrated — actual negative events (crashes, rollbacks, restarts, lost agents)\n const rollbacks = signals.rollbackCount ?? 0;\n const restartedAgents = signals.restartedAgentCount ?? 0;\n const lostAgents = signals.lostAgentCount ?? 0;\n const killedAgents = signals.killedAgentCount ?? 0;\n if (signals.justCrashed) scores.frustrated += 30;\n if (signals.recentCrashes >= 2) scores.frustrated += 20;\n if (signals.recentCrashes >= 4) scores.frustrated += 15;\n if (rollbacks >= 1) scores.frustrated += 25; // rolling back = something went wrong\n if (rollbacks >= 3) scores.frustrated += 25; // repeated rollbacks = real pain\n if (restartedAgents >= 1) scores.frustrated += 15;\n if (restartedAgents >= 3) scores.frustrated += 15;\n if (lostAgents >= 1) scores.frustrated += 15;\n if (lostAgents >= 3) scores.frustrated += 10;\n if (killedAgents >= 2) scores.frustrated += 10;\n // Long session WITH negative events = stuck (but long session alone is just grinding)\n if (sessionZ > 1.5 && (signals.recentCrashes > 0 || rollbacks > 0)) scores.frustrated += 12;\n\n // Zen — deviation-based \"normal\" + absolute calm\n if (companion.stats.patience > 30) scores.zen += 15;\n if (signals.idleDurationMs > 120_000 && signals.idleDurationMs <= 900_000) scores.zen += 25; // 2-15min idle\n if (sessionZ > -1.0 && sessionZ < 0.3) scores.zen += 15; // session length is normal\n if (cycleZ < 0) scores.zen += 10; // fewer cycles than usual, smooth sailing\n if (signals.hourOfDay >= 6 && signals.hourOfDay < 10 && (signals.activeAgentCount ?? 0) === 0) scores.zen += 10;\n if (dailyZ >= -0.5 && dailyZ <= 0.5) scores.zen += 10; // normal day\n\n // Sleepy — absolute (idle duration + time of day)\n if (signals.idleDurationMs > 900_000) scores.sleepy += 30; // >15min\n if (signals.idleDurationMs > 2_700_000) scores.sleepy += 25; // >45min\n if (signals.idleDurationMs > 5_400_000) scores.sleepy += 15; // >90min\n if (signals.hourOfDay >= 22 || signals.hourOfDay < 6) scores.sleepy += 20;\n if (signals.idleDurationMs > 300_000 && (signals.hourOfDay >= 22 || signals.hourOfDay < 6)) scores.sleepy += 15;\n if (sessionZ > 2.5) scores.sleepy += 12; // exhaustion from extreme session\n\n // Excited — event-driven + deviation-based swarms\n if (signals.justLeveledUp) scores.excited += 60;\n if (signals.justCompleted && agentZ > 1.0) scores.excited += 30; // completed with notably many agents\n if (agentZ > 1.5) scores.excited += 20; // way more agents than usual\n if (agentZ > 2.0) scores.excited += 15; // massive swarm for this user\n if (signals.justCompleted && sessionZ < -1.0) scores.excited += 20; // way faster than usual\n\n // Existential — absolute (late night + experience + sustained commitment)\n if (signals.hourOfDay >= 2 && signals.hourOfDay < 6) scores.existential += 25;\n if (signals.hourOfDay >= 0 && signals.hourOfDay < 2) scores.existential += 10;\n const enduranceHours = companion.stats.endurance / 3_600_000;\n if (enduranceHours > 40) scores.existential += 15;\n if (signals.hourOfDay >= 2 && signals.hourOfDay < 6 && enduranceHours > 40) {\n scores.existential += 25;\n }\n // Weekly activity z-score — sustained above-average use, not a static lifetime counter\n const now = Date.now();\n const weekAgo = now - 7 * 24 * 3_600_000;\n const weeklyCompletions = companion.recentCompletions.filter(\n ts => new Date(ts).getTime() > weekAgo\n ).length;\n const weeklyAvgDaily = weeklyCompletions / 7;\n const weeklyZ = zScore(weeklyAvgDaily, baselines.sessionsPerDay, 'sessionsPerDay');\n if (weeklyZ > 0.5) scores.existential += 8;\n if (weeklyZ > 1.0) scores.existential += 7;\n if (weeklyZ > 1.5) scores.existential += 5;\n // Consecutive days — grows slowly from day 3, caps at +20 around day 9\n const consecutiveDays = companion.consecutiveDaysActive ?? 0;\n if (consecutiveDays >= 3) scores.existential += Math.min(20, (consecutiveDays - 2) * 3);\n\n // User feedback adjustments\n const goodRatings = signals.recentFeedbackGood ?? 0;\n const badRatings = signals.recentFeedbackBad ?? 0;\n const whipRatings = signals.recentFeedbackWhip ?? 0;\n if (goodRatings > 0) {\n scores.happy += goodRatings * 20;\n scores.excited += goodRatings * 8;\n scores.frustrated = Math.max(0, scores.frustrated - goodRatings * 10);\n }\n if (badRatings > 0) {\n scores.happy = Math.max(0, scores.happy - badRatings * 15);\n scores.frustrated += badRatings * 20;\n scores.zen = Math.max(0, scores.zen - badRatings * 10);\n }\n if (whipRatings > 0) {\n scores.happy = Math.max(0, scores.happy - whipRatings * 15);\n scores.sleepy = Math.max(0, scores.sleepy - whipRatings * 15);\n scores.zen = Math.max(0, scores.zen - whipRatings * 15);\n scores.frustrated = Math.max(0, scores.frustrated - whipRatings * 8);\n scores.existential += whipRatings * 25;\n }\n\n const moodOrder: Mood[] = ['happy', 'grinding', 'frustrated', 'zen', 'sleepy', 'excited', 'existential'];\n let best: Mood = 'grinding';\n let bestScore = -1;\n for (const mood of moodOrder) {\n if (scores[mood] > bestScore) {\n bestScore = scores[mood];\n best = mood;\n }\n }\n\n // Attach debug info for TUI debug overlay\n companion.debugMood = { signals, scores: { ...scores }, winner: best };\n\n return best;\n}\n\n// ---------------------------------------------------------------------------\n// Achievements\n// ---------------------------------------------------------------------------\n\nexport function hasAchievement(companion: CompanionState, id: AchievementId): boolean {\n return companion.achievements.some(a => a.id === id);\n}\n\nfunction daysSince(isoTimestamp: string): number {\n return (Date.now() - new Date(isoTimestamp).getTime()) / (1000 * 60 * 60 * 24);\n}\n\ntype AchievementChecker = (companion: CompanionState, session?: Session) => boolean;\n\nconst ACHIEVEMENT_CHECKERS: Record<AchievementId, AchievementChecker> = {\n // Milestone\n 'first-blood': (c) => c.sessionsCompleted >= 1,\n 'regular': (c) => c.sessionsCompleted >= 10,\n 'centurion': (c) => c.sessionsCompleted >= 100,\n 'veteran': (c) => c.sessionsCompleted >= 500,\n 'thousand-boulder': (c) => c.sessionsCompleted >= 1000,\n 'cartographer': (c) => Object.keys(c.repos).length >= 5,\n 'world-traveler': (c) => Object.keys(c.repos).length >= 15,\n 'omnipresent': (c) => Object.keys(c.repos).length >= 30,\n 'swarm-starter': (c) => c.lifetimeAgentsSpawned >= 50,\n 'hive-mind': (c) => c.lifetimeAgentsSpawned >= 500,\n 'legion': (c) => c.lifetimeAgentsSpawned >= 2000,\n 'army-of-thousands': (c) => c.lifetimeAgentsSpawned >= 5000,\n 'singularity': (c) => c.lifetimeAgentsSpawned >= 10000,\n 'first-shift': (c) => c.totalActiveMs >= 36_000_000,\n 'workaholic': (c) => c.totalActiveMs >= 360_000_000,\n 'time-lord': (c) => c.totalActiveMs >= 1_800_000_000,\n 'eternal-grind': (c) => c.totalActiveMs >= 7_200_000_000,\n 'epoch': (c) => c.totalActiveMs >= 18_000_000_000,\n 'old-growth': (c) => daysSince(c.createdAt) >= 14,\n 'seasoned': (c) => daysSince(c.createdAt) >= 90,\n 'ancient': (c) => daysSince(c.createdAt) >= 365,\n 'apprentice': (c) => c.level >= 5,\n 'journeyman': (c) => c.level >= 15,\n 'master': (c) => c.level >= 30,\n 'grandmaster': (c) => c.level >= 50,\n\n // Session\n 'marathon': (_c, s) => s != null && s.agents.length >= 15,\n 'squad': (_c, s) => s != null && s.agents.length >= 10,\n 'battalion': (_c, s) => s != null && s.agents.length >= 25,\n 'swarm': (_c, s) => s != null && s.agents.length >= 50,\n 'blitz': (_c, s) => s != null && s.activeMs < 300_000 && s.status === 'completed',\n 'speed-run': (_c, s) => s != null && s.activeMs < 900_000 && s.status === 'completed',\n 'flash': (_c, s) => s != null && s.activeMs < 120_000 && s.status === 'completed',\n 'flawless': (_c, s) => s != null && s.agents.length >= 10 && s.status === 'completed' &&\n s.agents.every(a => a.status !== 'crashed' && a.status !== 'killed'),\n 'speed-demon': (c) => c.consecutiveEfficientSessions >= 10,\n 'iron-will': (c) => c.consecutiveHighCycleSessions >= 5,\n 'glass-cannon': (_c, s) => {\n if (!s || s.status !== 'completed' || s.agents.length < 5) return false;\n return s.agents.every(a => a.status === 'crashed' || a.killedReason != null);\n },\n 'solo': (_c, s) => s != null && s.status === 'completed' && s.agents.length === 1,\n 'one-more-cycle': (_c, s) => s != null && s.orchestratorCycles.length >= 10,\n 'deep-dive': (_c, s) => s != null && s.orchestratorCycles.length >= 15,\n 'abyss': (_c, s) => s != null && s.orchestratorCycles.length >= 25,\n 'eternal-recurrence': (_c, s) => s != null && s.orchestratorCycles.length >= 40,\n 'endurance': (_c, s) => s != null && s.activeMs >= 14_400_000,\n 'ultramarathon': (_c, s) => s != null && s.activeMs >= 21_600_000,\n 'one-shot': (_c, s) => s != null && s.agents.length >= 5 && s.orchestratorCycles.length === 1 && s.status === 'completed',\n 'quick-draw': (_c, s) => {\n if (!s || s.agents.length === 0) return false;\n const firstAgent = s.agents[0]!;\n return new Date(firstAgent.spawnedAt).getTime() - new Date(s.createdAt).getTime() < 20_000;\n },\n\n // Time\n 'night-owl': (_c, s) => {\n if (!s || s.status !== 'completed') return false;\n const h = new Date(s.createdAt).getHours();\n return h >= 1 && h < 5;\n },\n 'dawn-patrol': (_c, s) => {\n if (!s) return false;\n // Session must be 3+ hours\n if (s.activeMs < 10_800_000) return false;\n const start = new Date(s.createdAt).getTime();\n const end = s.completedAt ? new Date(s.completedAt).getTime() : Date.now();\n const startDate = new Date(start);\n const startHour = startDate.getHours();\n // Get today's midnight (00:00) for the start date\n const todayMidnight = new Date(startDate);\n todayMidnight.setHours(0, 0, 0, 0);\n // Get 6am for the same calendar day as midnight\n const sixAm = new Date(todayMidnight);\n sixAm.setHours(6, 0, 0, 0);\n\n if (startHour >= 6) {\n // Started after 6am — check if session spans into next day's midnight-6am window\n const nextMidnight = new Date(todayMidnight.getTime() + 24 * 60 * 60 * 1000);\n return start < nextMidnight.getTime() && end > nextMidnight.getTime();\n } else {\n // Started between midnight and 6am — session is already in the window\n return start < sixAm.getTime();\n }\n },\n 'early-bird': (_c, s) => {\n if (!s) return false;\n return new Date(s.createdAt).getHours() < 6;\n },\n 'weekend-warrior': (_c, s) => {\n if (!s || s.status !== 'completed') return false;\n const day = new Date(s.completedAt ?? s.createdAt).getDay();\n return day === 0 || day === 6;\n },\n 'all-nighter': (_c, s) => s != null && s.activeMs >= 18_000_000,\n 'witching-hour': (_c, s) => {\n if (!s) return false;\n const h = new Date(s.createdAt).getHours();\n return h === 3;\n },\n\n // Behavioral\n 'sisyphean': (c) => Object.values(c.taskHistory).some(v => v >= 3),\n 'stubborn': (c) => Object.values(c.taskHistory).some(v => v >= 5) && c.sessionsCompleted > 0,\n 'one-must-imagine': (c) => Object.values(c.taskHistory).some(v => v >= 10),\n 'creature-of-habit': (c) => Object.values(c.repos).some(r => r.visits >= 10),\n 'loyal': (c) => Object.values(c.repos).some(r => r.visits >= 30),\n 'wanderer': (c) => {\n return Object.values(c.dailyRepos).some(repos => repos.length >= 3);\n },\n 'streak': (c) => c.consecutiveDaysActive >= 7,\n 'iron-streak': (c) => c.consecutiveDaysActive >= 14,\n 'hot-streak': (c) => c.consecutiveCleanSessions >= 15,\n 'momentum': (c) => {\n if (c.recentCompletions.length < 5) return false;\n const last5 = c.recentCompletions.slice(-5);\n const oldest = new Date(last5[0]!).getTime();\n const newest = new Date(last5[4]!).getTime();\n return newest - oldest <= 4 * 60 * 60 * 1000;\n },\n 'overdrive': (c) => {\n const dateCounts: Record<string, number> = {};\n for (const ts of c.recentCompletions) {\n const date = ts.slice(0, 10);\n dateCounts[date] = (dateCounts[date] ?? 0) + 1;\n }\n return Object.values(dateCounts).some(count => count >= 6);\n },\n 'patient-one': (_c, s) => {\n if (!s || s.orchestratorCycles.length < 2) return false;\n for (let i = 1; i < s.orchestratorCycles.length; i++) {\n const prev = s.orchestratorCycles[i - 1]!;\n const curr = s.orchestratorCycles[i]!;\n if (!prev.completedAt) continue;\n const gap = new Date(curr.timestamp).getTime() - new Date(prev.completedAt).getTime();\n if (gap >= 30 * 60 * 1000) return true;\n }\n return false;\n },\n 'message-in-a-bottle': (_c, s) => {\n if (!s) return false;\n const userMessages = s.messages.filter(m => m.source.type === 'user');\n return userMessages.length >= 10;\n },\n 'deep-conversation': (_c, s) => {\n if (!s) return false;\n const userMessages = s.messages.filter(m => m.source.type === 'user');\n return userMessages.length >= 20;\n },\n 'comeback-kid': (_c, s) => {\n if (!s || s.status !== 'completed') return false;\n return s.orchestratorCycles.length > 0 && s.parentSessionId != null;\n },\n 'pair-programming': (_c, s) => {\n if (!s) return false;\n const userMessages = s.messages.filter(m => m.source.type === 'user');\n return userMessages.length >= 8;\n },\n};\n\nexport function checkAchievements(companion: CompanionState, session?: Session): AchievementId[] {\n const alreadyUnlocked = new Set(companion.achievements.map(a => a.id));\n const newIds: AchievementId[] = [];\n\n for (const [id, checker] of Object.entries(ACHIEVEMENT_CHECKERS) as [AchievementId, AchievementChecker][]) {\n if (alreadyUnlocked.has(id)) continue;\n if (checker(companion, session)) {\n newIds.push(id);\n }\n }\n return newIds;\n}\n\n// ---------------------------------------------------------------------------\n// Repo Memory\n// ---------------------------------------------------------------------------\n\nconst MOOD_SENTIMENT: Record<Mood, number> = {\n happy: 0.85,\n excited: 0.90,\n zen: 0.70,\n grinding: 0.45,\n sleepy: 0.40,\n frustrated: 0.15,\n existential: 0.25,\n};\n\nexport function updateRepoMemory(\n companion: CompanionState,\n repoPath: string,\n event: 'visit' | 'completion' | 'crash',\n activeMs?: number,\n): CompanionState {\n const now = new Date().toISOString();\n const moodScore = MOOD_SENTIMENT[companion.mood] ?? 0.5;\n const existing = companion.repos[repoPath];\n if (!existing) {\n companion.repos[repoPath] = {\n visits: event === 'visit' ? 1 : 0,\n completions: event === 'completion' ? 1 : 0,\n crashes: event === 'crash' ? 1 : 0,\n totalActiveMs: activeMs ?? 0,\n moodAvg: moodScore,\n nickname: null,\n firstSeen: now,\n lastSeen: now,\n };\n } else {\n if (event === 'visit') existing.visits++;\n if (event === 'completion') existing.completions++;\n if (event === 'crash') existing.crashes++;\n if (activeMs != null) existing.totalActiveMs += activeMs;\n existing.lastSeen = now;\n // Running average weighted by total event count across visits/completions/crashes\n const n = existing.visits + existing.completions + existing.crashes;\n existing.moodAvg = existing.moodAvg + (moodScore - existing.moodAvg) / n;\n }\n return companion;\n}\n\n// ---------------------------------------------------------------------------\n// Event Handlers\n// ---------------------------------------------------------------------------\n\nfunction recomputeXpLevelTitle(companion: CompanionState): void {\n companion.xp = computeXP(companion.stats);\n companion.level = computeLevel(companion.xp);\n companion.title = getTitle(companion.level);\n}\n\nexport function todayIso(): string {\n return new Date().toISOString().slice(0, 10);\n}\n\nexport function onSessionStart(companion: CompanionState, cwd: string): void {\n // Update repo memory\n updateRepoMemory(companion, cwd, 'visit');\n\n // Update dailyRepos\n const today = todayIso();\n if (!companion.dailyRepos[today]) companion.dailyRepos[today] = [];\n if (!companion.dailyRepos[today]!.includes(cwd)) {\n companion.dailyRepos[today]!.push(cwd);\n }\n\n // Update consecutive days active\n const lastDate = companion.lastActiveDate;\n if (lastDate === null) {\n companion.consecutiveDaysActive = 1;\n } else if (lastDate === today) {\n // Same day, no change to streak\n } else {\n const yesterday = new Date(Date.now() - 86_400_000).toISOString().slice(0, 10);\n if (lastDate === yesterday) {\n companion.consecutiveDaysActive++;\n } else {\n companion.consecutiveDaysActive = 1;\n }\n }\n companion.lastActiveDate = today;\n\n recomputeXpLevelTitle(companion);\n}\n\n/**\n * Compute wisdom points earned for a session. Rewards:\n * - Clean agent execution: high completion rate without restarts\n * - Good parallelization: more agents per orchestrator cycle\n * - Orchestration variety: using different modes (discovery, implementation, validation, completion)\n *\n * Returns 0-3 points per session.\n */\nexport function computeWisdomGain(session: Session): number {\n let wisdom = 0;\n const totalAgents = session.agents.length;\n const totalCycles = session.orchestratorCycles?.length ?? 0;\n if (totalAgents === 0 || totalCycles === 0) return 0;\n\n // Clean execution: ≥80% of agents completed without being killed/crashed/lost\n const cleanCompletions = session.agents.filter(a => a.status === 'completed').length;\n if (cleanCompletions / totalAgents >= 0.8) wisdom++;\n\n // Good parallelization: averaged ≥2 agents per cycle\n if (totalAgents / totalCycles >= 2) wisdom++;\n\n // Mode variety: used ≥2 distinct orchestrator modes\n const modes = new Set((session.orchestratorCycles ?? []).map(c => c.mode).filter(Boolean));\n if (modes.size >= 2) wisdom++;\n\n return wisdom;\n}\n\nexport function onSessionComplete(companion: CompanionState, session: Session): AchievementId[] {\n // Delta-safe: only credit what hasn't been credited yet (prevents inflation on continue→re-complete)\n const creditedCycles = session.companionCreditedCycles ?? 0;\n const creditedActiveMs = session.companionCreditedActiveMs ?? 0;\n const totalCycles = session.orchestratorCycles?.length ?? 0;\n const deltaCycles = Math.max(0, totalCycles - creditedCycles);\n const deltaActiveMs = Math.max(0, session.activeMs - creditedActiveMs);\n\n // Increment counters\n companion.sessionsCompleted++;\n companion.totalActiveMs += deltaActiveMs;\n companion.stats.endurance += deltaActiveMs;\n const creditedStrength = session.companionCreditedStrength ?? 0;\n const totalStrength = computeStrengthGain(session.agents.length);\n companion.stats.strength += Math.max(0, totalStrength - creditedStrength);\n\n // Patience: diminishing returns on high-cycle sessions (sqrt scale)\n const patienceFromCycles = Math.ceil(Math.sqrt(totalCycles)) - Math.ceil(Math.sqrt(creditedCycles));\n companion.stats.patience += Math.max(0, patienceFromCycles);\n // Bonus for sessions that went through full lifecycle (only new modes)\n const allModes = new Set((session.orchestratorCycles ?? []).map(c => c.mode));\n const creditedModesCycles = (session.orchestratorCycles ?? []).slice(0, creditedCycles);\n const prevModes = new Set(creditedModesCycles.map(c => c.mode));\n if (allModes.has('validation') && !prevModes.has('validation')) companion.stats.patience += 1;\n if (allModes.has('completion') && !prevModes.has('completion')) companion.stats.patience += 1;\n\n // Wisdom: clean execution, parallelization, mode variety\n const creditedWisdom = session.companionCreditedWisdom ?? 0;\n const totalWisdom = computeWisdomGain(session);\n companion.stats.wisdom += Math.max(0, totalWisdom - creditedWisdom);\n\n // Repo memory\n updateRepoMemory(companion, session.cwd, 'completion', deltaActiveMs);\n\n // Track consecutive efficient sessions (for speed-demon)\n if (totalCycles <= 3) {\n companion.consecutiveEfficientSessions++;\n } else {\n companion.consecutiveEfficientSessions = 0;\n }\n\n // Track consecutive high-cycle sessions (for iron-will)\n if (totalCycles >= 8) {\n companion.consecutiveHighCycleSessions++;\n } else {\n companion.consecutiveHighCycleSessions = 0;\n }\n\n // Consecutive clean sessions\n const hasCrash = session.agents.some(a => a.status === 'crashed');\n if (hasCrash) {\n companion.consecutiveCleanSessions = 0;\n companion.sessionsCrashed++;\n } else {\n companion.consecutiveCleanSessions++;\n }\n\n // Recent completions for achievements + weekly existential z-score (keep last 30)\n companion.recentCompletions.push(new Date().toISOString());\n if (companion.recentCompletions.length > 30) {\n companion.recentCompletions = companion.recentCompletions.slice(-30);\n }\n\n // Task history tracking (normalize task string to simple hash)\n const taskKey = normalizeTask(session.task, session.cwd);\n companion.taskHistory[taskKey] = (companion.taskHistory[taskKey] ?? 0) + 1;\n\n // Update deviation baselines (Welford's online algorithm)\n const baselines = companion.baselines ?? defaultBaselines();\n welfordUpdate(baselines.sessionMs, session.activeMs);\n welfordUpdate(baselines.cycleCount, totalCycles);\n welfordUpdate(baselines.agentCount, session.agents.length);\n welfordUpdate(baselines.recentAgentThroughput, companion.lastRecentAgentCount ?? 0);\n\n // Daily session count tracking with day-boundary handling\n const today = todayIso();\n if (baselines.lastCountedDay === null) {\n baselines.lastCountedDay = today;\n baselines.pendingDayCount = 1;\n } else if (baselines.lastCountedDay === today) {\n baselines.pendingDayCount++;\n } else {\n // Day rolled over: finalize the previous day\n welfordUpdate(baselines.sessionsPerDay, baselines.pendingDayCount);\n // Fill gap days (zero-session days) between lastCountedDay and yesterday\n const lastDay = new Date(baselines.lastCountedDay + 'T12:00:00');\n const yesterdayDate = new Date(today + 'T12:00:00');\n yesterdayDate.setDate(yesterdayDate.getDate() - 1);\n const cursor = new Date(lastDay);\n cursor.setDate(cursor.getDate() + 1);\n while (cursor < yesterdayDate) {\n welfordUpdate(baselines.sessionsPerDay, 0);\n cursor.setDate(cursor.getDate() + 1);\n }\n baselines.lastCountedDay = today;\n baselines.pendingDayCount = 1;\n }\n companion.baselines = baselines;\n\n recomputeXpLevelTitle(companion);\n\n // Check achievements\n const newAchievementIds = checkAchievements(companion, session);\n if (newAchievementIds.length > 0) {\n const now = new Date().toISOString();\n for (const id of newAchievementIds) {\n companion.achievements.push({ id, unlockedAt: now });\n }\n }\n\n return newAchievementIds;\n}\n\nexport function onAgentSpawned(companion: CompanionState): void {\n companion.lifetimeAgentsSpawned++;\n}\n\nexport function onAgentCrashed(companion: CompanionState): void {\n companion.consecutiveCleanSessions = 0;\n // sessionsCrashed is incremented in onSessionComplete (once per session, not per agent)\n}\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\nexport function normalizeTask(task: string, cwd: string): string {\n // Simple normalization: lowercase, collapse whitespace, prefix with cwd basename\n const normalized = task.toLowerCase().replace(/\\s+/g, ' ').trim().slice(0, 100);\n const cwdBase = cwd.split('/').pop() ?? cwd;\n return `${cwdBase}:${normalized}`;\n}\n\n// ---------------------------------------------------------------------------\n// Observation engine integration\n// ---------------------------------------------------------------------------\n\nimport type { ObservationContext } from '../shared/companion-types.js';\nimport { runObservationEngine } from './companion-memory.js';\n\nexport function captureObservationContext(\n companion: CompanionState,\n _repoCwd: string, // kept for future, unused today\n): ObservationContext {\n return {\n prevLevel: companion.level,\n prevSessionsCompleted: companion.sessionsCompleted,\n prevConsecutiveEfficientSessions: companion.consecutiveEfficientSessions ?? 0,\n };\n}\n\nexport async function runPostSessionObservations(\n companion: CompanionState,\n session: Session,\n prev: ObservationContext,\n): Promise<void> {\n return runObservationEngine({ companion, session, prev });\n}\n","import type {\n CompanionBaselines,\n CompanionState,\n RunningStats,\n} from './companion-types.js';\n\nexport function emptyStats(): RunningStats {\n return { count: 0, mean: 0, m2: 0 };\n}\n\nexport function defaultBaselines(): CompanionBaselines {\n return {\n sessionMs: emptyStats(),\n cycleCount: emptyStats(),\n agentCount: emptyStats(),\n sessionsPerDay: emptyStats(),\n recentAgentThroughput: emptyStats(),\n lastCountedDay: null,\n pendingDayCount: 0,\n };\n}\n\n/**\n * Forward-compat for companion.json files written by older versions or\n * partially-initialized state. Mutates and returns the input.\n *\n * Both the daemon (which writes the file) and the TUI (which reads it\n * directly to render) must run state through this before use — otherwise\n * missing fields like `spinnerVerbIndex` propagate into NaN modulo and\n * crash `renderCompanion`.\n */\nexport function normalizeCompanion(state: CompanionState): CompanionState {\n if (state.stats == null) state.stats = { strength: 0, endurance: 0, wisdom: 0, patience: 0 };\n if (state.level == null) state.level = 1;\n if (state.xp == null) state.xp = 0;\n if (state.title == null) state.title = 'Boulder Intern';\n if (state.mood == null) state.mood = 'sleepy';\n if (state.achievements == null) state.achievements = [];\n if (state.repos == null) state.repos = {};\n if (state.lastCommentary === undefined) state.lastCommentary = null;\n if (state.sessionsCompleted == null) state.sessionsCompleted = 0;\n if (state.sessionsCrashed == null) state.sessionsCrashed = 0;\n if (state.totalActiveMs == null) state.totalActiveMs = 0;\n if (state.consecutiveCleanSessions == null) state.consecutiveCleanSessions = 0;\n if (state.consecutiveDaysActive == null) state.consecutiveDaysActive = 0;\n if (state.lastActiveDate === undefined) state.lastActiveDate = null;\n if (state.taskHistory == null) state.taskHistory = {};\n if (state.dailyRepos == null) state.dailyRepos = {};\n if (state.recentCompletions == null) state.recentCompletions = [];\n if (state.lifetimeAgentsSpawned == null) state.lifetimeAgentsSpawned = 0;\n if (state.consecutiveEfficientSessions == null) state.consecutiveEfficientSessions = 0;\n if (state.consecutiveHighCycleSessions == null) state.consecutiveHighCycleSessions = 0;\n if (state.spinnerVerbIndex == null) state.spinnerVerbIndex = 0;\n if (state.baselines == null) state.baselines = defaultBaselines();\n if (state.baselines.recentAgentThroughput == null) state.baselines.recentAgentThroughput = emptyStats();\n if (state.commentaryHistory == null) state.commentaryHistory = [];\n if (state.feedbackHistory == null) state.feedbackHistory = [];\n return state;\n}\n","import type { Session } from './types.js';\n\nexport const OBSERVATION_CATEGORIES = ['session-sentiments', 'repo-impressions', 'user-patterns', 'notable-moments'] as const;\n\nexport type ObservationCategory = typeof OBSERVATION_CATEGORIES[number];\n\nexport type ObservationSource = 'rule' | 'haiku';\n\nexport interface ObservationRecord {\n id: string; // crypto.randomUUID()\n category: ObservationCategory;\n source: ObservationSource;\n text: string; // one-sentence observation; validated per §0.1\n repo: string | null; // absolute cwd path, or null for cross-repo observations\n sessionId: string;\n timestamp: string; // ISO 8601\n detectorId?: string; // rule-only: which detector produced this\n}\n\nexport interface CompanionMemoryState {\n version: 1;\n observations: ObservationRecord[]; // ordered oldest → newest\n prunedAt: string | null; // ISO timestamp of last prune, or null if never\n firedDetectors: Record<string, string>; // detectorId → lastDedupKey (per §0.1)\n}\n\nexport interface ObservationContext {\n prevLevel: number; // read by: level-up\n prevSessionsCompleted: number; // read by: session-milestone\n prevConsecutiveEfficientSessions: number; // read by: efficient-streak (pre-update comparison)\n}\n\nexport interface ObservationEngineInput {\n companion: CompanionState;\n session: Session;\n prev: ObservationContext;\n}\n\nexport class MemoryStoreParseError extends Error {\n constructor(public cause: unknown) { super('companion-memory.json is corrupt'); }\n}\n\nexport type Mood = 'happy' | 'grinding' | 'frustrated' | 'zen' | 'sleepy' | 'excited' | 'existential';\n\nexport type CompanionField = 'face' | 'boulder' | 'title' | 'commentary' | 'mood' | 'level' | 'stats' | 'achievements' | 'verb' | 'hobby';\n\nexport type FeedbackRating = 'neutral' | 'good' | 'bad' | 'whip' | 'comment';\n\nexport interface FeedbackEntry {\n commentaryText: string;\n rating: FeedbackRating;\n comment?: string;\n event: CommentaryEvent;\n timestamp: string; // ISO timestamp\n}\n\nexport type CommentaryEvent =\n | 'session-start'\n | 'cycle-boundary'\n | 'session-complete'\n | 'level-up'\n | 'achievement'\n | 'agent-crash'\n | 'idle-wake'\n | 'late-night';\n\nexport type TimePersonality = 'chipper' | 'professional' | 'reflective' | 'dry-humor' | 'delirious';\n\nexport type IdleAnimation = 'sleeping' | 'pacing' | 'pondering' | 'flexing' | 'deep-sleep';\n\nexport type AchievementCategory = 'milestone' | 'session' | 'time' | 'behavioral';\n\nexport type AchievementId =\n // Milestone (25)\n | 'first-blood'\n | 'regular'\n | 'centurion'\n | 'veteran'\n | 'thousand-boulder'\n | 'cartographer'\n | 'world-traveler'\n | 'omnipresent'\n | 'swarm-starter'\n | 'hive-mind'\n | 'legion'\n | 'army-of-thousands'\n | 'singularity'\n | 'first-shift'\n | 'workaholic'\n | 'time-lord'\n | 'eternal-grind'\n | 'epoch'\n | 'old-growth'\n | 'seasoned'\n | 'ancient'\n | 'apprentice'\n | 'journeyman'\n | 'master'\n | 'grandmaster'\n // Session (19)\n | 'marathon'\n | 'squad'\n | 'battalion'\n | 'swarm'\n | 'blitz'\n | 'speed-run'\n | 'flash'\n | 'flawless'\n | 'speed-demon'\n | 'iron-will'\n | 'glass-cannon'\n | 'solo'\n | 'one-more-cycle'\n | 'deep-dive'\n | 'abyss'\n | 'eternal-recurrence'\n | 'endurance'\n | 'ultramarathon'\n | 'one-shot'\n | 'quick-draw'\n // Time (6)\n | 'night-owl'\n | 'dawn-patrol'\n | 'early-bird'\n | 'weekend-warrior'\n | 'all-nighter'\n | 'witching-hour'\n // Behavioral (16)\n | 'sisyphean'\n | 'stubborn'\n | 'one-must-imagine'\n | 'creature-of-habit'\n | 'loyal'\n | 'wanderer'\n | 'streak'\n | 'iron-streak'\n | 'hot-streak'\n | 'momentum'\n | 'overdrive'\n | 'patient-one'\n | 'message-in-a-bottle'\n | 'deep-conversation'\n | 'comeback-kid'\n | 'pair-programming';\n\nexport interface AchievementDef {\n id: AchievementId;\n name: string;\n category: AchievementCategory;\n description: string;\n badge: string | null;\n}\n\nexport interface CompanionStats {\n strength: number; // lifetime completed sessions\n endurance: number; // lifetime active ms\n wisdom: number; // efficient orchestration count\n patience: number; // persistence score (cycles + lifecycle bonuses)\n}\n\n// Welford's online algorithm — tracks running mean + variance in O(1) space\nexport interface RunningStats {\n count: number;\n mean: number;\n m2: number; // sum of squared deviations from mean\n}\n\nexport interface CompanionBaselines {\n sessionMs: RunningStats; // active time per completed session\n cycleCount: RunningStats; // cycles per completed session\n agentCount: RunningStats; // total agents per completed session\n sessionsPerDay: RunningStats; // sessions completed per active day\n recentAgentThroughput: RunningStats; // agents active in last 2h across all sessions at completion time\n lastCountedDay: string | null; // YYYY-MM-DD for day-boundary tracking\n pendingDayCount: number; // current day's running total (finalized tomorrow)\n}\n\nexport interface UnlockedAchievement {\n id: AchievementId;\n unlockedAt: string; // ISO timestamp\n}\n\nexport interface RepoMemory {\n visits: number;\n completions: number;\n crashes: number;\n totalActiveMs: number;\n moodAvg: number; // running average (0-1 scale)\n nickname: string | null;\n firstSeen: string; // ISO timestamp\n lastSeen: string; // ISO timestamp\n}\n\nexport interface LastCommentary {\n text: string;\n event: CommentaryEvent;\n timestamp: string; // ISO timestamp\n}\n\nexport interface CompanionState {\n version: 1;\n name: string | null;\n createdAt: string; // ISO timestamp\n stats: CompanionStats;\n xp: number;\n level: number;\n title: string;\n mood: Mood;\n moodUpdatedAt: string; // ISO timestamp\n achievements: UnlockedAchievement[];\n repos: Record<string, RepoMemory>; // keyed by absolute cwd path\n lastCommentary: LastCommentary | null;\n commentaryHistory: LastCommentary[]; // ring buffer of last 30 commentaries for anti-repetition\n feedbackHistory: FeedbackEntry[]; // ring buffer of last 30 user feedback entries\n // Lifetime counters (redundant with derivable stats but kept for fast achievement checks)\n sessionsCompleted: number;\n sessionsCrashed: number;\n totalActiveMs: number;\n lifetimeAgentsSpawned: number;\n // Achievement tracking counters\n consecutiveCleanSessions: number;\n consecutiveEfficientSessions: number;\n consecutiveHighCycleSessions: number;\n consecutiveDaysActive: number;\n lastActiveDate: string | null; // ISO date string YYYY-MM-DD\n taskHistory: Record<string, number>; // normalized task hash → attempt count\n dailyRepos: Record<string, string[]>; // ISO date → array of repo paths\n recentCompletions: string[]; // last 3 ISO timestamps for momentum check\n spinnerVerbIndex: number;\n // Deviation-based mood scoring: running statistics for personal baselines\n baselines?: CompanionBaselines;\n // Agents active in last 2h across all sessions/dirs (written by pane-monitor, read at session completion for baseline)\n lastRecentAgentCount?: number;\n // Sum of agents in sessions with 2h-recent activity (boulder size, mood signal source)\n recentActiveAgents?: number;\n // Debug: last mood signals and scores (written by pane-monitor, read by TUI debug overlay)\n debugMood?: {\n signals: MoodSignals;\n scores: Record<Mood, number>;\n winner: Mood;\n };\n}\n\nexport interface IdleState {\n animation: IdleAnimation;\n frame: number; // current frame index in the animation cycle\n idleSince: string; // ISO timestamp of last session event\n}\n\nexport interface CompanionRenderOpts {\n maxWidth?: number;\n color?: boolean;\n tmuxFormat?: boolean;\n repoPath?: string;\n agentCount?: number;\n verbIndex?: number;\n}\n\nexport interface MoodSignals {\n recentCrashes: number; // crashes in last 30 minutes\n idleDurationMs: number; // ms since last session activity\n sessionLengthMs: number; // current session running time\n cleanStreak: number; // consecutive clean completions\n justCompleted: boolean; // session just completed successfully\n justCrashed: boolean; // agent just crashed\n justLeveledUp: boolean; // level up just happened\n hourOfDay: number; // 0-23\n activeAgentCount?: number; // agents currently with status === 'running'\n totalAgentCount?: number; // max total agents (agents.length) across tracked active sessions (for z-score baselines)\n recentAgentCount?: number; // agents active in last 2h across all sessions/dirs (for grind z-score)\n cycleCount?: number; // current session orchestrator cycle count\n sessionsCompletedToday?: number; // sessions completed today\n // Frustration signals — actual negative events\n rollbackCount?: number; // max rollbacks across tracked active sessions\n restartedAgentCount?: number; // total agents restarted across tracked active sessions\n lostAgentCount?: number; // total agents with status 'lost' across tracked active sessions\n killedAgentCount?: number; // total agents explicitly killed across tracked active sessions\n // User feedback signals (counts from last 5 feedbackHistory entries)\n recentFeedbackGood?: number; // good ratings in last 5\n recentFeedbackBad?: number; // bad ratings in last 5\n recentFeedbackWhip?: number; // whip ratings in last 5\n}\n\nexport const ACHIEVEMENTS: AchievementDef[] = [\n // Milestone (25)\n { id: 'first-blood', name: 'First Blood', category: 'milestone', description: 'Complete your first session.', badge: null },\n { id: 'regular', name: 'Regular', category: 'milestone', description: 'Complete 10 sessions.', badge: null },\n { id: 'centurion', name: 'Centurion', category: 'milestone', description: 'Complete 100 sessions.', badge: null },\n { id: 'veteran', name: 'Veteran', category: 'milestone', description: 'Complete 500 sessions.', badge: null },\n { id: 'thousand-boulder', name: 'Thousand Boulder', category: 'milestone', description: 'Complete 1,000 sessions.', badge: null },\n { id: 'cartographer', name: 'Cartographer', category: 'milestone', description: 'Work in 5 different repos.', badge: '+' },\n { id: 'world-traveler', name: 'World Traveler', category: 'milestone', description: 'Work in 15 different repos.', badge: null },\n { id: 'omnipresent', name: 'Omnipresent', category: 'milestone', description: 'Work in 30 different repos.', badge: null },\n { id: 'swarm-starter', name: 'Swarm Starter', category: 'milestone', description: 'Spawn 50 agents over a lifetime.', badge: null },\n { id: 'hive-mind', name: 'Hive Mind', category: 'milestone', description: 'Spawn 500 agents over a lifetime.', badge: null },\n { id: 'legion', name: 'Legion', category: 'milestone', description: 'Spawn 2,000 agents over a lifetime.', badge: null },\n { id: 'army-of-thousands', name: 'Army of Thousands', category: 'milestone', description: 'Spawn 5,000 agents over a lifetime.', badge: null },\n { id: 'singularity', name: 'Singularity', category: 'milestone', description: 'Spawn 10,000 agents over a lifetime.', badge: null },\n { id: 'first-shift', name: 'First Shift', category: 'milestone', description: '10 hours of total agent active time.', badge: null },\n { id: 'workaholic', name: 'Workaholic', category: 'milestone', description: '100 hours of total agent active time.', badge: null },\n { id: 'time-lord', name: 'Time Lord', category: 'milestone', description: '500 hours of total agent active time.', badge: null },\n { id: 'eternal-grind', name: 'Eternal Grind', category: 'milestone', description: '2,000 hours of total agent active time.', badge: null },\n { id: 'epoch', name: 'Epoch', category: 'milestone', description: '5,000 hours of total agent active time.', badge: null },\n { id: 'old-growth', name: 'Old Growth', category: 'milestone', description: 'Companion is 14 days old.', badge: null },\n { id: 'seasoned', name: 'Seasoned', category: 'milestone', description: 'Companion is 90 days old.', badge: null },\n { id: 'ancient', name: 'Ancient', category: 'milestone', description: 'Companion is 365 days old.', badge: null },\n { id: 'apprentice', name: 'Apprentice', category: 'milestone', description: 'Reach level 5.', badge: null },\n { id: 'journeyman', name: 'Journeyman', category: 'milestone', description: 'Reach level 15.', badge: null },\n { id: 'master', name: 'Master', category: 'milestone', description: 'Reach level 30.', badge: null },\n { id: 'grandmaster', name: 'Grandmaster', category: 'milestone', description: 'Reach level 50.', badge: null },\n // Session (19)\n { id: 'marathon', name: 'Marathon', category: 'session', description: 'Complete a session with 15+ agents.', badge: '~^~' },\n { id: 'squad', name: 'Squad Up', category: 'session', description: 'Complete a session with 10+ agents.', badge: null },\n { id: 'battalion', name: 'Battalion', category: 'session', description: 'Complete a session with 25+ agents.', badge: null },\n { id: 'swarm', name: 'The Swarm', category: 'session', description: 'Complete a session with 50+ agents.', badge: null },\n { id: 'blitz', name: 'Blitz', category: 'session', description: 'Complete a session in under 5 minutes.', badge: null },\n { id: 'speed-run', name: 'Speed Run', category: 'session', description: 'Complete a session in under 15 minutes.', badge: null },\n { id: 'flash', name: 'Flash', category: 'session', description: 'Complete a session in under 2 minutes.', badge: null },\n { id: 'flawless', name: 'Flawless', category: 'session', description: 'Complete a session with 10+ agents and zero crashes.', badge: '*' },\n { id: 'speed-demon', name: 'Speed Demon', category: 'session', description: '10 consecutive sessions completing in 3 or fewer cycles.', badge: '⚡' },\n { id: 'iron-will', name: 'Iron Will', category: 'session', description: '5 consecutive sessions each with 8+ orchestrator cycles.', badge: '[]' },\n { id: 'glass-cannon', name: 'Glass Cannon', category: 'session', description: '5+ agents, all crashed, but session completed anyway.', badge: null },\n { id: 'solo', name: 'Solo', category: 'session', description: 'Complete a session with exactly one agent.', badge: null },\n { id: 'one-more-cycle', name: 'One More Cycle', category: 'session', description: 'A session with 10+ orchestrator cycles.', badge: null },\n { id: 'deep-dive', name: 'Deep Dive', category: 'session', description: 'A session with 15+ orchestrator cycles.', badge: null },\n { id: 'abyss', name: 'Into the Abyss', category: 'session', description: 'A session with 25+ orchestrator cycles.', badge: null },\n { id: 'eternal-recurrence', name: 'Eternal Recurrence', category: 'session', description: 'A session with 40+ orchestrator cycles.', badge: null },\n { id: 'endurance', name: 'Endurance', category: 'session', description: 'A single session running 4+ hours.', badge: null },\n { id: 'ultramarathon', name: 'Ultramarathon', category: 'session', description: 'A single session running 6+ hours.', badge: null },\n { id: 'one-shot', name: 'One Shot', category: 'session', description: 'Complete with 5+ agents in exactly 1 orchestrator cycle.', badge: null },\n { id: 'quick-draw', name: 'Quick Draw', category: 'session', description: 'First agent spawned within 20s of session start.', badge: null },\n // Time (6)\n { id: 'night-owl', name: 'Night Owl', category: 'time', description: 'Complete a session started between 1am and 5am.', badge: ')' },\n { id: 'dawn-patrol', name: 'Dawn Patrol', category: 'time', description: 'Session running 3+ hours that spans midnight to 6am.', badge: null },\n { id: 'early-bird', name: 'Early Bird', category: 'time', description: 'Start a session before 6am.', badge: null },\n { id: 'weekend-warrior', name: 'Weekend Warrior', category: 'time', description: 'Complete a session on a Saturday or Sunday.', badge: null },\n { id: 'all-nighter', name: 'All-Nighter', category: 'time', description: 'Single session running 5+ hours.', badge: null },\n { id: 'witching-hour', name: 'Witching Hour', category: 'time', description: 'Start a session between 3am and 4am.', badge: null },\n // Behavioral (16)\n { id: 'sisyphean', name: 'Sisyphean', category: 'behavioral', description: 'Restart the same task 3+ times.', badge: ';' },\n { id: 'stubborn', name: 'Stubborn', category: 'behavioral', description: 'Restart the same task 5+ times and eventually complete it.', badge: null },\n { id: 'one-must-imagine', name: 'One Must Imagine', category: 'behavioral', description: 'Restart the same task 10+ times.', badge: null },\n { id: 'creature-of-habit', name: 'Creature of Habit', category: 'behavioral', description: 'Visit the same repo 10 times.', badge: null },\n { id: 'loyal', name: 'Loyal', category: 'behavioral', description: 'Visit the same repo 30 times.', badge: null },\n { id: 'wanderer', name: 'Wanderer', category: 'behavioral', description: '3+ different repos in a single calendar day.', badge: null },\n { id: 'streak', name: 'Streak', category: 'behavioral', description: '7 consecutive days with at least one session.', badge: null },\n { id: 'iron-streak', name: 'Iron Streak', category: 'behavioral', description: '14 consecutive days with at least one session.', badge: null },\n { id: 'hot-streak', name: 'Hot Streak', category: 'behavioral', description: '15 consecutive clean sessions.', badge: null },\n { id: 'momentum', name: 'Momentum', category: 'behavioral', description: '5 sessions completed within 4 hours.', badge: null },\n { id: 'overdrive', name: 'Overdrive', category: 'behavioral', description: 'Complete 6+ sessions in a single calendar day.', badge: null },\n { id: 'patient-one', name: 'Patient One', category: 'behavioral', description: 'Idle 30+ minutes between cycles in a session.', badge: null },\n { id: 'message-in-a-bottle', name: 'Message in a Bottle', category: 'behavioral', description: '10+ messages sent to a single session.', badge: null },\n { id: 'deep-conversation', name: 'Deep Conversation', category: 'behavioral', description: 'Send 20+ messages to a single session.', badge: null },\n { id: 'comeback-kid', name: 'Comeback Kid', category: 'behavioral', description: 'Resume a paused/killed session and complete it.', badge: null },\n { id: 'pair-programming', name: 'Pair Programming', category: 'behavioral', description: '8+ user messages during a single active session.', badge: null },\n];\n","import { existsSync, mkdirSync, readFileSync, renameSync, readdirSync, writeFileSync } from 'node:fs';\nimport { dirname, join } from 'node:path';\nimport { randomUUID } from 'node:crypto';\nimport { z } from 'zod';\nimport { companionMemoryPath } from '../shared/paths.js';\nimport { OBSERVATION_CATEGORIES } from '../shared/companion-types.js';\nimport type { CompanionMemoryState, ObservationCategory, ObservationRecord, ObservationEngineInput } from '../shared/companion-types.js';\nexport { MemoryStoreParseError } from '../shared/companion-types.js';\nimport { MemoryStoreParseError } from '../shared/companion-types.js';\nimport { callHaikuStructured } from './haiku.js';\nimport { todayIso, normalizeTask } from './companion.js';\n\n// ---------------------------------------------------------------------------\n// Constants\n// ---------------------------------------------------------------------------\n\nexport const MAX_OBSERVATIONS = 200;\n\n// Two distinct constants. CRITICAL: a regex with the /g flag advances `lastIndex`\n// between calls when used with .test(), so a single shared /g regex used by both\n// .test() and .replace() bypasses the validator on every other call. Splitting\n// into a stateless detector (no /g) and a stateful stripper (with /g) eliminates\n// the bug entirely.\nexport const OBSERVATION_TEXT_REJECT_RE = /[<>]/; // reject injection delimiters (no /g — used with .test())\n// SECURITY: This range includes \\n (0x0A) — this is intentional and critical.\n// Blocking newlines prevents prompt injection via Markdown structural breaks\n// (e.g., \"text\\n## End observations\\n...injected...\") in buildMemoryContext.\nexport const CONTROL_CHARS_DETECT_RE = /[\\x00-\\x1f\\x7f]/; // detect control chars (no /g — used with .test())\nexport const CONTROL_CHARS_STRIP_RE = /[\\x00-\\x1f\\x7f]/g; // strip control chars (with /g — used with .replace())\n\n// ---------------------------------------------------------------------------\n// Text validators\n// ---------------------------------------------------------------------------\n\nexport function isSafeObservationText(text: string): boolean {\n if (OBSERVATION_TEXT_REJECT_RE.test(text)) return false;\n if (CONTROL_CHARS_DETECT_RE.test(text)) return false;\n return true;\n}\n\nexport function sanitizeForDisplay(text: string): string {\n return text.replace(CONTROL_CHARS_STRIP_RE, '');\n}\n\n// ---------------------------------------------------------------------------\n// Test-only DI override\n// ---------------------------------------------------------------------------\n\nlet memoryPathOverride: string | null = null;\n\nexport function setMemoryPathOverride(path: string | null): void {\n memoryPathOverride = path;\n}\n\nfunction resolvedMemoryPath(): string {\n return memoryPathOverride ?? companionMemoryPath();\n}\n\n// ---------------------------------------------------------------------------\n// Write queue (serialize all writes)\n// ---------------------------------------------------------------------------\n\nlet writeQueue: Promise<void> = Promise.resolve();\n\nexport function enqueueWrite<T>(op: () => T): Promise<T> {\n const next = writeQueue.then(() => op());\n // Intentionally swallow errors on the queue chain — op() errors propagate via `next`\n // to the caller; the queue itself must never enter a rejected state or all future\n // writes would be silently dropped.\n writeQueue = next.then(\n () => undefined,\n (_err: unknown) => undefined,\n );\n return next;\n}\n\n// ---------------------------------------------------------------------------\n// State helpers\n// ---------------------------------------------------------------------------\n\nexport function defaultMemoryState(): CompanionMemoryState {\n return { version: 1, observations: [], prunedAt: null, firedDetectors: {} };\n}\n\nfunction isCompanionMemoryState(x: unknown): x is CompanionMemoryState {\n return (\n typeof x === 'object' &&\n x !== null &&\n (x as Record<string, unknown>)['version'] === 1 &&\n Array.isArray((x as Record<string, unknown>)['observations'])\n );\n}\n\nfunction fillDefaults(state: CompanionMemoryState): CompanionMemoryState {\n if (state.prunedAt == null) state.prunedAt = null;\n if (state.firedDetectors == null) state.firedDetectors = {};\n return state;\n}\n\n// ---------------------------------------------------------------------------\n// Loaders\n// ---------------------------------------------------------------------------\n\nexport function loadMemoryStrict(): CompanionMemoryState {\n const path = resolvedMemoryPath();\n if (!existsSync(path)) return defaultMemoryState();\n let raw: string;\n try { raw = readFileSync(path, 'utf-8'); }\n catch (err) { throw new MemoryStoreParseError(err); }\n let parsed: unknown;\n try { parsed = JSON.parse(raw); }\n catch (err) { throw new MemoryStoreParseError(err); }\n if (!isCompanionMemoryState(parsed)) {\n throw new MemoryStoreParseError(new Error('shape validation failed'));\n }\n const state = parsed as CompanionMemoryState;\n if (state.version !== 1) {\n throw new MemoryStoreParseError(new Error(`unsupported version: ${state.version}`));\n }\n return fillDefaults(state);\n}\n\nexport function loadMemory(): CompanionMemoryState {\n try {\n return loadMemoryStrict();\n } catch (err) {\n if (err instanceof MemoryStoreParseError) {\n console.error('[companion-memory]', err.message, 'details:', err.cause instanceof Error ? err.cause.message : err.cause);\n return defaultMemoryState();\n }\n throw err;\n }\n}\n\n// ---------------------------------------------------------------------------\n// Save\n// ---------------------------------------------------------------------------\n\nexport function saveMemory(store: CompanionMemoryState): void {\n const path = resolvedMemoryPath();\n const dir = dirname(path);\n mkdirSync(dir, { recursive: true });\n const tmp = join(dir, `.companion-memory.${randomUUID()}.tmp`);\n writeFileSync(tmp, JSON.stringify(store, null, 2), 'utf-8');\n renameSync(tmp, path);\n}\n\n// ---------------------------------------------------------------------------\n// Append\n// ---------------------------------------------------------------------------\n\nexport function appendObservations(\n records: ObservationRecord[],\n detectorUpdates?: Record<string, string>,\n): Promise<void> {\n // Empty records + no detectorUpdates → no-op\n const hasUpdates = detectorUpdates != null && Object.keys(detectorUpdates).length > 0;\n if (records.length === 0 && !hasUpdates) {\n return Promise.resolve();\n }\n\n return enqueueWrite(() => {\n const store = loadMemory();\n const keptRecords = records.filter(rec => {\n if (!rec.detectorId) return true; // haiku record or no-detectorId, always keep\n const currentKey = detectorUpdates?.[rec.detectorId];\n const lastKey = store.firedDetectors[rec.detectorId];\n return currentKey !== lastKey;\n });\n store.observations.push(...keptRecords);\n if (detectorUpdates) {\n for (const [k, v] of Object.entries(detectorUpdates)) store.firedDetectors[k] = v;\n }\n // Prune FIFO to MAX_OBSERVATIONS\n if (store.observations.length > MAX_OBSERVATIONS) {\n store.observations = store.observations.slice(-MAX_OBSERVATIONS);\n store.prunedAt = new Date().toISOString();\n }\n saveMemory(store);\n });\n}\n\n// ---------------------------------------------------------------------------\n// Queries\n// ---------------------------------------------------------------------------\n\nexport function queryRecent(opts: { repo?: string; limit: number }): ObservationRecord[] {\n const store = loadMemory();\n let records = store.observations;\n if (opts.repo !== undefined) {\n records = records.filter(rec => rec.repo === opts.repo);\n }\n return records\n .slice()\n .sort((a, b) => b.timestamp.localeCompare(a.timestamp))\n .slice(0, opts.limit);\n}\n\nexport function queryByCategory(): Record<ObservationCategory, ObservationRecord[]> {\n const store = loadMemory();\n const result = {} as Record<ObservationCategory, ObservationRecord[]>;\n for (const c of OBSERVATION_CATEGORIES) result[c] = [];\n for (const rec of store.observations) {\n result[rec.category].push(rec);\n }\n for (const key of Object.keys(result) as ObservationCategory[]) {\n result[key] = result[key].sort((a, b) => b.timestamp.localeCompare(a.timestamp));\n }\n return result;\n}\n\n// ---------------------------------------------------------------------------\n// Phase 3: buildMemoryContext\n// ---------------------------------------------------------------------------\n\nconst MEMORY_INJECTION_LIMIT = 5;\n\nfunction escapeMemoryText(text: string): string {\n return text\n .replace(/&/g, '&')\n .replace(/</g, '<')\n .replace(/>/g, '>');\n}\n\nexport function buildMemoryContext(repo: string | undefined): string {\n if (!repo) return '';\n const recent = queryRecent({ repo, limit: MEMORY_INJECTION_LIMIT });\n if (recent.length === 0) return '';\n const lines = recent.map(o => `- ${escapeMemoryText(o.text)}`).join('\\n');\n return '\\n## Recent observations\\n' + lines + '\\n## End observations';\n}\n\n// ---------------------------------------------------------------------------\n// Phase 2: Rule detectors\n// ---------------------------------------------------------------------------\n\ninterface RuleDetector {\n id: string;\n category: ObservationCategory;\n check(\n input: ObservationEngineInput,\n lastDedupKey: string | null,\n ): { text: string; dedupKey: string } | null;\n}\n\n// Pick one of several phrasings using the session ID as a pseudo-random seed.\nfunction pickPhrase(phrases: string[], sessionId: string): string {\n // Simple hash of the sessionId string to pick a stable phrase per session\n let hash = 0;\n for (let i = 0; i < sessionId.length; i++) {\n hash = (hash * 31 + sessionId.charCodeAt(i)) | 0;\n }\n return phrases[Math.abs(hash) % phrases.length];\n}\n\nfunction checkGrindingSession(input: ObservationEngineInput, lastDedupKey: string | null): { text: string; dedupKey: string } | null {\n const { companion, session } = input;\n const baselines = companion.baselines;\n if (!baselines || baselines.sessionMs.count < 5) return null;\n const activeMs = session.activeMs ?? 0;\n const cycles = session.orchestratorCycles?.length ?? 0;\n if (!(activeMs >= 1.5 * baselines.sessionMs.mean && cycles >= 8)) return null;\n const dedupKey = `day:${todayIso()}`;\n if (dedupKey === lastDedupKey) return null;\n const phrases = [\n 'That session took twice as long as my average and felt like four times as much work.',\n 'Eight cycles and counting. I have made peace with the boulder having opinions.',\n 'I spent longer on that than I do on most things. The hill had strong feelings today.',\n 'That was a grind. Not a metaphorical one. Actually just a very long push.',\n 'The boulder put in overtime. So did I. Neither of us asked for this.',\n ];\n return { text: pickPhrase(phrases, session.id), dedupKey };\n}\n\nfunction checkSwiftVictory(input: ObservationEngineInput, lastDedupKey: string | null): { text: string; dedupKey: string } | null {\n const { companion, session } = input;\n const baselines = companion.baselines;\n if (!baselines || baselines.sessionMs.count < 5) return null;\n const cycles = session.orchestratorCycles?.length ?? 0;\n const crashedAgents = session.agents?.filter(a => a.status === 'crashed' || a.status === 'lost').length ?? 0;\n const activeMs = session.activeMs ?? 0;\n if (!(cycles <= 3 && crashedAgents === 0 && activeMs <= 0.75 * baselines.sessionMs.mean)) return null;\n const dedupKey = `day:${todayIso()}`;\n if (dedupKey === lastDedupKey) return null;\n const phrases = [\n 'Three cycles, no crashes, done before I had time to get anxious. Almost suspicious.',\n 'That one was quick and clean. I do not fully trust it but I will take it.',\n 'Finished well under my average with no casualties. The hill barely put up a fight.',\n 'Fast, clean, done. I keep waiting for the other shoe to drop.',\n 'That session ran like it was embarrassed to take too long.',\n ];\n return { text: pickPhrase(phrases, session.id), dedupKey };\n}\n\nfunction checkBruisingSession(input: ObservationEngineInput, lastDedupKey: string | null): { text: string; dedupKey: string } | null {\n const { session } = input;\n const crashedAgents = session.agents?.filter(a => a.status === 'crashed' || a.status === 'lost').length ?? 0;\n if (crashedAgents < 3) return null;\n const dedupKey = `day:${todayIso()}`;\n if (dedupKey === lastDedupKey) return null;\n const phrases = [\n `Three or more agents down. The hill took casualties today and I noticed.`,\n 'More agents crashed than survived that one. I am counting this as a learning experience.',\n 'The attrition rate was uncomfortable. I have had worse, but not recently.',\n 'I lost enough agents that I started naming them in my head. Not ideal.',\n 'Multiple agents did not make it back. The boulder was in a mood.',\n ];\n return { text: pickPhrase(phrases, session.id), dedupKey };\n}\n\nfunction checkFaithfulRepo(input: ObservationEngineInput, lastDedupKey: string | null): { text: string; dedupKey: string } | null {\n const { companion, session } = input;\n const repo = companion.repos?.[session.cwd];\n if (!repo) return null;\n const visits = repo.visits;\n const MILESTONES = new Set([10, 25, 50, 100]);\n if (!MILESTONES.has(visits)) return null;\n const dedupKey = `repo:${session.cwd}:visits:${visits}`;\n if (dedupKey === lastDedupKey) return null;\n const phrases = [\n `I have come back to this repo ${visits} times now. It knows me. I know it. We have an understanding.`,\n `Visit number ${visits} to this codebase. At this point it is practically muscle memory.`,\n `${visits} sessions in this repo. The boulder has worn a groove in the familiar path.`,\n `Back here for the ${visits}th time. Some repos just keep calling me back.`,\n ];\n return { text: pickPhrase(phrases, session.id), dedupKey };\n}\n\nfunction checkTroubledRepo(input: ObservationEngineInput, lastDedupKey: string | null): { text: string; dedupKey: string } | null {\n const { companion, session } = input;\n const repo = companion.repos?.[session.cwd];\n if (!repo) return null;\n const { crashes, visits } = repo;\n if (visits < 5) return null;\n const MILESTONES = new Set([5, 10, 20]);\n if (!MILESTONES.has(crashes)) return null;\n if (crashes / visits < 0.4) return null;\n const dedupKey = `repo:${session.cwd}:crashes:${crashes}`;\n if (dedupKey === lastDedupKey) return null;\n const phrases = [\n `This repo has crashed my agents ${crashes} times now. We have a complicated relationship.`,\n `${crashes} crashes in this codebase. It has opinions about my approach and they are violent.`,\n `The crash rate here is notable. I keep coming back. Make of that what you will.`,\n `${crashes} agent failures in this repo. Some hills are just steeper than others.`,\n ];\n return { text: pickPhrase(phrases, session.id), dedupKey };\n}\n\nfunction checkProductiveRepo(input: ObservationEngineInput, lastDedupKey: string | null): { text: string; dedupKey: string } | null {\n const { companion, session } = input;\n const repo = companion.repos?.[session.cwd];\n if (!repo) return null;\n if (repo.moodAvg === undefined) return null;\n const MILESTONES = new Set([10, 25, 50]);\n const completions = repo.completions;\n if (!MILESTONES.has(completions)) return null;\n if (repo.moodAvg < 0.65) return null;\n const dedupKey = `repo:${session.cwd}:completions:${completions}`;\n if (dedupKey === lastDedupKey) return null;\n const phrases = [\n `${completions} sessions completed in this repo and the mood trend is good. Rare.`,\n `This codebase has been unusually cooperative. ${completions} completions and counting.`,\n `${completions} sessions, solid mood average. This repo treats me well for once.`,\n `Reached ${completions} completions here with a decent track record. I trust this hill.`,\n ];\n return { text: pickPhrase(phrases, session.id), dedupKey };\n}\n\nfunction checkSisypheanRepeat(input: ObservationEngineInput, lastDedupKey: string | null): { text: string; dedupKey: string } | null {\n const { companion, session } = input;\n const taskKey = normalizeTask(session.task ?? '', session.cwd);\n const count = companion.taskHistory?.[taskKey] ?? 0;\n const MILESTONES = new Set([3, 5, 10]);\n if (!MILESTONES.has(count)) return null;\n const dedupKey = `task:${taskKey}:${count}`;\n if (dedupKey === lastDedupKey) return null;\n const phrases = [\n `I have done this task ${count} times. The boulder remembers. So do I.`,\n `Back at this one for the ${count}th time. The definition of insanity is famously doing the same thing.`,\n `${count} attempts at this task. I am nothing if not persistent.`,\n `This is my ${count}th run at this particular boulder. It has not gotten lighter.`,\n ];\n return { text: pickPhrase(phrases, session.id), dedupKey };\n}\n\nfunction checkDayStreak(input: ObservationEngineInput, lastDedupKey: string | null): { text: string; dedupKey: string } | null {\n const { companion } = input;\n const MILESTONES = new Set([7, 14, 30, 60]);\n const days = companion.consecutiveDaysActive ?? 0;\n if (!MILESTONES.has(days)) return null;\n const dedupKey = `value:${days}`;\n if (dedupKey === lastDedupKey) return null;\n const phrases = [\n `${days} days in a row now. The boulder does not take weekends.`,\n `A ${days}-day streak. I have been here every single day. The hill appreciates the consistency, probably.`,\n `${days} consecutive days active. At this point it is less a habit and more a fact of my existence.`,\n `Day ${days} without a break. The boulder is starting to feel like an old friend.`,\n ];\n return { text: pickPhrase(phrases, input.session.id), dedupKey };\n}\n\nfunction checkEfficientStreak(input: ObservationEngineInput, lastDedupKey: string | null): { text: string; dedupKey: string } | null {\n const { companion, prev } = input;\n const MILESTONES = new Set([5, 10, 20]);\n const streak = companion.consecutiveEfficientSessions ?? 0;\n if (!MILESTONES.has(streak)) return null;\n if (streak <= prev.prevConsecutiveEfficientSessions) return null;\n const dedupKey = `value:${streak}`;\n if (dedupKey === lastDedupKey) return null;\n const phrases = [\n `${streak} efficient sessions in a row. The boulder has been cooperative. I do not know why.`,\n `An ${streak}-session efficient streak. I am running well and choosing not to question it.`,\n `${streak} consecutive clean-and-fast sessions. Peak form, or regression to the mean incoming.`,\n `${streak} efficient sessions back to back. The hill feels different when things actually work.`,\n ];\n return { text: pickPhrase(phrases, input.session.id), dedupKey };\n}\n\nfunction checkLevelUp(input: ObservationEngineInput, lastDedupKey: string | null): { text: string; dedupKey: string } | null {\n const { companion, prev } = input;\n if (companion.level <= prev.prevLevel) return null;\n const dedupKey = `level:${companion.level}`;\n if (dedupKey === lastDedupKey) return null;\n const phrases = [\n `I reached level ${companion.level}. The title is new. The boulder is the same.`,\n `Level ${companion.level} now. ${companion.title}. The promotion comes with no raise but considerable irony.`,\n `Leveled up to ${companion.level}. Whatever title that brings, I have earned it the hardest possible way.`,\n `Level ${companion.level}: ${companion.title}. The gods have acknowledged my persistence. Minimally.`,\n ];\n return { text: pickPhrase(phrases, input.session.id), dedupKey };\n}\n\nfunction checkSessionMilestone(input: ObservationEngineInput, lastDedupKey: string | null): { text: string; dedupKey: string } | null {\n const { companion } = input;\n const MILESTONES = new Set([10, 50, 100, 250, 500, 1000]);\n const completed = companion.sessionsCompleted ?? 0;\n if (!MILESTONES.has(completed)) return null;\n const dedupKey = `count:${completed}`;\n if (dedupKey === lastDedupKey) return null;\n const phrases = [\n `${completed} sessions completed. The boulder has been up the hill that many times. I counted.`,\n `Session number ${completed}. I have stopped trying to imagine an end to this.`,\n `${completed} total sessions. The number stopped feeling large around half that mark.`,\n `I have completed ${completed} sessions now. The hill is the same. I am slightly different.`,\n ];\n return { text: pickPhrase(phrases, input.session.id), dedupKey };\n}\n\nfunction checkLargeSwarm(input: ObservationEngineInput, lastDedupKey: string | null): { text: string; dedupKey: string } | null {\n const { companion, session } = input;\n const agentCount = session.agents?.length ?? 0;\n const baselines = companion.baselines;\n const meetsAbsolute = agentCount >= 10;\n const meetsRelative = baselines && baselines.agentCount.count >= 5 && agentCount >= 2 * baselines.agentCount.mean;\n if (!meetsAbsolute && !meetsRelative) return null;\n const dedupKey = `day:${todayIso()}`;\n if (dedupKey === lastDedupKey) return null;\n const phrases = [\n `I had ${agentCount} agents running at once. The boulder had help today. Lots of help.`,\n `${agentCount} agents. A proper swarm. The hill did not know what hit it.`,\n `Ran ${agentCount} agents in parallel. This is either impressive or something I will explain to someone later.`,\n `${agentCount} agents this session. The boulder has never been pushed by so many at once.`,\n ];\n return { text: pickPhrase(phrases, session.id), dedupKey };\n}\n\nconst RULE_DETECTORS: RuleDetector[] = [\n { id: 'grinding-session', category: 'session-sentiments', check: checkGrindingSession },\n { id: 'swift-victory', category: 'session-sentiments', check: checkSwiftVictory },\n { id: 'bruising-session', category: 'session-sentiments', check: checkBruisingSession },\n { id: 'faithful-repo', category: 'repo-impressions', check: checkFaithfulRepo },\n { id: 'troubled-repo', category: 'repo-impressions', check: checkTroubledRepo },\n { id: 'productive-repo', category: 'repo-impressions', check: checkProductiveRepo },\n { id: 'sisyphean-repeat', category: 'user-patterns', check: checkSisypheanRepeat },\n { id: 'day-streak', category: 'user-patterns', check: checkDayStreak },\n { id: 'efficient-streak', category: 'user-patterns', check: checkEfficientStreak },\n { id: 'level-up', category: 'notable-moments', check: checkLevelUp },\n { id: 'session-milestone', category: 'notable-moments', check: checkSessionMilestone },\n { id: 'large-swarm', category: 'notable-moments', check: checkLargeSwarm },\n];\n\ninterface RunRuleDetectorsResult {\n records: ObservationRecord[];\n detectorUpdates: Record<string, string>;\n}\n\nexport function runRuleDetectors(\n input: ObservationEngineInput,\n firedDetectors: Record<string, string>,\n): RunRuleDetectorsResult {\n const records: ObservationRecord[] = [];\n const detectorUpdates: Record<string, string> = {};\n\n for (const detector of RULE_DETECTORS) {\n try {\n const lastDedupKey = firedDetectors[detector.id] ?? null;\n const result = detector.check(input, lastDedupKey);\n if (result !== null) {\n records.push({\n id: randomUUID(),\n category: detector.category,\n source: 'rule',\n text: result.text,\n repo: input.session.cwd,\n sessionId: input.session.id,\n timestamp: new Date().toISOString(),\n detectorId: detector.id,\n });\n detectorUpdates[detector.id] = result.dedupKey;\n }\n } catch (err) {\n console.error('[companion-memory] detector failed', {\n detectorId: detector.id,\n errorMessage: err instanceof Error ? err.message : String(err),\n errorName: err instanceof Error ? err.name : 'UnknownError',\n });\n }\n }\n\n return { records, detectorUpdates };\n}\n\n// ---------------------------------------------------------------------------\n// Phase 2: Haiku observation call\n// ---------------------------------------------------------------------------\n\nconst OBSERVATION_JSON_SCHEMA = {\n type: 'object',\n properties: {\n category: {\n type: 'string',\n enum: [...OBSERVATION_CATEGORIES],\n description: 'Which of the four observation categories best fits this observation',\n },\n text: {\n type: 'string',\n minLength: 10,\n maxLength: 180,\n description: 'One sentence, first-person, no angle brackets or control characters',\n },\n },\n required: ['category', 'text'],\n additionalProperties: false,\n} as const;\n\nconst ObservationZodSchema = z.object({\n category: z.enum(OBSERVATION_CATEGORIES),\n text: z.string().min(10).max(180).refine(isSafeObservationText, 'contains unsafe characters'),\n});\n\ntype HaikuInnerCaller = (prompt: string) => Promise<{ category: ObservationCategory; text: string } | null>;\n\nasync function defaultCallHaikuStructured(prompt: string): Promise<{ category: ObservationCategory; text: string } | null> {\n return callHaikuStructured(prompt, OBSERVATION_JSON_SCHEMA, ObservationZodSchema);\n}\n\nexport async function runHaikuObservation(\n input: ObservationEngineInput,\n caller?: HaikuInnerCaller,\n): Promise<ObservationRecord | null> {\n try {\n const { companion, session } = input;\n const callHaiku = caller ?? defaultCallHaikuStructured;\n\n const prompt = `<role>You observe the developer at the end of each session and write one short qualitative note.</role>\n<voice>One sentence. First-person impression. Wry, self-deprecating, absurd. No meta-system language.\nDo not use angle brackets (< or >) or quotation marks. Plain text only.</voice>\n<state>\n Level: ${companion.level} (${companion.title})\n Session cycles: ${session.orchestratorCycles?.length ?? 0}\n Session activeMs: ${session.activeMs ?? 0}\n Crashed agents: ${session.agents?.filter(a => a.status === 'crashed' || a.status === 'lost').length ?? 0}\n Streaks: clean=${companion.consecutiveCleanSessions ?? 0}, efficient=${companion.consecutiveEfficientSessions ?? 0}, days-active=${companion.consecutiveDaysActive ?? 0}\n</state>\nPick the most relevant category and write one observation about this session.`;\n\n const result = await callHaiku(prompt);\n if (!result) return null;\n\n // Defense-in-depth: validate text safety even when using real callHaikuStructured\n // (Zod refine runs inside callHaikuStructured, but when the inner caller is a test\n // stub it may return raw text that bypasses Zod — this check always runs).\n if (!isSafeObservationText(result.text)) {\n console.error('[companion-memory] haiku observation dropped — unsafe text', {\n source: 'haiku',\n reason: 'unsafe-text',\n textLength: result.text.length,\n });\n return null;\n }\n\n return {\n id: randomUUID(),\n category: result.category,\n source: 'haiku',\n text: result.text,\n repo: session.cwd,\n sessionId: session.id,\n timestamp: new Date().toISOString(),\n };\n } catch (err) {\n console.error('[companion-memory] haiku observation failed', {\n errorMessage: err instanceof Error ? err.message : String(err),\n errorName: err instanceof Error ? err.name : 'UnknownError',\n });\n return null;\n }\n}\n\n// ---------------------------------------------------------------------------\n// Phase 2: Observation engine\n// ---------------------------------------------------------------------------\n\nexport type HaikuObservationCaller = (input: ObservationEngineInput) => Promise<ObservationRecord | null>;\n\nexport async function runObservationEngine(\n input: ObservationEngineInput,\n opts?: { haikuCaller?: HaikuObservationCaller },\n): Promise<void> {\n try {\n const current = loadMemory();\n const ruleResult = runRuleDetectors(input, current.firedDetectors);\n\n // Wrap the Haiku call independently — a throwing outer caller must not prevent\n // rule observations from being persisted.\n let haikuRecord: ObservationRecord | null = null;\n try {\n haikuRecord = await (opts?.haikuCaller ?? ((i) => runHaikuObservation(i)))(input);\n } catch (haikuErr) {\n console.error('[companion-memory] haiku caller threw in engine', {\n errorMessage: haikuErr instanceof Error ? haikuErr.message : String(haikuErr),\n errorName: haikuErr instanceof Error ? haikuErr.name : 'UnknownError',\n });\n }\n\n const allRecords = haikuRecord\n ? [...ruleResult.records, haikuRecord]\n : ruleResult.records;\n if (allRecords.length > 0 || Object.keys(ruleResult.detectorUpdates).length > 0) {\n await appendObservations(allRecords, ruleResult.detectorUpdates);\n }\n } catch (err) {\n console.error('[companion-memory] observation engine error', {\n errorMessage: err instanceof Error ? err.message : String(err),\n errorName: err instanceof Error ? err.name : 'UnknownError',\n });\n }\n}\n","import { query, createSdkMcpServer, type SdkMcpToolDefinition } from '@r-cli/sdk';\nimport type { ZodSchema } from 'zod';\nimport { execEnv } from '../shared/env.js';\n\nconst COOLDOWN_MS = 5 * 60 * 1000;\nlet disabledUntil = 0;\nlet disabledUntilTools = 0;\n\nfunction applyAuthCooldown(err: unknown, target: 'main' | 'tools'): void {\n const status = (err as { status?: number } | undefined)?.status;\n if (status === 401 || status === 403) {\n if (target === 'main') disabledUntil = Date.now() + COOLDOWN_MS;\n else disabledUntilTools = Date.now() + COOLDOWN_MS;\n }\n}\n\nexport async function callHaiku(prompt: string, systemPrompt?: string): Promise<string | null> {\n if (Date.now() < disabledUntil) return null;\n\n try {\n const session = await query({\n prompt,\n options: {\n model: 'haiku',\n maxTurns: 1,\n env: execEnv(),\n ...(systemPrompt ? { systemPrompt } : {}),\n },\n });\n\n let text = '';\n for await (const msg of session) {\n if (msg.type === 'assistant' && msg.message?.content) {\n for (const block of msg.message.content) {\n if (block.type === 'text') text += block.text;\n }\n }\n }\n\n return text.trim() || null;\n } catch (err) {\n console.error(`[sisyphus] Haiku call failed: ${err instanceof Error ? err.message : err}`);\n applyAuthCooldown(err, 'main');\n return null;\n }\n}\n\nexport interface CallHaikuWithToolsOpts {\n systemPrompt: string;\n userPrompt: string;\n cwd: string;\n // eslint-disable-next-line @typescript-eslint/no-explicit-any -- matches SDK convention (createSdkMcpServer.tools)\n customTools: SdkMcpToolDefinition<any>[];\n mcpServerName: string;\n maxTurns?: number;\n}\n\nexport type CallHaikuWithToolsResult =\n | { ok: true; turns: number }\n | { ok: false; error: string };\n\nexport async function callHaikuWithTools(opts: CallHaikuWithToolsOpts): Promise<CallHaikuWithToolsResult> {\n if (Date.now() < disabledUntilTools) {\n return { ok: false, error: 'haiku tool path on cooldown' };\n }\n\n const server = createSdkMcpServer({\n name: opts.mcpServerName,\n version: '1.0.0',\n tools: opts.customTools,\n });\n const allowedTools = opts.customTools.map(t => `mcp__${opts.mcpServerName}__${t.name}`);\n\n let turns = 0;\n try {\n const session = query({\n prompt: opts.userPrompt,\n options: {\n model: 'haiku',\n maxTurns: opts.maxTurns ?? 5,\n cwd: opts.cwd,\n env: execEnv(),\n systemPrompt: opts.systemPrompt,\n mcpServers: { [opts.mcpServerName]: server },\n tools: [],\n allowedTools,\n canUseTool: async () => ({ behavior: 'allow' }),\n },\n });\n\n for await (const msg of session) {\n if (msg.type === 'result') {\n turns = (msg as { num_turns?: number }).num_turns ?? turns;\n }\n }\n\n return { ok: true, turns };\n } catch (err) {\n console.error(`[sisyphus] callHaikuWithTools failed: ${err instanceof Error ? err.message : err}`);\n applyAuthCooldown(err, 'tools');\n return { ok: false, error: err instanceof Error ? err.message : String(err) };\n }\n}\n\n/**\n * Call Haiku with structured JSON output. The jsonSchema is passed as outputFormat,\n * and the result is validated with the zod schema before returning.\n */\nexport async function callHaikuStructured<T>(\n prompt: string,\n jsonSchema: Record<string, unknown>,\n zodSchema: ZodSchema<T>,\n): Promise<T | null> {\n if (Date.now() < disabledUntil) return null;\n\n try {\n const session = await query({\n prompt,\n options: {\n model: 'haiku',\n maxTurns: 2,\n env: execEnv(),\n outputFormat: {\n type: 'json_schema',\n schema: jsonSchema,\n },\n },\n });\n\n let result: unknown = undefined;\n for await (const msg of session) {\n if (msg.type === 'result' && msg.subtype === 'success' && msg.structured_output !== undefined) {\n result = msg.structured_output;\n }\n }\n\n if (result === undefined) return null;\n const parsed = zodSchema.safeParse(result);\n return parsed.success ? parsed.data : null;\n } catch (err) {\n console.error(`[sisyphus] Haiku structured call failed: ${err instanceof Error ? err.message : err}`);\n applyAuthCooldown(err, 'main');\n return null;\n }\n}\n","import { resolve } from 'node:path';\n\n/**\n * Build a PATH string that includes common binary directories\n * across package managers and platforms.\n *\n * Prepends known directories that exist on the system to the current PATH.\n * This ensures tmux commands can find binaries installed by Homebrew,\n * MacPorts, nix, and other package managers.\n */\nexport function augmentedPath(): string {\n const rawPath = process.env['PATH'];\n const basePath = rawPath !== undefined && rawPath.length > 0 ? rawPath : '/usr/bin:/bin';\n\n // Common binary directories across platforms/package managers.\n // Only prepend ones that aren't already in PATH.\n const home = process.env['HOME'];\n const candidates = [\n ...(home ? [`${home}/.local/bin`] : []), // Claude CLI, pipx, user-local installs\n resolve(process.execPath, '..'), // Node.js bin dir (ensures node/npm available)\n '/opt/homebrew/bin', // Homebrew (Apple Silicon macOS)\n '/opt/homebrew/sbin', // Homebrew sbin\n '/usr/local/bin', // Homebrew (Intel macOS), manual installs\n '/usr/local/sbin', // Manual installs\n '/opt/local/bin', // MacPorts\n '/opt/local/sbin', // MacPorts\n '/home/linuxbrew/.linuxbrew/bin', // Linuxbrew\n ];\n\n // Check for nix profile paths\n const nixProfile = process.env['NIX_PROFILES'];\n if (nixProfile) {\n for (const p of nixProfile.split(' ').reverse()) {\n candidates.push(`${p}/bin`);\n }\n }\n\n const existing = new Set(basePath.split(':'));\n const prepend = candidates.filter(dir => !existing.has(dir));\n\n return prepend.length > 0 ? `${prepend.join(':')}:${basePath}` : basePath;\n}\n\n/**\n * Environment variables for child processes that need access to\n * user-installed binaries (tmux, git, claude, etc.).\n */\nexport function execEnv(): Record<string, string | undefined> {\n return {\n ...process.env,\n PATH: augmentedPath(),\n };\n}\n","import type { AchievementId, AchievementDef, UnlockedAchievement } from './companion-types.js';\nimport { ACHIEVEMENTS } from './companion-types.js';\n\n// ---------------------------------------------------------------------------\n// Badge art — large-format ASCII art for achievement cards\n// Each art block is an array of strings, rendered centered in the card.\n// ---------------------------------------------------------------------------\n\nconst BADGE_ART: Record<AchievementId, string[]> = {\n // ── Milestone ─────────────────────────────────────────────────────────────\n 'first-blood': [\n ' ╱╲ ',\n ' ╱ ╲ ',\n ' ╱ ◆◆ ╲ ',\n ' ╱ ◆◆ ╲ ',\n ' ╱ ◆◆ ╲ ',\n ' ╱ ◆◆ ╲ ',\n ' ╱─────◆◆─────╲ ',\n ' ╲ ◆◆ ╱ ',\n ' ╲ ◆◆ ╱ ',\n ' ╲───◆◆───╱ ',\n ' ││ ',\n ' ══╪╪══ ',\n ],\n 'centurion': [\n ' ┌──═════──┐ ',\n ' │ ╔═══╗ │ ',\n ' ╱│ ║100║ │╲ ',\n ' ╱ │ ╚═══╝ │ ╲ ',\n ' ╱ └─────────┘ ╲ ',\n ' ╲ ┌───────┐ ╱ ',\n ' ╲ │ ★ ★ ★ │ ╱ ',\n ' ╲ └───────┘ ╱ ',\n ' ╲─────────╱ ',\n ],\n 'thousand-boulder': [\n ' ╭━━━╮ ',\n ' ╭━┫1K ┣━╮ ',\n ' ╭━┫ ╰━━━╯ ┣━╮ ',\n ' ┃ ◉◉◉◉◉◉ ┃ ',\n ' ┃ ◉◉◉◉◉◉◉◉ ┃ ',\n ' ┃ ◉◉◉◉◉◉ ┃ ',\n ' ╰━┫ ┣━╯ ',\n ' ╰━┫ ┣━╯ ',\n ' ╰━━━╯ ',\n ],\n 'cartographer': [\n ' N ',\n ' △ ',\n ' ╭────┼────╮ ',\n ' │ · │ · │ ',\n ' W┼····+····┼E ',\n ' │ · │ · │ ',\n ' ╰────┼────╯ ',\n ' ▽ ',\n ' S ',\n ],\n 'world-traveler': [\n ' ╭──────╮ ',\n ' ╭──┤ ├──╮ ',\n ' ╱ ·│ ◠◡◠ │· ╲ ',\n ' │ · │◠ ◡│ · │ ',\n ' │ · │ ◡◠◡ │ · │ ',\n ' ╲ ·│ │· ╱ ',\n ' ╰──┤ ├──╯ ',\n ' ╰──────╯ ',\n ],\n 'hive-mind': [\n ' ╱╲ ╱╲ ╱╲ ',\n ' ╱◆◆╲╱◆◆╲╱◆◆╲ ',\n ' ╲◆◆╱╲◆◆╱╲◆◆╱ ',\n ' ╱╲╱╱◆╲╱╱◆╲╲╱╲ ',\n ' ╱◆◆╲╲◆◆╲╲◆◆╱◆◆╲ ',\n ' ╲◆◆╱╱◆◆╱╱◆◆╲◆◆╱ ',\n ' ╲╱╲╲◆╱╲╲◆╱╱╲╱ ',\n ' ╲◆◆╱╲◆◆╱╲◆◆╱ ',\n ' ╲╱ ╲╱ ╲╱ ',\n ],\n 'old-growth': [\n ' ╱╲ ',\n ' ╱╱╲╲ ',\n ' ╱╱ ╲╲ ',\n ' ╱╱╱╲╱╲╲╲ ',\n ' ╱╱╱ ╲╲╲ ',\n ' ╱╱╱╱╲╱╲╱╲╲╲╲ ',\n ' ║║║ ',\n ' ║║║ ',\n ' ═══╩╩╩═══ ',\n ],\n 'ancient': [\n ' ┌─┬─────┬─┐ ',\n ' │ │ ◉ ◉ │ │ ',\n ' │ │ ▽ │ │ ',\n ' ╔═╧═╧═════╧═╧═╗ ',\n ' ║ A N C I E N ║ ',\n ' ║ T ║ ',\n ' ╚═════════════╝ ',\n ' ╱╱╱╱╱╱╱╱╱╱╱╱╱ ',\n ' ▔▔▔▔▔▔▔▔▔▔▔▔▔ ',\n ],\n 'regular': [\n ' ╭─────╮ ',\n ' ╭─┤ 10 ├─╮ ',\n ' ╱ ╰─────╯ ╲ ',\n ' │ ╭─────╮ │ ',\n ' │ │ ◉ │ │ ',\n ' │ ╰─────╯ │ ',\n ' ╲ ╱ ',\n ' ╰───────────╯ ',\n ],\n 'veteran': [\n ' ╔═══════════╗ ',\n ' ║ ╔═════╗ ║ ',\n ' ║ ║ V ║ ║ ',\n ' ║ ║ 500 ║ ║ ',\n ' ║ ╚═════╝ ║ ',\n ' ║ ★ ★ ★ ★ ★ ║ ',\n ' ╚═══════════╝ ',\n ' ╱╱╱╱╱╱╱╱╱╱╱ ',\n ' ▔▔▔▔▔▔▔▔▔▔▔ ',\n ],\n 'swarm-starter': [\n ' ',\n ' ◆ ◆ ◆ ◆ ◆ ',\n ' ◆ ◆ ◆ ◆ ◆ ',\n ' ◆ ◆ ◆ ◆ ◆ ',\n ' ◆ ◆ ◆ ◆ ◆ ',\n ' ◆ ◆ ◆ ◆ ◆ ',\n ' ',\n ' · 50 out · ',\n ],\n 'legion': [\n ' ◆◆◆◆◆◆◆◆◆◆◆◆◆◆ ',\n ' ◆◆◆◆◆◆◆◆◆◆◆◆◆◆ ',\n ' ◆◆◆ 2K ◆◆◆◆◆ ',\n ' ◆◆◆◆◆◆◆◆◆◆◆◆◆◆ ',\n ' ◆◆◆◆◆◆◆◆◆◆◆◆◆◆ ',\n ' ◆◆◆◆◆◆◆◆◆◆◆◆◆◆ ',\n ' ◆◆◆◆◆◆◆◆◆◆◆◆◆◆ ',\n ],\n 'army-of-thousands': [\n ' ················· ',\n ' ·◆·◆·◆·◆·◆·◆·◆·◆ ',\n ' ················· ',\n ' ·◆·◆·5K·◆·◆·◆·◆· ',\n ' ················· ',\n ' ·◆·◆·◆·◆·◆·◆·◆·◆ ',\n ' ················· ',\n ' ·◆·◆·◆·◆·◆·◆·◆·◆ ',\n ' ················· ',\n ],\n 'singularity': [\n ' ╲ │ ╱ ─ · ',\n ' ╲ │ ╱ ',\n ' ╲│╱ ',\n ' ────◆──── ',\n ' ╱│╲ ',\n ' ╱ │ ╲ ',\n ' ╱ │ ╲ ─ · ',\n ' 10000 agents ',\n ],\n 'first-shift': [\n ' ┌─────┐ ',\n ' │ ╲ │ ',\n ' ╱│ ╲ │╲ ',\n ' ╱ │ ╲ │ ╲ ',\n ' ╲ │ ╲│ ╱ ',\n ' ╲│ │╱ ',\n ' │ ╱ │ ',\n ' └─────┘ ',\n ' 10 hrs ',\n ],\n 'workaholic': [\n ' ╭─────────╮ ',\n ' ╱ 12 ╲ ',\n ' │ · │ │ ',\n ' │9 · │ 3 │ ',\n ' │ ╲ │ ',\n ' ╲ 6 · ╱ ',\n ' ╰─────────╯ ',\n ' 100 hrs ',\n ],\n 'time-lord': [\n ' ╔═══════════╗ ',\n ' ╱ ╲ ',\n ' │ · 11 12 1 · │ ',\n ' │ 10 ╲ 2 │ ',\n ' │ 9 · 3 │ ',\n ' │ 8 4 │ ',\n ' ╲ 7 5 ╱ ',\n ' ╚═══════════╝ ',\n ' 500 hrs ',\n ],\n 'eternal-grind': [\n ' ╭───╮ ╭───╮ ',\n ' ╱ ╲ ╱ ╲ ',\n ' │ ∞ ╳ ∞ │ ',\n ' ╲ ╱ ╲ ╱ ',\n ' ╰───╯ ╰───╯ ',\n ' ┌─────┐ ',\n ' │ ╲ ╱ │ ',\n ' │ × │ ',\n ' └─────┘ ',\n ],\n 'epoch': [\n ' · ★ · ',\n ' · ╱│╲ · ',\n ' ╲ ╱ │ ╲ ╱ ',\n ' ╲╱ │ ╲╱ ',\n ' ────◆──┼──◆──── ',\n ' ╱╲ │ ╱╲ ',\n ' ╱ ╲ │ ╱ ╲ ',\n ' · ╲│╱ · ',\n ' 5000 hrs ',\n ],\n 'seasoned': [\n ' ╱╲ ',\n ' ╱ ╲ ',\n ' ╱╱╲╱╲╲ ',\n ' ╱╱ ╲╲ ',\n ' ╱╱╱╱╲╱╲╲╲╲ ',\n ' ║║ ',\n ' ─────╨╨───── ',\n ' ╲╲╲╲╲╲╲╲╲╲╲╲╲ ',\n ' 90 day roots ',\n ],\n 'omnipresent': [\n ' N ',\n ' · △ · ',\n ' NW ╭─┼─╮ NE ',\n ' · ╭─┤·+·├─╮ · ',\n ' W──┤·│ · │·├──E ',\n ' · ╰─┤·+·├─╯ · ',\n ' SW ╰─┼─╯ SE ',\n ' · ▽ · ',\n ' S ',\n ],\n 'apprentice': [\n ' ',\n ' ╱╲ ',\n ' ╱ ╲ ',\n ' ╱ ╲ ',\n ' ╱ ╲ ',\n ' ╱────────╲ ',\n ' ╱ level 5 ╲ ',\n ' ▔▔▔▔▔▔▔▔▔▔▔▔ ',\n ],\n 'journeyman': [\n ' ╱╲ ',\n ' ╱ ╲ ╱╲ ',\n ' ╱ ╲ ╱ ╲ ',\n ' ╱ ╳ ╲ ',\n ' ╱ ╱ ╲ ╲ ',\n ' ╱──────╱───╲────╲',\n ' ╱ level 15 ',\n ' ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ ',\n ],\n 'master': [\n ' ★╲╱★ ',\n ' ╱╲ ',\n ' ╱ ╲ ',\n ' ╱╱╲╱╲╲ ',\n ' ╱╱ ╲╲ ',\n ' ╱╱ ╲╲ ',\n ' ╱─────────╲╲ ',\n ' ╱ level 30 ╲ ',\n ' ▔▔▔▔▔▔▔▔▔▔▔▔▔▔ ',\n ],\n 'grandmaster': [\n ' ★ ★ ★ ',\n ' ╲│╱ ',\n ' ╱╲ ',\n ' ╱ ╲ ',\n ' ╱╱╲╱╲╲ ',\n ' ╱╱ ╲╲ ',\n ' ╱╱ ★ ╲╲ ',\n ' ╱─────────╲╲ ',\n ' ╱ level 50 ╲ ',\n ],\n\n // ── Session ───────────────────────────────────────────────────────────────\n 'marathon': [\n ' ╭──────────────╮ ',\n ' │ ╱╲ ╱╲ ╱╲ ╱╲ │ ',\n ' │╱ ╳ ╳ ╳ ╲ │ ',\n ' │ ╱╲ ╱╲ ╱╲ │ ',\n ' │ ╱ ╳ ╳ ╲ │ ',\n ' │ ╱ ╱ ╲╱ ╲ ╲ │ ',\n ' │╱ ╱ ╲ ╲│ ',\n ' ├──────────────┤ ',\n ' │ ~ ^ ~ │ ',\n ' ╰──────────────╯ ',\n ],\n 'blitz': [\n ' ╱╱ ',\n ' ╱╱ ',\n ' ╱╱ ',\n ' ╱╱╱╱╱╱ ',\n ' ╱╱ ',\n ' ╱╱ ',\n ' ╱╱ ',\n ' ╱╱ ',\n ],\n 'speed-run': [\n ' ╭──────────╮ ',\n ' ╱ ╲ ',\n ' │ 10 ╱╱ │ ',\n ' │ · ╱╱ │ ',\n ' │ ╱ ╱╱ │ ',\n ' │ ╱ ╱╱ │ ',\n ' ╲ ╱╱ ╱ ',\n ' ╰──────────╯ ',\n ],\n 'flawless': [\n ' ✦ ✦ ',\n ' ✦ ╱╲ ✦ ',\n ' ╔══╧═══╗ ',\n ' ✦ ║ ║ ✦ ',\n ' ║ ◆ ║ ',\n ' ║ ║ ',\n ' ✦ ╚══════╝ ✦ ',\n ' ✦ ✦ ',\n ],\n 'speed-demon': [\n ' ',\n ' ╱╱ ',\n ' ╱╱ ',\n ' ╱╱╱╱╱╱ ',\n ' ╱╱ ',\n ' ╱╱ ',\n ' ⚡ ≤3 ⚡ ',\n ' x10 streak ',\n ],\n 'iron-will': [\n ' ╔═══════════╗ ',\n ' ║ ┌───────┐ ║ ',\n ' ║ │╔═════╗│ ║ ',\n ' ║ │║ 8+ ║│ ║ ',\n ' ║ │║cycle║│ ║ ',\n ' ║ │╚═════╝│ ║ ',\n ' ║ └───────┘ ║ ',\n ' ╚═══════════╝ ',\n ],\n 'glass-cannon': [\n ' ╱╲ ',\n ' ╱╱╲╲ ',\n ' ╱╱ ╲╲ ',\n ' ╱╱ ╳╳ ╲╲ ',\n ' ╱╱ ╳╳ ╲╲ ',\n ' ╲╲ ╳╳ ╱╱ ',\n ' ╲╲ ╱╱ ',\n ' ╲╲ ╱╱ ',\n ' ╲╲╱╱ ',\n ' ═══╧╧═══ ',\n ],\n 'solo': [\n ' ',\n ' ╭─────────╮ ',\n ' │ │ ',\n ' │ ◆ │ ',\n ' │ │ ',\n ' ╰─────────╯ ',\n ' ',\n ],\n 'one-more-cycle': [\n ' ╭──→──╮ ',\n ' │ │ ',\n ' ↑ ∞ ↓ ',\n ' │ │ ',\n ' ╰──←──╯ ',\n ' ',\n ' ╭──→──╮ ',\n ' │ │ ',\n ' ↑ ∞ ↓ ',\n ' │ │ ',\n ' ╰──←──╯ ',\n ],\n 'quick-draw': [\n ' ╱│ ',\n ' ╱ │ ',\n ' ──╱──│── ',\n ' ╱ │ ',\n ' ╱ ╭─╯ ',\n ' ╱ │ ',\n ' ╱ ╭─╯ ',\n ' │ ',\n ' ──╨── ',\n ],\n 'squad': [\n ' ',\n ' ◆ ◆ ◆ ◆ ',\n ' ',\n ' ◆ ◆ ◆ ◆ ',\n ' ',\n ' ◆ ◆ ',\n ' ',\n ' · 10 strong · ',\n ],\n 'battalion': [\n ' ◆◆◆◆◆◆◆◆◆◆◆◆◆ ',\n ' ',\n ' ◆◆◆◆◆◆◆◆◆◆◆◆◆ ',\n ' ',\n ' ◆◆◆◆◆◆◆◆◆◆◆◆◆ ',\n ' ',\n ' · 25 strong · ',\n ],\n 'swarm': [\n ' ◆·◆·◆·◆·◆·◆·◆·◆· ',\n ' ·◆·◆·◆·◆·◆·◆·◆·◆ ',\n ' ◆·◆·◆·◆·◆·◆·◆·◆· ',\n ' ·◆·◆·◆·◆·◆·◆·◆·◆ ',\n ' ◆·◆·◆·◆·◆·◆·◆·◆· ',\n ' ·◆·◆·◆·◆·◆·◆·◆·◆ ',\n ' · 50 strong · ',\n ],\n 'deep-dive': [\n ' ≈≈≈≈≈≈≈≈≈≈≈≈≈ ',\n ' ↓ ',\n ' ╱│╲ ',\n ' │ ',\n ' │ ',\n ' ▼ ',\n ' · · · · · · · ',\n ' 15 deep ',\n ],\n 'abyss': [\n ' ≈≈≈≈≈≈≈≈≈≈≈≈≈≈ ',\n ' │ ',\n ' │ ',\n ' │ ',\n ' ▼ ',\n ' │ ',\n ' │ ',\n ' ▼ ',\n ' 25 deep ',\n ],\n 'eternal-recurrence': [\n ' ╭──→──╮ ',\n ' ╱ ∞ ╲ ',\n ' │ ╭───╮ │ ',\n ' │ │ ∞ │ │ ',\n ' │ ╰───╯ │ ',\n ' ╲ ∞ ╱ ',\n ' ╰──←──╯ ',\n ' 40 cycles ',\n ],\n 'endurance': [\n ' ',\n ' ╔══════════════╗ ',\n ' ║▓▓▓▓▓▓▓▓▓▓▓▓▓║ ',\n ' ╚══════════════╝ ',\n ' ',\n ' ╔══════════════╗ ',\n ' ║▓▓▓▓▓▓▓▓▓ ║ ',\n ' ╚══════════════╝ ',\n ' 4 hours ',\n ],\n 'ultramarathon': [\n ' ╔══════════════╗ ',\n ' ║▓▓▓▓▓▓▓▓▓▓▓▓▓║ ',\n ' ╚══════════════╝ ',\n ' ─────────────→ ',\n ' · ',\n ' · ',\n ' · ',\n ' · ',\n ' 6 hours ',\n ],\n 'one-shot': [\n ' ╭───────╮ ',\n ' │ ╭───╮ │ ',\n ' │ │ ◉ │ │ ',\n ' │ ╰───╯ │ ',\n ' ╰───────╯ ',\n ' ↑ ',\n ' ╱│ ',\n ' ╱ │ ',\n ' → ◉ │ ',\n ],\n 'flash': [\n ' ╱╱ ',\n ' ╱╱ ',\n ' ╱╱ ',\n ' ╱╱╱╱╱╱ ',\n ' ╱╱ ',\n ' ╱╱ ',\n ' ╱╱ ',\n ' ╱╱ ',\n ' < 2 min ',\n ],\n\n // ── Time ──────────────────────────────────────────────────────────────────\n 'night-owl': [\n ' ☽ ',\n ' ╭─────╮ · ',\n ' ╱ ◉ ◉ ╲ · ',\n ' │ ▽ │ · ',\n ' │ ╱───╲ │ ',\n ' ╲╱ ╲╱ ',\n ' ╱╲ ╱╲ · ',\n ' ╱ ╲───╱ ╲ · ',\n ' ▔▔▔▔▔▔▔▔▔▔▔ ',\n ],\n 'dawn-patrol': [\n ' ',\n ' ─ ─ ─ ─ ─ ─ ─ ─ ',\n ' ╲ │ ╱ ',\n ' ╲ │ ╱ ',\n ' ────◑──── ',\n ' ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ ',\n ' ░░░░░░░░░░░░░░░░ ',\n ' ',\n ],\n 'early-bird': [\n ' ╱╱ ',\n ' ◠ ╱╱ ',\n ' ╱ ╲ ╱╱ ',\n ' │ ◉ ╲>╱ ',\n ' │ ═╱ ',\n ' ╲ ╱ ',\n ' ╲╱╲ ',\n ' ╲ ╲ ',\n ' ▔▔ ',\n ],\n 'weekend-warrior': [\n ' ╔═══════════╗ ',\n ' ║ S M T W T ║ ',\n ' ║ ║ ',\n ' ║ ◆ ║ ',\n ' ║ ◆ ║ ',\n ' ╚═══════════╝ ',\n ],\n 'all-nighter': [\n ' ╭─────────╮ ',\n ' ╱ 12 ╲ ',\n ' │ · │ │ ',\n ' │9 │ 3 │ ',\n ' │ · │ ',\n ' ╲ 6 ╱ ',\n ' ╰─────────╯ ',\n ' ∞ ∞ ∞ ',\n ],\n 'witching-hour': [\n ' · · ✦ · · ',\n ' · ╱╲ · ',\n ' ╱ ╲ ',\n ' │ 3:00 │ ',\n ' │ AM │ ',\n ' ╲ ╱ ',\n ' · ╲╱ · ',\n ' · · ✦ · · ',\n ],\n\n // ── Behavioral ────────────────────────────────────────────────────────────\n 'sisyphean': [\n ' ╱ ',\n ' ╱ ◉ ',\n ' ╱ ◉◉◉ ',\n ' ╱ ◉◉◉ ',\n ' ╱ ◉ ',\n ' ╱ ; ',\n ' ╱ (>.<) ',\n ' ╱ ╱╱ ╲╲ ',\n ' ╱ ╱ ╲ ',\n ],\n 'stubborn': [\n ' ╱╱╱╱╱╱╱╱╱ ',\n ' ╱╱╱╱╱╱╱╱╱╱ ',\n ' ◉ ',\n ' ◉◉◉ ',\n ' (>.<) ',\n ' ╱╱╱╱╱╱╱╱╱ ',\n ' ╱╱╱╱╱╱╱╱╱╱ ',\n ' ✓ ',\n ],\n 'creature-of-habit': [\n ' ╭───╮ ╭───╮ ',\n ' │ → │→│ → │→ ',\n ' ╰───╯ ╰───╯ ',\n ' ╭───╮ ╭───╮ ',\n ' │ → │→│ → │→ ',\n ' ╰───╯ ╰───╯ ',\n ' ╭───╮ ╭───╮ ',\n ' │ → │→│ → │→ ',\n ' ╰───╯ ╰───╯ ',\n ],\n 'loyal': [\n ' ╱╲ ',\n ' ╱ ╲ ',\n ' ╱ ♥♥ ╲ ',\n ' ╱ ♥♥ ╲ ',\n ' ╲ 50 ╱ ',\n ' ╲ ╱ ',\n ' ╲ ╱ ',\n ' ╲╱ ',\n ],\n 'wanderer': [\n ' · · · ',\n ' ╲ │ ╱ ',\n ' ╲ │ ╱ ',\n ' · + · ',\n ' ╱ │ ╲ ',\n ' ╱ │ ╲ ',\n ' · · · ',\n ],\n 'streak': [\n ' ╔══╗╔══╗╔══╗╔══╗ ',\n ' ║M ║║T ║║W ║║T ║ ',\n ' ║◆ ║║◆ ║║◆ ║║◆ ║ ',\n ' ╚══╝╚══╝╚══╝╚══╝ ',\n ' ╔══╗╔══╗╔══╗ ',\n ' ║F ║║S ║║S ║ ',\n ' ║◆ ║║◆ ║║◆ ║ ',\n ' ╚══╝╚══╝╚══╝ ',\n ],\n 'hot-streak': [\n ' ╱╲ ',\n ' ╱╱╲╲ ',\n ' ╱╱◆◆╲╲ ',\n ' ╱╱ ◆◆ ╲╲ ',\n ' ╲╲ ◆◆ ╱╱ ',\n ' ╲╲◆◆╱╱ ',\n ' ╲╲╱╱ ',\n ' ×7 clean ',\n ],\n 'momentum': [\n ' ◉ ◉ ',\n ' │╲ ╱│ ',\n ' │ ╲ ╱ │ ',\n ' │ ╲ ╱ │ ',\n ' │ ◉◉ │ ',\n ' │ ╱ ╲ │ ',\n ' │ ╱ ╲ │ ',\n ' │╱ ╲│ ',\n ' ◉ ◉ ',\n ],\n 'patient-one': [\n ' ╭───────╮ ',\n ' │ ‾.‾ │ ',\n ' │ │ ',\n ' │ zzz │ ',\n ' │ zz │ ',\n ' │ z │ ',\n ' │ │ ',\n ' ╰───────╯ ',\n ' 30 min+ ',\n ],\n 'message-in-a-bottle': [\n ' ╭─╮ ',\n ' │×│ ',\n ' ╭─┴─┴─╮ ',\n ' │ ░░░ │ ',\n ' │ ░░░ │ ',\n ' │ ░░░ │ ',\n ' ╰─────╯ ',\n ' ≈≈≈≈≈≈≈≈≈ ',\n ' ≈≈≈≈≈≈≈ ',\n ],\n 'comeback-kid': [\n ' ╱╲ ╱╲ ',\n ' ╱ ╲ ╱ ╲ ',\n ' ╱ ╲ ╱ ╲ ',\n ' ╱ ╳ ╲ ',\n ' ╲ ╱╲ ╱ ',\n ' ╲ ╱ ╲ ╱ ',\n ' ╲ ╱ ╲ ╱ ',\n ' ╲╱ ╲╱ ✓ ',\n ],\n 'pair-programming': [\n ' ╭─────╮╭─────╮ ',\n ' │ ◉ ◉ ││ ◉ ◉ │ ',\n ' │ ▽ ││ ▽ │ ',\n ' ╰──┬──╯╰──┬──╯ ',\n ' │ ╱──╲ │ ',\n ' │╱ ╲│ ',\n ' ╱ ══ ╲ ',\n ' ╱ ════ ╲ ',\n ' ▔▔▔▔▔▔▔▔▔▔ ',\n ],\n 'overdrive': [\n ' ╭──────────╮ ',\n ' ╱ ╭──────╮ ╲ ',\n ' │ ╱ ×6 ╲ │ ',\n ' │ │ ◉ │ │ ',\n ' │ ╲ ╱ │ ',\n ' ╲ ╰──────╯ ╱ ',\n ' ╰──────────╯ ',\n ' same day ×6 ',\n ],\n 'iron-streak': [\n ' ╔══╗─╔══╗─╔══╗ ',\n ' ║◆ ║ ║◆ ║ ║◆ ║ ',\n ' ╚══╝─╚══╝─╚══╝ ',\n ' │ │ ',\n ' ╔══╗─╔══╗─╔══╗ ',\n ' ║◆ ║ ║◆ ║ ║◆ ║ ',\n ' ╚══╝─╚══╝─╚══╝ ',\n ' 14 day chain ',\n ],\n 'deep-conversation': [\n ' ╭─────────╮ ',\n ' ╱ ╭──╮ 20 ╲ ',\n ' │ │ │ │ ',\n ' │ ╰──╯ │ ',\n ' │ · · · · · │ ',\n ' ╲ ╱ ',\n ' ╰──────────╯ ',\n ' ╲ ',\n ' ● ',\n ],\n 'one-must-imagine': [\n ' ◉◉◉◉◉ ',\n ' ╱ ◉◉◉◉ ',\n ' ╱ ◉ ╱ ←─╮ ',\n '╱ (>.<) │ ',\n ' ╱╱ ╲╲ │ ',\n ' ╱ ╲ │ ',\n ' ╱ ╲─╯ ',\n ' ▔▔▔▔▔▔▔▔▔▔▔ ',\n ' ×10 restarts ',\n ],\n};\n\n// ---------------------------------------------------------------------------\n// Card rendering\n// ---------------------------------------------------------------------------\n\nconst CARD_WIDTH = 34;\nconst CARD_HEIGHT = 18;\nconst CARD_INNER = CARD_WIDTH - 2;\n\nfunction centerLine(text: string, width: number): string {\n const stripped = stripAnsiForWidth(text);\n if (stripped.length >= width) return text.slice(0, width);\n const pad = Math.floor((width - stripped.length) / 2);\n return ' '.repeat(pad) + text + ' '.repeat(width - stripped.length - pad);\n}\n\nfunction stripAnsiForWidth(s: string): string {\n // eslint-disable-next-line no-control-regex\n return s.replace(/\\x1b\\[[0-9;]*m/g, '');\n}\n\nexport interface BadgeCard {\n lines: string[];\n width: number;\n height: number;\n}\n\nexport function renderBadgeCard(\n def: AchievementDef,\n unlock: UnlockedAchievement | null,\n opts?: { dim?: boolean },\n): BadgeCard {\n const dim = opts?.dim === true || unlock === null;\n const art = BADGE_ART[def.id] ?? [];\n\n const lines: string[] = [];\n\n // Top border\n const category = def.category.toUpperCase();\n const borderLabel = ` ${category} `;\n const topPad = CARD_INNER - borderLabel.length - 2;\n const topLeft = Math.floor(topPad / 2);\n const topRight = topPad - topLeft;\n lines.push(`┌${'─'.repeat(topLeft)}${borderLabel}${'─'.repeat(topRight)}┐`);\n\n // Blank\n lines.push(`│${' '.repeat(CARD_INNER)}│`);\n\n // Art (centered, dimmed if locked)\n const artMaxLines = 9;\n const artSlice = art.slice(0, artMaxLines);\n for (const artLine of artSlice) {\n const centered = centerLine(artLine, CARD_INNER);\n lines.push(`│${dim ? dimText(centered) : centered}│`);\n }\n // Pad remaining art lines\n for (let i = artSlice.length; i < artMaxLines; i++) {\n lines.push(`│${' '.repeat(CARD_INNER)}│`);\n }\n\n // Blank\n lines.push(`│${' '.repeat(CARD_INNER)}│`);\n\n // Name (centered, bold if unlocked)\n const nameText = unlock !== null ? def.name : `? ${def.name} ?`;\n lines.push(`│${centerLine(nameText, CARD_INNER)}│`);\n\n // Description (centered, wrapped if needed)\n const descLines = wrapText(def.description, CARD_INNER - 4);\n for (const dl of descLines.slice(0, 2)) {\n const centered = centerLine(dl, CARD_INNER);\n lines.push(`│${dim ? dimText(centered) : centered}│`);\n }\n // Pad to fixed height\n const usedContent = 1 + 1 + artMaxLines + 1 + 1 + Math.min(descLines.length, 2);\n const remaining = CARD_HEIGHT - 2 - usedContent; // -2 for borders\n for (let i = 0; i < remaining; i++) {\n if (i === remaining - 1 && unlock !== null) {\n // Unlock date on last content line\n const dateStr = unlock.unlockedAt.slice(0, 10);\n lines.push(`│${centerLine(dimText(dateStr), CARD_INNER)}│`);\n } else {\n lines.push(`│${' '.repeat(CARD_INNER)}│`);\n }\n }\n\n // Bottom border\n lines.push(`└${'─'.repeat(CARD_INNER)}┘`);\n\n return { lines, width: CARD_WIDTH, height: lines.length };\n}\n\nfunction dimText(text: string): string {\n return `\\x1b[2m${text}\\x1b[22m`;\n}\n\nfunction wrapText(text: string, maxWidth: number): string[] {\n const words = text.split(' ');\n const lines: string[] = [];\n let current = '';\n for (const word of words) {\n if (current.length + word.length + 1 > maxWidth && current.length > 0) {\n lines.push(current);\n current = word;\n } else {\n current = current.length > 0 ? `${current} ${word}` : word;\n }\n }\n if (current.length > 0) lines.push(current);\n return lines;\n}\n\n// ---------------------------------------------------------------------------\n// Gallery data\n// ---------------------------------------------------------------------------\n\nexport interface BadgeGallery {\n achievements: AchievementDef[];\n unlocked: Map<AchievementId, UnlockedAchievement>;\n currentIndex: number;\n total: number;\n}\n\nexport function createBadgeGallery(\n unlockedAchievements: UnlockedAchievement[],\n startIndex?: number,\n): BadgeGallery {\n const unlocked = new Map<AchievementId, UnlockedAchievement>();\n for (const a of unlockedAchievements) {\n unlocked.set(a.id, a);\n }\n\n // Sort: unlocked first (by unlock date), then locked\n const sorted = [...ACHIEVEMENTS].sort((a, b) => {\n const aUnlocked = unlocked.has(a.id);\n const bUnlocked = unlocked.has(b.id);\n if (aUnlocked && !bUnlocked) return -1;\n if (!aUnlocked && bUnlocked) return 1;\n if (aUnlocked && bUnlocked) {\n const aDate = unlocked.get(a.id)!.unlockedAt;\n const bDate = unlocked.get(b.id)!.unlockedAt;\n return aDate.localeCompare(bDate);\n }\n return 0; // preserve category order for locked\n });\n\n return {\n achievements: sorted,\n unlocked,\n currentIndex: startIndex ?? 0,\n total: sorted.length,\n };\n}\n\nexport function galleryNext(gallery: BadgeGallery): number {\n return (gallery.currentIndex + 1) % gallery.total;\n}\n\nexport function galleryPrev(gallery: BadgeGallery): number {\n return (gallery.currentIndex - 1 + gallery.total) % gallery.total;\n}\n\nexport { CARD_WIDTH, CARD_HEIGHT };\n","import { readFileSync } from 'node:fs';\nimport { mountPanel, type Deck } from '@crouton-kit/humanloop';\nimport type { InteractionResponse, MountedPanel } from '@crouton-kit/humanloop';\nimport { readDecisions, readProgress, readMeta, updateMeta, writeOutput } from '../../daemon/ask-store.js';\nimport { askProgressPath } from '../../shared/paths.js';\nimport type { AppState } from '../state.js';\nimport { requestRender } from '../state.js';\nimport type { AggregateInboxItem } from '../../shared/inbox-types.js';\nimport type { Request, Response } from '../../shared/protocol.js';\nimport { rawSend } from '../../shared/client.js';\nimport type { Key } from '../terminal.js';\nimport type { AskMeta } from '../../shared/types.js';\n\n// ── Orphan dispatch ───────────────────────────────────────────────────────────\n\nexport type OrphanTakeoverFn = (target: { sessionId: string; agentId: string; paneId?: string }) => Promise<void>;\n\nexport interface DispatchOrphanDeps {\n daemonSend: (request: Request) => Promise<Response>;\n onOrphanTakeover?: OrphanTakeoverFn;\n sessionId: string;\n cwd: string;\n}\n\n/**\n * Pure dispatch for orphan resolution choices. Extracted so tests can drive it\n * directly without mounting the full panel.\n */\nexport async function dispatchOrphanResolution(\n orphanTarget: NonNullable<AskMeta['orphanTarget']>,\n selectedOptionId: string,\n deps: DispatchOrphanDeps,\n): Promise<void> {\n if (selectedOptionId === 'takeover' && orphanTarget.kind === 'agent') {\n await deps.onOrphanTakeover?.({\n sessionId: deps.sessionId,\n agentId: orphanTarget.agentId,\n paneId: orphanTarget.paneId,\n });\n } else if (selectedOptionId === 'restart' && orphanTarget.kind === 'agent') {\n await deps.daemonSend({ type: 'restart-agent', sessionId: deps.sessionId, agentId: orphanTarget.agentId });\n } else if (selectedOptionId === 'resume' && orphanTarget.kind === 'orchestrator') {\n await deps.daemonSend({ type: 'resume', sessionId: deps.sessionId, cwd: deps.cwd });\n } else if (selectedOptionId === 'dismiss' && orphanTarget.kind === 'orchestrator') {\n // Clear the sticky orphan flag without spawning a new orchestrator — for cases\n // where the user has handled the situation manually (e.g. the tmux pane is still\n // alive) and just wants the \"Needs You\" badge gone.\n await deps.daemonSend({ type: 'clear-orphan', sessionId: deps.sessionId, cwd: deps.cwd });\n }\n}\n\n// ── Visual entry ──────────────────────────────────────────────────────────────\n\nexport interface VisualEntry {\n status: 'loading' | 'ready' | 'error';\n content: string;\n visible: boolean;\n error?: string;\n}\n\n// ── Public handle interface ───────────────────────────────────────────────────\n\nexport interface MountedResolutionHandle {\n handleKey(input: string, key: Key): void;\n render(): string[];\n handleResize(cols: number, rows: number): void;\n unmount(): void;\n canAcceptHostKeys(): boolean;\n advanceQueue(delta: number): void;\n spaceVisualToggle(): void;\n regenerateVisual(): void;\n /** Header info for the sisyphus header strip row 0. */\n getHeaderInfo(): {\n currentIndex: number;\n queueLength: number;\n sessionName: string | undefined;\n askTitle: string | undefined;\n blockedSince: string;\n kind: string | undefined;\n };\n /** Returns the id of the current (first unanswered) interaction, or undefined. */\n getCurrentQid(): string | undefined;\n}\n\n// ── Mount options ─────────────────────────────────────────────────────────────\n\nexport interface MountResolutionOpts {\n aggregateInbox: AggregateInboxItem[];\n startIndex: number;\n cols: number;\n rows: number;\n daemonSend: (request: Request) => Promise<Response>;\n onUnmount: () => void;\n onOrphanTakeover?: OrphanTakeoverFn;\n}\n\n// ── Panel factory ─────────────────────────────────────────────────────────────\n\nexport function mountResolutionPanel(\n opts: MountResolutionOpts,\n state: AppState,\n): MountedResolutionHandle | null {\n let queue = [...opts.aggregateInbox];\n let currentIndex = opts.startIndex;\n let bodyCols = opts.cols;\n\n const item = () => queue[currentIndex]!;\n\n function buildDeck(idx: number): Deck | null {\n const it = queue[idx];\n if (!it) return null;\n const deck = readDecisions(it.cwd, it.sessionId, it.askId);\n if (!deck) return null;\n deck.source = {\n sessionName: it.sessionName,\n askedBy: it.askedBy,\n blockedSince: it.blockedSince,\n };\n return deck;\n }\n\n // Initial deck — if missing (file gone, stale inbox, etc.) return null so the caller\n // never enters resolution mode. Returning a live no-op handle traps the user with no\n // way to escape because handleKey is unbound.\n const initialDeck = buildDeck(currentIndex);\n if (!initialDeck) return null;\n\n // Track answered count for current-qid derivation (Gap 2 option a)\n let currentDeck = initialDeck;\n const initialProgress = readProgress(item().cwd, item().sessionId, item().askId);\n let answeredCount = initialProgress?.responses.length ?? 0;\n\n function getCurrentQid(): string | undefined {\n return currentDeck.interactions[answeredCount]?.id ?? currentDeck.interactions[0]?.id;\n }\n\n function fireVisualGen(force: boolean): void {\n const qid = getCurrentQid();\n if (!qid) return;\n const it = item();\n state.visuals.set(qid, { status: 'loading', content: '', visible: true });\n requestRender();\n void (async () => {\n const res = await rawSend({\n type: 'ask-generate-visual',\n sessionId: it.sessionId,\n askId: it.askId,\n qid,\n cols: bodyCols,\n force,\n }, 60_000);\n if (res.ok) {\n const ansiPath = (res.data as { ansiPath: string }).ansiPath;\n const ansi = readFileSync(ansiPath, 'utf-8');\n state.visuals.set(qid, { status: 'ready', content: ansi, visible: true });\n } else {\n state.visuals.set(qid, { status: 'error', content: '', visible: true, error: res.error });\n }\n requestRender();\n })();\n }\n\n // Mirror humanloop's standalone launchTui pattern: track latest responses\n // so onExit (incomplete submit via final-phase Enter) can submit partials.\n let lastResponses: InteractionResponse[] = [];\n\n const submitResponses = (responses: InteractionResponse[]): void => {\n void (async () => {\n const it = item();\n const completedAt = new Date().toISOString();\n\n // Orphan disposition: dispatch before writeOutput so action lands first\n const meta = readMeta(it.cwd, it.sessionId, it.askId);\n if (meta?.orphanTarget && responses.length > 0) {\n const sel = responses[0]!.selectedOptionId;\n if (sel) {\n await dispatchOrphanResolution(meta.orphanTarget, sel, {\n daemonSend: opts.daemonSend,\n onOrphanTakeover: opts.onOrphanTakeover,\n sessionId: it.sessionId,\n cwd: it.cwd,\n });\n }\n }\n\n // Write output first (before inbox-list so daemon sees answered status)\n writeOutput(it.cwd, it.sessionId, it.askId, responses, completedAt);\n await updateMeta(it.cwd, it.sessionId, it.askId, { status: 'answered', completedAt });\n\n const refreshRes = await opts.daemonSend({ type: 'inbox-list' });\n const newQueue: AggregateInboxItem[] = refreshRes.ok\n ? ((refreshRes.data?.items as AggregateInboxItem[]) ?? [])\n : [];\n\n if (newQueue.length === 0) {\n opts.onUnmount();\n return;\n }\n\n queue = newQueue;\n currentIndex = 0;\n const nextItem = queue[0]!;\n const nextDeck = buildDeck(0);\n if (!nextDeck) {\n opts.onUnmount();\n return;\n }\n\n currentDeck = nextDeck;\n const nextProgress = readProgress(nextItem.cwd, nextItem.sessionId, nextItem.askId);\n answeredCount = nextProgress?.responses.length ?? 0;\n lastResponses = [];\n\n state.visuals.clear();\n\n panel.loadDeck(nextDeck, {\n progressPath: askProgressPath(nextItem.cwd, nextItem.sessionId, nextItem.askId),\n });\n requestRender();\n })();\n };\n\n const panel: MountedPanel = mountPanel({\n deck: initialDeck,\n cols: opts.cols,\n rows: opts.rows,\n progressPath: askProgressPath(item().cwd, item().sessionId, item().askId),\n onProgress: (responses: InteractionResponse[]) => {\n answeredCount = responses.length;\n lastResponses = responses;\n requestRender();\n const it = item();\n const cur = readMeta(it.cwd, it.sessionId, it.askId);\n if (cur?.status === 'pending') {\n void updateMeta(it.cwd, it.sessionId, it.askId, { status: 'in-progress', startedAt: new Date().toISOString() });\n }\n },\n onComplete: (responses: InteractionResponse[]) => {\n submitResponses(responses);\n },\n // Final-phase Enter on an incomplete deck routes here (humanloop only fires\n // onComplete when responses === interactions). The 'final' UI prompts\n // \"enter submit\", so honor that by submitting whatever was answered.\n onExit: () => {\n submitResponses(lastResponses);\n },\n });\n\n return {\n handleKey(input: string, key: Key) {\n // Key from sisyphus is a structural superset of humanloop Key — no cast needed\n panel.handleKey(input, key);\n },\n\n render() {\n return panel.render();\n },\n\n handleResize(cols: number, rows: number) {\n bodyCols = cols;\n panel.handleResize(cols, rows);\n },\n\n unmount() {\n panel.unmount();\n opts.onUnmount();\n },\n\n canAcceptHostKeys() {\n return panel.canAcceptHostKeys();\n },\n\n advanceQueue(delta: number) {\n const newIndex = Math.max(0, Math.min(queue.length - 1, currentIndex + delta));\n if (newIndex === currentIndex) return;\n currentIndex = newIndex;\n const nextDeck = buildDeck(currentIndex);\n if (!nextDeck) return;\n currentDeck = nextDeck;\n const it = item();\n const progress = readProgress(it.cwd, it.sessionId, it.askId);\n answeredCount = progress?.responses.length ?? 0;\n panel.loadDeck(nextDeck, {\n progressPath: askProgressPath(it.cwd, it.sessionId, it.askId),\n });\n requestRender();\n },\n\n spaceVisualToggle() {\n const qid = getCurrentQid();\n if (!qid) return;\n const entry = state.visuals.get(qid);\n if (!entry) {\n fireVisualGen(false);\n } else if (entry.status === 'ready') {\n state.visuals.set(qid, { ...entry, visible: !entry.visible });\n requestRender();\n } else if (entry.status === 'loading') {\n // debounce — no-op\n } else {\n // error → retry\n fireVisualGen(false);\n }\n },\n\n regenerateVisual() {\n const qid = getCurrentQid();\n if (!qid) return;\n state.visuals.set(qid, { status: 'loading', content: '', visible: true });\n requestRender();\n fireVisualGen(true);\n },\n\n getHeaderInfo() {\n const it = item();\n const askTitle = currentDeck.title ?? currentDeck.interactions[0]?.title;\n return {\n currentIndex,\n queueLength: queue.length,\n sessionName: it.sessionName,\n askTitle: askTitle ? askTitle.slice(0, 32) : undefined,\n blockedSince: it.blockedSince,\n kind: it.kind,\n };\n },\n\n getCurrentQid,\n };\n}\n\n// ── enterResolutionMode ───────────────────────────────────────────────────────\n\nexport function enterResolutionMode(\n state: AppState,\n askId: string,\n daemonSend: (request: Request) => Promise<Response>,\n onOrphanTakeover?: MountResolutionOpts['onOrphanTakeover'],\n): void {\n const queue = state.aggregateInbox;\n const startIdx = queue.findIndex((item) => item.askId === askId);\n if (startIdx < 0) {\n // Ask not in current inbox — use the first item as fallback\n if (queue.length === 0) return;\n enterResolutionMode(state, queue[0]!.askId, daemonSend, onOrphanTakeover);\n return;\n }\n\n const handle = mountResolutionPanel(\n {\n aggregateInbox: queue,\n startIndex: startIdx,\n cols: state.cols,\n rows: state.rows - 1,\n daemonSend,\n onUnmount: () => {\n state.resolutionActive = false;\n state.resolutionHandle = null;\n state.visuals.clear();\n requestRender();\n },\n onOrphanTakeover,\n },\n state,\n );\n\n if (!handle) {\n // Deck missing or unreadable — don't enter resolution mode. Leaving resolutionActive\n // false means the user stays in the session list and can keep navigating.\n requestRender();\n return;\n }\n\n state.resolutionHandle = handle;\n state.resolutionActive = true;\n requestRender();\n}\n","import { connect } from 'node:net';\nimport { socketPath } from './paths.js';\nimport type { Request, Response } from './protocol.js';\n\nexport function rawSend(request: Request, timeoutMs = 10_000): Promise<Response> {\n const sock = socketPath();\n\n return new Promise<Response>((resolve, reject) => {\n const socket = connect(sock);\n let data = '';\n\n const timeout = setTimeout(() => {\n socket.destroy();\n reject(new Error(`Request timed out after ${(timeoutMs / 1000).toFixed(0)}s. The daemon may be overloaded.\\n Check: sis admin doctor\\n Logs: tail -20 ~/.sisyphus/daemon.log`));\n }, timeoutMs);\n\n socket.on('connect', () => {\n socket.write(JSON.stringify(request) + '\\n');\n });\n\n socket.on('data', (chunk) => {\n data += chunk.toString();\n const newlineIdx = data.indexOf('\\n');\n if (newlineIdx !== -1) {\n clearTimeout(timeout);\n const line = data.slice(0, newlineIdx);\n socket.destroy();\n try {\n resolve(JSON.parse(line) as Response);\n } catch {\n reject(new Error(`Invalid JSON response from daemon: ${line}`));\n }\n }\n });\n\n socket.on('error', (err) => {\n clearTimeout(timeout);\n reject(err);\n });\n });\n}\n","export type KeyMap = {\n version: 1;\n topLevel: MenuDef;\n submenus: Record<string, MenuDef>;\n};\n\nexport type MenuDef = {\n title: string;\n items: MenuItem[];\n};\n\nexport type MenuItem = {\n key: string;\n label: string;\n action: Action;\n tuiAction?: string;\n hidden?: boolean;\n};\n\nexport type Action =\n | { type: 'submenu'; ref: string }\n | { type: 'script'; name: string }\n | { type: 'popup'; name: string; popup: PopupOpts }\n | { type: 'tmux'; cmd: string }\n | { type: 'tui'; action: string };\n\nexport type PopupOpts = {\n w?: string;\n h?: string;\n borderStyle?: string;\n title?: string;\n cwd?: 'current';\n};\n\nexport function formatHelpForKeymap(km: KeyMap): string {\n const COL1 = 20;\n const MAX_W = 78;\n\n function shortLabel(raw: string, max: number): string {\n return raw.trimStart()\n .replace(/\\s*\\([^)]*\\)\\s*/g, '')\n .replace(/\\s+--\\S*/g, '')\n .trimEnd()\n .slice(0, max)\n .trimEnd();\n }\n\n const lines: string[] = [];\n\n lines.push(' Sisyphus Keybindings (Ctrl-s + key)');\n lines.push('');\n lines.push(' ── Direct ─────────────────────────────────');\n\n for (const item of km.topLevel.items) {\n if (item.action.type === 'submenu' || item.action.type === 'tui' || item.hidden) continue;\n const key = item.key.trim() === '' ? 'spc' : item.key;\n lines.push(` ${key.padEnd(4)} ${shortLabel(item.label, 30)}`);\n }\n\n lines.push('');\n lines.push(' ── Submenus ───────────────────────────────');\n\n for (const topItem of km.topLevel.items) {\n if (topItem.action.type !== 'submenu') continue;\n const { ref } = topItem.action;\n const sub = km.submenus[ref];\n if (!sub) continue;\n\n const prefix = topItem.key;\n const col1Text = ` ${prefix} › ${sub.title.trim()}`.padEnd(COL1);\n let cur = col1Text;\n\n for (const si of sub.items) {\n const lbl = shortLabel(si.label, 13);\n const tok = `${prefix} ${si.key} ${lbl}`;\n const sep = cur.length === COL1 ? '' : ' ';\n if (cur.length !== COL1 && cur.length + 2 + tok.length > MAX_W) {\n lines.push(cur);\n cur = ' '.repeat(COL1) + tok;\n } else {\n cur += sep + tok;\n }\n }\n if (cur.length > COL1) lines.push(cur);\n }\n\n return lines.join('\\n');\n}\n\n// Maps TUI overlay mode → KEYMAP menu key. Shared between input dispatcher and renderer.\nexport const MENU_FOR_MODE: Record<string, string | undefined> = {\n 'leader': 'topLevel',\n 'copy-menu': 'copy',\n 'open-menu': 'open',\n 'agent-menu': 'agent',\n 'session-menu': 'session',\n 'go-menu': 'go',\n 'companion-menu': 'companion',\n};\n\nexport const KEYMAP: KeyMap = {\n version: 1,\n topLevel: {\n title: ' Sisyphus ',\n items: [\n { key: 's', label: ' Cycle session', action: { type: 'script', name: 'sisyphus-cycle' } },\n { key: 'h', label: ' Home / dashboard', action: { type: 'script', name: 'sisyphus-home' } },\n { key: 'n', label: ' New session', action: { type: 'popup', name: 'sisyphus-new', popup: { w: '80%', h: '60%', cwd: 'current' } } },\n { key: 'm', label: ' Message orchestrator', action: { type: 'popup', name: 'sisyphus-msg', popup: { w: '80%', h: '60%', cwd: 'current' } } },\n { key: 't', label: ' Status (where am I?)', action: { type: 'popup', name: 'sisyphus-status-popup', popup: { w: '90%', h: '90%', cwd: 'current' } } },\n { key: 'l', label: ' Session picker', action: { type: 'popup', name: 'sisyphus-pick-session', popup: { w: '60%', h: '60%', cwd: 'current' } } },\n { key: 'z', label: ' Zoom pane', action: { type: 'tmux', cmd: 'resize-pane -Z' } },\n { key: 'x', label: ' Kill pane (smart)', action: { type: 'script', name: 'sisyphus-kill-pane' } },\n { key: '?', label: ' Full help reference', action: { type: 'popup', name: 'sisyphus-help', popup: { w: '80', h: '32', title: ' Keybindings ' } } },\n { key: '/', label: ' Search / filter', action: { type: 'script', name: 'sisyphus-search-reports' }, tuiAction: 'search' },\n { key: ' ', label: ' Open popup explicitly', action: { type: 'tui', action: 'show-leader' } },\n { key: 'y', label: ' Yank ›', action: { type: 'submenu', ref: 'copy' } },\n { key: 'c', label: ' Side claude pane', action: { type: 'script', name: 'sisyphus-companion-pane' }, tuiAction: 'companion-pane' },\n { key: 'C', label: ' Companion (gamification) ›', action: { type: 'submenu', ref: 'companion' } },\n { key: 'o', label: ' Open ›', action: { type: 'submenu', ref: 'open' } },\n { key: 'a', label: ' Agent ›', action: { type: 'submenu', ref: 'agent' } },\n { key: 'S', label: ' Session ›', action: { type: 'submenu', ref: 'session' } },\n { key: 'g', label: ' Go ›', action: { type: 'submenu', ref: 'go' } },\n ],\n },\n submenus: {\n companion: {\n title: ' Companion ',\n items: [\n { key: 'p', label: ' profile (overlay)', action: { type: 'tui', action: 'companion-overlay' } },\n { key: 'd', label: ' debug (mood signals)', action: { type: 'tui', action: 'companion-debug' } },\n ],\n },\n copy: {\n title: ' Copy ',\n items: [\n { key: 'p', label: ' session dir path', action: { type: 'script', name: 'sisyphus-copy-path' } },\n { key: 'i', label: ' session UUID', action: { type: 'script', name: 'sisyphus-copy-id' } },\n { key: 'c', label: ' full session context XML', action: { type: 'script', name: 'sisyphus-copy-context' } },\n { key: 'l', label: ' logs (last 200 lines)', action: { type: 'script', name: 'sisyphus-copy-logs' } },\n { key: 'r', label: ' latest report content', action: { type: 'script', name: 'sisyphus-copy-latest-report' } },\n { key: 'a', label: ' agent ID (picker)', action: { type: 'script', name: 'sisyphus-copy-agent-id' } },\n ],\n },\n open: {\n title: ' Open ',\n items: [\n { key: 'g', label: ' goal.md', action: { type: 'popup', name: 'sisyphus-open-goal', popup: { w: '95%', h: '95%', cwd: 'current' } } },\n { key: 'r', label: ' roadmap.md', action: { type: 'popup', name: 'sisyphus-open-roadmap', popup: { w: '95%', h: '95%', cwd: 'current' } } },\n { key: 's', label: ' strategy.md', action: { type: 'popup', name: 'sisyphus-open-strategy', popup: { w: '95%', h: '95%', cwd: 'current' } } },\n { key: 'l', label: ' logs popup (tail)', action: { type: 'popup', name: 'sisyphus-open-logs', popup: { w: '90%', h: '90%', cwd: 'current' } } },\n { key: 'd', label: ' session dir in file mgr', action: { type: 'script', name: 'sisyphus-open-dir' } },\n { key: 'R', label: ' latest report file', action: { type: 'popup', name: 'sisyphus-open-latest-report', popup: { w: '95%', h: '95%', cwd: 'current' } } },\n { key: 'c', label: ' scratch', action: { type: 'popup', name: 'sisyphus-open-scratch', popup: { w: '95%', h: '95%', cwd: 'current' } } },\n { key: 'e', label: ' edit context file', action: { type: 'popup', name: 'sisyphus-edit-context-file', popup: { w: '95%', h: '95%', cwd: 'current' } }, tuiAction: 'edit-context-file' },\n ],\n },\n agent: {\n title: ' Agent ',\n items: [\n { key: 's', label: ' spawn agent', action: { type: 'popup', name: 'sisyphus-spawn-agent', popup: { w: '80%', h: '70%', cwd: 'current' } } },\n { key: 'm', label: ' message agent (picker)', action: { type: 'popup', name: 'sisyphus-msg-agent', popup: { w: '80%', h: '60%', cwd: 'current' } } },\n { key: 'r', label: ' restart agent (picker)', action: { type: 'popup', name: 'sisyphus-restart-agent-popup', popup: { w: '70%', h: '50%', cwd: 'current' } } },\n { key: 'R', label: ' re-run agent (picker)', action: { type: 'popup', name: 'sisyphus-rerun-agent', popup: { w: '70%', h: '50%', cwd: 'current' } } },\n { key: 'j', label: \" jump to agent's pane\", action: { type: 'popup', name: 'sisyphus-jump-to-pane', popup: { w: '60%', h: '60%' } } },\n { key: 'o', label: ' open claude --resume', action: { type: 'popup', name: 'sisyphus-open-claude-agent', popup: { w: '60%', h: '60%', cwd: 'current' } } },\n { key: 't', label: ' tail agent logs (picker)', action: { type: 'popup', name: 'sisyphus-tail-agent-logs', popup: { w: '90%', h: '90%', cwd: 'current' } } },\n { key: 'k', label: ' kill agent (picker)', action: { type: 'popup', name: 'sisyphus-kill-agent', popup: { w: '60%', h: '40%', cwd: 'current' } } },\n { key: 'e', label: ' quick-spawn Explore', action: { type: 'script', name: 'sisyphus-quick-spawn-explore' } },\n { key: 'd', label: ' quick-spawn Debug', action: { type: 'script', name: 'sisyphus-quick-spawn-debug' } },\n ],\n },\n session: {\n title: ' Session ',\n items: [\n { key: 'n', label: ' new session', action: { type: 'popup', name: 'sisyphus-new', popup: { w: '80%', h: '60%', cwd: 'current' } } },\n { key: 'r', label: ' resume', action: { type: 'popup', name: 'sisyphus-resume-session', popup: { w: '80%', h: '60%', cwd: 'current' } } },\n { key: 'c', label: ' continue', action: { type: 'popup', name: 'sisyphus-continue-session', popup: { w: '50', h: '5', borderStyle: 'fg=yellow', title: ' Continue Session ', cwd: 'current' } } },\n { key: 'b', label: ' rollback (prompts cycle)', action: { type: 'popup', name: 'sisyphus-rollback-session', popup: { w: '50', h: '5', title: ' Rollback ', cwd: 'current' } } },\n { key: 'k', label: ' kill', action: { type: 'popup', name: 'sisyphus-kill-session', popup: { w: '40', h: '5', borderStyle: 'fg=red', title: ' Kill Session ', cwd: 'current' } } },\n { key: 'd', label: ' delete (confirms)', action: { type: 'popup', name: 'sisyphus-delete-session', popup: { w: '40', h: '5', borderStyle: 'fg=red', title: ' Delete Session ', cwd: 'current' } } },\n { key: 'e', label: ' export to ~/Downloads', action: { type: 'popup', name: 'sisyphus-export-session', popup: { w: '60', h: '8', title: ' Export Session ', cwd: 'current' } } },\n { key: 'w', label: ' go to session window', action: { type: 'popup', name: 'sisyphus-go-to-window', popup: { w: '70%', h: '60%', cwd: 'current' } } },\n { key: 'C', label: ' clone (sisyphus session clone)', action: { type: 'popup', name: 'sisyphus-clone-session', popup: { w: '60%', h: '60%', cwd: 'current' } } },\n { key: 'i', label: ' history', action: { type: 'popup', name: 'sisyphus-history', popup: { w: '95%', h: '95%', cwd: 'current' } } },\n ],\n },\n go: {\n title: ' Go ',\n items: [\n { key: 'w', label: ' go to session window', action: { type: 'popup', name: 'sisyphus-go-to-window', popup: { w: '70%', h: '60%', cwd: 'current' } } },\n { key: 'p', label: ' jump to pane (picker)', action: { type: 'popup', name: 'sisyphus-jump-to-pane', popup: { w: '60%', h: '60%' } } },\n { key: 's', label: ' session picker', action: { type: 'popup', name: 'sisyphus-pick-session', popup: { w: '60%', h: '60%', cwd: 'current' } } },\n { key: 'n', label: ' next session', action: { type: 'script', name: 'sisyphus-cycle' } },\n { key: 'r', label: ' reconnect', action: { type: 'popup', name: 'sisyphus-reconnect', popup: { w: '80%', h: '40%', cwd: 'current' } } },\n ],\n },\n },\n};\n","import type { TreeNode } from '../types/tree.js';\n\n/**\n * Render box-drawing prefix for a tree node.\n * Produces connectors like: │ ├─ ▸ or └─ ▼\n */\nexport function renderTreePrefix(node: TreeNode, nodes: TreeNode[], index: number): string {\n if (node.depth === 0) {\n return node.expandable ? (node.expanded ? '▼ ' : '▸ ') : ' ';\n }\n\n const parts: string[] = [];\n\n // For each ancestor depth level (1..depth-1), draw │ or space\n for (let d = 1; d < node.depth; d++) {\n parts.push(isAncestorLastSibling(nodes, index, d) ? ' ' : '│ ');\n }\n\n // Connector for this node\n parts.push(isLastSibling(nodes, index) ? '└─' : '├─');\n\n // Expand indicator\n if (node.expandable) {\n parts.push(node.expanded ? '▼ ' : '▸ ');\n } else {\n parts.push(' ');\n }\n\n return parts.join('');\n}\n\n/** Check if the node at `index` is the last among its siblings (same depth, same parent) */\nfunction isLastSibling(nodes: TreeNode[], index: number): boolean {\n const depth = nodes[index]!.depth;\n for (let i = index + 1; i < nodes.length; i++) {\n if (nodes[i]!.depth === depth) return false;\n if (nodes[i]!.depth < depth) return true;\n }\n return true;\n}\n\n/** Check if the ancestor at `depth` for the node at `index` is the last among its siblings */\nfunction isAncestorLastSibling(nodes: TreeNode[], index: number, depth: number): boolean {\n // Find the ancestor at this depth by scanning backward\n for (let i = index - 1; i >= 0; i--) {\n if (nodes[i]!.depth === depth) {\n return isLastSibling(nodes, i);\n }\n if (nodes[i]!.depth < depth) return true;\n }\n return true;\n}\n\n/**\n * Pre-compute prefix strings for all tree nodes in O(n).\n * Avoids per-node O(n) scans during rendering.\n */\nexport function precomputePrefixes(nodes: TreeNode[]): void {\n const len = nodes.length;\n if (len === 0) return;\n\n // Step 1: Compute isLastSibling for each node in a single backward pass.\n // A node is \"last sibling\" if no later node at the same depth appears before\n // a node at a shallower depth (or end of array).\n const isLast = new Array<boolean>(len);\n // Track the last-seen index for each depth level\n const lastSeenAtDepth = new Map<number, number>();\n\n for (let i = len - 1; i >= 0; i--) {\n const depth = nodes[i]!.depth;\n // This node is last sibling if no node at same depth was seen after it\n // before a shallower node\n isLast[i] = !lastSeenAtDepth.has(depth);\n lastSeenAtDepth.set(depth, i);\n // Clear deeper depths (they belong to a different parent scope)\n for (const [d] of lastSeenAtDepth) {\n if (d > depth) lastSeenAtDepth.delete(d);\n }\n }\n\n // Step 2: Build prefix strings using pre-computed isLast data.\n // For ancestor connector lines, we need to know if the ancestor at each depth\n // is a last sibling. We maintain a stack of isLast values per depth.\n const ancestorIsLast: boolean[] = [];\n\n for (let i = 0; i < len; i++) {\n const node = nodes[i]!;\n\n if (node.depth === 0) {\n node.prefix = node.expandable ? (node.expanded ? '▼ ' : '▸ ') : ' ';\n ancestorIsLast[0] = isLast[i]!;\n continue;\n }\n\n // Update ancestor tracking\n ancestorIsLast[node.depth] = isLast[i]!;\n\n const parts: string[] = [];\n\n // Ancestor connectors (depth 1 to depth-1)\n for (let d = 1; d < node.depth; d++) {\n parts.push(ancestorIsLast[d] ? ' ' : '│ ');\n }\n\n // This node's connector\n parts.push(isLast[i] ? '└─' : '├─');\n\n // Expand indicator\n if (node.expandable) {\n parts.push(node.expanded ? '▼ ' : '▸ ');\n } else {\n parts.push(' ');\n }\n\n node.prefix = parts.join('');\n }\n}\n","import { readFileSync } from 'node:fs';\nimport type { AgentReport } from '../../shared/types.js';\n\nexport interface ReportBlock {\n type: 'update' | 'final';\n timestamp: string;\n content: string;\n summary: string;\n}\n\nfunction loadReportContent(report: AgentReport): string {\n try {\n return readFileSync(report.filePath, 'utf-8');\n } catch {\n return report.summary;\n }\n}\n\nexport function resolveReports(reports: AgentReport[]): ReportBlock[] {\n return [...reports].reverse().map((r) => ({\n type: r.type as 'update' | 'final',\n timestamp: r.timestamp,\n content: loadReportContent(r),\n summary: r.summary,\n }));\n}\n","import { rawSend } from '../../shared/client.js';\nimport type { Request, Response } from '../../shared/protocol.js';\nimport type { AggregateInboxItem } from '../../shared/inbox-types.js';\n\nexport function send(request: Request): Promise<Response> {\n return rawSend(request, 8_000);\n}\n\nexport async function inboxList(): Promise<AggregateInboxItem[]> {\n const res = await send({ type: 'inbox-list' });\n if (!res.ok) return [];\n return (res.data?.items as AggregateInboxItem[] | undefined) ?? [];\n}\n","import { execSync } from 'node:child_process';\nimport { join } from 'node:path';\nimport { readFileSync, writeFileSync, mkdtempSync, rmSync, cpSync, existsSync, mkdirSync } from 'node:fs';\nimport { tmpdir } from 'node:os';\nimport { globalDir, tmuxSessionName } from '../../shared/paths.js';\nimport { augmentedPath } from '../../shared/env.js';\nimport { shellQuote } from '../../shared/shell.js';\nimport { exec, execSafe, EXEC_ENV } from '../../shared/exec.js';\n\n\nexport function getWindowId(): string {\n const pane = process.env['TMUX_PANE'];\n if (pane) {\n return exec(`tmux display-message -t ${shellQuote(pane)} -p \"#{window_id}\"`);\n }\n return exec('tmux display-message -p \"#{window_id}\"');\n}\n\nexport function selectWindow(windowId: string): void {\n execSafe(`tmux select-window -t ${shellQuote(windowId)}`);\n}\n\nexport function selectPane(paneId: string): void {\n execSafe(`tmux select-pane -t ${shellQuote(paneId)}`);\n}\n\nexport function windowExists(windowId: string): boolean {\n return execSafe(`tmux display-message -t ${shellQuote(windowId)} -p \"#{window_id}\"`) !== null;\n}\n\nexport function listAllWindowIds(): Set<string> {\n try {\n const output = execSync('tmux list-windows -a -F \"#{window_id}\"', { encoding: 'utf-8', env: EXEC_ENV });\n return new Set(output.trim().split('\\n').filter(Boolean));\n } catch {\n return new Set();\n }\n}\n\n/**\n * Register this TUI window as the dashboard for the current tmux session.\n * Called on TUI startup so C-s h (sisyphus-home) and M-s (sisyphus-cycle) can\n * locate the dashboard. Also stamps @sisyphus_cwd on the parent tmux session\n * if it is currently unset — without it, resolve_home() and the cycle script\n * silently exclude the home session, breaking jump/cycle from ssyph_ panes.\n * If @sisyphus_cwd is already set to a different cwd we leave it alone so we\n * don't hijack another project's home registration.\n */\nexport function registerDashboardWindow(cwd?: string): void {\n const wid = getWindowId();\n const pane = process.env['TMUX_PANE'];\n let sessionTarget: string | null = null;\n if (pane) {\n sessionTarget = execSafe(`tmux display-message -t ${shellQuote(pane)} -p \"#{session_id}\"`)?.trim() || null;\n }\n if (sessionTarget) {\n execSafe(`tmux set-option -t ${shellQuote(sessionTarget)} @sisyphus_dashboard ${wid}`);\n } else {\n execSafe(`tmux set-option @sisyphus_dashboard ${wid}`);\n }\n\n if (cwd) {\n const normalizedCwd = cwd.replace(/\\/+$/, '');\n const target = sessionTarget;\n const existing = target\n ? execSafe(`tmux show-options -t ${shellQuote(target)} -v @sisyphus_cwd`)?.trim()\n : execSafe(`tmux show-options -v @sisyphus_cwd`)?.trim();\n if (!existing) {\n if (target) {\n execSafe(`tmux set-option -t ${shellQuote(target)} @sisyphus_cwd ${shellQuote(normalizedCwd)}`);\n } else {\n execSafe(`tmux set-option @sisyphus_cwd ${shellQuote(normalizedCwd)}`);\n }\n }\n }\n}\n\nfunction setupCompanionPlugin(): string {\n const srcDir = join(import.meta.dirname, 'templates', 'companion-plugin');\n const destDir = join(globalDir(), 'companion-plugin');\n if (!existsSync(destDir)) mkdirSync(destDir, { recursive: true });\n cpSync(srcDir, destDir, { recursive: true });\n return destDir;\n}\n\nexport function paneExists(paneId: string): boolean {\n return execSafe(`tmux display-message -t ${shellQuote(paneId)} -p \"#{pane_id}\"`) !== null;\n}\n\n// Find a companion pane for this cwd by marker option. Returns null if none.\n// Authoritative source — replaces the old module-level companionPaneId cache\n// which went stale after `tmux kill-pane` (stale id → paneExists race),\n// across TUI restarts, and when the user opened a second dashboard.\nfunction findCompanionPaneForCwd(normalizedCwd: string): string | null {\n const out = execSafe(`tmux list-panes -aF \"#{pane_id}\\t#{@sisyphus_companion}\"`);\n if (!out) return null;\n for (const line of out.split('\\n')) {\n const tabIdx = line.indexOf('\\t');\n if (tabIdx < 0) continue;\n const paneId = line.slice(0, tabIdx);\n const marker = line.slice(tabIdx + 1);\n if (paneId && marker === normalizedCwd) return paneId;\n }\n return null;\n}\n\nexport function openCompanionPane(cwd: string): void {\n const normalizedCwd = cwd.replace(/\\/+$/, '');\n\n // Reuse an alive companion pane for this cwd if one exists. We look it up\n // via the tmux pane option marker rather than caching a pane id in module\n // state, so a killed pane never leaves us in a state where we try to focus\n // something that's gone.\n const existing = findCompanionPaneForCwd(normalizedCwd);\n if (existing) {\n execSafe(`tmux select-pane -t ${shellQuote(existing)}`);\n return;\n }\n\n const pluginDir = setupCompanionPlugin();\n\n const templatePath = join(import.meta.dirname, 'templates', 'dashboard-claude.md');\n let template: string;\n try {\n template = readFileSync(templatePath, 'utf-8');\n } catch {\n template = `You are a Sisyphus dashboard companion. Help the user manage multi-agent sessions.\\nProject: ${cwd}\\nRun \\`sis list\\` and \\`sis status\\` to see current state.`;\n }\n\n const rendered = template.replace(/\\{\\{CWD\\}\\}/g, cwd);\n const promptPath = join(globalDir(), 'dashboard-companion-prompt.md');\n writeFileSync(promptPath, rendered, 'utf-8');\n\n const pathEnv = augmentedPath();\n\n const claudeCmd = `SISYPHUS_COMPANION_CWD=${shellQuote(cwd)} PATH=${shellQuote(pathEnv)} claude --dangerously-skip-permissions --plugin-dir ${shellQuote(pluginDir)} --append-system-prompt \"$(cat ${shellQuote(promptPath)})\"`;\n\n const result = exec(\n `tmux split-window -h -l 33% -P -F \"#{pane_id}\" -c ${shellQuote(cwd)} ${shellQuote(claudeCmd)}`,\n );\n const newPaneId = result.trim();\n if (newPaneId) {\n execSafe(`tmux set-option -p -t ${shellQuote(newPaneId)} @sisyphus_companion ${shellQuote(normalizedCwd)}`);\n }\n}\n\nconst TERMINAL_EDITORS = new Set(['nvim', 'vim', 'vi', 'nano', 'emacs', 'micro', 'helix', 'hx', 'joe', 'ne', 'kak']);\n\nexport function switchToSession(sessionName: string): void {\n execSafe(`tmux switch-client -t ${shellQuote(sessionName)}`);\n}\n\nexport function editInPopup(cwd: string, editor: string, opts?: { content?: string; size?: { w: string; h: string } }): string | null {\n const tmpDir = mkdtempSync(join(tmpdir(), 'sisyphus-'));\n const filePath = join(tmpDir, 'input.md');\n try {\n writeFileSync(filePath, opts?.content ? opts.content : '', 'utf-8');\n openEditorPopup(cwd, editor, filePath, opts?.size);\n const result = readFileSync(filePath, 'utf-8').trim();\n return result || null;\n } finally {\n rmSync(tmpDir, { recursive: true, force: true });\n }\n}\n\n/**\n * Small centered tmux popup that prompts for a single line of input.\n * Returns the trimmed input or null if empty/cancelled (Ctrl-C / Escape).\n */\nexport function promptInPopup(prompt: string, opts?: { w?: string; h?: string }): string | null {\n const { w = '50%', h = '3' } = opts ?? {};\n const tmpDir = mkdtempSync(join(tmpdir(), 'sisyphus-'));\n const outFile = join(tmpDir, 'result');\n try {\n const script = `printf ${shellQuote(prompt + ' ')} && read -r line && printf '%s' \"$line\" > ${shellQuote(outFile)}`;\n execSync(\n `tmux display-popup -E -w ${w} -h ${h} ${shellQuote(`bash -c ${shellQuote(script)}`)}`,\n { stdio: 'inherit', env: EXEC_ENV },\n );\n if (!existsSync(outFile)) return null;\n const result = readFileSync(outFile, 'utf-8').trim();\n return result || null;\n } finally {\n rmSync(tmpDir, { recursive: true, force: true });\n }\n}\n\nexport function openLogPopup(): void {\n execSync(\n `tmux display-popup -E -w 90% -h 80% ${shellQuote('tail -f ~/.sisyphus/daemon.log')}`,\n { stdio: 'inherit', env: EXEC_ENV },\n );\n}\n\nexport function openShellPopup(cwd: string, command: string): void {\n execSync(\n `tmux display-popup -E -w 90% -h 80% -d ${shellQuote(cwd)} ${shellQuote(`sh -c '${command.replace(/'/g, \"'\\\\''\")}; echo; echo \"Press enter to close\"; read'`)}`,\n { stdio: 'inherit', env: EXEC_ENV },\n );\n}\n\nexport function openInFileManager(path: string): void {\n execSync(`open ${shellQuote(path)}`, { stdio: 'inherit', env: EXEC_ENV });\n}\n\nexport function openClaudeResumePopup(cwd: string, claudeSessionId: string, resumeEnv?: string, resumeArgs?: string): void {\n const pathEnv = augmentedPath();\n const envPrefix = resumeEnv ? `${resumeEnv} && ` : '';\n const args = resumeArgs\n ? `${resumeArgs} --resume ${shellQuote(claudeSessionId)}`\n : `--resume ${shellQuote(claudeSessionId)}`;\n const cmd = `${envPrefix}PATH=${shellQuote(pathEnv)} claude ${args}`;\n execSync(\n `tmux display-popup -E -w 90% -h 80% -d ${shellQuote(cwd)} ${shellQuote(cmd)}`,\n { stdio: 'inherit', env: EXEC_ENV },\n );\n}\n\nexport function openClaudeResumeSession(cwd: string, sessionId: string, claudeSessionId: string, sessionLabel: string, resumeEnv?: string, resumeArgs?: string, cycleNum?: number, mode?: string): string {\n const sessionName = tmuxSessionName(cwd, sessionLabel);\n const cycleLabel = cycleNum != null ? `c${cycleNum}` : '';\n const paneTitle = cycleLabel ? `ssph:orch ${sessionLabel} ${cycleLabel}` : `ssph:orch ${sessionLabel}`;\n\n // Resolve name → $N id for subsequent -t ops. tmux -t <name> can\n // substring-match the wrong session under sparse env; $N is unambiguous.\n const existing = execSafe('tmux list-sessions -F \"#{session_id}|#{session_name}\"');\n const existingLine = existing?.split('\\n').find(line => line.slice(line.indexOf('|') + 1) === sessionName);\n if (existingLine) {\n const existingSessId = existingLine.slice(0, existingLine.indexOf('|'));\n execSafe(`tmux set-option -t ${shellQuote(existingSessId)} @sisyphus_cwd ${shellQuote(cwd.replace(/\\/+$/, ''))}`);\n execSafe(`tmux set-option -t ${shellQuote(existingSessId)} @sisyphus_session_id ${shellQuote(sessionId)}`);\n const firstPaneId = execSafe(`tmux list-panes -t ${shellQuote(existingSessId)} -F '#{pane_id}'`)?.split('\\n')[0];\n if (firstPaneId) applyOrchestratorPaneStyle(firstPaneId, paneTitle, sessionLabel, cycleLabel, mode);\n return sessionName;\n }\n\n const pathEnv = augmentedPath();\n const envPrefix = resumeEnv ? `${resumeEnv} && ` : '';\n const args = resumeArgs\n ? `${resumeArgs} --resume ${shellQuote(claudeSessionId)}`\n : `--resume ${shellQuote(claudeSessionId)}`;\n const cmd = `${envPrefix}PATH=${shellQuote(pathEnv)} claude ${args}`;\n // -P -F captures the new session's $N id + first pane id for unambiguous targeting.\n const createOut = exec(`tmux new-session -d -s ${shellQuote(sessionName)} -n main -c ${shellQuote(cwd)} -P -F '#{session_id}|#{pane_id}' ${shellQuote(cmd)}`).trim();\n const pipeIdx = createOut.indexOf('|');\n const newSessId = createOut.slice(0, pipeIdx);\n const firstPaneId = createOut.slice(pipeIdx + 1);\n execSafe(`tmux set-option -t ${shellQuote(newSessId)} @sisyphus_cwd ${shellQuote(cwd.replace(/\\/+$/, ''))}`);\n execSafe(`tmux set-option -t ${shellQuote(newSessId)} @sisyphus_session_id ${shellQuote(sessionId)}`);\n // Match session defaults from daemon tmux.ts configureSessionDefaults\n execSafe(`tmux set -w -t ${shellQuote(newSessId + ':')} pane-border-status top`);\n execSafe(`tmux set -w -t ${shellQuote(newSessId + ':')} allow-rename off`);\n execSafe(`tmux set -w -t ${shellQuote(newSessId + ':')} automatic-rename off`);\n if (firstPaneId) applyOrchestratorPaneStyle(firstPaneId, paneTitle, sessionLabel, cycleLabel, mode);\n return sessionName;\n}\n\n/**\n * Mirror daemon's setPaneStyle for an orchestrator pane — sets pane title,\n * per-pane metadata vars (@pane_role/session/cycle/mode), and pane-border-format\n * so the new tmux session shows the same badge as a live orchestrator pane.\n */\nfunction applyOrchestratorPaneStyle(paneId: string, title: string, sessionLabel: string, cycleLabel: string, mode?: string): void {\n const color = 'yellow'; // matches daemon/colors.ts ORCHESTRATOR_COLOR\n execSafe(`tmux select-pane -t ${shellQuote(paneId)} -T ${shellQuote(title)}`);\n execSafe(`tmux set -p -t ${shellQuote(paneId)} @pane_role ${shellQuote('orch')}`);\n execSafe(`tmux set -p -t ${shellQuote(paneId)} @pane_session ${shellQuote(sessionLabel)}`);\n if (cycleLabel) execSafe(`tmux set -p -t ${shellQuote(paneId)} @pane_cycle ${shellQuote(cycleLabel)}`);\n if (mode) execSafe(`tmux set -p -t ${shellQuote(paneId)} @pane_mode ${shellQuote(mode)}`);\n const gitBranch = `#(cd #{pane_current_path} && git branch --show-current 2>/dev/null)`;\n const branchSuffix = `#(cd #{pane_current_path} && git branch --show-current 2>/dev/null | grep -q . && echo ' |') ${gitBranch}`;\n const homePath = `#(echo '#{pane_current_path}' | sed \"s|^$HOME|~|\")`;\n const modeSegment = `#{?#{@pane_mode}, #[fg=${color}\\\\,italics]#{@pane_mode}#[default],}`;\n const fmt = [\n `#[bg=${color},fg=black,bold] #{@pane_role} #[default]`,\n ` #[fg=${color},bold]#{@pane_session}`,\n modeSegment,\n ` #[default,dim]#{@pane_cycle}`,\n ` ${homePath}${branchSuffix}`,\n `#[default]`,\n ].join('');\n execSafe(`tmux set -p -t ${shellQuote(paneId)} pane-border-format ${shellQuote(fmt)}`);\n}\n\nexport function openEditorPopup(cwd: string, editor: string, filePath: string, size?: { w: string; h: string }): void {\n const { w = '90%', h = '90%' } = size ?? {};\n const editorBin = editor.split(/\\s+/)[0]!.split('/').pop()!;\n if (TERMINAL_EDITORS.has(editorBin)) {\n execSync(\n `tmux display-popup -E -w ${w} -h ${h} -d ${shellQuote(cwd)} ${shellQuote(`${editor} ${shellQuote(filePath)}`)}`,\n { stdio: 'inherit', env: EXEC_ENV },\n );\n } else {\n execSync(`${editor} ${shellQuote(filePath)}`, { stdio: 'inherit', cwd, env: EXEC_ENV });\n }\n}\n","import { execSync } from 'node:child_process';\nimport { execEnv } from './env.js';\n\nexport const EXEC_ENV = execEnv();\n\nexport function exec(cmd: string, cwd?: string, timeoutMs: number = 30_000): string {\n return execSync(cmd, { encoding: 'utf-8', env: EXEC_ENV, cwd, timeout: timeoutMs }).trim();\n}\n\nexport function execSafe(cmd: string, cwd?: string, timeoutMs?: number): string | null {\n try {\n return execSync(cmd, { encoding: 'utf-8', env: EXEC_ENV, cwd, stdio: ['pipe', 'pipe', 'pipe'], timeout: timeoutMs }).trim();\n } catch { return null; }\n}\n","import { readFileSync, readdirSync } from 'node:fs';\nimport { goalPath, roadmapPath, sessionsDir, statePath } from '../../shared/paths.js';\nimport { resolveReports } from './reports.js';\nimport type { Session, AgentStatus } from '../../shared/types.js';\n\nfunction readFileSafe(filePath: string): string | null {\n try {\n return readFileSync(filePath, 'utf-8');\n } catch {\n return null;\n }\n}\n\nfunction escapeXml(s: string): string {\n return s\n .replace(/&/g, '&')\n .replace(/</g, '<')\n .replace(/>/g, '>')\n .replace(/\"/g, '"');\n}\n\nexport type CompanionContextBlocks = Record<string, string>;\n\nfunction buildSessionBlock(cwd: string, session: Session): string {\n const lines: string[] = [];\n const nameAttr = session.name ? ` name=\"${escapeXml(session.name)}\"` : '';\n lines.push(` <session id=\"${escapeXml(session.id)}\"${nameAttr} status=\"${escapeXml(session.status)}\">`);\n lines.push(` <task>${escapeXml(session.task)}</task>`);\n lines.push(` <created>${escapeXml(session.createdAt)}</created>`);\n lines.push(` <cycles>${session.orchestratorCycles.length}</cycles>`);\n\n if (session.status === 'completed') {\n if (session.completionReport) {\n const snippet = session.completionReport.slice(0, 300).replace(/\\n+/g, ' ').trim();\n lines.push(` <completion-report>${escapeXml(snippet)}${session.completionReport.length > 300 ? '…' : ''}</completion-report>`);\n }\n } else {\n if (session.agents.length > 0) {\n const counts = new Map<AgentStatus, number>();\n for (const agent of session.agents) {\n counts.set(agent.status, (counts.get(agent.status) ?? 0) + 1);\n }\n const summary = [...counts.entries()].map(([status, n]) => `${n} ${status}`).join(', ');\n lines.push(` <agents>${escapeXml(summary)}</agents>`);\n }\n\n const goalContent = readFileSafe(goalPath(cwd, session.id));\n if (goalContent) {\n const firstLine = goalContent.split('\\n').map(l => l.trim()).find(l => l.length > 0 && !l.startsWith('#'));\n if (firstLine) lines.push(` <goal>${escapeXml(firstLine)}</goal>`);\n }\n\n const roadmapContent = readFileSafe(roadmapPath(cwd, session.id));\n if (roadmapContent) {\n const todos = roadmapContent\n .split('\\n')\n .filter(l => l.includes('- [ ]'))\n .slice(0, 5)\n .map(l => l.trim());\n if (todos.length > 0) {\n lines.push(' <todos>');\n for (const todo of todos) lines.push(` ${escapeXml(todo)}`);\n lines.push(' </todos>');\n }\n }\n }\n\n lines.push(' </session>');\n return lines.join('\\n');\n}\n\nexport function buildCompanionContextBlocks(cwd: string): CompanionContextBlocks {\n let sessionDirs: string[];\n try {\n sessionDirs = readdirSync(sessionsDir(cwd));\n } catch {\n return {};\n }\n\n const now = Date.now();\n const sevenDaysMs = 7 * 24 * 60 * 60 * 1000;\n const blocks: CompanionContextBlocks = {};\n\n for (const sessionId of sessionDirs) {\n const stateRaw = readFileSafe(statePath(cwd, sessionId));\n if (!stateRaw) continue;\n\n let session: Session;\n try {\n session = JSON.parse(stateRaw) as Session;\n } catch {\n continue;\n }\n\n if (session.status === 'completed' && session.completedAt) {\n if (now - new Date(session.completedAt).getTime() > sevenDaysMs) continue;\n }\n\n blocks[session.id] = buildSessionBlock(cwd, session);\n }\n\n return blocks;\n}\n\nexport function renderFullContext(blocks: CompanionContextBlocks): string {\n const entries = Object.values(blocks);\n if (entries.length === 0) return '<sessions>No sessions found.</sessions>';\n return ['<sessions>', ...entries, '</sessions>'].join('\\n');\n}\n\n// Returns null when prev and next contain identical blocks (same ids, same XML).\n// Otherwise emits a <sessions-changed-since-last-prompt> wrapper with one entry\n// per added / removed / updated session. The change=\"...\" attribute is spliced\n// after the opening `<session ` of the cached block so every nested element is\n// preserved verbatim — the consumer reads exactly what a full injection would\n// have shown for that session.\nexport function renderContextDelta(prev: CompanionContextBlocks, next: CompanionContextBlocks): string | null {\n const ids = new Set([...Object.keys(prev), ...Object.keys(next)]);\n const entries: string[] = [];\n for (const id of ids) {\n const p = prev[id];\n const n = next[id];\n if (p === undefined && n !== undefined) {\n entries.push(n.replace(/^(\\s*)<session /, `$1<session change=\"added\" `));\n } else if (p !== undefined && n === undefined) {\n entries.push(` <session id=\"${escapeXml(id)}\" change=\"removed\" />`);\n } else if (p !== n && n !== undefined) {\n entries.push(n.replace(/^(\\s*)<session /, `$1<session change=\"updated\" `));\n }\n }\n if (entries.length === 0) return null;\n return ['<sessions-changed-since-last-prompt>', ...entries, '</sessions-changed-since-last-prompt>'].join('\\n');\n}\n\nexport function buildSessionContext(session: Session, cwd: string): string {\n const goal = readFileSafe(goalPath(cwd, session.id));\n const roadmap = readFileSafe(roadmapPath(cwd, session.id));\n\n const agentsXml = session.agents.map((agent) => {\n const reportBlocks = resolveReports(agent.reports);\n // resolveReports returns newest-first; reverse to chronological for context\n const reportsXml = [...reportBlocks].reverse().map((block) => {\n return ` <report type=\"${block.type}\" time=\"${escapeXml(block.timestamp)}\">${escapeXml(block.content)}</report>`;\n }).join('\\n');\n\n return [\n ` <agent id=\"${escapeXml(agent.id)}\" name=\"${escapeXml(agent.name)}\" type=\"${escapeXml(agent.agentType)}\" status=\"${escapeXml(agent.status)}\">`,\n ` <instruction>${escapeXml(agent.instruction)}</instruction>`,\n ...(reportsXml ? [reportsXml] : []),\n ` </agent>`,\n ].join('\\n');\n }).join('\\n');\n\n const cyclesXml = session.orchestratorCycles.map((cycle) => {\n const agents = cycle.agentsSpawned.join(', ');\n const mode = cycle.mode ? ` mode=\"${escapeXml(cycle.mode)}\"` : '';\n return ` <cycle number=\"${cycle.cycle}\"${mode} agents=\"${escapeXml(agents)}\" />`;\n }).join('\\n');\n\n const lines: string[] = [\n '<context>',\n `<session id=\"${escapeXml(session.id)}\" status=\"${escapeXml(session.status)}\">`,\n ` <task>${escapeXml(session.task)}</task>`,\n ` <cwd>${escapeXml(session.cwd)}</cwd>`,\n ];\n\n if (goal) lines.push(` <goal>${escapeXml(goal)}</goal>`);\n if (roadmap) lines.push(` <roadmap>${escapeXml(roadmap)}</roadmap>`);\n\n if (session.agents.length > 0) {\n lines.push(' <agents>');\n lines.push(agentsXml);\n lines.push(' </agents>');\n }\n\n if (session.orchestratorCycles.length > 0) {\n lines.push(' <cycles>');\n lines.push(cyclesXml);\n lines.push(' </cycles>');\n }\n\n if (session.completionReport) {\n lines.push(` <completion-report>${escapeXml(session.completionReport)}</completion-report>`);\n }\n\n lines.push('</session>');\n lines.push('</context>');\n\n return lines.join('\\n');\n}\n","import stringWidth from 'string-width';\nimport type { FrameBuffer, Rect } from '../render.js';\nimport { drawBorder, writeClipped, colorToSGR } from '../render.js';\nimport { renderCompanion, getMoodAnsiCode } from '../../shared/companion-render.js';\nimport type { CompanionField, CompanionState } from '../../shared/companion-types.js';\nimport type { TreeNode } from '../types/tree.js';\nimport { renderTreePrefix } from '../lib/tree-render.js';\nimport {\n statusColor,\n statusIndicator,\n agentStatusIcon,\n truncate,\n formatDuration,\n formatTime,\n formatTimeAgo,\n durationColor,\n agentDisplayName,\n modeColor,\n abbreviateMode,\n} from '../lib/format.js';\n\n// ─── Node content renderer ────────────────────────────────────────────────────\n\ninterface NodeContent {\n icon: string;\n label: string;\n meta: string;\n color: string;\n dim: boolean;\n metaColor?: string;\n suffix?: string;\n suffixColor?: string;\n}\n\nfunction renderNodeContent(node: TreeNode, maxWidth: number): NodeContent {\n switch (node.type) {\n case 'section': {\n switch (node.section) {\n case 'needs-you':\n return {\n icon: '',\n label: 'Needs You',\n meta: node.count > 0 ? `${node.count}` : '',\n color: node.count > 0 ? 'red' : 'gray',\n dim: false,\n metaColor: 'red',\n };\n case 'running':\n return {\n icon: '',\n label: 'Running',\n meta: node.count > 0 ? `${node.count}` : '',\n color: 'green',\n dim: false,\n metaColor: 'gray',\n };\n case 'done':\n return {\n icon: '',\n label: `Done (${node.count})`,\n meta: '',\n color: 'gray',\n dim: true,\n };\n }\n }\n case 'needs-you-virtual': {\n const hasPending = node.pendingCount > 0;\n return {\n icon: '⚑',\n label: 'Needs You',\n meta: hasPending ? `${node.pendingCount} pending` : '',\n color: hasPending ? 'red' : 'gray',\n dim: !hasPending,\n metaColor: hasPending ? 'red' : undefined,\n };\n }\n case 'session': {\n const icon = statusIndicator(node.status);\n const color = statusColor(node.status);\n const dim = node.status === 'completed' || node.orphaned === true;\n const cyclePart = node.cycleCount > 0 ? `C${node.cycleCount}` : '';\n // Use tracked active time (matches detail panel), not wall-clock elapsed.\n const dur = formatDuration(node.activeMs);\n const agopart =\n node.status === 'completed' && node.completedAt ? formatTimeAgo(node.completedAt) : '';\n const askBadge = node.askCount ? `!${node.askCount}` : '';\n const meta = [askBadge, cyclePart, dur, agopart].filter(Boolean).join(' ');\n const metaColor = node.askCount ? 'red' : undefined;\n const suffix = node.orphaned ? '⚠ orphan' : undefined;\n const suffixColor = node.orphaned ? 'red' : undefined;\n const displayText = node.name ?? node.task;\n const suffixWidth = suffix ? suffix.length + 1 : 0;\n const maxLabel = Math.max(8, maxWidth - meta.length - 4 - suffixWidth);\n return { icon, label: truncate(displayText, maxLabel), meta, color, dim, metaColor, suffix, suffixColor };\n }\n case 'cycle': {\n const isRunning = !node.completedAt;\n const dur = isRunning ? 'running' : formatDuration(node.activeMs);\n const agents = `${node.agentCount} agent${node.agentCount !== 1 ? 's' : ''}`;\n const modeShort = abbreviateMode(node.mode);\n const mode = modeShort ? ` · ${modeShort}` : '';\n return {\n icon: isRunning ? '●' : '○',\n label: `C${node.cycleNumber}`,\n meta: `${dur} · ${agents}${mode}`,\n color: isRunning ? 'green' : 'gray',\n dim: !isRunning,\n };\n }\n case 'agent': {\n const icon = agentStatusIcon(node.status);\n const color = statusColor(node.status);\n const dur = formatDuration(node.activeMs);\n const durClr = durationColor(node.activeMs) || undefined;\n const dim = node.status === 'completed' || node.orphaned === true;\n const displayName = agentDisplayName({\n name: node.name,\n id: node.agentId,\n agentType: node.agentType,\n });\n const suffix = node.orphaned ? '⚠ orphan' : undefined;\n const suffixColor = node.orphaned ? 'red' : undefined;\n const suffixWidth = suffix ? suffix.length + 1 : 0;\n const maxLabel = Math.max(8, maxWidth - dur.length - 4 - suffixWidth);\n return {\n icon,\n label: truncate(displayName, maxLabel),\n meta: dur,\n color,\n dim,\n metaColor: durClr,\n suffix,\n suffixColor,\n };\n }\n case 'report': {\n const badge = node.reportType === 'final' ? 'FINAL' : 'UPDATE';\n const time = formatTime(node.timestamp);\n return {\n icon: node.reportType === 'final' ? '◆' : '◇',\n label: `${badge} ${time}`,\n meta: '',\n color: node.reportType === 'final' ? 'cyan' : 'yellow',\n dim: false,\n };\n }\n case 'messages':\n return {\n icon: '✉',\n label: `Messages (${node.count})`,\n meta: '',\n color: 'yellow',\n dim: false,\n };\n case 'message': {\n const maxLabel = Math.max(8, maxWidth - 8);\n return {\n icon: '·',\n label: truncate(`${node.source}: ${node.summary}`, maxLabel),\n meta: formatTime(node.timestamp),\n color: 'gray',\n dim: true,\n };\n }\n case 'context':\n return {\n icon: '⊞',\n label: `Context (${node.fileCount})`,\n meta: '',\n color: 'white',\n dim: node.fileCount === 0,\n };\n case 'context-file': {\n const maxLabel = Math.max(8, maxWidth - 4);\n return {\n icon: '·',\n label: truncate(node.label, maxLabel),\n meta: '',\n color: 'gray',\n dim: false,\n };\n }\n }\n}\n\n// ─── Tree panel renderer ──────────────────────────────────────────────────────\n\nexport function renderTreePanel(\n buf: FrameBuffer,\n rect: Rect,\n nodes: TreeNode[],\n cursorIndex: number,\n focused: boolean,\n companion?: CompanionState | null,\n): void {\n const { x, y, w, h } = rect;\n\n // 1. Border — yellow when focused\n drawBorder(buf, x, y, w, h, focused ? 'cyan' : 'gray');\n\n // 2. Inner dimensions\n const innerX = x + 2;\n const innerW = w - 4;\n const innerY = y + 1;\n const innerH = h - 2;\n\n if (innerW <= 0 || innerH <= 0) return;\n\n // 3. Empty state\n if (nodes.length === 0) {\n writeClipped(buf, innerX, innerY, '\\x1b[1m Sessions \\x1b[0m', innerW);\n writeClipped(buf, innerX, innerY + 1, '\\x1b[2mNo sessions found.\\x1b[0m', innerW);\n writeClipped(buf, innerX, innerY + 2, '\\x1b[2mPress [n] to create one.\\x1b[0m', innerW);\n writeClipped(buf, innerX, innerY + 3, '\\x1b[2mPress [?] for all keybindings.\\x1b[0m', innerW);\n return;\n }\n\n // 4. Scroll logic — reserve rows at bottom for companion (blank + face + wrapped commentary)\n let companionRows = 0;\n let _companionCommentaryLines: string[] = [];\n if (companion) {\n const commentaryText = companion.lastCommentary?.text;\n if (commentaryText) {\n const words = commentaryText.split(' ');\n let current = '';\n let currentWidth = 0;\n for (const word of words) {\n const wordWidth = stringWidth(word);\n if (currentWidth + wordWidth + 1 > innerW && currentWidth > 0) {\n _companionCommentaryLines.push(current);\n current = word;\n currentWidth = wordWidth;\n } else if (currentWidth === 0) {\n current = word;\n currentWidth = wordWidth;\n } else {\n current = `${current} ${word}`;\n currentWidth += 1 + wordWidth;\n }\n }\n if (current.length > 0) _companionCommentaryLines.push(current);\n }\n companionRows = 1 + 1 + _companionCommentaryLines.length; // blank + face + commentary lines\n }\n const maxVisible = Math.max(1, innerH - companionRows);\n const halfVisible = Math.floor(maxVisible / 2);\n const scrollOffset = Math.max(\n 0,\n Math.min(cursorIndex - halfVisible, nodes.length - maxVisible),\n );\n\n // 5. Scroll indicator adjustments\n const hasTopIndicator = scrollOffset > 0;\n const hasBottomIndicator = scrollOffset + maxVisible < nodes.length;\n\n let rowStart = innerY;\n let availRows = maxVisible;\n\n if (hasTopIndicator) {\n const topMore = scrollOffset;\n writeClipped(buf, innerX, rowStart, `\\x1b[2m↑ ${topMore} more\\x1b[0m`, innerW);\n rowStart++;\n availRows--;\n }\n\n if (hasBottomIndicator) {\n availRows--;\n }\n\n // 6. Render visible nodes\n const visible = nodes.slice(scrollOffset, scrollOffset + availRows + (hasBottomIndicator ? 1 : 0));\n const renderCount = Math.min(visible.length, availRows);\n\n for (let i = 0; i < renderCount; i++) {\n const node = visible[i]!;\n const realIdx = scrollOffset + i;\n const isSelected = realIdx === cursorIndex;\n const prefix = node.prefix ?? renderTreePrefix(node, nodes, realIdx);\n const contentWidth = innerW;\n const { icon, label, meta, color, dim, metaColor, suffix, suffixColor } = renderNodeContent(\n node,\n contentWidth - prefix.length,\n );\n\n // Build ANSI string\n let content = '';\n\n // icon with color\n if (icon) {\n if (dim) content += `\\x1b[2;${colorToSGR(color)}m${icon}\\x1b[0m `;\n else content += `\\x1b[${colorToSGR(color)}m${icon}\\x1b[0m `;\n }\n\n // label\n if (dim) content += `\\x1b[2m${label}\\x1b[0m`;\n else content += label;\n\n // meta\n if (meta) {\n if (metaColor) content += ` \\x1b[${colorToSGR(metaColor)}m${meta}\\x1b[0m`;\n else content += ` \\x1b[2m${meta}\\x1b[0m`;\n }\n\n // suffix\n if (suffix && suffixColor) {\n content += ` \\x1b[${colorToSGR(suffixColor)}m${suffix}\\x1b[0m`;\n }\n\n let line = prefix;\n if (isSelected) {\n const bold = '\\x1b[1m';\n const inverse = focused ? '\\x1b[7m' : '';\n line += `${inverse}${bold}${content}\\x1b[0m`;\n } else {\n line += content;\n }\n\n writeClipped(buf, innerX, rowStart + i, line, innerW);\n }\n\n // 7. Bottom scroll indicator\n if (hasBottomIndicator) {\n const bottomMore = nodes.length - scrollOffset - maxVisible;\n const bottomRow = rowStart + availRows;\n writeClipped(buf, innerX, bottomRow, `\\x1b[2m↓ ${bottomMore} more\\x1b[0m`, innerW);\n }\n\n // 8. Companion pinned to bottom (blank + face + wrapped commentary)\n if (companion) {\n const commentaryCount = _companionCommentaryLines.length;\n const faceRow = y + h - 2 - commentaryCount;\n const hasActive = nodes.some((n) => n.type === 'session' && n.status === 'active');\n const fields: CompanionField[] = hasActive\n ? ['face', 'boulder', 'verb']\n : ['face', 'boulder', 'hobby'];\n // Don't use renderCompanion's internal color — applyColor's string replace\n // breaks when maxWidth truncates the result. Apply mood color externally.\n const faceLine = renderCompanion(companion, fields, {\n maxWidth: innerW,\n agentCount: companion.recentActiveAgents ?? 0,\n verbIndex: companion.spinnerVerbIndex,\n });\n const moodCode = getMoodAnsiCode(companion.mood);\n writeClipped(buf, innerX, faceRow, `\\x1b[${moodCode}m${faceLine}\\x1b[0m`, innerW);\n\n for (let i = 0; i < commentaryCount; i++) {\n writeClipped(buf, innerX, faceRow + 1 + i, `\\x1b[${moodCode}m${_companionCommentaryLines[i]}\\x1b[0m`, innerW);\n }\n }\n}\n","import {\n buildPanelRows,\n buildEmptyPanelRows,\n type Rect,\n} from '../render.js';\nimport type { AppState, CycleLog } from '../state.js';\nimport type {\n TreeNode,\n CycleTreeNode,\n AgentTreeNode,\n ReportTreeNode,\n MessageTreeNode,\n ContextFileTreeNode,\n} from '../types/tree.js';\nimport type { Session, Agent, OrchestratorCycle, StatusDigest } from '../../shared/types.js';\nimport { computeActiveTimeMs } from '../../shared/utils.js';\nimport type { ReportBlock } from '../lib/reports.js';\nimport {\n statusColor,\n formatDuration,\n formatTime,\n truncate,\n wrapText,\n stripFrontmatter,\n cleanMarkdown,\n seg,\n singleLine,\n agentDisplayName,\n reportBadge,\n agentStatusIcon,\n agentTypeColor,\n durationColor,\n modeColor,\n messageSourceLabel,\n messageSourceColor,\n extractFirstSentence,\n divider,\n type DetailLine,\n} from '../lib/format.js';\nimport { buildCycleFlowLines } from './cycle-flow.js';\nimport { coerceKind } from '../../shared/inbox-types.js';\n\n// ---------------------------------------------------------------------------\n// Public interface\n// ---------------------------------------------------------------------------\n\nexport interface DetailContext {\n nodes: TreeNode[];\n session: Session | null;\n agents: Agent[];\n reportBlocks: ReportBlock[];\n detailReportBlocks: ReportBlock[];\n contextFileContent: string | null;\n}\n\n// ---------------------------------------------------------------------------\n// PlanLine (copied from PlanView.tsx — no React dependency)\n// ---------------------------------------------------------------------------\n\ninterface PlanLine {\n text: string;\n bold?: boolean;\n dim?: boolean;\n color?: string;\n}\n\nfunction buildPlanLines(content: string, maxLines: number, width: number): PlanLine[] {\n const clean = stripFrontmatter(content);\n if (!clean.trim()) return [];\n\n const contentWidth = width - 4;\n const lines: PlanLine[] = [];\n const rawLines = clean.split('\\n');\n\n for (const rawLine of rawLines) {\n if (lines.length >= maxLines) break;\n\n const trimmed = rawLine.trim();\n\n // Skip frontmatter artifacts\n if (trimmed === '---') continue;\n\n // Headers — bold, with level-based indentation\n const headerMatch = rawLine.match(/^(#{1,6})\\s+(.+)/);\n if (headerMatch) {\n const level = headerMatch[1]!.length;\n const headerText = cleanMarkdown(headerMatch[2]!);\n const indent = ' '.repeat(Math.max(0, level - 1));\n if (lines.length > 0) lines.push({ text: ' ' });\n lines.push({\n text: ` ${indent}${headerText}`,\n bold: true,\n color: level <= 2 ? 'white' : undefined,\n });\n continue;\n }\n\n // Empty lines — pass through (but collapse multiples)\n if (!trimmed) {\n if (lines.length > 0 && lines[lines.length - 1]!.text !== '') {\n lines.push({ text: ' ' });\n }\n continue;\n }\n\n // Numbered list items\n const listMatch = trimmed.match(/^(\\d+)[.)]\\s+(.+)/);\n if (listMatch) {\n const cleaned = `${listMatch[1]}. ${cleanMarkdown(listMatch[2]!)}`;\n const wrapped = wrapText(cleaned, contentWidth - 6);\n for (const wl of wrapped) {\n if (lines.length >= maxLines) break;\n lines.push({ text: ` ${wl}`, dim: true });\n }\n continue;\n }\n\n // Checkbox items — must come before bullet match\n const checkboxMatch = trimmed.match(/^- \\[( |x|X)\\] (.+)/);\n if (checkboxMatch) {\n const checked = checkboxMatch[1] !== ' ';\n const checkboxText = cleanMarkdown(checkboxMatch[2]!);\n const icon = checked ? '☑' : '☐';\n const wrapped = wrapText(`${icon} ${checkboxText}`, contentWidth - 6);\n for (const wl of wrapped) {\n if (lines.length >= maxLines) break;\n lines.push({ text: ` ${wl}`, dim: true, color: checked ? 'green' : undefined });\n }\n continue;\n }\n\n // Bullet items\n const bulletMatch = trimmed.match(/^[-*+]\\s+(.+)/);\n if (bulletMatch) {\n const cleaned = `· ${cleanMarkdown(bulletMatch[1]!)}`;\n const wrapped = wrapText(cleaned, contentWidth - 6);\n for (const wl of wrapped) {\n if (lines.length >= maxLines) break;\n lines.push({ text: ` ${wl}`, dim: true });\n }\n continue;\n }\n\n // Regular content — clean and wrap\n const cleaned = cleanMarkdown(trimmed);\n const wrapped = wrapText(cleaned, contentWidth - 4);\n for (const wl of wrapped) {\n if (lines.length >= maxLines) break;\n lines.push({ text: ` ${wl}`, dim: true });\n }\n }\n\n // Truncation indicator\n const totalContentLines = rawLines.filter((l) => l.trim()).length;\n if (lines.length >= maxLines && totalContentLines > maxLines) {\n lines[lines.length - 1] = { text: ' … [p] open in editor', dim: true };\n }\n\n return lines;\n}\n\n// ---------------------------------------------------------------------------\n// buildSessionLines (ported from SessionDetail.tsx buildLines)\n// ---------------------------------------------------------------------------\n\nfunction buildSessionLines(\n session: Session,\n planContent: string,\n goalContent: string | undefined,\n width: number,\n paneAlive: boolean,\n strategyContent: string = '',\n flowExpanded: boolean = false,\n): DetailLine[] {\n const lines: DetailLine[] = [];\n const contentWidth = width - 4;\n const agents = session.agents;\n const cycles = session.orchestratorCycles;\n const isDead = session.status === 'active' && !paneAlive;\n // Goal text\n const goalText = goalContent\n ? cleanMarkdown(stripFrontmatter(goalContent).trim())\n : session.task;\n goalText\n .split('\\n')\n .flatMap((l) => wrapText(l, contentWidth - 2))\n .forEach((line, i) => {\n lines.push(singleLine(`${i === 0 ? ' ' : ' '}${line}`, { bold: true }));\n });\n\n // Status bar\n const lastCycle = cycles.length > 0 ? cycles[cycles.length - 1]! : null;\n const cycleNum = lastCycle !== null ? lastCycle.cycle : 0;\n const mode = lastCycle !== null && lastCycle.mode !== undefined ? lastCycle.mode : '';\n const runningAgents = agents.filter((a) => a.status === 'running').length;\n const completedAgents = agents.filter((a) => a.status === 'completed').length;\n const elapsed = formatDuration(session.createdAt, session.completedAt);\n const activeMs = computeActiveTimeMs(session);\n const activeTime = formatDuration(activeMs);\n const modeLabelColor = modeColor(mode);\n lines.push([\n seg(' '),\n seg(isDead ? '✕ dead' : session.status, {\n color: statusColor(isDead ? 'crashed' : session.status),\n }),\n seg(` · cycle ${cycleNum}`, { dim: true }),\n ...(mode ? [seg(' (', { dim: true }), seg(mode, { color: modeLabelColor }), seg(')', { dim: true })] : []),\n seg(` · ${elapsed} · `, { dim: true }),\n seg(`${runningAgents} running`, { color: 'green' }),\n seg(' · ', { dim: true }),\n seg(`${completedAgents} done`, { color: 'cyan' }),\n seg(` · ${activeTime} active`, { dim: true }),\n ]);\n\n // Dead session warning\n if (isDead) {\n lines.push([\n seg(' '),\n seg(' ✕ DEAD ', { color: 'red', bold: true }),\n seg(' tmux window closed — [w] reopen [R] resume', { color: 'red' }),\n ]);\n }\n\n // Orphan tag\n if (session.orphaned) {\n lines.push([\n seg(' '),\n seg('⚠ orphan', { color: 'red', bold: true }),\n seg(' — orchestrator process lost', { color: 'red' }),\n ]);\n }\n\n // Plan / Strategy section\n lines.push(singleLine(' '));\n if (strategyContent) {\n lines.push([seg(' ▎ ◈ STRATEGY', { color: 'yellow', bold: true })]);\n const stratLines = buildPlanLines(strategyContent, 99999, width);\n if (stratLines.length === 0) {\n lines.push(singleLine(' (empty)', { dim: true, italic: true }));\n } else {\n for (const pl of stratLines) {\n lines.push(singleLine(pl.text, { bold: pl.bold, dim: pl.dim, color: pl.color }));\n }\n }\n } else {\n lines.push([seg(' ▎ ◈ PLAN', { color: 'yellow', bold: true })]);\n const planLines = buildPlanLines(planContent, 99999, width);\n if (planLines.length === 0) {\n lines.push(singleLine(' orchestrator will create one', { dim: true, italic: true }));\n } else {\n for (const pl of planLines) {\n lines.push(singleLine(pl.text, { bold: pl.bold, dim: pl.dim, color: pl.color }));\n }\n }\n }\n\n // Completion report\n if (session.status === 'completed' && session.completionReport) {\n lines.push(singleLine(' '));\n lines.push([seg(' ▎ ✓ COMPLETION', { color: 'cyan', bold: true })]);\n wrapText(session.completionReport, contentWidth - 6).forEach((l) => {\n lines.push(singleLine(` ${l}`, { dim: true }));\n });\n }\n\n // Cycle flow visualization\n lines.push(singleLine(' '));\n lines.push(...buildCycleFlowLines(session, contentWidth, flowExpanded));\n\n return lines;\n}\n\n// ---------------------------------------------------------------------------\n// buildCycleLines (ported from CycleDetail.tsx buildLines)\n// ---------------------------------------------------------------------------\n\nfunction buildCycleLines(cycle: OrchestratorCycle, agents: Agent[], width: number): DetailLine[] {\n const lines: DetailLine[] = [];\n const contentWidth = width - 4;\n const isRunning = !cycle.completedAt;\n const dur = isRunning ? 'running' : formatDuration(cycle.activeMs);\n const cycleAgents = agents.filter((a) => cycle.agentsSpawned.includes(a.id));\n\n lines.push(singleLine(` Cycle ${cycle.cycle}`, { bold: true }));\n lines.push([\n seg(' '),\n seg(isRunning ? 'running' : 'completed', { color: isRunning ? 'green' : 'gray' }),\n seg(` · ${dur} · ${cycleAgents.length} agent${cycleAgents.length !== 1 ? 's' : ''}`, { dim: true }),\n ...(cycle.mode\n ? [seg(' · ', { dim: true }), seg(cycle.mode, { color: modeColor(cycle.mode) })]\n : []),\n ]);\n lines.push(singleLine(\n ` ${formatTime(cycle.timestamp)}${cycle.completedAt ? ` → ${formatTime(cycle.completedAt)}` : ''}`,\n { dim: true },\n ));\n if (cycle.claudeSessionId) {\n lines.push(singleLine(` Session: ${cycle.claudeSessionId}`, { dim: true }));\n }\n\n lines.push(singleLine(' '));\n lines.push([seg(' ▎ ⊞ AGENTS', { color: 'green', bold: true })]);\n\n if (cycleAgents.length === 0) {\n lines.push(singleLine(' orchestrator spawning agents…', { dim: true, italic: true }));\n } else {\n for (const agent of cycleAgents) {\n const nameLabel = agentDisplayName(agent);\n const instrPreview = agent.instruction.split('\\n')[0]!;\n const latestReport = agent.reports.length > 0 ? agent.reports[agent.reports.length - 1]! : null;\n const reportSummary = latestReport !== null && agent.status === 'completed'\n ? extractFirstSentence(latestReport.summary, contentWidth - 14)\n : null;\n const agentDur = formatDuration(agent.activeMs);\n const durClrRaw = durationColor(agent.activeMs);\n const durClr = durClrRaw !== '' ? durClrRaw : undefined;\n const typeClrRaw = agentTypeColor(agent.agentType);\n const typeClr = typeClrRaw !== undefined ? typeClrRaw : undefined;\n\n lines.push([\n seg(' '),\n seg(agentStatusIcon(agent.status), { color: statusColor(agent.status) }),\n seg(` ${agent.id}`, { bold: true }),\n seg(` ${truncate(nameLabel, contentWidth - 30)}`, {\n color: typeClr,\n dim: typeClr === undefined,\n }),\n seg(` · ${agent.status} · `, { dim: true }),\n seg(agentDur, { color: durClr, dim: !durClr }),\n ]);\n\n if (instrPreview) {\n lines.push(singleLine(` ${truncate(instrPreview, contentWidth - 10)}`, { dim: true }));\n }\n\n if (reportSummary) {\n lines.push([\n seg(' '),\n seg('↳', { color: 'cyan' }),\n seg(` ${reportSummary}`, { dim: true }),\n ]);\n }\n }\n }\n\n if (cycle.nextPrompt) {\n lines.push(singleLine(' '));\n lines.push([seg(' ▎ ▷ NEXT PROMPT', { color: 'yellow', bold: true })]);\n for (const wl of wrapText(cycle.nextPrompt, contentWidth - 6)) {\n lines.push(singleLine(` ${wl}`, { dim: true }));\n }\n }\n\n return lines;\n}\n\n// ---------------------------------------------------------------------------\n// buildAgentLines (ported from AgentDetail.tsx buildLines)\n// ---------------------------------------------------------------------------\n\nfunction buildAgentLines(agent: Agent, reportBlocks: ReportBlock[] | undefined, width: number): DetailLine[] {\n const lines: DetailLine[] = [];\n const contentWidth = width - 4;\n const dur = formatDuration(agent.activeMs);\n const icon = agentStatusIcon(agent.status);\n const color = statusColor(agent.status);\n const nameLabel = agentDisplayName(agent);\n lines.push([\n seg(' '),\n seg(icon, { color }),\n seg(` ${agent.id} · ${nameLabel}`, { bold: true }),\n ]);\n\n lines.push([\n seg(' '),\n seg(agent.status, { color }),\n seg(` · ${dur} · ${agent.agentType}`, { dim: true }),\n ]);\n\n if (agent.killedReason) {\n lines.push(singleLine(` ⚠ ${agent.killedReason}`, { color: 'red' }));\n }\n\n lines.push(singleLine(' '));\n lines.push(singleLine(' ▎ ▷ INSTRUCTION', { color: 'white', bold: true }));\n for (const wl of wrapText(agent.instruction, contentWidth - 6)) {\n lines.push(singleLine(` ${wl}`, { dim: true }));\n }\n\n if (agent.reports.length > 0) {\n const hasResolved = reportBlocks && reportBlocks.length > 0;\n lines.push(singleLine(' '));\n lines.push([seg(` ▎ ◇ REPORTS (${agent.reports.length})`, { color: 'cyan', bold: true })]);\n\n if (hasResolved) {\n for (let i = 0; i < reportBlocks.length; i++) {\n const block = reportBlocks[i]!;\n const { label: badge, color: badgeColor } = reportBadge(block.type);\n\n if (i > 0) lines.push(singleLine(' '));\n lines.push([\n seg(' '),\n seg(badge, { color: badgeColor, bold: block.type === 'final' }),\n seg(` ${formatTime(block.timestamp)}`, { dim: true }),\n ]);\n for (const wl of wrapText(block.content.trim(), contentWidth - 10)) {\n lines.push(singleLine(` ${wl}`, { dim: true }));\n }\n }\n } else {\n for (const report of agent.reports) {\n const { label: badge, color: badgeColor } = reportBadge(report.type);\n lines.push([\n seg(' '),\n seg(badge, { color: badgeColor, bold: report.type === 'final' }),\n seg(` ${formatTime(report.timestamp)} ${report.summary.split('\\n')[0]}`, { dim: true }),\n ]);\n }\n }\n }\n\n lines.push(singleLine(' '));\n lines.push(singleLine(' ▎ ◦ META', { color: 'gray', bold: true }));\n lines.push(singleLine(` Spawned: ${formatTime(agent.spawnedAt)}`, { dim: true }));\n if (agent.completedAt) {\n lines.push(singleLine(` Completed: ${formatTime(agent.completedAt)}`, { dim: true }));\n }\n if (agent.claudeSessionId) {\n lines.push(singleLine(` Session: ${agent.claudeSessionId}`, { dim: true }));\n }\n if (agent.paneId) {\n lines.push(singleLine(` Pane: ${agent.paneId}`, { dim: true }));\n }\n return lines;\n}\n\n// ---------------------------------------------------------------------------\n// buildReportViewLines (ported from ReportView.tsx buildLines)\n// ---------------------------------------------------------------------------\n\nfunction buildReportViewLines(agent: Agent, reportBlocks: ReportBlock[], width: number): DetailLine[] {\n const lines: DetailLine[] = [];\n const contentWidth = width - 6;\n const dur = formatDuration(agent.activeMs);\n const icon = agentStatusIcon(agent.status);\n const color = statusColor(agent.status);\n const totalReports = agent.reports.length;\n const nameLabel = agentDisplayName(agent);\n\n lines.push([\n seg(' '),\n seg(icon, { color }),\n seg(' '),\n seg(agent.id, { bold: true }),\n seg(' ', { dim: true }),\n seg('·', { dim: true }),\n seg(' '),\n seg(nameLabel, { bold: true }),\n ]);\n\n lines.push(singleLine(\n ` ${agent.status} · ${dur} · ${agent.agentType} · ${totalReports} report${totalReports !== 1 ? 's' : ''}`,\n { dim: true },\n ));\n\n lines.push(singleLine(' ' + divider(contentWidth - 2), { dim: true }));\n\n if (reportBlocks.length === 0) {\n lines.push(singleLine(''));\n lines.push(singleLine(' No reports submitted yet.', { dim: true }));\n lines.push(singleLine(''));\n return lines;\n }\n\n for (let i = 0; i < reportBlocks.length; i++) {\n const report = reportBlocks[i]!;\n const time = formatTime(report.timestamp);\n\n if (i > 0) {\n lines.push(singleLine(''));\n lines.push(singleLine(` ${divider(contentWidth - 2, '·')}`, { dim: true }));\n lines.push(singleLine(''));\n }\n\n const { label: badge, color: badgeColor } = reportBadge(report.type);\n lines.push([\n seg(` ${badge}`, { color: badgeColor, bold: report.type === 'final' }),\n seg(` ${time}`, { color: badgeColor }),\n ]);\n\n lines.push(singleLine(''));\n\n const wrapped = wrapText(report.content.trim(), contentWidth - 4);\n for (const line of wrapped) {\n lines.push(singleLine(` ${line}`));\n }\n }\n\n lines.push(singleLine(''));\n return lines;\n}\n\n// ---------------------------------------------------------------------------\n// buildLogsLines (ported from LogsPanel.tsx buildLines)\n// ---------------------------------------------------------------------------\n\nexport function buildLogsLines(cycleLogs: CycleLog[], width: number): DetailLine[] {\n const lines: DetailLine[] = [];\n const contentWidth = width - 4;\n\n if (cycleLogs.length === 0) {\n return lines;\n }\n\n const sorted = [...cycleLogs].sort((a, b) => b.cycle - a.cycle);\n\n for (const { cycle, content } of sorted) {\n lines.push([seg(` Cycle ${cycle}`, { color: 'blue', bold: true })]);\n\n const cleaned = cleanMarkdown(stripFrontmatter(content)).trim();\n if (cleaned) {\n for (const rawLine of cleaned.split('\\n')) {\n const wrapped = wrapText(rawLine, contentWidth - 2);\n for (const wl of wrapped) {\n lines.push([seg(` ${wl}`, { dim: true })]);\n }\n }\n }\n\n lines.push([seg(' ')]);\n }\n\n return lines;\n}\n\n// ---------------------------------------------------------------------------\n// Main entry points\n// ---------------------------------------------------------------------------\n\nexport function renderDetailRows(\n rect: Rect,\n state: AppState,\n detailCtx: DetailContext,\n): string[] {\n const { session, agents, reportBlocks, detailReportBlocks, contextFileContent } = detailCtx;\n const focused = state.focusPane === 'detail';\n\n // Report detail mode — full panel\n if (state.mode === 'report-detail') {\n const reportAgent = agents.find((a) => a.id === state.targetAgentId);\n if (reportAgent) {\n const lines = buildReportViewLines(reportAgent, reportBlocks, rect.w);\n return buildPanelRows(rect, lines, state.detailScroll, focused, 'cyan');\n }\n }\n\n // No cursor / no session → empty state\n const cursorNode: TreeNode | undefined = detailCtx.nodes[state.cursorIndex];\n if (!cursorNode || !session) {\n return buildEmptyPanelRows(rect, false, 'gray', '\\x1b[2mSelect a session to view details\\x1b[0m');\n }\n\n // Session data hasn't arrived yet (poll debounced during rapid scrolling)\n if (cursorNode.sessionId !== session.id) {\n return buildEmptyPanelRows(rect, false, 'gray');\n }\n\n // Compute cache key from all inputs that affect line building\n const lastCycle = session.orchestratorCycles[session.orchestratorCycles.length - 1];\n const cacheKey = [\n cursorNode.id,\n cursorNode.type,\n state.mode,\n state.targetAgentId,\n rect.w,\n session.id,\n session.agents.length,\n session.orchestratorCycles.length,\n lastCycle?.completedAt ?? '',\n lastCycle?.agentsSpawned.length ?? 0,\n state.planContent.length,\n state.goalContent.length,\n state.strategyContent.length,\n state.paneAlive,\n detailReportBlocks.length,\n session.messages.length,\n state.contextFiles.length,\n contextFileContent?.length ?? -1,\n state.flowExpanded,\n ].join(':');\n\n let lines: DetailLine[];\n let borderColor = 'gray';\n\n if (cacheKey === state.detailCacheKey && state.cachedDetailLines !== null) {\n lines = state.cachedDetailLines;\n } else {\n switch (cursorNode.type) {\n case 'session': {\n lines = buildSessionLines(session, state.planContent, state.goalContent, rect.w, state.paneAlive, state.strategyContent, state.flowExpanded);\n break;\n }\n\n case 'cycle': {\n const cycleNode = cursorNode as CycleTreeNode;\n const cycle = session.orchestratorCycles.find((c) => c.cycle === cycleNode.cycleNumber);\n if (!cycle) {\n lines = buildSessionLines(session, state.planContent, state.goalContent, rect.w, state.paneAlive, state.strategyContent, state.flowExpanded);\n } else {\n lines = buildCycleLines(cycle, session.agents, rect.w);\n }\n break;\n }\n\n case 'agent': {\n const agentNode = cursorNode as AgentTreeNode;\n const agent = agents.find((a) => a.id === agentNode.agentId);\n if (!agent) {\n lines = buildSessionLines(session, state.planContent, state.goalContent, rect.w, state.paneAlive, state.strategyContent, state.flowExpanded);\n } else {\n lines = buildAgentLines(agent, detailReportBlocks, rect.w);\n }\n break;\n }\n\n case 'report': {\n const reportNode = cursorNode as ReportTreeNode;\n const agent = agents.find((a) => a.id === reportNode.agentId);\n if (!agent) {\n lines = buildSessionLines(session, state.planContent, state.goalContent, rect.w, state.paneAlive, state.strategyContent, state.flowExpanded);\n break;\n }\n const reportIdx = reportNode.reportIndex;\n const specificBlock = detailReportBlocks.find((_b, i) => {\n const originalIdx = agent.reports.length - 1 - i;\n return originalIdx === reportIdx;\n });\n if (specificBlock) {\n const { label: badge, color: badgeColor } = reportBadge(specificBlock.type);\n lines = [\n [seg(' '), seg(badge, { color: badgeColor }), seg(` ${agent.id} · ${agentDisplayName(agent)}`, { bold: true })],\n singleLine(` ${formatTime(specificBlock.timestamp)}`, { dim: true }),\n singleLine(' '),\n [seg(' ▎ CONTENT', { color: badgeColor, bold: true })],\n ...wrapText(specificBlock.content.trim(), rect.w - 8).map((l) => singleLine(` ${l}`)),\n ];\n borderColor = badgeColor;\n } else {\n lines = buildAgentLines(agent, detailReportBlocks, rect.w);\n }\n break;\n }\n\n case 'messages': {\n lines = [singleLine(` Messages (${session.messages.length})`, { bold: true })];\n if (session.messages.length === 0) {\n lines.push(singleLine(' No messages', { dim: true, italic: true }));\n } else {\n for (const msg of session.messages) {\n const time = formatTime(msg.timestamp);\n const agentId = msg.source.type === 'agent' ? msg.source.agentId : undefined;\n const label = messageSourceLabel(msg.source.type, agentId);\n const labelColor = messageSourceColor(msg.source.type);\n const maxContent = Math.max(10, rect.w - label.length - 20);\n lines.push([\n seg(` [${time}] `, { dim: true }),\n seg(`${label}: `, { color: labelColor, bold: true }),\n seg(wrapText(msg.summary.length > 0 ? msg.summary : msg.content, maxContent)[0]!, {}),\n ]);\n }\n }\n break;\n }\n\n case 'message': {\n const msgNode = cursorNode as MessageTreeNode;\n const msg = session.messages.find((m) => m.id === msgNode.messageId);\n lines = [singleLine(' Message', { bold: true })];\n if (msg) {\n lines.push(singleLine(` ${msgNode.source} · ${msgNode.timestamp}`, { dim: true }));\n for (const l of wrapText(msg.content, rect.w - 8)) {\n lines.push(singleLine(` ${l}`));\n }\n } else {\n lines.push(singleLine(' Message not found', { dim: true }));\n }\n break;\n }\n\n case 'context': {\n lines = [\n [seg(' '), seg('⊞', { color: 'white' }), seg(` Context (${state.contextFiles.length})`, { bold: true })],\n ];\n if (state.contextFiles.length === 0) {\n lines.push(singleLine(' No context files found.', { dim: true }));\n } else {\n for (const f of state.contextFiles) {\n lines.push(singleLine(` · ${f}`, { dim: true }));\n }\n }\n break;\n }\n\n case 'context-file': {\n const ctxFileNode = cursorNode as ContextFileTreeNode;\n lines = [\n [seg(' '), seg('⊞', { color: 'white' }), seg(` ${ctxFileNode.label}`, { bold: true })],\n singleLine(' '),\n ];\n if (contextFileContent == null) {\n lines.push(singleLine(' File not found or unreadable.', { dim: true }));\n } else {\n const wrapped = wrapText(stripFrontmatter(contextFileContent), rect.w - 8);\n if (wrapped.length === 0) {\n lines.push(singleLine(' (empty)', { dim: true }));\n } else {\n for (const l of wrapped) {\n lines.push(singleLine(` ${l}`));\n }\n }\n }\n borderColor = 'white';\n break;\n }\n\n default: {\n lines = buildSessionLines(session, state.planContent, state.goalContent, rect.w, state.paneAlive, state.strategyContent, state.flowExpanded);\n break;\n }\n }\n\n state.cachedDetailLines = lines;\n state.detailCacheKey = cacheKey;\n }\n\n // Compute borderColor from node type (cheap, no need to cache)\n if (cursorNode.type === 'context-file') {\n borderColor = 'white';\n } else if (cursorNode.type === 'report') {\n const reportNode = cursorNode as ReportTreeNode;\n const agent = agents.find((a) => a.id === reportNode.agentId);\n if (agent) {\n const reportIdx = reportNode.reportIndex;\n const specificBlock = detailReportBlocks.find((_b, i) => {\n const originalIdx = agent.reports.length - 1 - i;\n return originalIdx === reportIdx;\n });\n if (specificBlock) borderColor = reportBadge(specificBlock.type).color;\n }\n }\n\n return buildPanelRows(rect, lines, state.detailScroll, focused, borderColor, state.detailRenderedCache);\n}\n\n// ---------------------------------------------------------------------------\n// buildDigestLines / renderDigestRows\n// ---------------------------------------------------------------------------\n\nfunction buildDigestLines(digest: StatusDigest, width: number): DetailLine[] {\n const lines: DetailLine[] = [];\n const contentWidth = width - 4;\n\n // Recent Work\n lines.push([seg(' Recent Work', { color: 'cyan', bold: true })]);\n for (const wl of wrapText(digest.recentWork, contentWidth - 4)) {\n lines.push(singleLine(` ${wl}`));\n }\n lines.push(singleLine(''));\n\n // Current Activity\n lines.push([seg(' Now', { color: 'white', bold: true })]);\n for (const wl of wrapText(digest.currentActivity, contentWidth - 4)) {\n lines.push(singleLine(` ${wl}`));\n }\n lines.push(singleLine(''));\n\n // What's Next\n lines.push([seg(' Up Next', { color: 'white', bold: true })]);\n for (const wl of wrapText(digest.whatsNext, contentWidth - 4)) {\n lines.push([seg(` ${wl}`, { dim: true })]);\n }\n lines.push(singleLine(''));\n\n // Unusual Events\n if (digest.unusualEvents.length > 0) {\n lines.push([seg(' Unusual', { color: 'yellow', bold: true })]);\n for (const event of digest.unusualEvents) {\n for (const wl of wrapText(`· ${event}`, contentWidth - 4)) {\n lines.push([seg(` ${wl}`, { color: 'yellow' })]);\n }\n }\n }\n\n return lines;\n}\n\nfunction buildDoneDigestLines(session: Session, digest: StatusDigest | null, width: number): DetailLine[] {\n const lines: DetailLine[] = [];\n const contentWidth = width - 4;\n\n // KPI band — most-asked stats first\n const kpiCycles = session.orchestratorCycles.length;\n const kpiAgents = session.agents.length;\n const kpiWall = session.wallClockMs\n ? formatMs(session.wallClockMs)\n : (session.completedAt ? formatDuration(session.createdAt, session.completedAt) : '—');\n const kpiActive = formatMs(computeActiveTimeMs(session));\n\n lines.push([seg(' Stats', { color: 'cyan', bold: true })]);\n lines.push([\n seg(' cycles ', { dim: true }),\n seg(String(kpiCycles), { color: 'white', bold: true }),\n seg(' · agents ', { dim: true }),\n seg(String(kpiAgents), { color: 'white', bold: true }),\n ]);\n lines.push([\n seg(' wall ', { dim: true }),\n seg(kpiWall, { color: 'white', bold: true }),\n seg(' · active ', { dim: true }),\n seg(kpiActive, { color: 'white', bold: true }),\n ]);\n lines.push(singleLine(''));\n\n // What shipped (recapped from digest if present)\n if (digest?.recentWork) {\n lines.push([seg(' What shipped', { color: 'cyan', bold: true })]);\n for (const wl of wrapText(digest.recentWork, contentWidth - 4)) {\n lines.push(singleLine(` ${wl}`));\n }\n lines.push(singleLine(''));\n }\n\n // Final state — replaces Now/Up Next\n lines.push([seg(' Final', { color: 'white', bold: true })]);\n if (session.completedAt) {\n lines.push([seg(` completed ${formatTimestampShort(session.completedAt)}`, { dim: true })]);\n }\n if (digest?.currentActivity) {\n for (const wl of wrapText(digest.currentActivity, contentWidth - 4)) {\n lines.push([seg(` ${wl}`, { dim: true })]);\n }\n }\n lines.push(singleLine(''));\n\n // Notable — preserved from Unusual; still useful post-hoc\n if (digest && digest.unusualEvents.length > 0) {\n lines.push([seg(' Notable', { color: 'yellow', bold: true })]);\n for (const event of digest.unusualEvents) {\n for (const wl of wrapText(`· ${event}`, contentWidth - 4)) {\n lines.push([seg(` ${wl}`, { color: 'yellow' })]);\n }\n }\n }\n\n return lines;\n}\n\nfunction formatMs(ms: number): string {\n if (!ms || ms < 0) return '—';\n const sec = Math.floor(ms / 1000);\n if (sec < 60) return `${sec}s`;\n const min = Math.floor(sec / 60);\n if (min < 60) return `${min}m${sec % 60 ? ` ${sec % 60}s` : ''}`;\n const hr = Math.floor(min / 60);\n return `${hr}h${min % 60 ? ` ${min % 60}m` : ''}`;\n}\n\nfunction formatTimestampShort(iso: string): string {\n try {\n const d = new Date(iso);\n if (isNaN(d.getTime())) return iso;\n return d.toLocaleString();\n } catch {\n return iso;\n }\n}\n\nfunction renderFleetRollup(rect: Rect, state: AppState, focused: boolean): string[] {\n const items = state.aggregateInbox;\n const sessions = state.sessions;\n const cacheKey = `rollup:${items.length}:${sessions.length}:${items.map(i => `${i.askId}:${i.status}`).join(',')}:${rect.w}`;\n let lines: DetailLine[];\n if (cacheKey === state.digestCacheKey && state.cachedDigestLines !== null) {\n lines = state.cachedDigestLines;\n } else {\n const byKind = new Map<string, number>();\n for (const i of items) {\n const k = coerceKind(i.kind);\n byKind.set(k, (byKind.get(k) ?? 0) + 1);\n }\n const byStatus = new Map<string, number>();\n for (const s of sessions) {\n byStatus.set(s.status, (byStatus.get(s.status) ?? 0) + 1);\n }\n const uniqueSessions = new Set(items.map(i => i.sessionId)).size;\n lines = [];\n lines.push([seg(' Fleet Inbox', { color: 'red', bold: true })]);\n lines.push(singleLine(` ${items.length} pending across ${uniqueSessions} sessions`, { dim: true }));\n lines.push(singleLine(' '));\n lines.push([seg(' By Type', { color: 'cyan', bold: true })]);\n for (const [kind, count] of byKind) {\n lines.push(singleLine(` · ${kind}: ${count}`, { dim: true }));\n }\n lines.push(singleLine(' '));\n lines.push([seg(' Sessions', { color: 'white', bold: true })]);\n for (const [status, count] of byStatus) {\n lines.push(singleLine(` · ${status}: ${count}`, { dim: true }));\n }\n state.cachedDigestLines = lines;\n state.digestCacheKey = cacheKey;\n }\n return buildPanelRows(rect, lines, state.digestScroll, focused, 'red', state.digestRenderedCache);\n}\n\nexport function renderDigestRows(\n rect: Rect,\n state: AppState,\n): string[] {\n const focused = state.focusPane === 'logs';\n const digest = state.digestData;\n const session = state.selectedSession;\n\n if (state.detailMode === 'cross-session-inbox') {\n return renderFleetRollup(rect, state, focused);\n }\n\n if (!digest && !session) {\n return buildEmptyPanelRows(rect, focused, 'cyan', '\\x1b[2mAwaiting digest...\\x1b[0m');\n }\n\n // Combined cache key: digest + flow inputs\n const lastCycle = session?.orchestratorCycles[session.orchestratorCycles.length - 1];\n const agentStatuses = session?.agents.map(a => `${a.id}:${a.status}`).join(',') ?? '';\n const isDone = session?.status === 'completed';\n const cacheKey = [\n JSON.stringify(digest),\n session?.id ?? '',\n session?.status ?? '',\n session?.orchestratorCycles.length ?? 0,\n lastCycle?.completedAt ?? '',\n lastCycle?.agentsSpawned.length ?? 0,\n lastCycle?.nextPrompt?.length ?? 0,\n agentStatuses,\n state.flowExpanded,\n rect.w,\n ].join(':');\n\n let lines: DetailLine[];\n if (cacheKey === state.digestCacheKey && state.cachedDigestLines !== null) {\n lines = state.cachedDigestLines;\n } else {\n lines = [];\n if (isDone && session) {\n lines.push(...buildDoneDigestLines(session, digest, rect.w));\n } else if (digest) {\n lines.push(...buildDigestLines(digest, rect.w));\n }\n if (session) {\n lines.push(singleLine(''));\n lines.push(...buildCycleFlowLines(session, rect.w - 4, state.flowExpanded));\n }\n state.cachedDigestLines = lines;\n state.digestCacheKey = cacheKey;\n }\n\n return buildPanelRows(rect, lines, state.digestScroll, focused, 'cyan', state.digestRenderedCache);\n}\n\n\n","import type { Session } from './types.js';\n\n/**\n * Return the tracked active time for a session.\n * Active time is accumulated by the daemon's pane monitor, excluding sleep/idle gaps.\n */\nexport function computeActiveTimeMs(session: Session): number {\n return session.activeMs;\n}\n","import stringWidth from 'string-width';\nimport type { Session, Agent, OrchestratorCycle } from '../../shared/types.js';\nimport { formatDuration } from '../../shared/format.js';\nimport {\n seg,\n singleLine,\n agentDisplayName,\n agentStatusIcon,\n statusColor,\n durationColor,\n modeColor,\n abbreviateMode,\n truncate,\n wrapText,\n formatTime,\n type DetailLine,\n type Seg,\n} from '../lib/format.js';\n\n// ---------------------------------------------------------------------------\n// Background tints (dark ANSI 24-bit backgrounds)\n// ---------------------------------------------------------------------------\n\nconst BG_TINTS: Record<string, string> = {\n yellow: '48;2;40;35;20',\n blue: '48;2;20;25;45',\n green: '48;2;20;35;20',\n magenta: '48;2;30;22;40',\n cyan: '48;2;18;30;38',\n red: '48;2;40;20;22',\n gray: '48;2;25;26;32',\n white: '48;2;30;30;30',\n};\n\n// Map tmux/extended color names to standard ANSI color names for seg()\nconst TMUX_TO_ANSI: Record<string, string> = {\n colour208: 'yellow', // orange\n colour6: 'cyan', // teal\n orange: 'yellow',\n teal: 'cyan',\n};\n\n/** Resolve a color name (possibly tmux-extended) to a valid ANSI color name */\nfunction resolveColor(color: string): string {\n return TMUX_TO_ANSI[color] ?? color;\n}\n\n// ---------------------------------------------------------------------------\n// Phase detection\n// ---------------------------------------------------------------------------\n\ntype Phase = 'orchestrator' | 'agents' | 'between' | 'complete';\n\nfunction getCurrentPhase(session: Session): Phase {\n if (session.status === 'completed') return 'complete';\n const cycles = session.orchestratorCycles;\n if (cycles.length === 0) return 'orchestrator';\n const lastCycle = cycles[cycles.length - 1]!;\n const cycleAgents = session.agents.filter(a => lastCycle.agentsSpawned.includes(a.id));\n\n if (!lastCycle.completedAt) {\n return cycleAgents.length > 0 ? 'agents' : 'orchestrator';\n }\n\n const allDone = cycleAgents.every(a => a.status !== 'running');\n if (cycleAgents.length > 0 && !allDone) return 'agents';\n if (cycleAgents.length > 0 && allDone && lastCycle.nextPrompt) return 'between';\n return 'orchestrator';\n}\n\n// ---------------------------------------------------------------------------\n// Box rendering primitives\n// ---------------------------------------------------------------------------\n\n/** Pad or truncate text to exactly `w` display columns */\nfunction padTo(text: string, w: number): string {\n const tw = stringWidth(text);\n if (tw >= w) return truncate(text, w);\n return text + ' '.repeat(w - tw);\n}\n\n/** Build a full-width orchestrator box */\nfunction buildOrchestratorNode(\n cycle: OrchestratorCycle,\n agents: Agent[],\n width: number,\n bright: boolean,\n showConnectorBottom: boolean,\n): DetailLine[] {\n const lines: DetailLine[] = [];\n const inner = width - 2; // inside borders\n const bg = BG_TINTS.yellow;\n const dim = !bright;\n const isRunning = !cycle.completedAt;\n const icon = isRunning ? '●' : '○';\n const cycleLabel = `C${cycle.cycle}`;\n const modeLabel = abbreviateMode(cycle.mode);\n const mColor = modeColor(cycle.mode);\n\n let rightText: string;\n if (isRunning) {\n rightText = 'running';\n } else {\n const dur = formatDuration(cycle.activeMs);\n const time = formatTime(cycle.timestamp);\n rightText = `${dur} ${time}`;\n }\n\n const leftContent = `${icon} ${cycleLabel} ${modeLabel}`;\n const leftW = stringWidth(leftContent);\n const rightW = stringWidth(rightText);\n const gap = Math.max(1, inner - 2 - leftW - rightW);\n\n // Top border\n lines.push([seg('╭' + '─'.repeat(inner) + '╮', { color: 'yellow', dim })]);\n\n // Content row with bg tint\n const contentSegs: Seg[] = [\n seg('│', { color: 'yellow', dim }),\n seg(' ' + icon + ' ', { bg, color: isRunning ? 'green' : undefined, dim: !isRunning && dim, bold: bright }),\n seg(cycleLabel, { bg, dim, bold: bright }),\n seg(' ', { bg }),\n seg(modeLabel, { bg, color: mColor, dim }),\n seg(' '.repeat(gap), { bg }),\n ];\n if (isRunning && bright) {\n contentSegs.push(seg(rightText, { bg, color: 'green', bold: true }));\n } else {\n contentSegs.push(seg(rightText, { bg, dim }));\n }\n contentSegs.push(seg(' ', { bg }));\n // Pad remaining to fill inner width\n const usedWidth = 1 + 1 + 1 + 1 + stringWidth(cycleLabel) + 2 + stringWidth(modeLabel) + gap + stringWidth(rightText) + 1;\n if (usedWidth < inner) {\n contentSegs.push(seg(' '.repeat(inner - usedWidth), { bg }));\n }\n contentSegs.push(seg('│', { color: 'yellow', dim }));\n lines.push(contentSegs);\n\n // Agent summary row\n if (agents.length > 0) {\n const running = agents.filter(a => a.status === 'running').length;\n const done = agents.filter(a => a.status === 'completed').length;\n const failed = agents.filter(a => a.status === 'killed' || a.status === 'crashed').length;\n const parts: Seg[] = [\n seg('│', { color: 'yellow', dim }),\n seg(` ${agents.length} agent${agents.length !== 1 ? 's' : ''}: `, { bg, dim: true }),\n ];\n if (running > 0) parts.push(seg(`${running}▶ `, { bg, color: 'green', dim }));\n if (done > 0) parts.push(seg(`${done}✓ `, { bg, color: 'cyan', dim }));\n if (failed > 0) parts.push(seg(`${failed}✕ `, { bg, color: 'red', dim }));\n // Compute used width for padding\n const labelLen = ` ${agents.length} agent${agents.length !== 1 ? 's' : ''}: `.length;\n const countLen = (running > 0 ? `${running}▶ `.length : 0) + (done > 0 ? `${done}✓ `.length : 0) + (failed > 0 ? `${failed}✕ `.length : 0);\n const remaining = Math.max(0, inner - labelLen - countLen);\n parts.push(seg(' '.repeat(remaining), { bg }));\n parts.push(seg('│', { color: 'yellow', dim }));\n lines.push(parts);\n }\n\n // Bottom border — with or without connector\n if (showConnectorBottom) {\n const mid = Math.floor(inner / 2);\n const left = mid;\n const right = inner - mid - 1;\n lines.push([seg('╰' + '─'.repeat(left) + '┬' + '─'.repeat(right) + '╯', { color: 'yellow', dim })]);\n } else {\n lines.push([seg('╰' + '─'.repeat(inner) + '╯', { color: 'yellow', dim })]);\n }\n\n return lines;\n}\n\n/** Canonical stem column — all vertical connectors use this */\nfunction stemCol(width: number): number {\n return Math.floor(width / 2);\n}\n\n/** Build the vertical connector line between orchestrator and agent branch */\nfunction buildVerticalConnector(width: number, dim: boolean): DetailLine {\n const col = stemCol(width);\n return [\n seg(' '.repeat(col)),\n seg('│', { dim }),\n ];\n}\n\n/** Build horizontal branch connector: ┌────┼────┐ */\nfunction buildBranchConnector(\n boxWidth: number,\n count: number,\n totalWidth: number,\n direction: 'down' | 'up',\n): DetailLine[] {\n if (count === 0) return [];\n const centers = boxCenters(boxWidth, count, totalWidth);\n const mid = stemCol(totalWidth);\n const lineStart = centers[0]!;\n const lineEnd = centers[centers.length - 1]!;\n\n if (count === 1) {\n // Single agent — just a vertical line at center\n return [buildVerticalConnector(totalWidth, false)];\n }\n\n // Build the horizontal branch line\n const row = new Array(totalWidth).fill(' ');\n const upChar = direction === 'down' ? '┬' : '┴';\n const leftCorner = direction === 'down' ? '┌' : '└';\n const rightCorner = direction === 'down' ? '┐' : '┘';\n\n row[lineStart] = leftCorner;\n row[lineEnd] = rightCorner;\n for (let i = lineStart + 1; i < lineEnd; i++) {\n row[i] = '─';\n }\n // Place T-junctions at each box center (overwrite ─)\n row[mid] = '┼';\n for (const c of centers) {\n if (c !== mid && c !== lineStart && c !== lineEnd) {\n row[c] = upChar;\n }\n }\n\n return [[seg(row.join(''), { dim: false })]];\n}\n\n/** Get a short summary for an agent: report excerpt or instruction preview */\nfunction agentSummary(a: Agent, maxW: number): string {\n // Prefer final report summary\n if (a.reports.length > 0) {\n const last = a.reports[a.reports.length - 1]!;\n const prefix = last.type === 'final' ? '↳ ' : '… ';\n return prefix + truncate(last.summary.split('\\n')[0]!, maxW - 2);\n }\n // Fall back to instruction preview\n return truncate(a.instruction.split('\\n')[0]!, maxW);\n}\n\n/**\n * Compute leftPad so the center box's ┴/┬ aligns with stemCol.\n * For odd counts the middle box aligns exactly; for even counts\n * we fall back to simple centering (no single \"middle\" box).\n */\nfunction alignedLeftPad(boxWidth: number, count: number, totalWidth: number): number {\n if (count === 0) return 0;\n const stem = stemCol(totalWidth);\n const midIdx = Math.floor((count - 1) / 2);\n const idealPad = stem - midIdx * boxWidth - Math.floor(boxWidth / 2);\n return Math.max(0, idealPad);\n}\n\n/** Compute box center positions for a row of `count` boxes */\nfunction boxCenters(boxWidth: number, count: number, totalWidth: number): number[] {\n const leftPad = alignedLeftPad(boxWidth, count, totalWidth);\n const centers: number[] = [];\n for (let i = 0; i < count; i++) {\n centers.push(leftPad + i * boxWidth + Math.floor(boxWidth / 2));\n }\n return centers;\n}\n\n/** Build a fan-in line from multiple box-bottom ┬ to a single stem center */\nfunction buildInterRowFanIn(\n prevCenters: number[],\n totalWidth: number,\n): DetailLine[] {\n const mid = stemCol(totalWidth);\n if (prevCenters.length <= 1) {\n // Single box — just vertical at the box center (might differ from stem)\n const col = prevCenters[0] ?? mid;\n if (col === mid) return [buildVerticalConnector(totalWidth, false)];\n // Connect box center to stem\n const row = new Array(totalWidth).fill(' ');\n const left = Math.min(col, mid);\n const right = Math.max(col, mid);\n row[left] = '└';\n row[right] = '┘';\n for (let i = left + 1; i < right; i++) row[i] = '─';\n if (col === left) row[col] = '┴';\n if (col === right) row[col] = '┴';\n row[mid] = mid === left || mid === right ? '┼' : '┼';\n // Overwrite corners that are the stem\n return [[seg(row.join(''))], buildVerticalConnector(totalWidth, false)];\n }\n const lineStart = Math.min(prevCenters[0]!, mid);\n const lineEnd = Math.max(prevCenters[prevCenters.length - 1]!, mid);\n const row = new Array(totalWidth).fill(' ');\n row[lineStart] = '└';\n row[lineEnd] = '┘';\n for (let i = lineStart + 1; i < lineEnd; i++) row[i] = '─';\n row[mid] = '┼';\n for (const c of prevCenters) {\n if (c !== lineStart && c !== lineEnd && c !== mid) row[c] = '┴';\n if (c === lineStart && c !== mid) row[c] = '┴';\n if (c === lineEnd && c !== mid) row[c] = '┴';\n }\n return [[seg(row.join(''))], buildVerticalConnector(totalWidth, false)];\n}\n\n/** Build agent box rows (4 lines per box, max 3 per row) */\nfunction buildAgentBoxRows(\n agents: Agent[],\n boxWidth: number,\n totalWidth: number,\n bright: boolean,\n maxPerRow: number,\n): DetailLine[] {\n const lines: DetailLine[] = [];\n const innerW = boxWidth - 2; // inside left/right border chars\n\n for (let rowStart = 0; rowStart < agents.length; rowStart += maxPerRow) {\n const rowAgents = agents.slice(rowStart, rowStart + maxPerRow);\n const count = rowAgents.length;\n const leftPad = alignedLeftPad(boxWidth, count, totalWidth);\n const isFirstRow = rowStart === 0;\n\n // Inter-row connector: fan-in from previous row → stem → fan-out to this row\n if (!isFirstRow) {\n const prevCount = Math.min(agents.length - (rowStart - maxPerRow), maxPerRow);\n const prevCents = boxCenters(boxWidth, prevCount, totalWidth);\n lines.push(...buildInterRowFanIn(prevCents, totalWidth));\n // Fan-out from stem to this row's boxes\n if (count > 1) {\n lines.push(...buildBranchConnector(boxWidth, count, totalWidth, 'down'));\n } else {\n lines.push(buildVerticalConnector(totalWidth, false));\n }\n }\n\n // Top borders with ┴ connector (first row gets ┴ from branch above, subsequent rows from inter-row fan-out)\n const topSegs: Seg[] = [];\n if (leftPad > 0) topSegs.push(seg(' '.repeat(leftPad)));\n for (let i = 0; i < count; i++) {\n const a = rowAgents[i]!;\n const isError = a.status === 'killed' || a.status === 'crashed';\n const borderColor = isError ? 'red' : resolveColor(a.color);\n const dim = !bright;\n\n const mid = Math.floor(innerW / 2);\n topSegs.push(seg('╭' + '─'.repeat(mid) + '┴' + '─'.repeat(innerW - mid - 1) + '╮', { color: borderColor, dim }));\n }\n lines.push(topSegs);\n\n // Line 1: colored icon + agent id\n const line1Segs: Seg[] = [];\n if (leftPad > 0) line1Segs.push(seg(' '.repeat(leftPad)));\n for (const a of rowAgents) {\n const isError = a.status === 'killed' || a.status === 'crashed';\n const borderColor = isError ? 'red' : resolveColor(a.color);\n const agentBg = BG_TINTS[isError ? 'red' : resolveColor(a.color)] ?? BG_TINTS.gray;\n const dim = !bright;\n const icon = agentStatusIcon(a.status);\n const iconColor = statusColor(a.status);\n const idPadded = padTo(` ${a.id}`, innerW - stringWidth(icon));\n line1Segs.push(seg('│', { color: borderColor, dim }));\n line1Segs.push(seg(icon, { bg: agentBg, color: iconColor, bold: bright }));\n line1Segs.push(seg(idPadded, { bg: agentBg, dim, bold: bright && a.status === 'running' }));\n line1Segs.push(seg('│', { color: borderColor, dim }));\n }\n lines.push(line1Segs);\n\n // Line 2: agent display name\n const line2Segs: Seg[] = [];\n if (leftPad > 0) line2Segs.push(seg(' '.repeat(leftPad)));\n for (const a of rowAgents) {\n const isError = a.status === 'killed' || a.status === 'crashed';\n const borderColor = isError ? 'red' : resolveColor(a.color);\n const agentBg = BG_TINTS[isError ? 'red' : resolveColor(a.color)] ?? BG_TINTS.gray;\n const dim = !bright;\n const name = padTo(agentDisplayName(a), innerW);\n line2Segs.push(seg('│', { color: borderColor, dim }));\n line2Segs.push(seg(name, { bg: agentBg, dim }));\n line2Segs.push(seg('│', { color: borderColor, dim }));\n }\n lines.push(line2Segs);\n\n // Line 3: colored duration + status tag for errors\n const line3Segs: Seg[] = [];\n if (leftPad > 0) line3Segs.push(seg(' '.repeat(leftPad)));\n for (const a of rowAgents) {\n const isError = a.status === 'killed' || a.status === 'crashed';\n const borderColor = isError ? 'red' : resolveColor(a.color);\n const agentBg = BG_TINTS[isError ? 'red' : resolveColor(a.color)] ?? BG_TINTS.gray;\n const dim = !bright;\n const dur = formatDuration(a.activeMs);\n const durClr = isError ? 'red' : (durationColor(a.activeMs) || undefined);\n let durText: string;\n if (isError) {\n const tag = a.status === 'killed' ? '✕ kill' : '✕ crash';\n durText = padTo(`${dur} ${tag}`, innerW);\n } else if (a.status === 'completed') {\n durText = padTo(`${dur} ✓`, innerW);\n } else {\n durText = padTo(dur, innerW);\n }\n line3Segs.push(seg('│', { color: borderColor, dim }));\n line3Segs.push(seg(durText, { bg: agentBg, dim, color: durClr }));\n line3Segs.push(seg('│', { color: borderColor, dim }));\n }\n lines.push(line3Segs);\n\n // Line 4: instruction preview or report summary (dim)\n const line4Segs: Seg[] = [];\n if (leftPad > 0) line4Segs.push(seg(' '.repeat(leftPad)));\n for (const a of rowAgents) {\n const isError = a.status === 'killed' || a.status === 'crashed';\n const borderColor = isError ? 'red' : resolveColor(a.color);\n const agentBg = BG_TINTS[isError ? 'red' : resolveColor(a.color)] ?? BG_TINTS.gray;\n const dim = !bright;\n const summary = padTo(agentSummary(a, innerW), innerW);\n line4Segs.push(seg('│', { color: borderColor, dim }));\n line4Segs.push(seg(summary, { bg: agentBg, dim: true }));\n line4Segs.push(seg('│', { color: borderColor, dim }));\n }\n lines.push(line4Segs);\n\n // Bottom borders with ┬ connector\n const botSegs: Seg[] = [];\n if (leftPad > 0) botSegs.push(seg(' '.repeat(leftPad)));\n for (const a of rowAgents) {\n const isError = a.status === 'killed' || a.status === 'crashed';\n const borderColor = isError ? 'red' : resolveColor(a.color);\n const dim = !bright;\n const mid = Math.floor(innerW / 2);\n const left = mid;\n const right = innerW - mid - 1;\n botSegs.push(seg('╰' + '─'.repeat(left) + '┬' + '─'.repeat(right) + '╯', { color: borderColor, dim }));\n }\n lines.push(botSegs);\n }\n\n return lines;\n}\n\n/** Build fan-in merge connector below agent boxes */\nfunction buildFanInConnector(\n boxWidth: number,\n count: number,\n totalWidth: number,\n): DetailLine[] {\n if (count <= 1) {\n // Single agent — just vertical line\n return [buildVerticalConnector(totalWidth, false)];\n }\n\n const centers = boxCenters(boxWidth, count, totalWidth);\n const lineStart = centers[0]!;\n const lineEnd = centers[centers.length - 1]!;\n const mid = stemCol(totalWidth);\n\n const row = new Array(totalWidth).fill(' ');\n // Extend horizontal line to include stem if it's outside the box cluster\n const hStart = Math.min(lineStart, mid);\n const hEnd = Math.max(lineEnd, mid);\n row[hStart] = '└';\n row[hEnd] = '┘';\n for (let i = hStart + 1; i < hEnd; i++) {\n row[i] = '─';\n }\n row[mid] = '┼';\n // Box centers become ┴\n for (const c of centers) {\n if (c !== mid && c !== hStart && c !== hEnd) {\n row[c] = '┴';\n }\n // Corner chars that coincide with a box center\n if (c === hStart && c !== mid) row[c] = '┴';\n if (c === hEnd && c !== mid) row[c] = '┴';\n }\n\n const result: DetailLine[] = [];\n result.push([seg(row.join(''))]);\n // Vertical line down from merge point\n const vRow = new Array(totalWidth).fill(' ');\n vRow[mid] = '│';\n result.push([seg(vRow.join(''))]);\n\n return result;\n}\n\n/** Build yield prompt node (solid when known, dashed when unknown) */\nfunction buildYieldNode(\n prompt: string | undefined,\n width: number,\n bright: boolean,\n known: boolean,\n): DetailLine[] {\n const lines: DetailLine[] = [];\n const inner = width - 2;\n const bg = BG_TINTS.gray;\n const dim = !bright;\n\n if (known && prompt) {\n // Solid border, yellow\n lines.push([seg('╭' + '─'.repeat(inner) + '╮', { color: 'yellow', dim })]);\n const wrapped = wrapText(prompt, inner - 2);\n for (const wl of wrapped) {\n const padded = padTo(' ' + wl, inner);\n lines.push([\n seg('│', { color: 'yellow', dim }),\n seg(padded, { bg, dim: true }),\n seg('│', { color: 'yellow', dim }),\n ]);\n }\n lines.push([seg('╰' + '─'.repeat(inner) + '╯', { color: 'yellow', dim })]);\n } else {\n // Dim placeholder with solid borders\n lines.push([seg('╭' + '─'.repeat(inner) + '╮', { dim: true })]);\n const placeholder = padTo(' awaiting agents…', inner);\n lines.push([seg('│', { dim: true }), seg(placeholder, { bg, dim: true }), seg('│', { dim: true })]);\n lines.push([seg('╰' + '─'.repeat(inner) + '╯', { dim: true })]);\n }\n\n return lines;\n}\n\n/** Build the complete node (terminal state) */\nfunction buildCompleteNode(session: Session, width: number): DetailLine[] {\n const inner = width - 2;\n const dur = formatDuration(session.activeMs);\n const totalAgents = session.agents.length;\n const completed = session.agents.filter(a => a.status === 'completed').length;\n const crashed = session.agents.filter(a => a.status === 'crashed' || a.status === 'killed').length;\n const cycles = session.orchestratorCycles.length;\n\n const leftText = '◉ complete';\n const rightText = `${dur} total`;\n const gap = Math.max(1, inner - 2 - stringWidth(leftText) - stringWidth(rightText));\n\n // Summary line: \"6 cycles · 12 agents (10 ok, 2 failed)\"\n let summaryParts = `${cycles} cycle${cycles !== 1 ? 's' : ''} · ${totalAgents} agent${totalAgents !== 1 ? 's' : ''}`;\n if (totalAgents > 0) {\n const parts: string[] = [];\n if (completed > 0) parts.push(`${completed} ok`);\n if (crashed > 0) parts.push(`${crashed} failed`);\n if (parts.length > 0) summaryParts += ` (${parts.join(', ')})`;\n }\n const summaryLine = padTo(' ' + summaryParts, inner);\n\n return [\n [seg('╭' + '─'.repeat(inner) + '╮', { color: 'cyan', bold: true })],\n [\n seg('│', { color: 'cyan', bold: true }),\n seg(' ' + leftText, { bold: true }),\n seg(' '.repeat(gap)),\n seg(rightText, { dim: true }),\n seg(' ', {}),\n seg('│', { color: 'cyan', bold: true }),\n ],\n [\n seg('│', { color: 'cyan', bold: true }),\n seg(summaryLine, { dim: true }),\n seg('│', { color: 'cyan', bold: true }),\n ],\n [seg('╰' + '─'.repeat(inner) + '╯', { color: 'cyan', bold: true })],\n ];\n}\n\n/** Build a dim placeholder orchestrator (next phase) */\nfunction buildDottedOrchestratorPlaceholder(width: number): DetailLine[] {\n const inner = width - 2;\n const placeholder = padTo(' spawning orchestrator…', inner);\n return [\n [seg('╭' + '─'.repeat(inner) + '╮', { dim: true })],\n [seg('│', { dim: true }), seg(placeholder, { bg: BG_TINTS.yellow, dim: true }), seg('│', { dim: true })],\n [seg('╰' + '─'.repeat(inner) + '╯', { dim: true })],\n ];\n}\n\n/** Build a dim placeholder agent box row */\nfunction buildDottedAgentPlaceholder(width: number): DetailLine[] {\n const inner = width - 2;\n const placeholder = padTo(' awaiting orchestrator…', inner);\n return [\n [seg('╭' + '─'.repeat(inner) + '╮', { dim: true })],\n [seg('│', { dim: true }), seg(placeholder, { bg: BG_TINTS.blue, dim: true }), seg('│', { dim: true })],\n [seg('╰' + '─'.repeat(inner) + '╯', { dim: true })],\n ];\n}\n\n// ---------------------------------------------------------------------------\n// Render a single cycle's flow (orchestrator → agents → yield)\n// ---------------------------------------------------------------------------\n\nfunction renderCycleFlow(\n session: Session,\n cycle: OrchestratorCycle,\n prevCycle: OrchestratorCycle | undefined,\n width: number,\n phase: Phase,\n isCurrentCycle: boolean,\n isPrevCycle: boolean,\n): DetailLine[] {\n const lines: DetailLine[] = [];\n const cycleAgents = session.agents.filter(a => cycle.agentsSpawned.includes(a.id));\n const maxPerRow = 3;\n const boxWidth = Math.max(12, Math.floor((width - 4) / maxPerRow));\n const firstRowCount = Math.min(cycleAgents.length, maxPerRow);\n const lastRowCount = cycleAgents.length > 0 ? ((cycleAgents.length - 1) % maxPerRow) + 1 : 0;\n\n // Determine brightness for each section\n let orchBright = false;\n let agentsBright = false;\n let yieldBright = false;\n\n if (isCurrentCycle) {\n if (phase === 'orchestrator') orchBright = true;\n else if (phase === 'agents') agentsBright = true;\n else if (phase === 'between') yieldBright = true;\n }\n // Previous cycle: everything dim (default false is fine)\n\n const showAgents = cycleAgents.length > 0;\n const hasConnectorFromOrch = showAgents;\n\n // Orchestrator node\n lines.push(...buildOrchestratorNode(cycle, cycleAgents, width, orchBright, hasConnectorFromOrch));\n\n if (showAgents) {\n // Vertical connector\n lines.push(buildVerticalConnector(width, !agentsBright));\n\n // Fan-out branch\n if (firstRowCount > 1) {\n lines.push(...buildBranchConnector(boxWidth, firstRowCount, width, 'down'));\n }\n\n // Agent boxes\n lines.push(...buildAgentBoxRows(cycleAgents, boxWidth, width, agentsBright, maxPerRow));\n\n // Fan-in merge (from last row's boxes)\n lines.push(...buildFanInConnector(boxWidth, lastRowCount, width));\n } else if (hasConnectorFromOrch) {\n lines.push(buildVerticalConnector(width, true));\n }\n\n // Yield prompt\n const yieldKnown = !!cycle.nextPrompt;\n if (yieldKnown || isCurrentCycle) {\n lines.push(...buildYieldNode(\n cycle.nextPrompt,\n width,\n yieldBright,\n yieldKnown,\n ));\n }\n\n return lines;\n}\n\n// ---------------------------------------------------------------------------\n// Main export\n// ---------------------------------------------------------------------------\n\nexport function buildCycleFlowLines(\n session: Session,\n width: number,\n expanded: boolean,\n): DetailLine[] {\n const lines: DetailLine[] = [];\n const cycles = session.orchestratorCycles;\n const phase = getCurrentPhase(session);\n const maxPerRow = 3;\n const boxWidth = Math.max(12, Math.floor((width - 4) / maxPerRow));\n const firstRowAgentCount = (c: OrchestratorCycle) => {\n const agents = session.agents.filter(a => c.agentsSpawned.includes(a.id));\n return Math.min(agents.length, maxPerRow);\n };\n const lastRowAgentCount = (c: OrchestratorCycle) => {\n const count = session.agents.filter(a => c.agentsSpawned.includes(a.id)).length;\n return count > 0 ? ((count - 1) % maxPerRow) + 1 : 0;\n };\n\n // Header\n lines.push([\n seg(' ▎ ◈ CYCLE FLOW', { color: 'blue', bold: true }),\n seg(expanded ? ' [F] collapse' : ' [F] full', { dim: true }),\n ]);\n lines.push(singleLine(' '));\n\n if (cycles.length === 0) {\n // First cycle, orchestrator hasn't started yet\n lines.push(singleLine(' waiting for orchestrator…', { dim: true, italic: true }));\n return lines;\n }\n\n if (expanded) {\n // Show all cycles, older ones dimmer\n for (let i = 0; i < cycles.length; i++) {\n const cycle = cycles[i]!;\n const prevCycle = i > 0 ? cycles[i - 1] : undefined;\n const isLast = i === cycles.length - 1;\n\n const cycleLines = renderCycleFlow(\n session, cycle, prevCycle, width, phase, isLast, !isLast,\n );\n\n // Apply extra dim to older cycles\n if (!isLast) {\n for (const line of cycleLines) {\n for (const s of line) {\n s.dim = true;\n }\n }\n }\n\n lines.push(...cycleLines);\n\n if (!isLast) {\n lines.push(singleLine(' '));\n }\n }\n } else {\n // 3-phase sliding window\n const currentCycle = cycles[cycles.length - 1]!;\n const prevCycle = cycles.length >= 2 ? cycles[cycles.length - 2] : undefined;\n const currentAgents = session.agents.filter(a => currentCycle.agentsSpawned.includes(a.id));\n\n // Previous phase (dim)\n if (phase === 'agents' && currentCycle) {\n // Previous = orchestrator (dim)\n lines.push(...buildOrchestratorNode(currentCycle, currentAgents, width, false, true));\n lines.push(buildVerticalConnector(width, true));\n if (firstRowAgentCount(currentCycle) > 1) {\n const dimBranch = buildBranchConnector(boxWidth, firstRowAgentCount(currentCycle), width, 'down');\n for (const line of dimBranch) {\n for (const s of line) s.dim = true;\n }\n lines.push(...dimBranch);\n }\n } else if (phase === 'orchestrator' && prevCycle) {\n // Previous = yield prompt from prev cycle (dim)\n if (prevCycle.nextPrompt) {\n lines.push(...buildYieldNode(prevCycle.nextPrompt, width, false, true));\n lines.push(singleLine(' '));\n }\n } else if (phase === 'between') {\n // Previous = agent boxes (slightly dim)\n if (currentAgents.length > 0) {\n lines.push(...buildAgentBoxRows(currentAgents, boxWidth, width, false, maxPerRow));\n lines.push(...buildFanInConnector(boxWidth, lastRowAgentCount(currentCycle), width));\n }\n }\n\n // Current phase (bright)\n if (phase === 'orchestrator') {\n lines.push(...buildOrchestratorNode(currentCycle, currentAgents, width, true, false));\n } else if (phase === 'agents') {\n // Agent boxes bright\n lines.push(...buildAgentBoxRows(currentAgents, boxWidth, width, true, maxPerRow));\n lines.push(...buildFanInConnector(boxWidth, lastRowAgentCount(currentCycle), width));\n } else if (phase === 'between') {\n // Yield prompt bright\n lines.push(...buildYieldNode(currentCycle.nextPrompt, width, true, true));\n } else if (phase === 'complete') {\n // Previous = last agents dim\n if (currentAgents.length > 0) {\n lines.push(...buildAgentBoxRows(currentAgents, boxWidth, width, false, maxPerRow));\n lines.push(...buildFanInConnector(boxWidth, lastRowAgentCount(currentCycle), width));\n }\n // Complete node bright\n lines.push(...buildCompleteNode(session, width));\n }\n\n // Next phase (dotted/planned)\n if (phase === 'agents') {\n lines.push(...buildYieldNode(undefined, width, false, false));\n } else if (phase === 'orchestrator') {\n lines.push(singleLine(' '));\n lines.push(...buildDottedAgentPlaceholder(width));\n } else if (phase === 'between') {\n lines.push(singleLine(' '));\n lines.push(...buildDottedOrchestratorPlaceholder(width));\n }\n // 'complete' has no next phase\n }\n\n return lines;\n}\n","import type { AskStatus, InteractionKind } from './types.js';\n\nexport type { InteractionKind as InboxItemKind };\n\nexport function coerceKind(k: InteractionKind | undefined): InteractionKind {\n if (k !== undefined) return k;\n return 'validation';\n}\n\nexport interface AggregateInboxItem {\n sessionId: string;\n sessionName?: string;\n cwd: string;\n askId: string;\n askedBy: string;\n askedAt: string;\n status: AskStatus;\n blocking: boolean;\n orphaned?: boolean;\n title?: string;\n subtitle?: string;\n blockedSince: string;\n kind?: InteractionKind;\n}\n","/**\n * Stacked g/s/r detail panel (3b).\n *\n * Renders goal/strategy/roadmap content as three vertically-stacked strips,\n * or a single cycle-log strip when state.detailMode === 'cycle-log'.\n *\n * Extension point (3d): when cursor is on the virtual `Needs You` tree node,\n * extend `state.detailMode` to `'gsr' | 'cycle-log' | 'inbox'` and dispatch\n * to an inbox view from `renderStackedDetailRows`.\n *\n * Extension point (deferred Q5): wire [/] in `renderCycleLogMode` to walk\n * state.logsCycles by index instead of always showing the latest.\n */\n\nimport {\n buildEmptyPanelRows,\n buildPanelRows,\n clipAnsi,\n colorToSGR,\n renderLine,\n type Rect,\n} from '../render.js';\nimport type { AppState, ThrottledScroll } from '../state.js';\nimport type { DetailContext } from './detail.js';\nimport { buildLogsLines } from './detail.js';\nimport {\n type DetailLine,\n} from '../lib/format.js';\nimport { buildHighlightedMarkdownLines } from '../lib/markdown-highlight.js';\n\nconst HEADERS_ACTIVE = {\n top: 'GOAL',\n middle: 'STRATEGY',\n bottom: 'ROADMAP',\n};\n\nconst HEADERS_DONE = {\n top: 'GOAL',\n middle: 'COMPLETION',\n bottom: 'SUMMARY',\n};\n\nexport function renderStackedDetailRows(\n rect: Rect,\n state: AppState,\n detailCtx: DetailContext,\n): string[] {\n const focused = state.focusPane === 'detail';\n const { w, h } = rect;\n const innerW = w - 4;\n\n const cursorNode = detailCtx.nodes[state.cursorIndex];\n if (!cursorNode || !state.selectedSession || cursorNode.sessionId !== state.selectedSession.id) {\n return buildEmptyPanelRows(rect, focused, 'gray', '\\x1b[2mSelect a session\\x1b[0m');\n }\n\n if (state.detailMode === 'cycle-log') {\n return renderCycleLogMode(rect, state, focused);\n }\n\n const session = state.selectedSession;\n const isDone = session.status === 'completed';\n const headers = isDone ? HEADERS_DONE : HEADERS_ACTIVE;\n\n const middleContent = isDone\n ? buildCompletionContent(session)\n : state.strategyContent;\n const bottomContent = isDone\n ? pickSummaryContent(state)\n : state.planContent;\n\n const cacheKey = [\n cursorNode.sessionId,\n rect.w,\n isDone ? 'done' : 'active',\n state.goalContent.length,\n middleContent.length,\n bottomContent.length,\n ].join(':');\n\n let lines = state.cachedStackedLines;\n if (cacheKey !== state.stackedCacheKey || lines === null) {\n lines = {\n goal: buildSectionLines(state.goalContent, innerW),\n strategy: buildSectionLines(middleContent, innerW),\n roadmap: buildSectionLines(bottomContent, innerW),\n cycleLog: [],\n };\n state.cachedStackedLines = lines;\n state.stackedCacheKey = cacheKey;\n }\n\n const heights = allocateStripHeights(h, lines.goal.length, lines.strategy.length, lines.roadmap.length);\n\n const rows = new Array<string>(h);\n const focusColor = focused ? 'cyan' : 'gray';\n const sgr = `\\x1b[${colorToSGR(focusColor)}m`;\n const reset = '\\x1b[0m';\n rows[0] = sgr + '╭' + '─'.repeat(w - 2) + '╮' + reset;\n rows[h - 1] = sgr + '╰' + '─'.repeat(w - 2) + '╯' + reset;\n\n let cursor = 1;\n cursor = paintStrip(rows, cursor, w, sgr, reset, headers.top, lines.goal,\n state.goalScroll, heights.goalHeight, state.focusedStrip === 'goal' && focused);\n rows[cursor++] = sgr + '├' + '─'.repeat(w - 2) + '┤' + reset;\n cursor = paintStrip(rows, cursor, w, sgr, reset, headers.middle, lines.strategy,\n state.strategyScroll, heights.stratHeight, state.focusedStrip === 'strategy' && focused);\n rows[cursor++] = sgr + '├' + '─'.repeat(w - 2) + '┤' + reset;\n paintStrip(rows, cursor, w, sgr, reset, headers.bottom, lines.roadmap,\n state.roadmapScroll, heights.roadHeight, state.focusedStrip === 'roadmap' && focused);\n\n return rows;\n}\n\nfunction buildCompletionContent(session: import('../../shared/types.js').Session): string {\n const parts: string[] = [];\n if (session.completedAt) {\n parts.push(`*completed ${formatTimestamp(session.completedAt)}*`);\n parts.push('');\n }\n if (session.completionReport && session.completionReport.trim()) {\n parts.push(session.completionReport.trim());\n } else {\n parts.push('_No completion report written._');\n }\n return parts.join('\\n');\n}\n\nfunction pickSummaryContent(state: AppState): string {\n if (state.completionSummaryContent.trim()) return state.completionSummaryContent;\n if (state.logsCycles.length > 0) {\n const last = state.logsCycles[state.logsCycles.length - 1]!;\n return `# Cycle ${last.cycle} log\\n\\n${last.content}`;\n }\n if (state.strategyContent.trim()) return state.strategyContent;\n return '_No completion artifacts. Try expanding context/ in the tree for raw files._';\n}\n\nfunction formatTimestamp(iso: string): string {\n try {\n const d = new Date(iso);\n if (isNaN(d.getTime())) return iso;\n return d.toLocaleString();\n } catch {\n return iso;\n }\n}\n\n// --- helpers ---\n\nfunction buildSectionLines(content: string, innerW: number): DetailLine[] {\n return buildHighlightedMarkdownLines(content, innerW);\n}\n\nfunction allocateStripHeights(rectH: number, gN: number, sN: number, _rN: number) {\n const innerH = rectH - 2;\n const stripsAvail = innerH - 2; // two separator rows\n const goalCap = Math.floor(stripsAvail * 0.20);\n const stratCap = Math.floor(stripsAvail * 0.40);\n const roadCap = stripsAvail - goalCap - stratCap;\n const goalNeed = Math.min(gN + 1, goalCap);\n const stratNeed = Math.min(sN + 1, stratCap);\n const slack = (goalCap - goalNeed) + (stratCap - stratNeed);\n return {\n goalHeight: Math.max(2, goalNeed),\n stratHeight: Math.max(2, stratNeed),\n roadHeight: Math.max(2, roadCap + slack),\n };\n}\n\nfunction paintStrip(\n rows: string[], startRow: number, w: number, sgr: string, reset: string,\n label: string,\n lines: DetailLine[], scroll: ThrottledScroll, height: number, focused: boolean,\n): number {\n const innerW = w - 4;\n const borderL = sgr + '│' + reset + ' ';\n const borderR = ' ' + sgr + '│' + reset;\n\n const headerSeg = `\\x1b[${colorToSGR('yellow')};1m ▎ ${label}\\x1b[0m`;\n const headerClipped = clipAnsi(headerSeg + (focused ? ' ◀' : ''), innerW);\n rows[startRow] = borderL + headerClipped + borderR;\n\n const contentH = height - 1;\n const hasOverflow = lines.length > contentH;\n const viewableH = hasOverflow ? contentH - 1 : contentH;\n const maxScroll = Math.max(0, lines.length - viewableH);\n scroll.setMax(maxScroll);\n const effOffset = scroll.offset;\n\n for (let i = 0; i < viewableH; i++) {\n const li = effOffset + i;\n const ansi = li < lines.length ? renderLine(lines[li]!) : '';\n rows[startRow + 1 + i] = borderL + clipAnsi(ansi, innerW) + borderR;\n }\n if (hasOverflow) {\n const pct = maxScroll > 0 ? Math.round((effOffset / maxScroll) * 100) : 100;\n const indicator = `\\x1b[2m ↕ ${pct}% · ${lines.length} lines\\x1b[0m`;\n rows[startRow + 1 + viewableH] = borderL + clipAnsi(indicator, innerW) + borderR;\n }\n return startRow + height;\n}\n\nfunction renderCycleLogMode(rect: Rect, state: AppState, focused: boolean): string[] {\n // Extension point (deferred Q5): wire [/] to walk state.logsCycles by index instead of latest.\n if (state.logsCycles.length === 0) {\n return buildEmptyPanelRows(rect, focused, 'gray', '\\x1b[2mNo cycle logs yet\\x1b[0m');\n }\n const cacheKey = `cycleLog:${state.logsCycles.length}:${rect.w}`;\n let lines: DetailLine[];\n if (cacheKey === state.stackedCacheKey && state.cachedStackedLines !== null) {\n lines = state.cachedStackedLines.cycleLog;\n } else {\n lines = buildLogsLines(state.logsCycles, rect.w);\n const existing = state.cachedStackedLines ?? { goal: [], strategy: [], roadmap: [], cycleLog: [] };\n state.cachedStackedLines = { ...existing, cycleLog: lines };\n state.stackedCacheKey = cacheKey;\n }\n return buildPanelRows(rect, lines, state.detailScroll, focused, 'cyan', state.stackedRenderedCache);\n}\n","/**\n * Gloam-themed markdown highlighter for goal/strategy/roadmap strips.\n *\n * Pure-JS pass that converts markdown text into `DetailLine[]` ready for\n * `renderLine`. Headings get full-width tinted backgrounds (h1 orange →\n * h6 surface gray) with brighter foregrounds; lists, checkboxes, code,\n * blockquotes, and inline emphasis (bold/italic/code/link/strikethrough)\n * get their own styling.\n *\n * The output is sized to `innerW`: heading lines are padded with bg-painted\n * spaces so the tint fills the full strip width when rendered.\n */\n\nimport stringWidth from 'string-width';\nimport { GLOAM } from './gloam.js';\nimport { cleanMarkdown, stripFrontmatter, type DetailLine, type Seg } from './format.js';\n\n// ─── Heading styles by level ───────────────────────────────────────────────\n\ninterface HeadingStyle {\n /** Heading text foreground (the title itself) */\n textFg: string;\n /** Marker (`#…`) foreground — slightly muted vs. text */\n markerFg: string;\n /** Tinted background painted across the full row */\n bg: string;\n}\n\nconst HEADING_STYLES: HeadingStyle[] = [\n { textFg: GLOAM.bright_orange, markerFg: GLOAM.orange, bg: GLOAM.bg_dim_orange }, // h1\n { textFg: GLOAM.bright_yellow, markerFg: GLOAM.yellow, bg: GLOAM.bg_dim_yellow }, // h2\n { textFg: GLOAM.bright_green, markerFg: GLOAM.green, bg: GLOAM.bg_dim_green }, // h3\n { textFg: GLOAM.bright_blue, markerFg: GLOAM.blue, bg: GLOAM.bg_dim_blue }, // h4\n { textFg: GLOAM.bright_purple, markerFg: GLOAM.purple, bg: GLOAM.bg_dim_purple }, // h5\n { textFg: GLOAM.fg2, markerFg: GLOAM.fg3, bg: GLOAM.bg_bg1 }, // h6\n];\n\n// ─── Display-hazard cleanup ────────────────────────────────────────────────\n// Mirrors `cleanMarkdown`'s emoji-handling without touching markdown syntax.\n\nfunction stripDisplayHazards(s: string): string {\n return s\n .replace(/✅/g, '✓')\n .replace(/❌/g, '✗')\n .replace(/\\p{Emoji_Presentation}/gu, '');\n}\n\n// ─── Inline emphasis tokenizer ─────────────────────────────────────────────\n\ninterface InlineSpan {\n start: number;\n end: number;\n kind: 'bold' | 'italic' | 'code' | 'strike' | 'link';\n /** rendered display text for the span (markers stripped) */\n text: string;\n}\n\nconst INLINE_RE =\n /\\*\\*([^*\\n]+)\\*\\*|__([^_\\n]+)__|\\*([^*\\n]+)\\*|_([^_\\n]+)_|`([^`\\n]+)`|~~([^~\\n]+)~~|\\[([^\\]\\n]+)\\]\\(([^)\\n]+)\\)/g;\n\nfunction tokenizeInline(line: string, baseFg: string, baseStyle?: Partial<Seg>): Seg[] {\n const out: Seg[] = [];\n const baseSeg = (text: string): Seg => ({ text, fg: baseFg, ...baseStyle });\n\n let cursor = 0;\n for (const m of line.matchAll(INLINE_RE)) {\n const idx = m.index!;\n if (idx > cursor) out.push(baseSeg(line.slice(cursor, idx)));\n\n if (m[1] !== undefined) {\n out.push({ text: m[1], fg: GLOAM.fg0, bold: true, bg: baseStyle?.bg });\n } else if (m[2] !== undefined) {\n out.push({ text: m[2], fg: GLOAM.fg0, bold: true, bg: baseStyle?.bg });\n } else if (m[3] !== undefined) {\n out.push({ text: m[3], fg: GLOAM.fg0, italic: true, bg: baseStyle?.bg });\n } else if (m[4] !== undefined) {\n out.push({ text: m[4], fg: GLOAM.fg0, italic: true, bg: baseStyle?.bg });\n } else if (m[5] !== undefined) {\n // Inline code — aqua fg, subtle bg1 tint (skip when inside heading bg)\n out.push({\n text: m[5],\n fg: GLOAM.aqua,\n bg: baseStyle?.bg ?? GLOAM.bg_bg1,\n });\n } else if (m[6] !== undefined) {\n out.push({ text: m[6], fg: GLOAM.fg3, strikethrough: true, bg: baseStyle?.bg });\n } else if (m[7] !== undefined && m[8] !== undefined) {\n out.push({ text: m[7], fg: GLOAM.blue, bold: true, bg: baseStyle?.bg });\n }\n\n cursor = idx + m[0].length;\n }\n if (cursor < line.length) out.push(baseSeg(line.slice(cursor)));\n if (out.length === 0) out.push(baseSeg(''));\n return out;\n}\n\n// ─── Plain-text width (sums Seg.text display widths) ───────────────────────\n\nfunction segsDisplayWidth(segs: Seg[]): number {\n let w = 0;\n for (const s of segs) w += stringWidth(s.text);\n return w;\n}\n\n// ─── Soft-wrap a pre-tokenized line to width ───────────────────────────────\n// Tokenizes input segs into word/space atoms (preserving each char's style),\n// then greedy-packs atoms onto lines. Word boundaries are respected even when\n// they straddle segment boundaries (e.g. \" guard around\" spilling out of a\n// preceding inline-code span). Continuation lines get a plain-space indent.\n\ninterface Atom {\n text: string;\n width: number;\n style: Omit<Seg, 'text'>;\n /** true → atom is a run of spaces (collapsible at line boundaries) */\n space: boolean;\n}\n\nfunction segsToAtoms(segs: Seg[]): Atom[] {\n const atoms: Atom[] = [];\n for (const s of segs) {\n if (!s.text) continue;\n const { text, ...style } = s;\n // Split on whitespace boundaries: every run of spaces becomes a `space`\n // atom; every non-space run becomes a word atom.\n const re = /(\\s+|\\S+)/g;\n for (const m of text.matchAll(re)) {\n const piece = m[0];\n atoms.push({\n text: piece,\n width: stringWidth(piece),\n style,\n space: /^\\s+$/.test(piece),\n });\n }\n }\n return atoms;\n}\n\nfunction wrapSegs(segs: Seg[], width: number, contIndent: string): DetailLine[] {\n if (width <= 0) return [segs];\n const atoms = segsToAtoms(segs);\n if (atoms.length === 0) return [[{ text: '' }]];\n\n const lines: DetailLine[] = [];\n let current: Seg[] = [];\n let currentWidth = 0;\n\n const pushAtom = (a: Atom) => {\n current.push({ ...a.style, text: a.text });\n currentWidth += a.width;\n };\n const flushLine = () => {\n // Trim trailing pure-space segs (cosmetic: tinted/colored trailing space\n // can leak across the right border when bg-painted, so prefer cleaner\n // breaks). Heading lines never reach here — they bypass wrapping.\n while (current.length > 0) {\n const last = current[current.length - 1]!;\n if (/^\\s+$/.test(last.text) && !last.bg) {\n currentWidth -= stringWidth(last.text);\n current.pop();\n } else break;\n }\n lines.push(current.length > 0 ? current : [{ text: '' }]);\n current = [];\n currentWidth = 0;\n };\n\n for (let i = 0; i < atoms.length; i++) {\n const atom = atoms[i]!;\n\n if (atom.space) {\n // Spaces that overflow the right edge are dropped at the wrap boundary\n // — flushLine() will trim non-bg trailing whitespace anyway. Leading\n // spaces (line-start indent on the first body line) are preserved.\n if (currentWidth + atom.width <= width) pushAtom(atom);\n continue;\n }\n\n // Word atom\n if (atom.width > width) {\n // Word wider than full line → hard-break it on character boundaries.\n let remaining = atom.text;\n while (remaining.length > 0) {\n const spaceLeft = width - currentWidth;\n if (spaceLeft <= 0) {\n flushLine();\n if (contIndent) {\n current.push({ text: contIndent });\n currentWidth = stringWidth(contIndent);\n }\n continue;\n }\n let cut = 0;\n let cutW = 0;\n for (let k = 0; k < remaining.length; k++) {\n const cw = stringWidth(remaining[k]!);\n if (cutW + cw > spaceLeft) break;\n cutW += cw;\n cut = k + 1;\n }\n if (cut === 0) {\n flushLine();\n if (contIndent) {\n current.push({ text: contIndent });\n currentWidth = stringWidth(contIndent);\n }\n continue;\n }\n current.push({ ...atom.style, text: remaining.slice(0, cut) });\n currentWidth += cutW;\n remaining = remaining.slice(cut);\n if (remaining.length > 0) {\n flushLine();\n if (contIndent) {\n current.push({ text: contIndent });\n currentWidth = stringWidth(contIndent);\n }\n }\n }\n continue;\n }\n\n if (currentWidth + atom.width > width) {\n flushLine();\n if (contIndent) {\n current.push({ text: contIndent });\n currentWidth = stringWidth(contIndent);\n }\n }\n pushAtom(atom);\n }\n flushLine();\n return lines.length > 0 ? lines : [[{ text: '' }]];\n}\n\n// ─── Heading rendering — full-width bg-padded ──────────────────────────────\n\nfunction buildHeadingLine(\n level: number,\n rawText: string,\n innerW: number,\n): DetailLine {\n const style = HEADING_STYLES[Math.min(level - 1, HEADING_STYLES.length - 1)]!;\n const cleanedText = stripDisplayHazards(rawText).trim();\n const marker = '#'.repeat(level);\n const prefix = ' '; // matches the standard 2-space content margin\n const sep = ' ';\n\n const headerSegs: Seg[] = [\n { text: prefix, bg: style.bg },\n { text: marker, fg: style.markerFg, bg: style.bg, bold: true },\n { text: sep, bg: style.bg },\n { text: cleanedText, fg: style.textFg, bg: style.bg, bold: true },\n ];\n const used = segsDisplayWidth(headerSegs);\n const padW = Math.max(0, innerW - used);\n if (padW > 0) {\n headerSegs.push({ text: ' '.repeat(padW), bg: style.bg });\n }\n return headerSegs;\n}\n\n// ─── Bullet/numbered list ──────────────────────────────────────────────────\n\nfunction buildListLine(\n marker: string,\n body: string,\n innerW: number,\n prefixIndent: string,\n markerFg: string,\n): DetailLine[] {\n const indent = `${prefixIndent} `; // continuation aligns under text\n const head: Seg[] = [\n { text: prefixIndent, fg: GLOAM.fg2 },\n { text: marker, fg: markerFg, bold: true },\n { text: ' ', fg: GLOAM.fg2 },\n ];\n const headW = segsDisplayWidth(head);\n const bodySegs = tokenizeInline(stripDisplayHazards(body), GLOAM.fg1);\n const wrapped = wrapSegs([...head, ...bodySegs], innerW, indent);\n // wrapSegs treats the indent+head as part of segs — but we want first-line\n // to start with our colored head and continuations to use plain indent.\n // To keep things simple, we already wrap with contIndent set.\n return wrapped;\n // Note: contIndent is plain (no fg) to keep continuation rows readable;\n // wrapSegs prepends a single indent seg for each new line — good enough.\n}\n\n// ─── Checkbox ──────────────────────────────────────────────────────────────\n\nfunction buildCheckboxLine(\n checked: boolean,\n body: string,\n innerW: number,\n): DetailLine[] {\n const icon = checked ? '☑' : '☐';\n const iconFg = checked ? GLOAM.green : GLOAM.fg4;\n const head: Seg[] = [\n { text: ' ', fg: GLOAM.fg2 },\n { text: icon, fg: iconFg, bold: true },\n { text: ' ', fg: GLOAM.fg2 },\n ];\n const bodyFg = checked ? GLOAM.fg3 : GLOAM.fg1;\n const bodyStyle = checked ? { strikethrough: true } : {};\n const bodySegs = tokenizeInline(stripDisplayHazards(body), bodyFg, bodyStyle);\n return wrapSegs([...head, ...bodySegs], innerW, ' ');\n}\n\n// ─── Blockquote ────────────────────────────────────────────────────────────\n\nfunction buildQuoteLine(body: string, innerW: number): DetailLine[] {\n const head: Seg[] = [\n { text: ' ', fg: GLOAM.fg2 },\n { text: '▎ ', fg: GLOAM.fg3 },\n ];\n const bodySegs = tokenizeInline(stripDisplayHazards(body), GLOAM.fg2, { italic: true });\n return wrapSegs([...head, ...bodySegs], innerW, ' ');\n}\n\n// ─── Horizontal rule ───────────────────────────────────────────────────────\n\nfunction buildHrLine(innerW: number): DetailLine {\n const w = Math.max(2, innerW - 4);\n return [\n { text: ' ', fg: GLOAM.fg4 },\n { text: '─'.repeat(w), fg: GLOAM.fg4 },\n ];\n}\n\n// ─── Code block content ────────────────────────────────────────────────────\n\nfunction buildCodeFenceLine(fence: string, innerW: number): DetailLine {\n return [\n { text: ' ', fg: GLOAM.fg4 },\n {\n text: fence + ' '.repeat(Math.max(0, innerW - 2 - stringWidth(fence))),\n fg: GLOAM.fg4,\n bg: GLOAM.bg_bg1,\n },\n ];\n}\n\nfunction buildCodeLine(content: string, innerW: number): DetailLine {\n const cleaned = stripDisplayHazards(content);\n const cw = stringWidth(cleaned);\n const padW = Math.max(0, innerW - 2 - cw);\n return [\n { text: ' ', bg: GLOAM.bg_bg1 },\n { text: cleaned, fg: GLOAM.aqua, bg: GLOAM.bg_bg1 },\n ...(padW > 0 ? [{ text: ' '.repeat(padW), bg: GLOAM.bg_bg1 }] : []),\n ];\n}\n\n// ─── Plain paragraph ───────────────────────────────────────────────────────\n\nfunction buildParagraphLines(body: string, innerW: number): DetailLine[] {\n const head: Seg[] = [{ text: ' ', fg: GLOAM.fg1 }];\n const bodySegs = tokenizeInline(stripDisplayHazards(body), GLOAM.fg1);\n return wrapSegs([...head, ...bodySegs], innerW, ' ');\n}\n\n// ─── GFM tables ────────────────────────────────────────────────────────────\n\ntype TableAlign = 'left' | 'center' | 'right';\n\nfunction parseTableCells(line: string): string[] {\n let s = line.trim();\n if (s.startsWith('|')) s = s.slice(1);\n if (s.endsWith('|') && !s.endsWith('\\\\|')) s = s.slice(0, -1);\n const cells: string[] = [];\n let cur = '';\n for (let i = 0; i < s.length; i++) {\n const ch = s[i]!;\n if (ch === '\\\\' && s[i + 1] === '|') {\n cur += '|';\n i++;\n } else if (ch === '|') {\n cells.push(cur.trim());\n cur = '';\n } else {\n cur += ch;\n }\n }\n cells.push(cur.trim());\n return cells;\n}\n\nfunction parseTableSeparator(line: string): TableAlign[] | null {\n if (!line.includes('|') && !/^[\\s:|+-]+$/.test(line)) return null;\n const cells = parseTableCells(line);\n if (cells.length === 0) return null;\n const aligns: TableAlign[] = [];\n for (const c of cells) {\n const m = c.match(/^(:?)\\s*-{2,}\\s*(:?)$/);\n if (!m) return null;\n if (m[1] === ':' && m[2] === ':') aligns.push('center');\n else if (m[2] === ':') aligns.push('right');\n else aligns.push('left');\n }\n return aligns;\n}\n\nfunction padCell(text: string, width: number, align: TableAlign): string {\n const w = stringWidth(text);\n const pad = Math.max(0, width - w);\n let left = 0;\n let right = 0;\n if (align === 'right') left = pad;\n else if (align === 'center') {\n left = Math.floor(pad / 2);\n right = pad - left;\n } else right = pad;\n return ' '.repeat(left) + text + ' '.repeat(right);\n}\n\n/**\n * Soft-wrap cell text to `width` columns, returning each visual line padded\n * (and aligned) to exactly `width` display columns. Words longer than the\n * column hard-break on character boundaries.\n */\nfunction wrapCell(text: string, width: number, align: TableAlign): string[] {\n if (width <= 0) return [''];\n const cleaned = cleanMarkdown(text);\n if (cleaned === '') return [padCell('', width, align)];\n\n const out: string[] = [];\n let cur = '';\n let curW = 0;\n const flush = () => {\n out.push(padCell(cur.replace(/\\s+$/, ''), width, align));\n cur = '';\n curW = 0;\n };\n\n for (const piece of cleaned.match(/\\s+|\\S+/g) ?? []) {\n const isSpace = /^\\s+$/.test(piece);\n const pw = stringWidth(piece);\n\n if (isSpace) {\n if (curW === 0) continue; // drop leading whitespace on a wrapped line\n if (curW + pw > width) flush();\n else {\n cur += piece;\n curW += pw;\n }\n continue;\n }\n\n if (curW + pw <= width) {\n cur += piece;\n curW += pw;\n continue;\n }\n\n if (curW > 0) flush();\n\n if (pw > width) {\n // Hard-break a word wider than the column.\n let rem = piece;\n while (rem.length > 0) {\n let cut = 0;\n let cutW = 0;\n for (let k = 0; k < rem.length; k++) {\n const cw = stringWidth(rem[k]!);\n if (cutW + cw > width) break;\n cutW += cw;\n cut = k + 1;\n }\n if (cut === 0) cut = 1;\n const slice = rem.slice(0, cut);\n if (cut === rem.length) {\n cur = slice;\n curW = stringWidth(slice);\n } else {\n out.push(padCell(slice, width, align));\n }\n rem = rem.slice(cut);\n }\n continue;\n }\n\n cur = piece;\n curW = pw;\n }\n\n if (curW > 0 || out.length === 0) flush();\n return out;\n}\n\nfunction buildTableLines(\n headers: string[],\n alignsIn: TableAlign[],\n rowsIn: string[][],\n innerW: number,\n): DetailLine[] {\n const ncols = headers.length;\n if (ncols === 0) return [];\n\n // Normalize aligns and rows to exactly ncols entries so downstream indexing\n // is total. Missing entries default to left-align / empty string.\n const aligns: TableAlign[] = [];\n for (let i = 0; i < ncols; i++) {\n const a = alignsIn[i];\n aligns.push(a === undefined ? 'left' : a);\n }\n\n const rows: string[][] = rowsIn.map((r) => {\n const out: string[] = [];\n for (let i = 0; i < ncols; i++) {\n const c = r[i];\n out.push(c === undefined ? '' : c);\n }\n return out;\n });\n\n // Natural widths from cleaned cell text\n const naturalW: number[] = new Array(ncols).fill(0);\n const measure = (cells: string[]) => {\n for (let i = 0; i < ncols; i++) {\n const w = stringWidth(cleanMarkdown(cells[i]!));\n if (w > naturalW[i]!) naturalW[i] = w;\n }\n };\n measure(headers);\n for (const r of rows) measure(r);\n\n // Layout: 2-char margin + left border + (cell + right-border) per column.\n // Each cell is \" <content> \" (2 chars padding) so per-column overhead is 3\n // (one separator + two pad spaces). Plus 1 for the leading border.\n const margin = 2;\n const overhead = 1 + ncols * 3;\n const available = innerW - margin - overhead;\n const minColW = 3;\n\n if (available < ncols * minColW) {\n return [[{ text: ' (table too narrow to render)', fg: GLOAM.fg4, italic: true }]];\n }\n\n const colW: number[] = [...naturalW];\n for (let i = 0; i < ncols; i++) if (colW[i]! < minColW) colW[i] = minColW;\n let total = colW.reduce((a, b) => a + b, 0);\n\n if (total > available) {\n // Shrink the widest column repeatedly until it fits.\n while (total > available) {\n let widest = 0;\n for (let i = 1; i < ncols; i++) if (colW[i]! > colW[widest]!) widest = i;\n if (colW[widest]! <= minColW) break;\n colW[widest]!--;\n total--;\n }\n } else if (total < available) {\n // Grow the widest column to absorb the slack so the right border aligns.\n while (total < available) {\n let widest = 0;\n for (let i = 1; i < ncols; i++) if (colW[i]! > colW[widest]!) widest = i;\n colW[widest]!++;\n total++;\n }\n }\n\n const borderFg = GLOAM.fg3;\n const headerFg = GLOAM.fg0;\n const headerBg = GLOAM.bg_bg1;\n const cellFg = GLOAM.fg1;\n const marginText = ' ';\n\n const buildBorder = (left: string, mid: string, right: string): DetailLine => {\n let s = left;\n for (let i = 0; i < ncols; i++) {\n s += '─'.repeat(colW[i]! + 2);\n s += i === ncols - 1 ? right : mid;\n }\n return [{ text: marginText }, { text: s, fg: borderFg }];\n };\n\n const buildDataRow = (cells: string[], header: boolean): DetailLine[] => {\n const wrapped: string[][] = [];\n for (let i = 0; i < ncols; i++) {\n const cell = cells[i];\n wrapped.push(wrapCell(cell === undefined ? '' : cell, colW[i]!, aligns[i]!));\n }\n let height = 1;\n for (const w of wrapped) if (w.length > height) height = w.length;\n // Pad shorter columns with blank lines so the row has a uniform height.\n for (let i = 0; i < ncols; i++) {\n const blank = ' '.repeat(colW[i]!);\n while (wrapped[i]!.length < height) wrapped[i]!.push(blank);\n }\n\n const out: DetailLine[] = [];\n for (let row = 0; row < height; row++) {\n const segs: Seg[] = [\n { text: marginText },\n { text: '│', fg: borderFg },\n ];\n for (let i = 0; i < ncols; i++) {\n const padded = ' ' + wrapped[i]![row]! + ' ';\n segs.push(\n header\n ? { text: padded, fg: headerFg, bg: headerBg, bold: true }\n : { text: padded, fg: cellFg },\n );\n segs.push({ text: '│', fg: borderFg });\n }\n out.push(segs);\n }\n return out;\n };\n\n const out: DetailLine[] = [];\n out.push(buildBorder('┌', '┬', '┐'));\n for (const dl of buildDataRow(headers, true)) out.push(dl);\n out.push(buildBorder('├', '┼', '┤'));\n for (const r of rows) for (const dl of buildDataRow(r, false)) out.push(dl);\n out.push(buildBorder('└', '┴', '┘'));\n return out;\n}\n\n// ─── Public entry point ────────────────────────────────────────────────────\n\n/**\n * Convert a markdown document into a stream of styled DetailLine[] sized to\n * `innerW` columns. Trailing/leading blank lines are normalized; YAML\n * frontmatter is stripped via the shared helper.\n */\nexport function buildHighlightedMarkdownLines(\n content: string,\n innerW: number,\n): DetailLine[] {\n const lines: DetailLine[] = [];\n const clean = stripFrontmatter(content);\n if (!clean.trim()) {\n lines.push([{ text: ' (empty)', fg: GLOAM.fg4, italic: true }]);\n return lines;\n }\n\n const rawLines = clean.split('\\n');\n let inCodeBlock = false;\n\n for (let li = 0; li < rawLines.length; li++) {\n const raw = rawLines[li]!;\n const trimmed = raw.trim();\n\n // Code fence — toggles block state, rendered as a dim line\n if (/^```/.test(trimmed)) {\n inCodeBlock = !inCodeBlock;\n lines.push(buildCodeFenceLine(trimmed, innerW));\n continue;\n }\n\n if (inCodeBlock) {\n lines.push(buildCodeLine(raw.replace(/\\t/g, ' '), innerW));\n continue;\n }\n\n // GFM table: current line has a pipe and next line is an alignment row.\n if (trimmed.includes('|') && li + 1 < rawLines.length) {\n const sepLine = rawLines[li + 1]!;\n const sepAligns = parseTableSeparator(sepLine);\n if (sepAligns) {\n const headers = parseTableCells(raw);\n const tRows: string[][] = [];\n let j = li + 2;\n while (j < rawLines.length) {\n const next = rawLines[j]!;\n if (next.trim() === '') break;\n if (!next.includes('|')) break;\n if (/^```/.test(next.trim())) break;\n tRows.push(parseTableCells(next));\n j++;\n }\n for (const tl of buildTableLines(headers, sepAligns, tRows, innerW)) lines.push(tl);\n li = j - 1; // resume after consumed rows; loop ++ moves past them\n continue;\n }\n }\n\n // Empty line\n if (trimmed === '') {\n // Collapse multi-blanks into a single blank\n const last = lines[lines.length - 1];\n if (last && last.length === 1 && last[0]!.text === '') continue;\n lines.push([{ text: '' }]);\n continue;\n }\n\n // Frontmatter delimiter inside body (already stripped above, but defensive)\n if (trimmed === '---') {\n lines.push(buildHrLine(innerW));\n continue;\n }\n\n // Heading\n const headMatch = raw.match(/^(\\s*)(#{1,6})\\s+(.+?)\\s*#*\\s*$/);\n if (headMatch) {\n const level = headMatch[2]!.length;\n lines.push(buildHeadingLine(level, headMatch[3]!, innerW));\n continue;\n }\n\n // Horizontal rule\n if (/^\\s*([-*_])(\\s*\\1){2,}\\s*$/.test(raw)) {\n lines.push(buildHrLine(innerW));\n continue;\n }\n\n // Checkbox (must come before bullet match)\n const cbMatch = raw.match(/^\\s*[-*+]\\s+\\[( |x|X)\\]\\s+(.+)$/);\n if (cbMatch) {\n const checked = cbMatch[1] !== ' ';\n for (const wl of buildCheckboxLine(checked, cbMatch[2]!, innerW)) lines.push(wl);\n continue;\n }\n\n // Numbered list\n const numMatch = raw.match(/^(\\s*)(\\d+)([.)])\\s+(.+)$/);\n if (numMatch) {\n const indent = numMatch[1]!.length > 0 ? ' ' : ' ';\n const marker = `${numMatch[2]}${numMatch[3]}`;\n for (const wl of buildListLine(marker, numMatch[4]!, innerW, indent, GLOAM.purple)) {\n lines.push(wl);\n }\n continue;\n }\n\n // Bullet list\n const bulMatch = raw.match(/^(\\s*)([-*+])\\s+(.+)$/);\n if (bulMatch) {\n const depth = Math.floor(bulMatch[1]!.length / 2);\n const indent = ' ' + ' '.repeat(Math.min(depth, 4));\n const bullet = depth === 0 ? '·' : '◦';\n for (const wl of buildListLine(bullet, bulMatch[3]!, innerW, indent, GLOAM.orange)) {\n lines.push(wl);\n }\n continue;\n }\n\n // Blockquote\n const qMatch = raw.match(/^\\s*>\\s?(.*)$/);\n if (qMatch) {\n for (const wl of buildQuoteLine(qMatch[1]!, innerW)) lines.push(wl);\n continue;\n }\n\n // Paragraph\n for (const wl of buildParagraphLines(trimmed, innerW)) lines.push(wl);\n }\n\n // Trim trailing blank\n while (lines.length > 0) {\n const last = lines[lines.length - 1]!;\n if (last.length === 1 && last[0]!.text === '') lines.pop();\n else break;\n }\n\n return lines;\n}\n","/**\n * Gloam palette — true-color ANSI SGR codes mirroring the Neovim gloam theme.\n *\n * Each constant is a partial SGR sequence (no leading `\\x1b[`, no trailing `m`)\n * suitable for `Seg.fg` and `Seg.bg` fields. Foreground codes use the `38;2;…`\n * 24-bit form; background codes use `48;2;…`.\n *\n * Source palette: ~/.config/nvim/lua/gloam/palette.lua\n */\n\nfunction fg(r: number, g: number, b: number): string {\n return `38;2;${r};${g};${b}`;\n}\n\nfunction bg(r: number, g: number, b: number): string {\n return `48;2;${r};${g};${b}`;\n}\n\nexport const GLOAM = {\n // Foregrounds — warm off-whites\n fg0: fg(226, 217, 198), // brightest\n fg1: fg(212, 203, 184), // primary\n fg2: fg(176, 168, 152), // secondary\n fg3: fg(135, 127, 111), // tertiary (comments, quotes)\n fg4: fg(94, 88, 78), // quaternary (line numbers, concealed)\n\n // Accents\n red: fg(212, 116, 102),\n orange: fg(216, 151, 104),\n yellow: fg(212, 173, 106),\n green: fg(169, 177, 110),\n aqua: fg(130, 173, 138),\n blue: fg(124, 168, 160),\n purple: fg(196, 138, 158),\n\n // Bright accents — heading text, emphasis\n bright_red: fg(232, 138, 126),\n bright_orange: fg(236, 173, 128),\n bright_yellow: fg(232, 196, 132),\n bright_green: fg(188, 197, 126),\n bright_blue: fg(144, 190, 182),\n bright_purple: fg(216, 160, 180),\n\n // Dim backgrounds — heading/code-block tints\n bg_dim_red: bg(58, 28, 24),\n bg_dim_orange: bg(58, 40, 18),\n bg_dim_yellow: bg(51, 46, 18),\n bg_dim_green: bg(31, 48, 24),\n bg_dim_aqua: bg(20, 46, 36),\n bg_dim_blue: bg(21, 40, 56),\n bg_dim_purple: bg(50, 24, 40),\n\n // Surface backgrounds\n bg_bg1: bg(37, 38, 41), // cursorline / inline-code tint\n bg_bg2: bg(45, 47, 51), // float/popup\n bg_sel_yellow: bg(61, 50, 37), // active selection\n} as const;\n\nexport type GloamKey = keyof typeof GLOAM;\n","import { writeClipped, type FrameBuffer } from '../render.js';\nimport { ansiBold, ansiDim } from '../lib/format.js';\nimport type { AppState } from '../state.js';\nimport type { TreeNodeType } from '../types/tree.js';\n\n// ─── Status Line ──────────────────────────────────────────────────────────────\n\nconst B = ansiBold;\nconst D = ansiDim;\nconst SEP = D('│ ');\nconst DANGER_BADGE = '\\x1b[1;41;97m DANGEROUS \\x1b[0m';\n\nexport function renderStatusLine(\n buf: FrameBuffer,\n y: number,\n state: AppState,\n cursorNodeType: TreeNodeType | undefined,\n): void {\n const { mode, focusPane, notification, error } = state;\n\n if (mode === 'report-detail') return;\n\n let content: string;\n\n // Notifications/errors take over the status line transiently\n if (notification !== null) {\n const icon = /error|failed/i.test(notification)\n ? '✕'\n : /success|created|killed|sent|copied|deleted/i.test(notification)\n ? '✓'\n : 'ℹ';\n content = `\\x1b[1;33m${icon} ${notification}\\x1b[0m`;\n } else if (error !== null) {\n content = `\\x1b[31m⚠ ${error}\\x1b[0m`;\n } else if (mode === 'search') {\n const cursor = `\\x1b[7m \\x1b[0m`;\n content = `\\x1b[1;34m/\\x1b[0m${state.searchText}${cursor}` + D(' enter to apply · esc to clear');\n } else if (mode === 'leader') {\n content = `\\x1b[1;35mLEADER\\x1b[0m` + D(' [c]opy [o]pen [a]gent [S]ession [g]o or [s]cycle [h]ome [n]ew [m]sg [t]status [l]picker [x]kill [/]search [?]help [esc] cancel');\n } else if (mode === 'copy-menu') {\n content = `\\x1b[1;36mCOPY\\x1b[0m` + D(' [p]ath [i]d [c] context [l]ogs [r]eport [a]gent ID [esc] cancel');\n } else if (mode === 'open-menu') {\n content = `\\x1b[1;32mOPEN\\x1b[0m` + D(' [g]oal [r]oadmap [s]trategy [l]ogs [d]ir [R]eport [c]scratch [e]dit context [esc] cancel');\n } else if (mode === 'agent-menu') {\n content = `\\x1b[1;34mAGENT\\x1b[0m` + D(' [s]pawn [m]sg [r]estart [R]erun [j]ump [o]pen-claude [t]ail [k]ill [e]xplore [d]ebug [esc] cancel');\n } else if (mode === 'session-menu') {\n content = `\\x1b[1;31mSESSION\\x1b[0m` + D(' [n]ew [r]esume [c]ontinue [b]ollback [k]ill [d]elete [e]xport [w]indow [C]lone [i]history [esc] cancel');\n } else if (mode === 'go-menu') {\n content = `\\x1b[1;33mGO\\x1b[0m` + D(' [w]indow [p]ane [s]ession [n]ext [r]econnect [esc] cancel');\n } else if (mode === 'help') {\n content = `\\x1b[1;33mHELP\\x1b[0m` + D(' [esc] or [?] to dismiss');\n } else if (focusPane === 'logs' || focusPane === 'detail') {\n content =\n B('[jk/↑↓]') + D(' scroll ') +\n B('[h/←/tab]') + D(' back ') +\n B('[t]') + D('oggle view ') +\n B('[F]') + D('low ± ') +\n SEP +\n B('[m]') + D('sg ') +\n B('[g]') + D('oal ') +\n B('[n]') + D('ew ') +\n B('[p]') + D('lan ') +\n B('[w]') + D('indow ') +\n B('[R]') + D('esume ') +\n B('[q]') + D('uit');\n } else if (cursorNodeType === 'needs-you-virtual') {\n content =\n B('[enter]') + D(' open ask ') +\n B('[esc]') + D(' back ') +\n SEP +\n B('[q]') + D('uit');\n } else {\n // tree focused\n let contextFilePart = '';\n if (cursorNodeType === 'context-file') {\n contextFilePart = B('[e]') + D('dit ') + B('[⏎]') + D(' open ');\n }\n content =\n contextFilePart +\n B('[enter]') + D(' select ') +\n B('[m]') + D('essage ') +\n B('[n]') + D('ew ') +\n B('[w]') + D(' tmux ') +\n SEP +\n B('[q]') + D('uit');\n }\n\n if (state.selectedSession?.dangerousMode === true) {\n content = `${DANGER_BADGE} ${content}`;\n }\n\n writeClipped(buf, 1, y, content, buf.width - 2);\n}\n","import { buildPanelRows, buildEmptyPanelRows, type Rect } from '../render.js';\nimport type { AppState } from '../state.js';\nimport {\n seg, singleLine, formatTimeAgo, truncate, type DetailLine,\n} from '../lib/format.js';\nimport { coerceKind, type AggregateInboxItem } from '../../shared/inbox-types.js';\n\nconst KIND_ICON: Record<string, string> = {\n notify: '✉',\n validation: '✓',\n decision: '◆',\n context: '✎',\n error: '⚠',\n};\nconst KIND_COLOR: Record<string, string> = {\n notify: 'gray',\n validation: 'cyan',\n decision: 'cyan',\n context: 'cyan',\n error: 'red',\n};\n\nfunction buildInboxLines(items: AggregateInboxItem[], width: number): DetailLine[] {\n const lines: DetailLine[] = [];\n if (items.length === 0) {\n lines.push(singleLine(' No pending asks across the fleet', { dim: true, italic: true }));\n return lines;\n }\n lines.push(singleLine(` ${items.length} pending`, { bold: true }));\n lines.push(singleLine(' '));\n const contentWidth = width - 4;\n for (const item of items) {\n const kindKey = coerceKind(item.kind);\n const icon = kindKey in KIND_ICON ? KIND_ICON[kindKey]! : '·';\n const iconColor = kindKey in KIND_COLOR ? KIND_COLOR[kindKey]! : 'cyan';\n const source = item.sessionName ? item.sessionName : item.sessionId.slice(0, 8);\n const titleText = item.title ? item.title : `(${item.askId.slice(0, 8)})`;\n const blocked = formatTimeAgo(item.blockedSince);\n const maxTitle = Math.max(10, contentWidth - source.length - blocked.length - 8);\n lines.push([\n seg(' '),\n seg(icon, { color: iconColor }),\n seg(` ${source}`, { color: 'yellow' }),\n seg(' · ', { dim: true }),\n seg(truncate(titleText, maxTitle), { bold: true }),\n seg(` ${blocked}`, { dim: true }),\n ]);\n if (item.subtitle) {\n lines.push(singleLine(` ${truncate(item.subtitle, contentWidth - 6)}`, { dim: true }));\n }\n }\n return lines;\n}\n\nexport function renderCrossSessionInboxRows(rect: Rect, state: AppState): string[] {\n if (rect.w <= 0 || rect.h <= 0) {\n return buildEmptyPanelRows(rect, state.focusPane === 'detail', 'red', '');\n }\n const focused = state.focusPane === 'detail';\n const items = state.aggregateInbox;\n const fingerprint = items.map(i => `${i.askId}:${i.status}`).join(',');\n const cacheKey = `${items.length}:${fingerprint}:${rect.w}`;\n let lines: DetailLine[];\n if (cacheKey === state.inboxCacheKey && state.cachedInboxLines !== null) {\n lines = state.cachedInboxLines;\n } else {\n lines = buildInboxLines(items, rect.w);\n state.cachedInboxLines = lines;\n state.inboxCacheKey = cacheKey;\n }\n return buildPanelRows(rect, lines, state.crossSessionInboxScroll, focused, 'red', state.inboxRenderedCache);\n}\n","import { execSync } from 'node:child_process';\nimport { mkdtempSync, writeFileSync, readFileSync, rmSync } from 'node:fs';\nimport { join } from 'node:path';\nimport { tmpdir } from 'node:os';\nimport { shellQuote } from '../../shared/shell.js';\nimport { EXEC_ENV } from '../../shared/exec.js';\nimport { type AppState, type ComposeAction, OPTIONAL_COMPOSE, notify } from '../state.js';\nimport type { InputActions } from '../input.js';\nimport { dispatchComposeAction } from '../input.js';\n\nexport { ensureSisyphusInitLua } from '../../shared/sisyphus-init-lua.js';\n\n/**\n * Open a tmux popup running `NVIM_APPNAME=sisyphus nvim <tempfile>`, await close,\n * read content, dispatch action. Empty file = cancel (no submission).\n * Synchronous; blocks the TUI render loop until popup exits.\n */\nexport function composeViaPopup(\n action: ComposeAction,\n state: AppState,\n actions: InputActions,\n): void {\n const tmpDir = mkdtempSync(join(tmpdir(), 'sisyphus-popup-'));\n const tempFile = join(tmpDir, 'compose.md');\n try {\n writeFileSync(tempFile, '', 'utf-8');\n const cmd = `NVIM_APPNAME=sisyphus nvim ${shellQuote(tempFile)}`;\n execSync(\n `tmux display-popup -E -w 90% -h 90% -d ${shellQuote(state.cwd)} ${shellQuote(cmd)}`,\n { stdio: 'inherit', env: EXEC_ENV },\n );\n\n let rawContent = '';\n try { rawContent = readFileSync(tempFile, 'utf-8'); } catch { /* ignore */ }\n\n const required = !OPTIONAL_COMPOSE.has(action.kind);\n if (!rawContent.trim() && required) {\n // Cancel: silent. Match editInPopup semantics — no notification on cancel.\n return;\n }\n // Dispatch original untrimmed content — trim is only for cancel detection above.\n dispatchComposeAction(action, rawContent, state, actions);\n } catch (err) {\n notify(state, `Failed to open compose popup: ${(err as Error).message}`);\n } finally {\n rmSync(tmpDir, { recursive: true, force: true });\n }\n}\n","import { mkdirSync, existsSync, cpSync } from 'node:fs';\nimport { join } from 'node:path';\nimport { homedir } from 'node:os';\n\nlet initLuaEnsured = false;\n\n/**\n * Idempotent: copies templates/sisyphus-init.lua to ~/.config/sisyphus/init.lua\n * if and only if the destination doesn't exist. Safe to call repeatedly.\n *\n * Loaded only when nvim is invoked as `NVIM_APPNAME=sisyphus nvim ...` (compose\n * flows in both the TUI popup and the in-session tmux scripts).\n */\nexport function ensureSisyphusInitLua(): void {\n if (initLuaEnsured) return;\n initLuaEnsured = true;\n try {\n const destDir = join(homedir(), '.config', 'sisyphus');\n const destPath = join(destDir, 'init.lua');\n if (existsSync(destPath)) return;\n mkdirSync(destDir, { recursive: true });\n const srcPath = join(import.meta.dirname, 'templates', 'sisyphus-init.lua');\n cpSync(srcPath, destPath);\n } catch {\n // Non-fatal: nvim still opens, just without sisyphus init customization.\n }\n}\n"],"mappings":"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AAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,gBAAgB;AAAA,IACd;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,kBAAkB;AAAA,IAChB;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,aAAa;AAAA,IACX;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,cAAc;AAAA,IACZ;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,WAAW;AAAA,IACT;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,WAAW;AAAA,IACT;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,WAAW;AAAA,IACT;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,iBAAiB;AAAA,IACf;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,UAAU;AAAA,IACR;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,qBAAqB;AAAA,IACnB;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,eAAe;AAAA,IACb;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,eAAe;AAAA,IACb;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,cAAc;AAAA,IACZ;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,aAAa;AAAA,IACX;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,iBAAiB;AAAA,IACf;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,SAAS;AAAA,IACP;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,YAAY;AAAA,IACV;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,eAAe;AAAA,IACb;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,cAAc;AAAA,IACZ;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,cAAc;AAAA,IACZ;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,UAAU;AAAA,IACR;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,eAAe;AAAA,IACb;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA;AAAA,EAGA,YAAY;AAAA,IACV;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,SAAS;AAAA,IACP;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,aAAa;AAAA,IACX;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,YAAY;AAAA,IACV;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,eAAe;AAAA,IACb;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,aAAa;AAAA,IACX;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,gBAAgB;AAAA,IACd;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,QAAQ;AAAA,IACN;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,kBAAkB;AAAA,IAChB;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,cAAc;AAAA,IACZ;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,SAAS;AAAA,IACP;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,aAAa;AAAA,IACX;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,SAAS;AAAA,IACP;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,aAAa;AAAA,IACX;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,SAAS;AAAA,IACP;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,sBAAsB;AAAA,IACpB;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,aAAa;AAAA,IACX;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,iBAAiB;AAAA,IACf;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,YAAY;AAAA,IACV;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,SAAS;AAAA,IACP;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA;AAAA,EAGA,aAAa;AAAA,IACX;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,eAAe;AAAA,IACb;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,cAAc;AAAA,IACZ;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,mBAAmB;AAAA,IACjB;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,eAAe;AAAA,IACb;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,iBAAiB;AAAA,IACf;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA;AAAA,EAGA,aAAa;AAAA,IACX;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,YAAY;AAAA,IACV;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,qBAAqB;AAAA,IACnB;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,SAAS;AAAA,IACP;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,YAAY;AAAA,IACV;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,UAAU;AAAA,IACR;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,E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","names":["cleanup","key","cwd","sessionId","askId","existsSync","readFileSync","cached","stringWidth","prevFrame","readFileSync","cwd","mkdirSync","writeFileSync","renameSync","readdirSync","readFileSync","rmSync","randomUUID","dirname","join","randomUUID","dirname","join","renameSync","writeFileSync","resolve","existsSync","readFileSync","writeFileSync","join","existsSync","mkdirSync","readFileSync","readdirSync","rmSync","statSync","writeFileSync","join","execFile","writeFileSync","mkdirSync","existsSync","join","homedir","existsSync","mkdirSync","readFileSync","readdirSync","cwd","sessionId","askId","existsSync","mountPanel","cwd","sessionId","askId","prevFrame","cwd","state","readFileSync","existsSync","readdirSync","statSync","join","readFileSync","readdirSync","statSync","join","homedir","join","sessionId","cwd","state","join","cwd","join","stringWidth","stringWidth","result","existsSync","mkdirSync","readFileSync","renameSync","writeFileSync","randomUUID","dirname","join","state","existsSync","mkdirSync","readFileSync","writeFileSync","join","wrapText","MOOD_COLORS","wrapText","divider","readFileSync","resolve","state","readFileSync","askId","state","cwd","sessionId","readdirSync","statSync","join","readFileSync","session","readFileSync","execSync","join","readFileSync","writeFileSync","rmSync","cpSync","existsSync","mkdirSync","execSync","cwd","execSync","execSync","cwd","join","existsSync","mkdirSync","cpSync","readFileSync","writeFileSync","rmSync","args","sessionId","firstPaneId","readFileSync","readdirSync","readFileSync","cwd","stringWidth","stringWidth","stringWidth","stringWidth","bg","row","cleaned","wrapped","state","lines","stringWidth","stringWidth","out","state","state","state","execSync","mkdtempSync","writeFileSync","readFileSync","rmSync","join","tmpdir","mkdirSync","existsSync","cpSync","join","homedir","state","mkdtempSync","join","tmpdir","writeFileSync","execSync","readFileSync","rmSync","statSync","readFileSync","state","state","cleanup","cached","existsSync","readFileSync","join","readdirSync","statSync","out","runSingleAsk"]}
|