sisyphi 1.1.34 → 1.1.35
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +1391 -382
- package/dist/cli.js.map +1 -1
- package/dist/templates/agent-plugin/agents/operator.md +10 -0
- package/dist/templates/agent-plugin/hooks/CLAUDE.md +0 -1
- package/dist/templates/agent-plugin/hooks/operator-user-prompt.sh +33 -1
- package/dist/templates/agent-plugin/skills/operator/SKILL.md +38 -0
- package/dist/templates/agent-plugin/skills/operator-memory/SKILL.md +64 -0
- package/dist/templates/orchestrator-planning.md +7 -1
- package/dist/tui.js +45 -20
- package/dist/tui.js.map +1 -1
- package/package.json +1 -1
- package/templates/agent-plugin/agents/operator.md +10 -0
- package/templates/agent-plugin/hooks/CLAUDE.md +0 -1
- package/templates/agent-plugin/hooks/operator-user-prompt.sh +33 -1
- package/templates/agent-plugin/skills/operator/SKILL.md +38 -0
- package/templates/agent-plugin/skills/operator-memory/SKILL.md +64 -0
- package/templates/orchestrator-planning.md +7 -1
package/dist/cli.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/shared/paths.ts","../src/daemon/lib/atomic.ts","../src/cli/deploy/creds.ts","../src/cli/index.ts","../src/cli/commands/start.ts","../src/shared/client.ts","../src/cli/install.ts","../src/cli/tmux-setup.ts","../src/shared/keymap.ts","../src/cli/plugins.ts","../src/shared/config.ts","../src/daemon/plugins.ts","../src/cli/client.ts","../src/cli/stdin.ts","../src/cli/tmux.ts","../src/shared/shell.ts","../src/cli/commands/dashboard.ts","../src/cli/commands/status.ts","../src/shared/utils.ts","../src/shared/format.ts","../src/cli/commands/list.ts","../src/cli/commands/tell.ts","../src/cli/commands/read.ts","../src/cli/commands/message.ts","../src/cli/commands/ask.ts","../src/shared/ask-schema.ts","../src/daemon/ask-store.ts","../src/daemon/history.ts","../src/daemon/state.ts","../src/shared/gitignore.ts","../src/shared/types.ts","../src/daemon/notify.ts","../src/shared/exec.ts","../src/shared/env.ts","../src/cli/commands/kill.ts","../src/cli/commands/delete.ts","../src/cli/commands/resume.ts","../src/cli/commands/continue.ts","../src/cli/commands/complete.ts","../src/cli/commands/rollback.ts","../src/cli/commands/reconnect.ts","../src/cli/commands/clone.ts","../src/cli/commands/update-task.ts","../src/cli/commands/set-effort.ts","../src/tui/lib/context.ts","../src/tui/lib/reports.ts","../src/cli/commands/print-context.ts","../src/cli/commands/spawn.ts","../src/daemon/frontmatter.ts","../src/cli/commands/submit.ts","../src/cli/commands/report.ts","../src/cli/commands/await.ts","../src/cli/commands/kill-agent.ts","../src/cli/commands/restart-agent.ts","../src/cli/commands/yield.ts","../src/cli/commands/register-segment.ts","../src/cli/commands/unregister-segment.ts","../src/cli/commands/setup.ts","../src/cli/onboard.ts","../src/cli/commands/setup-keybind.ts","../src/cli/commands/home-init.ts","../src/cli/commands/doctor.ts","../src/cli/commands/init.ts","../src/cli/commands/uninstall.ts","../src/cli/commands/configure-upload.ts","../src/cli/commands/getting-started.ts","../src/cli/commands/history.ts","../src/shared/session-export.ts","../src/cli/commands/export.ts","../src/cli/commands/upload.ts","../src/shared/upload.ts","../src/shared/manifest.ts","../src/shared/version.ts","../src/cli/commands/scratch.ts","../src/cli/commands/review.ts","../src/cli/commands/companion.ts","../src/shared/companion-render.ts","../src/shared/companion-types.ts","../src/shared/companion-badges.ts","../src/daemon/companion-memory.ts","../src/daemon/haiku.ts","../src/daemon/companion.ts","../src/shared/companion-normalize.ts","../src/daemon/companion-popup.ts","../src/cli/commands/deploy.ts","../src/cli/deploy/runner.ts","../src/cli/deploy/pricing.ts","../src/cli/deploy/runtime.ts","../src/cli/deploy/tailnet.ts","../src/cli/deploy/templates.ts","../src/cli/deploy/tailscale.ts","../src/cli/cloud/runner.ts","../src/cli/deploy/ssh-exec.ts","../src/cli/cloud/grove.ts","../src/cli/cloud/repo.ts","../src/cli/cloud/sidecar.ts","../src/cli/deploy/provider-pick.ts","../src/cli/commands/cloud.ts","../src/cli/commands/notify.ts","../src/cli/commands/tmux-sessions.ts"],"sourcesContent":["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 { 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 { chmodSync, existsSync, mkdirSync, readFileSync } from 'node:fs';\nimport { createInterface } from 'node:readline';\nimport { atomicWrite } from '../../daemon/lib/atomic.js';\nimport {\n deployCredsPath,\n deployDir,\n deployTailscaleEnvPath,\n} from '../../shared/paths.js';\n\nexport type Provider = 'hetzner' | 'aws';\n\nexport const PROVIDERS: readonly Provider[] = ['hetzner', 'aws'];\n\nexport function isValidProvider(value: string): value is Provider {\n return (PROVIDERS as readonly string[]).includes(value);\n}\n\ninterface CredsSpec {\n provider: Provider;\n required: readonly string[];\n optional?: readonly string[];\n helpUrl: string;\n}\n\nconst SPECS: Record<Provider, CredsSpec> = {\n hetzner: {\n provider: 'hetzner',\n required: ['HCLOUD_TOKEN'],\n helpUrl: 'https://console.hetzner.cloud/projects → API tokens → Generate',\n },\n aws: {\n provider: 'aws',\n required: ['AWS_ACCESS_KEY_ID', 'AWS_SECRET_ACCESS_KEY'],\n optional: ['AWS_REGION', 'AWS_SESSION_TOKEN'],\n helpUrl: 'https://console.aws.amazon.com/iam/home → Users → Security credentials',\n },\n};\n\nexport function ensureDeployDir(): void {\n const dir = deployDir();\n if (!existsSync(dir)) mkdirSync(dir, { recursive: true, mode: 0o700 });\n}\n\nfunction parseEnvFile(text: string): Record<string, string> {\n const out: Record<string, string> = {};\n for (const line of text.split('\\n')) {\n const trimmed = line.trim();\n if (!trimmed || trimmed.startsWith('#')) continue;\n const eq = trimmed.indexOf('=');\n if (eq < 0) continue;\n const key = trimmed.slice(0, eq).trim();\n let value = trimmed.slice(eq + 1).trim();\n if ((value.startsWith('\"') && value.endsWith('\"')) || (value.startsWith(\"'\") && value.endsWith(\"'\"))) {\n value = value.slice(1, -1);\n }\n out[key] = value;\n }\n return out;\n}\n\nfunction serializeEnvFile(values: Record<string, string>): string {\n const lines: string[] = ['# Managed by `sis deploy`. Do not edit unless you know what you are doing.'];\n for (const [k, v] of Object.entries(values)) {\n lines.push(`${k}=${v}`);\n }\n return lines.join('\\n') + '\\n';\n}\n\nfunction readEnvFile(path: string): Record<string, string> | null {\n if (!existsSync(path)) return null;\n return parseEnvFile(readFileSync(path, 'utf-8'));\n}\n\nfunction writeEnvFile(path: string, values: Record<string, string>): void {\n ensureDeployDir();\n atomicWrite(path, serializeEnvFile(values));\n chmodSync(path, 0o600);\n}\n\nasync function promptLine(question: string, hidden: boolean): Promise<string> {\n const rl = createInterface({ input: process.stdin, output: process.stdout, terminal: true });\n // Mute echo for secrets — same trick as `read -s`.\n if (hidden) {\n const stdout = process.stdout as NodeJS.WriteStream & { _writeToOutput?: (s: string) => void };\n const originalWrite = stdout.write.bind(stdout);\n let prompted = false;\n (rl as unknown as { _writeToOutput: (s: string) => void })._writeToOutput = (stringToWrite: string) => {\n if (!prompted) {\n originalWrite(stringToWrite);\n prompted = true;\n }\n // swallow subsequent keystroke echoes\n };\n }\n const answer = await new Promise<string>((resolve) => rl.question(question, resolve));\n rl.close();\n if (hidden) process.stdout.write('\\n');\n return answer.trim();\n}\n\nasync function promptMissing(spec: CredsSpec, existing: Record<string, string>): Promise<Record<string, string>> {\n const next = { ...existing };\n const missing = spec.required.filter((k) => !next[k]);\n if (missing.length === 0) return next;\n\n console.log('');\n console.log(`Provider creds needed for: ${spec.provider}`);\n console.log(`Where to get them: ${spec.helpUrl}`);\n console.log('');\n for (const key of missing) {\n const isSecret = /SECRET|TOKEN|KEY/.test(key) && key !== 'AWS_ACCESS_KEY_ID';\n const value = await promptLine(` ${key}: `, isSecret);\n if (!value) throw new Error(`${key} is required.`);\n next[key] = value;\n }\n return next;\n}\n\n/**\n * Load creds for a provider. If any required keys are missing, prompts the\n * user and persists to `~/.sisyphus/deploy/<provider>.env` (0600). Returns\n * the loaded env vars merged with `process.env`-style record suitable for\n * passing as `env` to a child process.\n */\nexport async function loadProviderCreds(provider: Provider): Promise<Record<string, string>> {\n const spec = SPECS[provider];\n const path = deployCredsPath(provider);\n const existing = readEnvFile(path) ?? {};\n const final = await promptMissing(spec, existing);\n if (final !== existing) writeEnvFile(path, final);\n return final;\n}\n\nexport function maskValue(value: string): string {\n if (value.length <= 8) return '*'.repeat(value.length);\n return value.slice(0, 4) + '*'.repeat(value.length - 8) + value.slice(-4);\n}\n\n// ── Tailscale ─────────────────────────────────────────────────────────────────\n\nexport interface TailscaleEnv {\n // OAuth client (preferred): mints ephemeral, single-use, tagged keys per `up`.\n oauthClientId?: string;\n oauthClientSecret?: string;\n // Fallback: a reusable auth key pasted from the admin UI.\n authKey?: string;\n // Tag applied to minted keys (e.g. \"tag:sisyphus\") — required when using OAuth.\n tag?: string;\n}\n\nexport function readTailscaleEnv(): TailscaleEnv {\n const raw = readEnvFile(deployTailscaleEnvPath()) ?? {};\n return {\n oauthClientId: raw.TS_OAUTH_CLIENT_ID,\n oauthClientSecret: raw.TS_OAUTH_CLIENT_SECRET,\n authKey: raw.TS_AUTHKEY,\n tag: raw.TS_TAG,\n };\n}\n\nexport function writeTailscaleEnv(env: TailscaleEnv): void {\n const values: Record<string, string> = {};\n if (env.oauthClientId) values.TS_OAUTH_CLIENT_ID = env.oauthClientId;\n if (env.oauthClientSecret) values.TS_OAUTH_CLIENT_SECRET = env.oauthClientSecret;\n if (env.authKey) values.TS_AUTHKEY = env.authKey;\n if (env.tag) values.TS_TAG = env.tag;\n writeEnvFile(deployTailscaleEnvPath(), values);\n}\n\nexport { promptLine };\n","const nodeVersion = parseInt(process.versions.node.split('.')[0]!, 10);\nif (nodeVersion < 22) {\n console.error(`Sisyphus requires Node.js v22+ (current: v${process.versions.node})`);\n process.exit(1);\n}\n\nimport { Command } from 'commander';\nimport { existsSync, mkdirSync, readFileSync } from 'node:fs';\nimport { dirname, join } from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport { registerStart } from './commands/start.js';\nimport { registerStatus } from './commands/status.js';\nimport { registerDashboard } from './commands/dashboard.js';\nimport { registerList } from './commands/list.js';\nimport { registerTell } from './commands/tell.js';\nimport { registerRead } from './commands/read.js';\nimport { registerMessage } from './commands/message.js';\nimport { registerAsk } from './commands/ask.js';\nimport { registerKill } from './commands/kill.js';\nimport { registerDelete } from './commands/delete.js';\nimport { registerResume } from './commands/resume.js';\nimport { registerContinue } from './commands/continue.js';\nimport { registerComplete } from './commands/complete.js';\nimport { registerRollback } from './commands/rollback.js';\nimport { registerReconnect } from './commands/reconnect.js';\nimport { registerClone } from './commands/clone.js';\nimport { registerSessionTask } from './commands/update-task.js';\nimport { registerSessionEffort } from './commands/set-effort.js';\nimport { registerSessionContext } from './commands/print-context.js';\nimport { registerSpawn } from './commands/spawn.js';\nimport { registerSubmit } from './commands/submit.js';\nimport { registerReport } from './commands/report.js';\nimport { registerAwait } from './commands/await.js';\nimport { registerAgentKill } from './commands/kill-agent.js';\nimport { registerAgentRestart } from './commands/restart-agent.js';\nimport { registerYield } from './commands/yield.js';\nimport { registerSegmentRegister } from './commands/register-segment.js';\nimport { registerSegmentUnregister } from './commands/unregister-segment.js';\nimport { registerSetup } from './commands/setup.js';\nimport { registerSetupKeybind } from './commands/setup-keybind.js';\nimport { registerHomeInit } from './commands/home-init.js';\nimport { registerDoctor } from './commands/doctor.js';\nimport { registerInit } from './commands/init.js';\nimport { registerUninstall } from './commands/uninstall.js';\nimport { registerConfigureUpload } from './commands/configure-upload.js';\nimport { registerGettingStarted } from './commands/getting-started.js';\nimport { registerHistory } from './commands/history.js';\nimport { registerExport } from './commands/export.js';\nimport { registerUpload } from './commands/upload.js';\nimport { registerScratch } from './commands/scratch.js';\nimport { registerReview } from './commands/review.js';\nimport { registerCompanion } from './commands/companion.js';\nimport { registerDeploy } from './commands/deploy.js';\nimport { registerCloud } from './commands/cloud.js';\nimport { attachNotify } from './commands/notify.js';\nimport { attachTmuxSessions } from './commands/tmux-sessions.js';\nimport { globalDir } from '../shared/paths.js';\n\nconst program = new Command();\n\nprogram\n .name('sis')\n .description('tmux-integrated orchestration daemon for Claude Code')\n .version(\n JSON.parse(\n readFileSync(join(dirname(fileURLToPath(import.meta.url)), '..', 'package.json'), 'utf-8'),\n ).version,\n );\n\nprogram.configureHelp({\n sortSubcommands: false,\n});\n\n// Flat hot-path\nregisterStart(program);\nregisterStatus(program);\nregisterDashboard(program);\nregisterList(program);\nregisterTell(program);\nregisterRead(program);\nregisterMessage(program);\nregisterAsk(program);\n\n// session group\nconst session = program.command('session').description('Manage sessions');\nregisterKill(session);\nregisterDelete(session);\nregisterResume(session);\nregisterContinue(session);\nregisterComplete(session);\nregisterRollback(session);\nregisterReconnect(session);\nregisterClone(session);\nregisterSessionTask(session);\nregisterSessionEffort(session);\nregisterSessionContext(session);\n\n// agent group\nconst agent = program.command('agent').description('Manage agents');\nregisterSpawn(agent);\nregisterSubmit(agent);\nregisterReport(agent);\nregisterAwait(agent);\nregisterAgentKill(agent);\nregisterAgentRestart(agent);\n\n// orch group\nconst orch = program.command('orch').description('Orchestrator commands');\nregisterYield(orch);\n\n// segment group\nconst segment = program.command('segment').description('Status-line segments');\nregisterSegmentRegister(segment);\nregisterSegmentUnregister(segment);\n\n// admin group\nconst admin = program.command('admin').description('Admin / setup commands');\nregisterSetup(admin);\nregisterSetupKeybind(admin);\nregisterHomeInit(admin);\nregisterDoctor(admin);\nregisterInit(admin);\nregisterUninstall(admin);\nregisterConfigureUpload(admin);\nregisterGettingStarted(admin);\nregisterHistory(admin);\nregisterExport(admin);\nregisterUpload(admin);\nregisterScratch(admin);\nregisterReview(admin);\n\n// companion group (root action + memory + popup-test + context)\nregisterCompanion(program);\n\n// deploy group (Terraform-wrapped cloud provisioning)\nregisterDeploy(program);\n\n// cloud group (per-repo workflow on the deployed box)\nregisterCloud(program);\n\n// diagnostic group (hidden)\nconst diagnostic = program.command('diagnostic', { hidden: true });\nattachNotify(diagnostic);\nattachTmuxSessions(diagnostic);\n\nprogram.addHelpText('after', `\nExamples:\n $ sis start \"Implement auth system\" Start a new session\n $ sis start \"Build @reqs.md\" -n auth Start with name + requirements\n $ sis status Check current sessions\n $ sis dashboard Open the TUI\n $ sis admin doctor Verify installation\n\nRun 'sis admin getting-started' for a complete usage guide.\n`);\n\n// Show welcome on first run (before ~/.sisyphus exists)\nconst args = process.argv.slice(2);\nconst firstArg = args[0];\nconst skipWelcome = ['admin', 'help', '--help', '-h', '--version', '-V'];\nif (!existsSync(globalDir()) && firstArg && !skipWelcome.includes(firstArg)) {\n mkdirSync(globalDir(), { recursive: true });\n console.log('');\n console.log(\" Welcome to Sisyphus. Run 'sis admin setup' to get started.\");\n console.log('');\n}\n\nprogram.parseAsync(process.argv).catch((err: Error) => {\n console.error(err.message);\n process.exit(1);\n});\n","import type { Command } from 'commander';\nimport { execSync, spawnSync } from 'node:child_process';\nimport { basename } from 'node:path';\nimport { sendRequest } from '../client.js';\nimport { readStdin } from '../stdin.js';\nimport { getTmuxSessionInfo, isTmuxInstalled } from '../tmux.js';\nimport { shellQuote } from '../../shared/shell.js';\nimport { openDashboardWindow } from './dashboard.js';\nimport type { Request } from '../../shared/protocol.js';\n\n\n/**\n * Get or create a tmux session for the given cwd.\n * Returns the session name. Does NOT attach — caller decides.\n */\nfunction ensureTmuxSessionExists(cwd: string): string {\n const sessionName = `sisyphus-${basename(cwd)}`;\n\n try {\n execSync(`tmux has-session -t ${shellQuote(sessionName)}`, { stdio: 'pipe' });\n } catch {\n execSync(\n `tmux new-session -d -s ${shellQuote(sessionName)} -c ${shellQuote(cwd)}`,\n { stdio: 'pipe' },\n );\n }\n\n return sessionName;\n}\n\n/**\n * Attach the user's terminal to a tmux session.\n * If already inside tmux, switches the client. Otherwise, attaches directly.\n * Attach/switch takes over the terminal — this blocks until detach.\n */\nfunction attachToTmuxSession(sessionName: string): void {\n if (process.env['TMUX']) {\n // Already in tmux — switch to the target session\n spawnSync('tmux', ['switch-client', '-t', sessionName], { stdio: 'inherit' });\n } else {\n // Not in tmux — attach takes over the terminal\n spawnSync('tmux', ['attach-session', '-t', sessionName], { stdio: 'inherit' });\n }\n}\n\n\nexport function registerStart(program: Command): void {\n program\n .command('start')\n .description('Start a new sisyphus session')\n .argument('[task]', 'Task description for the orchestrator (omit when using --stdin)')\n .option('-c, --context <context>', 'Background context for the orchestrator')\n .option('-n, --name <name>', 'Human-readable name for the session')\n .option('--effort <tier>', 'Pipeline effort tier (low|medium|high|xhigh)')\n .option('--no-tmux-check', 'Skip the tmux session check')\n .option('--stdin', 'Read the task description from stdin (avoids shell escaping for long prompts)')\n .option('--context-stdin', 'Read the context from stdin (mutually exclusive with --stdin)')\n .action(async (taskArg: string | undefined, opts: { context?: string; name?: string; effort?: string; tmuxCheck?: boolean; stdin?: boolean; contextStdin?: boolean }) => {\n const cwd = process.env['SISYPHUS_CWD'] ?? process.cwd();\n\n if (opts.stdin && opts.contextStdin) {\n console.error('Error: --stdin and --context-stdin cannot be combined; pipe one and pass the other on argv');\n process.exit(1);\n }\n\n let task: string | undefined = taskArg;\n let context: string | undefined = opts.context;\n\n if (opts.stdin) {\n const piped = await readStdin({ force: true });\n if (!piped) {\n console.error('Error: --stdin set but no input received on stdin');\n process.exit(1);\n }\n if (taskArg !== undefined && taskArg !== '-') {\n console.error('Error: --stdin conflicts with [task] positional; pass one or the other');\n process.exit(1);\n }\n task = piped;\n } else if (taskArg === '-') {\n const piped = await readStdin({ force: true });\n if (!piped) {\n console.error(\"Error: task '-' means read stdin, but no input received\");\n process.exit(1);\n }\n task = piped;\n }\n\n if (opts.contextStdin) {\n const piped = await readStdin({ force: true });\n if (!piped) {\n console.error('Error: --context-stdin set but no input received on stdin');\n process.exit(1);\n }\n if (opts.context !== undefined) {\n console.error('Error: --context-stdin conflicts with -c/--context; use one');\n process.exit(1);\n }\n context = piped;\n }\n\n if (!task) {\n console.error('Error: provide <task> argument, pipe via --stdin, or pass `-` as the task');\n process.exit(1);\n }\n\n if (opts.effort !== undefined) {\n const validTiers = ['low', 'medium', 'high', 'xhigh'];\n if (!validTiers.includes(opts.effort)) {\n console.error(`Error: --effort must be one of: ${validTiers.join(', ')}`);\n process.exit(1);\n }\n }\n\n if (!isTmuxInstalled()) {\n console.error('Error: tmux is not installed. Sisyphus requires tmux for agent panes.');\n console.error(' Install: brew install tmux (macOS) or apt install tmux (Linux)');\n process.exit(1);\n }\n\n // Send the start request — this is just a socket call, no tmux needed\n const effort = opts.effort as 'low' | 'medium' | 'high' | 'xhigh' | undefined;\n const request: Request = { type: 'start', task, context, cwd, name: opts.name, ...(effort !== undefined ? { effort } : {}) };\n const response = await sendRequest(request);\n if (!response.ok) {\n console.error(`Error: ${response.error}`);\n process.exit(1);\n }\n\n const sessionId = response.data?.sessionId as string;\n console.log(`Task handed off to sisyphus orchestrator (session ${sessionId})`);\n\n if (opts.tmuxCheck === false) {\n // --no-tmux-check: print info and exit, don't touch tmux\n const tmuxSessionName = response.data?.tmuxSessionName as string | undefined;\n if (tmuxSessionName) {\n console.log(`Tmux session: ${tmuxSessionName}`);\n console.log(` tmux attach -t ${tmuxSessionName}`);\n }\n console.log(`Monitor: sis status ${sessionId}`);\n return;\n }\n\n // Determine which tmux session to use for the dashboard.\n // If we're already in tmux, use the current session.\n // If not, create a dedicated session for this project.\n let tmuxSession: string;\n let tmuxSessionTarget: string;\n if (process.env['TMUX']) {\n const info = getTmuxSessionInfo();\n tmuxSession = info.name;\n tmuxSessionTarget = info.id;\n } else {\n tmuxSession = ensureTmuxSessionExists(cwd);\n tmuxSessionTarget = tmuxSession;\n }\n\n // Tag the tmux session with the cwd — but don't clobber a tag that\n // already points to a different project. Overwriting would re-home an\n // existing session onto this project, poisoning alt+s cycle groups and\n // C-s h for the original project.\n // Target by $N id when available — tmux -t <name> can substring-match\n // the wrong session under sparse env.\n try {\n const normalizedCwd = cwd.replace(/\\/+$/, '');\n let existing = '';\n try {\n existing = execSync(\n `tmux show-options -t ${shellQuote(tmuxSessionTarget)} -v @sisyphus_cwd`,\n { encoding: 'utf-8', stdio: ['pipe', 'pipe', 'pipe'] },\n ).trim();\n } catch {\n // option unset\n }\n if (!existing || existing === normalizedCwd) {\n execSync(\n `tmux set-option -t ${shellQuote(tmuxSessionTarget)} @sisyphus_cwd ${shellQuote(normalizedCwd)}`,\n { stdio: 'ignore' },\n );\n } else {\n console.error(\n `Note: tmux session \"${tmuxSession}\" is already the home for ${existing}; leaving its @sisyphus_cwd unchanged.`,\n );\n }\n } catch (err) {\n console.error(`Warning: failed to tag tmux session with cwd: ${err instanceof Error ? err.message : String(err)}`);\n }\n\n // Open dashboard in the tmux session\n try {\n openDashboardWindow(tmuxSession, cwd);\n } catch (err) {\n console.error(`Warning: failed to open dashboard window: ${err instanceof Error ? err.message : String(err)}`);\n }\n\n // If we weren't in tmux, attach now — user lands on the dashboard\n if (!process.env['TMUX']) {\n attachToTmuxSession(tmuxSession);\n }\n\n console.log(`Monitor: sis status ${sessionId}`);\n });\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","import { execSync } from 'node:child_process';\nimport { existsSync, mkdirSync, readFileSync, rmSync, unlinkSync, writeFileSync } from 'node:fs';\nimport { connect } from 'node:net';\nimport { homedir } from 'node:os';\nimport { dirname, join, resolve } from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport { daemonLogPath, daemonUpdatingPath, globalDir, socketPath } from '../shared/paths.js';\nimport { type SetupResult, removeTmuxKeybind, setupTmuxKeybind } from './tmux-setup.js';\nimport { ensureRequiredPlugins, ensureSisyphusPluginInstalled, type SisyphusPluginInfo } from './plugins.js';\n\nconst PLIST_LABEL = 'com.sisyphus.daemon';\nconst PLIST_FILENAME = `${PLIST_LABEL}.plist`;\n\nfunction launchAgentDir(): string {\n return join(homedir(), 'Library', 'LaunchAgents');\n}\n\nfunction plistPath(): string {\n return join(launchAgentDir(), PLIST_FILENAME);\n}\n\nfunction daemonBinPath(): string {\n // In bundled output, cli.js and daemon.js are siblings in dist/\n const installDir = dirname(fileURLToPath(import.meta.url));\n return resolve(installDir, 'daemon.js');\n}\n\nfunction generatePlist(nodePath: string, daemonPath: string, logPath: string): string {\n return `<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n <key>Label</key>\n <string>${PLIST_LABEL}</string>\n <key>ProgramArguments</key>\n <array>\n <string>${nodePath}</string>\n <string>${daemonPath}</string>\n </array>\n <key>RunAtLoad</key>\n <true/>\n <key>KeepAlive</key>\n <true/>\n <key>StandardOutPath</key>\n <string>${logPath}</string>\n <key>StandardErrorPath</key>\n <string>${logPath}</string>\n</dict>\n</plist>\n`;\n}\n\nexport function isInstalled(): boolean {\n return existsSync(plistPath());\n}\n\nexport async function ensureDaemonInstalled(): Promise<void> {\n if (process.platform !== 'darwin') return;\n\n // Idempotent: ensures the user-facing slash-command plugin is available.\n // Placed outside the !isInstalled() guard so users whose daemon was installed\n // before this plugin shipped self-heal the next time the daemon is unreachable.\n const sisyphusPlugin = ensureSisyphusPluginInstalled();\n\n if (!isInstalled()) {\n const nodePath = process.execPath;\n const daemonPath = daemonBinPath();\n const logPath = daemonLogPath();\n\n mkdirSync(globalDir(), { recursive: true });\n mkdirSync(launchAgentDir(), { recursive: true });\n\n const plist = generatePlist(nodePath, daemonPath, logPath);\n writeFileSync(plistPath(), plist, 'utf8');\n\n execSync(`launchctl load -w ${plistPath()}`);\n\n const keybindResult = await setupTmuxKeybind();\n\n await ensureRequiredPlugins(process.cwd());\n\n printGettingStarted(keybindResult, sisyphusPlugin);\n }\n\n await waitForDaemon();\n}\n\nexport async function uninstallDaemon(purge: boolean): Promise<void> {\n if (process.platform !== 'darwin') {\n console.log('Auto-install is only supported on macOS.');\n return;\n }\n\n const plist = plistPath();\n if (existsSync(plist)) {\n try {\n execSync(`launchctl unload -w ${plist}`, { stdio: 'pipe' });\n } catch {\n // already unloaded or not registered — ignore\n }\n unlinkSync(plist);\n console.log('Daemon unloaded and plist removed.');\n } else {\n console.log('Daemon is not installed (plist not found).');\n }\n\n removeTmuxKeybind();\n\n if (purge) {\n const dir = globalDir();\n if (existsSync(dir)) {\n rmSync(dir, { recursive: true, force: true });\n console.log(`Removed ${dir}`);\n }\n }\n}\n\nfunction printGettingStarted(\n keybindResult: SetupResult,\n sisyphusPlugin: SisyphusPluginInfo,\n): void {\n const lines = [\n '',\n 'Sisyphus installed — daemon running via launchd.',\n '',\n ];\n\n if (keybindResult.status === 'installed') {\n lines.push(`Tmux keybind: ${keybindResult.message}`, '');\n } else if (keybindResult.status === 'conflict') {\n lines.push(`Keybind: ${keybindResult.message}`, '');\n } else if (keybindResult.status === 'conf-modification-declined') {\n lines.push(keybindResult.message, '');\n }\n\n if (sisyphusPlugin.installed && sisyphusPlugin.autoInstalled) {\n lines.push(`Sisyphus plugin installed: sisyphus@sisyphus → ${sisyphusPlugin.installPath}`, '');\n } else if (!sisyphusPlugin.installed) {\n lines.push('Sisyphus plugin: failed to install (run `sis admin setup` to retry; needs `claude` CLI)', '');\n }\n\n lines.push(\n 'Run `sis admin getting-started` for a complete usage guide.',\n '',\n );\n\n console.log(lines.join('\\n'));\n}\n\nfunction testConnection(): Promise<void> {\n return new Promise((resolve, reject) => {\n const sock = connect(socketPath());\n sock.on('connect', () => { sock.destroy(); resolve(); });\n sock.on('error', (err) => { sock.destroy(); reject(err); });\n });\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\nexport async function waitForDaemon(maxWaitMs = 6000): Promise<void> {\n const start = Date.now();\n let updatingLogged = false;\n\n while (Date.now() - start < maxWaitMs) {\n // Extend timeout if daemon is updating\n const updatingPath = daemonUpdatingPath();\n if (existsSync(updatingPath)) {\n if (!updatingLogged) {\n try {\n const version = readFileSync(updatingPath, 'utf-8').trim();\n console.log(`Updating sisyphus to ${version}...`);\n } catch {\n console.log('Updating sisyphus...');\n }\n updatingLogged = true;\n }\n maxWaitMs = Math.max(maxWaitMs, 30000);\n }\n\n if (existsSync(socketPath())) {\n try {\n await testConnection();\n return;\n } catch {\n // not ready yet\n }\n }\n await sleep(300);\n }\n throw new Error(`Daemon did not start within ${maxWaitMs}ms. Check ${daemonLogPath()}`);\n}\n","import { execSync } from 'node:child_process';\nimport { existsSync, mkdirSync, readFileSync, writeFileSync, chmodSync, unlinkSync } from 'node:fs';\nimport { homedir } from 'node:os';\nimport { join } from 'node:path';\nimport { createInterface } from 'node:readline';\nimport { globalDir } from '../shared/paths.js';\nimport { KEYMAP, formatHelpForKeymap, type MenuDef, type MenuItem, type Action } from '../shared/keymap.js';\n\nexport const DEFAULT_CYCLE_KEY = 'M-s';\nexport const DEFAULT_PREFIX_KEY = 'C-s';\nexport const KEY_TABLE = 'sisyphus';\n\nconst SISYPHUS_CONF_MARKER = '# sisyphus-managed — do not edit';\n\nfunction scriptPath(name: string): string {\n return join(globalDir(), 'bin', name);\n}\n\nexport function cycleScriptPath(): string {\n return scriptPath('sisyphus-cycle');\n}\n\nexport function homeScriptPath(): string {\n return scriptPath('sisyphus-home');\n}\n\nexport function killPaneScriptPath(): string {\n return scriptPath('sisyphus-kill-pane');\n}\n\nexport function newPromptScriptPath(): string {\n return scriptPath('sisyphus-new');\n}\n\nexport function messageScriptPath(): string {\n return scriptPath('sisyphus-msg');\n}\n\nexport function deleteSessionScriptPath(): string {\n return scriptPath('sisyphus-delete-session');\n}\n\nexport function killSessionScriptPath(): string {\n return scriptPath('sisyphus-kill-session');\n}\n\nexport function helpScriptPath(): string {\n return scriptPath('sisyphus-help');\n}\n\nexport function statusPopupScriptPath(): string {\n return scriptPath('sisyphus-status-popup');\n}\n\nexport function pickSessionScriptPath(): string {\n return scriptPath('sisyphus-pick-session');\n}\n\nexport function continueSessionScriptPath(): string {\n return scriptPath('sisyphus-continue-session');\n}\n\nexport function restartAgentScriptPath(): string {\n return scriptPath('sisyphus-restart-agent-popup');\n}\n\nexport function exportSessionScriptPath(): string {\n return scriptPath('sisyphus-export-session');\n}\n\nexport function openRoadmapScriptPath(): string {\n return scriptPath('sisyphus-open-roadmap');\n}\n\nexport function openStrategyScriptPath(): string {\n return scriptPath('sisyphus-open-strategy');\n}\n\nexport function keymapJsonPath(): string {\n return join(globalDir(), 'keymap.json');\n}\n\nexport function writeKeymapJson(): void {\n mkdirSync(globalDir(), { recursive: true });\n writeFileSync(keymapJsonPath(), JSON.stringify(KEYMAP, null, 2), 'utf8');\n}\n\nexport function tmuxVersionAtLeast(major: number, minor: number): boolean {\n try {\n const out = execSync('tmux -V', { stdio: ['pipe', 'pipe', 'pipe'] }).toString().trim();\n const match = out.match(/tmux\\s+(\\d+)\\.(\\d+)/);\n if (!match) return false;\n const v = parseInt(match[1], 10) * 1000 + parseInt(match[2], 10);\n return v >= major * 1000 + minor;\n } catch {\n return false;\n }\n}\n\nfunction menuItemCommand(action: Action, scriptsDir: string): string | null {\n switch (action.type) {\n case 'script':\n return `run-shell ${join(scriptsDir, action.name)}`;\n case 'popup': {\n const { w, h, borderStyle, title, cwd } = action.popup;\n let args = '-E';\n if (w) args += ` -w ${w}`;\n if (h) args += ` -h ${h}`;\n if (borderStyle) args += ` -S '${borderStyle}'`;\n if (title) args += ` -T '${title}'`;\n if (cwd === 'current') args += ` -d '#{pane_current_path}'`;\n return `display-popup ${args} ${join(scriptsDir, action.name)}`;\n }\n case 'submenu':\n return `run-shell ${join(scriptsDir, `sisyphus-menu-${action.ref}`)}`;\n case 'tmux':\n return action.cmd;\n case 'tui':\n return null;\n }\n}\n\nexport function generateMenuLine(item: MenuItem, scriptsDir: string): string {\n const cmd = menuItemCommand(item.action, scriptsDir);\n if (cmd === null) return '';\n const label = item.label.replace(/\"/g, '\\\\\"');\n return `\"${label}\" ${item.key} \"${cmd}\"`;\n}\n\nexport function generateSubmenuScript(submenuId: string, def: MenuDef, scriptsDir: string): string {\n const lines = def.items\n .map(item => generateMenuLine(item, scriptsDir))\n .filter(l => l !== '');\n const args = lines.join(' \\\\\\n ');\n return `#!/bin/bash\nexec tmux display-menu -T '${def.title}' -x R -y S \\\\\n ${args}\n`;\n}\n\nexport function generateTopLevelBinding(prefixKey: string, def: MenuDef, scriptsDir: string): string {\n const args = def.items\n .map(item => generateMenuLine(item, scriptsDir))\n .filter(l => l !== '')\n .join(' ');\n return `bind-key -T root ${prefixKey} display-menu -T '${def.title}' -x R -y S ${args}`;\n}\n\nexport function sisyphusTmuxConfPath(): string {\n return join(globalDir(), 'tmux.conf');\n}\n\nfunction userTmuxConfPath(): string | null {\n const dotfile = join(homedir(), '.tmux.conf');\n const xdg = join(homedir(), '.config', 'tmux', 'tmux.conf');\n if (existsSync(xdg)) return xdg;\n if (existsSync(dotfile)) return dotfile;\n return null;\n}\n\nconst CYCLE_SCRIPT = `#!/bin/bash\n# Target by $N session ID (column 5 in TSV) — tmux -t <name> can substring-match\n# the wrong session under sparse env.\nMANIFEST=\"$HOME/.sisyphus/sessions-manifest.tsv\"\nif [ ! -f \"$MANIFEST\" ]; then\n tmux display-message \"sisyphus: no manifest — daemon running?\"\n exit 0\nfi\ncurrent_id=$(tmux display-message -p '#{session_id}')\ncurrent_name=$(tmux display-message -p '#{session_name}')\ncwd=\"\"\nwhile IFS=$'\\\\t' read -r type name scwd phase sid; do\n [ \"$sid\" = \"$current_id\" ] && { cwd=\"$scwd\"; break; }\ndone < \"$MANIFEST\"\nif [ -z \"$cwd\" ]; then\n tmux display-message \"sisyphus: '$current_name' has no @sisyphus_cwd — run 'sis start' here to register\"\n exit 0\nfi\nsession_ids=()\nwhile IFS=$'\\\\t' read -r type name scwd phase sid; do\n [[ \"$type\" == \"#\"* ]] && continue\n [ \"$scwd\" = \"$cwd\" ] && session_ids+=(\"$sid\")\ndone < \"$MANIFEST\"\nif (( \\${#session_ids[@]} <= 1 )); then\n tmux display-message \"sisyphus: only one session in $cwd — nothing to cycle to\"\n exit 0\nfi\nfor (( i=0; i<\\${#session_ids[@]}; i++ )); do\n if [ \"\\${session_ids[$i]}\" = \"$current_id\" ]; then\n next=$(( (i + 1) % \\${#session_ids[@]} ))\n tmux switch-client -t \"\\${session_ids[$next]}\"\n exit 0\n fi\ndone\ntmux switch-client -t \"\\${session_ids[0]}\"\n`;\n\n// Live tmux query for the home session + its dashboard window ID.\n// Sets HOME_SESSION and HOME_DWID. Returns 0 on success, 1 if no home found.\n// Optional arg: explicit cwd to look up. If omitted, uses @sisyphus_cwd from\n// the current tmux session, falling back to #{pane_current_path}.\n// Sets HOME_SESSION (tmux $N id) and HOME_DWID for the non-ssyph_ session\n// matching the given cwd. Always targets by $N — tmux -t <name> can\n// substring-match under sparse env.\nconst RESOLVE_HOME = `\nHOME_SESSION=\"\"\nHOME_DWID=\"\"\nresolve_home() {\n local target_cwd=\"$1\"\n local current_id sid sname scwd\n if [ -z \"$target_cwd\" ]; then\n current_id=$(tmux display-message -p '#{session_id}')\n target_cwd=$(tmux show-options -t \"$current_id\" -v @sisyphus_cwd 2>/dev/null)\n [ -z \"$target_cwd\" ] && target_cwd=$(tmux display-message -p '#{pane_current_path}')\n fi\n target_cwd=\"\\${target_cwd%/}\"\n [ -z \"$target_cwd\" ] && return 1\n while IFS=$'\\\\t' read -r sid sname; do\n [ -z \"$sid\" ] && continue\n case \"$sname\" in ssyph_*) continue ;; esac\n scwd=$(tmux show-options -t \"$sid\" -v @sisyphus_cwd 2>/dev/null)\n scwd=\"\\${scwd%/}\"\n if [ \"$scwd\" = \"$target_cwd\" ]; then\n HOME_SESSION=\"$sid\"\n HOME_DWID=$(tmux show-options -t \"$sid\" -v @sisyphus_dashboard 2>/dev/null)\n return 0\n fi\n done < <(tmux list-sessions -F '#{session_id}\t#{session_name}')\n return 1\n}`.trim();\n\nfunction homeScript(): string {\n const tuiPath = join(import.meta.dirname, 'tui.js');\n return `#!/bin/bash\n# Jump to the dashboard window for the home session matching this cwd.\n${RESOLVE_HOME}\nif ! resolve_home; then\n tmux display-message \"No sisyphus dashboard for this cwd\"\n exit 0\nfi\n# Validate dashboard window is still alive; clear if stale\nif [ -n \"$HOME_DWID\" ] && ! tmux list-panes -t \"$HOME_DWID\" >/dev/null 2>&1; then\n HOME_DWID=\"\"\nfi\n# Reconcile: if option is unset/stale, scan home session for an existing TUI window\n# (pane running 'node'). This prevents duplicate dashboards when the option drifts.\nif [ -z \"$HOME_DWID\" ]; then\n HOME_DWID=$(tmux list-windows -t \"$HOME_SESSION\" -F '#{window_id} #{pane_current_command}' 2>/dev/null \\\n | awk '$2==\"node\"{print $1; exit}')\n [ -n \"$HOME_DWID\" ] && tmux set-option -t \"$HOME_SESSION\" @sisyphus_dashboard \"$HOME_DWID\"\nfi\nif [ -z \"$HOME_DWID\" ]; then\n # Reopen dashboard: create window, launch TUI, update option\n home_cwd=$(tmux show-options -t \"$HOME_SESSION\" -v @sisyphus_cwd 2>/dev/null)\n [ -z \"$home_cwd\" ] && { tmux display-message \"Home session has no cwd\"; exit 0; }\n HOME_DWID=$(tmux new-window -t \"$HOME_SESSION:\" -n \"sisyphus-dashboard\" -c \"$home_cwd\" -P -F \"#{window_id}\")\n tmux send-keys -t \"$HOME_DWID\" \"node '${tuiPath}' --cwd '$home_cwd'; exit\" Enter\n tmux set-option -t \"$HOME_SESSION\" @sisyphus_dashboard \"$HOME_DWID\"\nfi\ncurrent_id=$(tmux display-message -p '#{session_id}')\n[ \"$current_id\" != \"$HOME_SESSION\" ] && tmux switch-client -t \"$HOME_SESSION\"\ntmux select-window -t \"$HOME_DWID\"\n`;\n}\n\nconst KILL_PANE_SCRIPT = `#!/bin/bash\n# Smart kill-pane invoked via the sisyphus prefix menu (C-s x).\n# If this is the last pane, switch to the home session before killing.\n${RESOLVE_HOME}\nsession_id=$(tmux display-message -p '#{session_id}')\npane_count=$(tmux list-panes -t \"$session_id\" -F '#{pane_id}' | wc -l | tr -d ' ')\n\nif [ \"$pane_count\" -le 1 ]; then\n if resolve_home; then\n tmux switch-client -t \"$HOME_SESSION\"\n [ -n \"$HOME_DWID\" ] && tmux select-window -t \"$HOME_DWID\"\n tmux kill-session -t \"$session_id\"\n exit 0\n fi\n tmux kill-pane\nelse\n tmux kill-pane\n tmux select-layout even-horizontal\nfi\n`;\n\nconst NEW_PROMPT_SCRIPT = `#!/bin/bash\n# Open nvim to compose a new sisyphus task, then start a session\ntmpfile=$(mktemp /tmp/sisyphus-new-XXXXXX.md)\ntrap 'rm -f \"$tmpfile\"' EXIT\nnvim \"$tmpfile\"\ngrep -q '[^[:space:]]' \"$tmpfile\" || exit 0\nexec sis start \"$(cat \"$tmpfile\")\"\n`;\n\nconst MESSAGE_SCRIPT = `#!/bin/bash\n# Open nvim to compose a message for the current session's orchestrator\n# Resolve session ID: direct tmux option → manifest lookup.\n# All -t targeting uses $N session id — tmux -t <name> can substring-match under sparse env.\ntmux_sid=$(tmux display-message -p '#{session_id}')\nsession_id=$(tmux show-options -t \"$tmux_sid\" -v @sisyphus_session_id 2>/dev/null)\n\nif [ -z \"$session_id\" ]; then\n MANIFEST=\"$HOME/.sisyphus/sessions-manifest.tsv\"\n [ ! -f \"$MANIFEST\" ] && { echo \"No active sessions found\"; sleep 1; exit 1; }\n cwd=\"\"\n while IFS=$'\\\\t' read -r type name scwd phase sid; do\n [ \"$sid\" = \"$tmux_sid\" ] && { cwd=\"$scwd\"; break; }\n done < \"$MANIFEST\"\n [ -z \"$cwd\" ] && { echo \"Session not in manifest\"; sleep 1; exit 1; }\n while IFS=$'\\\\t' read -r type name scwd phase sid; do\n if [ \"$type\" = \"S\" ] && [ \"$scwd\" = \"$cwd\" ]; then\n session_id=$(tmux show-options -t \"$sid\" -v @sisyphus_session_id 2>/dev/null)\n [ -n \"$session_id\" ] && break\n fi\n done < \"$MANIFEST\"\nfi\n\n[ -z \"$session_id\" ] && { echo \"No active sisyphus session found\"; sleep 1; exit 1; }\n\ntmpfile=$(mktemp /tmp/sisyphus-msg-XXXXXX.md)\ntrap 'rm -f \"$tmpfile\"' EXIT\nnvim \"$tmpfile\"\ngrep -q '[^[:space:]]' \"$tmpfile\" || exit 0\nexec sis message --session \"$session_id\" \"$(cat \"$tmpfile\")\"\n`;\n\n// --- Shared session ID + cwd resolution for session-scoped scripts ---\n// All tmux -t targeting uses $N session id — -t <name> can substring-match under sparse env.\nconst SESSION_RESOLVE = `\ntmux_sid=$(tmux display-message -p '#{session_id}')\nsession_id=$(tmux show-options -t \"$tmux_sid\" -v @sisyphus_session_id 2>/dev/null)\ncwd=$(tmux show-options -t \"$tmux_sid\" -v @sisyphus_cwd 2>/dev/null)\n\nif [ -z \"$session_id\" ]; then\n MANIFEST=\"$HOME/.sisyphus/sessions-manifest.tsv\"\n [ ! -f \"$MANIFEST\" ] && { echo \"No active sessions found\"; sleep 1; exit 1; }\n if [ -z \"$cwd\" ]; then\n while IFS=$'\\\\t' read -r type name scwd phase sid; do\n [ \"$sid\" = \"$tmux_sid\" ] && { cwd=\"$scwd\"; break; }\n done < \"$MANIFEST\"\n fi\n [ -z \"$cwd\" ] && { echo \"Session not in manifest\"; sleep 1; exit 1; }\n while IFS=$'\\\\t' read -r type name scwd phase sid; do\n if [ \"$type\" = \"S\" ] && [ \"$scwd\" = \"$cwd\" ]; then\n session_id=$(tmux show-options -t \"$sid\" -v @sisyphus_session_id 2>/dev/null)\n [ -n \"$session_id\" ] && break\n fi\n done < \"$MANIFEST\"\nfi\n\n[ -z \"$session_id\" ] && { echo \"No active sisyphus session found\"; sleep 1; exit 1; }\n[ -z \"$cwd\" ] && cwd=$(tmux display-message -p '#{pane_current_path}')`.trim();\n\n// --- Go-home helper used by kill/delete scripts ---\n// Assumes $cwd was captured before the destructive action ran (via SESSION_RESOLVE).\nconst GO_HOME_AFTER = `\n${RESOLVE_HOME}\nif resolve_home \"$cwd\"; then\n tmux switch-client -t \"$HOME_SESSION\"\n [ -n \"$HOME_DWID\" ] && tmux select-window -t \"$HOME_DWID\"\nfi`.trim();\n\nconst KILL_SESSION_SCRIPT = `#!/bin/bash\n# Kill the sisyphus session associated with the current tmux session\n${SESSION_RESOLVE}\n\nsis session kill \"$session_id\" >/dev/null 2>&1\n${GO_HOME_AFTER}\n`;\n\nconst DELETE_SESSION_SCRIPT = `#!/bin/bash\n# Delete the sisyphus session associated with the current tmux session\n${SESSION_RESOLVE}\n\nprintf \"\\\\033[31mType 'yes' to confirm:\\\\033[0m \"\nread -r answer\n[ \"$answer\" = \"yes\" ] || exit 0\nsis session delete \"$session_id\" --cwd \"$cwd\" >/dev/null 2>&1\n${GO_HOME_AFTER}\n`;\n\nconst HELP_SCRIPT = `#!/bin/bash\ncat <<'EOF_HELP'\n${formatHelpForKeymap(KEYMAP)}\nEOF_HELP\nread -n 1 -s -r -p \" Press any key to close\"\n`;\n\nconst STATUS_POPUP_SCRIPT = `#!/bin/bash\n# Show session status — if no sisyphus session here, list all.\n# -t targeting uses $N session id — -t <name> can substring-match under sparse env.\ntmux_sid=$(tmux display-message -p '#{session_id}')\nsession_id=$(tmux show-options -t \"$tmux_sid\" -v @sisyphus_session_id 2>/dev/null)\n\nif [ -z \"$session_id\" ]; then\n MANIFEST=\"$HOME/.sisyphus/sessions-manifest.tsv\"\n if [ -f \"$MANIFEST\" ]; then\n cwd=\"\"\n while IFS=$'\\\\t' read -r type name scwd phase sid; do\n [ \"$sid\" = \"$tmux_sid\" ] && { cwd=\"$scwd\"; break; }\n done < \"$MANIFEST\"\n if [ -n \"$cwd\" ]; then\n while IFS=$'\\\\t' read -r type name scwd phase sid; do\n if [ \"$type\" = \"S\" ] && [ \"$scwd\" = \"$cwd\" ]; then\n session_id=$(tmux show-options -t \"$sid\" -v @sisyphus_session_id 2>/dev/null)\n [ -n \"$session_id\" ] && break\n fi\n done < \"$MANIFEST\"\n fi\n fi\nfi\n\nif [ -n \"$session_id\" ]; then\n sis status \"$session_id\" 2>&1 | less -R\nelse\n sis list 2>&1 | less -R\nfi\n`;\n\nconst PICK_SESSION_SCRIPT = `#!/bin/bash\n# Session picker — switch to a sisyphus session.\n# switch-client -t targets $N session id — -t <name> can substring-match under sparse env.\nMANIFEST=\"$HOME/.sisyphus/sessions-manifest.tsv\"\n[ ! -f \"$MANIFEST\" ] && { echo \"No sessions found\"; sleep 1; exit 0; }\n\ncurrent_id=$(tmux display-message -p '#{session_id}')\ncwd=\"\"\nwhile IFS=$'\\\\t' read -r type name scwd phase sid; do\n [ \"$sid\" = \"$current_id\" ] && { cwd=\"$scwd\"; break; }\ndone < \"$MANIFEST\"\n\ndeclare -a entries=()\ndeclare -a targets=()\nwhile IFS=$'\\\\t' read -r type name scwd phase sid; do\n [[ \"$type\" == \"#\"* ]] && continue\n [ -n \"$cwd\" ] && [ \"$scwd\" != \"$cwd\" ] && continue\n display=\"$name\"\n if [[ \"$name\" == ssyph_* ]]; then\n display=\"\\${name#ssyph_}\"\n display=\"\\${display#*_}\"\n fi\n [ \"$type\" = \"H\" ] && display=\"~ home\"\n marker=\"\"\n [ \"$sid\" = \"$current_id\" ] && marker=\" *\"\n phase_label=\"\\${phase:-—}\"\n entries+=(\"\\${display} [\\${phase_label}]\\${marker}\")\n targets+=(\"$sid\")\ndone < \"$MANIFEST\"\n\n(( \\${#entries[@]} == 0 )) && { echo \"No sessions found\"; sleep 1; exit 0; }\n\nif command -v fzf &>/dev/null; then\n idx=$(for (( i=0; i<\\${#entries[@]}; i++ )); do echo \"$i \\${entries[$i]}\"; done | \\\\\n fzf --height=100% --reverse --with-nth=2.. --prompt=\"Switch to: \" | awk '{print $1}')\n [ -z \"$idx\" ] && exit 0\n tmux switch-client -t \"\\${targets[$idx]}\"\nelse\n for (( i=0; i<\\${#entries[@]}; i++ )); do\n printf \" %d) %s\\\\n\" $((i+1)) \"\\${entries[$i]}\"\n done\n printf \"\\\\nPick session: \"\n read -r choice\n idx=$((choice - 1))\n (( idx >= 0 && idx < \\${#entries[@]} )) || exit 0\n tmux switch-client -t \"\\${targets[$idx]}\"\nfi\n`;\n\nconst CONTINUE_SESSION_SCRIPT = `#!/bin/bash\n# Continue a completed session\n${SESSION_RESOLVE}\n\nshort_id=\"\\${session_id:0:8}\"\nprintf \"\\\\033[33mContinue session %s...?\\\\033[0m (y/n) \" \"$short_id\"\nread -r answer\n[ \"$answer\" = \"y\" ] || [ \"$answer\" = \"yes\" ] || exit 0\nsis session continue --session \"$session_id\"\nsleep 1\n`;\n\nconst OPEN_ROADMAP_SCRIPT = `#!/bin/bash\n# Open roadmap.md for the current session in nvim\n${SESSION_RESOLVE}\n\nfile=\"$cwd/.sisyphus/sessions/$session_id/roadmap.md\"\n[ ! -f \"$file\" ] && { tmux display-message \"No roadmap.md for this session\"; exit 0; }\nexec nvim \"$file\"\n`;\n\nconst OPEN_STRATEGY_SCRIPT = `#!/bin/bash\n# Open strategy.md for the current session in nvim\n${SESSION_RESOLVE}\n\nfile=\"$cwd/.sisyphus/sessions/$session_id/strategy.md\"\n[ ! -f \"$file\" ] && { tmux display-message \"No strategy.md for this session\"; exit 0; }\nexec nvim \"$file\"\n`;\n\nconst EXPORT_SESSION_SCRIPT = `#!/bin/bash\n# Export session data as zip to ~/Downloads\n${SESSION_RESOLVE}\n\necho \"Exporting session \\${session_id:0:8}...\"\nsis admin export \"$session_id\" --cwd \"$cwd\"\necho \"\"\nread -n 1 -s -r -p \"Press a key to close.\"\n`;\n\nconst RESTART_AGENT_SCRIPT = `#!/bin/bash\n# Pick a sisyphus agent and restart it (fzf picker with confirm for running agents).\n# Assumes macOS (fzf optional). Requires \\`sis status --json\\`.\n${SESSION_RESOLVE}\n\ncommand -v jq &>/dev/null || { echo \"jq required\"; sleep 1; exit 1; }\n\nagents_json=$(sis status \"$session_id\" --json 2>/dev/null)\nif [ -z \"$agents_json\" ]; then\n echo \"Failed to read session status\"; sleep 1; exit 1\nfi\n\ndeclare -a entries=()\ndeclare -a ids=()\ndeclare -a statuses=()\nwhile IFS=$'\\\\t' read -r aid aname atype astatus; do\n [ -z \"$aid\" ] && continue\n entries+=(\"$aid $aname ($atype) — $astatus\")\n ids+=(\"$aid\")\n statuses+=(\"$astatus\")\ndone < <(echo \"$agents_json\" | jq -r '.agents[] | [.id, .name, .agentType, .status] | @tsv')\n\n(( \\${#entries[@]} == 0 )) && { echo \"No agents in session\"; sleep 1; exit 0; }\n\nif command -v fzf &>/dev/null; then\n idx=$(for (( i=0; i<\\${#entries[@]}; i++ )); do echo \"$i \\${entries[$i]}\"; done \\\\\n | fzf --reverse --height=100% --with-nth=2.. --prompt=\"Restart: \" | awk '{print $1}')\n [ -z \"$idx\" ] && exit 0\nelse\n for (( i=0; i<\\${#entries[@]}; i++ )); do\n printf \" %d) %s\\\\n\" $((i+1)) \"\\${entries[$i]}\"\n done\n printf \"\\\\nPick agent: \"\n read -r choice\n idx=$((choice - 1))\n (( idx >= 0 && idx < \\${#entries[@]} )) || exit 0\nfi\n\nif [ \"\\${statuses[$idx]}\" = \"running\" ]; then\n printf \"\\\\033[33mAgent is running. Restart anyway? (yes/no): \\\\033[0m\"\n read -r answer\n [ \"$answer\" = \"yes\" ] || exit 0\nfi\n\nsis agent restart \"\\${ids[$idx]}\" --session \"$session_id\"\necho \"\"\nread -n 1 -s -r -p \"Press a key to close.\"\n`;\n\n// === Stage 2 script constants ===\n\nconst OPEN_GOAL_SCRIPT = `#!/bin/bash\n# Open goal.md for the current session in nvim.\n# Run from a sisyphus session pane, not the home dashboard.\n${SESSION_RESOLVE}\n\nfile=\"$cwd/.sisyphus/sessions/$session_id/goal.md\"\n[ ! -f \"$file\" ] && { tmux display-message \"No goal.md for this session\"; exit 0; }\nexec nvim \"$file\"\n`;\n\nconst OPEN_DIR_SCRIPT = `#!/bin/bash\n# Open session dir in Finder (macOS).\n# macOS-only — Linux/Windows port deferred.\n# Run from a sisyphus session pane, not the home dashboard.\n${SESSION_RESOLVE}\n\ndir=\"$cwd/.sisyphus/sessions/$session_id\"\n[ ! -d \"$dir\" ] && { tmux display-message \"Session dir not found: $dir\"; exit 0; }\nexec open \"$dir\"\n`;\n\nconst OPEN_LOGS_SCRIPT = `#!/bin/bash\n# Tail the newest cycle log for this session in a popup.\n# Run from a sisyphus session pane, not the home dashboard.\n${SESSION_RESOLVE}\n\nsession_dir=\"$cwd/.sisyphus/sessions/$session_id\"\ntarget=$(ls -t \"$session_dir/logs/\"cycle-*.md 2>/dev/null | head -1)\n[ -z \"$target\" ] && { tmux display-message \"No logs for this session yet\"; exit 0; }\nexec tail -n 500 -f \"$target\"\n`;\n\nconst RESUME_SESSION_SCRIPT = `#!/bin/bash\n# Resume a paused/completed session with optional follow-up instructions.\n# Run from a sisyphus session pane, not the home dashboard.\n${SESSION_RESOLVE}\n\nshort_id=\"\\${session_id:0:8}\"\n\n# Optional message — leave empty to resume with no extra instructions.\ntmpfile=$(mktemp /tmp/sisyphus-resume-XXXXXX.md)\ntrap 'rm -f \"$tmpfile\"' EXIT\nprintf \"# Resume session %s\\\\n# (Optional) Add follow-up instructions for the orchestrator below.\\\\n# Save & quit empty to resume with no message.\\\\n\\\\n\" \"$short_id\" > \"$tmpfile\"\nnvim \"$tmpfile\"\n\n# Strip comment + blank lines to detect empty submission\nbody=$(grep -v '^[[:space:]]*#' \"$tmpfile\" | sed '/^[[:space:]]*$/d')\n\nif [ -z \"$body\" ]; then\n exec sis session resume \"$session_id\"\nelse\n exec sis session resume \"$session_id\" \"$body\"\nfi\n`;\n\nconst ROLLBACK_SESSION_SCRIPT = `#!/bin/bash\n# Roll back session to a chosen cycle. Prompts inline.\n# Run from a sisyphus session pane, not the home dashboard.\n${SESSION_RESOLVE}\n\nshort_id=\"\\${session_id:0:8}\"\nprintf \"Rollback %s to cycle: \" \"$short_id\"\nread -r cycle_input\n\n# Validate: positive integer\ncase \"$cycle_input\" in\n ''|*[!0-9]*)\n echo \"Invalid cycle number\"\n read -n 1 -s -r -p \"Press a key to close.\"\n exit 0\n ;;\nesac\n\nif [ \"$cycle_input\" -lt 1 ]; then\n echo \"Cycle must be >= 1\"\n read -n 1 -s -r -p \"Press a key to close.\"\n exit 0\nfi\n\nsis session rollback \"$session_id\" \"$cycle_input\"\necho \"\"\necho \"Rolled back to cycle $cycle_input — use [C-s S r] to resume.\"\nread -n 1 -s -r -p \"Press a key to close.\"\n`;\n\nconst GO_TO_WINDOW_SCRIPT = `#!/bin/bash\n# Switch to the sisyphus session's tmux window. If the window is dead,\n# fall back to opening the orchestrator's last claude --resume in a popup.\n# Run from a sisyphus session pane, not the home dashboard.\n${SESSION_RESOLVE}\n\ncommand -v jq &>/dev/null || { echo \"jq required\"; sleep 1; exit 1; }\n\n# Walk the manifest for the S-row whose tmux session has @sisyphus_session_id == ours.\n# Manifest format: type\\tname\\tcwd\\tphase\\tsessionId\nMANIFEST=\"$HOME/.sisyphus/sessions-manifest.tsv\"\n[ ! -f \"$MANIFEST\" ] && { tmux display-message \"No manifest\"; exit 0; }\n\ntarget_sid=\"\"\nwhile IFS=$'\\\\t' read -r type name scwd phase sid; do\n [[ \"$type\" == \"#\"* ]] && continue\n [ \"$type\" = \"S\" ] || continue\n [ \"$scwd\" = \"$cwd\" ] || continue\n ssid=$(tmux show-options -t \"$sid\" -v @sisyphus_session_id 2>/dev/null)\n if [ \"$ssid\" = \"$session_id\" ]; then\n target_sid=\"$sid\"\n break\n fi\ndone < \"$MANIFEST\"\n\nif [ -n \"$target_sid\" ] && tmux has-session -t \"$target_sid\" 2>/dev/null; then\n tmux switch-client -t \"$target_sid\"\n exit 0\nfi\n\n# Fallback: orchestrator window is gone. Open last claude session in a popup.\nstate=\"$cwd/.sisyphus/sessions/$session_id/state.json\"\n[ ! -f \"$state\" ] && { tmux display-message \"Window dead and no state.json — try sis session resume\"; exit 0; }\n\nclaude_sid=$(jq -r '[.orchestratorCycles[].claudeSessionId] | last // empty' \"$state\")\n\nif [ -z \"$claude_sid\" ]; then\n tmux display-message \"No orchestrator claude session id found — try sis session resume\"\n exit 0\nfi\n\n# Validate before passing to exec — value must be a safe session id.\n[[ \"$claude_sid\" =~ ^[A-Za-z0-9_-]+$ ]] || { tmux display-message \"Invalid claude session id\"; exit 1; }\n\nexec claude --resume \"$claude_sid\"\n`;\n\nconst SPAWN_AGENT_SCRIPT = `#!/bin/bash\n# Compose an instruction for a new agent and spawn it.\n# Run from a sisyphus session pane, not the home dashboard.\n${SESSION_RESOLVE}\n\ntmpfile=$(mktemp /tmp/sisyphus-spawn-XXXXXX.md)\ntrap 'rm -f \"$tmpfile\"' EXIT\nprintf \"# Spawn agent in session %s\\\\n# Write the agent's instruction below. Empty = abort.\\\\n\\\\n\" \"\\${session_id:0:8}\" > \"$tmpfile\"\nnvim \"$tmpfile\"\n\nbody=$(grep -v '^[[:space:]]*#' \"$tmpfile\" | sed '/^[[:space:]]*$/d')\n[ -z \"$body\" ] && exit 0\n\nexec sis agent spawn --session \"$session_id\" --name \"agent\" --instruction \"$body\"\n`;\n\nconst SEARCH_REPORTS_SCRIPT = `#!/bin/bash\n# fzf over reports/*.md across all sessions for the current cwd.\n# Falls back to numbered list if fzf is missing.\n\n# Resolve cwd via tmux option (set by daemon) or fall back.\ntmux_sid=$(tmux display-message -p '#{session_id}')\ncwd=$(tmux show-options -t \"$tmux_sid\" -v @sisyphus_cwd 2>/dev/null)\n[ -z \"$cwd\" ] && cwd=$(tmux display-message -p '#{pane_current_path}')\n\nsessions_dir=\"$cwd/.sisyphus/sessions\"\n[ ! -d \"$sessions_dir\" ] && { tmux display-message \"No sessions in $cwd\"; exit 0; }\n\n# Find all report files. -path filter scopes to */reports/*.md inside any session.\nmapfile -t files < <(find \"$sessions_dir\" -type f -path '*/reports/*.md' 2>/dev/null | sort)\n(( \\${#files[@]} == 0 )) && { tmux display-message \"No reports yet in $cwd\"; exit 0; }\n\nif command -v fzf &>/dev/null; then\n picked=$(printf '%s\\\\n' \"\\${files[@]}\" \\\\\n | sed \"s|$sessions_dir/||\" \\\\\n | fzf --reverse --height=100% --prompt=\"Report: \" \\\\\n --preview 'f={}; cat -- \"'\"$sessions_dir\"'/$f\"' --preview-window=right:60%)\n [ -z \"$picked\" ] && exit 0\n exec nvim \"$sessions_dir/$picked\"\nelse\n for (( i=0; i<\\${#files[@]}; i++ )); do\n rel=\"\\${files[$i]#$sessions_dir/}\"\n printf \" %d) %s\\\\n\" $((i+1)) \"\\${rel}\"\n done\n printf \"\\\\nPick: \"\n read -r choice\n idx=$((choice - 1))\n (( idx >= 0 && idx < \\${#files[@]} )) || exit 0\n exec nvim \"\\${files[$idx]}\"\nfi\n`;\n\n// === end Stage 2 script constants ===\n\n// === Stage 3 script constants ===\n\nconst JUMP_TO_PANE_SCRIPT = `#!/bin/bash\n# Pick a sisyphus agent and jump to its tmux pane.\n# Assumes macOS (pbcopy, fzf optional). Requires \\`sis status --json\\`.\n${SESSION_RESOLVE}\n\ncommand -v jq &>/dev/null || { echo \"jq required\"; sleep 1; exit 1; }\n\nagents_json=$(sis status \"$session_id\" --json 2>/dev/null)\nif [ -z \"$agents_json\" ]; then\n echo \"Failed to read session status\"; sleep 1; exit 1\nfi\n\ndeclare -a entries=()\ndeclare -a ids=()\ndeclare -a panes=()\nwhile IFS=$'\\\\t' read -r aid aname atype astatus pid; do\n [ -z \"$aid\" ] && continue\n entries+=(\"$aid $aname ($atype) — $astatus\")\n ids+=(\"$aid\")\n panes+=(\"$pid\")\ndone < <(echo \"$agents_json\" | jq -r '.agents[] | [.id, .name, .agentType, .status, .paneId] | @tsv')\n\n(( \\${#entries[@]} == 0 )) && { echo \"No agents in session\"; sleep 1; exit 0; }\n\nif command -v fzf &>/dev/null; then\n idx=$(for (( i=0; i<\\${#entries[@]}; i++ )); do echo \"$i \\${entries[$i]}\"; done \\\\\n | fzf --reverse --height=100% --with-nth=2.. --prompt=\"Jump to: \" | awk '{print $1}')\n [ -z \"$idx\" ] && exit 0\nelse\n for (( i=0; i<\\${#entries[@]}; i++ )); do\n printf \" %d) %s\\\\n\" $((i+1)) \"\\${entries[$i]}\"\n done\n printf \"\\\\nPick agent: \"\n read -r choice\n idx=$((choice - 1))\n (( idx >= 0 && idx < \\${#entries[@]} )) || exit 0\nfi\n\ntarget_pane=\"\\${panes[$idx]}\"\n[ -z \"$target_pane\" ] && { echo \"Agent has no active pane\"; sleep 1; exit 1; }\ntarget_session=$(tmux display-message -p -t \"$target_pane\" '#{session_id}' 2>/dev/null)\ntarget_window=$(tmux display-message -p -t \"$target_pane\" '#{window_id}' 2>/dev/null)\n[ -n \"$target_session\" ] && tmux switch-client -t \"$target_session\"\n[ -n \"$target_window\" ] && tmux select-window -t \"$target_window\"\ntmux select-pane -t \"$target_pane\"\n`;\n\nconst MSG_AGENT_SCRIPT = `#!/bin/bash\n# Pick a sisyphus agent and send it a message via nvim.\n# Assumes macOS (fzf optional). Requires \\`sis status --json\\` and \\`--agent\\` on message.\n${SESSION_RESOLVE}\n\ncommand -v jq &>/dev/null || { echo \"jq required\"; sleep 1; exit 1; }\n\nagents_json=$(sis status \"$session_id\" --json 2>/dev/null)\nif [ -z \"$agents_json\" ]; then\n echo \"Failed to read session status\"; sleep 1; exit 1\nfi\n\ndeclare -a entries=()\ndeclare -a ids=()\nwhile IFS=$'\\\\t' read -r aid aname atype astatus; do\n [ -z \"$aid\" ] && continue\n entries+=(\"$aid $aname ($atype) — $astatus\")\n ids+=(\"$aid\")\ndone < <(echo \"$agents_json\" | jq -r '.agents[] | [.id, .name, .agentType, .status] | @tsv')\n\n(( \\${#entries[@]} == 0 )) && { echo \"No agents in session\"; sleep 1; exit 0; }\n\nif command -v fzf &>/dev/null; then\n idx=$(for (( i=0; i<\\${#entries[@]}; i++ )); do echo \"$i \\${entries[$i]}\"; done \\\\\n | fzf --reverse --height=100% --with-nth=2.. --prompt=\"Message agent: \" | awk '{print $1}')\n [ -z \"$idx\" ] && exit 0\nelse\n for (( i=0; i<\\${#entries[@]}; i++ )); do\n printf \" %d) %s\\\\n\" $((i+1)) \"\\${entries[$i]}\"\n done\n printf \"\\\\nPick agent: \"\n read -r choice\n idx=$((choice - 1))\n (( idx >= 0 && idx < \\${#entries[@]} )) || exit 0\nfi\n\ntmpfile=$(mktemp /tmp/sisyphus-msg-agent-XXXX.md)\ntrap 'rm -f \"$tmpfile\"' EXIT\nnvim \"$tmpfile\"\ngrep -q '[^[:space:]]' \"$tmpfile\" || exit 0\nexec sis message --session \"$session_id\" --agent \"\\${ids[$idx]}\" \"$(cat \"$tmpfile\")\"\n`;\n\nconst RERUN_AGENT_SCRIPT = `#!/bin/bash\n# Pick a sisyphus agent and spawn a retry with its original instruction.\n# Assumes macOS (fzf optional). Requires \\`sis status --json\\`.\n${SESSION_RESOLVE}\n\ncommand -v jq &>/dev/null || { echo \"jq required\"; sleep 1; exit 1; }\n\nagents_json=$(sis status \"$session_id\" --json 2>/dev/null)\nif [ -z \"$agents_json\" ]; then\n echo \"Failed to read session status\"; sleep 1; exit 1\nfi\n\ndeclare -a entries=()\ndeclare -a ids=()\ndeclare -a atypes=()\ndeclare -a anames=()\ndeclare -a instrs=()\nwhile IFS=$'\\\\t' read -r aid aname atype astatus ainstr_b64; do\n [ -z \"$aid\" ] && continue\n entries+=(\"$aid $aname ($atype) — $astatus\")\n ids+=(\"$aid\")\n atypes+=(\"$atype\")\n anames+=(\"$aname\")\n instrs+=(\"$(echo \"$ainstr_b64\" | base64 -d)\")\ndone < <(echo \"$agents_json\" | jq -r '.agents[] | [.id, .name, .agentType, .status, (.instruction // \"\" | @base64)] | @tsv')\n\n(( \\${#entries[@]} == 0 )) && { echo \"No agents in session\"; sleep 1; exit 0; }\n\nif command -v fzf &>/dev/null; then\n idx=$(for (( i=0; i<\\${#entries[@]}; i++ )); do echo \"$i \\${entries[$i]}\"; done \\\\\n | fzf --reverse --height=100% --with-nth=2.. --prompt=\"Rerun: \" | awk '{print $1}')\n [ -z \"$idx\" ] && exit 0\nelse\n for (( i=0; i<\\${#entries[@]}; i++ )); do\n printf \" %d) %s\\\\n\" $((i+1)) \"\\${entries[$i]}\"\n done\n printf \"\\\\nPick agent: \"\n read -r choice\n idx=$((choice - 1))\n (( idx >= 0 && idx < \\${#entries[@]} )) || exit 0\nfi\n\ninstr=\"\\${instrs[$idx]}\"\nif [ \"\\${#instr}\" -lt 20 ]; then\n echo \"Original instruction is shorter than 20 chars — cannot rerun safely.\"\n read -n 1 -s -r -p \"Press a key to close.\"\n exit 1\nfi\n\nexec sis agent spawn --session \"$session_id\" --agent-type \"\\${atypes[$idx]}\" --name \"\\${anames[$idx]}-retry-$(date +%s)\" --instruction \"$instr\"\n`;\n\nconst OPEN_CLAUDE_AGENT_SCRIPT = `#!/bin/bash\n# Pick a sisyphus agent or orchestrator cycle and resume its Claude session.\n# Assumes macOS (fzf optional). Requires \\`sis status --json\\`.\n${SESSION_RESOLVE}\n\ncommand -v jq &>/dev/null || { echo \"jq required\"; sleep 1; exit 1; }\n\nstate=\"$cwd/.sisyphus/sessions/$session_id/state.json\"\n[ ! -f \"$state\" ] && { echo \"No state.json for this session\"; sleep 1; exit 1; }\n\nagents_json=$(sis status \"$session_id\" --json 2>/dev/null)\nif [ -z \"$agents_json\" ]; then\n echo \"Failed to read session status\"; sleep 1; exit 1\nfi\n\ndeclare -a entries=()\ndeclare -a claudes=()\nwhile IFS=$'\\\\t' read -r rid rname rtype rcid; do\n [ -z \"$rid\" ] && continue\n entries+=(\"$rid $rname ($rtype)\")\n claudes+=(\"$rcid\")\ndone < <(echo \"$agents_json\" | jq -r '\n ((.agents // [])[] | [.id, .name, .agentType, (.claudeSessionId // \"\")] | @tsv),\n ((.orchestratorCycles // [])[] | [\"cycle-\" + (.cycle|tostring), \"orchestrator\", \"cycle\", (.claudeSessionId // \"\")] | @tsv)\n')\n\n(( \\${#entries[@]} == 0 )) && { echo \"No agents or cycles in session\"; sleep 1; exit 0; }\n\nif command -v fzf &>/dev/null; then\n idx=$(for (( i=0; i<\\${#entries[@]}; i++ )); do echo \"$i \\${entries[$i]}\"; done \\\\\n | fzf --reverse --height=100% --with-nth=2.. --prompt=\"Open Claude: \" | awk '{print $1}')\n [ -z \"$idx\" ] && exit 0\nelse\n for (( i=0; i<\\${#entries[@]}; i++ )); do\n printf \" %d) %s\\\\n\" $((i+1)) \"\\${entries[$i]}\"\n done\n printf \"\\\\nPick: \"\n read -r choice\n idx=$((choice - 1))\n (( idx >= 0 && idx < \\${#entries[@]} )) || exit 0\nfi\n\ncid=\"\\${claudes[$idx]}\"\n[ -z \"$cid\" ] && { echo \"No Claude session\"; sleep 1; exit 1; }\n[[ \"$cid\" =~ ^[A-Za-z0-9_-]+$ ]] || { echo \"Invalid claude session id\"; sleep 1; exit 1; }\ncd \"$cwd\" && exec claude --resume \"$cid\"\n`;\n\nconst TAIL_AGENT_LOGS_SCRIPT = `#!/bin/bash\n# Pick a sisyphus agent and view its tmux pane scrollback (last 2000 lines) in less.\n# Uses tmux capture-pane — no tail -f, no pipe-pane side effects.\n# Assumes macOS (fzf optional). Requires \\`sis status --json\\`.\n${SESSION_RESOLVE}\n\ncommand -v jq &>/dev/null || { echo \"jq required\"; sleep 1; exit 1; }\n\nagents_json=$(sis status \"$session_id\" --json 2>/dev/null)\nif [ -z \"$agents_json\" ]; then\n echo \"Failed to read session status\"; sleep 1; exit 1\nfi\n\ndeclare -a entries=()\ndeclare -a ids=()\ndeclare -a panes=()\nwhile IFS=$'\\\\t' read -r aid aname atype astatus pid; do\n [ -z \"$aid\" ] && continue\n entries+=(\"$aid $aname ($atype) — $astatus\")\n ids+=(\"$aid\")\n panes+=(\"$pid\")\ndone < <(echo \"$agents_json\" | jq -r '.agents[] | [.id, .name, .agentType, .status, .paneId] | @tsv')\n\n(( \\${#entries[@]} == 0 )) && { echo \"No agents in session\"; sleep 1; exit 0; }\n\nif command -v fzf &>/dev/null; then\n idx=$(for (( i=0; i<\\${#entries[@]}; i++ )); do echo \"$i \\${entries[$i]}\"; done \\\\\n | fzf --reverse --height=100% --with-nth=2.. --prompt=\"Tail logs: \" | awk '{print $1}')\n [ -z \"$idx\" ] && exit 0\nelse\n for (( i=0; i<\\${#entries[@]}; i++ )); do\n printf \" %d) %s\\\\n\" $((i+1)) \"\\${entries[$i]}\"\n done\n printf \"\\\\nPick agent: \"\n read -r choice\n idx=$((choice - 1))\n (( idx >= 0 && idx < \\${#entries[@]} )) || exit 0\nfi\n\ntarget_pane=\"\\${panes[$idx]}\"\n[ -z \"$target_pane\" ] && { echo \"Agent has no active pane\"; sleep 1; exit 1; }\ntmux capture-pane -t \"$target_pane\" -p -S -2000 | less +G\n`;\n\nconst KILL_AGENT_SCRIPT = `#!/bin/bash\n# Pick a sisyphus agent and kill it (with red confirmation prompt).\n# Assumes macOS (fzf optional). Requires \\`sis status --json\\` and \\`sis agent kill\\`.\n${SESSION_RESOLVE}\n\ncommand -v jq &>/dev/null || { echo \"jq required\"; sleep 1; exit 1; }\n\nagents_json=$(sis status \"$session_id\" --json 2>/dev/null)\nif [ -z \"$agents_json\" ]; then\n echo \"Failed to read session status\"; sleep 1; exit 1\nfi\n\ndeclare -a entries=()\ndeclare -a ids=()\nwhile IFS=$'\\\\t' read -r aid aname atype astatus; do\n [ -z \"$aid\" ] && continue\n entries+=(\"$aid $aname ($atype) — $astatus\")\n ids+=(\"$aid\")\ndone < <(echo \"$agents_json\" | jq -r '.agents[] | [.id, .name, .agentType, .status] | @tsv')\n\n(( \\${#entries[@]} == 0 )) && { echo \"No agents in session\"; sleep 1; exit 0; }\n\nif command -v fzf &>/dev/null; then\n idx=$(for (( i=0; i<\\${#entries[@]}; i++ )); do echo \"$i \\${entries[$i]}\"; done \\\\\n | fzf --reverse --height=100% --with-nth=2.. --prompt=\"Kill agent: \" | awk '{print $1}')\n [ -z \"$idx\" ] && exit 0\nelse\n for (( i=0; i<\\${#entries[@]}; i++ )); do\n printf \" %d) %s\\\\n\" $((i+1)) \"\\${entries[$i]}\"\n done\n printf \"\\\\nPick agent: \"\n read -r choice\n idx=$((choice - 1))\n (( idx >= 0 && idx < \\${#entries[@]} )) || exit 0\nfi\n\nprintf '\\\\033[31mKill %s? (yes/no): \\\\033[0m' \"\\${ids[$idx]}\"\nread -r answer\n[ \"$answer\" = \"yes\" ] || exit 0\nsis agent kill \"\\${ids[$idx]}\" --session \"$session_id\"\necho \"\"\nread -n 1 -s -r -p \"Press a key to close.\"\n`;\n\nconst COPY_AGENT_ID_SCRIPT = `#!/bin/bash\n# Pick a sisyphus agent and copy its ID to clipboard.\n# Assumes macOS (pbcopy, fzf optional). Requires \\`sis status --json\\`.\n${SESSION_RESOLVE}\n\ncommand -v jq &>/dev/null || { echo \"jq required\"; sleep 1; exit 1; }\n\nagents_json=$(sis status \"$session_id\" --json 2>/dev/null)\nif [ -z \"$agents_json\" ]; then\n echo \"Failed to read session status\"; sleep 1; exit 1\nfi\n\ndeclare -a entries=()\ndeclare -a ids=()\nwhile IFS=$'\\\\t' read -r aid aname atype astatus; do\n [ -z \"$aid\" ] && continue\n entries+=(\"$aid $aname ($atype) — $astatus\")\n ids+=(\"$aid\")\ndone < <(echo \"$agents_json\" | jq -r '.agents[] | [.id, .name, .agentType, .status] | @tsv')\n\n(( \\${#entries[@]} == 0 )) && { echo \"No agents in session\"; sleep 1; exit 0; }\n\nif command -v fzf &>/dev/null; then\n idx=$(for (( i=0; i<\\${#entries[@]}; i++ )); do echo \"$i \\${entries[$i]}\"; done \\\\\n | fzf --reverse --height=100% --with-nth=2.. --prompt=\"Copy agent ID: \" | awk '{print $1}')\n [ -z \"$idx\" ] && exit 0\nelse\n for (( i=0; i<\\${#entries[@]}; i++ )); do\n printf \" %d) %s\\\\n\" $((i+1)) \"\\${entries[$i]}\"\n done\n printf \"\\\\nPick agent: \"\n read -r choice\n idx=$((choice - 1))\n (( idx >= 0 && idx < \\${#entries[@]} )) || exit 0\nfi\n\naid=\"\\${ids[$idx]}\"\nprintf '%s' \"$aid\" | pbcopy\ntmux display-message \"Copied $aid\"\n`;\n\nconst COPY_LOGS_SCRIPT = `#!/bin/bash\n# Copy last 200 lines of the newest cycle log to clipboard.\n# Assumes macOS (pbcopy).\n${SESSION_RESOLVE}\n\ndir=\"$cwd/.sisyphus/sessions/$session_id/logs\"\n[ -d \"$dir\" ] || { tmux display-message \"No logs dir\"; exit 0; }\nlatest=$(ls -t \"$dir\"/cycle-*.md 2>/dev/null | head -1)\n[ -z \"$latest\" ] && { tmux display-message \"No cycle logs yet\"; exit 0; }\ntail -n 200 \"$latest\" | pbcopy\ntmux display-message \"Copied last 200 lines of $(basename \"$latest\")\"\n`;\n\nconst COPY_LATEST_REPORT_SCRIPT = `#!/bin/bash\n# Copy the newest report file to clipboard.\n# Assumes macOS (pbcopy).\n${SESSION_RESOLVE}\n\ndir=\"$cwd/.sisyphus/sessions/$session_id/reports\"\n[ -d \"$dir\" ] || { tmux display-message \"No reports dir\"; exit 0; }\nlatest=$(ls -t \"$dir\" 2>/dev/null | head -1)\n[ -z \"$latest\" ] && { tmux display-message \"No reports yet\"; exit 0; }\ncat \"$dir/$latest\" | pbcopy\ntmux display-message \"Copied $latest\"\n`;\n\nconst COPY_PATH_SCRIPT = `#!/bin/bash\n# Copy the session directory path to clipboard.\n# Assumes macOS (pbcopy).\n${SESSION_RESOLVE}\n\nprintf '%s' \"$cwd/.sisyphus/sessions/$session_id\" | pbcopy\ntmux display-message \"Copied session path\"\n`;\n\nconst COPY_ID_SCRIPT = `#!/bin/bash\n# Copy the session ID to clipboard.\n# Assumes macOS (pbcopy).\n${SESSION_RESOLVE}\n\nprintf '%s' \"$session_id\" | pbcopy\ntmux display-message \"Copied session ID\"\n`;\n\nconst COPY_CONTEXT_SCRIPT = `#!/bin/bash\n# Copy the session context XML to clipboard.\n# Assumes macOS (pbcopy). Requires \\`sis session context\\`.\n${SESSION_RESOLVE}\n\nsis session context \"$session_id\" --cwd \"$cwd\" | pbcopy\ntmux display-message \"Copied session context (XML)\"\n`;\n\nconst EDIT_CONTEXT_FILE_SCRIPT = `#!/bin/bash\n# Pick a context file for the current session and open it in nvim.\n# Excludes archive/ subdirectory. Assumes macOS (fzf optional).\n${SESSION_RESOLVE}\n\nctx_dir=\"$cwd/.sisyphus/sessions/$session_id/context\"\n[ -d \"$ctx_dir\" ] || { echo \"No context dir for this session\"; read -n 1 -s -r -p \"Press a key to close.\"; exit 0; }\n\nmapfile -t files < <(find \"$ctx_dir\" -type f -not -path '*/archive/*' | sort)\n(( \\${#files[@]} == 0 )) && { echo \"No context files yet\"; read -n 1 -s -r -p \"Press a key to close.\"; exit 0; }\n\nif command -v fzf &>/dev/null; then\n picked=$(printf '%s\\\\n' \"\\${files[@]}\" | sed \"s|$ctx_dir/||\" \\\\\n | fzf --reverse --height=100% --prompt=\"Context file: \")\n [ -z \"$picked\" ] && exit 0\nelse\n declare -a display_files=()\n for f in \"\\${files[@]}\"; do\n display_files+=(\"\\${f#$ctx_dir/}\")\n done\n for (( i=0; i<\\${#display_files[@]}; i++ )); do\n printf \" %d) %s\\\\n\" $((i+1)) \"\\${display_files[$i]}\"\n done\n printf \"\\\\nPick file: \"\n read -r choice\n idx=$((choice - 1))\n (( idx >= 0 && idx < \\${#display_files[@]} )) || exit 0\n picked=\"\\${display_files[$idx]}\"\nfi\n\nfile=\"$ctx_dir/$picked\"\nexec nvim \"$file\"\n`;\n\n// === end Stage 3 script constants ===\n\n// === Stage 4 script constants ===\n\nconst QUICK_SPAWN_EXPLORE_SCRIPT = `#!/bin/bash\n# Spawn an Explore agent with the macOS clipboard contents as the instruction.\n# macOS only — pbpaste hard dependency.\n${SESSION_RESOLVE}\n\nif ! command -v pbpaste >/dev/null 2>&1; then\n echo \"pbpaste not found — macOS only for now\"\n read -n 1 -s -r -p \"Press a key to close.\"\n exit 1\nfi\n\ninstruction=$(pbpaste)\nif [ -z \"\\${instruction// }\" ]; then\n echo \"Clipboard is empty — copy a task description first\"\n read -n 1 -s -r -p \"Press a key to close.\"\n exit 1\nfi\n\nif [ \"\\${#instruction}\" -lt 20 ]; then\n echo \"Clipboard text too short (\\${#instruction} chars; spawn requires 20+)\"\n read -n 1 -s -r -p \"Press a key to close.\"\n exit 1\nfi\n\nname=\"explore-$(date +%s)\"\nsis agent spawn \\\\\n --agent-type sisyphus:explore \\\\\n --name \"$name\" \\\\\n --session \"$session_id\" \\\\\n --instruction \"$instruction\"\nexit_code=$?\n[ $exit_code -ne 0 ] && read -n 1 -s -r -p \"Press a key to close.\"\nexit $exit_code\n`;\n\nconst QUICK_SPAWN_DEBUG_SCRIPT = `#!/bin/bash\n# Spawn a Debug agent with the macOS clipboard contents as the instruction.\n# macOS only — pbpaste hard dependency.\n${SESSION_RESOLVE}\n\nif ! command -v pbpaste >/dev/null 2>&1; then\n echo \"pbpaste not found — macOS only for now\"\n read -n 1 -s -r -p \"Press a key to close.\"\n exit 1\nfi\n\ninstruction=$(pbpaste)\nif [ -z \"\\${instruction// }\" ]; then\n echo \"Clipboard is empty — copy a task description first\"\n read -n 1 -s -r -p \"Press a key to close.\"\n exit 1\nfi\n\nif [ \"\\${#instruction}\" -lt 20 ]; then\n echo \"Clipboard text too short (\\${#instruction} chars; spawn requires 20+)\"\n read -n 1 -s -r -p \"Press a key to close.\"\n exit 1\nfi\n\nname=\"debug-$(date +%s)\"\nsis agent spawn \\\\\n --agent-type sisyphus:debug \\\\\n --name \"$name\" \\\\\n --session \"$session_id\" \\\\\n --instruction \"$instruction\"\nexit_code=$?\n[ $exit_code -ne 0 ] && read -n 1 -s -r -p \"Press a key to close.\"\nexit $exit_code\n`;\n\nconst OPEN_LATEST_REPORT_SCRIPT = `#!/bin/bash\n# Open the most-recently-modified file in the current session's reports/ in nvim.\n${SESSION_RESOLVE}\n\nreports_dir=\"$cwd/.sisyphus/sessions/$session_id/reports\"\nif [ ! -d \"$reports_dir\" ]; then\n echo \"No reports/ directory for this session\"\n read -n 1 -s -r -p \"Press a key to close.\"\n exit 0\nfi\n\nlatest=$(ls -t \"$reports_dir\"/*.md 2>/dev/null | head -1)\nif [ -z \"$latest\" ]; then\n echo \"No reports yet\"\n read -n 1 -s -r -p \"Press a key to close.\"\n exit 0\nfi\n\nexec nvim \"$latest\"\n`;\n\nconst CLONE_SESSION_SCRIPT = `#!/bin/bash\n# Clone the current session into a new independent session.\n# Orchestrator-only — the underlying CLI rejects calls from other panes/agents.\n${SESSION_RESOLVE}\n\nprintf \"Goal for cloned session: \"\nread -e goal\n[ -z \"\\${goal// }\" ] && exit 0\n\nprintf \"Optional name (blank to skip): \"\nread -e clone_name\n\nprintf \"Copy strategy.md? (y/N): \"\nread -r copy_strategy\n\nargs=()\n[ -n \"$clone_name\" ] && args+=(--name \"$clone_name\")\n[ \"$copy_strategy\" = \"y\" ] || [ \"$copy_strategy\" = \"Y\" ] && args+=(--strategy)\n\nsis session clone \"\\${args[@]}\" \"$goal\"\nexit_code=$?\nread -n 1 -s -r -p \"Press a key to close.\"\nexit $exit_code\n`;\n\nconst HISTORY_SCRIPT = `#!/bin/bash\n# Show rich session detail (history command's per-session view) in a popup.\n${SESSION_RESOLVE}\nsis admin history \"$session_id\" 2>&1 | less -R\n`;\n\nconst RECONNECT_SCRIPT = `#!/bin/bash\n# Reconnect daemon to an orphaned tmux session for the current cwd.\n${SESSION_RESOLVE}\nsis session reconnect \"$session_id\"\nexit_code=$?\nread -n 1 -s -r -p \"Press a key to close.\"\nexit $exit_code\n`;\n\nconst OPEN_SCRATCH_SCRIPT = `#!/bin/bash\n# Open a standalone Claude scratch window in the home tmux session for this cwd.\n# scratch resolves the home session itself via @sisyphus_cwd; no session_id needed.\nexec sis admin scratch\n`;\n\n// === end Stage 4 script constants ===\n\nfunction installScript(name: string, content: string): void {\n mkdirSync(join(globalDir(), 'bin'), { recursive: true });\n const path = scriptPath(name);\n writeFileSync(path, content, 'utf8');\n chmodSync(path, 0o755);\n}\n\nfunction installAllScripts(): void {\n // Existing scripts with real content\n installScript('sisyphus-cycle', CYCLE_SCRIPT);\n installScript('sisyphus-home', homeScript());\n installScript('sisyphus-kill-pane', KILL_PANE_SCRIPT);\n installScript('sisyphus-new', NEW_PROMPT_SCRIPT);\n installScript('sisyphus-msg', MESSAGE_SCRIPT);\n installScript('sisyphus-kill-session', KILL_SESSION_SCRIPT);\n installScript('sisyphus-delete-session', DELETE_SESSION_SCRIPT);\n installScript('sisyphus-status-popup', STATUS_POPUP_SCRIPT);\n installScript('sisyphus-pick-session', PICK_SESSION_SCRIPT);\n installScript('sisyphus-continue-session', CONTINUE_SESSION_SCRIPT);\n installScript('sisyphus-restart-agent-popup', RESTART_AGENT_SCRIPT);\n installScript('sisyphus-open-roadmap', OPEN_ROADMAP_SCRIPT);\n installScript('sisyphus-open-strategy', OPEN_STRATEGY_SCRIPT);\n installScript('sisyphus-export-session', EXPORT_SESSION_SCRIPT);\n\n // === Stage 1 (descriptor + generator + stub installs) ===\n const scriptsDir = join(globalDir(), 'bin');\n\n // Submenu dispatch scripts — one per submenu, generated from descriptor\n for (const [id, def] of Object.entries(KEYMAP.submenus)) {\n installScript(`sisyphus-menu-${id}`, generateSubmenuScript(id, def, scriptsDir));\n }\n // === end Stage 1 ===\n\n // === Stage 2 (tmux submenu scripts) ===\n installScript('sisyphus-open-goal', OPEN_GOAL_SCRIPT);\n installScript('sisyphus-open-dir', OPEN_DIR_SCRIPT);\n installScript('sisyphus-open-logs', OPEN_LOGS_SCRIPT);\n installScript('sisyphus-resume-session', RESUME_SESSION_SCRIPT);\n installScript('sisyphus-rollback-session', ROLLBACK_SESSION_SCRIPT);\n installScript('sisyphus-go-to-window', GO_TO_WINDOW_SCRIPT);\n installScript('sisyphus-spawn-agent', SPAWN_AGENT_SCRIPT);\n installScript('sisyphus-search-reports', SEARCH_REPORTS_SCRIPT);\n // === end Stage 2 ===\n\n // === Stage 3 (cursor pickers) ===\n installScript('sisyphus-jump-to-pane', JUMP_TO_PANE_SCRIPT);\n installScript('sisyphus-msg-agent', MSG_AGENT_SCRIPT);\n installScript('sisyphus-rerun-agent', RERUN_AGENT_SCRIPT);\n installScript('sisyphus-open-claude-agent', OPEN_CLAUDE_AGENT_SCRIPT);\n installScript('sisyphus-tail-agent-logs', TAIL_AGENT_LOGS_SCRIPT);\n installScript('sisyphus-kill-agent', KILL_AGENT_SCRIPT);\n installScript('sisyphus-copy-agent-id', COPY_AGENT_ID_SCRIPT);\n installScript('sisyphus-copy-logs', COPY_LOGS_SCRIPT);\n installScript('sisyphus-copy-latest-report', COPY_LATEST_REPORT_SCRIPT);\n installScript('sisyphus-copy-path', COPY_PATH_SCRIPT);\n installScript('sisyphus-copy-id', COPY_ID_SCRIPT);\n installScript('sisyphus-copy-context', COPY_CONTEXT_SCRIPT);\n installScript('sisyphus-edit-context-file', EDIT_CONTEXT_FILE_SCRIPT);\n // === end Stage 3 ===\n\n // === Stage 4 (creative additions) ===\n installScript('sisyphus-quick-spawn-explore', QUICK_SPAWN_EXPLORE_SCRIPT);\n installScript('sisyphus-quick-spawn-debug', QUICK_SPAWN_DEBUG_SCRIPT);\n installScript('sisyphus-open-latest-report', OPEN_LATEST_REPORT_SCRIPT);\n installScript('sisyphus-clone-session', CLONE_SESSION_SCRIPT);\n installScript('sisyphus-history', HISTORY_SCRIPT);\n installScript('sisyphus-reconnect', RECONNECT_SCRIPT);\n installScript('sisyphus-open-scratch', OPEN_SCRATCH_SCRIPT);\n // === end Stage 4 ===\n\n // === Stage 6 (help script override) ===\n installScript('sisyphus-help', HELP_SCRIPT);\n // === end Stage 6 ===\n}\n\nexport function getExistingBinding(key: string, table: string = 'root'): string | null {\n try {\n const output = execSync(`tmux list-keys -T ${table}`, { stdio: ['pipe', 'pipe', 'pipe'] }).toString();\n for (const line of output.split('\\n')) {\n if (line.includes(key)) {\n const parts = line.trim().split(/\\s+/);\n const keyIdx = parts.indexOf(key);\n if (keyIdx !== -1) {\n return line.trim();\n }\n }\n }\n return null;\n } catch {\n return null;\n }\n}\n\nexport function isSisyphusBinding(binding: string): boolean {\n return binding.includes('sisyphus');\n}\n\nexport type SetupResult =\n | { status: 'installed'; message: string }\n | { status: 'already-installed'; message: string }\n | { status: 'conflict'; message: string; existingBinding: string }\n | { status: 'unsupported-tmux'; message: string }\n | { status: 'conf-modification-declined'; message: string; manualLine: string; userConf: string };\n\nexport interface SetupOptions {\n /** Skip the confirmation prompt before appending to the user's tmux.conf. */\n assumeYes?: boolean;\n}\n\nasync function confirmConfAppend(userConf: string, line: string): Promise<boolean> {\n // Don't block scripted/non-TTY callers; they can opt in with assumeYes.\n if (!process.stdin.isTTY || !process.stdout.isTTY) return false;\n\n const rl = createInterface({ input: process.stdin, output: process.stdout });\n return new Promise((resolve) => {\n const question =\n `\\nSisyphus needs to append one line to ${userConf} so its tmux keybindings persist:\\n` +\n ` ${line}\\n\\n` +\n `Append it now? (y/N) `;\n rl.question(question, (answer) => {\n rl.close();\n resolve(answer.trim().toLowerCase() === 'y');\n });\n });\n}\n\nexport async function setupTmuxKeybind(\n cycleKey: string = DEFAULT_CYCLE_KEY,\n prefixKey: string = DEFAULT_PREFIX_KEY,\n opts: SetupOptions = {},\n): Promise<SetupResult> {\n installAllScripts();\n\n // Version check — hard requirement for display-menu flags used\n if (!tmuxVersionAtLeast(3, 2)) {\n let version = 'unknown';\n try { version = execSync('tmux -V', { stdio: ['pipe', 'pipe', 'pipe'] }).toString().trim(); } catch {}\n return {\n status: 'unsupported-tmux',\n message: `tmux 3.2+ required for sisyphus keybindings; got ${version}`,\n };\n }\n\n // Check for existing bindings before writing anything\n for (const [label, key] of [['cycle', cycleKey], ['prefix', prefixKey]] as const) {\n const existing = getExistingBinding(key);\n if (existing !== null && !isSisyphusBinding(existing)) {\n return {\n status: 'conflict',\n message: `Tmux key ${key} (${label}) is already bound to something else. Run \"sis admin setup-keybind <key>\" to use a different key.`,\n existingBinding: existing,\n };\n }\n }\n\n writeKeymapJson();\n\n const scriptsDir = join(globalDir(), 'bin');\n const bindings = [\n // C-s → display-menu top-level (descriptor-driven)\n generateTopLevelBinding(prefixKey, KEYMAP.topLevel, scriptsDir),\n // M-s → cycle (unchanged)\n `bind-key -T root ${cycleKey} run-shell ${cycleScriptPath()}`,\n // smart-kill is reachable via the sisyphus prefix menu (C-s x) — see KEYMAP.topLevel.\n // We deliberately don't override `prefix x` so users keep their default tmux kill-pane.\n ];\n\n const confPath = sisyphusTmuxConfPath();\n writeFileSync(confPath, `${SISYPHUS_CONF_MARKER}\\n${bindings.join('\\n')}\\n`, 'utf8');\n\n // Append source line to tmux.conf if not already there\n const userConf = userTmuxConfPath();\n const markedSourceLine = `source-file ${confPath} ${SISYPHUS_CONF_MARKER}`;\n let persistedToConf = false;\n let appendDeclined = false;\n\n if (userConf !== null) {\n const contents = readFileSync(userConf, 'utf8');\n if (contents.includes(confPath)) {\n persistedToConf = true;\n } else {\n const shouldAppend = opts.assumeYes\n ? true\n : await confirmConfAppend(userConf, markedSourceLine);\n if (shouldAppend) {\n const separator = contents.endsWith('\\n') ? '' : '\\n';\n writeFileSync(userConf, `${contents}${separator}${markedSourceLine}\\n`, 'utf8');\n persistedToConf = true;\n } else {\n appendDeclined = true;\n }\n }\n }\n\n // Apply bindings live\n try {\n for (const b of bindings) {\n execSync(`tmux ${b}`, { stdio: 'pipe' });\n }\n } catch {\n // tmux not running\n }\n\n if (appendDeclined && userConf !== null) {\n return {\n status: 'conf-modification-declined',\n message:\n `Tmux keybindings applied to the live session, but not persisted.\\n` +\n `To persist them, add this line to ${userConf}:\\n ${markedSourceLine}`,\n manualLine: markedSourceLine,\n userConf,\n };\n }\n\n if (getExistingBinding(cycleKey) !== null && isSisyphusBinding(getExistingBinding(cycleKey)!)) {\n return {\n status: 'already-installed',\n message: `Tmux keybindings already configured: ${cycleKey} (cycle), ${prefixKey}+key (?=help for full list).`,\n };\n }\n\n const persistNote = persistedToConf\n ? ''\n : `\\nNote: No tmux.conf found. Add this to your tmux config for persistence:\\n source-file ${confPath}`;\n return {\n status: 'installed',\n message: `Tmux keybindings set: ${cycleKey} cycles, ${prefixKey}+key (?=help for full list)${persistNote}`,\n };\n}\n\nexport function removeTmuxKeybind(): void {\n const confPath = sisyphusTmuxConfPath();\n for (const candidate of [join(homedir(), '.tmux.conf'), join(homedir(), '.config', 'tmux', 'tmux.conf')]) {\n if (existsSync(candidate)) {\n const contents = readFileSync(candidate, 'utf8');\n const filtered = contents\n .split('\\n')\n .filter((line) => !line.includes(confPath))\n .join('\\n');\n if (filtered !== contents) {\n writeFileSync(candidate, filtered, 'utf8');\n }\n }\n }\n\n if (existsSync(confPath)) {\n unlinkSync(confPath);\n }\n\n // Unbind live\n try {\n execSync(`tmux unbind-key -T root ${DEFAULT_CYCLE_KEY}`, { stdio: 'pipe' });\n execSync(`tmux unbind-key -T root ${DEFAULT_PREFIX_KEY}`, { stdio: 'pipe' });\n const output = execSync(`tmux list-keys -T ${KEY_TABLE}`, { stdio: ['pipe', 'pipe', 'pipe'] }).toString();\n for (const line of output.split('\\n')) {\n const parts = line.trim().split(/\\s+/);\n if (parts.length >= 4 && parts[2] === KEY_TABLE) {\n execSync(`tmux unbind-key -T ${KEY_TABLE} ${parts[3]}`, { stdio: 'pipe' });\n }\n }\n } catch {\n // tmux not running\n }\n\n // Remove keymap.json\n const kmPath = keymapJsonPath();\n if (existsSync(kmPath)) unlinkSync(kmPath);\n\n // Remove scripts\n const scripts = [\n 'sisyphus-cycle', 'sisyphus-home', 'sisyphus-kill-pane', 'sisyphus-new', 'sisyphus-msg',\n 'sisyphus-kill-session', 'sisyphus-delete-session', 'sisyphus-help', 'sisyphus-status-popup',\n 'sisyphus-pick-session', 'sisyphus-continue-session', 'sisyphus-restart-agent-popup',\n 'sisyphus-open-roadmap', 'sisyphus-open-strategy', 'sisyphus-export-session',\n // Stage 1: submenu dispatch scripts\n ...Object.keys(KEYMAP.submenus).map(id => `sisyphus-menu-${id}`),\n // Stage 1: new stub scripts\n 'sisyphus-copy-path', 'sisyphus-copy-id', 'sisyphus-copy-context',\n 'sisyphus-copy-logs', 'sisyphus-copy-latest-report', 'sisyphus-copy-agent-id',\n 'sisyphus-open-goal', 'sisyphus-open-dir', 'sisyphus-open-logs',\n 'sisyphus-open-latest-report', 'sisyphus-open-scratch', 'sisyphus-edit-context-file',\n 'sisyphus-spawn-agent', 'sisyphus-msg-agent', 'sisyphus-rerun-agent',\n 'sisyphus-jump-to-pane', 'sisyphus-open-claude-agent', 'sisyphus-tail-agent-logs',\n 'sisyphus-kill-agent', 'sisyphus-quick-spawn-explore', 'sisyphus-quick-spawn-debug',\n 'sisyphus-resume-session', 'sisyphus-rollback-session', 'sisyphus-go-to-window',\n 'sisyphus-clone-session', 'sisyphus-history', 'sisyphus-reconnect',\n 'sisyphus-search-reports',\n ];\n for (const name of scripts) {\n const path = scriptPath(name);\n if (existsSync(path)) unlinkSync(path);\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: ' Companion ›', 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 { key: 't', label: ' open in tmux pane', action: { type: 'tui', action: 'companion-pane' } },\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 { execSync } from 'node:child_process';\nimport { loadConfig } from '../shared/config.js';\nimport { resolveInstalledPlugin } from '../daemon/plugins.js';\n\nexport interface SisyphusPluginInfo {\n installed: boolean;\n autoInstalled: boolean;\n installPath: string | null;\n}\n\nfunction exec(cmd: string): string {\n try {\n return execSync(cmd, { encoding: 'utf-8', stdio: ['pipe', 'pipe', 'pipe'] }).trim();\n } catch {\n return '';\n }\n}\n\nfunction isMarketplaceInstalled(marketplace: string): boolean {\n const output = exec('claude plugins marketplace list');\n return output.includes(marketplace);\n}\n\nfunction installMarketplace(marketplace: string, owner = 'CaptainCrouton89'): void {\n console.log(`Adding marketplace: ${owner}/${marketplace}`);\n execSync(`claude plugins marketplace add ${owner}/${marketplace}`, { stdio: 'inherit' });\n}\n\nfunction installPlugin(key: string): void {\n console.log(`Installing plugin: ${key}`);\n execSync(`claude plugins install ${key} --scope user`, { stdio: 'inherit' });\n}\n\nconst SISYPHUS_PLUGIN_KEY = 'sisyphus@sisyphus';\nconst SISYPHUS_MARKETPLACE = 'sisyphus';\nconst SISYPHUS_OWNER = 'crouton-labs';\n\n/**\n * Ensures the user-facing sisyphus plugin (slash commands: /sisyphus:begin,\n * /sisyphus:autopsy, /sisyphus:configure-upload) is installed in the user's\n * Claude Code workspace. Adds the marketplace if needed.\n */\nexport function ensureSisyphusPluginInstalled(): SisyphusPluginInfo {\n const existing = resolveInstalledPlugin(SISYPHUS_PLUGIN_KEY);\n if (existing) {\n return { installed: true, autoInstalled: false, installPath: existing };\n }\n\n try {\n if (!isMarketplaceInstalled(SISYPHUS_MARKETPLACE)) {\n installMarketplace(SISYPHUS_MARKETPLACE, SISYPHUS_OWNER);\n }\n installPlugin(SISYPHUS_PLUGIN_KEY);\n } catch (err) {\n console.warn(`Warning: failed to install ${SISYPHUS_PLUGIN_KEY} — ${(err as Error).message}`);\n return { installed: false, autoInstalled: false, installPath: null };\n }\n\n const installPath = resolveInstalledPlugin(SISYPHUS_PLUGIN_KEY);\n return { installed: installPath !== null, autoInstalled: installPath !== null, installPath };\n}\n\nexport async function ensureRequiredPlugins(cwd: string): Promise<void> {\n const config = loadConfig(cwd);\n const required = config.requiredPlugins;\n if (!required || required.length === 0) return;\n\n for (const plugin of required) {\n const key = `${plugin.name}@${plugin.marketplace}`;\n const existing = resolveInstalledPlugin(key);\n if (existing) continue;\n\n console.log(`Required plugin ${key} not found — installing...`);\n\n if (!isMarketplaceInstalled(plugin.marketplace)) {\n installMarketplace(plugin.marketplace);\n }\n\n installPlugin(key);\n\n // Verify\n const verified = resolveInstalledPlugin(key);\n if (verified) {\n console.log(`Installed ${key} → ${verified}`);\n } else {\n console.warn(`Warning: failed to verify ${key} installation`);\n }\n }\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 { readFileSync } from 'node:fs';\nimport { execFileSync } from 'node:child_process';\nimport { homedir } from 'node:os';\nimport { join } from 'node:path';\nimport { loadConfig } from '../shared/config.js';\n\ninterface PluginEntry {\n scope: string;\n installPath: string;\n version: string;\n installedAt: string;\n lastUpdated: string;\n}\n\ninterface InstalledPlugins {\n version: number;\n plugins: Record<string, PluginEntry[]>;\n}\n\nfunction installedPluginsPath(): string {\n return join(homedir(), '.claude', 'plugins', 'installed_plugins.json');\n}\n\nexport function resolveInstalledPlugin(name: string): string | null {\n let data: InstalledPlugins;\n try {\n data = JSON.parse(readFileSync(installedPluginsPath(), 'utf-8'));\n } catch {\n return null;\n }\n\n const entries = data.plugins?.[name];\n if (!entries || entries.length === 0) return null;\n\n // Prefer user-scoped entry\n const userEntry = entries.find(e => e.scope === 'user');\n return (userEntry ?? entries[0])!.installPath;\n}\n\n/**\n * Auto-install a plugin if not already present.\n * key format: \"name@marketplace\" (e.g. \"termrender@crouton-kit\")\n */\nfunction ensurePluginInstalled(key: string): string | null {\n const existing = resolveInstalledPlugin(key);\n if (existing) return existing;\n\n console.log(`[sisyphus] Auto-installing plugin ${key}...`);\n try {\n execFileSync('claude', ['plugin', 'install', key], {\n stdio: 'pipe',\n timeout: 60_000,\n });\n } catch (err) {\n console.log(`[sisyphus] Warning: failed to install plugin ${key} — ${(err as Error).message}`);\n return null;\n }\n\n // Re-read registry after install\n const installed = resolveInstalledPlugin(key);\n if (!installed) {\n console.log(`[sisyphus] Warning: plugin ${key} installed but not found in registry`);\n }\n return installed;\n}\n\nexport function resolveRequiredPluginDirs(cwd: string): string[] {\n const config = loadConfig(cwd);\n const required = config.requiredPlugins;\n if (!required || required.length === 0) return [];\n\n const dirs: string[] = [];\n for (const plugin of required) {\n const key = `${plugin.name}@${plugin.marketplace}`;\n const path = ensurePluginInstalled(key);\n if (path) {\n dirs.push(path);\n } else {\n console.log(`[sisyphus] Warning: required plugin ${key} not available — skipping`);\n }\n }\n return dirs;\n}\n\n/**\n * Resolve per-agent-type plugin dirs from frontmatter `plugins` field.\n * Auto-installs missing plugins. Keys are \"name@marketplace\" strings.\n */\nexport function resolveAgentPluginDirs(plugins: string[] | undefined): string[] {\n if (!plugins || plugins.length === 0) return [];\n\n const dirs: string[] = [];\n for (const key of plugins) {\n const path = ensurePluginInstalled(key);\n if (path) {\n dirs.push(path);\n }\n }\n return dirs;\n}\n","import type { Request, Response } from '../shared/protocol.js';\nimport { rawSend as sharedRawSend } from '../shared/client.js';\nimport { ensureDaemonInstalled, waitForDaemon } from './install.js';\n\nexport function rawSend(request: Request, timeoutMs = 10_000): Promise<Response> {\n return sharedRawSend(request, timeoutMs);\n}\n\nexport async function sendRequest(request: Request, timeoutMs?: number): Promise<Response> {\n const sleep = (ms: number) => new Promise<void>((resolve) => setTimeout(resolve, ms));\n const MAX_ATTEMPTS = 5;\n const RETRY_DELAY_MS = 2000;\n let installedDaemon = false;\n let lastErr: unknown;\n\n for (let attempt = 1; attempt <= MAX_ATTEMPTS; attempt++) {\n try {\n return await rawSend(request, timeoutMs);\n } catch (err) {\n lastErr = err;\n const code = (err as NodeJS.ErrnoException).code;\n if (code !== 'ENOENT' && code !== 'ECONNREFUSED') {\n throw err;\n }\n\n if (attempt === MAX_ATTEMPTS) break;\n\n if (process.platform === 'darwin' && !installedDaemon) {\n installedDaemon = true;\n await ensureDaemonInstalled();\n await waitForDaemon(5000);\n } else {\n process.stderr.write(`Daemon not ready, retrying (${attempt}/${MAX_ATTEMPTS - 1})...\\n`);\n await sleep(RETRY_DELAY_MS);\n }\n }\n }\n\n if (process.platform !== 'darwin') {\n const lines = [`Sisyphus daemon is not running.`];\n if (process.platform === 'linux') {\n lines.push(\n '',\n ' Start options:',\n ' sisyphusd & # Run in background',\n ' nohup sisyphusd > ~/.sisyphus/daemon.log 2>&1 & # Persist after logout',\n '',\n ' For systemd (recommended):',\n ' # Create ~/.config/systemd/user/sisyphus.service with:',\n ' # [Unit]',\n ' # Description=Sisyphus Daemon',\n ' # [Service]',\n ' # ExecStart=/usr/bin/env node <path-to-sisyphusd>',\n ' # Restart=always',\n ' # [Install]',\n ' # WantedBy=default.target',\n ' systemctl --user enable --now sisyphus',\n );\n } else {\n lines.push(\n '',\n ' Start it manually: sisyphusd &',\n );\n }\n lines.push(\n '',\n ' Diagnose: sis admin doctor',\n ' Logs: tail -f ~/.sisyphus/daemon.log',\n );\n throw new Error(lines.join('\\n'));\n }\n throw lastErr;\n}\n","export function readStdin(opts: { force?: boolean } = {}): Promise<string | null> {\n // Without `force`, skip stdin if attached to a TTY — caller is interactive,\n // not piping. With `force`, read regardless: user explicitly asked via `--stdin`.\n if (!opts.force && process.stdin.isTTY) return Promise.resolve(null);\n\n return new Promise((resolve, reject) => {\n const chunks: Buffer[] = [];\n process.stdin.on('data', (chunk: Buffer) => chunks.push(chunk));\n process.stdin.on('end', () => {\n const text = Buffer.concat(chunks).toString('utf-8').trim();\n resolve(text || null);\n });\n process.stdin.on('error', reject);\n });\n}\n","import { execSync } from 'node:child_process';\n\nexport function isTmuxInstalled(): boolean {\n try {\n execSync('which tmux', { stdio: 'pipe' });\n return true;\n } catch {\n return false;\n }\n}\n\nexport function assertTmux(): void {\n if (!process.env.TMUX) {\n throw new Error('Not running inside a tmux pane. Sisyphus requires tmux.');\n }\n}\n\nexport function getTmuxSession(): string {\n assertTmux();\n return execSync('tmux display-message -p \"#{session_name}\"', { encoding: 'utf8' }).trim();\n}\n\n/**\n * Current tmux session's $N id and name. Always prefer the id for `-t` targeting\n * — tmux -t <name> silently substring-matches other sessions under sparse env.\n */\nexport function getTmuxSessionInfo(): { id: string; name: string } {\n assertTmux();\n const out = execSync('tmux display-message -p \"#{session_id}|#{session_name}\"', { encoding: 'utf8' }).trim();\n const pipeIdx = out.indexOf('|');\n return { id: out.slice(0, pipeIdx), name: out.slice(pipeIdx + 1) };\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 type { Command } from 'commander';\nimport { join } from 'node:path';\nimport { execSync } from 'node:child_process';\nimport { assertTmux, getTmuxSession } from '../tmux.js';\nimport { shellQuote } from '../../shared/shell.js';\n\n\n/**\n * Opens the dashboard in a new tmux window (for background use, e.g. from `start`).\n *\n * Tracks the window by its tmux window ID stored in the @sisyphus_dashboard\n * session option — not by window name, which is fragile (renames, collisions).\n * The \"; exit\" suffix closes the window when the TUI exits.\n *\n * Returns true if a new dashboard was created, false if an existing one was focused.\n */\nexport function openDashboardWindow(tmuxSession: string, cwd: string): boolean {\n // Check for existing dashboard by stored window ID\n try {\n const storedId = execSync(\n `tmux show-option -t ${shellQuote(tmuxSession)} -v @sisyphus_dashboard`,\n { encoding: 'utf-8', stdio: ['pipe', 'pipe', 'pipe'] },\n ).trim();\n\n if (storedId) {\n try {\n execSync(\n `tmux display-message -t ${shellQuote(storedId)} -p \"#{window_id}\"`,\n { stdio: 'pipe' },\n );\n execSync(`tmux select-window -t ${shellQuote(storedId)}`, { stdio: 'pipe' });\n return false;\n } catch {\n // Window is gone — fall through to create a new one\n }\n }\n } catch {\n // Option not set — fall through to create\n }\n\n const tuiPath = join(import.meta.dirname, 'tui.js');\n\n const windowId = execSync(\n `tmux new-window -t ${shellQuote(tmuxSession + ':')} -n \"sisyphus-dashboard\" -c ${shellQuote(cwd)} -P -F \"#{window_id}\"`,\n { encoding: 'utf-8' },\n ).trim();\n\n const cmd = `node ${shellQuote(tuiPath)} --cwd ${shellQuote(cwd)}; exit`;\n execSync(\n `tmux send-keys -t ${shellQuote(windowId)} ${shellQuote(cmd)} Enter`,\n );\n\n execSync(\n `tmux set-option -t ${shellQuote(tmuxSession)} @sisyphus_dashboard ${shellQuote(windowId)}`,\n { stdio: 'pipe' },\n );\n\n return true;\n}\n\nexport function registerDashboard(program: Command): void {\n program\n .command('dashboard')\n .description('Launch the TUI dashboard for monitoring and managing sessions')\n .action(async () => {\n assertTmux();\n const tuiPath = join(import.meta.dirname, 'tui.js');\n execSync(`node ${shellQuote(tuiPath)} --cwd ${shellQuote(process.cwd())}`, {\n stdio: 'inherit',\n });\n });\n}\n","import { execSync } from 'node:child_process';\nimport { existsSync, readFileSync } from 'node:fs';\nimport type { Command } from 'commander';\nimport { sendRequest } from '../client.js';\nimport type { Request } from '../../shared/protocol.js';\nimport type { Session, Agent, OrchestratorCycle } from '../../shared/types.js';\nimport { computeActiveTimeMs } from '../../shared/utils.js';\nimport { roadmapPath, cycleLogPath } from '../../shared/paths.js';\nimport { formatDuration, statusColor } from '../../shared/format.js';\n\nconst COLOR_CODES: Record<string, string> = {\n green: '\\x1b[32m', yellow: '\\x1b[33m', cyan: '\\x1b[36m',\n red: '\\x1b[31m', gray: '\\x1b[90m', white: '\\x1b[37m',\n};\nconst RESET = '\\x1b[0m';\nconst BOLD = '\\x1b[1m';\nconst DIM = '\\x1b[2m';\n\nfunction colorize(text: string, status: string): string {\n const colorName = statusColor(status);\n const code = COLOR_CODES[colorName];\n if (!code) return `${text}\\x1b[0m`;\n return `${code}${text}\\x1b[0m`;\n}\n\nfunction inferOrchestratorPhase(session: Session): string {\n const cycles = session.orchestratorCycles;\n if (cycles.length === 0) return 'planning';\n const lastCycle = cycles[cycles.length - 1];\n\n if (!lastCycle.completedAt) {\n // Orchestrator pane is alive\n const elapsed = Date.now() - new Date(lastCycle.timestamp).getTime();\n if (elapsed < 5000 || lastCycle.agentsSpawned.length === 0) return 'planning';\n return 'spawning';\n } else {\n // Orchestrator yielded\n const runningAgents = session.agents.filter(\n a => lastCycle.agentsSpawned.includes(a.id) && a.status === 'running'\n );\n if (runningAgents.length > 0) {\n return `waiting on ${runningAgents.map(a => a.id).join(', ')}`;\n }\n return 'starting';\n }\n}\n\nfunction formatAgent(agent: Agent, verbose: boolean): string {\n const status = colorize(agent.status, agent.status);\n const name = `${BOLD}${agent.name}${RESET}`;\n const type = `${DIM}(${agent.agentType})${RESET}`;\n const duration = formatDuration(agent.activeMs);\n let line = ` ${agent.id} ${name} ${type} — ${status} ${DIM}(${duration})${RESET}`;\n if (verbose && agent.instruction) {\n const truncated = agent.instruction.length > 200 ? agent.instruction.slice(0, 200) + '...' : agent.instruction;\n line += `\\n ${DIM}Instruction: ${truncated}${RESET}`;\n }\n if (agent.reports.length > 0) {\n for (const r of agent.reports) {\n const label = r.type === 'final' ? 'Final' : 'Update';\n line += `\\n ${label}: ${r.summary}`;\n }\n }\n if (agent.killedReason) {\n line += `\\n Reason: ${agent.killedReason}`;\n }\n return line;\n}\n\nfunction formatCycle(cycle: OrchestratorCycle, phase?: string): string {\n let duration: string;\n if (cycle.completedAt) {\n duration = ` ${DIM}(${formatDuration(cycle.activeMs)})${RESET}`;\n } else {\n const elapsed = formatDuration(cycle.activeMs);\n duration = ` ${DIM}(running, ${elapsed})${RESET}`;\n }\n const agents = cycle.agentsSpawned.length > 0\n ? ` — agents: ${cycle.agentsSpawned.join(', ')}`\n : '';\n const phaseStr = phase ? ` — orchestrator: ${phase}` : '';\n return ` Cycle ${cycle.cycle}${duration}${agents}${phaseStr}`;\n}\n\nfunction computeLastActivity(session: Session): Date | null {\n const timestamps: number[] = [];\n\n for (const cycle of session.orchestratorCycles) {\n timestamps.push(new Date(cycle.timestamp).getTime());\n if (cycle.completedAt) timestamps.push(new Date(cycle.completedAt).getTime());\n }\n\n for (const agent of session.agents) {\n timestamps.push(new Date(agent.spawnedAt).getTime());\n if (agent.completedAt) timestamps.push(new Date(agent.completedAt).getTime());\n for (const r of agent.reports) {\n timestamps.push(new Date(r.timestamp).getTime());\n }\n }\n\n if (timestamps.length === 0) return null;\n return new Date(Math.max(...timestamps));\n}\n\nfunction readRoadmap(cwd: string, sessionId: string): string | null {\n try {\n return readFileSync(roadmapPath(cwd, sessionId), 'utf8');\n } catch {\n return null;\n }\n}\n\nfunction readCycleLog(cwd: string, sessionId: string, cycle: number): string | null {\n try {\n const path = cycleLogPath(cwd, sessionId, cycle);\n if (!existsSync(path)) return null;\n return readFileSync(path, 'utf8');\n } catch {\n return null;\n }\n}\n\nfunction capturePaneOutput(paneId: string, lines: number = 50): string | null {\n try {\n return execSync(\n `tmux capture-pane -t \"${paneId}\" -p -S -${lines}`,\n { encoding: 'utf-8', stdio: ['pipe', 'pipe', 'pipe'] },\n ).trimEnd();\n } catch {\n return null;\n }\n}\n\nfunction printSession(session: Session, verbose: boolean): void {\n const status = colorize(session.status, session.status);\n const sessionDuration = formatDuration(session.createdAt, session.completedAt);\n console.log(`\\n${BOLD}Session: ${session.id}${RESET}`);\n console.log(` Status: ${status}`);\n const effortLabel = session.effort != null ? session.effort : 'high (default)';\n console.log(` Effort: ${effortLabel}`);\n console.log(` Task: ${session.task}`);\n if (session.context) {\n const truncated = !verbose && session.context.length > 120 ? session.context.slice(0, 120) + '...' : session.context;\n console.log(` Context: ${truncated}`);\n }\n console.log(` CWD: ${session.cwd}`);\n console.log(` Created: ${session.createdAt}`);\n const activeTime = formatDuration(computeActiveTimeMs(session));\n console.log(` Duration: ${sessionDuration}${session.completedAt ? '' : ' (ongoing)'} (${activeTime} active)`);\n\n const lastActivity = computeLastActivity(session);\n if (lastActivity) {\n console.log(` Last activity: ${formatDuration(Date.now() - lastActivity.getTime())} ago`);\n }\n\n console.log(` Orchestrator cycles: ${session.orchestratorCycles.length}`);\n\n // Active agents block\n const runningAgents = session.agents.filter(a => a.status === 'running');\n if (runningAgents.length > 0) {\n console.log(`\\n${BOLD}Active agents (${runningAgents.length}):${RESET}`);\n for (const agent of runningAgents) {\n const name = `${BOLD}${agent.name}${RESET}`;\n const type = `${DIM}(${agent.agentType})${RESET}`;\n const duration = formatDuration(agent.activeMs);\n console.log(` ${agent.id} ${name} ${type} running ${duration}`);\n if (verbose && agent.instruction) {\n const truncated = agent.instruction.length > 200 ? agent.instruction.slice(0, 200) + '...' : agent.instruction;\n console.log(` ${DIM}Instruction: ${truncated}${RESET}`);\n }\n }\n }\n\n // Roadmap\n const roadmap = readRoadmap(session.cwd, session.id);\n if (roadmap) {\n console.log(`\\n${BOLD}Roadmap:${RESET}`);\n console.log(roadmap);\n }\n\n if (session.orchestratorCycles.length > 0) {\n console.log(`\\n ${BOLD}Cycles:${RESET}`);\n const cycles = session.orchestratorCycles;\n for (let i = 0; i < cycles.length; i++) {\n const isLast = i === cycles.length - 1;\n const phase = isLast && session.status === 'active' ? inferOrchestratorPhase(session) : undefined;\n console.log(formatCycle(cycles[i], phase));\n\n // Verbose: show cycle log\n if (verbose) {\n const log = readCycleLog(session.cwd, session.id, cycles[i].cycle);\n if (log) {\n const lines = log.split('\\n');\n const preview = lines.slice(0, 20).join('\\n');\n console.log(` ${DIM}--- cycle log ---${RESET}`);\n for (const line of preview.split('\\n')) {\n console.log(` ${DIM}${line}${RESET}`);\n }\n if (lines.length > 20) {\n console.log(` ${DIM}... (${lines.length - 20} more lines)${RESET}`);\n }\n }\n }\n }\n }\n\n if (session.agents.length > 0) {\n console.log(`\\n ${BOLD}Agents:${RESET}`);\n for (const agent of session.agents) {\n console.log(formatAgent(agent, verbose));\n }\n }\n\n // Verbose: capture live pane output\n if (verbose) {\n // Orchestrator pane (from last running cycle)\n const lastCycle = session.orchestratorCycles[session.orchestratorCycles.length - 1];\n if (lastCycle && !lastCycle.completedAt && lastCycle.paneId) {\n const output = capturePaneOutput(lastCycle.paneId);\n if (output) {\n console.log(`\\n<orchestrator-pane-output lines=\"50\">`);\n console.log(output);\n console.log(`</orchestrator-pane-output>`);\n }\n }\n\n // Running agent panes\n for (const agent of runningAgents) {\n if (agent.paneId) {\n const output = capturePaneOutput(agent.paneId, 30);\n if (output) {\n console.log(`\\n<agent-pane-output agent=\"${agent.id}\" name=\"${agent.name}\" lines=\"30\">`);\n console.log(output);\n console.log(`</agent-pane-output>`);\n }\n }\n }\n }\n\n // Completion report\n if (verbose && session.completionReport) {\n console.log(`\\n${BOLD}Completion Report:${RESET}`);\n console.log(session.completionReport);\n }\n}\n\nexport function registerStatus(program: Command): void {\n program\n .command('status')\n .description('Show session status')\n .argument('[session-id]', 'Session ID (defaults to SISYPHUS_SESSION_ID env)')\n .option('-v, --verbose', 'Show detailed output (roadmap, pane output, agent instructions)')\n .option('-j, --json', 'Output raw JSON instead of formatted text')\n .action(async (sessionIdArg?: string, opts?: { verbose?: boolean; json?: boolean }) => {\n const sessionId = sessionIdArg ?? process.env.SISYPHUS_SESSION_ID;\n const verbose = opts?.verbose ?? false;\n const json = opts?.json ?? false;\n const cwd = process.env['SISYPHUS_CWD'] ?? process.cwd();\n\n const request: Request = { type: 'status', sessionId, cwd };\n const response = await sendRequest(request);\n if (response.ok) {\n const session = response.data?.session as Session | undefined;\n if (session) {\n if (json) {\n console.log(JSON.stringify(session));\n } else {\n printSession(session, verbose);\n }\n } else {\n console.log('No session found');\n }\n } else {\n console.error(`Error: ${response.error}`);\n process.exit(1);\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","/** 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 type { Command } from 'commander';\nimport { sendRequest } from '../client.js';\nimport type { Request } from '../../shared/protocol.js';\nimport { basename } from 'node:path';\n\ninterface SessionSummary {\n id: string;\n name?: string;\n task: string;\n status: string;\n agentCount: number;\n createdAt: string;\n cwd?: string;\n}\n\nconst STATUS_COLORS: Record<string, string> = {\n active: '\\x1b[32m',\n paused: '\\x1b[33m',\n completed: '\\x1b[36m',\n};\nconst RESET = '\\x1b[0m';\nconst BOLD = '\\x1b[1m';\nconst DIM = '\\x1b[2m';\n\nfunction truncateTask(task: string, max: number): string {\n if (task.length <= max) return task;\n return task.slice(0, max - 1) + '…';\n}\n\nexport function registerList(program: Command): void {\n program\n .command('list')\n .description('List sessions (defaults to current project)')\n .option('-a, --all', 'Show sessions from all projects')\n .option('--cwd <path>', 'Project directory to list sessions for (overrides SISYPHUS_CWD)')\n .action(async (opts: { all?: boolean; cwd?: string }) => {\n const cwd = opts.cwd ?? process.env['SISYPHUS_CWD'] ?? process.cwd();\n const request: Request = { type: 'list', cwd, all: opts.all };\n const response = await sendRequest(request);\n if (response.ok) {\n const sessions = (response.data?.sessions ?? []) as SessionSummary[];\n const totalCount = response.data?.totalCount as number | undefined;\n const filtered = response.data?.filtered as boolean | undefined;\n\n if (sessions.length === 0) {\n if (filtered && totalCount && totalCount > 0) {\n console.log(`No sessions in this project. ${totalCount} session(s) in other projects.`);\n console.log(`${DIM}Run ${RESET}sis list --all${DIM} to show all.${RESET}`);\n } else {\n console.log('No sessions');\n }\n return;\n }\n\n for (const s of sessions) {\n const color = STATUS_COLORS[s.status] ?? '';\n const status = `${color}${s.status}${RESET}`;\n const agents = `${DIM}${s.agentCount} agent(s)${RESET}`;\n const task = truncateTask(s.task, 60);\n const label = s.name ? `${s.name} ${DIM}(${s.id.slice(0, 8)})${RESET}` : s.id;\n const cwdLabel = opts.all && s.cwd ? ` ${DIM}${basename(s.cwd)}${RESET}` : '';\n console.log(` ${BOLD}${label}${RESET} ${status} ${agents} ${task}${cwdLabel}`);\n }\n\n if (filtered && totalCount && totalCount > sessions.length) {\n const otherCount = totalCount - sessions.length;\n console.log(`\\n${DIM}${otherCount} more session(s) in other projects. Run ${RESET}sis list --all${DIM} to show all.${RESET}`);\n }\n } else {\n console.error(`Error: ${response.error}`);\n process.exit(1);\n }\n });\n}\n","import { readFileSync } from 'node:fs';\nimport type { Command } from 'commander';\nimport { sendRequest } from '../client.js';\nimport type { Request } from '../../shared/protocol.js';\nimport type { MessageSource } from '../../shared/types.js';\n\ninterface TellOptions {\n session?: string;\n // Commander exposes `--no-submit` as `opts.submit`, defaulting to true.\n submit?: boolean;\n stdin?: boolean;\n}\n\nconst ORCH_ALIASES = new Set(['orchestrator', 'orch', 'o']);\n\nfunction parseTarget(raw: string): { kind: 'orchestrator' } | { kind: 'agent'; agentId: string } | null {\n if (ORCH_ALIASES.has(raw)) return { kind: 'orchestrator' };\n if (/^agent-\\d+$/i.test(raw)) return { kind: 'agent', agentId: raw };\n return null;\n}\n\nfunction readStdin(): string {\n // Synchronous read of all stdin. Same pattern as other CLI commands that take piped input.\n return readFileSync(0, 'utf-8');\n}\n\nexport function registerTell(program: Command): void {\n program\n .command('tell <target> [text]')\n .description('Type a prompt directly into a running pane (orchestrator or agent-NNN). Submits immediately unlike `message`.')\n .option('--session <sessionId>', 'Session ID (defaults to SISYPHUS_SESSION_ID)')\n .option('--no-submit', 'Paste text but do not press Enter (caller can review/submit manually)')\n .option('--stdin', 'Read prompt body from stdin instead of the [text] argument (avoids shell escaping)')\n .action(async (targetRaw: string, textArg: string | undefined, opts: TellOptions) => {\n const sessionId = opts.session ?? process.env.SISYPHUS_SESSION_ID;\n if (!sessionId) {\n console.error('Error: provide --session or set SISYPHUS_SESSION_ID');\n process.exit(1);\n }\n\n const target = parseTarget(targetRaw);\n if (!target) {\n console.error(`Error: target must be 'orchestrator' (or 'o'/'orch') or 'agent-NNN', got: ${targetRaw}`);\n process.exit(1);\n }\n\n let text: string;\n if (opts.stdin) {\n text = readStdin();\n if (text === '') {\n console.error('Error: --stdin set but stdin was empty');\n process.exit(1);\n }\n if (textArg != null && textArg !== '') {\n console.error('Error: --stdin conflicts with [text] argument; pass one source');\n process.exit(1);\n }\n } else {\n if (textArg == null || textArg === '') {\n console.error('Error: provide [text] argument or use --stdin');\n process.exit(1);\n }\n text = textArg;\n }\n\n const source: MessageSource | undefined = process.env.SISYPHUS_AGENT_ID\n ? { type: 'agent' as const, agentId: process.env.SISYPHUS_AGENT_ID }\n : undefined;\n\n const submit = opts.submit !== false;\n const request: Request = {\n type: 'tell',\n sessionId,\n target,\n text,\n submit,\n ...(source ? { source } : {}),\n };\n const response = await sendRequest(request);\n if (response.ok) {\n console.log(`Sent to ${targetRaw}${submit ? '' : ' (not submitted)'}`);\n } else {\n console.error(`Error: ${response.error}`);\n process.exit(1);\n }\n });\n}\n","import { existsSync, readFileSync } from 'node:fs';\nimport { homedir } from 'node:os';\nimport { join } from 'node:path';\nimport type { Command } from 'commander';\nimport { sendRequest } from '../client.js';\nimport type { Request } from '../../shared/protocol.js';\nimport type { Session, OrchestratorCycle } from '../../shared/types.js';\n\ninterface ReadOptions {\n session?: string;\n cycle?: string;\n tail?: string;\n head?: string;\n raw?: boolean;\n summary?: boolean;\n toolDetail?: boolean;\n}\n\nconst ORCH_ALIASES = new Set(['orchestrator', 'orch', 'o']);\nconst TURN_TYPES = new Set(['user', 'assistant']);\n\ninterface JsonlEntry {\n type?: string;\n timestamp?: string;\n message?: { role?: string; content?: unknown };\n}\n\ninterface ContentBlock {\n type?: string;\n text?: string;\n thinking?: string;\n name?: string;\n input?: unknown;\n content?: unknown;\n}\n\nfunction projectDirFromCwd(cwd: string): string {\n // Claude Code project encoding: cwd with `/` → `-`. Leading `/` becomes leading `-`.\n return cwd.replace(/\\//g, '-');\n}\n\nfunction transcriptPath(cwd: string, claudeSessionId: string): string {\n return join(homedir(), '.claude', 'projects', projectDirFromCwd(cwd), `${claudeSessionId}.jsonl`);\n}\n\nfunction truncate(s: string, max: number): string {\n if (s.length <= max) return s;\n return s.slice(0, max) + `… (${s.length - max} more chars)`;\n}\n\nfunction formatBlocks(content: unknown, toolDetail: boolean): string {\n if (typeof content === 'string') return content;\n if (!Array.isArray(content)) return JSON.stringify(content);\n const parts: string[] = [];\n for (const block of content as ContentBlock[]) {\n switch (block.type) {\n case 'text':\n parts.push(block.text ?? '');\n break;\n case 'thinking':\n parts.push(`[thinking]\\n${block.thinking ?? ''}`);\n break;\n case 'tool_use': {\n const inputStr = JSON.stringify(block.input ?? {});\n parts.push(`[tool_use: ${block.name}] ${toolDetail ? inputStr : truncate(inputStr, 400)}`);\n break;\n }\n case 'tool_result': {\n const c = typeof block.content === 'string' ? block.content : JSON.stringify(block.content ?? '');\n parts.push(`[tool_result]\\n${toolDetail ? c : truncate(c, 600)}`);\n break;\n }\n default:\n parts.push(`[${block.type ?? 'unknown'}] ${truncate(JSON.stringify(block), 200)}`);\n }\n }\n return parts.join('\\n');\n}\n\nfunction summaryLine(entry: JsonlEntry): string {\n const role = (entry.type ?? '?').toUpperCase().padEnd(9);\n const ts = (entry.timestamp ?? '').slice(11, 19);\n const content = entry.message?.content;\n let preview = '';\n if (typeof content === 'string') {\n preview = content.replace(/\\s+/g, ' ').slice(0, 120);\n } else if (Array.isArray(content)) {\n const blocks = content as ContentBlock[];\n const first = blocks[0];\n if (!first) preview = '(empty)';\n else if (first.type === 'text') preview = (first.text ?? '').replace(/\\s+/g, ' ').slice(0, 120);\n else if (first.type === 'thinking') preview = `[thinking] ${(first.thinking ?? '').replace(/\\s+/g, ' ').slice(0, 100)}`;\n else if (first.type === 'tool_use') preview = `[${first.name}] ${truncate(JSON.stringify(first.input ?? {}), 100)}`;\n else if (first.type === 'tool_result') {\n const c = typeof first.content === 'string' ? first.content : JSON.stringify(first.content ?? '');\n preview = `[tool_result] ${c.replace(/\\s+/g, ' ').slice(0, 100)}`;\n } else preview = `[${first.type ?? '?'}]`;\n if (blocks.length > 1) preview += ` (+${blocks.length - 1} more block${blocks.length - 1 > 1 ? 's' : ''})`;\n }\n return `${role} ${ts} ${preview}`;\n}\n\nexport function registerRead(program: Command): void {\n program\n .command('read <target>')\n .description(\"Print the Claude conversation transcript for a target ('orchestrator' or 'agent-NNN').\")\n .option('--session <sessionId>', 'Session ID (defaults to SISYPHUS_SESSION_ID)')\n .option('--cycle <n>', 'Orchestrator cycle number (default: most recent live, else last completed)')\n .option('--tail <n>', 'Show last N turns', undefined)\n .option('--head <n>', 'Show first N turns', undefined)\n .option('--raw', 'Print raw JSONL (no formatting, no filtering)')\n .option('--summary', 'One-line-per-turn summary instead of full content')\n .option('--tool-detail', 'Include full tool inputs/outputs (default: truncated to 400/600 chars)')\n .action(async (targetRaw: string, opts: ReadOptions) => {\n const sessionId = opts.session ?? process.env.SISYPHUS_SESSION_ID;\n if (!sessionId) {\n console.error('Error: provide --session or set SISYPHUS_SESSION_ID');\n process.exit(1);\n }\n\n const response = await sendRequest({ type: 'status', sessionId, cwd: process.cwd() } as Request);\n if (!response.ok) {\n console.error(`Error: ${response.error}`);\n process.exit(1);\n }\n const session = (response.data as { session?: Session })?.session;\n if (!session) {\n console.error('Error: status response did not include session');\n process.exit(1);\n }\n\n let claudeSessionId: string | undefined;\n let label: string;\n if (ORCH_ALIASES.has(targetRaw)) {\n let cycle: OrchestratorCycle | undefined;\n if (opts.cycle) {\n const n = parseInt(opts.cycle, 10);\n if (!Number.isFinite(n)) {\n console.error(`Error: --cycle must be a number, got: ${opts.cycle}`);\n process.exit(1);\n }\n cycle = session.orchestratorCycles.find(c => c.cycle === n);\n if (!cycle) {\n console.error(`Error: orchestrator cycle ${n} not found in session`);\n process.exit(1);\n }\n } else {\n cycle = [...session.orchestratorCycles].reverse().find(c => !c.completedAt) ?? session.orchestratorCycles.at(-1);\n }\n if (!cycle) {\n console.error('Error: no orchestrator cycles found');\n process.exit(1);\n }\n claudeSessionId = cycle.claudeSessionId;\n label = `orchestrator cycle ${cycle.cycle}${cycle.completedAt ? ' (completed)' : ' (live)'}`;\n } else if (/^agent-\\d+$/i.test(targetRaw)) {\n const ag = session.agents.find(a => a.id === targetRaw);\n if (!ag) {\n console.error(`Error: agent ${targetRaw} not found in session ${sessionId}`);\n process.exit(1);\n }\n claudeSessionId = ag.claudeSessionId;\n label = `agent ${ag.id} — ${ag.name} (${ag.status})`;\n } else {\n console.error(`Error: target must be 'orchestrator' (or 'o'/'orch') or 'agent-NNN', got: ${targetRaw}`);\n process.exit(1);\n }\n\n if (!claudeSessionId) {\n console.error(`Error: no claudeSessionId stored for ${label} — transcript may not exist yet`);\n process.exit(1);\n }\n\n const path = transcriptPath(session.cwd, claudeSessionId);\n if (!existsSync(path)) {\n console.error(`Error: transcript not found at ${path}`);\n process.exit(1);\n }\n\n const raw = readFileSync(path, 'utf-8');\n\n if (opts.raw) {\n process.stdout.write(raw);\n return;\n }\n\n const allEntries: JsonlEntry[] = raw\n .split('\\n')\n .filter(Boolean)\n .map(line => { try { return JSON.parse(line) as JsonlEntry; } catch { return null; } })\n .filter((e): e is JsonlEntry => e !== null);\n\n let entries = allEntries.filter(e => e.type && TURN_TYPES.has(e.type));\n\n const totalTurns = entries.length;\n const head = opts.head ? parseInt(opts.head, 10) : undefined;\n const tail = opts.tail ? parseInt(opts.tail, 10) : undefined;\n let sliceNote = '';\n if (head && Number.isFinite(head)) {\n entries = entries.slice(0, head);\n sliceNote = `first ${head} of ${totalTurns}`;\n }\n if (tail && Number.isFinite(tail)) {\n entries = entries.slice(-tail);\n sliceNote = sliceNote ? `${sliceNote}, then last ${tail}` : `last ${tail} of ${totalTurns}`;\n }\n\n console.log(`=== ${label} — ${entries.length} turn(s)${sliceNote ? ` (${sliceNote})` : ''} ===`);\n console.log(`transcript: ${path}\\n`);\n\n if (opts.summary) {\n for (const e of entries) console.log(summaryLine(e));\n return;\n }\n\n for (const e of entries) {\n const role = (e.type ?? '?').toUpperCase();\n const ts = e.timestamp ?? '';\n const body = formatBlocks(e.message?.content, opts.toolDetail ?? false);\n console.log(`──── ${role} ${ts} ────`);\n console.log(body);\n console.log('');\n }\n });\n}\n","import type { Command } from 'commander';\nimport { sendRequest } from '../client.js';\nimport { readStdin } from '../stdin.js';\nimport type { Request } from '../../shared/protocol.js';\nimport type { MessageSource } from '../../shared/types.js';\n\nexport function registerMessage(program: Command): void {\n program\n .command('message')\n .description('Queue a message for the orchestrator to see on next cycle')\n .argument('[content]', 'Message content (omit when using --stdin or piping)')\n .option('--session <sessionId>', 'Session ID (defaults to SISYPHUS_SESSION_ID env var)')\n .option('--agent <agentId>', 'Route message to a specific agent inbox instead of the orchestrator')\n .option('--stdin', 'Force-read message content from stdin (avoids shell escaping for long prompts)')\n .action(async (contentArg: string | undefined, opts: { session?: string; agent?: string; stdin?: boolean }) => {\n const sessionId = opts.session ?? process.env.SISYPHUS_SESSION_ID;\n if (!sessionId) {\n console.error('Error: provide --session or set SISYPHUS_SESSION_ID environment variable');\n process.exit(1);\n }\n\n let content: string | null | undefined;\n if (opts.stdin) {\n content = await readStdin({ force: true });\n if (!content) {\n console.error('Error: --stdin set but no input received on stdin');\n process.exit(1);\n }\n if (contentArg !== undefined && contentArg !== '-') {\n console.error('Error: --stdin conflicts with [content] argument; pass one source');\n process.exit(1);\n }\n } else if (contentArg === '-' || contentArg === undefined) {\n content = await readStdin();\n if (!content) {\n console.error('Error: provide [content] argument, pipe via stdin, or use --stdin');\n process.exit(1);\n }\n } else {\n content = contentArg;\n }\n\n const source: MessageSource | undefined = process.env.SISYPHUS_AGENT_ID\n ? { type: 'agent' as const, agentId: process.env.SISYPHUS_AGENT_ID }\n : undefined;\n\n const request: Request = { type: 'message', sessionId, content: content!, source, ...(opts.agent ? { agentId: opts.agent } : {}) };\n const response = await sendRequest(request);\n if (response.ok) {\n console.log('Message queued');\n } else {\n console.error(`Error: ${response.error}`);\n process.exit(1);\n }\n });\n}\n","import type { Command } from 'commander';\nimport { existsSync, readFileSync, watchFile, unwatchFile } from 'node:fs';\nimport { join, resolve } from 'node:path';\nimport { ulid } from 'ulid';\nimport { parseDeck } from '../../shared/ask-schema.js';\nimport { createAsk, readMeta, updateMeta, writeDecisions } from '../../daemon/ask-store.js';\nimport { emitHistoryEvent } from '../../daemon/history.js';\nimport { askOutputPath, statePath } from '../../shared/paths.js';\nimport * as state from '../../daemon/state.js';\nimport { ORCHESTRATOR_ASKED_BY } from '../../shared/types.js';\nimport type { AskOutput, AskStatus } from '../../shared/types.js';\nimport { execSafe } from '../../shared/exec.js';\nimport { shellQuote } from '../../shared/shell.js';\n\nconst ULID_RE = /^[0-9A-HJKMNP-TV-Z]{26}$/;\n\nfunction validateAskId(askId: string): void {\n if (!ULID_RE.test(askId)) {\n console.error(`Error: invalid askId format: ${askId}`);\n process.exit(1);\n }\n}\n\nexport function registerAsk(program: Command): void {\n const ask = program\n .command('ask')\n .description('Submit a structured question deck for the user to answer (blocks until answered)')\n .argument('[file]', 'Path to deck JSON (omit for poll/peek subcommands)')\n .option('--session <id>', 'Session id (defaults to SISYPHUS_SESSION_ID)')\n .addHelpText('after', `\nPosts a deck of questions to the user's dashboard inbox. They walk through it and you read the structured JSON back from stdout.\n\nThe CLI always blocks until the user answers (which can take 10+ minutes).\n\n- **Orchestrator:** invoke synchronously so the orchestrator's pane stays alive while the bash blocks. Daemon refuses \\`sis orch yield\\` while orchestrator owns a pending deck; foreground is the supported pattern.\n- **Agents / one-off Claude Code sessions:** invoke through the Bash tool with \\`run_in_background: true\\` and end your turn — the bash completion notification wakes you with stdout ready to parse.\n\nFor guidance on when to use a deck, how to design options the user can actually choose between, and how to bundle related questions into one deck, read the \\`humanloop\\` skill before authoring.\n\nDECK JSON SCHEMA\n { \"title\"?: string, \"interactions\": Interaction[] } // interactions[] non-empty\n\n Interaction:\n id string, /^[A-Za-z0-9_-]+$/, max 64 chars, unique within deck\n title string (required, non-empty)\n subtitle? string\n body? string // markdown rendered in dashboard\n bodyPath? string // path RELATIVE to the deck JSON's directory\n // and must resolve INSIDE that directory\n // (no '..', no symlinks out, no absolute\n // paths pointing elsewhere). Mutually\n // exclusive with 'body'. To use bodyPath,\n // write the deck JSON next to the markdown\n // file (e.g. both in\n // \\$SISYPHUS_SESSION_DIR/context/) and pass\n // a basename like \"summary.md\".\n kind? \"notify\" | \"validation\" | \"decision\" | \"context\" | \"error\"\n // display hint for inbox icon/sort weight.\n // No other values accepted.\n options Option[] // 2–4 options recommended (see humanloop)\n allowFreetext? boolean\n freetextLabel? string\n\n Option:\n id string (required)\n label string (required)\n description? string\n shortcut? string\n\nOUTPUT\n On answer, stdout is one line of JSON:\n { \"responses\": [{ \"id\", \"selectedOptionId\"?, \"freetext\"? }, ...], \"completedAt\" }\n Branch on each response by its interaction \\`id\\`.\n\nValidation errors at submit are precise — read them, don't guess.\n`)\n .action(async (file: string | undefined, opts: { session?: string }) => {\n if (!file) {\n ask.help();\n return;\n }\n await submit(file, opts);\n });\n\n ask\n .command('poll <askId>')\n .description('Block until <askId> is answered, then print output JSON')\n .option('--session <id>', 'Session id (defaults to SISYPHUS_SESSION_ID)')\n .action(async (askId: string, opts: { session?: string }) => poll(askId, opts));\n\n ask\n .command('peek <askId>')\n .description('Print {askId, status, completedAt?, output?} for <askId> without blocking')\n .option('--session <id>', 'Session id (defaults to SISYPHUS_SESSION_ID)')\n .action(async (askId: string, opts: { session?: string }) => peek(askId, opts));\n}\n\nfunction mintAskId(): string {\n return ulid();\n}\n\nfunction resolveClaudeSessionId(cwd: string, sessionId: string, askedBy: string): string | undefined {\n if (!existsSync(statePath(cwd, sessionId))) return undefined;\n const session = state.getSession(cwd, sessionId);\n if (askedBy === ORCHESTRATOR_ASKED_BY) {\n const last = session.orchestratorCycles[session.orchestratorCycles.length - 1];\n return last?.claudeSessionId;\n }\n return session.agents.find(a => a.id === askedBy)?.claudeSessionId;\n}\n\nfunction resolveSessionEnv(opts: { session?: string }): { cwd: string; sessionId: string } {\n const sessionId = opts.session ?? process.env.SISYPHUS_SESSION_ID;\n const cwd = process.env.SISYPHUS_CWD ?? process.cwd();\n if (!sessionId) {\n console.error('Error: provide --session or set SISYPHUS_SESSION_ID');\n process.exit(1);\n }\n return { cwd, sessionId };\n}\n\n/**\n * Idempotently mark an ask answered: stamp meta.completedAt, emit `ask-answered`,\n * and credit `userBlockedMs` on the session/cycle if the ask was blocking.\n * Re-entrant: the `meta.completedAt` check ensures only the first observer credits the wait.\n */\nasync function markAnswered(cwd: string, sessionId: string, askId: string): Promise<void> {\n const meta = readMeta(cwd, sessionId, askId);\n if (!meta || meta.completedAt) return;\n\n const completedAt = new Date().toISOString();\n const durationMs = new Date(completedAt).getTime() - new Date(meta.askedAt).getTime();\n\n try {\n await updateMeta(cwd, sessionId, askId, { status: 'answered', completedAt });\n } catch {\n // updateMeta throws if the meta file vanished mid-flight; treat as best-effort.\n return;\n }\n\n emitHistoryEvent(sessionId, 'ask-answered', {\n askId,\n askedBy: meta.askedBy,\n blocking: meta.blocking,\n durationMs,\n askedAt: meta.askedAt,\n completedAt,\n });\n\n if (meta.blocking && durationMs > 0) {\n try {\n if (existsSync(statePath(cwd, sessionId))) {\n await state.incrementUserBlockedMs(cwd, sessionId, durationMs, meta.askedAt, meta.askedBy);\n }\n } catch {\n // State increment is best-effort — history event is the source of truth for autopsy.\n }\n }\n}\n\nfunction waitForOutput(cwd: string, sessionId: string, askId: string, initialPpid?: number): Promise<AskOutput> {\n const outputPath = askOutputPath(cwd, sessionId, askId);\n\n if (existsSync(outputPath)) {\n return Promise.resolve(JSON.parse(readFileSync(outputPath, 'utf-8')) as AskOutput);\n }\n\n return new Promise((res, _rej) => {\n let ppidWatcher: ReturnType<typeof setInterval> | undefined;\n\n const cleanup = () => {\n unwatchFile(outputPath, onChange);\n if (ppidWatcher !== undefined) clearInterval(ppidWatcher);\n process.removeListener('SIGINT', onSigint);\n };\n\n const onChange = () => {\n if (!existsSync(outputPath)) return;\n try {\n const out = JSON.parse(readFileSync(outputPath, 'utf-8')) as AskOutput;\n cleanup();\n res(out);\n } catch (err) {\n const code = (err as NodeJS.ErrnoException).code;\n if (code === 'ENOENT' || err instanceof SyntaxError) {\n // File disappeared mid-read or atomic rename not yet complete — next tick will retry\n return;\n }\n throw err;\n }\n };\n watchFile(outputPath, { interval: 250 }, onChange);\n\n if (initialPpid !== undefined && initialPpid !== 1) {\n ppidWatcher = setInterval(() => {\n if (process.ppid !== initialPpid || process.ppid === 1) {\n cleanup();\n process.exit(0);\n }\n }, 250);\n }\n\n const onSigint = () => {\n cleanup();\n process.exit(130);\n };\n process.once('SIGINT', onSigint);\n });\n}\n\n/**\n * Spawn a tmux pane next to the caller showing the deck so the user can answer\n * inline without leaving the agent's pane. The dashboard inbox remains a valid\n * second surface — both write through the same on-disk ask-store paths.\n *\n * No-op outside tmux, when the user opts out, or if the split fails (the\n * dashboard is still a valid answering surface, so we never want to break the\n * ask itself for a UX nicety).\n */\nfunction maybeSpawnAskPane(cwd: string, sessionId: string, askId: string): void {\n const callerPane = process.env.TMUX_PANE;\n if (!callerPane) return;\n if (process.env.SISYPHUS_DISABLE_ASK_PANE === '1') return;\n\n const tuiPath = join(import.meta.dirname, 'tui.js');\n const cmd = `node ${shellQuote(tuiPath)} --cwd ${shellQuote(cwd)} --session-id ${shellQuote(sessionId)} --ask ${shellQuote(askId)}`;\n\n // -d: don't auto-focus the new pane (caller stays focused)\n // -h: horizontal split (new pane sits to the right)\n // -t: target the caller's pane so the split is adjacent\n execSafe(`tmux split-window -d -h -t ${shellQuote(callerPane)} -c ${shellQuote(cwd)} ${shellQuote(cmd)}`);\n}\n\nasync function submit(file: string, opts: { session?: string }): Promise<void> {\n const { cwd, sessionId } = resolveSessionEnv(opts);\n const askedBy = process.env.SISYPHUS_AGENT_ID ?? ORCHESTRATOR_ASKED_BY;\n\n const deckPath = resolve(file);\n if (!existsSync(deckPath)) {\n console.error(`Error: deck file not found: ${deckPath}`);\n process.exit(1);\n }\n\n let decisions;\n try {\n decisions = parseDeck(deckPath);\n } catch (err) {\n console.error(`Error: ${(err as Error).message}`);\n process.exit(1);\n }\n\n const initialPpid = process.ppid;\n const claudeSessionId = resolveClaudeSessionId(cwd, sessionId, askedBy);\n const askId = mintAskId();\n\n const q0 = decisions.interactions[0];\n createAsk(cwd, sessionId, {\n askId,\n askedBy,\n blocking: true,\n pid: process.pid,\n claudeSessionId,\n cwd,\n title: decisions.title !== undefined ? decisions.title : q0?.title,\n subtitle: q0?.subtitle,\n kind: q0?.kind,\n });\n writeDecisions(cwd, sessionId, askId, decisions);\n\n maybeSpawnAskPane(cwd, sessionId, askId);\n\n const output = await waitForOutput(cwd, sessionId, askId, initialPpid);\n await markAnswered(cwd, sessionId, askId);\n process.stdout.write(JSON.stringify(output) + '\\n');\n}\n\nasync function poll(askId: string, opts: { session?: string }): Promise<void> {\n validateAskId(askId);\n const { cwd, sessionId } = resolveSessionEnv(opts);\n const meta = readMeta(cwd, sessionId, askId);\n if (!meta) {\n console.error(`Error: askId not found: ${askId}`);\n process.exit(1);\n }\n const output = await waitForOutput(cwd, sessionId, askId);\n await markAnswered(cwd, sessionId, askId);\n process.stdout.write(JSON.stringify(output) + '\\n');\n}\n\nasync function peek(askId: string, opts: { session?: string }): Promise<void> {\n validateAskId(askId);\n const { cwd, sessionId } = resolveSessionEnv(opts);\n const meta = readMeta(cwd, sessionId, askId);\n if (!meta) {\n process.stdout.write(JSON.stringify({ askId, status: 'not-found' satisfies AskStatus }) + '\\n');\n return;\n }\n const outputPath = askOutputPath(cwd, sessionId, askId);\n const result: { askId: string; status: AskStatus; completedAt?: string; output?: AskOutput } = {\n askId,\n status: meta.status,\n };\n if (meta.completedAt) result.completedAt = meta.completedAt;\n try {\n if (existsSync(outputPath)) {\n result.output = JSON.parse(readFileSync(outputPath, 'utf-8')) as AskOutput;\n }\n } catch (err) {\n if (!(err instanceof SyntaxError)) throw err;\n // output.json mid-write (atomic rename in progress); leave output key absent\n }\n process.stdout.write(JSON.stringify(result) + '\\n');\n}\n","import { spawnSync } from 'node:child_process';\nimport { existsSync, lstatSync, readFileSync, realpathSync } from 'node:fs';\nimport { dirname, resolve, sep } from 'node:path';\nimport { z } from 'zod';\nimport type { Deck } from './types.js';\n\n// ── zod v4 building blocks ────────────────────────────────────────────────────\n// v4 notes: .nonempty() → .min(1); error messages use {error: 'string'} per check.\n\nexport const interactionOptionSchema = z.object({\n id: z.string().min(1),\n label: z.string().min(1),\n description: z.string().optional(),\n shortcut: z.string().optional(),\n});\n\nconst interactionSchema = z.object({\n id: z.string().regex(/^[A-Za-z0-9_-]+$/, { error: 'interaction id must match /^[A-Za-z0-9_-]+$/' }).min(1).max(64),\n title: z.string().min(1, { error: 'title must be non-empty' }),\n subtitle: z.string().min(1, { error: 'subtitle must be non-empty when present' }).optional(),\n body: z.string().optional(),\n bodyPath: z.string().optional(),\n options: z.array(interactionOptionSchema),\n allowFreetext: z.boolean().optional(),\n freetextLabel: z.string().optional(),\n kind: z.enum(['notify', 'validation', 'decision', 'context', 'error']).optional(),\n});\n\nconst deckSourceSchema = z.object({\n sessionName: z.string().optional(),\n askedBy: z.string().optional(),\n blockedSince: z.string().optional(),\n});\n\nexport const deckSchema = z.object({\n title: z.string().optional(),\n source: deckSourceSchema.optional(),\n interactions: z.array(interactionSchema).min(1, { error: 'interactions[] must be non-empty' }),\n}).superRefine((input, ctx) => {\n const seen = new Map<string, number>();\n for (let i = 0; i < input.interactions.length; i++) {\n const interaction = input.interactions[i];\n if (interaction.body !== undefined && interaction.bodyPath !== undefined) {\n ctx.addIssue({\n code: 'custom',\n message: 'body and bodyPath are mutually exclusive',\n path: ['interactions', i],\n });\n }\n const prev = seen.get(interaction.id);\n if (prev !== undefined) {\n ctx.addIssue({\n code: 'custom',\n message: `duplicate interaction id \"${interaction.id}\" at indices ${prev} and ${i}`,\n path: ['interactions', i, 'id'],\n });\n }\n seen.set(interaction.id, i);\n }\n});\n\n// ── termrender invocation ─────────────────────────────────────────────────────\nfunction runTermrenderCheck(content: string): { ok: true } | { ok: false; error: string } {\n const result = spawnSync('termrender', ['--check'], {\n input: content,\n encoding: 'utf-8',\n timeout: 5000,\n });\n if (result.error) {\n return { ok: false, error: `termrender invocation failed: ${result.error.message}` };\n }\n if (result.status !== 0) {\n return { ok: false, error: `termrender --check exited ${result.status}: ${result.stderr.trim()}` };\n }\n return { ok: true };\n}\n\n// ── C2 bodyPath defense + inlining ────────────────────────────────────────────\nfunction inlineBodyPath(deckPath: string, bodyPath: string): string {\n const deckDir = dirname(deckPath);\n const joined = resolve(deckDir, bodyPath);\n\n // STEP 1: existence + lstat BEFORE realpath to catch symlinks and directories.\n if (!existsSync(joined)) {\n throw new Error(\n `bodyPath does not exist: '${bodyPath}' (resolved against deck dir '${deckDir}'). bodyPath is interpreted relative to the deck JSON's directory; place the body file there and use a relative path (e.g. \"completion-summary.md\").`,\n );\n }\n const stat = lstatSync(joined);\n if (!stat.isFile()) {\n // Catches symlinks, directories, FIFOs — lstat does not follow symlinks.\n throw new Error(`bodyPath must be a regular file (not a symlink, directory, or special file): ${bodyPath}`);\n }\n\n // STEP 2: realpath both sides, prefix-check (defense-in-depth for .. traversal).\n // realpathSync is safe here: lstat already confirmed the path exists.\n const realResolved = realpathSync(joined);\n const realDeckDir = realpathSync(deckDir);\n const prefix = realDeckDir + sep;\n if (realResolved !== realDeckDir && !realResolved.startsWith(prefix)) {\n throw new Error(\n `bodyPath '${bodyPath}' escapes the deck's directory ('${realDeckDir}'). bodyPath is resolved relative to the deck JSON file and must stay inside its directory (no '..', absolute paths pointing elsewhere, or symlinks out). Fix: write the deck JSON next to the body file (e.g. both inside $SISYPHUS_SESSION_DIR/context/) and use a relative path like \"completion-summary.md\".`,\n );\n }\n\n // STEP 3: read. lstat confirmed regular file; realpath confirmed in-tree.\n return readFileSync(joined, 'utf-8');\n}\n\n// ── public entry point ────────────────────────────────────────────────────────\nexport function parseDeck(deckPath: string): Deck {\n const raw = readFileSync(deckPath, 'utf-8');\n let json: unknown;\n try {\n json = JSON.parse(raw);\n } catch {\n throw new Error('deck is not valid JSON');\n }\n\n const parsed = deckSchema.parse(json);\n\n const inlinedInteractions = parsed.interactions.map(interaction => {\n let body = interaction.body;\n if (interaction.bodyPath !== undefined) {\n body = inlineBodyPath(deckPath, interaction.bodyPath);\n }\n if (body !== undefined) {\n const check = runTermrenderCheck(body);\n if (!check.ok) {\n throw new Error(check.error);\n }\n }\n // Drop bodyPath from persisted decisions.json (recipe §1.8).\n const { bodyPath: _drop, ...rest } = interaction;\n return body !== undefined ? { ...rest, body } : { ...rest };\n });\n\n return { ...parsed, interactions: inlinedInteractions };\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';\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 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 { 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 { 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","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\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\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 { 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 { 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 { 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 { Command } from 'commander';\nimport { sendRequest } from '../client.js';\nimport type { Request } from '../../shared/protocol.js';\n\nexport function registerKill(program: Command): void {\n program\n .command('kill <sessionId>')\n .description('Kill a running session and all its agents')\n .action(async (sessionId: string) => {\n const request: Request = { type: 'kill', sessionId };\n const response = await sendRequest(request);\n if (response.ok) {\n console.log(`Session ${sessionId} killed.`);\n if (response.data) {\n const { killedAgents } = response.data as { killedAgents: number };\n console.log(`Cleaned up: ${killedAgents} agent(s) killed, tmux window removed.`);\n }\n } else {\n console.error(`Error: ${response.error}`);\n process.exit(1);\n }\n });\n}\n","import type { Command } from 'commander';\nimport { sendRequest } from '../client.js';\nimport type { Request } from '../../shared/protocol.js';\n\nexport function registerDelete(program: Command): void {\n program\n .command('delete <sessionId>')\n .description('Delete a session and all its data')\n .option('--cwd <path>', 'Project directory', process.env.SISYPHUS_CWD || process.cwd())\n .action(async (sessionId: string, opts: { cwd: string }) => {\n const request: Request = { type: 'delete', sessionId, cwd: opts.cwd };\n const response = await sendRequest(request);\n if (response.ok) {\n console.log(`Session ${sessionId} deleted.`);\n } else {\n console.error(`Error: ${response.error}`);\n process.exit(1);\n }\n });\n}\n","import type { Command } from 'commander';\nimport { sendRequest } from '../client.js';\nimport { readStdin } from '../stdin.js';\nimport type { Request } from '../../shared/protocol.js';\n\nexport function registerResume(program: Command): void {\n program\n .command('resume')\n .description('Respawn orchestrator with new instructions (for paused/completed sessions)')\n .addHelpText('after', '\\n Use `resume` to restart a paused or completed session with new instructions.\\n Use `continue` to keep working on a completed session without new instructions.\\n')\n .argument('<session-id>', 'Session ID to resume')\n .argument('[message]', 'Additional instructions for the orchestrator (omit when using --stdin)')\n .option('--stdin', 'Read message from stdin (avoids shell escaping for long prompts)')\n .action(async (sessionId: string, messageArg: string | undefined, opts: { stdin?: boolean }) => {\n const cwd = process.env['SISYPHUS_CWD'] ?? process.cwd();\n\n let message: string | undefined = messageArg;\n if (opts.stdin) {\n const piped = await readStdin({ force: true });\n if (!piped) {\n console.error('Error: --stdin set but no input received on stdin');\n process.exit(1);\n }\n if (messageArg !== undefined && messageArg !== '-') {\n console.error('Error: --stdin conflicts with [message] argument; pass one source');\n process.exit(1);\n }\n message = piped;\n } else if (messageArg === '-') {\n const piped = await readStdin({ force: true });\n if (!piped) {\n console.error(\"Error: message '-' means read stdin, but no input received\");\n process.exit(1);\n }\n message = piped;\n }\n\n const request: Request = { type: 'resume', sessionId, cwd, message };\n const response = await sendRequest(request);\n if (response.ok) {\n const tmuxSessionName = response.data?.tmuxSessionName as string | undefined;\n console.log(`Session ${sessionId} resumed`);\n if (tmuxSessionName) {\n console.log(`Tmux session: ${tmuxSessionName}`);\n console.log(` tmux attach -t ${tmuxSessionName}`);\n }\n } else {\n console.error(`Error: ${response.error}`);\n process.exit(1);\n }\n });\n}\n","import type { Command } from 'commander';\nimport { sendRequest } from '../client.js';\nimport type { Request } from '../../shared/protocol.js';\nimport { assertTmux } from '../tmux.js';\n\nexport function registerContinue(program: Command): void {\n program\n .command('continue')\n .description('Clear roadmap and continue working on a completed session (stays in current cycle)')\n .addHelpText('after', '\\n Use `continue` when a session completed but you want to add more work.\\n Use `resume` when you want to restart with specific new instructions.\\n')\n .option('--session <sessionId>', 'Session ID (defaults to SISYPHUS_SESSION_ID env var)')\n .action(async (opts: { session?: string }) => {\n assertTmux();\n const sessionId = opts.session ?? process.env.SISYPHUS_SESSION_ID;\n if (!sessionId) {\n console.error('Error: provide --session or set SISYPHUS_SESSION_ID environment variable');\n process.exit(1);\n }\n\n const request: Request = { type: 'continue', sessionId };\n const response = await sendRequest(request);\n if (response.ok) {\n console.log('Session reactivated. Roadmap cleared.');\n console.log('\\nThe previous roadmap has been wiped — you are starting fresh.');\n console.log('Consider writing a new roadmap before spawning agents.');\n } else {\n console.error(`Error: ${response.error}`);\n process.exit(1);\n }\n });\n}\n","import type { Command } from 'commander';\nimport { sendRequest } from '../client.js';\nimport type { Request } from '../../shared/protocol.js';\nimport { assertTmux } from '../tmux.js';\n\nexport function registerComplete(program: Command): void {\n program\n .command('complete')\n .description('Mark session as completed (orchestrator only)')\n .requiredOption('--report <report>', 'Final completion report')\n .option('--session <sessionId>', 'Session ID (defaults to SISYPHUS_SESSION_ID env var)')\n .action(async (opts: { report: string; session?: string }) => {\n assertTmux();\n const sessionId = opts.session ?? process.env.SISYPHUS_SESSION_ID;\n if (!sessionId) {\n console.error('Error: provide --session or set SISYPHUS_SESSION_ID environment variable');\n process.exit(1);\n }\n\n const request: Request = { type: 'complete', sessionId, report: opts.report };\n const response = await sendRequest(request);\n if (response.ok) {\n console.log('Session completed.');\n console.log(`\\nTo keep working in this session:`);\n console.log(` sis session continue # reactivate session and clear roadmap for new work`);\n } else {\n console.error(`Error: ${response.error}`);\n process.exit(1);\n }\n });\n}\n","import type { Command } from 'commander';\nimport { sendRequest } from '../client.js';\nimport type { Request } from '../../shared/protocol.js';\n\nexport function registerRollback(program: Command): void {\n program\n .command('rollback <sessionId> <cycle>')\n .description('Roll back a session to a previous cycle boundary')\n .action(async (sessionId: string, cycleStr: string) => {\n const toCycle = parseInt(cycleStr, 10);\n if (isNaN(toCycle) || toCycle < 1) {\n console.error('Error: cycle must be a positive integer');\n process.exit(1);\n }\n\n const cwd = process.env['SISYPHUS_CWD'] ?? process.cwd();\n const request: Request = { type: 'rollback', sessionId, cwd, toCycle };\n const response = await sendRequest(request);\n if (response.ok) {\n const data = response.data as { restoredToCycle: number };\n console.log(`Session ${sessionId} rolled back to cycle ${data.restoredToCycle}.`);\n console.log(`Session is now paused. Use 'sis session resume ${sessionId}' to respawn the orchestrator.`);\n } else {\n console.error(`Error: ${response.error}`);\n process.exit(1);\n }\n });\n}\n","import type { Command } from 'commander';\nimport { sendRequest } from '../client.js';\nimport type { Request } from '../../shared/protocol.js';\n\nexport function registerReconnect(program: Command): void {\n program\n .command('reconnect')\n .description('Reconnect daemon to an orphaned tmux session (no state change, no orchestrator spawn)')\n .argument('<session-id>', 'Session ID to reconnect')\n .action(async (sessionId: string) => {\n const cwd = process.env['SISYPHUS_CWD'] ?? process.cwd();\n const request: Request = { type: 'reconnect', sessionId, cwd };\n const response = await sendRequest(request);\n if (response.ok) {\n const tmuxSessionName = response.data?.tmuxSessionName as string;\n const tmuxWindowId = response.data?.tmuxWindowId as string;\n console.log(`Reconnected to ${tmuxSessionName} (window ${tmuxWindowId})`);\n } else {\n console.error(`Error: ${response.error}`);\n process.exit(1);\n }\n });\n}\n","import type { Command } from 'commander';\nimport { sendRequest } from '../client.js';\nimport type { Request } from '../../shared/protocol.js';\nimport { assertTmux } from '../tmux.js';\n\nexport function registerClone(program: Command): void {\n program\n .command('clone')\n .description('Clone the current session into a new independent session with a different goal')\n .argument('<goal>', 'Goal for the cloned session')\n .option('-c, --context <text>', 'Additional context for the clone')\n .option('--strategy', 'Copy strategy.md from the source session')\n .option('-n, --name <name>', 'Name for the cloned session')\n .action(async (goal: string, opts: { context?: string; strategy?: boolean; name?: string }) => {\n assertTmux();\n\n const sessionId = process.env.SISYPHUS_SESSION_ID;\n if (!sessionId) {\n console.error('Error: SISYPHUS_SESSION_ID not set. Run this from an orchestrator or agent pane.');\n process.exit(1);\n }\n\n const agentId = process.env.SISYPHUS_AGENT_ID;\n if (agentId !== 'orchestrator') {\n console.error('Error: clone can only be called by the orchestrator. Use sis message to ask the orchestrator to clone.');\n process.exit(1);\n }\n\n const request: Request = {\n type: 'clone',\n sessionId,\n goal,\n context: opts.context,\n name: opts.name,\n strategy: opts.strategy,\n };\n\n const response = await sendRequest(request);\n if (response.ok) {\n const data = response.data as { sessionId: string; tmuxSessionName: string };\n console.log('Session cloned successfully.');\n console.log(` Clone: ${data.sessionId}`);\n console.log(` Tmux: ${data.tmuxSessionName}`);\n console.log('');\n console.log(`The cloned session now owns: \"${goal}\"`);\n console.log('This is the other session\\'s responsibility. You do not need to monitor it.');\n console.log('');\n console.log('Update your scope:');\n console.log('- Remove cloned work from goal.md');\n console.log('- Update roadmap.md to reflect reduced scope');\n console.log('- Update strategy.md if approach changes');\n } else {\n console.error(`Error: ${response.error}`);\n process.exit(1);\n }\n });\n}\n","import type { Command } from 'commander';\nimport { sendRequest } from '../client.js';\nimport type { Request } from '../../shared/protocol.js';\n\nexport function registerSessionTask(program: Command): void {\n program\n .command('task <task>')\n .description('Update the session task/goal')\n .option('--session <sessionId>', 'Session ID (defaults to SISYPHUS_SESSION_ID env var)')\n .action(async (task: string, opts: { session?: string }) => {\n const sessionId = opts.session ?? process.env.SISYPHUS_SESSION_ID;\n if (!sessionId) {\n console.error('Error: provide --session or set SISYPHUS_SESSION_ID environment variable');\n process.exit(1);\n }\n\n const request: Request = { type: 'update-task', sessionId, task };\n const response = await sendRequest(request);\n if (response.ok) {\n console.log('Task updated');\n } else {\n console.error(`Error: ${response.error}`);\n process.exit(1);\n }\n });\n}\n","import type { Command } from 'commander';\nimport { sendRequest } from '../client.js';\nimport type { Request } from '../../shared/protocol.js';\n\nconst VALID_TIERS = ['low', 'medium', 'high', 'xhigh'] as const;\ntype EffortTier = typeof VALID_TIERS[number];\n\nexport function registerSessionEffort(program: Command): void {\n program\n .command('effort <sessionId> <tier>')\n .description('Set the pipeline effort tier for a session (future cycles only; running agents keep their original prompt)')\n .action(async (sessionId: string, tier: string) => {\n if (!VALID_TIERS.includes(tier as EffortTier)) {\n console.error(`Error: tier must be one of: ${VALID_TIERS.join(', ')}`);\n process.exit(1);\n }\n\n const request: Request = { type: 'set-effort', sessionId, effort: tier as EffortTier };\n const response = await sendRequest(request);\n if (response.ok) {\n console.log(`Effort tier set to '${tier}' for session ${sessionId}`);\n console.log('Note: Future cycles only — running agents keep their original prompt.');\n } else {\n console.error(`Error: ${response.error}`);\n process.exit(1);\n }\n });\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 function buildCompanionContext(cwd: string): string {\n let sessionDirs: string[];\n try {\n sessionDirs = readdirSync(sessionsDir(cwd));\n } catch {\n return '<sessions>No sessions found.</sessions>';\n }\n\n const now = Date.now();\n const sevenDaysMs = 7 * 24 * 60 * 60 * 1000;\n const sessionBlocks: string[] = [];\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 // Skip completed sessions older than 7 days\n if (session.status === 'completed' && session.completedAt) {\n if (now - new Date(session.completedAt).getTime() > sevenDaysMs) continue;\n }\n\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 // Agent summary by status\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 // Goal: first meaningful line\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 // Roadmap unchecked todos (up to 5)\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 sessionBlocks.push(lines.join('\\n'));\n }\n\n if (sessionBlocks.length === 0) {\n return '<sessions>No sessions found.</sessions>';\n }\n\n return ['<sessions>', ...sessionBlocks, '</sessions>'].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 { 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 type { Command } from 'commander';\nimport { sendRequest } from '../client.js';\nimport type { Request } from '../../shared/protocol.js';\nimport type { Session } from '../../shared/types.js';\nimport { buildSessionContext } from '../../tui/lib/context.js';\n\nexport function registerSessionContext(program: Command): void {\n program\n .command('context <sessionId>')\n .description('Print session context XML (same as dashboard space y C)')\n .requiredOption('--cwd <path>', 'Working directory of the session')\n .action(async (sessionId: string, opts: { cwd: string }) => {\n const request: Request = { type: 'status', sessionId, cwd: opts.cwd };\n const response = await sendRequest(request);\n if (!response.ok) {\n console.error(`Error: ${response.error}`);\n process.exit(1);\n }\n const session = response.data?.session as Session | undefined;\n if (!session) {\n console.error('Error: Session not found');\n process.exit(1);\n }\n process.stdout.write(buildSessionContext(session, opts.cwd));\n });\n}\n","import type { Command } from 'commander';\nimport { existsSync } from 'node:fs';\nimport { join, resolve } from 'node:path';\nimport { sendRequest } from '../client.js';\nimport type { Request } from '../../shared/protocol.js';\nimport { readStdin } from '../stdin.js';\nimport { assertTmux } from '../tmux.js';\nimport { discoverAgentTypes } from '../../daemon/frontmatter.js';\n\nfunction listTypes(): void {\n const cwd = process.env['SISYPHUS_CWD'] ?? process.cwd();\n const pluginDir = resolve(import.meta.dirname, '..', 'templates', 'agent-plugin');\n const types = discoverAgentTypes(pluginDir, cwd);\n\n if (types.length === 0) {\n console.log('No agent types found.');\n return;\n }\n\n const maxName = Math.max(...types.map(t => t.qualifiedName.length), 4);\n const maxSource = Math.max(...types.map(t => t.source.length), 6);\n\n console.log(`${'TYPE'.padEnd(maxName)} ${'SOURCE'.padEnd(maxSource)} DESCRIPTION`);\n for (const t of types) {\n const desc = t.description ?? '';\n console.log(`${t.qualifiedName.padEnd(maxName)} ${t.source.padEnd(maxSource)} ${desc}`);\n }\n}\n\nexport function registerSpawn(program: Command): void {\n program\n .command('spawn')\n .description('Spawn a new agent (orchestrator only)')\n .argument('[instruction]', 'Task instruction for the agent')\n .option('--agent-type <type>', 'Agent type (e.g. sisyphus:debug, sisyphus:explore)', 'worker')\n .option('--name <name>', 'Agent name')\n .option('--instruction <instruction>', 'Task instruction for the agent (or pipe via stdin)')\n .option('--stdin', 'Force-read instruction from stdin (avoids shell escaping for long prompts)')\n .option('--repo <name>', 'Repo subdirectory to use for this agent')\n .option('--session <sessionId>', 'Session ID (defaults to SISYPHUS_SESSION_ID env var)')\n .option('--list-types', 'List available agent types and exit')\n .action(async (positionalInstruction: string | undefined, opts: { agentType: string; name?: string; instruction?: string; stdin?: boolean; repo?: string; session?: string; listTypes?: boolean }) => {\n if (opts.listTypes) {\n listTypes();\n return;\n }\n\n if (!opts.name) {\n console.error('Error: required option --name <name> not specified');\n process.exit(1);\n }\n\n assertTmux();\n const sessionId = opts.session ?? process.env.SISYPHUS_SESSION_ID;\n if (!sessionId) {\n console.error('Error: provide --session or set SISYPHUS_SESSION_ID environment variable');\n process.exit(1);\n }\n\n const positional = positionalInstruction === '-' ? undefined : positionalInstruction;\n let instruction: string | null | undefined;\n if (opts.stdin) {\n instruction = await readStdin({ force: true });\n if (!instruction) {\n console.error('Error: --stdin set but no input received on stdin');\n process.exit(1);\n }\n if (opts.instruction || positional) {\n console.error('Error: --stdin conflicts with --instruction / [instruction]; pass one source');\n process.exit(1);\n }\n } else {\n instruction = opts.instruction ?? positional ?? await readStdin();\n }\n if (!instruction) {\n console.error('Error: --instruction is required (or pipe via stdin / use --stdin)');\n process.exit(1);\n }\n if (instruction.trim().length < 20) {\n console.error(`Error: instruction too short (${instruction.trim().length} chars). Did you mean to pipe via stdin? Use '-' as the positional or omit it entirely.`);\n process.exit(1);\n }\n\n const sisyphusCwd = process.env['SISYPHUS_CWD'] ?? process.cwd();\n\n if (opts.repo && (opts.repo.includes('/') || opts.repo.includes('..') || opts.repo.includes('\\\\'))) {\n console.error('Error: --repo must be a directory name, not a path');\n process.exit(1);\n }\n\n if (opts.repo && opts.repo !== '.') {\n const repoPath = join(sisyphusCwd, opts.repo);\n if (!existsSync(repoPath)) {\n console.error(`Error: repo directory does not exist: ${repoPath}`);\n process.exit(1);\n }\n }\n\n const request: Request = {\n type: 'spawn',\n sessionId,\n agentType: opts.agentType,\n name: opts.name,\n instruction,\n ...(opts.repo ? { repo: opts.repo } : {}),\n };\n const response = await sendRequest(request);\n if (response.ok) {\n const agentId = response.data?.agentId as string;\n console.log(`Agent spawned: ${agentId}`);\n console.log(`Tip: \\`sis agent await ${agentId}\\` blocks for the report and consumes it inline (won't appear in next cycle).`);\n console.log(\"Run `sis orch yield` when done spawning agents.\");\n } else {\n console.error(`Error: ${response.error}`);\n if (response.error?.includes(\"Unknown session\")) console.error(\"Hint: run `sis list` to see active sessions.\");\n process.exit(1);\n }\n });\n}\n","import { readFileSync, existsSync, readdirSync } from 'node:fs';\nimport { homedir } from 'node:os';\nimport { join, basename } from 'node:path';\nimport type { Provider } from '../shared/types.js';\nimport { projectAgentPluginDir, userAgentPluginDir } from '../shared/paths.js';\n\nexport interface AgentTypeFrontmatter {\n name?: string;\n model?: string;\n fallbackModel?: string;\n color?: string;\n description?: string;\n skills?: string[];\n plugins?: string[];\n permissionMode?: string;\n effort?: string;\n interactive?: boolean;\n systemPrompt?: 'append' | 'replace';\n}\n\nexport { type Provider } from '../shared/types.js';\n\nexport function detectProvider(model: string | undefined): Provider {\n if (!model) return 'anthropic';\n if (/^(gpt-|codex-)/.test(model)) return 'openai';\n return 'anthropic';\n}\n\nexport function parseAgentFrontmatter(content: string): AgentTypeFrontmatter {\n const match = content.match(/^---\\n([\\s\\S]*?)\\n---/);\n if (!match) return {};\n\n const block = match[1]!;\n const fm: AgentTypeFrontmatter = {};\n\n const str = (key: string): string | undefined => {\n const m = block.match(new RegExp(`^${key}:\\\\s*(.+)$`, 'm'));\n return m ? m[1]!.trim() : undefined;\n };\n\n fm.name = str('name');\n fm.model = str('model');\n fm.fallbackModel = str('fallbackModel');\n fm.color = str('color');\n fm.description = str('description');\n fm.permissionMode = str('permissionMode');\n fm.effort = str('effort');\n\n const interactive = str('interactive');\n if (interactive === 'true') fm.interactive = true;\n\n const systemPrompt = str('systemPrompt');\n if (systemPrompt === 'append' || systemPrompt === 'replace') fm.systemPrompt = systemPrompt;\n\n // Parse YAML lists (skills, plugins)\n for (const key of ['skills', 'plugins'] as const) {\n const listMatch = block.match(new RegExp(`^${key}:\\\\s*\\\\n((?:\\\\s+-\\\\s+.+\\\\n?)*)`, 'm'));\n if (listMatch) {\n (fm as Record<string, unknown>)[key] = listMatch[1]!\n .split('\\n')\n .map(line => line.replace(/^\\s+-\\s+/, '').trim())\n .filter(Boolean);\n }\n // Also support inline YAML array: plugins: [a, b]\n const inlineMatch = block.match(new RegExp(`^${key}:\\\\s*\\\\[([^\\\\]]+)\\\\]`, 'm'));\n if (inlineMatch && !(fm as Record<string, unknown>)[key]) {\n (fm as Record<string, unknown>)[key] = inlineMatch[1]!\n .split(',')\n .map(s => s.trim())\n .filter(Boolean);\n }\n }\n\n return fm;\n}\n\nexport function extractAgentBody(content: string): string {\n const match = content.match(/^---\\n[\\s\\S]*?\\n---\\n?([\\s\\S]*)$/);\n return match ? match[1]!.trim() : content.trim();\n}\n\nfunction findPluginInstallPath(namespace: string): string | null {\n try {\n const registryPath = join(homedir(), '.claude', 'plugins', 'installed_plugins.json');\n const registry = JSON.parse(readFileSync(registryPath, 'utf-8'));\n for (const key of Object.keys(registry)) {\n if (key.startsWith(`${namespace}@`)) {\n return registry[key].installPath ?? null;\n }\n }\n } catch {\n // File missing, parse error, or no match\n }\n return null;\n}\n\nexport function resolveAgentTypePath(agentType: string, pluginDir: string, cwd: string): string | null {\n if (!agentType) return null;\n\n let namespace: string | undefined;\n let name: string;\n\n if (agentType.includes(':')) {\n [namespace, name] = agentType.split(':', 2) as [string, string];\n } else {\n name = agentType;\n }\n\n const searchPaths: string[] = [];\n\n if (namespace) {\n // Bundled (handles sisyphus:* via pluginDir)\n searchPaths.push(join(pluginDir, 'agents', `${name}.md`));\n // Installed plugin\n const installPath = findPluginInstallPath(namespace);\n if (installPath) {\n searchPaths.push(join(installPath, 'agents', `${name}.md`));\n }\n } else {\n // Project-local sisyphus extension (carries hooks/skills, not just agent body)\n searchPaths.push(join(projectAgentPluginDir(cwd), 'agents', `${name}.md`));\n // User-global sisyphus extension\n searchPaths.push(join(userAgentPluginDir(), 'agents', `${name}.md`));\n // Project-local Claude convention\n searchPaths.push(join(cwd, '.claude', 'agents', `${name}.md`));\n // User-global Claude convention\n searchPaths.push(join(homedir(), '.claude', 'agents', `${name}.md`));\n // Bundled\n searchPaths.push(join(pluginDir, 'agents', `${name}.md`));\n }\n\n for (const path of searchPaths) {\n if (existsSync(path)) return path;\n }\n\n return null;\n}\n\nexport interface DiscoveredAgentType {\n qualifiedName: string;\n source: 'bundled' | 'plugin' | 'project' | 'user' | 'project-sis' | 'user-sis';\n description?: string;\n model?: string;\n}\n\nexport function discoverAgentTypes(pluginDir: string, cwd: string): DiscoveredAgentType[] {\n const seen = new Set<string>();\n const results: DiscoveredAgentType[] = [];\n\n function scanDir(dir: string, prefix: string | null, source: DiscoveredAgentType['source']): void {\n let files: string[];\n try {\n files = readdirSync(dir);\n } catch {\n return;\n }\n for (const file of files) {\n if (!file.endsWith('.md') || file === 'CLAUDE.md') continue;\n const name = basename(file, '.md');\n const qualifiedName = prefix ? `${prefix}:${name}` : name;\n if (seen.has(qualifiedName)) continue;\n seen.add(qualifiedName);\n\n try {\n const content = readFileSync(join(dir, file), 'utf-8');\n const fm = parseAgentFrontmatter(content);\n results.push({ qualifiedName, source, description: fm.description, model: fm.model });\n } catch {\n results.push({ qualifiedName, source });\n }\n }\n }\n\n // Priority order: project-sis > user-sis > project > user > bundled > plugins\n scanDir(join(projectAgentPluginDir(cwd), 'agents'), null, 'project-sis');\n scanDir(join(userAgentPluginDir(), 'agents'), null, 'user-sis');\n scanDir(join(cwd, '.claude', 'agents'), null, 'project');\n scanDir(join(homedir(), '.claude', 'agents'), null, 'user');\n scanDir(join(pluginDir, 'agents'), 'sisyphus', 'bundled');\n\n // Installed plugins (handles v1 flat and v2 nested formats)\n try {\n const registryPath = join(homedir(), '.claude', 'plugins', 'installed_plugins.json');\n const registry = JSON.parse(readFileSync(registryPath, 'utf-8'));\n const pluginEntries = registry.plugins ?? registry;\n for (const key of Object.keys(pluginEntries)) {\n const atIdx = key.indexOf('@');\n if (atIdx < 1) continue;\n const namespace = key.slice(0, atIdx);\n const entry = pluginEntries[key];\n const installPath = Array.isArray(entry) ? entry[0]?.installPath : entry?.installPath;\n if (installPath) {\n scanDir(join(installPath, 'agents'), namespace, 'plugin');\n }\n }\n } catch {\n // Registry missing or unparseable\n }\n\n return results;\n}\n\nexport interface ResolvedAgentConfig {\n frontmatter: AgentTypeFrontmatter;\n body: string;\n filePath: string;\n}\n\nexport function resolveAgentConfig(agentType: string, pluginDir: string, cwd: string): ResolvedAgentConfig | null {\n const filePath = resolveAgentTypePath(agentType, pluginDir, cwd);\n if (!filePath) return null;\n\n try {\n const content = readFileSync(filePath, 'utf-8');\n return {\n frontmatter: parseAgentFrontmatter(content),\n body: extractAgentBody(content),\n filePath,\n };\n } catch {\n return null;\n }\n}\n","import type { Command } from 'commander';\nimport { sendRequest } from '../client.js';\nimport type { Request } from '../../shared/protocol.js';\nimport { readStdin } from '../stdin.js';\nimport { assertTmux } from '../tmux.js';\n\nexport function registerSubmit(program: Command): void {\n program\n .command('submit')\n .description('Submit work report and exit (agent only)')\n .option('--report <report>', 'Work report (or pipe via stdin)')\n .option('--stdin', 'Force-read report from stdin (avoids shell escaping for long prompts)')\n .option('--session <sessionId>', 'Session ID (defaults to SISYPHUS_SESSION_ID env var)')\n .action(async (opts: { report?: string; stdin?: boolean; session?: string }) => {\n assertTmux();\n const sessionId = opts.session ?? process.env.SISYPHUS_SESSION_ID;\n const agentId = process.env.SISYPHUS_AGENT_ID;\n if (!sessionId || !agentId) {\n console.error('Error: provide --session or set SISYPHUS_SESSION_ID (and SISYPHUS_AGENT_ID) environment variables');\n process.exit(1);\n }\n\n let report: string | null | undefined;\n if (opts.stdin) {\n report = await readStdin({ force: true });\n if (!report) {\n console.error('Error: --stdin set but no input received on stdin');\n process.exit(1);\n }\n if (opts.report) {\n console.error('Error: --stdin conflicts with --report; pass one source');\n process.exit(1);\n }\n } else {\n report = opts.report ?? await readStdin();\n }\n if (!report) {\n console.error('Error: provide --report, pipe content via stdin, or use --stdin');\n process.exit(1);\n }\n\n const request: Request = { type: 'submit', sessionId, agentId, report };\n const response = await sendRequest(request);\n if (response.ok) {\n console.log('Report submitted successfully');\n console.log('Your pane will close. The orchestrator resumes when all agents finish.');\n } else {\n console.error(`Error: ${response.error}`);\n process.exit(1);\n }\n });\n}\n","import type { Command } from 'commander';\nimport { sendRequest } from '../client.js';\nimport type { Request } from '../../shared/protocol.js';\nimport { readStdin } from '../stdin.js';\nimport { assertTmux } from '../tmux.js';\n\nexport function registerReport(program: Command): void {\n program\n .command('report')\n .description('Send a progress report without exiting (agent only)')\n .option('--message <message>', 'Progress report content')\n .option('--stdin', 'Force-read message from stdin (avoids shell escaping for long prompts)')\n .option('--session <sessionId>', 'Session ID (defaults to SISYPHUS_SESSION_ID env var)')\n .action(async (opts: { message?: string; stdin?: boolean; session?: string }) => {\n assertTmux();\n const sessionId = opts.session ?? process.env.SISYPHUS_SESSION_ID;\n const agentId = process.env.SISYPHUS_AGENT_ID;\n if (!sessionId || !agentId) {\n console.error('Error: provide --session or set SISYPHUS_SESSION_ID (and SISYPHUS_AGENT_ID) environment variables');\n process.exit(1);\n }\n\n let content: string | null | undefined;\n if (opts.stdin) {\n content = await readStdin({ force: true });\n if (!content) {\n console.error('Error: --stdin set but no input received on stdin');\n process.exit(1);\n }\n if (opts.message) {\n console.error('Error: --stdin conflicts with --message; pass one source');\n process.exit(1);\n }\n } else {\n content = opts.message ?? await readStdin();\n }\n if (!content) {\n console.error('Error: provide --message, pipe content via stdin, or use --stdin');\n process.exit(1);\n }\n\n const request: Request = { type: 'report', sessionId, agentId, content };\n const response = await sendRequest(request);\n if (response.ok) {\n console.log('Progress report recorded');\n } else {\n console.error(`Error: ${response.error}`);\n process.exit(1);\n }\n });\n}\n","import type { Command } from 'commander';\nimport { existsSync, readFileSync } from 'node:fs';\nimport { sendRequest } from '../client.js';\nimport type { Request } from '../../shared/protocol.js';\nimport { assertTmux } from '../tmux.js';\n\n// Daemon-side handleAwait blocks until the agent reaches a terminal status.\n// Use a long socket timeout so realistic agent runtimes don't trip the default 10s.\nconst AWAIT_TIMEOUT_MS = 24 * 60 * 60 * 1000;\n\nexport function registerAwait(program: Command): void {\n program\n .command('await')\n .description('Block until an agent reaches a terminal status, then print its final report inline. Marks the agent as consumed-inline so its report is suppressed from the next cycle.')\n .argument('<agentId>', 'Agent ID to await')\n .option('--session <sessionId>', 'Session ID (defaults to SISYPHUS_SESSION_ID env var)')\n .action(async (agentId: string, opts: { session?: string }) => {\n assertTmux();\n const sessionId = opts.session ?? process.env.SISYPHUS_SESSION_ID;\n if (!sessionId) {\n console.error('Error: provide --session or set SISYPHUS_SESSION_ID environment variable');\n process.exit(1);\n }\n\n const request: Request = { type: 'await', sessionId, agentId };\n const response = await sendRequest(request, AWAIT_TIMEOUT_MS);\n if (!response.ok) {\n console.error(`Error: ${response.error}`);\n process.exit(1);\n }\n\n const data = response.data ?? {};\n const status = data.status as string;\n const reportPath = data.reportPath as string | null;\n const agentName = data.agentName as string;\n const agentType = data.agentType as string;\n\n const shortType = agentType && agentType !== 'worker' ? agentType.replace(/^sisyphus:/, '') : '';\n const label = shortType ? `${shortType}-${agentName}` : agentName;\n console.log(`[${status}] ${agentId} (${label})`);\n if (reportPath && existsSync(reportPath)) {\n try {\n const body = readFileSync(reportPath, 'utf-8');\n if (body.length > 0) {\n // Avoid double newline: file usually ends with \\n already.\n process.stdout.write(body.endsWith('\\n') ? body : body + '\\n');\n }\n } catch (err) {\n console.error(`Warning: could not read report at ${reportPath}: ${err instanceof Error ? err.message : err}`);\n }\n }\n });\n}\n","import type { Command } from 'commander';\nimport { sendRequest } from '../client.js';\nimport type { Request } from '../../shared/protocol.js';\n\nexport function registerAgentKill(program: Command): void {\n program\n .command('kill <agentId>')\n .description('Kill a running agent')\n .option('-s, --session <sessionId>', 'Session ID (defaults to SISYPHUS_SESSION_ID)')\n .action(async (agentId: string, opts: { session?: string }) => {\n const sessionId = opts.session ?? process.env.SISYPHUS_SESSION_ID;\n if (!sessionId) {\n console.error('Error: No session ID. Use --session or set SISYPHUS_SESSION_ID.');\n process.exit(1);\n }\n\n const request: Request = { type: 'kill-agent', sessionId, agentId };\n const response = await sendRequest(request);\n if (response.ok) {\n console.log(`Agent ${agentId} killed.`);\n } else {\n console.error(`Error: ${response.error}`);\n process.exit(1);\n }\n });\n}\n","import type { Command } from 'commander';\nimport { sendRequest } from '../client.js';\nimport type { Request } from '../../shared/protocol.js';\n\nexport function registerAgentRestart(program: Command): void {\n program\n .command('restart <agentId>')\n .description('Restart a failed/killed/lost agent in a new tmux pane')\n .option('-s, --session <sessionId>', 'Session ID (defaults to SISYPHUS_SESSION_ID)')\n .action(async (agentId: string, opts: { session?: string }) => {\n const sessionId = opts.session ?? process.env.SISYPHUS_SESSION_ID;\n if (!sessionId) {\n console.error('Error: No session ID. Use --session or set SISYPHUS_SESSION_ID.');\n process.exit(1);\n }\n\n const request: Request = { type: 'restart-agent', sessionId, agentId };\n const response = await sendRequest(request);\n if (response.ok) {\n console.log(`Agent ${agentId} restarted.`);\n } else {\n console.error(`Error: ${response.error}`);\n process.exit(1);\n }\n });\n}\n","import type { Command } from 'commander';\nimport { sendRequest } from '../client.js';\nimport type { Request } from '../../shared/protocol.js';\nimport { readStdin } from '../stdin.js';\nimport { assertTmux } from '../tmux.js';\n\nexport function registerYield(program: Command): void {\n program\n .command('yield')\n .description('Yield control back to daemon (orchestrator only)')\n .option('--prompt <text>', 'Short orienting nudge for the next cycle (or pipe via stdin) — name what just happened; leave tactical decisions to the fresh read of the reports')\n .option('--stdin', 'Force-read prompt from stdin (avoids shell escaping for long prompts)')\n .option('--mode <mode>', 'System prompt mode for next cycle (discovery, planning, implementation, validation, completion)')\n .option('--session <sessionId>', 'Session ID (defaults to SISYPHUS_SESSION_ID env var)')\n .action(async (opts: { prompt?: string; stdin?: boolean; mode?: string; session?: string }) => {\n assertTmux();\n const sessionId = opts.session ?? process.env.SISYPHUS_SESSION_ID;\n if (!sessionId) {\n console.error('Error: provide --session or set SISYPHUS_SESSION_ID environment variable');\n process.exit(1);\n }\n\n let nextPrompt: string | undefined;\n if (opts.stdin) {\n const piped = await readStdin({ force: true });\n if (!piped) {\n console.error('Error: --stdin set but no input received on stdin');\n process.exit(1);\n }\n if (opts.prompt) {\n console.error('Error: --stdin conflicts with --prompt; pass one source');\n process.exit(1);\n }\n nextPrompt = piped;\n } else {\n nextPrompt = opts.prompt ?? await readStdin() ?? undefined;\n }\n\n const request: Request = { type: 'yield', sessionId, agentId: 'orchestrator', nextPrompt, mode: opts.mode };\n const response = await sendRequest(request);\n if (response.ok) {\n console.log('Yielded. Waiting for agents to complete.');\n } else {\n console.error(`Error: ${response.error}`);\n process.exit(1);\n }\n });\n}\n","import type { Command } from 'commander';\nimport { sendRequest } from '../client.js';\nimport type { Request } from '../../shared/protocol.js';\n\nexport function registerSegmentRegister(program: Command): void {\n program\n .command('register')\n .description('Register or update an external status bar segment')\n .requiredOption('--id <id>', 'Segment identifier')\n .requiredOption('--side <side>', 'Side to render on: left or right')\n .requiredOption('--priority <n>', 'Priority (lower = further from center)', parseInt)\n .requiredOption('--bg <color>', 'Background hex color (e.g. #2d2f33)')\n .requiredOption('--content <content>', 'tmux format string content')\n .action(async (opts: { id: string; side: string; priority: number; bg: string; content: string }) => {\n if (opts.side !== 'left' && opts.side !== 'right') {\n console.error('Error: --side must be \"left\" or \"right\"');\n process.exit(1);\n }\n const request: Request = {\n type: 'register-segment',\n id: opts.id,\n side: opts.side as 'left' | 'right',\n priority: opts.priority,\n bg: opts.bg,\n content: opts.content,\n };\n const response = await sendRequest(request);\n if (response.ok) {\n console.log(`Segment '${opts.id}' registered.`);\n } else {\n console.error(`Error: ${response.error}`);\n process.exit(1);\n }\n });\n}\n","import type { Command } from 'commander';\nimport { sendRequest } from '../client.js';\nimport type { Request } from '../../shared/protocol.js';\n\nexport function registerSegmentUnregister(program: Command): void {\n program\n .command('unregister')\n .description('Remove an external status bar segment')\n .requiredOption('--id <id>', 'Segment identifier to remove')\n .action(async (opts: { id: string }) => {\n const request: Request = { type: 'unregister-segment', id: opts.id };\n const response = await sendRequest(request);\n if (response.ok) {\n console.log(`Segment '${opts.id}' unregistered.`);\n } else {\n console.error(`Error: ${response.error}`);\n process.exit(1);\n }\n });\n}\n","import { execSync } from 'node:child_process';\nimport type { Command } from 'commander';\nimport { runOnboarding, type OnboardResult } from '../onboard.js';\nimport { ensureDaemonInstalled, isInstalled } from '../install.js';\nimport { setupTmuxKeybind, DEFAULT_CYCLE_KEY, DEFAULT_PREFIX_KEY } from '../tmux-setup.js';\n\nfunction getTmuxVersion(): string {\n try {\n return execSync('tmux -V', { encoding: 'utf-8', stdio: 'pipe' }).trim();\n } catch {\n return 'installed';\n }\n}\n\nfunction printResults(result: OnboardResult, daemonOk: boolean, keybindMsg: string): void {\n console.log('');\n console.log('Setting up Sisyphus...');\n console.log('');\n\n // tmux\n if (result.tmuxInstalled) {\n const detail = getTmuxVersion();\n console.log(` \\u2713 tmux: ${detail}${result.tmuxAutoInstalled ? ' (just installed)' : ''}`);\n } else {\n const hint = process.platform === 'darwin'\n ? 'Install Homebrew (https://brew.sh) then: brew install tmux'\n : 'apt install tmux (Debian/Ubuntu) or your package manager';\n console.log(` \\u2717 tmux: Not installed \\u2014 ${hint}`);\n }\n\n // tmux config\n if (result.tmuxDefaultsWritten) {\n console.log(' \\u2713 tmux config: Sensible defaults written to ~/.tmux.conf');\n }\n\n // Terminal\n if (process.platform === 'darwin') {\n if (result.terminal.isIterm) {\n console.log(` \\u2713 Terminal: ${result.terminal.name}`);\n } else {\n const name = result.terminal.name ? result.terminal.name : 'unknown';\n console.log(` \\u26a0 Terminal: ${name} \\u2014 iTerm2 recommended (https://iterm2.com)`);\n }\n }\n\n // iTerm option key\n if (result.itermOptionKey.checked) {\n if (result.itermOptionKey.allCorrect) {\n console.log(' \\u2713 Right Option Key: Esc+');\n } else {\n const profiles = result.itermOptionKey.incorrectProfiles.map((p) => `\"${p}\"`).join(', ');\n console.log(` \\u26a0 Right Option Key: Not set to Esc+ for ${profiles}`);\n console.log(' Fix: iTerm2 \\u2192 Settings \\u2192 Profiles \\u2192 Keys \\u2192 Right Option Key \\u2192 Esc+');\n }\n }\n\n // Daemon\n if (daemonOk) {\n console.log(' \\u2713 Daemon: Running');\n } else {\n console.log(' \\u2717 Daemon: Failed to start');\n }\n\n // Keybindings\n console.log(` \\u2713 Keybindings: ${keybindMsg}`);\n\n // Session bar\n console.log(' \\u2713 Status bar: daemon-rendered via @sisyphus_left / @sisyphus_right');\n console.log(' status-left: #{E:@sisyphus_left}');\n console.log(' status-right: #{E:@sisyphus_right}');\n\n // Sisyphus user plugin (slash commands: /sisyphus:begin, /sisyphus:autopsy, /sisyphus:configure-upload)\n if (result.sisyphusPlugin.installed && result.sisyphusPlugin.installPath) {\n const suffix = result.sisyphusPlugin.autoInstalled ? ' (just installed)' : '';\n console.log(` \\u2713 sisyphus@sisyphus plugin: ${result.sisyphusPlugin.installPath}${suffix}`);\n } else {\n console.log(' \\u2717 sisyphus@sisyphus plugin: Failed to install (needs `claude` CLI)');\n }\n\n // Nvim\n if (result.nvim.installed) {\n const extra = result.nvim.autoInstalled ? ' (just installed)' : '';\n console.log(` \\u2713 Editor: nvim ${result.nvim.version}${extra}`);\n if (result.nvim.lazyVimInstalled) {\n console.log(' \\u2713 LazyVim: Starter config installed to ~/.config/nvim/');\n }\n if (result.nvim.baleiaInstalled) {\n console.log(' \\u2713 ANSI colors: baleia.nvim plugin configured (auto-detects escape codes)');\n }\n } else {\n console.log(' \\u26a0 Editor: nvim not installed');\n if (process.platform === 'darwin') {\n console.log(' Install: brew install neovim');\n }\n }\n\n console.log('');\n console.log(\"Run 'sis admin getting-started' for a usage guide.\");\n console.log('');\n}\n\nexport function registerSetup(program: Command): void {\n program\n .command('setup')\n .description('One-time setup: install dependencies, daemon, keybindings, and commands')\n .option('-y, --yes', 'Skip confirmation prompts (e.g. before modifying ~/.tmux.conf)')\n .action(async (opts: { yes?: boolean }) => {\n // 1. Onboarding (tmux, terminal, iterm, nvim, plugin)\n const result = runOnboarding();\n\n // 2. Daemon\n let daemonOk = false;\n try {\n await ensureDaemonInstalled();\n daemonOk = true;\n } catch {\n daemonOk = isInstalled();\n }\n\n // 3. Keybindings\n const keybindResult = await setupTmuxKeybind(\n DEFAULT_CYCLE_KEY,\n DEFAULT_PREFIX_KEY,\n { assumeYes: opts.yes },\n );\n let keybindMsg: string;\n if (keybindResult.status === 'installed' || keybindResult.status === 'already-installed') {\n keybindMsg = `${DEFAULT_CYCLE_KEY} cycle, ${DEFAULT_PREFIX_KEY} prefix (h=dashboard, x=kill)`;\n } else {\n keybindMsg = keybindResult.message;\n }\n\n printResults(result, daemonOk, keybindMsg);\n });\n}\n","import { execSync } from 'node:child_process';\nimport { existsSync, readFileSync, writeFileSync } from 'node:fs';\nimport { homedir } from 'node:os';\nimport { dirname, join } from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport { ensureSisyphusPluginInstalled, type SisyphusPluginInfo } from './plugins.js';\nimport { sisyphusTmuxConfPath } from './tmux-setup.js';\n\nexport interface TerminalInfo {\n name: string;\n isIterm: boolean;\n}\n\nexport interface ItermOptionKeyResult {\n checked: boolean;\n allCorrect: boolean;\n incorrectProfiles: string[];\n}\n\nexport interface NvimInfo {\n installed: boolean;\n autoInstalled: boolean;\n version: string;\n lazyVimInstalled: boolean;\n baleiaInstalled: boolean;\n}\n\nexport interface TermrenderInfo {\n installed: boolean;\n autoInstalled: boolean;\n}\n\nexport interface OnboardResult {\n tmuxInstalled: boolean;\n tmuxAutoInstalled: boolean;\n terminal: TerminalInfo;\n itermOptionKey: ItermOptionKeyResult;\n tmuxDefaultsWritten: boolean;\n nvim: NvimInfo;\n sisyphusPlugin: SisyphusPluginInfo;\n termrender: TermrenderInfo;\n}\n\nexport function detectTerminal(): TerminalInfo {\n const termProgram = process.env['TERM_PROGRAM'] || '';\n const isIterm = termProgram === 'iTerm.app' || !!process.env['ITERM_SESSION_ID'];\n return { name: termProgram || 'unknown', isIterm };\n}\n\nfunction isTmuxAvailable(): boolean {\n try {\n execSync('which tmux', { stdio: 'pipe' });\n return true;\n } catch {\n return false;\n }\n}\n\nfunction isBrewAvailable(): boolean {\n try {\n execSync('which brew', { stdio: 'pipe' });\n return true;\n } catch {\n return false;\n }\n}\n\nfunction tryAutoInstallTmux(): boolean {\n if (!isBrewAvailable()) return false;\n try {\n console.log(' Installing tmux via Homebrew...');\n execSync('brew install tmux', { stdio: 'inherit' });\n return isTmuxAvailable();\n } catch {\n return false;\n }\n}\n\nexport function checkItermOptionKey(): ItermOptionKeyResult {\n if (process.platform !== 'darwin') {\n return { checked: false, allCorrect: true, incorrectProfiles: [] };\n }\n\n const plistPath = join(homedir(), 'Library', 'Preferences', 'com.googlecode.iterm2.plist');\n if (!existsSync(plistPath)) {\n return { checked: false, allCorrect: false, incorrectProfiles: [] };\n }\n\n try {\n const json = execSync(\n `plutil -extract \"New Bookmarks\" json -o - \"${plistPath}\"`,\n { encoding: 'utf-8', stdio: ['pipe', 'pipe', 'pipe'] },\n );\n const profiles = JSON.parse(json) as Array<Record<string, unknown>>;\n const currentProfile = process.env['ITERM_PROFILE'];\n const incorrect: string[] = [];\n for (const profile of profiles) {\n const name = (profile['Name'] as string) || 'Unnamed';\n // Only check the current profile (or all if we can't detect which)\n if (currentProfile && name !== currentProfile) continue;\n // 0 = Normal, 1 = Meta, 2 = Esc+\n if (profile['Right Option Key Sends'] !== 2) {\n incorrect.push(name);\n }\n }\n return { checked: true, allCorrect: incorrect.length === 0, incorrectProfiles: incorrect };\n } catch {\n return { checked: false, allCorrect: false, incorrectProfiles: [] };\n }\n}\n\nfunction hasExistingTmuxConf(): boolean {\n return (\n existsSync(join(homedir(), '.tmux.conf')) ||\n existsSync(join(homedir(), '.config', 'tmux', 'tmux.conf'))\n );\n}\n\nconst SISYPHUS_DEFAULTS_MARKER = '# sisyphus-managed — do not edit';\n\nfunction buildTmuxDefaults(): string {\n const sisyphusConf = sisyphusTmuxConfPath();\n return `# Sensible tmux defaults (installed by sisyphus)\n# Customize freely — sisyphus won't overwrite this file.\n\n# Enable mouse (click panes, scroll, resize)\nset -g mouse on\n\n# Scrollback history\nset -g history-limit 100000\n\n# 256 color + true color support\nset -g default-terminal \"tmux-256color\"\nset -as terminal-overrides \",*:Tc\"\n\n# Low escape delay (keeps Option/Meta keybindings responsive)\nset -sg escape-time 10\n\n# Window numbering from 1\nset -g base-index 1\nsetw -g pane-base-index 1\n\n# Renumber windows when one closes\nset -g renumber-windows on\n\n# Clipboard integration\nset -g set-clipboard on\n\n# Focus events (for editors)\nset -g focus-events on\n\n# Don't detach the client when the last session is destroyed\nset -g detach-on-destroy off\n\n# Vim-style copy mode\nsetw -g mode-keys vi\nbind -T copy-mode-vi v send-keys -X begin-selection\nbind -T copy-mode-vi y send-keys -X copy-selection-and-cancel\n\n# --- Pane navigation (no prefix needed) ---\nbind -n C-h select-pane -L\nbind -n C-l select-pane -R\n\n# --- Window navigation (no prefix needed) ---\nbind -n C-n next-window\nbind -n C-p previous-window\n\n# --- Splits / new window / new session in current directory ---\nbind '\"' split-window -v -c \"#{pane_current_path}\"\nbind % split-window -h -c \"#{pane_current_path}\" \\\\; select-layout even-horizontal\nbind -n M-= split-window -h -c \"#{pane_current_path}\" \\\\; select-layout even-horizontal\nbind n new-window -c \"#{pane_current_path}\"\nbind N new-session -c \"#{pane_current_path}\"\n\n# --- Kill pane + rebalance ---\nbind x kill-pane \\\\; select-layout even-horizontal\nbind -n M-- kill-pane \\\\; select-layout even-horizontal\n\n# --- Auto-rebalance on pane close ---\nset-hook -g after-kill-pane \"select-layout even-horizontal\"\nset-hook -g pane-exited \"select-layout even-horizontal\"\n\n# --- Manual re-tile ---\nbind = select-layout even-horizontal\n\n# --- Resize panes (repeatable with prefix) ---\nbind -r H resize-pane -L 5\nbind -r J resize-pane -D 5\nbind -r K resize-pane -U 5\nbind -r L resize-pane -R 5\n\n# --- Reload config (prefix + Ctrl-r) ---\nbind C-r source-file ~/.tmux.conf \\\\; display \"Reloaded!\"\n\n# --- Half-page scroll (no prefix; -e exits copy mode at bottom) ---\nbind -n C-u copy-mode -e \\\\; send-keys -X halfpage-up\nbind -n C-d copy-mode -e \\\\; send-keys -X halfpage-down\n\n# --- Line scroll (no prefix; -e exits copy mode at bottom) ---\nbind -n C-k copy-mode -e \\\\; send -X scroll-up\nbind -n C-j copy-mode -e \\\\; send -X scroll-down\nbind -T copy-mode-vi C-k send -X scroll-up\nbind -T copy-mode-vi C-j send -X scroll-down\n\n# --- Status bar (gloam palette) ---\nset -g status on\nset -g status-style \"bg=#1d1e21,fg=#d4cbb8\"\nset -g status-position bottom\nset -g status-left \"#{E:@sisyphus_left}\"\nset -g status-left-length 250\nset -g status-right \"#{E:@sisyphus_right}#[fg=#2d2f33]#[bg=#2d2f33,fg=#b0a898] %H:%M \"\nset -g status-right-length 250\nset -g status-interval 2\n\n# Hide window list (session name on left + sisyphus pills on right cover it)\nset -g window-status-format \"\"\nset -g window-status-current-format \"\"\nset -g window-status-separator \"\"\n\n# --- Pane borders ---\nset -g pane-border-style fg=default\nset -g pane-active-border-style fg=green\n\n# Source the sisyphus-managed conf (C-s prefix menu, M-s session cycle)\n# -q so missing file is silent if sisyphus hasn't been set up yet\nsource-file -q ${sisyphusConf} ${SISYPHUS_DEFAULTS_MARKER}\n`;\n}\n\nfunction writeTmuxDefaults(): void {\n const confPath = join(homedir(), '.tmux.conf');\n writeFileSync(confPath, buildTmuxDefaults(), 'utf8');\n}\n\nexport function isNvimAvailable(): boolean {\n try {\n execSync('which nvim', { stdio: 'pipe' });\n return true;\n } catch {\n return false;\n }\n}\n\nfunction getNvimVersion(): string {\n try {\n return execSync('nvim --version', { encoding: 'utf-8', stdio: 'pipe' }).split('\\n')[0]?.replace('NVIM ', '') || 'unknown';\n } catch {\n return 'unknown';\n }\n}\n\nfunction hasLazyVimConfig(): boolean {\n return existsSync(join(homedir(), '.config', 'nvim', 'lazy-lock.json'));\n}\n\nfunction bundledBaleiaPluginPath(): string {\n const distDir = dirname(fileURLToPath(import.meta.url));\n return join(distDir, 'templates', 'baleia.lua');\n}\n\nfunction installBaleiaPlugin(): boolean {\n const pluginsDir = join(homedir(), '.config', 'nvim', 'lua', 'plugins');\n if (!existsSync(pluginsDir)) return false;\n\n const dest = join(pluginsDir, 'sisyphus-baleia.lua');\n if (existsSync(dest)) return true; // already installed\n\n const src = bundledBaleiaPluginPath();\n if (!existsSync(src)) return false;\n\n try {\n writeFileSync(dest, readFileSync(src, 'utf-8'), 'utf8');\n return true;\n } catch {\n return false;\n }\n}\n\nexport function tryAutoInstallNvim(): NvimInfo {\n if (isNvimAvailable()) {\n const baleiaInstalled = installBaleiaPlugin();\n return { installed: true, autoInstalled: false, version: getNvimVersion(), lazyVimInstalled: hasLazyVimConfig(), baleiaInstalled };\n }\n if (!isBrewAvailable()) {\n return { installed: false, autoInstalled: false, version: '', lazyVimInstalled: false, baleiaInstalled: false };\n }\n try {\n console.log(' Installing neovim via Homebrew...');\n execSync('brew install neovim', { stdio: 'inherit' });\n } catch {\n return { installed: false, autoInstalled: false, version: '', lazyVimInstalled: false, baleiaInstalled: false };\n }\n if (!isNvimAvailable()) {\n return { installed: false, autoInstalled: false, version: '', lazyVimInstalled: false, baleiaInstalled: false };\n }\n // Clone LazyVim starter config if no nvim config exists.\n // Neutralize global LFS filters and hooks — users with stale `git-lfs` config\n // (filter installed, binary missing) or broken `core.hooksPath` would otherwise\n // hit \"git-lfs: command not found\" or hook errors during clone.\n const nvimConfigDir = join(homedir(), '.config', 'nvim');\n let lazyVimInstalled = false;\n if (!existsSync(nvimConfigDir)) {\n const cloneCmd = [\n 'git',\n '-c core.hooksPath=/dev/null',\n '-c filter.lfs.smudge=cat',\n '-c filter.lfs.process=',\n '-c filter.lfs.required=false',\n 'clone --depth=1 https://github.com/LazyVim/starter',\n nvimConfigDir,\n ].join(' ');\n try {\n console.log(' Cloning LazyVim starter config...');\n execSync(cloneCmd, {\n stdio: 'inherit',\n env: { ...process.env, GIT_LFS_SKIP_SMUDGE: '1' },\n });\n const gitDir = join(nvimConfigDir, '.git');\n if (existsSync(gitDir)) {\n execSync(`rm -rf \"${gitDir}\"`, { stdio: 'pipe' });\n }\n lazyVimInstalled = true;\n } catch (err) {\n const detail = err instanceof Error && err.message ? err.message : String(err);\n console.warn(` ⚠ LazyVim starter clone failed: ${detail.split('\\n')[0]}`);\n console.warn(' nvim is installed; clone manually:');\n console.warn(` git clone https://github.com/LazyVim/starter ${nvimConfigDir}`);\n }\n }\n const baleiaInstalled = installBaleiaPlugin();\n return { installed: true, autoInstalled: true, version: getNvimVersion(), lazyVimInstalled, baleiaInstalled };\n}\n\nexport function isTermrenderAvailable(): boolean {\n try {\n execSync('which termrender', { stdio: 'pipe' });\n return true;\n } catch {\n return false;\n }\n}\n\nfunction isPipxAvailable(): boolean {\n try {\n execSync('which pipx', { stdio: 'pipe' });\n return true;\n } catch {\n return false;\n }\n}\n\nfunction isPipAvailable(): boolean {\n try {\n execSync('which pip3', { stdio: 'pipe' });\n return true;\n } catch {\n try {\n execSync('which pip', { stdio: 'pipe' });\n return true;\n } catch {\n return false;\n }\n }\n}\n\nfunction tryAutoInstallTermrender(): TermrenderInfo {\n if (isTermrenderAvailable()) {\n return { installed: true, autoInstalled: false };\n }\n // Prefer pipx (isolated install), fall back to pip\n if (isPipxAvailable()) {\n try {\n console.log(' Installing termrender via pipx...');\n execSync('pipx install termrender', { stdio: 'inherit' });\n if (isTermrenderAvailable()) return { installed: true, autoInstalled: true };\n } catch { /* fall through */ }\n }\n if (isPipAvailable()) {\n try {\n console.log(' Installing termrender via pip...');\n const pip = (() => { try { execSync('which pip3', { stdio: 'pipe' }); return 'pip3'; } catch { return 'pip'; } })();\n execSync(`${pip} install termrender`, { stdio: 'inherit' });\n if (isTermrenderAvailable()) return { installed: true, autoInstalled: true };\n } catch { /* fall through */ }\n }\n return { installed: false, autoInstalled: false };\n}\n\nexport function runOnboarding(): OnboardResult {\n const terminal = detectTerminal();\n const tmuxAlreadyInstalled = isTmuxAvailable();\n\n let tmuxInstalled = tmuxAlreadyInstalled;\n let tmuxAutoInstalled = false;\n let tmuxDefaultsWritten = false;\n\n // Auto-install tmux if missing\n if (!tmuxAlreadyInstalled && process.platform === 'darwin') {\n tmuxAutoInstalled = tryAutoInstallTmux();\n tmuxInstalled = tmuxAutoInstalled;\n\n // Write sensible defaults only for fresh tmux installs (don't touch existing configs)\n if (tmuxAutoInstalled && !hasExistingTmuxConf()) {\n writeTmuxDefaults();\n tmuxDefaultsWritten = true;\n }\n }\n\n // Check iTerm2 right option key\n let itermOptionKey: ItermOptionKeyResult = { checked: false, allCorrect: true, incorrectProfiles: [] };\n if (terminal.isIterm) {\n itermOptionKey = checkItermOptionKey();\n }\n\n // Nvim\n const nvim = tryAutoInstallNvim();\n\n // User-facing slash commands ship as a Claude Code plugin from the\n // `sisyphus@sisyphus` marketplace. Best-effort: failures warn but don't abort setup.\n const sisyphusPlugin = ensureSisyphusPluginInstalled();\n\n // termrender (markdown rendering for TUI)\n const termrender = tryAutoInstallTermrender();\n\n return { tmuxInstalled, tmuxAutoInstalled, terminal, itermOptionKey, tmuxDefaultsWritten, nvim, sisyphusPlugin, termrender };\n}\n\nexport function formatOnboardingMessages(result: OnboardResult): string[] {\n const lines: string[] = [];\n\n // Terminal recommendation (macOS only)\n if (process.platform === 'darwin' && !result.terminal.isIterm) {\n lines.push(\n ` Terminal: ${result.terminal.name || 'unknown'}`,\n ' Tip: iTerm2 is recommended for the best experience with sisyphus.',\n ' Download: https://iterm2.com',\n '',\n );\n }\n\n // tmux status\n if (result.tmuxAutoInstalled) {\n lines.push(' \\u2713 tmux installed via Homebrew.');\n if (result.tmuxDefaultsWritten) {\n lines.push(' \\u2713 Default tmux config written to ~/.tmux.conf');\n }\n lines.push('');\n } else if (!result.tmuxInstalled) {\n const installHint = process.platform === 'darwin'\n ? ' Install Homebrew (https://brew.sh) then run: brew install tmux'\n : ' Install: apt install tmux (Debian/Ubuntu) or your package manager';\n lines.push(\n ' \\u2717 tmux is required but could not be installed automatically.',\n installHint,\n '',\n );\n }\n\n // termrender\n if (result.termrender.autoInstalled) {\n lines.push(' \\u2713 termrender installed (markdown rendering for TUI).', '');\n } else if (!result.termrender.installed) {\n lines.push(\n ' \\u26a0 termrender not installed (rich markdown rendering unavailable).',\n ' Install: pipx install termrender (or: pip install termrender)',\n '',\n );\n }\n\n // iTerm2 right option key\n if (result.itermOptionKey.checked && !result.itermOptionKey.allCorrect) {\n const profiles = result.itermOptionKey.incorrectProfiles;\n lines.push(\n ' \\u26a0 Right Option Key is not sending Esc+ in iTerm2:',\n ...profiles.map((p) => ` \\u2022 Profile \"${p}\"`),\n '',\n ' Sisyphus uses Option keybindings (e.g., Option-s to cycle sessions).',\n ' Fix: iTerm2 \\u2192 Settings \\u2192 Profiles \\u2192 Keys \\u2192 Right Option Key \\u2192 Esc+',\n '',\n );\n }\n\n return lines;\n}\n","import type { Command } from 'commander';\nimport { DEFAULT_CYCLE_KEY, setupTmuxKeybind } from '../tmux-setup.js';\n\nexport function registerSetupKeybind(program: Command): void {\n program\n .command('setup-keybind [cycle-key]')\n .description('Install sisyphus tmux keybindings (default: M-s cycle, C-s prefix)')\n .option('-y, --yes', 'Skip confirmation prompt before modifying ~/.tmux.conf')\n .action(async (key: string | undefined, opts: { yes?: boolean }) => {\n const resolvedKey = key ?? DEFAULT_CYCLE_KEY;\n const result = await setupTmuxKeybind(resolvedKey, undefined, { assumeYes: opts.yes });\n\n switch (result.status) {\n case 'installed':\n console.log(result.message);\n console.log('Note: requires tmux 3.2+ for display-menu keybindings.');\n break;\n case 'already-installed':\n console.log(result.message);\n break;\n case 'conflict':\n console.log(`Key ${resolvedKey} is already bound:`);\n console.log(` ${result.existingBinding}`);\n console.log('');\n console.log('Use a different key, e.g.:');\n console.log(' sis admin setup-keybind M-S');\n console.log(' sis admin setup-keybind M-w');\n console.log(' sis admin setup-keybind M-j');\n break;\n case 'unsupported-tmux':\n console.log(result.message);\n break;\n case 'conf-modification-declined':\n console.log(result.message);\n console.log('');\n console.log('Re-run with --yes to skip the prompt.');\n break;\n }\n });\n}\n","import type { Command } from 'commander';\nimport { execSync } from 'node:child_process';\nimport { shellQuote } from '../../shared/shell.js';\nimport { openDashboardWindow } from './dashboard.js';\n\n/**\n * `sis admin home-init <name> <cwd>`\n *\n * Bootstrap a tmux home session — a regular (non-`ssyph_`-prefixed) session\n * with `@sisyphus_cwd` set, hosting the dashboard in window 1. Idempotent:\n * re-running on an existing session is a no-op aside from re-focusing the\n * dashboard window.\n *\n * Designed to run on the cloud box itself (over SSH) so `import.meta.dirname`\n * resolves to the box's installed sisyphi `tui.js`. Does not require a tmux\n * client — talks to the tmux server directly with `-t` targeting.\n */\nexport function registerHomeInit(parent: Command): void {\n parent\n .command('home-init <name> <cwd>')\n .description('Bootstrap a tmux home session with the sisyphus dashboard.')\n .action((name: string, cwd: string) => {\n ensureSession(name, cwd);\n setSessionCwd(name, cwd);\n openDashboardWindow(name, cwd);\n });\n}\n\nfunction sessionExists(name: string): boolean {\n try {\n execSync(`tmux has-session -t ${shellQuote(name)}`, { stdio: 'pipe' });\n return true;\n } catch {\n return false;\n }\n}\n\nfunction ensureSession(name: string, cwd: string): void {\n if (sessionExists(name)) return;\n execSync(\n `tmux new-session -d -s ${shellQuote(name)} -c ${shellQuote(cwd)}`,\n { stdio: 'pipe' },\n );\n}\n\nfunction setSessionCwd(name: string, cwd: string): void {\n execSync(\n `tmux set-option -t ${shellQuote(name)} @sisyphus_cwd ${shellQuote(cwd.replace(/\\/+$/, ''))}`,\n { stdio: 'pipe' },\n );\n}\n","import { execSync } from 'node:child_process';\nimport { existsSync, statSync } from 'node:fs';\nimport { homedir } from 'node:os';\nimport { join } from 'node:path';\nimport type { Command } from 'commander';\nimport { daemonLogPath, daemonPidPath, globalDir, socketPath } from '../../shared/paths.js';\nimport { isInstalled } from '../install.js';\nimport { detectTerminal, checkItermOptionKey, isNvimAvailable, isTermrenderAvailable } from '../onboard.js';\nimport { resolveInstalledPlugin } from '../../daemon/plugins.js';\nimport { cycleScriptPath, DEFAULT_CYCLE_KEY, getExistingBinding, isSisyphusBinding, sisyphusTmuxConfPath } from '../tmux-setup.js';\n\ninterface Check {\n name: string;\n status: 'ok' | 'warn' | 'fail';\n detail: string;\n fix?: string;\n}\n\nfunction checkNodeVersion(): Check {\n const major = parseInt(process.versions.node.split('.')[0]!, 10);\n if (major < 22) {\n return { name: 'Node.js', status: 'fail', detail: `v${process.versions.node} (v22+ required)`, fix: 'Install Node.js 22+: https://nodejs.org' };\n }\n return { name: 'Node.js', status: 'ok', detail: `v${process.versions.node}` };\n}\n\nfunction checkClaudeCli(): Check {\n try {\n execSync('which claude', { stdio: 'pipe' });\n return { name: 'Claude CLI', status: 'ok', detail: 'Found on PATH' };\n } catch {\n return {\n name: 'Claude CLI',\n status: 'fail',\n detail: 'Not found on PATH',\n fix: 'Install Claude Code: https://docs.anthropic.com/en/docs/claude-code/overview',\n };\n }\n}\n\nfunction checkGit(): Check {\n try {\n const version = execSync('git --version', { encoding: 'utf-8', stdio: 'pipe' }).trim();\n return { name: 'git', status: 'ok', detail: version };\n } catch {\n return { name: 'git', status: 'fail', detail: 'Not found on PATH', fix: 'Install git: https://git-scm.com/downloads' };\n }\n}\n\nfunction checkTmuxVersion(): Check {\n try {\n const version = execSync('tmux -V', { encoding: 'utf-8', stdio: 'pipe' }).trim();\n // Parse \"tmux X.Y\" or \"tmux next-X.Y\"\n const match = version.match(/(\\d+\\.\\d+)/);\n if (!match) return { name: 'tmux version', status: 'warn', detail: `Could not parse version: ${version}` };\n const ver = parseFloat(match[1]);\n if (ver < 3.2) {\n const upgradeHint = process.platform === 'darwin' ? 'brew install tmux (or upgrade)' : 'apt install tmux (Debian/Ubuntu) or your package manager';\n return { name: 'tmux version', status: 'warn', detail: `${version} (3.2+ recommended for popup support)`, fix: upgradeHint };\n }\n return { name: 'tmux version', status: 'ok', detail: version };\n } catch {\n return { name: 'tmux version', status: 'warn', detail: 'Could not determine version' };\n }\n}\n\nfunction checkDaemonInstalled(): Check {\n if (process.platform === 'darwin') {\n if (isInstalled()) {\n return { name: 'Daemon plist', status: 'ok', detail: 'Installed in LaunchAgents' };\n }\n return {\n name: 'Daemon plist',\n status: 'fail',\n detail: 'Not installed',\n fix: 'Run any sis command to auto-install, or: sis start \"test\"',\n };\n }\n // Linux: check if PID file exists (daemon started manually)\n const pid = daemonPidPath();\n if (existsSync(pid)) {\n return { name: 'Daemon setup', status: 'ok', detail: `PID file found at ${pid}` };\n }\n return {\n name: 'Daemon setup',\n status: 'fail',\n detail: 'Daemon not running (no PID file)',\n fix: 'Start manually: sisyphusd & — or configure via systemd',\n };\n}\n\nfunction checkDaemonRunning(): Check {\n const pid = daemonPidPath();\n if (!existsSync(pid)) {\n const fix = process.platform === 'darwin'\n ? 'launchctl load -w ~/Library/LaunchAgents/com.sisyphus.daemon.plist'\n : 'sisyphusd & — or check if the process is running';\n return {\n name: 'Daemon process',\n status: 'fail',\n detail: 'No PID file found',\n fix,\n };\n }\n try {\n const sock = socketPath();\n execSync(`test -S \"${sock}\"`, { stdio: 'pipe' });\n return { name: 'Daemon process', status: 'ok', detail: `Socket at ${sock}` };\n } catch {\n return {\n name: 'Daemon process',\n status: 'warn',\n detail: 'PID file exists but socket not found',\n fix: `Check logs: tail -20 ${daemonLogPath()}`,\n };\n }\n}\n\nfunction checkTmux(): Check {\n try {\n execSync('which tmux', { stdio: 'pipe' });\n } catch {\n const installHint = process.platform === 'darwin' ? 'brew install tmux' : 'apt install tmux (Debian/Ubuntu) or your package manager';\n return { name: 'tmux', status: 'fail', detail: 'Not found on PATH', fix: installHint };\n }\n try {\n execSync('tmux list-sessions', { stdio: 'pipe' });\n return { name: 'tmux', status: 'ok', detail: 'Running' };\n } catch {\n return { name: 'tmux', status: 'warn', detail: 'Installed but no server running' };\n }\n}\n\nfunction checkCycleScript(): Check {\n const path = cycleScriptPath();\n if (!existsSync(path)) {\n return {\n name: 'Cycle script',\n status: 'fail',\n detail: `Not found at ${path}`,\n fix: 'sis admin setup-keybind',\n };\n }\n try {\n const mode = statSync(path).mode;\n if ((mode & 0o111) === 0) {\n return {\n name: 'Cycle script',\n status: 'fail',\n detail: 'Not executable',\n fix: `chmod +x ${path}`,\n };\n }\n } catch { /* ignore stat errors */ }\n return { name: 'Cycle script', status: 'ok', detail: path };\n}\n\nfunction checkTmuxKeybind(): Check {\n const existing = getExistingBinding(DEFAULT_CYCLE_KEY);\n if (existing === null) {\n // Also check if the sisyphus tmux.conf exists (binding might be configured but tmux not running)\n if (existsSync(sisyphusTmuxConfPath())) {\n return {\n name: `Tmux keybind (${DEFAULT_CYCLE_KEY})`,\n status: 'warn',\n detail: 'Configured in sisyphus tmux.conf but not active (tmux may not be running)',\n };\n }\n return {\n name: `Tmux keybind (${DEFAULT_CYCLE_KEY})`,\n status: 'fail',\n detail: 'Not bound',\n fix: 'sis admin setup-keybind',\n };\n }\n if (isSisyphusBinding(existing)) {\n return { name: `Tmux keybind (${DEFAULT_CYCLE_KEY})`, status: 'ok', detail: 'Bound to sisyphus-cycle' };\n }\n return {\n name: `Tmux keybind (${DEFAULT_CYCLE_KEY})`,\n status: 'warn',\n detail: `Bound to something else: ${existing}`,\n fix: 'sis admin setup-keybind M-S (or another free key)',\n };\n}\n\nfunction checkGlobalDir(): Check {\n const dir = globalDir();\n if (existsSync(dir)) {\n return { name: 'Data directory', status: 'ok', detail: dir };\n }\n return { name: 'Data directory', status: 'warn', detail: `${dir} does not exist (created on first use)` };\n}\n\nfunction checkTerminal(): Check {\n if (process.platform !== 'darwin') {\n return { name: 'Terminal', status: 'ok', detail: 'Non-macOS (skipped)' };\n }\n const terminal = detectTerminal();\n if (terminal.isIterm) {\n return { name: 'Terminal', status: 'ok', detail: terminal.name };\n }\n return {\n name: 'Terminal',\n status: 'warn',\n detail: terminal.name ? terminal.name : 'unknown',\n fix: 'iTerm2 recommended for best experience: https://iterm2.com',\n };\n}\n\nfunction checkItermRightOptionKey(): Check | null {\n if (process.platform !== 'darwin') return null;\n const terminal = detectTerminal();\n if (!terminal.isIterm) return null;\n const result = checkItermOptionKey();\n if (!result.checked) return null;\n if (result.allCorrect) {\n return { name: 'Right Option Key', status: 'ok', detail: 'Esc+' };\n }\n const profiles = result.incorrectProfiles.map((p) => `\"${p}\"`).join(', ');\n return {\n name: 'Right Option Key',\n status: 'warn',\n detail: `Not Esc+ for ${profiles}`,\n fix: 'iTerm2 \\u2192 Settings \\u2192 Profiles \\u2192 Keys \\u2192 Right Option Key \\u2192 Esc+',\n };\n}\n\nfunction checkSisyphusPlugin(): Check {\n const installPath = resolveInstalledPlugin('sisyphus@sisyphus');\n if (installPath) {\n return { name: 'sisyphus@sisyphus plugin', status: 'ok', detail: installPath };\n }\n return {\n name: 'sisyphus@sisyphus plugin',\n status: 'warn',\n detail: 'Not installed (slash commands /sisyphus:begin, /sisyphus:autopsy, /sisyphus:configure-upload unavailable)',\n fix: 'sis admin setup',\n };\n}\n\nfunction checkTermrender(): Check {\n if (isTermrenderAvailable()) {\n try {\n const version = execSync('termrender --version', { encoding: 'utf-8', stdio: 'pipe' }).trim();\n return { name: 'termrender', status: 'ok', detail: version };\n } catch {\n return { name: 'termrender', status: 'ok', detail: 'installed' };\n }\n }\n return {\n name: 'termrender',\n status: 'warn',\n detail: 'Not installed (rich markdown rendering unavailable)',\n fix: 'pipx install termrender (or: pip install termrender)',\n };\n}\n\nfunction checkNvim(): Check {\n if (!isNvimAvailable()) {\n const fix = process.platform === 'darwin' ? 'brew install neovim' : 'Install neovim from https://neovim.io';\n return { name: 'nvim', status: 'warn', detail: 'Not installed', fix };\n }\n try {\n const version = execSync('nvim --version', { encoding: 'utf-8', stdio: 'pipe' }).split('\\n')[0]?.replace('NVIM ', '');\n return { name: 'nvim', status: 'ok', detail: version ?? 'installed' };\n } catch {\n return { name: 'nvim', status: 'ok', detail: 'installed' };\n }\n}\n\nfunction checkNotifyBinary(): Check | null {\n if (process.platform !== 'darwin') return null;\n const binary = join(homedir(), '.sisyphus', 'SisyphusNotify.app', 'Contents', 'MacOS', 'sisyphus-notify');\n if (existsSync(binary)) {\n return { name: 'Notifications', status: 'ok', detail: 'SisyphusNotify.app built' };\n }\n return {\n name: 'Notifications',\n status: 'warn',\n detail: 'SisyphusNotify.app not built (click-to-switch unavailable)',\n fix: 'Requires Xcode CLI tools: xcode-select --install, then reinstall sisyphus',\n };\n}\n\nconst SYMBOLS = { ok: '\\u2713', warn: '!', fail: '\\u2717' } as const;\n\nexport function registerDoctor(program: Command): void {\n program\n .command('doctor')\n .description('Check sisyphus installation health')\n .action(() => {\n const itermCheck = checkItermRightOptionKey();\n const notifyCheck = checkNotifyBinary();\n const checks: Check[] = [\n checkNodeVersion(),\n checkClaudeCli(),\n checkGit(),\n checkTmux(),\n checkTmuxVersion(),\n checkTerminal(),\n ...(itermCheck ? [itermCheck] : []),\n checkGlobalDir(),\n checkDaemonInstalled(),\n checkDaemonRunning(),\n checkCycleScript(),\n checkTmuxKeybind(),\n checkSisyphusPlugin(),\n checkNvim(),\n ...(notifyCheck ? [notifyCheck] : []),\n checkTermrender(),\n ];\n\n let hasIssues = false;\n for (const c of checks) {\n const sym = SYMBOLS[c.status];\n console.log(` ${sym} ${c.name}: ${c.detail}`);\n if (c.status !== 'ok') hasIssues = true;\n }\n\n // Print fixes\n const fixable = checks.filter((c) => c.fix && c.status !== 'ok');\n if (fixable.length > 0) {\n console.log('\\nFixes:');\n for (const c of fixable) {\n console.log(` ${c.name}: ${c.fix}`);\n }\n }\n\n if (!hasIssues) {\n console.log('\\nAll checks passed.');\n }\n });\n}\n","import type { Command } from 'commander';\nimport { existsSync, mkdirSync, writeFileSync } from 'node:fs';\nimport { join } from 'node:path';\n\nconst DEFAULT_CONFIG = {};\n\nconst ORCHESTRATOR_TEMPLATE = `# Custom Orchestrator Prompt\n\n<!-- This file overrides the default orchestrator system prompt. -->\n<!-- Delete this file to use the built-in prompt. -->\n<!-- See: https://github.com/silasrhyneer/sisyphi for details. -->\n`;\n\nexport function registerInit(program: Command): void {\n program\n .command('init')\n .description('Initialize sisyphus configuration for this project')\n .option('--orchestrator', 'Also create a custom orchestrator prompt template')\n .action((opts: { orchestrator?: boolean }) => {\n const cwd = process.cwd();\n const sisDir = join(cwd, '.sisyphus');\n const configPath = join(sisDir, 'config.json');\n\n if (existsSync(configPath)) {\n console.log(`Already initialized: ${configPath}`);\n return;\n }\n\n mkdirSync(sisDir, { recursive: true });\n writeFileSync(configPath, JSON.stringify(DEFAULT_CONFIG, null, 2) + '\\n', 'utf-8');\n console.log(`Created ${configPath}`);\n\n if (opts.orchestrator) {\n const orchPath = join(sisDir, 'orchestrator.md');\n if (!existsSync(orchPath)) {\n writeFileSync(orchPath, ORCHESTRATOR_TEMPLATE, 'utf-8');\n console.log(`Created ${orchPath}`);\n }\n }\n\n console.log('');\n console.log('Configuration options (add to .sisyphus/config.json):');\n console.log(' orchestratorEffort — \"low\" | \"medium\" | \"high\" | \"xhigh\" | \"max\" (default: \"xhigh\")');\n console.log(' agentEffort — \"low\" | \"medium\" | \"high\" | \"xhigh\" | \"max\" (default: \"medium\")');\n console.log(' pollIntervalMs — Daemon poll interval in ms (default: 5000)');\n console.log(' autoUpdate — Auto-update daemon on restart (default: true)');\n console.log(' notifications — { enabled: boolean, sound: string } (default: enabled, Hero.aiff)');\n console.log(' companionPopup — Show companion commentary as tmux popup (default: true)');\n });\n}\n","import type { Command } from 'commander';\nimport { createInterface } from 'node:readline';\nimport { uninstallDaemon } from '../install.js';\n\nasync function confirm(question: string): Promise<boolean> {\n const rl = createInterface({ input: process.stdin, output: process.stdout });\n return new Promise((resolve) => {\n rl.question(question, (answer) => {\n rl.close();\n resolve(answer.trim().toLowerCase() === 'y');\n });\n });\n}\n\nexport function registerUninstall(program: Command): void {\n program\n .command('uninstall')\n .description('Unload the sisyphus daemon from launchd and remove the plist')\n .option('--purge', 'Also remove all session data in ~/.sisyphus')\n .option('-y, --yes', 'Skip confirmation prompt for --purge')\n .action(async (opts: { purge?: boolean; yes?: boolean }) => {\n const purge = opts.purge ?? false;\n\n if (purge && !opts.yes) {\n const ok = await confirm('This will delete all session data in ~/.sisyphus. Continue? (y/N) ');\n if (!ok) {\n console.log('Aborted.');\n return;\n }\n }\n\n await uninstallDaemon(purge);\n });\n}\n","import { chmodSync, existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';\nimport { createInterface } from 'node:readline';\nimport { dirname } from 'node:path';\nimport type { Command } from 'commander';\nimport { globalConfigPath } from '../../shared/paths.js';\n\nasync function readUrlFromInput(interactive: boolean): Promise<string> {\n if (interactive) {\n return new Promise((resolve) => {\n const rl = createInterface({ input: process.stdin, output: process.stdout });\n rl.question('Paste the upload URL (with embedded ?token=): ', (answer) => {\n rl.close();\n resolve(answer.trim());\n });\n });\n }\n return new Promise((resolve) => {\n const chunks: string[] = [];\n process.stdin.setEncoding('utf-8');\n process.stdin.on('data', (chunk: string) => { chunks.push(chunk); });\n process.stdin.on('end', () => { resolve(chunks.join('').trim()); });\n });\n}\n\nexport function registerConfigureUpload(program: Command): void {\n program\n .command('configure-upload')\n .description('Configure the upload proxy from a token-bearing URL (writes ~/.sisyphus/config.json)')\n .argument('[url]', 'Worker URL with embedded ?token= query (https://worker/upload?token=sisyphus_pat_...); omit to read from stdin')\n .option('--stdin', 'Read URL from stdin (pipe-friendly: pbpaste | sis admin configure-upload --stdin)')\n .action(async (urlArg: string | undefined, opts: { stdin?: boolean }) => {\n let rawUrl: string;\n\n const fromStdin = opts.stdin || urlArg === '-' || (!urlArg && process.stdin.isTTY === false);\n const fromInteractive = !urlArg && !opts.stdin && process.stdin.isTTY === true;\n\n if (fromStdin || fromInteractive) {\n rawUrl = await readUrlFromInput(fromInteractive);\n } else {\n rawUrl = urlArg!;\n console.warn(\n 'warning: passing the token on argv exposes it via `ps` and shell history; pipe it on stdin instead: `pbpaste | sis admin configure-upload --stdin`',\n );\n }\n\n let parsed: URL;\n try {\n parsed = new URL(rawUrl);\n } catch {\n console.error('Error: Invalid URL');\n process.exit(1);\n }\n\n const token = parsed.searchParams.get('token');\n if (!token) {\n console.error('Error: URL is missing ?token=... query param');\n process.exit(1);\n }\n\n if (!token.startsWith('sisyphus_pat_')) {\n console.error('Error: token does not start with sisyphus_pat_ — refusing to write');\n process.exit(1);\n }\n\n parsed.searchParams.delete('token');\n\n // Strip /upload if it's the trailing segment — upload.ts appends /upload itself\n const strippedPath = parsed.pathname.replace(/\\/upload\\/?$/, '');\n const url = parsed.origin + (strippedPath.length > 0 ? strippedPath : '');\n\n // Always write to ~/.sisyphus/config.json — `loadConfig` only honors `upload`\n // from the global config (project-local upload blocks are silently stripped\n // as a security measure; see src/shared/config.ts).\n const configPath = globalConfigPath();\n\n let existing: Record<string, unknown> = {};\n if (existsSync(configPath)) {\n try {\n existing = JSON.parse(readFileSync(configPath, 'utf-8')) as Record<string, unknown>;\n } catch {\n console.error(`Error: ${configPath} could not be parsed — fix or delete it first`);\n process.exit(1);\n }\n }\n\n const merged = { ...existing, upload: { url, token } };\n mkdirSync(dirname(configPath), { recursive: true });\n writeFileSync(configPath, JSON.stringify(merged, null, 2) + '\\n', 'utf-8');\n chmodSync(configPath, 0o600);\n\n console.log(`✓ upload configured (${configPath})`);\n });\n}\n","import { execSync } from 'node:child_process';\nimport { dirname, join } from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport type { Command } from 'commander';\nimport { isTmuxInstalled } from '../tmux.js';\nimport { isNvimAvailable, detectTerminal, checkItermOptionKey } from '../onboard.js';\n\nfunction templatePath(name: string): string {\n return join(dirname(fileURLToPath(import.meta.url)), 'templates', name);\n}\n\nfunction isClaudeCode(): boolean {\n return !!process.env['CLAUDECODE'];\n}\n\nfunction printNonClaudeMessage(): void {\n console.log(`\n ╔══════════════════════════════════════════════════╗\n ║ sis admin getting-started — Interactive Tutorial ║\n ╚══════════════════════════════════════════════════╝\n\n This command provides an interactive tutorial best experienced\n inside Claude Code. Claude will walk you through setup step by step.\n\n To start:\n 1. Open Claude Code: claude\n 2. Run: sis admin getting-started\n\n If you just want the quick reference, run:\n sis --help\n sis admin doctor\n`);\n}\n\nfunction printStep0(): void {\n const tmuxInstalled = isTmuxInstalled();\n const inTmux = !!process.env['TMUX'];\n let tmuxSession: string | null = null;\n if (process.env['TMUX']) {\n const segments = process.env['TMUX'].split(',');\n const pathPart = segments[0];\n if (pathPart) {\n const parts = pathPart.split('/');\n tmuxSession = parts[parts.length - 1] || null;\n }\n }\n\n console.log(`\n<claude-instructions>\n# Sisyphus Getting Started — Step 0: Entry & Tmux Gate\n\n## Environment Data\n- tmuxInstalled: ${tmuxInstalled}\n- inTmux: ${inTmux}\n- tmuxSession: ${tmuxSession ?? 'none'}\n\n## Tutorial Overview\n\nThis tutorial has 6 steps. Share this overview so the user knows what's coming and can skip ahead:\n\n| Step | Topic | Command |\n|------|-------|---------|\n| 0 | Entry & tmux gate (you are here) | \\`sis admin getting-started\\` |\n| 1 | Tmux basics — sessions, panes, navigation | \\`--tutorial 1\\` |\n| 2 | Nvim basics — open, save, quit (optional) | \\`--tutorial 2\\` |\n| 3 | Sisyphus concepts — session model & keybinds | \\`--tutorial 3\\` |\n| 4 | Live demo — launch and observe a real session | \\`--tutorial 4\\` |\n| 5 | What's next — real usage guidance & suggestions | \\`--tutorial 5\\` |\n\nTell the user they can skip to any step with \\`sis admin getting-started --tutorial <N>\\`.\n\n## Instructions for Claude\n\nYou are guiding a user through the Sisyphus interactive tutorial.\n\n### First: Ask if they want the tutorial\n\nAsk the user if they'd like the interactive walkthrough. If they decline, give this quick summary and stop:\n\n> Sisyphus is a multi-agent orchestrator for Claude Code. Start a session with \\`sis start \"task\"\\`,\n> monitor with \\`sis dashboard\\`, and check health with \\`sis admin doctor\\`.\n\n### If they want the tutorial:\n\n**Case 1: tmux is NOT installed (tmuxInstalled: false)**\n- Explain what tmux is in 2-3 sentences: \"tmux is a terminal multiplexer — it lets you split your terminal into multiple panes and keep sessions running in the background. Sisyphus uses it to give each agent its own workspace.\"\n- Show this ASCII diagram:\n\n\\`\\`\\`\n Regular terminal: With tmux:\n ┌──────────────┐ ┌──────┬──────┐\n │ │ │ Agent│ Agent│\n │ one view │ │ 001 │ 002 │\n │ │ ├──────┼──────┤\n │ │ │ Agent│ Orch │\n └──────────────┘ │ 003 │ │\n └──────┴──────┘\n\\`\\`\\`\n\n- Tell them to install tmux:\n - macOS: \\`brew install tmux\\`\n - Linux: \\`apt install tmux\\` or their package manager\n- After install, re-run: \\`sis admin getting-started --tutorial 0\\` to verify\n\n**Case 2: tmux installed but NOT in a tmux session (inTmux: false)**\n- Tell the user they need to be inside a tmux session for the tutorial\n- Have them run: \\`tmux new-session\\`\n- Then resume the conversation with Claude in the new tmux session: \\`claude\\`\n- Then re-run: \\`sis admin getting-started --tutorial 0\\` to verify\n\n**Case 3: In tmux (inTmux: true)**\n- Tell the user they're all set — tmux is running\n- Proceed by running: \\`sis admin getting-started --tutorial 1\\`\n</claude-instructions>\n`);\n}\n\nfunction printStep1(): void {\n console.log(`\n<claude-instructions>\n# Sisyphus Getting Started — Step 1: Tmux Basics\n\n## Instructions for Claude\n\nTeach the user tmux fundamentals. Be conversational and encouraging.\n\n### 1. Explain the concepts with diagrams\n\n**Sessions, Windows, and Panes:**\n\n\\`\\`\\`\ntmux session \"work\"\n├── window 1: \"code\"\n│ ┌──────────┬──────────┐\n│ │ pane 1 │ pane 2 │\n│ │ (editor)│ (tests) │\n│ └──────────┴──────────┘\n└── window 2: \"servers\"\n ┌──────────────────────┐\n │ pane 1 │\n │ (dev server) │\n └──────────────────────┘\n\\`\\`\\`\n\n- **Session**: A collection of windows. Persists even if you close the terminal.\n- **Window**: Like a tab. Each window fills the screen.\n- **Pane**: A split within a window. Sisyphus puts each agent in its own pane.\n\n### 2. Hands-on: Create a test split\n\nRun this command for the user:\n\\`\\`\\`\ntmux split-window -h\n\\`\\`\\`\n\nTell them: \"I just split your terminal. You should see two panes side by side.\"\n\nExplain navigation:\n- \\`Ctrl+l\\`: move to the right pane\n- \\`Ctrl+h\\`: move to the left pane\n- \\`Ctrl+j\\`: move to the pane below\n- \\`Ctrl+k\\`: move to the pane above\n- No prefix key needed — just hold Ctrl and press the direction letter\n- For windows: \\`Ctrl+n\\` next window, \\`Ctrl+p\\` previous window\n\nAsk them to try navigating between panes.\n\n### 3. Clean up the test pane\n\nOnce they confirm they can navigate, close the extra pane:\n\\`\\`\\`\ntmux kill-pane -t {the other pane}\n\\`\\`\\`\n\nOr tell them they can type \\`exit\\` in the extra pane to close it.\n\n### 4. Teach essential commands\n\n- **Detach**: \\`Ctrl-b d\\` — leaves tmux running in background, returns to normal terminal\n- **Reattach**: \\`tmux attach\\` (or \\`tmux a\\`) — reconnects to the running session\n- **Scroll up/down**: \\`Ctrl+u\\` / \\`Ctrl+d\\` — scroll half-page up/down (no prefix needed). Press \\`q\\` to exit scroll mode.\n- **New window**: \\`Ctrl-b n\\` — opens a new window in the current directory\n- **Kill pane**: \\`Ctrl-b x\\` — closes the current pane and rebalances layout\n- **Re-tile**: \\`Ctrl-b =\\` — rebalance all panes to equal widths\n\n### 5. Verification\n\nAsk the user to confirm: \"Can you navigate between panes with Ctrl+h and Ctrl+l?\"\n\nOnce confirmed, proceed:\n\\`\\`\\`\nsis admin getting-started --tutorial 2\n\\`\\`\\`\n</claude-instructions>\n`);\n}\n\nfunction printStep2(): void {\n const nvimInstalled = isNvimAvailable();\n\n console.log(`\n<claude-instructions>\n# Sisyphus Getting Started — Step 2: Nvim Basics\n\n## Environment Data\n- nvimInstalled: ${nvimInstalled}\n\n## Instructions for Claude\n\nThis step is OPTIONAL. Nvim is useful for reviewing and editing files when you jump into agent panes, but not required.\n\nNote: The sisyphus dashboard has keys that auto-open files in nvim — users don't need to know how to open files from the command line. Focus on what they'll need once they're INSIDE nvim.\n\n### If nvim is NOT installed (nvimInstalled: false)\n\nAsk the user: \"Neovim is handy for reviewing and editing files in tmux panes. Want me to install it, or skip this step?\"\n\n- **Install**: Run \\`brew install neovim\\` (macOS) or suggest their package manager\n- **Skip**: That's fine — they can use \\`cat\\`, \\`less\\`, or any editor they prefer. Proceed to step 3.\n\n### If nvim IS installed (nvimInstalled: true)\n\nBriefly explain the key concept — nvim has two modes:\n\n- **Normal mode** (default): Keys are commands, not text. This is where you navigate.\n- **Insert mode**: Press \\`i\\` to enter. Now you type normally. \\`Esc\\` goes back to normal.\n\nTell them the basics they need once they're inside nvim: \\`i\\` to enter insert mode, \\`Esc\\` to return to normal mode, \\`:w\\` to save, \\`:q\\` to quit, \\`:wq\\` to save and quit.\n\n### Verification\n\nAsk if they were able to edit and save the file (or if they skipped).\n\nProceed:\n\\`\\`\\`\nsis admin getting-started --tutorial 3\n\\`\\`\\`\n</claude-instructions>\n`);\n}\n\nfunction printStep3(): void {\n // Detect iTerm Right Option Key status for environment data\n let rightOptionKeyStatus = 'unknown';\n const terminal = detectTerminal();\n if (!terminal.isIterm) {\n rightOptionKeyStatus = 'not-iterm';\n } else {\n const result = checkItermOptionKey();\n if (!result.checked) {\n rightOptionKeyStatus = 'could-not-check';\n } else if (result.allCorrect) {\n rightOptionKeyStatus = 'ok';\n } else {\n rightOptionKeyStatus = `incorrect:${result.incorrectProfiles.join(',')}`;\n }\n }\n\n console.log(`\n<claude-instructions>\n# Sisyphus Getting Started — Step 3: Sisyphus Concepts & Keybinds\n\n## Environment Data\n- rightOptionKeyStatus: ${rightOptionKeyStatus}\n\n## Instructions for Claude\n\n### 1. CRITICAL FIRST: Right Option Key Setup\n\n**This must be done before anything else.** Sisyphus keybinds use the Option key as \"Meta\". By default, macOS terminals send special characters when you press Option (e.g., Option+s types \\`ß\\`). We need the RIGHT Option key to send escape sequences instead.\n\n**Check the environment data above:**\n\n- **rightOptionKeyStatus: ok** — They're all set, briefly confirm and move on.\n\n- **rightOptionKeyStatus: incorrect:ProfileName** — Walk them through the fix:\n\n > Your Right Option key isn't configured correctly yet. Here's how to fix it:\n >\n > 1. Open **iTerm2 Settings** (Cmd+,)\n > 2. Go to **Profiles** → select your profile (shown above)\n > 3. Click the **Keys** tab\n > 4. At the bottom, find **Right Option Key**\n > 5. Change it from **Normal** to **Esc+**\n >\n > \\`\\`\\`\n > ┌─ iTerm2 Settings ──────────────────────────┐\n > │ Profiles > Keys │\n > │ │\n > │ Right Option Key: │\n > │ ○ Normal (sends special chars like ß) │\n > │ ● Esc+ (sends escape sequences) ← ✓ │\n > └─────────────────────────────────────────────┘\n > \\`\\`\\`\n >\n > **Why right and not left?** You'll still want the left Option key for\n > typing special characters (accents, symbols). The right Option key\n > becomes your \"Meta\" key for tmux/sisyphus keybinds.\n\n After they change it, have them verify by re-running \\`sis admin doctor\\` — look for \"Right Option Key: Esc+\".\n\n- **rightOptionKeyStatus: not-iterm** — They're not using iTerm2. Explain:\n > Sisyphus keybinds use Option as Meta. In iTerm2 this is configured via\n > \"Right Option Key → Esc+\". For your terminal, look for a similar setting\n > like \"Option sends Meta\" or \"Option sends Esc+\". Without this, pressing\n > Option+s will type a special character instead of triggering the keybind.\n\n- **rightOptionKeyStatus: could-not-check** or **unknown** — Ask them to manually check:\n > Press Option+s in your terminal. If you see \\`ß\\` (or another special character),\n > your Option key needs to be reconfigured. In iTerm2: Settings → Profiles → Keys →\n > Right Option Key → Esc+.\n\n### 2. Explain the session model\n\nThis is the KEY concept. Use the diagram and be clear:\n\n\\`\\`\\`\n YOUR tmux session (\"work\") Sisyphus tmux session (\"sisyphus-abc123\")\n ┌─────────────────────┐ ┌──────────┬──────────┬──────────┐\n │ │ │ Orch │ Agent │ Agent │\n │ Your normal work │ ←──→ │ (yellow)│ (blue) │ (green) │\n │ + dashboard │ │ │ │ │\n │ │ │ Plans & │ Writes │ Writes │\n │ │ │ assigns │ code │ tests │\n └─────────────────────┘ └──────────┴──────────┴──────────┘\n\\`\\`\\`\n\nKey points:\n- Sisyphus creates its OWN tmux session — it doesn't clutter yours\n- The **orchestrator** (yellow pane) plans work and spawns agents\n- **Agents** (colored panes) work in parallel on subtasks\n- Your session stays clean — you get a **dashboard** for monitoring\n- You can jump between your session and the sisyphus session to observe\n\n### 3. Teach keybinds\n\nTwo keybinds to remember (both use the RIGHT Option key):\n\n| Keybind | Action |\n|---------|--------|\n| Right Option + s | Cycle through sisyphus sessions |\n| Right Option + Shift + s | Jump back to dashboard |\n\n### 4. Verify keybinds are installed\n\nRun \\`sis admin doctor\\` and check the output. Look for:\n- \"Cycle script\" — should be ✓\n- \"Tmux keybind\" — should be ✓\n- \"Right Option Key\" — should be \"Esc+\"\n\nIf cycle script or keybind is missing, run: \\`sis admin setup-keybind\\`\n\n### 5. Test the keybind\n\nHave the user try pressing Right Option + s. Nothing should happen yet (no sisyphus session running) — and that's fine. The important thing is no special character appears.\n\nIf they see \\`ß\\` or similar, circle back to the Right Option Key setup above.\n\n### 6. Verification\n\nConfirm:\n- They understand the two-session model (their session vs sisyphus session)\n- \\`sis admin doctor\\` shows keybinds installed AND Right Option Key: Esc+\n- Right Option + s doesn't produce a special character\n\nProceed:\n\\`\\`\\`\nsis admin getting-started --tutorial 4\n\\`\\`\\`\n</claude-instructions>\n`);\n}\n\nfunction printStep4(): void {\n console.log(`\n<claude-instructions>\n# Sisyphus Getting Started — Step 4: Demo Session\n\n## Instructions for Claude\n\nThis is the grand finale — a live demo session.\n\n### 1. Health check\n\nRun \\`sis admin doctor\\` first. If any checks are failing, help the user fix them before proceeding.\nAll core checks (tmux, daemon, keybinds) should be ✓.\n\n### 2. BEFORE launching: Teach navigation\n\n**This is critical.** When \\`sis start\\` runs, it auto-opens the dashboard in a new tmux window. The user will suddenly be looking at the dashboard and may feel \"stuck\". Teach them how to navigate BEFORE launching:\n\nExplain clearly:\n\n> Before we launch, you need to know how to move between tmux windows. Right now you're in a window with Claude. When sisyphus starts, it'll open a dashboard in a new window. Think of windows like tabs:\n>\n> \\`\\`\\`\n> Window 1 (you are here) Window 2 (dashboard)\n> ┌──────────────────┐ ┌──────────────────┐\n> │ Claude Code │ │ Sisyphus │\n> │ (this session) │ → │ Dashboard │\n> └──────────────────┘ └──────────────────┘\n> Ctrl+n → ← Ctrl+p\n> \\`\\`\\`\n>\n> - **\\`Ctrl+n\\`** — next window (go to dashboard)\n> - **\\`Ctrl+p\\`** — previous window (come back here)\n>\n> And remember from step 3:\n> - **Right Option + s** — jump to the sisyphus agent session (where you can watch agents work live)\n> - **Right Option + Shift + s** — jump back to dashboard\n\nHave the user confirm they understand these keybinds before proceeding.\n\n### 3. Set expectations, copy demo app, and launch\n\nFirst, copy the demo todo app to a temp directory and init a git repo (sisyphus needs git):\n\\`\\`\\`\nrm -rf /tmp/sisyphus-tutorial-demo\ncp -r ${templatePath('tutorial-demo')} /tmp/sisyphus-tutorial-demo\ngit -C /tmp/sisyphus-tutorial-demo init\ngit -C /tmp/sisyphus-tutorial-demo add -A\ngit -C /tmp/sisyphus-tutorial-demo commit -m \"Initial todo app\"\n\\`\\`\\`\n\nTell the user:\n\n> I've set up a small todo app in /tmp/sisyphus-tutorial-demo — a Node.js API\n> with a few files. I'm going to launch sisyphus on it. Here's what will happen:\n> 1. The dashboard opens automatically (you'll be switched to it)\n> 2. Press **Ctrl+p** to come back here to Claude — I'll guide you through what to watch\n> 3. The session takes a few minutes. You can watch agents work live!\n\nThen launch from the demo directory:\n\\`\\`\\`\ncd /tmp/sisyphus-tutorial-demo && sis start \"Add three improvements to this todo app: (1) add a priority field (high/medium/low) to todos, (2) add a GET /todos/stats endpoint that returns counts of total/done/pending todos, (3) add tests for the new features. Explain your thinking at each step.\" -c \"TUTORIAL DEMO: A user is watching this session to learn how sisyphus works. Be EXTRA VERBOSE — explain your reasoning, narrate what you're doing, and make your planning visible. When spawning agents, give each agent context that this is a tutorial demo and they should explain their work clearly. Keep scope small: 2-3 agents, 1-2 cycles.\"\n\\`\\`\\`\n\nAfter launching, tell them:\n\n> The dashboard just opened. Press **Ctrl+p** to come back here — I'll provide live commentary as the session runs so you know what's happening.\n\nWait for them to confirm they're back, then start live commentary.\n\n### 4. Live commentary loop\n\n**This is the most important part of the demo.** Don't just launch and wait — actively narrate.\n\nOnce the user is back, start a polling loop. Every ~45 seconds, run \\`sis status --verbose <session-id>\\` and provide SHORT, contextual commentary about what's happening. The \\`--verbose\\` flag shows agent instructions, full roadmap, cycle logs, and live pane output from the orchestrator and running agents — use this rich data to narrate what's actually happening, not just phase names.\n\n**How to narrate each phase:**\n\n- **Cycle 1, no agents yet**: \"The orchestrator is reading the codebase and planning. It's figuring out how to split the work. Check the dashboard (\\`Ctrl+n\\`) — you'll see the roadmap updating.\"\n\n- **Agents spawning**: \"Agents just spawned! You should see new panes appearing. Try \\`Right Option + s\\` to jump to the sisyphus session and watch them work. Each colored pane is an independent Claude instance.\"\n\n- **Agents working**: \"Agent-001 is working on [X], Agent-002 is on [Y]. They're working in parallel — this is the key advantage of sisyphus. Jump over and watch if you like (\\`Right Option + s\\`).\"\n\n- **Agents submitting**: \"Agent-001 just submitted its report! [N] more to go. When all agents finish, the orchestrator will respawn to review.\"\n\n- **Between cycles**: \"All agents done. The orchestrator is respawning with fresh context to review the reports and decide what's next. This is the cycle boundary — the orchestrator never runs out of context because it starts fresh each time.\"\n\n- **Completion**: \"The session is complete! Let me show you the results.\"\n\n**Important:**\n- Keep commentary to 1-3 sentences per check — don't wall-of-text\n- Remind them of navigation keys when relevant (\"jump over with Right Option + s to see this live\")\n- If agents are still working with no change, say so briefly (\"Still working... Agent-001 is the furthest along\")\n- Reference specific agent names and tasks from the status output\n- Stop polling when status shows \"completed\"\n\nBetween polls, encourage the user to explore:\n> \"While we wait, try jumping around: \\`Ctrl+n\\` for dashboard, \\`Right Option + s\\` for the agent session, \\`Right Option + Shift + s\\` to jump back. I'll keep narrating here.\"\n\n### 5. After completion\n\nOnce the session shows \"completed\":\n\n- Show them what the agents built: \\`cd /tmp/sisyphus-tutorial-demo && git log --oneline\\`\n- Run the tests to prove the work: \\`cd /tmp/sisyphus-tutorial-demo && node --test test.js\\`\n- Show the session artifacts: find the session dir in \\`.sisyphus/sessions/\\` and show \\`roadmap.md\\`\n- Explain: \"Every session creates a roadmap, agent reports, and logs — all stored in .sisyphus/sessions/\"\n\n### 6. Proceed to wrap-up\n\nTell the user the demo is done. Then run:\n\\`\\`\\`\nsis admin getting-started --tutorial 5\n\\`\\`\\`\n</claude-instructions>\n`);\n}\n\nfunction printStep5(): void {\n // Gather codebase context for suggestions\n let recentCommits = '';\n let topLevelFiles = '';\n try {\n recentCommits = execSync('git log --oneline -15 2>/dev/null', { encoding: 'utf-8' }).trim();\n } catch { /* not in a git repo */ }\n try {\n topLevelFiles = execSync('ls -1 2>/dev/null', { encoding: 'utf-8' }).trim();\n } catch { /* ignore */ }\n\n console.log(`\n<claude-instructions>\n# Sisyphus Getting Started — Step 5: What's Next\n\n## Codebase Context\n<recent-commits>\n${recentCommits || '(no git repo detected)'}\n</recent-commits>\n\n<top-level-files>\n${topLevelFiles || '(could not list)'}\n</top-level-files>\n\n## Instructions for Claude\n\n### 1. Congratulate them\n\nTell them they've completed the tutorial and recap what they learned:\n- tmux basics (sessions, panes, navigation)\n- nvim basics for reviewing files\n- The sisyphus session model (separate tmux session for orchestrator + agents)\n- Monitoring with dashboard and keybinds\n- A live session lifecycle\n\n### 2. Navigation cheat sheet\n\n| Key | Action |\n|-----|--------|\n| \\`Ctrl+n\\` / \\`Ctrl+p\\` | Next/previous tmux window |\n| \\`Ctrl+h/j/k/l\\` | Navigate between panes |\n| \\`Right Option + s\\` | Jump to sisyphus agent session |\n| \\`Right Option + Shift + s\\` | Jump to dashboard |\n\n### 3. How to use sisyphus for REAL work\n\nThis is the most important part. Explain clearly:\n\n> **Sisyphus is for big, end-to-end features — the kind that need exploration,\n> planning, and parallel implementation across multiple systems.**\n>\n> You don't need to define the task precisely. Broad is fine — the orchestrator\n> will explore the codebase, write specs, plan phases, and break it down itself.\n\n**Real sisyphus sessions (from production use):**\n- \"Design and implement a human-in-the-loop agent inbox system\" — exploration, spec writing, DB schema, API endpoints, UI components, webhook integration, e2e validation\n- \"Build multi-user organization features — invites, privilege gating, org switcher, workspace sharing, credit tracking\" — touched auth, DB, API, UI, billing, permissions\n- \"Rework all 5 worker onboarding templates to match production pipeline patterns\" — mapped existing patterns, designed new architecture, implemented across templates, validated with e2e tests\n- \"Autonomous failure detection system across 8 sequential phases\" — monitoring, alerting, recovery, dashboard, with each phase building on the last\n- \"Comprehensive code quality audit — find and fix dead code, null handling, useless fallbacks\" — systematic codebase-wide analysis and cleanup\n- \"Implement @requirements.md\" — point it at a spec and let it go\n\n**NOT good for sisyphus:**\n- Five unrelated small tasks bundled together (\"fix the login bug, update the README, add a loading spinner\") — these aren't one feature, they're a todo list\n- Something Claude Code in plan mode would handle — plan mode already handles substantial single-engineer work. If it fits in one Claude session, just do it directly.\n- Quick fixes, bug fixes, small refactors — use regular Claude Code\n\n**How to start:**\nThe easiest way is the \\`/sisyphus:begin\\` slash command inside Claude Code. Just tell Claude\nwhat you want to build and it'll hand it off to sisyphus with the right context.\n\nOr directly: \\`sis start \"your task\" -c \"any background context\"\\`\n\n### 4. Suggest real tasks for THEIR codebase\n\nLook at the recent commits and top-level files above. Based on what you can see of their project, suggest 2-3 concrete sisyphus-scale tasks they could try. Be specific to their codebase — reference actual directories, patterns, or areas you can see.\n\nIf there are no commits or files (e.g., they ran this from /tmp), skip this section.\n\nFormat as:\n> Based on your codebase, here are some tasks sisyphus would be great for:\n> - \"...\"\n> - \"...\"\n\n### 5. There's more to learn\n\nTell them:\n\n> There's actually a lot of depth to how sisyphus works — the design is intentional\n> and there's real reasoning behind why it does things the way it does. If you want\n> to understand the philosophy, or you want a deeper rundown on the dashboard,\n> monitoring, configuration, or how to steer sessions — just ask and I'll explain.\n\nIf the user says yes or asks to learn more, run \\`sis admin getting-started --explain\\`\nand use its output to explain the system to them conversationally. Don't dump the whole\nthing — answer what they're curious about, using the reference as your source material.\n</claude-instructions>\n`);\n}\n\nfunction buildCommandTable(program: Command): string {\n const lines: string[] = ['| Command | Purpose |', '|---------|---------|'];\n for (const cmd of program.commands) {\n if ((cmd as unknown as { _hidden: boolean })._hidden) continue;\n if (cmd.name() === 'help') continue;\n const subs = cmd.commands.filter(c => !(c as unknown as { _hidden: boolean })._hidden && c.name() !== 'help');\n const hasOwnAction = (cmd as unknown as { _actionHandler?: unknown })._actionHandler != null;\n const fmtArgs = (c: typeof cmd) =>\n c.registeredArguments.map(a => a.required ? `<${a.name()}>` : `[${a.name()}]`).join(' ');\n if (subs.length === 0) {\n // flat or argument-only command\n const args = fmtArgs(cmd);\n const usage = args ? `sis ${cmd.name()} ${args}` : `sis ${cmd.name()}`;\n lines.push(`| \\`${usage}\\` | ${cmd.description()} |`);\n } else {\n // group: if it has its own root action (e.g. `companion`), emit a row for the bare invocation first\n if (hasOwnAction) {\n const args = fmtArgs(cmd);\n const usage = args ? `sis ${cmd.name()} ${args}` : `sis ${cmd.name()}`;\n lines.push(`| \\`${usage}\\` | ${cmd.description()} |`);\n }\n // then one row per subcommand\n for (const sub of subs) {\n const args = fmtArgs(sub);\n const usage = args ? `sis ${cmd.name()} ${sub.name()} ${args}` : `sis ${cmd.name()} ${sub.name()}`;\n lines.push(`| \\`${usage}\\` | ${sub.description()} |`);\n }\n }\n }\n return lines.join('\\n');\n}\n\nfunction printExplain(program: Command): void {\n console.log(`\n<claude-instructions>\n# Sisyphus — Comprehensive Reference\n\nThis is a detailed reference for how sisyphus works. The user asked to understand\nsisyphus more deeply. Use this to answer their questions conversationally — don't dump\nthe whole thing. Read through it, then respond to what they're curious about.\n\n## Design Philosophy\n\nSisyphus is built on specific insights about how to get the best work out of LLM agents.\nThese aren't arbitrary — each design decision solves a real failure mode.\n\n### 1. The Orchestrator as \"Human-in-the-Loop\"\n\nWhen you use Claude Code effectively, YOU are the orchestrator — you review work,\nsteer direction, break problems down, and assign the next piece. Sisyphus automates\nthat human role. The orchestrator does what a skilled developer does when prompting\nClaude: explore the codebase, understand the problem, write specs, plan phases,\nassign focused work, review results, and iterate.\n\nThe strategy layer mirrors how developers actually work on end-to-end features:\nexplore, understand, spec, plan, implement, review, validate. The orchestrator\nfollows this same workflow, but runs it with parallel agents.\n\n### 2. Fresh Context Kills Shortcuts\n\nThe orchestrator is KILLED after every cycle and respawned fresh. This is the most\nimportant design decision.\n\nWhen an LLM accumulates context over a long session, it starts taking shortcuts.\nIt \"knows\" what it did earlier, so it skips re-reading, assumes things still hold,\nand builds on stale understanding. A fresh start forces honest reassessment every\ncycle — the orchestrator reads the actual state, not its memory of it.\n\nThis is inspired by adversarial training (think GANs) — better results come from\nadversarial pressure. Each fresh orchestrator effectively audits the previous cycle's\nwork because it has no stake in defending prior decisions. It sees the roadmap, the\nreports, the code — and judges them with fresh eyes.\n\n### 3. Single-Focus Agents\n\nEach agent gets ONE task with a fully self-contained instruction. No context switching,\nno juggling multiple concerns, no \"also while you're there could you...\"\n\nLLMs perform dramatically better when focused. An agent implementing a priority field\ndoesn't think about the stats endpoint. It reads the relevant context, does its one\nthing well, and reports back. The orchestrator handles decomposition — agents handle\nexecution.\n\n### 4. Shared Context Directory (Saved Research)\n\nEvery session has a context/ directory where agents save research, specs, plans, and\ndesign docs. These files persist across ALL cycles and are visible to the orchestrator\nand subsequent agents.\n\nThis means research is never repeated. Cycle 1 agents explore and write findings to\ncontext/explore-auth-system.md. Cycle 3 agents read those findings and build on them.\nKnowledge accumulates even though the orchestrator itself is stateless.\n\nPlan lead agents save their plans under context/{agent-id}/ so parallel plan agents\ndon't interfere with each other's validation.\n\n### 5. Two-Layer Planning (Strategy + Roadmap)\n\nThe system maintains two documents at different abstraction levels:\n\n**strategy.md** — The high-level problem-solving map. What phases exist, what gates\nbetween them, what backtrack paths exist. Updated every few cycles when the shape of\nwork changes. Helps the orchestrator see the forest.\n\n**roadmap.md** — Working memory. Updated every cycle. Current Stage, Exit Criteria,\nActive Context, Next Steps. The orchestrator reads this first each cycle to understand\nwhere things stand. Helps the orchestrator see the trees.\n\nThis prevents the failure mode where a single document becomes either too abstract\nto act on or too detailed to show the big picture.\n\n### 6. Adversarial Review Is Built In\n\nThe orchestrator doesn't just implement — it runs mandatory critique cycles. After\nimplementation, review agents attack different dimensions: code reuse, quality,\nefficiency, correctness. Fix agents address the findings. Re-review until only nits\nremain. Multiple agents auditing each other produces better results than any single\nagent reviewing its own work.\n\nThe rule: never let 2+ stages complete without critique. Small issues compound into\narchitectural problems if unchecked.\n\n### 7. Evidence Over Assumptions\n\nValidation requires PROOF — command output, test results, HTTP responses. \"The code\nlooks correct\" is not evidence. \"All 14 tests pass\" is. This catches the gap between\ncode that looks right and code that works.\n\n## Architecture Overview\n\n\\`\\`\\`\n┌─────────────────────────────────────────────────────────────────────┐\n│ USER'S TMUX SESSION │\n│ │\n│ ┌─────────────────────────┐ ┌──────────────────────────────────┐ │\n│ │ Window 1: Claude Code │ │ Window 2: Dashboard (TUI) │ │\n│ │ │ │ │ │\n│ │ User's normal work │ │ Real-time session monitor │ │\n│ │ + this conversation │ │ Roadmap, agents, reports │ │\n│ │ │ │ Interactive controls │ │\n│ └─────────────────────────┘ └──────────────────────────────────┘ │\n└──────────────────────────────────┬──────────────────────────────────┘\n │ Right Option+s / Right Option+Shift+s\n ▼\n┌─────────────────────────────────────────────────────────────────────┐\n│ SISYPHUS TMUX SESSION │\n│ (created per sisyphus session) │\n│ │\n│ ┌──────────┬──────────┬──────────┬──────────┐ │\n│ │ Orch │ Agent │ Agent │ Agent │ ← panes │\n│ │ (yellow) │ (blue) │ (green) │ (magenta)│ │\n│ │ │ │ │ │ │\n│ │ Plans, │ Impl │ Tests │ Docs │ ← each is a │\n│ │ assigns, │ feature │ │ │ Claude Code │\n│ │ reviews │ │ │ │ instance │\n│ └──────────┴──────────┴──────────┴──────────┘ │\n└─────────────────────────────────────────────────────────────────────┘\n │\n ▼\n┌─────────────────────────────────────────────────────────────────────┐\n│ DAEMON (sisyphusd) │\n│ Background process via launchd │\n│ │\n│ Listens on ~/.sisyphus/daemon.sock │\n│ Manages session lifecycle, pane monitoring, state persistence │\n│ Polls panes to detect when agents/orchestrator finish │\n└─────────────────────────────────────────────────────────────────────┘\n\\`\\`\\`\n\n## The Session Lifecycle (in detail)\n\n\\`\\`\\`\n ┌──────────────────────────────────────────────────────────────────┐\n │ SESSION LIFECYCLE │\n │ │\n │ sis start \"task\" │\n │ │ │\n │ ▼ │\n │ ┌─────────┐ spawn agents ┌──────────────┐ │\n │ │ Orch │ ──────────────────→ │ Agents work │ │\n │ │ plans │ then yields │ in parallel │ │\n │ └────┬────┘ └──────┬───────┘ │\n │ │ │ each calls │\n │ │ orchestrator │ sis agent submit │\n │ │ is KILLED │ when done │\n │ │ ▼ │\n │ │ ┌──────────────┐ │\n │ │ │ All agents │ │\n │ │ │ finished? │ │\n │ │ └──────┬───────┘ │\n │ │ │ yes │\n │ │ ┌──────────────────────┘ │\n │ │ ▼ │\n │ │ ┌─────────┐ │\n │ └──── │ Respawn │ Fresh orchestrator with full state │\n │ next cycle │ Orch │ Reviews reports, plans next cycle │\n │ └────┬────┘ │\n │ │ │\n │ ▼ │\n │ ┌───────────────┐ ┌───────────┐ │\n │ │ More work │──yes──→ │ Spawn │ → (loop) │\n │ │ needed? │ │ agents │ │\n │ └───────┬───────┘ └───────────┘ │\n │ │ no │\n │ ▼ │\n │ ┌───────────────┐ │\n │ │ sisyphus │ │\n │ │ complete │ │\n │ └───────────────┘ │\n └──────────────────────────────────────────────────────────────────┘\n\\`\\`\\`\n\n**Key insight**: The orchestrator is STATELESS. It gets killed after each yield and\nrespawned fresh with the complete session state (roadmap, agent reports, cycle history).\nThis means it never runs out of context, no matter how many cycles a session takes.\n\n## The Dashboard\n\nThe dashboard is a real-time TUI that shows session state. Launch with \\`sis dashboard\\`\nor it auto-opens when a session starts.\n\n**Dashboard sections:**\n- **Header**: Session ID, status, task description\n- **Roadmap**: Current strategic plan with checked/unchecked items\n- **Agents**: List of all agents with status, duration, and report summaries\n- **Cycles**: Orchestrator cycle history\n- **Messages**: Recent session messages\n\n**Dashboard keys:**\n| Key | Action |\n|-----|--------|\n| \\`m\\` | Message the orchestrator (steer direction mid-session) |\n| \\`w\\` | Jump to the sisyphus tmux session (watch agents work) |\n| \\`k\\` | Kill the session |\n| \\`r\\` | Resume a paused/completed session |\n| \\`q\\` | Quit the dashboard |\n| \\`↑/↓\\` | Scroll through content |\n| \\`Tab\\` | Cycle through sections |\n\n**The \\`m\\` key is the most powerful feature.** You can message the orchestrator at any time\nto course-correct: \"Focus on the API layer first\", \"Skip the tests for now\",\n\"The approach for auth is wrong, use JWT instead\". The orchestrator reads these\nmessages when it respawns each cycle.\n\n## Monitoring Strategy\n\nSisyphus sessions should be actively monitored. Here's what to watch for:\n\n**Things that go wrong:**\n- Agents stuck waiting for user input (they're autonomous — they shouldn't need input)\n- Agents going down rabbit holes or working on the wrong thing\n- Merge conflicts between agents touching the same files\n- Orchestrator spawning too many agents or too few\n- Agents crashing or getting killed unexpectedly\n\n**When to intervene:**\n- Use \\`m\\` in the dashboard to message the orchestrator with corrections\n- Use \\`sis session kill <id>\\` to stop a runaway session\n- Use \\`sis session resume <id> \"new instructions\"\\` to restart with different direction\n\n**Useful monitoring commands:**\n\\`\\`\\`\nsis status <id> # Quick status check\nsis status --verbose <id> # Full detail: roadmap, pane output, agent instructions\nsis dashboard # Interactive TUI\ntail -f ~/.sisyphus/daemon.log # Daemon activity log\n\\`\\`\\`\n\n## The .sisyphus/ Directory\n\nEverything sisyphus does lives in a \\`.sisyphus/\\` directory at the root of your project.\nThis is project-local — each project gets its own. It contains:\n\n\\`\\`\\`\n.sisyphus/\n├── config.json # Project-specific config (model, poll interval, etc.)\n├── orchestrator.md # Optional custom orchestrator prompt override\n└── sessions/\n ├── <session-id-1>/ # Each session gets its own directory\n ├── <session-id-2>/\n └── ...\n\\`\\`\\`\n\nThere's also a global directory at \\`~/.sisyphus/\\` for the daemon socket, PID file,\nlogs, keybind scripts, and global config. But the session state — the roadmaps,\nreports, context files, cycle logs — all lives in your project's \\`.sisyphus/sessions/\\`.\n\n## Session Files\n\nEvery session creates a directory at \\`.sisyphus/sessions/<id>/\\` with:\n\n\\`\\`\\`\n.sisyphus/sessions/<id>/\n├── state.json # Session state (agents, cycles, status)\n├── roadmap.md # Strategic plan (updated by orchestrator each cycle)\n├── goal.md # Original task description\n├── initial-prompt.md # Immutable record of the initial user prompt\n├── strategy.md # High-level strategy notes\n├── logs/\n│ ├── cycle-000.md # What the orchestrator did in cycle 0\n│ ├── cycle-001.md # What it did in cycle 1, etc.\n│ └── ...\n├── reports/\n│ ├── agent-001-final.md # Agent's final report\n│ ├── agent-002-update.md # Agent's progress update\n│ └── ...\n├── prompts/ # System/user prompts sent to orchestrator and agents\n└── context/ # Shared context files for agents\n\\`\\`\\`\n\n## Configuration\n\n**Global config**: \\`~/.sisyphus/config.json\\`\n**Project config**: \\`.sisyphus/config.json\\` (overrides global)\n\nOptions:\n- \\`model\\` — Claude model for orchestrator and agents\n- \\`orchestratorPrompt\\` — Path to custom orchestrator prompt\n- \\`pollIntervalMs\\` — How often daemon checks pane status (default: 2000)\n\n## Starting Sessions — Best Practices\n\n**The /sisyphus:begin slash command** is the recommended way to start. Inside Claude Code:\n\\`\\`\\`\n/sisyphus:begin\n\\`\\`\\`\nThen describe your task. Claude will hand it off with the right context.\n\n**Direct CLI:**\n\\`\\`\\`\nsis start \"task description\" -c \"background context\"\nsis start \"Implement @requirements.md\" -n my-feature\n\\`\\`\\`\n\n**Reference files with @**: \\`sis start \"Build @docs/spec.md\"\\` — the orchestrator\nwill read the referenced file as part of its planning.\n\n**The -c flag** adds background context the orchestrator sees but doesn't act on directly.\nUse it for constraints: \\`-c \"Don't modify the auth module, use the existing API\"\\`\n\n**The -n flag** gives the session a human-readable name for easier tracking.\n\n## CLI Command Reference\n\n${buildCommandTable(program)}\n\n## Troubleshooting\n\n**Daemon not running:**\n\\`\\`\\`\nsisyphusd restart\n\\`\\`\\`\n\n**Keybinds not working (special characters appear):**\niTerm2 → Settings → Profiles → Keys → Right Option Key → Esc+\n\n**Agents stuck:** Check \\`sis status --verbose <id>\\` to see pane output. If an\nagent is waiting for input, kill the session and restart with clearer instructions.\n\n**Dashboard not opening:** Run \\`sis dashboard\\` manually. Must be inside tmux.\n\n**Session seems hung:** Check \\`tail -20 ~/.sisyphus/daemon.log\\` for errors.\nThe daemon polls panes every 2s — if a pane dies unexpectedly, it'll be detected.\n</claude-instructions>\n`);\n}\n\nconst STEPS: Array<() => void> = [printStep0, printStep1, printStep2, printStep3, printStep4, printStep5];\n\nexport function registerGettingStarted(program: Command): void {\n program\n .command('getting-started')\n .description('Interactive tutorial (best with Claude Code)')\n .option('--tutorial <step>', 'Tutorial step (0-5)', parseInt)\n .option('--explain', 'Comprehensive reference for how sisyphus works')\n .action((opts) => {\n if (opts.explain) {\n printExplain(program);\n return;\n }\n if (opts.tutorial !== undefined) {\n const step = opts.tutorial as number;\n if (step < 0 || step > 5 || Number.isNaN(step)) {\n console.error(`Invalid tutorial step: ${opts.tutorial}. Must be 0-5.`);\n process.exit(1);\n }\n STEPS[step]!();\n return;\n }\n if (!isClaudeCode()) {\n printNonClaudeMessage();\n return;\n }\n printStep0();\n });\n}\n","import type { Command } from 'commander';\nimport { readdirSync, readFileSync, existsSync } from 'node:fs';\nimport { join, resolve } from 'node:path';\nimport { historyBaseDir, historySessionDir, historyEventsPath, historySessionSummaryPath, statePath } from '../../shared/paths.js';\nimport { formatDuration, statusColor } from '../../shared/format.js';\nimport type { SessionSummary, SessionSummaryAgent } from '../../shared/history-types.js';\nimport type { HistoryEvent } from '../../shared/history-types.js';\nimport type { Session } from '../../shared/types.js';\n\nconst RESET = '\\x1b[0m';\nconst BOLD = '\\x1b[1m';\nconst DIM = '\\x1b[2m';\nconst COLOR: Record<string, string> = {\n green: '\\x1b[32m', yellow: '\\x1b[33m', cyan: '\\x1b[36m',\n red: '\\x1b[31m', gray: '\\x1b[90m', white: '\\x1b[37m', magenta: '\\x1b[35m',\n};\n\nfunction c(color: string, text: string): string {\n return `${COLOR[color] ?? ''}${text}${RESET}`;\n}\n\n// Agent types that run interactive TUI sessions. Their activeMs includes\n// user think-time while the pane is open — not actual compute. Treat\n// separately from compute-only agent types in efficiency metrics.\nconst INTERACTIVE_AGENT_TYPES = new Set<string>([\n 'sisyphus:requirements',\n 'sisyphus:design',\n 'sisyphus:spec',\n]);\n\nfunction isInteractiveAgent(agentType: string | null | undefined): boolean {\n return agentType != null && INTERACTIVE_AGENT_TYPES.has(agentType);\n}\n\nfunction splitAgentTime(agents: SessionSummaryAgent[]): { computeMs: number; interactiveMs: number; blockedMs: number } {\n let computeMs = 0;\n let interactiveMs = 0;\n let blockedMs = 0;\n for (const a of agents) {\n const blocked = a.userBlockedMs ?? 0;\n const remaining = Math.max(0, a.activeMs - blocked);\n blockedMs += blocked;\n if (isInteractiveAgent(a.agentType)) interactiveMs += remaining;\n else computeMs += remaining;\n }\n return { computeMs, interactiveMs, blockedMs };\n}\n\n// ---------------------------------------------------------------------------\n// Data loading\n// ---------------------------------------------------------------------------\n\nfunction loadAllSummaries(): Array<{ id: string; summary: SessionSummary }> {\n const base = historyBaseDir();\n if (!existsSync(base)) return [];\n\n const results: Array<{ id: string; summary: SessionSummary }> = [];\n for (const name of readdirSync(base)) {\n const summaryPath = historySessionSummaryPath(name);\n if (existsSync(summaryPath)) {\n try {\n const raw = readFileSync(summaryPath, 'utf-8');\n results.push({ id: name, summary: JSON.parse(raw) as SessionSummary });\n continue;\n } catch { /* fall through to live rebuild */ }\n }\n // No session.json — synthesize from live state if session is still in-flight\n const live = buildLiveSummary(name);\n if (live) results.push({ id: name, summary: live });\n }\n // Newest first\n results.sort((a, b) => new Date(b.summary.startedAt).getTime() - new Date(a.summary.startedAt).getTime());\n return results;\n}\n\n/**\n * Synthesize a SessionSummary on demand for an in-flight session (no `session.json` yet).\n * Reads the session's `cwd` from the first `session-start` event, then reads live\n * `state.json` and maps it to the same shape `writeSessionSummary` produces.\n * Fields that are only finalized at completion are marked null/empty.\n * Returns null if events or live state can't be read.\n */\nfunction buildLiveSummary(sessionId: string): SessionSummary | null {\n const eventsPath = historyEventsPath(sessionId);\n if (!existsSync(eventsPath)) return null;\n\n // Extract cwd from the session-start event (only place it's recorded in the history dir)\n let cwd: string | null = null;\n try {\n const lines = readFileSync(eventsPath, 'utf-8').split('\\n');\n for (const line of lines) {\n if (!line.trim()) continue;\n try {\n const ev = JSON.parse(line) as HistoryEvent;\n if (ev.event === 'session-start' && typeof ev.data.cwd === 'string') {\n cwd = ev.data.cwd;\n break;\n }\n } catch { continue; }\n }\n } catch { return null; }\n if (!cwd) return null;\n\n const sPath = statePath(cwd, sessionId);\n if (!existsSync(sPath)) return null;\n\n let session: Session;\n try {\n session = JSON.parse(readFileSync(sPath, 'utf-8')) as Session;\n } catch { return null; }\n\n // Live wall clock: created → now. activeMs is already flushed periodically by the daemon;\n // both may lag the true live value by one poll interval (~seconds), acceptable for a read-only view.\n const liveWallClockMs = Date.now() - new Date(session.createdAt).getTime();\n\n return {\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 ?? null,\n activeMs: session.activeMs,\n wallClockMs: session.wallClockMs ?? liveWallClockMs,\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: liveWallClockMs > 0\n ? Math.max(0, session.activeMs - (session.userBlockedMs ?? 0))\n / Math.max(1, liveWallClockMs - (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: null,\n achievements: [],\n xpGained: 0,\n sentiment: null,\n };\n}\n\nfunction loadEvents(sessionId: string): HistoryEvent[] {\n const eventsPath = historyEventsPath(sessionId);\n if (!existsSync(eventsPath)) return [];\n const lines = readFileSync(eventsPath, 'utf-8').split('\\n').filter(l => l.trim());\n const events: HistoryEvent[] = [];\n for (const line of lines) {\n try { events.push(JSON.parse(line) as HistoryEvent); } catch { continue; }\n }\n return events;\n}\n\nfunction findSession(idOrName: string): { id: string; summary: SessionSummary } | null {\n // Try exact ID match first\n const summaryPath = historySessionSummaryPath(idOrName);\n if (existsSync(summaryPath)) {\n try {\n return { id: idOrName, summary: JSON.parse(readFileSync(summaryPath, 'utf-8')) as SessionSummary };\n } catch { /* fall through */ }\n }\n // Exact-ID path with no session.json — try live rebuild before falling back to search\n if (existsSync(historySessionDir(idOrName))) {\n const live = buildLiveSummary(idOrName);\n if (live) return { id: idOrName, summary: live };\n }\n // Search by name or partial ID (loadAllSummaries handles live rebuild for in-flight sessions)\n const all = loadAllSummaries();\n return all.find(s =>\n s.id.startsWith(idOrName) ||\n s.summary.name === idOrName ||\n s.summary.name?.includes(idOrName),\n ) ?? null;\n}\n\n// ---------------------------------------------------------------------------\n// Duration parsing\n// ---------------------------------------------------------------------------\n\nfunction parseSince(since: string): number {\n const match = since.match(/^(\\d+)\\s*(d|h|m|w)$/);\n if (!match) {\n console.error(`Error: invalid --since format \"${since}\". Use e.g. 7d, 24h, 30m, 2w`);\n process.exit(1);\n }\n const n = parseInt(match[1]!, 10);\n const unit = match[2]!;\n const ms = { d: 86400000, h: 3600000, m: 60000, w: 604800000 }[unit]!;\n return Date.now() - n * ms;\n}\n\n// ---------------------------------------------------------------------------\n// Formatters\n// ---------------------------------------------------------------------------\n\nfunction fmtStatus(status: string): string {\n return c(statusColor(status), status);\n}\n\nfunction fmtDate(iso: string): string {\n const d = new Date(iso);\n return d.toLocaleDateString('en-US', { month: 'short', day: 'numeric' }) + ' ' +\n d.toLocaleTimeString('en-US', { hour: '2-digit', minute: '2-digit', hour12: false });\n}\n\nfunction fmtProject(cwd: string): string {\n const parts = cwd.split('/');\n return parts.slice(-2).join('/');\n}\n\n// ---------------------------------------------------------------------------\n// Subcommands\n// ---------------------------------------------------------------------------\n\nfunction listSessions(opts: {\n cwd?: string; status?: string; since?: string; search?: string;\n limit: number; json: boolean;\n}): void {\n let sessions = loadAllSummaries();\n\n if (opts.cwd) {\n const abs = resolve(opts.cwd);\n sessions = sessions.filter(s => s.summary.cwd === abs);\n }\n if (opts.status) {\n sessions = sessions.filter(s => s.summary.status === opts.status);\n }\n if (opts.since) {\n const cutoff = parseSince(opts.since);\n sessions = sessions.filter(s => new Date(s.summary.startedAt).getTime() >= cutoff);\n }\n if (opts.search) {\n const q = opts.search.toLowerCase();\n sessions = sessions.filter(s =>\n s.summary.task.toLowerCase().includes(q) ||\n (s.summary.name ?? '').toLowerCase().includes(q) ||\n s.summary.messages.some(m => m.content.toLowerCase().includes(q)),\n );\n }\n\n sessions = sessions.slice(0, opts.limit);\n\n if (opts.json) {\n console.log(JSON.stringify(sessions.map(s => s.summary), null, 2));\n return;\n }\n\n if (sessions.length === 0) {\n console.log(c('gray', 'No sessions found.'));\n return;\n }\n\n for (const { summary: s } of sessions) {\n const name = s.name ? c('white', s.name) : c('gray', s.sessionId.slice(0, 8));\n const status = fmtStatus(s.status);\n const date = c('gray', fmtDate(s.startedAt));\n const dur = formatDuration(s.activeMs);\n const proj = c('gray', fmtProject(s.cwd));\n const agents = s.agentCount > 0 ? `${s.agentCount} agents` : '';\n const cycles = s.cycleCount > 0 ? `${s.cycleCount} cycles` : '';\n const meta = [agents, cycles, dur].filter(Boolean).join(', ');\n\n console.log(`${date} ${status} ${name} ${DIM}${meta}${RESET} ${proj}`);\n\n const taskPreview = s.task.length > 100 ? s.task.slice(0, 100) + '...' : s.task;\n console.log(` ${DIM}${taskPreview}${RESET}`);\n console.log('');\n }\n\n const total = loadAllSummaries().length;\n if (total > sessions.length) {\n console.log(c('gray', ` Showing ${sessions.length} of ${total} sessions. Use --limit or filters to see more.`));\n }\n}\n\nfunction showSession(idOrName: string, opts: { json: boolean; events: boolean }): void {\n const found = findSession(idOrName);\n if (!found) {\n console.error(`Error: session \"${idOrName}\" not found`);\n process.exit(1);\n }\n\n const { id, summary: s } = found;\n\n if (opts.json && !opts.events) {\n console.log(JSON.stringify(s, null, 2));\n return;\n }\n\n if (opts.events) {\n const events = loadEvents(id);\n if (opts.json) {\n console.log(JSON.stringify(events, null, 2));\n return;\n }\n if (events.length === 0) {\n console.log(c('gray', 'No events recorded.'));\n return;\n }\n for (const e of events) {\n const time = c('gray', fmtDate(e.ts));\n const event = c('cyan', e.event.padEnd(18));\n const data = formatEventData(e);\n console.log(`${time} ${event} ${data}`);\n }\n return;\n }\n\n // Detail view\n const inProgress = s.completedAt == null;\n const inProgressTag = inProgress ? ` ${c('yellow', '(in progress)')}` : '';\n console.log(`${BOLD}${s.name ?? s.sessionId.slice(0, 8)}${RESET} ${fmtStatus(s.status)}${inProgressTag}`);\n console.log(`${DIM}ID:${RESET} ${s.sessionId}`);\n console.log(`${DIM}Project:${RESET} ${s.cwd}`);\n console.log(`${DIM}Model:${RESET} ${s.model ?? 'default'}`);\n console.log(`${DIM}Started:${RESET} ${fmtDate(s.startedAt)}`);\n console.log(`${DIM}Ended:${RESET} ${s.completedAt ? fmtDate(s.completedAt) : c('gray', '— still running')}`);\n const { computeMs, interactiveMs } = splitAgentTime(s.agents);\n const wallStr = s.wallClockMs ? formatDuration(s.wallClockMs) : '—';\n console.log(`${DIM}Active:${RESET} ${formatDuration(s.activeMs)} ${DIM}Wall:${RESET} ${wallStr}`);\n if (interactiveMs > 0) {\n console.log(`${DIM}Compute:${RESET} ${formatDuration(computeMs)} ${DIM}Interactive:${RESET} ${formatDuration(interactiveMs)} ${DIM}(TUI wait time, not compute)${RESET}`);\n }\n if (s.userBlockedMs > 0) {\n console.log(`${DIM}Waiting on user:${RESET} ${formatDuration(s.userBlockedMs)} ${DIM}(blocked on sis ask, not compute)${RESET}`);\n }\n console.log('');\n\n // Task\n console.log(`${BOLD}Task${RESET}`);\n console.log(s.task);\n console.log('');\n\n // Context\n if (s.context) {\n console.log(`${BOLD}Context${RESET}`);\n console.log(s.context.length > 500 ? s.context.slice(0, 500) + '...' : s.context);\n console.log('');\n }\n\n // Agents\n if (s.agents.length > 0) {\n console.log(`${BOLD}Agents${RESET} (${s.agents.length})`);\n for (const a of s.agents) {\n const name = a.nickname ? `${a.name} \"${a.nickname}\"` : a.name;\n const type = a.agentType ? c('gray', ` [${a.agentType}]`) : '';\n const interactive = isInteractiveAgent(a.agentType) ? c('yellow', ' (interactive)') : '';\n const blocked = a.userBlockedMs ?? 0;\n const waiting = blocked > 0 ? ` ${DIM}· ${formatDuration(blocked)} waiting${RESET}` : '';\n console.log(` ${fmtStatus(a.status)} ${name}${type}${interactive} ${DIM}${formatDuration(a.activeMs)}${RESET}${waiting}`);\n }\n console.log('');\n }\n\n // Cycles\n if (s.cycles.length > 0) {\n console.log(`${BOLD}Cycles${RESET} (${s.cycles.length})`);\n for (const cy of s.cycles) {\n const mode = cy.mode ? c('magenta', cy.mode) : '';\n const blocked = cy.userBlockedMs ?? 0;\n const waiting = blocked > 0 ? ` ${DIM}· ${formatDuration(blocked)} waiting${RESET}` : '';\n console.log(` ${DIM}#${cy.cycle}${RESET} ${mode} ${cy.agentsSpawned} agents ${DIM}${formatDuration(cy.activeMs)}${RESET}${waiting}`);\n }\n console.log('');\n }\n\n // Messages\n if (s.messages.length > 0) {\n console.log(`${BOLD}Messages${RESET} (${s.messages.length})`);\n for (const m of s.messages) {\n const src = c('gray', m.source);\n const preview = m.content.length > 120 ? m.content.slice(0, 120) + '...' : m.content;\n console.log(` ${src} ${preview}`);\n }\n console.log('');\n }\n\n // Completion report\n if (s.completionReport) {\n console.log(`${BOLD}Completion Report${RESET}`);\n console.log(s.completionReport);\n console.log('');\n }\n\n // Achievements\n if (s.achievements.length > 0) {\n console.log(`${BOLD}Achievements Unlocked${RESET}`);\n console.log(` ${s.achievements.join(', ')}`);\n console.log('');\n }\n\n // Final mood signals\n if (s.finalMoodSignals) {\n const sig = s.finalMoodSignals;\n const parts = [\n sig.recentCrashes > 0 ? c('red', `${sig.recentCrashes} crashes`) : null,\n `${sig.activeAgentCount ?? 0} active agents`,\n `cycle ${sig.cycleCount ?? 0}`,\n `hour ${sig.hourOfDay}`,\n sig.idleDurationMs > 60000 ? `idle ${formatDuration(sig.idleDurationMs)}` : null,\n ].filter(Boolean);\n console.log(`${DIM}Final signals: ${parts.join(' · ')}${RESET}`);\n }\n}\n\nfunction formatEventData(e: HistoryEvent): string {\n const d = e.data;\n switch (e.event) {\n case 'session-start':\n return `${c('white', (d.task as string).slice(0, 80))} ${c('gray', fmtProject(d.cwd as string))}`;\n case 'session-named':\n return c('white', d.name as string);\n case 'agent-spawned':\n return `${c('white', d.agentId as string)} ${d.agentType ?? ''} ${DIM}${(d.instruction as string)?.slice(0, 60) ?? ''}...${RESET}`;\n case 'agent-nicknamed':\n return `${d.agentId} \"${c('white', d.nickname as string)}\"`;\n case 'agent-completed':\n return `${d.agentId} ${DIM}${formatDuration(d.activeMs as number)}${RESET} ${DIM}${(d.reportSummary as string)?.slice(0, 60) ?? ''}${RESET}`;\n case 'agent-exited':\n return `${d.agentId} ${fmtStatus(d.status as string)} ${d.reason ?? ''}`;\n case 'cycle-boundary':\n return `#${d.cycle} ${d.mode ? c('magenta', d.mode as string) : ''} ${d.agentsSpawned} agents`;\n case 'signals-snapshot': {\n const sig = d.signals as Record<string, unknown> | undefined;\n return `${d.from} → ${c('white', d.to as string)} ${sig ? `crashes=${sig.recentCrashes} agents=${sig.activeAgentCount ?? 0}` : ''}`;\n }\n case 'message':\n return `${c('gray', d.source as string)} ${(d.content as string).slice(0, 80)}`;\n case 'review-started': {\n const fileParts = typeof d.filePath === 'string' ? d.filePath.split('/').slice(-2).join('/') : '';\n return `${c('cyan', d.type as string)} ${c('gray', fileParts)}`;\n }\n case 'agent-killed':\n return `${d.agentId} ${fmtStatus(d.status as string)} ${DIM}${formatDuration(d.activeMs as number)}${RESET} ${d.reason ?? ''}`;\n case 'agent-restarted':\n return `${d.agentId} restart #${d.restartCount} ${DIM}was ${d.previousStatus}${RESET}`;\n case 'rollback':\n return `cycle ${d.fromCycle} → ${d.toCycle} ${d.killedAgentCount} agents killed`;\n case 'session-resumed':\n return `was ${fmtStatus(d.previousStatus as string)} ${d.lostAgentCount} agents lost`;\n case 'session-continued':\n return `${d.cycleCount} cycles ${DIM}${formatDuration(d.activeMs as number)}${RESET}`;\n case 'session-end':\n return `${fmtStatus(d.status as string)} ${formatDuration(d.activeMs as number)} ${d.agentCount} agents ${d.cycleCount} cycles`;\n default:\n return JSON.stringify(d);\n }\n}\n\nfunction showStats(opts: { cwd?: string; since?: string; json: boolean }): void {\n // Exclude in-flight sessions — their activeMs/wallClockMs are live snapshots that\n // would skew aggregate averages, efficiency, and percentiles.\n let sessions = loadAllSummaries().filter(s => s.summary.completedAt != null);\n\n if (opts.cwd) {\n const abs = resolve(opts.cwd);\n sessions = sessions.filter(s => s.summary.cwd === abs);\n }\n if (opts.since) {\n const cutoff = parseSince(opts.since);\n sessions = sessions.filter(s => new Date(s.summary.startedAt).getTime() >= cutoff);\n }\n\n if (sessions.length === 0) {\n console.log(c('gray', 'No sessions found.'));\n return;\n }\n\n const completed = sessions.filter(s => s.summary.status === 'completed');\n const killed = sessions.filter(s => s.summary.status === 'killed');\n const totalActiveMs = sessions.reduce((sum, s) => sum + s.summary.activeMs, 0);\n const totalAgents = sessions.reduce((sum, s) => sum + s.summary.agentCount, 0);\n const totalCycles = sessions.reduce((sum, s) => sum + s.summary.cycleCount, 0);\n const totalMessages = sessions.reduce((sum, s) => sum + s.summary.messages.length, 0);\n\n // Per-project breakdown\n const byProject = new Map<string, { count: number; activeMs: number; agents: number }>();\n for (const { summary: s } of sessions) {\n const proj = s.cwd;\n const entry = byProject.get(proj) ?? { count: 0, activeMs: 0, agents: 0 };\n entry.count++;\n entry.activeMs += s.activeMs;\n entry.agents += s.agentCount;\n byProject.set(proj, entry);\n }\n\n // Avg session duration\n const avgMs = totalActiveMs / sessions.length;\n\n // Efficiency\n const efficiencyValues: number[] = [];\n for (const { summary: s } of sessions) {\n const eff = s.efficiency ?? (s.wallClockMs\n ? Math.max(0, s.activeMs - (s.userBlockedMs ?? 0))\n / Math.max(1, s.wallClockMs - (s.userBlockedMs ?? 0))\n : null);\n if (eff != null) efficiencyValues.push(eff);\n }\n const avgEfficiency = efficiencyValues.length > 0\n ? efficiencyValues.reduce((a, b) => a + b, 0) / efficiencyValues.length\n : null;\n\n // Duration distributions (p50/p90)\n const sortedActiveMs = sessions.map(s => s.summary.activeMs).sort((a, b) => a - b);\n const n = sortedActiveMs.length;\n const p50Ms = n >= 3 ? sortedActiveMs[Math.ceil(50 / 100 * n) - 1]! : null;\n const p90Ms = n >= 3 ? sortedActiveMs[Math.ceil(90 / 100 * n) - 1]! : null;\n\n // Per-agent-type performance\n const agentTypeMap = new Map<string, { count: number; totalMs: number; crashed: number; completed: number }>();\n for (const { summary: s } of sessions) {\n for (const a of s.agents) {\n const type = a.agentType ?? 'untyped';\n const entry = agentTypeMap.get(type) ?? { count: 0, totalMs: 0, crashed: 0, completed: 0 };\n entry.count++;\n entry.totalMs += a.activeMs;\n if (a.status === 'crashed') entry.crashed++;\n if (a.status === 'completed') entry.completed++;\n agentTypeMap.set(type, entry);\n }\n }\n\n // Temporal patterns\n const hourBlocks = new Map<string, number>();\n const dayCounts = new Map<string, number>();\n const dayNames = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'];\n for (const { summary: s } of sessions) {\n const d = new Date(s.startedAt);\n const hour = d.getHours();\n const blockStart = hour - (hour % 2);\n const blockLabel = `${String(blockStart).padStart(2, '0')}:00–${String(blockStart + 2).padStart(2, '0')}:00`;\n hourBlocks.set(blockLabel, (hourBlocks.get(blockLabel) ?? 0) + 1);\n const day = dayNames[d.getDay()]!;\n dayCounts.set(day, (dayCounts.get(day) ?? 0) + 1);\n }\n\n if (opts.json) {\n console.log(JSON.stringify({\n total: sessions.length,\n completed: completed.length,\n killed: killed.length,\n totalActiveMs,\n avgActiveMs: Math.round(avgMs),\n avgEfficiency,\n p50Ms,\n p90Ms,\n totalAgents,\n totalCycles,\n totalMessages,\n byProject: Object.fromEntries([...byProject.entries()].map(([k, v]) => [k, v])),\n agentTypes: Object.fromEntries([...agentTypeMap.entries()].map(([k, v]) => [k, {\n ...v,\n avgMs: Math.round(v.totalMs / v.count),\n crashRate: v.count > 0 ? v.crashed / v.count : 0,\n completionRate: v.count > 0 ? v.completed / v.count : 0,\n }])),\n temporalPatterns: sessions.length >= 5 ? {\n hourBlocks: Object.fromEntries(hourBlocks),\n dayOfWeek: Object.fromEntries(dayCounts),\n } : null,\n }, null, 2));\n return;\n }\n\n console.log(`${BOLD}Session History Stats${RESET}`);\n console.log('');\n console.log(` ${BOLD}Sessions:${RESET} ${sessions.length} total ${c('cyan', `${completed.length} completed`)} ${c('red', `${killed.length} killed`)}`);\n const timeLine = ` ${BOLD}Time:${RESET} ${formatDuration(totalActiveMs)} total ${formatDuration(avgMs)} avg` +\n (p50Ms != null && p90Ms != null ? ` ${DIM}p50=${formatDuration(p50Ms)} p90=${formatDuration(p90Ms)}${RESET}` : '');\n console.log(timeLine);\n if (avgEfficiency != null) {\n const effColor = avgEfficiency >= 0.7 ? 'green' : avgEfficiency >= 0.4 ? 'yellow' : 'red';\n console.log(` ${BOLD}Efficiency:${RESET} ${c(effColor, (avgEfficiency * 100).toFixed(1) + '%')} ${DIM}(${efficiencyValues.length} sessions with data)${RESET}`);\n }\n console.log(` ${BOLD}Agents:${RESET} ${totalAgents} spawned (${(totalAgents / sessions.length).toFixed(1)} avg/session)`);\n console.log(` ${BOLD}Cycles:${RESET} ${totalCycles} total (${(totalCycles / sessions.length).toFixed(1)} avg/session)`);\n console.log(` ${BOLD}Messages:${RESET} ${totalMessages} total`);\n console.log('');\n\n console.log(`${BOLD}By Project${RESET}`);\n const sorted = [...byProject.entries()].sort((a, b) => b[1].count - a[1].count);\n for (const [proj, data] of sorted) {\n console.log(` ${c('gray', fmtProject(proj))} ${data.count} sessions ${formatDuration(data.activeMs)} ${data.agents} agents`);\n }\n\n // Per-agent-type performance table\n if (agentTypeMap.size > 0) {\n console.log('');\n console.log(`${BOLD}By Agent Type${RESET}`);\n const typeHeader = ` ${'Type'.padEnd(20)} ${'Count'.padStart(6)} ${'Avg Time'.padStart(10)} ${'Crash %'.padStart(8)} ${'Done %'.padStart(8)}`;\n console.log(`${DIM}${typeHeader}${RESET}`);\n const sortedTypes = [...agentTypeMap.entries()].sort((a, b) => b[1].count - a[1].count);\n for (const [type, data] of sortedTypes) {\n const avgTime = formatDuration(data.totalMs / data.count);\n const crashRate = data.count > 0 ? ((data.crashed / data.count) * 100).toFixed(0) + '%' : '0%';\n const completionRate = data.count > 0 ? ((data.completed / data.count) * 100).toFixed(0) + '%' : '0%';\n const crashColor = data.crashed > 0 ? 'red' : 'green';\n console.log(` ${type.padEnd(20)} ${String(data.count).padStart(6)} ${avgTime.padStart(10)} ${c(crashColor, crashRate.padStart(8))} ${c('cyan', completionRate.padStart(8))}`);\n }\n }\n\n // Temporal patterns\n if (sessions.length >= 5) {\n console.log('');\n console.log(`${BOLD}Temporal Patterns${RESET}`);\n const topBlocks = [...hourBlocks.entries()].sort((a, b) => b[1] - a[1]).slice(0, 3);\n console.log(` ${DIM}Busiest times:${RESET} ${topBlocks.map(([label, count]) => `${label} (${count})`).join(' ')}`);\n const dayOrder = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'];\n const dayParts = dayOrder.map(d => `${d} ${dayCounts.get(d) ?? 0}`);\n console.log(` ${DIM}By day:${RESET} ${dayParts.join(' ')}`);\n }\n}\n\n// ---------------------------------------------------------------------------\n// Registration\n// ---------------------------------------------------------------------------\n\nexport function registerHistory(program: Command): void {\n program\n .command('history')\n .description('Browse session history and metrics')\n .argument('[session]', 'Session ID or name to inspect')\n .option('--cwd <path>', 'Filter by project directory')\n .option('--status <status>', 'Filter by status (completed, killed)')\n .option('--since <duration>', 'Filter by recency (e.g. 7d, 24h, 2w)')\n .option('--search <query>', 'Search task text and messages')\n .option('--events', 'Show raw event timeline')\n .option('--stats', 'Show aggregate statistics')\n .option('--json', 'Output as JSON')\n .option('-n, --limit <n>', 'Max sessions to show', '20')\n .action(async (session: string | undefined, opts: {\n cwd?: string; status?: string; since?: string; search?: string;\n events?: boolean; stats?: boolean; json?: boolean; limit: string;\n }) => {\n const limit = parseInt(opts.limit, 10) || 20;\n const json = opts.json ?? false;\n\n if (opts.stats) {\n showStats({ cwd: opts.cwd, since: opts.since, json });\n return;\n }\n\n if (session) {\n showSession(session, { json, events: opts.events ?? false });\n return;\n }\n\n listSessions({\n cwd: opts.cwd,\n status: opts.status,\n since: opts.since,\n search: opts.search,\n limit,\n json,\n });\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 type { Command } from 'commander';\nimport { sendRequest } from '../client.js';\nimport type { Request } from '../../shared/protocol.js';\nimport type { Session } from '../../shared/types.js';\nimport { exportSessionToZip } from '../../shared/session-export.js';\n\nexport { exportSessionToZip };\n\nexport function registerExport(program: Command): void {\n program\n .command('export')\n .description('Export session data as zip to ~/Downloads')\n .argument('[session-id]', 'Session ID (defaults to SISYPHUS_SESSION_ID or active session)')\n .option('--cwd <path>', 'Project directory override')\n .action(async (sessionIdArg?: string, opts?: { cwd?: string }) => {\n let sessionId = sessionIdArg ?? process.env.SISYPHUS_SESSION_ID;\n const cwd = opts?.cwd ?? process.env['SISYPHUS_CWD'] ?? process.cwd();\n\n if (!sessionId) {\n const request: Request = { type: 'status', cwd };\n const response = await sendRequest(request);\n if (response.ok) {\n const session = response.data?.session as Session | undefined;\n if (session) {\n sessionId = session.id;\n }\n }\n }\n\n if (!sessionId) {\n console.error('Error: No session ID provided and no active session found.');\n console.error('Usage: sis admin export [session-id]');\n process.exit(1);\n }\n\n try {\n const outputPath = await exportSessionToZip(sessionId, cwd);\n console.log(`Exported to ${outputPath}`);\n } catch (err) {\n console.error(`Error: ${(err as Error).message}`);\n process.exit(1);\n }\n });\n}\n","import type { Command } from 'commander';\nimport { rmSync } from 'node:fs';\nimport { tmpdir } from 'node:os';\nimport { sendRequest } from '../client.js';\nimport type { Request } from '../../shared/protocol.js';\nimport type { Session } from '../../shared/types.js';\nimport { loadConfig } from '../../shared/config.js';\nimport { exportSessionToZip } from '../../shared/session-export.js';\nimport { uploadSession, isUploadConfigured } from '../../shared/upload.js';\nimport { buildManifest } from '../../shared/manifest.js';\nimport { getSession } from '../../daemon/state.js';\nimport { getSisyphusVersion } from '../../shared/version.js';\n\nexport function registerUpload(program: Command): void {\n program\n .command('upload')\n .description('Upload a session zip to the configured upload endpoint')\n .argument('[session-id]', 'Session ID (defaults to SISYPHUS_SESSION_ID or active session)')\n .option('--cwd <path>', 'Project directory override')\n .action(async (sessionIdArg?: string, opts?: { cwd?: string }) => {\n let sessionId = sessionIdArg ?? process.env.SISYPHUS_SESSION_ID;\n const cwd = opts?.cwd ?? process.env['SISYPHUS_CWD'] ?? process.cwd();\n\n if (!sessionId) {\n const request: Request = { type: 'status', cwd };\n const response = await sendRequest(request);\n if (response.ok) {\n const session = response.data?.session as Session | undefined;\n if (session) {\n sessionId = session.id;\n }\n }\n }\n\n if (!sessionId) {\n console.error('Error: No session ID provided and no active session found.');\n console.error('Usage: sis admin upload [session-id]');\n process.exit(1);\n }\n\n const config = loadConfig(cwd);\n if (!isUploadConfigured(config.upload)) {\n console.error(\n \"Error: upload not configured. Run 'sis admin configure-upload <url-with-token>' or set { upload: { url, token } } in .sisyphus/config.json.\",\n );\n process.exit(1);\n }\n\n let zipPath: string;\n try {\n zipPath = await exportSessionToZip(sessionId, cwd, { reveal: false, outputDir: tmpdir() });\n } catch (err) {\n console.error(`Error: ${(err as Error).message}`);\n process.exit(1);\n }\n\n try {\n const session = getSession(cwd, sessionId);\n if (session.status !== 'completed') {\n console.warn(`warning: session ${sessionId} is not completed (status: ${session.status}); uploading anyway`);\n }\n\n const manifest = buildManifest({ session, status: 'completed', config, sisyphusVersion: getSisyphusVersion() });\n\n let result: Awaited<ReturnType<typeof uploadSession>>;\n try {\n result = await uploadSession({ config: config.upload, zipPath, manifest });\n } catch (err) {\n const errMsg = (err as Error).message;\n const persistReq: Request = {\n type: 'set-upload-status',\n sessionId,\n cwd,\n status: 'failed',\n error: errMsg,\n };\n try {\n await sendRequest(persistReq);\n } catch {\n // daemon unreachable — best-effort\n }\n console.error(`Upload failed: ${errMsg}`);\n process.exit(1);\n }\n\n const persistReq: Request = {\n type: 'set-upload-status',\n sessionId,\n cwd,\n status: 'uploaded',\n storageKey: result!.storageKey,\n };\n try {\n const resp = await sendRequest(persistReq);\n if (!resp.ok) {\n console.warn(`warning: could not persist upload status (${resp.error ? resp.error : 'no error detail'})`);\n }\n } catch {\n console.warn('warning: daemon unreachable — upload status not persisted to session state');\n }\n\n console.log(`Uploaded to ${result!.storageKey}`);\n } finally {\n rmSync(zipPath!, { force: true });\n }\n });\n}\n","import { readFile } from 'node:fs/promises';\nimport type { SessionManifest } from './manifest.js';\nimport type { UploadConfig } from './config.js';\n\nexport type { UploadConfig };\n\nexport interface UploadResult {\n storageKey: string;\n userId: string;\n uploadedAt: string;\n}\n\nfunction parseWorkerError(body: string): string {\n try {\n const parsed = JSON.parse(body);\n if (parsed && typeof parsed.error === 'string') return parsed.error;\n } catch { /* fall through */ }\n return body;\n}\n\nexport class UploadError extends Error {\n constructor(public readonly status: number, rawBody: string) {\n const parsed = parseWorkerError(rawBody);\n super(`HTTP ${status}: ${parsed}`);\n }\n}\n\nexport function isUploadConfigured(upload: UploadConfig | undefined): upload is UploadConfig {\n return !!upload && upload.url.length > 0 && upload.token.length > 0;\n}\n\nexport async function uploadSession(args: {\n config: UploadConfig;\n zipPath: string;\n manifest: SessionManifest;\n}): Promise<UploadResult> {\n const { config, zipPath, manifest } = args;\n\n const formData = new FormData();\n formData.append('manifest', new Blob([JSON.stringify(manifest)], { type: 'application/json' }));\n formData.append('bundle', new Blob([await readFile(zipPath)], { type: 'application/zip' }), `${manifest.sessionId}.zip`);\n\n const res = await fetch(`${config.url}/upload`, {\n method: 'POST',\n headers: { Authorization: `Bearer ${config.token}` },\n body: formData,\n });\n\n if (!res.ok) {\n const rawBody = await res.text();\n const body = rawBody.length > 4096 ? rawBody.slice(0, 4096) + '… [truncated]' : rawBody;\n throw new UploadError(res.status, body);\n }\n\n return res.json() as Promise<UploadResult>;\n}\n","import os from 'node:os';\nimport type { Session } from './types.js';\nimport type { Config, EffortLevel } from './config.js';\n\nexport type ManifestStatus = 'completed' | 'failed' | 'cancelled';\nexport type ManifestEffortTier = 'low' | 'medium' | 'high' | 'xhigh';\n\nexport interface SessionManifest {\n // userId is omitted on the wire — Worker injects from token\n userId?: string;\n sessionId: string;\n sisyphusVersion: string;\n hostname: string;\n platform: NodeJS.Platform;\n status: ManifestStatus;\n completedAt: string;\n durationMs: number;\n wallClockMs: number;\n model: string;\n effortTier: ManifestEffortTier;\n cycleCount: number;\n agentCount: number;\n goal: string;\n}\n\n// 'max' is Config's wider effort level; collapse to 'xhigh' for the manifest's narrower union\nfunction mapEffortFallback(level: EffortLevel | undefined): ManifestEffortTier | undefined {\n if (level === undefined) return undefined;\n if (level === 'max') return 'xhigh';\n return level;\n}\n\nfunction resolveEffortTier(session: Session, config: Config): ManifestEffortTier {\n if (session.effort) return session.effort;\n const fromConfig = mapEffortFallback(config.orchestratorEffort);\n if (fromConfig) return fromConfig;\n return 'medium';\n}\n\nexport function buildManifest(args: {\n session: Session;\n // explicit — Session.status ('active' | 'paused' | 'completed') doesn't overlap with ManifestStatus\n status: ManifestStatus;\n config: Config;\n sisyphusVersion: string;\n}): SessionManifest {\n const { session, status, config, sisyphusVersion } = args;\n return {\n sessionId: session.id,\n sisyphusVersion,\n hostname: os.hostname(),\n platform: process.platform,\n status,\n completedAt: session.completedAt ?? new Date().toISOString(),\n durationMs: session.activeMs,\n wallClockMs: session.wallClockMs ?? 0,\n model: session.model ?? config.model ?? '',\n effortTier: resolveEffortTier(session, config),\n cycleCount: session.orchestratorCycles.length,\n agentCount: session.agents.length,\n goal: session.task.slice(0, 200),\n };\n}\n","import { readFileSync } from 'node:fs';\nimport { resolve } from 'node:path';\n\nfunction readSisyphusVersion(): string {\n // Bundled: dist/daemon.js → ../package.json\n // Source (tsx): src/shared/version.ts → ../../package.json\n for (const rel of ['../package.json', '../../package.json']) {\n try {\n const raw = readFileSync(resolve(import.meta.dirname, rel), 'utf-8');\n const pkg = JSON.parse(raw) as { name?: string; version?: string };\n if (pkg.name === 'sisyphi' && pkg.version) return pkg.version;\n } catch {}\n }\n return '0.0.0';\n}\n\nconst cachedVersion = readSisyphusVersion();\n\nexport function getSisyphusVersion(): string {\n return cachedVersion;\n}\n","import type { Command } from 'commander';\nimport { execSync } from 'node:child_process';\nimport { assertTmux } from '../tmux.js';\nimport { shellQuote } from '../../shared/shell.js';\n\n/**\n * Find the home session (non-ssyph_ session with matching @sisyphus_cwd).\n * Returns the tmux session name, or null if none found.\n *\n * Queries by $N session ID — tmux's -t <name> can substring-match the wrong\n * session under sparse env, and scratch may run from any shell context.\n */\nfunction findHomeSession(cwd: string): string | null {\n const normalizedCwd = cwd.replace(/\\/+$/, '');\n let output: string;\n try {\n output = execSync('tmux list-sessions -F \"#{session_id}|#{session_name}\"', {\n encoding: 'utf-8',\n stdio: ['pipe', 'pipe', 'pipe'],\n }).trim();\n } catch {\n return null;\n }\n for (const line of output.split('\\n').filter(Boolean)) {\n const pipeIdx = line.indexOf('|');\n if (pipeIdx < 0) continue;\n const sessId = line.slice(0, pipeIdx);\n const name = line.slice(pipeIdx + 1);\n if (name.startsWith('ssyph_')) continue;\n try {\n const val = execSync(\n `tmux show-options -t ${shellQuote(sessId)} -v @sisyphus_cwd`,\n { encoding: 'utf-8', stdio: ['pipe', 'pipe', 'pipe'] },\n ).trim();\n if (val === normalizedCwd) return name;\n } catch {\n // Option not set — skip\n }\n }\n return null;\n}\n\nexport function registerScratch(program: Command): void {\n program\n .command('scratch [prompt...]')\n .description('Open a standalone Claude Code session in the home tmux session')\n .option('-c, --cwd <path>', 'Working directory for the Claude session')\n .action((promptParts: string[], opts: { cwd?: string }) => {\n assertTmux();\n\n const cwd = opts.cwd ?? process.env['SISYPHUS_CWD'] ?? process.cwd();\n const homeSession = findHomeSession(cwd);\n\n if (!homeSession) {\n // Fall back to current tmux session\n const current = execSync('tmux display-message -p \"#{session_name}\"', {\n encoding: 'utf-8',\n }).trim();\n openScratchWindow(current, cwd, promptParts.join(' '));\n return;\n }\n\n openScratchWindow(homeSession, cwd, promptParts.join(' '));\n });\n}\n\nfunction openScratchWindow(tmuxSession: string, cwd: string, prompt: string): void {\n const windowId = execSync(\n `tmux new-window -t ${shellQuote(tmuxSession + ':')} -n \"scratch\" -c ${shellQuote(cwd)} -P -F \"#{window_id}\"`,\n { encoding: 'utf-8' },\n ).trim();\n\n let cmd = 'claude --dangerously-skip-permissions';\n if (prompt) {\n cmd += ` -p ${shellQuote(prompt)}`;\n }\n\n execSync(\n `tmux send-keys -t ${shellQuote(windowId)} ${shellQuote(cmd)} Enter`,\n );\n\n console.log(`Scratch session opened in ${tmuxSession}`);\n}\n","import type { Command } from 'commander';\nimport { join, resolve, dirname } from 'node:path';\nimport { existsSync, readFileSync, writeFileSync, renameSync, readdirSync } from 'node:fs';\nimport { contextDir, sessionsDir } from '../../shared/paths.js';\nimport type { RequirementStatus } from '../../shared/requirements-types.js';\n\n// Keeps the JSON Schema enum in sync with the TS union.\nconst _statusCheck: RequirementStatus[] = ['draft', 'question', 'approved', 'rejected', 'deferred'];\n\nfunction resolveContextArtifact(\n file: string | undefined,\n opts: { sessionId?: string; cwd?: string },\n filename: string,\n notFoundMessage: string,\n): string {\n const cwd = opts.cwd || process.env.SISYPHUS_CWD || process.cwd();\n if (file) return resolve(file);\n\n const sessionId = opts.sessionId || process.env.SISYPHUS_SESSION_ID;\n if (sessionId) {\n const target = join(contextDir(cwd, sessionId), filename);\n if (!existsSync(target)) {\n console.error(`Error: File not found: ${target}`);\n process.exit(1);\n }\n return target;\n }\n\n const dir = sessionsDir(cwd);\n if (existsSync(dir)) {\n const sessions = readdirSync(dir);\n for (const session of sessions.reverse()) {\n const candidate = join(dir, session, 'context', filename);\n if (existsSync(candidate)) return candidate;\n }\n }\n\n console.error(`Error: ${notFoundMessage}`);\n process.exit(1);\n}\n\nexport function registerReview(program: Command): void {\n program\n .command('requirements')\n .description('Export and inspect EARS requirements produced by `sisyphus:spec` (or compatible writers)')\n .argument('[file]', 'Path to requirements.json (auto-detected from session if omitted)')\n .option('--session-id <id>', 'Session ID to find requirements for')\n .option('--cwd <path>', 'Project directory')\n .option('--schema', 'Print the requirements.json schema and exit')\n .option('--annotated', 'Print the schema with writing guidance annotations and exit')\n .option('--export', 'Render requirements.json into requirements.md (no LLM tokens; overwrites existing requirements.md)')\n .option('--force', 'With --export: overwrite existing requirements.md even if hand-edited; existing file is moved to requirements.md.bak before overwrite')\n .addHelpText('after', `\nFile resolution (first match wins):\n 1. Positional [file] argument\n 2. --session-id (or SISYPHUS_SESSION_ID env) → .sisyphus/sessions/<id>/context/requirements.json\n 3. Most recent session with a requirements.json\n\nExamples:\n $ sis admin requirements Auto-detect from current session\n $ sis admin requirements path/to/requirements.json Open a specific file\n $ sis admin requirements --session-id abc123 Target a specific session\n $ sis admin requirements --schema Print the JSON schema\n $ sis admin requirements --annotated Print schema with writing guidance\n $ sis admin requirements --export Render requirements.md from JSON\n $ sis admin requirements --export --session-id abc123 Target a specific session\n $ sis admin requirements --export --force Overwrite even if hand-edited\n`)\n .action(async (file, opts) => {\n if (opts.force && !opts.export) {\n console.error('Error: --force requires --export');\n process.exit(1);\n }\n if (opts.export && opts.schema) {\n console.error('Error: --export cannot be combined with --schema');\n process.exit(1);\n }\n if (opts.export && opts.annotated) {\n console.error('Error: --export cannot be combined with --annotated');\n process.exit(1);\n }\n if (opts.export) {\n const targetPath = resolveContextArtifact(\n file,\n opts,\n 'requirements.json',\n 'No requirements.json found. Provide a path or use --session-id.',\n );\n\n if (!existsSync(targetPath)) {\n console.error(`Error: File not found: ${targetPath}`);\n process.exit(1);\n }\n\n const parsed = JSON.parse(readFileSync(targetPath, 'utf-8')) as Record<string, unknown>;\n const rendered = renderRequirementsMarkdown(parsed);\n const outPath = join(dirname(targetPath), 'requirements.md');\n const tmpPath = outPath + '.tmp';\n\n if (existsSync(outPath)) {\n const existing = readFileSync(outPath, 'utf-8');\n if (existing !== rendered) {\n if (!opts.force) {\n process.stderr.write(\n `Error: ${outPath} has been hand-edited (differs from rendered output).\\n` +\n `Use --force to overwrite (existing file backed up to requirements.md.bak).\\n`,\n );\n process.exit(1);\n }\n const bakPath = outPath + '.bak';\n renameSync(outPath, bakPath);\n process.stderr.write(`Note: Existing requirements.md backed up to ${bakPath}\\n`);\n }\n }\n\n writeFileSync(tmpPath, rendered, 'utf-8');\n renameSync(tmpPath, outPath);\n process.stdout.write(resolve(outPath) + '\\n');\n return;\n }\n if (opts.schema) {\n process.stdout.write(JSON.stringify(REQUIREMENTS_SCHEMA, null, 2) + '\\n');\n return;\n }\n if (opts.annotated) {\n process.stdout.write(REQUIREMENTS_ANNOTATED + '\\n');\n return;\n }\n });\n\n}\n\n// ── Requirements schema ──────────────────────────────────────────────\n\nconst REQUIREMENTS_SCHEMA = {\n $schema: 'https://json-schema.org/draft/2020-12/schema',\n $defs: {\n requirementItem: {\n type: 'object',\n required: ['id', 'title', 'ears', 'criteria', 'status'],\n additionalProperties: false,\n properties: {\n id: { type: 'string', pattern: '^REQ-\\\\d{3}$' },\n title: { type: 'string' },\n ears: {\n type: 'object',\n required: ['shall'],\n properties: {\n when: { type: 'string' },\n while: { type: 'string' },\n if: { type: 'string' },\n where: { type: 'string' },\n shall: { type: 'string' },\n },\n oneOf: [\n { required: ['when', 'shall'] },\n { required: ['while', 'shall'] },\n { required: ['if', 'shall'] },\n { required: ['where', 'shall'] },\n ],\n },\n criteria: {\n type: 'array',\n items: {\n type: 'object',\n required: ['text', 'checked'],\n properties: {\n text: { type: 'string' },\n checked: { type: 'boolean' },\n },\n },\n },\n status: { type: 'string', enum: _statusCheck },\n agentNotes: { type: 'string' },\n userNotes: { type: 'string' },\n },\n },\n },\n title: 'Sisyphus Requirements',\n description: 'EARS-format behavioral requirements',\n type: 'object',\n required: ['meta', 'groups'],\n properties: {\n meta: {\n type: 'object',\n required: ['lastModified'],\n additionalProperties: false,\n properties: {\n title: { type: 'string' },\n subtitle: { type: 'string' },\n summary: { type: 'string' },\n version: { type: 'integer' },\n lastModified: { type: 'string', format: 'date-time' },\n draft: { type: 'integer', minimum: 1 },\n stage: { type: 'string', enum: ['stage-2-in-progress', 'stage-2-verdict-pending', 'writer-redispatch-pending', 'stage-2-done', 'stage-3-done'] },\n bounceIterations: { type: 'integer', minimum: 0 },\n openAskId: { type: 'string' },\n writerRedispatchIterations: { type: 'integer' },\n },\n },\n groups: {\n type: 'array',\n items: {\n type: 'object',\n required: ['id', 'name', 'description', 'requirements'],\n additionalProperties: false,\n properties: {\n id: { type: 'string', pattern: '^[a-z0-9-]+$' },\n name: { type: 'string' },\n description: { type: 'string' },\n context: { type: 'string' },\n requirements: {\n type: 'array',\n items: { $ref: '#/$defs/requirementItem' },\n },\n safeAssumptions: {\n type: 'array',\n items: { $ref: '#/$defs/requirementItem' },\n },\n },\n },\n },\n },\n};\n\nconst REQUIREMENTS_ANNOTATED = `# requirements.json — Annotated Writing Guide\n#\n# This is NOT valid JSON — it's a reference showing every field with\n# inline guidance. Run \\`sis admin requirements --schema\\` for the raw\n# JSON Schema.\n#\n# Safe assumptions must satisfy the same EARS shape requirements as\n# regular requirements.\n#\n# ── BEHAVIORAL ONLY ──\n# Each requirement describes what the system does at its boundary —\n# what the user, caller, or tester observes. The design (already\n# approved) is the technical contract; the plan phase (later) handles\n# implementation breakdown. Do not write requirements that name files,\n# functions, libraries, data structures, or algorithms.\n\n{\n \"meta\": {\n \"title\": \"Feature Name Requirements\",\n // ^ Human-readable title.\n\n \"subtitle\": \"EARS Behavioral Spec\",\n // ^ Secondary label. Usually \"EARS Behavioral Spec\".\n\n \"summary\": \"2-3 sentences: what is being built, who it's for, and the key constraint.\",\n // ^ Orients the reviewer before they see individual items.\n // Lead with the user-facing outcome only. The implementation\n // belongs in design.md (technical) and plan.md (steps).\n\n \"version\": 1,\n // ^ Always 1. Reserved for future schema versioning.\n\n \"lastModified\": \"2026-04-04T12:00:00Z\",\n // ^ ISO 8601 timestamp. Update on each save.\n\n \"draft\": 1\n // ^ Increment on each revision cycle (1, 2, 3...).\n\n // ── Spec lead state-machine fields (do NOT write unless you are the spec lead) ──\n // \"stage\": \"stage-2-in-progress\" | \"stage-2-verdict-pending\" | \"writer-redispatch-pending\" | \"stage-2-done\" | \"stage-3-done\"\n // \"bounceIterations\": number — bounce-loop counter, never decrements\n // \"openAskId\": string — background ask id for active Stage 2 review deck\n // \"writerRedispatchIterations\": number — writer re-dispatch counter, never decrements\n },\n\n \"groups\": [\n // Each group is a thematic area (e.g., \"Session Creation\", \"Error Recovery\").\n // Aim for 3-7 groups. Present them in narrative order.\n {\n \"id\": \"kebab-case-group-id\",\n // ^ Unique, stable across drafts. Use kebab-case.\n\n \"name\": \"Group Display Name\",\n // ^ Short label shown as the group header.\n\n \"description\": \"What this group covers — one sentence.\",\n // ^ Shown below the group name. Keep it scannable.\n\n \"context\": \"Rich introduction paragraph for this group.\\\\n\\\\nInclude ASCII diagrams:\\\\n\\\\n User ──► Action ──► Response\\\\n │\\\\n ┌─────┴─────┐\\\\n ▼ ▼\\\\n Success Failure\",\n // ^ Use ASCII diagrams for flows, state transitions, architecture.\n // Newlines are literal \\\\n in JSON.\n\n \"requirements\": [\n {\n \"id\": \"REQ-001\",\n // ^ Sequential within the file. REQ-001, REQ-002, etc.\n // Unique across ALL groups, not just this one.\n\n \"title\": \"Short requirement title\",\n // ^ One line.\n\n \"ears\": {\n // ── EARS pattern object ──\n // Exactly ONE condition key + \"shall\". Never a flat string.\n //\n // Pick the matching pattern:\n // Event-driven: { \"when\": \"When [trigger]\", \"shall\": \"...\" }\n // State-driven: { \"while\": \"While [condition]\", \"shall\": \"...\" }\n // Unwanted: { \"if\": \"If [bad condition]\", \"shall\": \"...\" }\n // Optional: { \"where\": \"Where [feature flag]\", \"shall\": \"...\" }\n\n \"when\": \"When the user runs \\`start\\` with a task description\",\n // ^ Start with the EARS keyword: When/While/If/Where.\n\n \"shall\": \"the system shall return a session ID and surface the orchestrator's first response\"\n // ^ Observable behavior — what the caller sees at the boundary.\n // Not \"spawn\", \"instantiate\", \"import\", or any verb that\n // requires reading code to verify.\n },\n\n \"criteria\": [\n // Acceptance criteria — checkable assertions.\n {\n \"text\": \"Session ID is returned to the caller\",\n // ^ One testable statement per criterion.\n\n \"checked\": false\n // ^ Always false when you write it.\n }\n ],\n\n \"status\": \"draft\",\n // ^ Your control. Values:\n // \"draft\" — new or revised, needs review\n // \"question\" — blocked on user input, won't proceed without answer\n // \"approved\" — user approved\n // \"rejected\" — user rejected\n // \"deferred\" — postponed, skip for now\n //\n // Approved items are skipped on re-entry.\n\n \"agentNotes\": \"Context for the reviewer — why this requirement exists, caveats, trade-offs.\",\n // ^ Explain anything non-obvious. Link to code if relevant.\n\n \"userNotes\": \"\"\n // ^ Leave empty. The user writes back to you here.\n }\n ],\n\n /*\n * safeAssumptions — items the writer is confident the user will accept without\n * discussion: defaults, conventions, and obviously-correct behaviors that follow\n * directly from the design.\n *\n * NOT safe assumptions: anything novel, anything the writer is uncertain about,\n * or anything that would change with a small design tweak.\n *\n * Field shape: identical to a requirements item — same id pattern (REQ-NNN), same\n * ears structure, same criteria, same agentNotes. Use agentNotes to briefly justify\n * why each item qualifies as safe.\n */\n \"safeAssumptions\": [\n {\n \"id\": \"REQ-010\",\n \"title\": \"Default session timeout is 30 minutes\",\n \"ears\": {\n \"where\": \"Where no custom timeout is configured\",\n \"shall\": \"the system shall expire idle sessions after 30 minutes\"\n },\n \"criteria\": [\n { \"text\": \"Session expires after 30 minutes of inactivity\", \"checked\": false }\n ],\n \"status\": \"draft\",\n \"agentNotes\": \"Safe assumption: 30-minute idle timeout is a near-universal default and the design doc does not specify an alternative.\",\n \"userNotes\": \"\"\n }\n ]\n }\n ]\n}`;\n\n// ── Requirements markdown renderer ───────────────────────────────────\n\nfunction renderRequirementItem(out: string[], req: Record<string, unknown>): void {\n const item: string[] = [];\n\n item.push(`### ${req.id}: ${req.title}`);\n item.push('');\n item.push(`**Status:** ${req.status}`);\n item.push('');\n\n const ears = req.ears as Record<string, string> | undefined;\n if (ears) {\n const earsClauses: string[] = [];\n if (ears.when) earsClauses.push(ears.when);\n if (ears.while) earsClauses.push(ears.while);\n if (ears.if) earsClauses.push(ears.if);\n if (ears.where) earsClauses.push(ears.where);\n if (ears.shall) earsClauses.push(ears.shall);\n if (earsClauses.length > 0) {\n item.push(earsClauses.join(', '));\n item.push('');\n }\n }\n\n const criteria = req.criteria as Array<{ text: string; checked: boolean }> | undefined;\n if (criteria && criteria.length > 0) {\n item.push('**Acceptance Criteria:**');\n item.push('');\n for (const c of criteria) {\n item.push(`- [${c.checked ? 'x' : ' '}] ${c.text}`);\n }\n item.push('');\n }\n\n const agentNotes = req.agentNotes ? String(req.agentNotes).trim() : '';\n if (agentNotes) {\n item.push('**Agent Notes:**');\n item.push('');\n item.push(agentNotes);\n item.push('');\n }\n\n const userNotes = req.userNotes ? String(req.userNotes).trim() : '';\n if (userNotes) {\n item.push('**User Notes:**');\n item.push('');\n item.push(userNotes);\n item.push('');\n }\n\n while (item.length > 0 && item[item.length - 1] === '') item.pop();\n out.push(...item);\n}\n\nfunction renderRequirementsMarkdown(json: Record<string, unknown>): string {\n const meta = json.meta as Record<string, unknown>;\n const groups = json.groups as Array<Record<string, unknown>>;\n const out: string[] = [];\n\n const title = meta.title ? String(meta.title) : undefined;\n if (title) {\n out.push(`# ${title}`);\n out.push('');\n }\n if (meta.subtitle) {\n out.push(`*${meta.subtitle}*`);\n out.push('');\n }\n const draftParts: string[] = [];\n if (meta.draft) draftParts.push(`Draft ${meta.draft}`);\n if (meta.lastModified) draftParts.push(String(meta.lastModified));\n if (draftParts.length > 0) {\n out.push(draftParts.join(' — '));\n out.push('');\n }\n if (title || draftParts.length > 0) {\n out.push('---');\n out.push('');\n }\n if (meta.summary) {\n out.push(String(meta.summary));\n out.push('');\n }\n\n for (let gi = 0; gi < groups.length; gi++) {\n const group = groups[gi];\n\n if (gi > 0) {\n out.push('');\n out.push('');\n }\n\n out.push(`## ${group.name}`);\n out.push('');\n\n if (group.description) {\n out.push(String(group.description));\n out.push('');\n }\n\n if (group.context) {\n out.push(String(group.context));\n out.push('');\n }\n\n const requirements = group.requirements as Array<Record<string, unknown>>;\n for (let ri = 0; ri < requirements.length; ri++) {\n if (ri > 0) out.push('');\n renderRequirementItem(out, requirements[ri]);\n }\n\n const safeAssumptions = group.safeAssumptions as Array<Record<string, unknown>> | undefined;\n if (safeAssumptions && safeAssumptions.length > 0) {\n out.push('');\n out.push('### Safe Assumptions');\n out.push('');\n for (let si = 0; si < safeAssumptions.length; si++) {\n if (si > 0) out.push('');\n renderRequirementItem(out, safeAssumptions[si]);\n }\n }\n }\n\n return out.join('\\n') + '\\n';\n}\n","import type { Command } from 'commander';\nimport { basename } from 'node:path';\nimport { sendRequest } from '../client.js';\nimport { buildCompanionContext } from '../../tui/lib/context.js';\nimport { renderCompanion } from '../../shared/companion-render.js';\nimport { ACHIEVEMENTS } from '../../shared/companion-types.js';\nimport type { CompanionState, CompanionMemoryState, ObservationCategory, ObservationRecord } from '../../shared/companion-types.js';\nimport { MemoryStoreParseError } from '../../shared/companion-types.js';\nimport { createBadgeGallery, renderBadgeCard } from '../../shared/companion-badges.js';\nimport { loadMemoryStrict, sanitizeForDisplay } from '../../daemon/companion-memory.js';\nimport { showCommentaryPopup } from '../../daemon/companion-popup.js';\n\nconst CATEGORY_LABELS: Record<string, string> = {\n milestone: 'Milestone',\n session: 'Session',\n time: 'Time',\n behavioral: 'Behavioral',\n};\n\nconst CATEGORY_ORDER: Array<[ObservationCategory, string]> = [\n ['session-sentiments', 'Session Sentiments'],\n ['repo-impressions', 'Repo Impressions'],\n ['user-patterns', 'User Patterns'],\n ['notable-moments', 'Notable Moments'],\n];\n\nfunction formatTimestamp(iso: string): string {\n const d = new Date(iso);\n const hh = String(d.getHours()).padStart(2, '0');\n const mm = String(d.getMinutes()).padStart(2, '0');\n const ss = String(d.getSeconds()).padStart(2, '0');\n const yyyy = d.getFullYear();\n const mon = String(d.getMonth() + 1).padStart(2, '0');\n const dd = String(d.getDate()).padStart(2, '0');\n return `${hh}:${mm}:${ss} ${yyyy}-${mon}-${dd}`;\n}\n\nasync function runCompanionMemory(opts: { repo?: string }): Promise<void> {\n let state: CompanionMemoryState;\n try {\n state = loadMemoryStrict();\n } catch (err) {\n if (err instanceof MemoryStoreParseError) {\n process.stderr.write(`${err.message}\\n`);\n process.exitCode = 1;\n return;\n }\n throw err;\n }\n console.log(renderMemory(state, opts.repo));\n}\n\nexport function renderMemory(state: CompanionMemoryState, repo?: string): string {\n let observations: ObservationRecord[] = state.observations;\n if (repo !== undefined) {\n observations = observations.filter(obs => obs.repo === repo);\n }\n\n const grouped = new Map<ObservationCategory, ObservationRecord[]>();\n for (const [cat] of CATEGORY_ORDER) grouped.set(cat, []);\n for (const obs of observations) grouped.get(obs.category)?.push(obs);\n for (const [, recs] of grouped) recs.sort((a, b) => b.timestamp.localeCompare(a.timestamp));\n\n const lines: string[] = [];\n for (const [cat, label] of CATEGORY_ORDER) {\n const recs = grouped.get(cat) ?? [];\n if (recs.length > 0) {\n lines.push(`${label} (${recs.length})`);\n for (const rec of recs) {\n const ts = formatTimestamp(rec.timestamp);\n const src = `(${rec.source})`.padEnd(7);\n const text = sanitizeForDisplay(rec.text);\n const repoStr = rec.repo !== null ? `[${sanitizeForDisplay(basename(rec.repo))}]` : '[—]';\n lines.push(` [${ts}] ${src} ${text} ${repoStr}`);\n }\n } else {\n lines.push(label);\n lines.push(' (none)');\n }\n lines.push('');\n }\n if (lines[lines.length - 1] === '') lines.pop();\n\n const prunedStr = state.prunedAt !== null\n ? state.prunedAt.slice(0, 10)\n : 'never';\n lines.push('');\n lines.push(`${observations.length} observations total, last pruned ${prunedStr}`);\n\n return lines.join('\\n');\n}\n\nexport function registerCompanion(program: Command): void {\n const companion = program\n .command('companion')\n .description('Show companion profile and stats');\n\n // Default action — preserves existing bare `sis companion` behavior\n companion\n .option('--name <name>', 'Set companion name')\n .option('--badges', 'Show badge gallery')\n .action(async (opts: { name?: string; badges?: boolean }) => {\n const res = await sendRequest({ type: 'companion', name: opts.name });\n if (!res.ok) {\n console.error(res.error);\n process.exit(1);\n }\n const companion = res.data as unknown as CompanionState;\n\n // Header: face + identity\n const face = renderCompanion(companion, ['face', 'boulder'], { color: true });\n const displayName = companion.name !== null ? companion.name : '(unnamed)';\n console.log();\n console.log(` ${face}`);\n console.log();\n console.log(` ${displayName} · Level ${companion.level} ${companion.title}`);\n console.log(` Mood: ${companion.mood} · XP: ${companion.xp}`);\n console.log();\n\n // Stats\n const s = companion.stats;\n const endH = Math.floor(s.endurance / 3_600_000);\n console.log(' Stats');\n console.log(` Strength ${s.strength} sessions`);\n console.log(` Endurance ${endH}h total active`);\n console.log(` Wisdom ${s.wisdom} efficient sessions`);\n console.log(` Patience ${s.patience} persistence score`);\n console.log();\n\n if (opts.badges) {\n // Full badge gallery\n const gallery = createBadgeGallery(companion.achievements);\n console.log(` Badges ${companion.achievements.length}/${ACHIEVEMENTS.length} earned`);\n console.log();\n\n for (let i = 0; i < gallery.total; i++) {\n const def = gallery.achievements[i]!;\n const unlock = gallery.unlocked.get(def.id) ?? null;\n const card = renderBadgeCard(def, unlock);\n for (const line of card.lines) {\n console.log(` ${line}`);\n }\n console.log();\n }\n } else {\n // Compact achievement list\n const unlocked = new Set(companion.achievements.map(a => a.id));\n const byCategory = new Map<string, typeof ACHIEVEMENTS>();\n for (const def of ACHIEVEMENTS) {\n const group = byCategory.get(def.category) ?? [];\n group.push(def);\n byCategory.set(def.category, group);\n }\n\n console.log(` Achievements ${companion.achievements.length}/${ACHIEVEMENTS.length} (use --badges for gallery)`);\n for (const [category, defs] of byCategory) {\n const label = CATEGORY_LABELS[category] ?? category;\n const unlockedCount = defs.filter(d => unlocked.has(d.id)).length;\n console.log(` ${label} (${unlockedCount}/${defs.length})`);\n for (const def of defs) {\n const icon = unlocked.has(def.id) ? '✓' : '·';\n console.log(` ${icon} ${def.name} — ${def.description}`);\n }\n }\n console.log();\n }\n\n // Repos\n const repos = Object.entries(companion.repos);\n if (repos.length > 0) {\n repos.sort(([, a], [, b]) => b.visits - a.visits);\n console.log(' Repositories');\n for (const [path, mem] of repos.slice(0, 10)) {\n const nick = mem.nickname ? ` \"${mem.nickname}\"` : '';\n const parts = [`${mem.visits} visits`, `${mem.completions} completions`];\n if (mem.crashes > 0) parts.push(`${mem.crashes} crashes`);\n console.log(` ${path}${nick}`);\n console.log(` ${parts.join(' · ')}`);\n }\n if (repos.length > 10) {\n console.log(` … and ${repos.length - 10} more`);\n }\n console.log();\n }\n\n // Commentary\n if (companion.lastCommentary) {\n console.log(` \"${companion.lastCommentary.text}\"`);\n console.log();\n }\n });\n\n // New: memory subcommand\n companion\n .command('memory')\n .description('Show accumulated companion observations grouped by category')\n .option('--repo <path>', 'Filter observations by repo path')\n .action(async (opts: { repo?: string }) => {\n await runCompanionMemory(opts);\n });\n\n companion\n .command('context')\n .description('Output session context JSON for companion hook')\n .option('--cwd <path>', 'Project directory', process.cwd())\n .action((opts: { cwd: string }) => {\n const context = buildCompanionContext(opts.cwd);\n process.stdout.write(JSON.stringify({ additionalContext: context }));\n });\n\n companion\n .command('popup-test')\n .description('Show a test commentary popup to validate feedback key handling')\n .option('--text <text>', 'Custom popup text', 'Cycle complete. Everything went exactly as planned. Nothing suspicious here.')\n .action((opts: { text: string }) => {\n const feedback = showCommentaryPopup(opts.text);\n if (feedback === null) {\n console.error('No feedback received (popup suppressed or not in tmux).');\n process.exitCode = 1;\n return;\n }\n if (feedback.rating === 'comment' && feedback.comment !== undefined) {\n console.log(`rating: comment \"${feedback.comment}\"`);\n } else {\n console.log(`rating: ${feedback.rating}${feedback.comment !== undefined ? ` comment: ${feedback.comment}` : ''}`);\n }\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 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 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 { 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 { 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 { writeFileSync, readFileSync, unlinkSync, existsSync } from 'node:fs';\nimport { tmpdir } from 'node:os';\nimport { join, resolve } from 'node:path';\nimport { getMoodFace, getMoodTmuxColor } from '../shared/companion-render.js';\nimport type { FeedbackRating } from '../shared/companion-types.js';\nimport { loadCompanion } from './companion.js';\nimport { loadConfig } from '../shared/config.js';\nimport { execSafe } from '../shared/exec.js';\nimport { shellQuote } from '../shared/shell.js';\n\nconst POPUP_WIDTH = 38;\nconst INNER_WIDTH = POPUP_WIDTH - 6; // 2 border + 2 padding each side\nconst POPUP_DURATION = 15;\nconst POPUP_TMP_PREFIX = join(tmpdir(), 'sisyphus-popup');\nconst POPUP_SCRIPT = join(tmpdir(), 'sisyphus-popup.sh');\nconst POPUP_RESULT_PREFIX = join(tmpdir(), 'sisyphus-popup-result');\nconst WHIP_ANIMATION_PATH = resolve(import.meta.dirname, '../templates/whip-animation.sh');\nconst WHIP_ANIMATION_ROWS = 12; // canvas height baked into whip-frames.json\n\nexport interface PopupPage {\n text: string;\n title?: string; // overrides default face title\n}\n\nfunction wrapText(text: string, width: number): string[] {\n const words = text.split(' ');\n const lines: string[] = [];\n let current = '';\n for (const word of words) {\n if (current && current.length + 1 + word.length > width) {\n lines.push(current);\n current = word;\n } else {\n current = current ? `${current} ${word}` : word;\n }\n }\n if (current) lines.push(current);\n return lines;\n}\n\n/** Show a single commentary popup (convenience wrapper). */\nexport function showCommentaryPopup(text: string): { rating: FeedbackRating; comment?: string } | null {\n return showCommentaryPopupQueue([{ text }]);\n}\n\n/** Show one or more popup pages in sequence. Enter advances; last Enter closes. */\nexport function showCommentaryPopupQueue(pages: PopupPage[]): { rating: FeedbackRating; comment?: string } | null {\n if (pages.length === 0) return null;\n\n try {\n const config = loadConfig(process.cwd());\n if (config.companionPopup === false) return null;\n\n const companion = loadCompanion();\n const intensity = companion.debugMood?.scores[companion.mood] ?? 0;\n const face = getMoodFace(companion.mood, intensity);\n const moodColor = getMoodTmuxColor(companion.mood);\n const defaultTitle = ` (${face}) `;\n\n let maxContentHeight = 0;\n\n // Write each page's content file\n for (let i = 0; i < pages.length; i++) {\n const lines = wrapText(pages[i].text, INNER_WIDTH);\n const isLast = i === pages.length - 1;\n const hint = isLast ? '[0:ok 1:good 2:bad 3:whip]' : '[enter:next 0-3:rate]';\n const hintPad = Math.max(0, Math.floor((INNER_WIDTH - hint.length) / 2));\n const hintLine = ' '.repeat(hintPad + 2) + hint;\n const content = '\\n\\n' + lines.map(l => ` ${l}`).join('\\n') + '\\n\\n' + hintLine + '\\n';\n const contentLineCount = content.split('\\n').length - 1; // trailing \\n artifact\n const contentHeight = Math.max(contentLineCount + 2, 5);\n if (contentHeight > maxContentHeight) maxContentHeight = contentHeight;\n writeFileSync(`${POPUP_TMP_PREFIX}-${i}.txt`, content);\n }\n\n // Popup must fit the whip animation's 12-row canvas (+2 for border) since '3:whip' is always available.\n const whipAvailable = existsSync(WHIP_ANIMATION_PATH);\n if (whipAvailable && maxContentHeight < WHIP_ANIMATION_ROWS + 2) {\n maxContentHeight = WHIP_ANIMATION_ROWS + 2;\n }\n\n const initialTitle = pages[0].title ?? defaultTitle;\n\n const script = `#!/bin/sh\nprintf '\\\\033[?25l'\nstty -echo 2>/dev/null\nRESULT_FILE=${shellQuote(POPUP_RESULT_PREFIX)}\nPAGE=0\nTOTAL=${pages.length}\n\nshow_page() {\n printf '\\\\033[2J\\\\033[H'\n cat ${shellQuote(POPUP_TMP_PREFIX)}-$PAGE.txt\n}\n\nshow_page\nwhile IFS= read -r -n1 -t ${POPUP_DURATION} k; do\n case \"$k\" in\n 0) printf 'neutral' > \"$RESULT_FILE\"; break ;;\n 1) printf 'good' > \"$RESULT_FILE\"; break ;;\n 2) printf 'bad' > \"$RESULT_FILE\"; break ;;\n 3) printf 'whip' > \"$RESULT_FILE\"\n ${whipAvailable ? `bash ${shellQuote(WHIP_ANIMATION_PATH)}` : ':'}\n break ;;\n c|C)\n stty echo\n printf '\\\\033[2J\\\\033[H> '\n IFS= read -r -t 30 line\n printf 'comment:%s' \"$line\" > \"$RESULT_FILE\"\n break\n ;;\n '')\n PAGE=$((PAGE + 1))\n if [ $PAGE -ge $TOTAL ]; then\n printf 'neutral' > \"$RESULT_FILE\"\n break\n fi\n show_page\n ;;\n esac\ndone\nif [ ! -f \"$RESULT_FILE\" ]; then\n printf 'neutral' > \"$RESULT_FILE\"\nfi\n`;\n writeFileSync(POPUP_SCRIPT, script, { mode: 0o755 });\n\n // Delete stale result file before running popups\n try { unlinkSync(POPUP_RESULT_PREFIX); } catch { /* ignore */ }\n\n // Daemon runs outside tmux — target each attached client\n const clientsRaw = execSafe('tmux list-clients -F \"#{client_name} #{client_width}\"');\n if (!clientsRaw) return null;\n for (const line of clientsRaw.split('\\n').filter(Boolean)) {\n const lastSpace = line.lastIndexOf(' ');\n const client = line.slice(0, lastSpace);\n const clientWidth = parseInt(line.slice(lastSpace + 1), 10);\n if (!clientWidth) continue;\n const x = Math.max(0, clientWidth - POPUP_WIDTH);\n const args = [\n `-c ${shellQuote(client)}`,\n '-E -b rounded',\n `-T ${shellQuote(initialTitle)}`,\n `-S \"fg=${moodColor}\"`,\n `-s \"fg=${moodColor}\"`,\n `-x ${x} -y 0`,\n `-w ${POPUP_WIDTH} -h ${maxContentHeight}`,\n shellQuote(POPUP_SCRIPT),\n ].join(' ');\n execSafe(`tmux display-popup ${args}`);\n }\n\n // Read feedback written by the last client's popup\n let raw: string;\n try {\n raw = readFileSync(POPUP_RESULT_PREFIX, 'utf8').trim();\n } catch {\n return null;\n } finally {\n try { unlinkSync(POPUP_RESULT_PREFIX); } catch { /* ignore */ }\n }\n\n if (raw.startsWith('comment:')) {\n return { rating: 'comment', comment: raw.slice('comment:'.length) };\n }\n const validRatings: FeedbackRating[] = ['neutral', 'good', 'bad', 'whip'];\n const rating = validRatings.includes(raw as FeedbackRating) ? (raw as FeedbackRating) : 'neutral';\n return { rating };\n } catch { /* non-fatal */ }\n return null;\n}\n","import { homedir } from 'node:os';\nimport { join } from 'node:path';\nimport type { Command } from 'commander';\nimport {\n deployDown,\n deployListProviders,\n deployLogs,\n deploySsh,\n deployStatus,\n deployUp,\n deployUpdate,\n type UpOptions,\n} from '../deploy/runner.js';\nimport { PROVIDERS, type Provider } from '../deploy/creds.js';\nimport { authTailscale } from '../deploy/tailscale.js';\n\ninterface RawUpOptions {\n region?: string;\n arch?: string;\n size?: string;\n sshKey?: string;\n chromium?: boolean; // commander exposes --no-chromium as opts.chromium = false\n autoUpdate?: boolean;\n name?: string;\n yes?: boolean;\n}\n\ninterface DownOptions {\n yes?: boolean;\n}\n\nfunction assertArch(raw: string): 'arm' | 'x86' {\n if (raw === 'arm' || raw === 'x86') return raw;\n throw new Error(`Invalid --arch: ${raw}. Must be 'arm' or 'x86'.`);\n}\n\nfunction defaultRegion(provider: Provider): string {\n return provider === 'hetzner' ? 'nbg1' : 'us-east-1';\n}\n\nfunction resolveUpOptions(provider: Provider, raw: RawUpOptions): UpOptions {\n // arch/name/sshKey carry commander-supplied defaults — guaranteed defined.\n if (!raw.arch || !raw.name || !raw.sshKey) {\n throw new Error('Internal error: commander failed to apply defaults for --arch/--name/--ssh-key.');\n }\n const arch = assertArch(raw.arch);\n // --region's default is provider-specific, so commander can't supply it.\n const region = raw.region === undefined ? defaultRegion(provider) : raw.region;\n // --size has no default — undefined means \"fall through to the Terraform module's arch-based default\".\n const size = raw.size === undefined ? null : raw.size;\n // commander: --no-chromium → chromium === false; absent → undefined (default install on)\n const withChromium = raw.chromium !== false;\n const enableAutoUpdate = raw.autoUpdate !== false;\n const yes = raw.yes === true;\n return { region, arch, size, sshKey: raw.sshKey, name: raw.name, withChromium, enableAutoUpdate, yes };\n}\n\nexport function registerDeploy(program: Command): void {\n const deploy = program\n .command('deploy')\n .description('Provision a Tailscale-only sisyphus box on Hetzner or AWS via Terraform.');\n\n deploy\n .option('--providers', 'List available providers and provisioning status.')\n .action((opts: { providers?: boolean }) => {\n if (opts.providers) {\n deployListProviders();\n return;\n }\n deploy.help();\n });\n\n // sisyphus deploy auth tailscale — one-time OAuth client setup\n const auth = deploy.command('auth').description('Configure deploy credentials.');\n auth\n .command('tailscale')\n .description('Configure Tailscale OAuth client or fallback auth key.')\n .action(async () => {\n await authTailscale();\n });\n\n for (const provider of PROVIDERS) {\n const sub = deploy.command(provider).description(`${provider} commands.`);\n\n sub\n .command('up')\n .description(`Provision the ${provider} box (terraform init → plan → apply).`)\n .option('--region <region>', `Provider region (defaults: hetzner=nbg1, aws=us-east-1).`)\n .option('--arch <arch>', \"'arm' (default) or 'x86'. Picks the default --size and image.\", 'arm')\n .option('--size <size>', 'Instance type override (defaults follow --arch).')\n .option('--ssh-key <path>', 'Path to SSH public key.', join(homedir(), '.ssh', 'id_ed25519.pub'))\n .option('--no-chromium', 'Skip headless Chromium install.')\n .option('--no-auto-update', 'Skip the daily auto-update systemd timer.')\n .option('--name <name>', 'Box hostname / Tailscale node name.', 'sisyphus')\n .option('-y, --yes', 'Skip the re-provision confirmation prompt when state already exists.')\n .action(async (raw: RawUpOptions) => {\n const opts = resolveUpOptions(provider, raw);\n await deployUp(provider, opts);\n });\n\n sub\n .command('down')\n .description(`Destroy the ${provider} box (terraform destroy).`)\n .option('-y, --yes', 'Skip confirmation prompt.')\n .action(async (opts: DownOptions) => {\n await deployDown(provider, { yes: opts.yes === true });\n });\n\n sub\n .command('status')\n .description(`Print current ${provider} outputs (IP, hostname, instance type, est. cost).`)\n .action(() => {\n deployStatus(provider);\n });\n\n sub\n .command('ssh [remoteCmd...]')\n .description(`SSH (or mosh, if available) into the ${provider} box via Tailscale.`)\n .action((remoteCmd: string[]) => {\n deploySsh(provider, remoteCmd);\n });\n\n sub\n .command('logs')\n .description(`Tail cloud-init + daemon logs from the ${provider} box.`)\n .action(() => {\n deployLogs(provider);\n });\n\n sub\n .command('update')\n .description(`Run \\`npm i -g sisyphi@latest && systemctl --user restart sisyphusd\\` on the ${provider} box.`)\n .action(() => {\n deployUpdate(provider);\n });\n }\n\n}\n","import { spawn, spawnSync } from 'node:child_process';\nimport { copyFileSync, existsSync, mkdirSync, readFileSync } from 'node:fs';\nimport {\n deployProviderDir,\n deployStateBackupPath,\n deployStatePath,\n} from '../../shared/paths.js';\nimport { EXEC_ENV } from '../../shared/exec.js';\nimport { ensureDeployDir, loadProviderCreds, type Provider } from './creds.js';\nimport { formatCostLine } from './pricing.js';\nimport { clearRuntimeState, readRuntimeState, writeRuntimeState } from './runtime.js';\nimport { discoverNodeWithRetry, isTailscaleAvailable } from './tailnet.js';\nimport { providerModuleDir } from './templates.js';\nimport { mintTailscaleKey } from './tailscale.js';\n\n/**\n * UpOptions is the fully-resolved option struct passed to deployUp.\n * Defaults are applied at the commander layer (deploy.ts) so this\n * module can assume every field is populated.\n */\nexport interface UpOptions {\n region: string;\n arch: 'arm' | 'x86';\n size: string | null;\n sshKey: string;\n name: string;\n withChromium: boolean;\n enableAutoUpdate: boolean;\n yes: boolean;\n}\n\nexport interface DeployOutputs {\n ipv4: string;\n tailscale_hostname: string;\n ssh_command: string;\n instance_type: string;\n}\n\n/**\n * Run `terraform <args>` in the provider's working directory, streaming\n * output to the user. Returns exit code; throws on spawn failure.\n *\n * Working directory is the bundled provider module (read-only). State\n * is written to `~/.sisyphus/deploy/<provider>/terraform.tfstate` via\n * the `-state` flag, keeping the bundled module immutable across\n * provisions.\n */\nfunction runTerraform(provider: Provider, args: string[], extraEnv: Record<string, string>): number {\n ensureProviderStateDir(provider);\n ensureTerraformInstalled();\n\n const result = spawnSync('terraform', args, {\n cwd: providerModuleDir(provider),\n stdio: 'inherit',\n env: { ...EXEC_ENV, ...extraEnv },\n });\n if (result.error) throw result.error;\n // status is null when the process was killed by a signal — treat as failure.\n return result.status === null ? 1 : result.status;\n}\n\nfunction ensureTerraformInstalled(): void {\n const result = spawnSync('terraform', ['version'], { stdio: 'pipe', env: EXEC_ENV });\n if (result.error || result.status !== 0) {\n const platform = process.platform;\n const hint = platform === 'darwin'\n ? 'brew install terraform'\n : 'See https://developer.hashicorp.com/terraform/install';\n throw new Error(`terraform binary not found on PATH. Install: ${hint}`);\n }\n}\n\nfunction ensureProviderStateDir(provider: Provider): void {\n ensureDeployDir();\n const dir = deployProviderDir(provider);\n if (!existsSync(dir)) mkdirSync(dir, { recursive: true, mode: 0o700 });\n}\n\nfunction backupState(provider: Provider): void {\n const src = deployStatePath(provider);\n if (existsSync(src)) copyFileSync(src, deployStateBackupPath(provider));\n}\n\nfunction readSshPubkey(path: string): string {\n if (!existsSync(path)) {\n const privateKeyPath = path.replace(/\\.pub$/, '');\n throw new Error(\n `SSH pubkey not found at ${path}. Generate one with:\\n ssh-keygen -t ed25519 -f ${privateKeyPath}\\nor pass --ssh-key <path>.`,\n );\n }\n return readFileSync(path, 'utf-8').trim();\n}\n\nfunction readOutputs(provider: Provider): DeployOutputs | null {\n const result = spawnSync('terraform', ['output', '-json', `-state=${deployStatePath(provider)}`], {\n cwd: providerModuleDir(provider),\n encoding: 'utf-8',\n env: EXEC_ENV,\n });\n if (result.status !== 0) return null;\n\n try {\n const parsed = JSON.parse(result.stdout) as Record<string, { value: unknown }>;\n if (Object.keys(parsed).length === 0) return null;\n const required: Array<keyof DeployOutputs> = ['ipv4', 'tailscale_hostname', 'ssh_command', 'instance_type'];\n for (const k of required) {\n if (parsed[k]?.value === undefined) return null;\n }\n return {\n ipv4: String(parsed.ipv4!.value),\n tailscale_hostname: String(parsed.tailscale_hostname!.value),\n ssh_command: String(parsed.ssh_command!.value),\n instance_type: String(parsed.instance_type!.value),\n };\n } catch {\n return null;\n }\n}\n\nexport function isProvisioned(provider: Provider): boolean {\n if (!existsSync(deployStatePath(provider))) return false;\n return readOutputs(provider) !== null;\n}\n\n// ── Actions ──────────────────────────────────────────────────────────────────\n\nexport async function deployUp(provider: Provider, opts: UpOptions): Promise<void> {\n // Bail before minting a Tailscale key — re-running `up` on a live box has\n // surprising provider-specific behavior, and a single-use OAuth key would\n // be wasted if the user backs out.\n if (isProvisioned(provider) && !(await confirmReprovision(provider, opts.yes))) {\n return;\n }\n\n const sshPubkey = readSshPubkey(opts.sshKey);\n\n const creds = await loadProviderCreds(provider);\n const tsAuthKey = await mintTailscaleKey({ hostname: opts.name });\n\n const tfvars: Record<string, string> = {\n name: opts.name,\n region: opts.region,\n arch: opts.arch,\n ssh_pubkey: sshPubkey,\n ts_authkey: tsAuthKey,\n with_chromium: String(opts.withChromium),\n enable_auto_update: String(opts.enableAutoUpdate),\n };\n if (opts.size !== null) tfvars.size = opts.size;\n\n const tfvarArgs = Object.entries(tfvars).flatMap(([k, v]) => ['-var', `${k}=${v}`]);\n\n console.log(`\\n→ terraform init (${provider})...\\n`);\n let code = runTerraform(provider, ['init', '-input=false'], creds);\n if (code !== 0) throw new Error(`terraform init failed (exit ${code})`);\n\n backupState(provider);\n\n console.log(`\\n→ terraform plan (${provider})...\\n`);\n code = runTerraform(\n provider,\n ['plan', '-input=false', `-state=${deployStatePath(provider)}`, ...tfvarArgs],\n creds,\n );\n if (code !== 0) throw new Error(`terraform plan failed (exit ${code})`);\n\n console.log(`\\n→ terraform apply (${provider})...\\n`);\n code = runTerraform(\n provider,\n ['apply', '-input=false', '-auto-approve', `-state=${deployStatePath(provider)}`, ...tfvarArgs],\n creds,\n );\n if (code !== 0) throw new Error(`terraform apply failed (exit ${code})`);\n\n const outputs = readOutputs(provider);\n if (!outputs) {\n console.log(`\\nApplied — but could not parse outputs. Run \\`sis deploy ${provider} status\\`.`);\n return;\n }\n\n console.log('');\n console.log('Box provisioned. Cloud-init will run for ~3–5 minutes before the daemon is reachable.');\n console.log('');\n console.log(` Public IP: ${outputs.ipv4}`);\n console.log(` Requested hostname: ${outputs.tailscale_hostname}`);\n\n // Discover the box on the user's tailnet so subsequent ssh/logs/update\n // calls reach the right node even if Tailscale suffixed the hostname\n // (`sisyphus-1`) due to a stale offline node squatting the requested\n // name. Skip silently when local Tailscale isn't available.\n if (isTailscaleAvailable()) {\n process.stdout.write(' Waiting for tailnet join...');\n const node = await discoverNodeWithRetry(opts.name);\n if (node) {\n writeRuntimeState(provider, {\n tailscaleHostname: node.shortName,\n tailscaleFqdn: node.magicDnsName,\n tailscaleIpv4: node.ipv4,\n discoveredAt: new Date().toISOString(),\n });\n process.stdout.write(` joined as ${node.shortName} (${node.ipv4})\\n`);\n if (node.shortName !== opts.name) {\n console.log(` Note: Tailscale suffixed the hostname because \"${opts.name}\" was already`);\n console.log(' claimed by an offline node. Delete the stale node at');\n console.log(' https://login.tailscale.com/admin/machines to reuse the original name.');\n }\n } else {\n process.stdout.write(' no peer matched after 60s\\n');\n console.log(' (Cloud-init may still be installing Tailscale. Re-run `status` later.)');\n }\n } else {\n console.log(' (Local `tailscale` CLI not on PATH — skipping tailnet discovery.)');\n }\n\n console.log('');\n console.log(` Tail provisioning: sis deploy ${provider} logs`);\n console.log(` Verify daemon: sis deploy ${provider} ssh -- sis admin doctor`);\n console.log('');\n}\n\nexport async function deployDown(provider: Provider, opts: { yes: boolean }): Promise<void> {\n if (!existsSync(deployStatePath(provider))) {\n console.log(`No ${provider} state found at ${deployStatePath(provider)}. Nothing to destroy.`);\n return;\n }\n\n if (!opts.yes) {\n const outputs = readOutputs(provider);\n if (outputs) {\n console.log(`About to destroy ${provider} box \"${outputs.tailscale_hostname}\" (${outputs.instance_type}, ${outputs.ipv4}).`);\n } else {\n console.log(`About to destroy ${provider} state at ${deployStatePath(provider)}.`);\n }\n const confirmed = await confirm('Type \"yes\" to continue:');\n if (!confirmed) {\n console.log('Aborted.');\n return;\n }\n }\n\n const creds = await loadProviderCreds(provider);\n backupState(provider);\n // terraform destroy still parses the config; required vars must be set\n // even though their values don't affect the deletion API calls. Pass\n // placeholders — the actual values are already baked into state.\n const destroyVarArgs = [\n '-var', 'ssh_pubkey=destroy',\n '-var', 'ts_authkey=destroy',\n ];\n const code = runTerraform(\n provider,\n ['destroy', '-input=false', '-auto-approve', `-state=${deployStatePath(provider)}`, ...destroyVarArgs],\n creds,\n );\n if (code !== 0) throw new Error(`terraform destroy failed (exit ${code})`);\n clearRuntimeState(provider);\n console.log(`\\n${provider} box destroyed.`);\n}\n\nexport function deployStatus(provider: Provider): void {\n if (!isProvisioned(provider)) {\n console.log(`${provider}: not provisioned.`);\n return;\n }\n const outputs = readOutputs(provider);\n if (!outputs) {\n console.log(`${provider}: state present but outputs unreadable. Try \\`sis deploy ${provider} up\\` to reconcile.`);\n return;\n }\n const runtime = readRuntimeState(provider);\n const effectiveHost = runtime ? runtime.tailscaleHostname : outputs.tailscale_hostname;\n\n console.log(`${provider}: provisioned`);\n console.log(` Public IP: ${outputs.ipv4}`);\n console.log(` Tailscale hostname: ${effectiveHost}`);\n if (runtime) {\n console.log(` Tailscale IPv4: ${runtime.tailscaleIpv4}`);\n console.log(` MagicDNS FQDN: ${runtime.tailscaleFqdn}`);\n if (runtime.tailscaleHostname !== outputs.tailscale_hostname) {\n console.log(` (Requested \"${outputs.tailscale_hostname}\" but Tailscale assigned \"${runtime.tailscaleHostname}\".)`);\n }\n } else {\n console.log(' (No tailnet runtime state — re-run `up` or check that local tailscale is logged in.)');\n }\n console.log(` SSH: ssh sisyphus@${effectiveHost}`);\n console.log(` Instance type: ${outputs.instance_type}`);\n console.log(` ${formatCostLine(provider, outputs.instance_type)}`);\n}\n\nexport function deployListProviders(): void {\n const providers: Provider[] = ['hetzner', 'aws'];\n for (const p of providers) {\n const status = isProvisioned(p) ? 'provisioned' : 'not provisioned';\n console.log(` ${p.padEnd(10)} ${status}`);\n }\n}\n\n// ── ssh / logs / update ──────────────────────────────────────────────────────\n\n/**\n * Pick the host to SSH to: runtime state's discovered hostname (handles\n * Tailscale `-1` suffix) when present, otherwise the Terraform output.\n */\nexport function effectiveSshTarget(provider: Provider): string {\n const runtime = readRuntimeState(provider);\n if (runtime) return `sisyphus@${runtime.tailscaleHostname}`;\n\n const outputs = readOutputs(provider);\n if (!outputs) {\n throw new Error(`${provider} not provisioned. Run \\`sis deploy ${provider} up\\`.`);\n }\n return `sisyphus@${outputs.tailscale_hostname}`;\n}\n\nexport function deploySsh(provider: Provider, remoteCmd: string[]): void {\n const target = effectiveSshTarget(provider);\n\n const moshAvailable = spawnSync('mosh', ['--version'], { stdio: 'pipe', env: EXEC_ENV }).status === 0;\n const bin = moshAvailable && remoteCmd.length === 0 ? 'mosh' : 'ssh';\n const args = remoteCmd.length > 0 ? [target, ...remoteCmd] : [target];\n\n const child = spawn(bin, args, { stdio: 'inherit', env: EXEC_ENV });\n child.on('exit', (code) => process.exit(code === null ? 1 : code));\n}\n\nexport function deployLogs(provider: Provider): void {\n const target = effectiveSshTarget(provider);\n // tail -F survives log rotation; -n 200 gives recent context.\n const remoteCmd = 'tail -F -n 200 /var/log/cloud-init-output.log ~/.sisyphus/daemon.log 2>/dev/null';\n const child = spawn('ssh', [target, remoteCmd], { stdio: 'inherit', env: EXEC_ENV });\n child.on('exit', (code) => process.exit(code === null ? 1 : code));\n}\n\nexport function deployUpdate(provider: Provider): void {\n const target = effectiveSshTarget(provider);\n const remoteCmd = 'sudo npm i -g sisyphi@latest && systemctl --user restart sisyphusd && sisyphusd --version || true';\n const child = spawn('ssh', [target, remoteCmd], { stdio: 'inherit', env: EXEC_ENV });\n child.on('exit', (code) => process.exit(code === null ? 1 : code));\n}\n\n// ── helpers ──────────────────────────────────────────────────────────────────\n\nasync function confirm(prompt: string): Promise<boolean> {\n const { promptLine } = await import('./creds.js');\n const answer = await promptLine(`${prompt} `, false);\n return answer.toLowerCase() === 'yes';\n}\n\n/**\n * Warn before re-running `up` on an already-provisioned box. Behavior is\n * very different per provider:\n * - Hetzner: `user_data` is ForceNew, so a fresh `ts_authkey` triggers\n * destroy-and-recreate. All on-box state is lost.\n * - AWS: `user_data` updates in place by default; cloud-init won't re-run\n * on a live instance, so the freshly-minted Tailscale key is wasted.\n * Either way, `update` is the right tool for software pushes and `down`\n * + `up` is the right tool for an explicit rebuild.\n */\nasync function confirmReprovision(provider: Provider, yes: boolean): Promise<boolean> {\n const outputs = readOutputs(provider);\n console.log('');\n if (outputs) {\n console.log(`${provider} is already provisioned: \"${outputs.tailscale_hostname}\" (${outputs.instance_type}, ${outputs.ipv4}).`);\n } else {\n console.log(`${provider} state already exists at ${deployStatePath(provider)}.`);\n }\n if (provider === 'hetzner') {\n console.log('Re-running `up` on Hetzner will DESTROY and RECREATE the box (user_data is ForceNew).');\n console.log('All on-box state — daemon history, sessions, anything not in your repo — will be lost.');\n } else {\n console.log('Re-running `up` on AWS updates user_data in state but does NOT recreate the instance.');\n console.log('Cloud-init won\\'t re-run on the live box, and the freshly-minted Tailscale key will be wasted.');\n }\n console.log('');\n console.log(`To push a new sisyphus version: sis deploy ${provider} update`);\n console.log(`To rebuild from scratch: sis deploy ${provider} down && sis deploy ${provider} up`);\n console.log('');\n if (yes) return true;\n const confirmed = await confirm('Type \"yes\" to proceed anyway:');\n if (!confirmed) console.log('Aborted.');\n return confirmed;\n}\n","// Hardcoded monthly cost estimates (USD) for the instance types sisyphus\n// deploy provisions. Verified against provider list pricing on the date\n// below; users should treat the figure as informational, not authoritative.\n//\n// Bump LAST_VERIFIED whenever you re-check the table.\nexport const LAST_VERIFIED = '2026-05-06';\n\ninterface Price {\n monthlyUsd: number;\n arch: 'arm' | 'x86';\n}\n\nconst TABLE: Record<string, Price> = {\n // Hetzner Cloud — list pricing in EUR converted at ~1.08 USD/EUR.\n // EU-only (cax = ARM, cx = Intel x86):\n 'hetzner:cax11': { monthlyUsd: 4.00, arch: 'arm' },\n 'hetzner:cax21': { monthlyUsd: 7.00, arch: 'arm' },\n 'hetzner:cx22': { monthlyUsd: 4.50, arch: 'x86' },\n 'hetzner:cx32': { monthlyUsd: 8.00, arch: 'x86' },\n // US (ash / hil) — AMD x86 only (cpx series):\n 'hetzner:cpx11': { monthlyUsd: 4.85, arch: 'x86' },\n 'hetzner:cpx21': { monthlyUsd: 8.85, arch: 'x86' },\n\n // AWS EC2 us-east-1, on-demand, 730h/mo.\n 'aws:t4g.medium': { monthlyUsd: 24.40, arch: 'arm' },\n 'aws:t4g.large': { monthlyUsd: 48.91, arch: 'arm' },\n 'aws:t3.medium': { monthlyUsd: 30.37, arch: 'x86' },\n 'aws:t3.large': { monthlyUsd: 60.74, arch: 'x86' },\n};\n\nexport function lookupMonthlyCost(provider: string, instanceType: string): number | null {\n const entry = TABLE[`${provider}:${instanceType}`];\n return entry ? entry.monthlyUsd : null;\n}\n\nexport function formatCostLine(provider: string, instanceType: string): string {\n const cost = lookupMonthlyCost(provider, instanceType);\n if (cost === null) {\n return `Estimated cost: unknown for ${provider}:${instanceType} (not in pricing table). Verify against your bill.`;\n }\n return `Estimated cost: ~$${cost.toFixed(2)}/mo (pricing last verified ${LAST_VERIFIED}; verify against your bill for current rates).`;\n}\n","import { existsSync, readFileSync, unlinkSync } from 'node:fs';\nimport { atomicWrite } from '../../daemon/lib/atomic.js';\nimport { deployRuntimePath } from '../../shared/paths.js';\nimport type { Provider } from './creds.js';\n\n/**\n * Per-provider runtime state — facts learned *after* `terraform apply`\n * that aren't (or can't be) Terraform outputs. Currently just the\n * post-tailnet-discovery hostname/IP, which the runner uses for all\n * subsequent ssh/logs/update calls because the requested `--name` may\n * have been suffixed by Tailscale to avoid collisions with stale\n * offline nodes.\n *\n * Lives at `~/.sisyphus/deploy/<provider>/runtime.json`. Cleared on\n * `down`. Independent of Terraform state.\n */\nexport interface RuntimeState {\n /** Short MagicDNS label, e.g. \"sisyphus-1\". */\n tailscaleHostname: string;\n /** Full MagicDNS FQDN, e.g. \"sisyphus-1.taildaec87.ts.net\". */\n tailscaleFqdn: string;\n tailscaleIpv4: string;\n discoveredAt: string;\n}\n\nexport function readRuntimeState(provider: Provider): RuntimeState | null {\n const path = deployRuntimePath(provider);\n if (!existsSync(path)) return null;\n try {\n return JSON.parse(readFileSync(path, 'utf-8')) as RuntimeState;\n } catch {\n return null;\n }\n}\n\nexport function writeRuntimeState(provider: Provider, state: RuntimeState): void {\n atomicWrite(deployRuntimePath(provider), JSON.stringify(state, null, 2) + '\\n');\n}\n\nexport function clearRuntimeState(provider: Provider): void {\n const path = deployRuntimePath(provider);\n if (existsSync(path)) unlinkSync(path);\n}\n","import { execSafe } from '../../shared/exec.js';\n\nexport interface DiscoveredNode {\n /** Short MagicDNS label (e.g. \"sisyphus-1\"). May differ from requested name when Tailscale suffixes to avoid collisions with offline nodes. */\n shortName: string;\n /** Fully-qualified MagicDNS name (e.g. \"sisyphus-1.taildaec87.ts.net\"). */\n magicDnsName: string;\n /** Tailscale IPv4 (always present). */\n ipv4: string;\n /** Tailscale IPv6 if exposed. */\n ipv6: string | null;\n}\n\ninterface TailscalePeer {\n HostName?: string;\n DNSName?: string;\n TailscaleIPs?: string[];\n Online?: boolean;\n Created?: string;\n}\n\ninterface TailscaleStatus {\n Peer?: Record<string, TailscalePeer>;\n}\n\n/**\n * Locate a freshly-joined sisyphus box on the user's tailnet by reading\n * `tailscale status --json` locally.\n *\n * Tailscale appends `-1`, `-2`, ... to the MagicDNS label when the\n * requested hostname collides with an existing (even offline) node, so\n * the actual short name may not match `requestedName`. We match peers by\n * the OS-level `HostName` (which is what we passed to `tailscale up\n * --hostname=...` and is preserved verbatim) and require `Online=true`\n * to disambiguate from stale offline nodes.\n */\nexport function discoverNode(requestedName: string): DiscoveredNode | null {\n const json = execSafe('tailscale status --json');\n if (!json) return null;\n\n let status: TailscaleStatus;\n try {\n status = JSON.parse(json) as TailscaleStatus;\n } catch {\n return null;\n }\n\n const peers = status.Peer === undefined ? [] : Object.values(status.Peer);\n const candidates = peers.filter(\n (p) => p.HostName === requestedName && p.Online === true,\n );\n if (candidates.length === 0) return null;\n\n // Multiple online peers with the same OS hostname shouldn't happen, but\n // pick the most recently created defensively.\n candidates.sort((a, b) => {\n const ac = a.Created === undefined ? '' : a.Created;\n const bc = b.Created === undefined ? '' : b.Created;\n return bc.localeCompare(ac);\n });\n const peer = candidates[0]!;\n\n const dnsRaw = peer.DNSName === undefined ? '' : peer.DNSName;\n const dns = dnsRaw.replace(/\\.$/, '');\n if (!dns) return null;\n const shortName = dns.split('.')[0]!;\n\n const ips = peer.TailscaleIPs === undefined ? [] : peer.TailscaleIPs;\n const ipv4 = ips.find((ip) => /^\\d+\\.\\d+\\.\\d+\\.\\d+$/.test(ip));\n if (!ipv4) return null;\n const ipv6 = ips.find((ip) => ip.includes(':')) ?? null;\n\n return { shortName, magicDnsName: dns, ipv4, ipv6 };\n}\n\n/**\n * Poll for the new box on the tailnet. Tailscale propagation typically\n * completes within 5–15s but can take longer on a busy tailnet, hence\n * the generous default of 60s.\n */\nexport async function discoverNodeWithRetry(\n requestedName: string,\n maxRetries = 30,\n intervalMs = 2000,\n): Promise<DiscoveredNode | null> {\n for (let i = 0; i < maxRetries; i++) {\n const node = discoverNode(requestedName);\n if (node) return node;\n if (i < maxRetries - 1) {\n await new Promise((resolve) => setTimeout(resolve, intervalMs));\n }\n }\n return null;\n}\n\n/**\n * Cheap pre-flight check: is `tailscale` on PATH and reachable? Used to\n * decide whether to attempt discovery at all (vs. silently skipping when\n * the user doesn't run Tailscale locally).\n */\nexport function isTailscaleAvailable(): boolean {\n return execSafe('tailscale version') !== null;\n}\n","import { existsSync } from 'node:fs';\nimport { dirname, resolve } from 'node:path';\nimport { fileURLToPath } from 'node:url';\n\n/**\n * Resolve the bundled `deploy/` directory shipped with the npm package.\n *\n * Layout in the published package:\n * dist/cli.js (this file at runtime, after tsup bundle)\n * deploy/ (sibling of dist/, copied via tsup onSuccess)\n *\n * Layout in the source repo:\n * src/cli/deploy/templates.ts (this file)\n * deploy/ (sibling of src/, root of repo)\n */\nexport function deployRoot(): string {\n const here = dirname(fileURLToPath(import.meta.url));\n\n // Bundled: dist/cli.js → ../deploy\n const bundled = resolve(here, '..', 'deploy');\n if (existsSync(bundled)) return bundled;\n\n // Source: src/cli/deploy/ → ../../../deploy\n const sourceRoot = resolve(here, '..', '..', '..', 'deploy');\n if (existsSync(sourceRoot)) return sourceRoot;\n\n throw new Error(\n `Could not locate deploy/ templates. Looked at:\\n ${bundled}\\n ${sourceRoot}\\n` +\n 'This usually means the npm package was built without the deploy/ tree. ' +\n \"Confirm package.json `files` includes 'deploy' and tsup.config.ts copies it into dist/.\",\n );\n}\n\nexport function providerModuleDir(provider: string): string {\n return resolve(deployRoot(), provider);\n}\n","import {\n promptLine,\n readTailscaleEnv,\n writeTailscaleEnv,\n type TailscaleEnv,\n} from './creds.js';\n\ninterface MintOptions {\n hostname: string;\n}\n\ninterface OAuthTokenResponse {\n access_token: string;\n token_type: string;\n expires_in: number;\n}\n\ninterface CreateKeyResponse {\n id: string;\n key: string;\n expires: string;\n}\n\nconst TS_API = 'https://api.tailscale.com/api/v2';\nconst KEY_EXPIRY_SECONDS = 90 * 24 * 60 * 60;\n\n/**\n * Mint a Tailscale auth key for the box being provisioned. Two paths:\n *\n * 1. OAuth client (preferred): mints an ephemeral, single-use, tagged\n * key via API. No human-readable key sits in Terraform state plain\n * text.\n * 2. Manual auth key (fallback): user pastes a reusable key from the\n * admin UI. Less secure, but zero-config.\n *\n * If neither is configured, prompts the user to choose and persists.\n */\nexport async function mintTailscaleKey(opts: MintOptions): Promise<string> {\n let env = readTailscaleEnv();\n\n if (!env.oauthClientId && !env.authKey) {\n env = await firstRunPrompt();\n writeTailscaleEnv(env);\n }\n\n if (env.oauthClientId && env.oauthClientSecret) {\n if (!env.tag) {\n throw new Error('Tailscale tag is missing from ~/.sisyphus/deploy/tailscale.env. Re-run `sis deploy auth tailscale`.');\n }\n return mintViaOAuth(env.oauthClientId, env.oauthClientSecret, env.tag, opts.hostname);\n }\n\n if (env.authKey) {\n return env.authKey;\n }\n\n throw new Error('Tailscale not configured. Run `sis deploy auth tailscale`.');\n}\n\nasync function firstRunPrompt(): Promise<TailscaleEnv> {\n console.log('');\n console.log('Tailscale credentials not configured. Pick one:');\n console.log('');\n console.log(' 1) OAuth client (recommended) — mints fresh ephemeral keys per box');\n console.log(' and auto-cleans stale offline nodes so hostnames don\\'t get suffixed.');\n console.log(' Create at https://login.tailscale.com/admin/settings/oauth');\n console.log(' with scopes `auth_keys:write` + `devices:write` and tag `tag:sisyphus`.');\n console.log(' 2) Reusable auth key (simpler) — paste from');\n console.log(' https://login.tailscale.com/admin/settings/keys');\n console.log('');\n const choice = (await promptLine('Choice [1/2]: ', false)).trim();\n\n if (choice === '1') {\n const clientId = await promptLine(' TS_OAUTH_CLIENT_ID: ', false);\n const clientSecret = await promptLine(' TS_OAUTH_CLIENT_SECRET: ', true);\n if (!clientId || !clientSecret) throw new Error('OAuth client ID and secret are required.');\n const tagInput = await promptLine(' Tag for minted keys [tag:sisyphus]: ', false);\n const tag = tagInput.length > 0 ? tagInput : 'tag:sisyphus';\n return { oauthClientId: clientId, oauthClientSecret: clientSecret, tag };\n }\n\n if (choice === '2') {\n const key = await promptLine(' TS_AUTHKEY: ', true);\n if (!key) throw new Error('Auth key is required.');\n return { authKey: key };\n }\n\n throw new Error(`Invalid choice: ${choice}`);\n}\n\nasync function mintViaOAuth(\n clientId: string,\n clientSecret: string,\n tag: string,\n hostname: string,\n): Promise<string> {\n const token = await fetchAccessToken(clientId, clientSecret);\n\n // Best-effort: clear out stale offline devices that share the requested\n // hostname so Tailscale doesn't suffix the new node with `-1`. Requires\n // the `devices:write` scope on the OAuth client; failures here are not\n // fatal because the new mint still works (just with a suffix).\n try {\n const removed = await deleteStaleDevicesForHostname(token, hostname);\n if (removed > 0) {\n console.log(`Tailscale: removed ${removed} stale offline node(s) named \"${hostname}\".`);\n }\n } catch (err) {\n console.log(`Tailscale: skipped stale-node cleanup (${(err as Error).message}). Add 'devices:write' scope to clean up automatically.`);\n }\n\n const body = {\n capabilities: {\n devices: {\n create: {\n reusable: false,\n ephemeral: false,\n preauthorized: true,\n tags: [tag],\n },\n },\n },\n expirySeconds: KEY_EXPIRY_SECONDS,\n description: `sisyphus deploy: ${hostname}`,\n };\n\n const res = await fetch(`${TS_API}/tailnet/-/keys`, {\n method: 'POST',\n headers: {\n Authorization: `Bearer ${token}`,\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify(body),\n });\n\n if (!res.ok) {\n const detail = await res.text();\n throw new Error(`Tailscale key mint failed (HTTP ${res.status}): ${detail}`);\n }\n\n const data = (await res.json()) as CreateKeyResponse;\n if (!data.key) throw new Error('Tailscale API returned no key.');\n return data.key;\n}\n\ninterface TailscaleDevice {\n id: string;\n hostname: string;\n lastSeen: string;\n}\n\nasync function deleteStaleDevicesForHostname(token: string, hostname: string): Promise<number> {\n const res = await fetch(`${TS_API}/tailnet/-/devices`, {\n headers: { Authorization: `Bearer ${token}` },\n });\n if (!res.ok) {\n throw new Error(`HTTP ${res.status} listing devices`);\n }\n\n const data = (await res.json()) as { devices: TailscaleDevice[] };\n const STALE_AFTER_MS = 5 * 60 * 1000;\n const now = Date.now();\n const stale = data.devices.filter((d) => {\n if (d.hostname !== hostname) return false;\n const seen = Date.parse(d.lastSeen);\n if (Number.isNaN(seen)) return false;\n return now - seen > STALE_AFTER_MS;\n });\n\n let removed = 0;\n for (const device of stale) {\n const r = await fetch(`${TS_API}/device/${device.id}`, {\n method: 'DELETE',\n headers: { Authorization: `Bearer ${token}` },\n });\n if (r.ok) removed++;\n }\n return removed;\n}\n\nasync function fetchAccessToken(clientId: string, clientSecret: string): Promise<string> {\n const credentials = Buffer.from(`${clientId}:${clientSecret}`).toString('base64');\n const res = await fetch(`${TS_API}/oauth/token`, {\n method: 'POST',\n headers: {\n Authorization: `Basic ${credentials}`,\n 'Content-Type': 'application/x-www-form-urlencoded',\n },\n body: 'grant_type=client_credentials&scope=auth_keys',\n });\n\n if (!res.ok) {\n const detail = await res.text();\n throw new Error(`Tailscale OAuth failed (HTTP ${res.status}): ${detail}`);\n }\n\n const data = (await res.json()) as OAuthTokenResponse;\n if (!data.access_token) throw new Error('Tailscale OAuth returned no access_token.');\n return data.access_token;\n}\n\n/**\n * Interactive setup for `sis deploy auth tailscale`. Walks the user\n * through OAuth client creation or manual key paste, then persists.\n */\nexport async function authTailscale(): Promise<void> {\n const env = await firstRunPrompt();\n writeTailscaleEnv(env);\n\n if (env.oauthClientId) {\n if (!env.oauthClientSecret) {\n throw new Error('OAuth client secret missing after first-run prompt — internal error.');\n }\n console.log('');\n console.log('Verifying credentials...');\n // Let exceptions propagate to the CLI's top-level handler; it logs the\n // message and exits non-zero. We don't catch + re-log because that\n // double-prints the failure to stderr.\n await fetchAccessToken(env.oauthClientId, env.oauthClientSecret);\n console.log('OAuth client verified — `sis deploy <provider> up` will mint ephemeral keys.');\n } else {\n console.log('');\n console.log('Auth key saved. Note: reusable auth keys are less secure than OAuth clients.');\n }\n}\n","import { spawn, spawnSync } from 'node:child_process';\nimport { hostname } from 'node:os';\nimport { boxRepoPath } from '../../shared/paths.js';\nimport { shellQuote, shellQuoteHomePath } from '../../shared/shell.js';\nimport { EXEC_ENV } from '../../shared/exec.js';\nimport { promptLine } from '../deploy/creds.js';\nimport type { Provider } from '../deploy/creds.js';\nimport { effectiveSshTarget } from '../deploy/runner.js';\nimport { runOnBox, runOnBoxStreaming } from '../deploy/ssh-exec.js';\nimport { ensureGroveInstalled, ensureGroveRegistered } from './grove.js';\nimport {\n buildRsyncArgs,\n detectPackageManager,\n getOriginUrl,\n getRepoToplevel,\n packageManagerInstallCmd,\n type PackageManager,\n} from './repo.js';\nimport { readSidecar, writeSidecar, type CloudSidecar } from './sidecar.js';\n\nexport interface SyncOptions {\n fresh: boolean;\n yes: boolean;\n}\n\nexport interface StartOptions {\n fresh: boolean;\n yes: boolean;\n}\n\n// ── sync ─────────────────────────────────────────────────────────────────────\n\nexport async function cloudSync(provider: Provider, repo: string, opts: SyncOptions): Promise<void> {\n const target = effectiveSshTarget(provider);\n const remoteDir = boxRepoPath(repo);\n const localOrigin = getOriginUrl();\n\n ensureGroveInstalled(provider);\n\n const existing = readSidecar(provider, repo);\n if (existing && existing.originUrl && localOrigin && existing.originUrl !== localOrigin) {\n throw new Error(\n `Repo \"${repo}\" on the box is registered to a different origin:\\n` +\n ` box: ${existing.originUrl}\\n` +\n ` local: ${localOrigin}\\n` +\n `Pass --name <slug> to disambiguate, or --fresh to overwrite.`,\n );\n }\n\n if (opts.fresh) {\n if (!localOrigin) {\n throw new Error(\n '--fresh requires an `origin` remote on the local repo. ' +\n 'Not available when running from a non-git parent dir.',\n );\n }\n if (!opts.yes) {\n console.log(`This will wipe ~/projects/${repo} on the box and re-clone from ${localOrigin}.`);\n const confirmed = (await promptLine('Continue? Type \"yes\": ', false)).toLowerCase() === 'yes';\n if (!confirmed) {\n console.log('Aborted.');\n return;\n }\n }\n console.log(`→ wiping ${remoteDir} and cloning ${localOrigin} on box...`);\n const cloneCmd = [\n `rm -rf ${shellQuoteHomePath(remoteDir)}`,\n `mkdir -p ${shellQuoteHomePath('~/projects')}`,\n `git clone ${shellQuote(localOrigin)} ${shellQuoteHomePath(remoteDir)}`,\n ].join(' && ');\n const code = await runOnBoxStreaming(provider, cloneCmd);\n if (code !== 0) throw new Error(`fresh clone failed (exit ${code})`);\n } else {\n // Ensure the remote dir exists — rsync will create it but mkdir is harmless.\n const mkdir = runOnBox(provider, `mkdir -p ${shellQuoteHomePath(remoteDir)}`);\n if (mkdir.exitCode !== 0) {\n throw new Error(`Failed to mkdir on box: ${mkdir.stderr}`);\n }\n const toplevel = getRepoToplevel();\n const args = buildRsyncArgs(toplevel, `${target}:${remoteDir}/`);\n console.log(`→ rsync ${toplevel}/ → ${target}:${remoteDir}/`);\n const code = await runRsync(args);\n if (code !== 0) throw new Error(`rsync failed (exit ${code})`);\n }\n\n ensureGroveRegistered(provider, repo, remoteDir);\n\n const sidecar: CloudSidecar = {\n originUrl: localOrigin,\n localHostname: hostname(),\n lastSync: new Date().toISOString(),\n packageManager: existing?.packageManager,\n lastInstall: existing?.lastInstall,\n };\n writeSidecar(provider, repo, sidecar);\n console.log(`✓ synced ${repo} → ${target}:${remoteDir}/`);\n}\n\nfunction runRsync(args: string[]): Promise<number> {\n return new Promise((resolve, reject) => {\n const child = spawn('rsync', args, { stdio: 'inherit', env: EXEC_ENV });\n child.on('error', reject);\n child.on('exit', (code) => resolve(code === null ? 1 : code));\n });\n}\n\n// ── install ──────────────────────────────────────────────────────────────────\n\nexport async function cloudInstall(provider: Provider, repo: string): Promise<void> {\n const remoteDir = boxRepoPath(repo);\n const toplevel = getRepoToplevel();\n const pm: PackageManager = detectPackageManager(toplevel);\n const cmd = packageManagerInstallCmd(pm);\n if (!cmd) {\n console.log('No lockfile detected — skipping install.');\n return;\n }\n console.log(`→ ${pm} install in ${remoteDir} on box...`);\n // `cd` then run; explicit shell wrapping is fine over ssh.\n const remoteCmd = `cd ${shellQuoteHomePath(remoteDir)} && ${cmd}`;\n const code = await runOnBoxStreaming(provider, remoteCmd);\n if (code !== 0) throw new Error(`${pm} install failed (exit ${code})`);\n\n const existing = readSidecar(provider, repo);\n // Carry forward existing identity fields; only overwrite when missing.\n const sidecar: CloudSidecar = {\n originUrl: existing && existing.originUrl !== undefined ? existing.originUrl : getOriginUrl(),\n localHostname: existing ? existing.localHostname : hostname(),\n lastSync: existing?.lastSync,\n lastInstall: new Date().toISOString(),\n packageManager: pm,\n };\n writeSidecar(provider, repo, sidecar);\n console.log(`✓ installed ${repo} (${pm})`);\n}\n\n// ── session ──────────────────────────────────────────────────────────────────\n\nexport async function cloudSession(provider: Provider, repo: string): Promise<void> {\n const remoteDir = boxRepoPath(repo);\n // home-init is a sisyphus admin subcommand on the box; runs against the\n // local tmux server there. `~` expands in the remote shell.\n const cmd = `sis admin home-init ${shellQuote(repo)} ${shellQuoteHomePath(remoteDir)}`;\n console.log(`→ initializing tmux home session \"${repo}\" on box...`);\n const result = runOnBox(provider, cmd);\n if (result.exitCode !== 0) {\n throw new Error(`home-init failed: ${result.stderr || result.stdout}`);\n }\n if (result.stdout.trim()) console.log(result.stdout.trim());\n console.log(`✓ session \"${repo}\" ready on box`);\n}\n\n// ── attach ───────────────────────────────────────────────────────────────────\n\nexport function cloudAttach(provider: Provider, repo: string): void {\n if (process.env.TMUX) {\n throw new Error(\n 'Refusing to attach from inside tmux — would nest the cloud tmux client.\\n' +\n 'Use a fresh terminal, or run from outside tmux:\\n' +\n ` tmux new-window 'ssh -t ${effectiveSshTarget(provider)} tmux attach -t ${repo}'`,\n );\n }\n const target = effectiveSshTarget(provider);\n const child = spawn('ssh', ['-t', target, `tmux attach-session -t ${shellQuote(repo)}`], {\n stdio: 'inherit',\n env: EXEC_ENV,\n });\n child.on('exit', (code) => process.exit(code === null ? 1 : code));\n}\n\n// ── claude-login ─────────────────────────────────────────────────────────────\n\n/**\n * Open an interactive ssh shell on the box running `claude auth login` so the\n * user can complete the device-code flow (URL prints on box, user pastes the\n * code from their local browser back into the same terminal). Self-heals on\n * boxes provisioned before claude-code was added to cloud-init by installing\n * it on demand.\n */\nexport function cloudClaudeLogin(provider: Provider): void {\n const target = effectiveSshTarget(provider);\n // `command -v` probes for an existing install; npm i -g runs as sisyphus\n // (cloud-init installed it as root, but a per-user fallback also works).\n const remote = [\n 'command -v claude >/dev/null 2>&1',\n '|| sudo npm i -g @anthropic-ai/claude-code',\n '&& claude auth login',\n ].join(' ');\n const child = spawn('ssh', ['-t', target, remote], {\n stdio: 'inherit',\n env: EXEC_ENV,\n });\n child.on('exit', (code) => process.exit(code === null ? 1 : code));\n}\n\n// ── start (umbrella) ─────────────────────────────────────────────────────────\n\nexport async function cloudStart(provider: Provider, repo: string, opts: StartOptions): Promise<void> {\n await cloudSync(provider, repo, { fresh: opts.fresh, yes: opts.yes });\n await cloudInstall(provider, repo);\n await cloudSession(provider, repo);\n console.log('');\n console.log(`Box-side dashboard ready. Attach with:`);\n console.log(` tmux new-window 'ssh -t ${effectiveSshTarget(provider)} tmux attach -t ${repo}'`);\n console.log('(or run inside the slash command, which does this for you.)');\n}\n\n// ── status ───────────────────────────────────────────────────────────────────\n\nexport interface CloudStatus {\n provider: Provider;\n target: string;\n sidecar: CloudSidecar | null;\n sessionRunning: boolean;\n}\n\nexport function cloudStatus(provider: Provider, repo: string): void {\n const target = effectiveSshTarget(provider);\n const sidecar = readSidecar(provider, repo);\n // tmux has-session exits 0 when present.\n const sessionProbe = runOnBox(provider, `tmux has-session -t ${shellQuote(repo)} 2>/dev/null`);\n const sessionRunning = sessionProbe.exitCode === 0;\n\n console.log(`Cloud status for \"${repo}\":`);\n console.log(` Provider: ${provider}`);\n console.log(` Target: ${target}`);\n console.log(` Planted: ${sidecar ? 'yes' : 'no'}`);\n if (sidecar) {\n console.log(` Origin: ${sidecar.originUrl ? sidecar.originUrl : '(none)'}`);\n console.log(` Last sync: ${sidecar.lastSync ? sidecar.lastSync : '(never)'}`);\n console.log(` Last install: ${sidecar.lastInstall ? sidecar.lastInstall : '(never)'}`);\n console.log(` Package manager: ${sidecar.packageManager ? sidecar.packageManager : '(none)'}`);\n }\n console.log(` Session: ${sessionRunning ? 'running' : 'absent'}`);\n if (sessionRunning) {\n console.log(` Attach: tmux new-window 'ssh -t ${target} tmux attach -t ${repo}'`);\n }\n}\n","import { spawn, spawnSync } from 'node:child_process';\nimport { EXEC_ENV } from '../../shared/exec.js';\nimport { effectiveSshTarget } from './runner.js';\nimport type { Provider } from './creds.js';\n\nexport interface RunResult {\n stdout: string;\n stderr: string;\n exitCode: number;\n}\n\n/**\n * Run a command on the box via SSH, capturing stdout/stderr.\n *\n * `EXEC_ENV` is the *local* PATH augmentation (so `ssh` resolves) — it is not\n * forwarded to the remote shell, which uses the box's own `~/.profile`/sshd\n * environment.\n */\nexport function runOnBox(provider: Provider, cmd: string): RunResult {\n const target = effectiveSshTarget(provider);\n const result = spawnSync('ssh', [target, cmd], {\n encoding: 'utf-8',\n env: EXEC_ENV,\n });\n // spawnSync with encoding returns string | null per Node types; null only\n // when stdio for the stream is \"ignore\" (we don't set that). Assert string.\n if (typeof result.stdout !== 'string' || typeof result.stderr !== 'string') {\n throw new Error('Internal: ssh spawn did not capture output as string');\n }\n return {\n stdout: result.stdout,\n stderr: result.stderr,\n // status is null when killed by signal — treat as failure.\n exitCode: result.status === null ? 1 : result.status,\n };\n}\n\n/**\n * Run a command on the box via SSH, streaming stdout/stderr to the user's\n * terminal. Returns the exit code. Use for long-running commands like\n * package-manager installs.\n */\nexport function runOnBoxStreaming(provider: Provider, cmd: string): Promise<number> {\n const target = effectiveSshTarget(provider);\n return new Promise((resolve, reject) => {\n const child = spawn('ssh', [target, cmd], {\n stdio: 'inherit',\n env: EXEC_ENV,\n });\n child.on('error', reject);\n child.on('exit', (code) => resolve(code === null ? 1 : code));\n });\n}\n","import { shellQuote, shellQuoteHomePath } from '../../shared/shell.js';\nimport { runOnBox } from '../deploy/ssh-exec.js';\nimport type { Provider } from '../deploy/creds.js';\n\n/**\n * Pinned grove version installed on the cloud box. Bump intentionally; auto-\n * updates are not wired into the daily sisyphusd-update timer.\n */\nexport const GROVE_VERSION = '0.2.13';\n\n/**\n * Ensure grove is installed on the box. Idempotent: short-circuits if `grove`\n * is already on PATH. Installs globally via `sudo npm i -g` (the deploy box\n * uses the NodeSource APT install with /usr/lib/node_modules root-owned).\n */\nexport function ensureGroveInstalled(provider: Provider): void {\n const probe = runOnBox(provider, 'command -v grove >/dev/null 2>&1');\n if (probe.exitCode === 0) return;\n process.stderr.write('Installing grove on box...\\n');\n const install = runOnBox(provider, `sudo npm i -g @crouton-kit/grove@${GROVE_VERSION}`);\n if (install.exitCode !== 0) {\n throw new Error(`Failed to install grove: ${install.stderr || install.stdout}`);\n }\n}\n\n/**\n * Register a repo path with grove. Uses `--update` for idempotency: re-running\n * with the same name+path is a no-op, and updating the path on a name reuse\n * is intentional (we control the path layout).\n */\nexport function ensureGroveRegistered(\n provider: Provider,\n repo: string,\n instancePath: string,\n): void {\n const cmd = `grove register --update --name ${shellQuote(repo)} ${shellQuoteHomePath(instancePath)}`;\n const result = runOnBox(provider, cmd);\n if (result.exitCode !== 0) {\n throw new Error(`Failed to register grove project ${repo}: ${result.stderr || result.stdout}`);\n }\n}\n","import { spawnSync } from 'node:child_process';\nimport { existsSync } from 'node:fs';\nimport { basename, join } from 'node:path';\nimport { EXEC_ENV } from '../../shared/exec.js';\n\nfunction captureGit(args: string[]): { stdout: string; ok: boolean } {\n const result = spawnSync('git', args, {\n encoding: 'utf-8',\n env: EXEC_ENV,\n });\n if (typeof result.stdout !== 'string') {\n throw new Error('Internal: git spawn did not capture stdout as string');\n }\n return { stdout: result.stdout.trim(), ok: result.status === 0 };\n}\n\n/**\n * Infer the repo name from the local git working tree's top-level dir basename.\n * Falls back to `basename(cwd)` when cwd is not inside a git repo — supports\n * parent dirs that contain repos but aren't themselves a repo.\n */\nexport function inferRepoName(): string {\n const { stdout, ok } = captureGit(['rev-parse', '--show-toplevel']);\n if (ok && stdout) return basename(stdout);\n return basename(process.cwd());\n}\n\n/**\n * Read the local repo's `origin` remote URL. Returns null if no `origin` is\n * configured or cwd is not inside a git repo.\n */\nexport function getOriginUrl(): string | null {\n const { stdout, ok } = captureGit(['remote', 'get-url', 'origin']);\n if (!ok) return null;\n return stdout.length > 0 ? stdout : null;\n}\n\n/**\n * Path to the local git toplevel, or cwd when cwd is not inside a git repo.\n * Non-repo mode is intentional: enables syncing parent dirs that contain\n * multiple child repos (each child's `.git/` rides along via rsync).\n */\nexport function getRepoToplevel(): string {\n const { stdout, ok } = captureGit(['rev-parse', '--show-toplevel']);\n if (ok && stdout) return stdout;\n return process.cwd();\n}\n\n/**\n * Defensive excludes layered on top of `.gitignore` filtering. Most of these\n * are usually gitignored, but listing them prevents accidentally pushing\n * hundreds of MB when a repo's `.gitignore` is incomplete.\n */\nconst DEFAULT_EXCLUDES = [\n '.sisyphus/',\n '.terraform/',\n 'node_modules/',\n 'dist/',\n '.next/',\n '.turbo/',\n 'coverage/',\n 'tmp/',\n '.git/lfs/',\n '.DS_Store',\n];\n\n/**\n * Build the rsync argv for a local→box sync. Includes `.git/` so the user can\n * `git push` from the box.\n */\nexport function buildRsyncArgs(localDir: string, remoteTarget: string): string[] {\n // Trailing slash on source = \"copy contents\", not \"copy dir into dest\".\n const src = localDir.endsWith('/') ? localDir : `${localDir}/`;\n return [\n '-avz',\n '--filter=:- .gitignore',\n ...DEFAULT_EXCLUDES.map((e) => `--exclude=${e}`),\n '-e', 'ssh',\n src,\n remoteTarget,\n ];\n}\n\nexport type PackageManager = 'pnpm' | 'npm' | 'yarn' | 'bun' | null;\n\n/**\n * Detect the package manager used by a repo from its lockfile.\n * Returns null when no known lockfile is present (no install step needed).\n */\nexport function detectPackageManager(toplevel: string): PackageManager {\n if (existsSync(join(toplevel, 'pnpm-lock.yaml'))) return 'pnpm';\n if (existsSync(join(toplevel, 'bun.lockb'))) return 'bun';\n if (existsSync(join(toplevel, 'yarn.lock'))) return 'yarn';\n if (existsSync(join(toplevel, 'package-lock.json'))) return 'npm';\n return null;\n}\n\nexport function packageManagerInstallCmd(pm: PackageManager): string | null {\n switch (pm) {\n case 'pnpm': return 'pnpm install';\n case 'bun': return 'bun install';\n case 'yarn': return 'yarn install';\n case 'npm': return 'npm install';\n default: return null;\n }\n}\n","import { boxCloudSidecarPath, boxCloudSidecarDir } from '../../shared/paths.js';\nimport { shellQuoteHomePath } from '../../shared/shell.js';\nimport { runOnBox } from '../deploy/ssh-exec.js';\nimport type { Provider } from '../deploy/creds.js';\nimport type { PackageManager } from './repo.js';\n\nexport interface CloudSidecar {\n originUrl: string | null;\n localHostname: string;\n lastSync?: string;\n lastInstall?: string;\n packageManager?: PackageManager;\n}\n\n/**\n * Read the per-repo sidecar JSON from the box at `~/.sisyphus/cloud/<repo>.json`.\n * Returns null if the file doesn't exist or is unparseable.\n */\nexport function readSidecar(provider: Provider, repo: string): CloudSidecar | null {\n const path = boxCloudSidecarPath(repo);\n // `cat` returns non-zero if file missing — that's our \"no sidecar\" signal.\n const result = runOnBox(provider, `cat ${shellQuoteHomePath(path)} 2>/dev/null`);\n if (result.exitCode !== 0 || !result.stdout.trim()) return null;\n try {\n const parsed = JSON.parse(result.stdout) as CloudSidecar;\n return parsed;\n } catch {\n return null;\n }\n}\n\n/**\n * Write/replace the sidecar JSON on the box. Creates `~/.sisyphus/cloud/`\n * if needed.\n */\nexport function writeSidecar(provider: Provider, repo: string, data: CloudSidecar): void {\n const dir = boxCloudSidecarDir();\n const path = boxCloudSidecarPath(repo);\n const json = JSON.stringify(data, null, 2);\n // Heredoc with a fixed sentinel keeps the JSON payload from needing further\n // shell escaping. Sentinel is unlikely to appear in real payloads.\n const cmd = [\n `mkdir -p ${shellQuoteHomePath(dir)}`,\n `cat > ${shellQuoteHomePath(path)} <<'SISYPHUS_CLOUD_SIDECAR_EOF'`,\n json,\n 'SISYPHUS_CLOUD_SIDECAR_EOF',\n ].join('\\n');\n const result = runOnBox(provider, cmd);\n if (result.exitCode !== 0) {\n throw new Error(`Failed to write sidecar for ${repo}: ${result.stderr || result.stdout}`);\n }\n}\n","import { isValidProvider, PROVIDERS, type Provider } from './creds.js';\nimport { isProvisioned } from './runner.js';\n\n/**\n * Resolve which provider a `cloud` command should target.\n *\n * - `explicit` set: validate against the known provider list and return.\n * - Exactly one provisioned: return it silently.\n * - Zero provisioned: throw with a hint to run `deploy <provider> up`.\n * - Multiple provisioned: throw with a hint to pass `--provider`.\n */\nexport function pickProvider(explicit?: string): Provider {\n if (explicit) {\n if (!isValidProvider(explicit)) {\n throw new Error(`Unknown provider \"${explicit}\". Valid: ${PROVIDERS.join(', ')}.`);\n }\n return explicit;\n }\n\n const provisioned = PROVIDERS.filter((p) => isProvisioned(p));\n if (provisioned.length === 1) return provisioned[0]!;\n if (provisioned.length === 0) {\n throw new Error(\n 'No cloud provider provisioned. Run `sis deploy <hetzner|aws> up` first.',\n );\n }\n throw new Error(\n `Multiple providers provisioned (${provisioned.join(', ')}). Pass --provider <name>.`,\n );\n}\n","import type { Command } from 'commander';\nimport {\n cloudAttach,\n cloudClaudeLogin,\n cloudInstall,\n cloudSession,\n cloudStart,\n cloudStatus,\n cloudSync,\n} from '../cloud/runner.js';\nimport { inferRepoName } from '../cloud/repo.js';\nimport { pickProvider } from '../deploy/provider-pick.js';\nimport type { Provider } from '../deploy/creds.js';\nimport { validateRepoName } from '../../shared/shell.js';\n\ninterface CommonRaw {\n name?: string;\n provider?: string;\n}\n\ninterface StartRaw extends CommonRaw {\n fresh?: boolean;\n yes?: boolean;\n}\n\nfunction resolve(raw: CommonRaw): { provider: Provider; repo: string } {\n const provider = pickProvider(raw.provider);\n const repo = raw.name ? raw.name : inferRepoName();\n if (!validateRepoName(repo)) {\n throw new Error(`Invalid --name \"${repo}\": must not contain '/' '\\\\' or '..'.`);\n }\n return { provider, repo };\n}\n\nexport function registerCloud(program: Command): void {\n const cloud = program\n .command('cloud')\n .description('Per-repo workflow on the shared cloud box (sync, install, dashboard).');\n\n cloud\n .command('sync')\n .description('Rsync this repo to the cloud box; ensures grove is installed and the repo is registered.')\n .option('--fresh', 'Wipe the box-side dir and `git clone` from origin instead of rsync.')\n .option('-y, --yes', 'Skip the --fresh confirmation prompt.')\n .option('--name <repo>', 'Override the repo name (default: basename of git toplevel).')\n .option('--provider <name>', 'Cloud provider (default: auto-pick if exactly one is provisioned).')\n .action(async (raw: StartRaw) => {\n const { provider, repo } = resolve(raw);\n await cloudSync(provider, repo, { fresh: raw.fresh === true, yes: raw.yes === true });\n });\n\n cloud\n .command('install')\n .description('Run the repo\\'s package-manager install on the box.')\n .option('--name <repo>', 'Override the repo name.')\n .option('--provider <name>', 'Cloud provider.')\n .action(async (raw: CommonRaw) => {\n const { provider, repo } = resolve(raw);\n await cloudInstall(provider, repo);\n });\n\n cloud\n .command('session')\n .description('Create or refresh the box-side tmux home session for this repo.')\n .option('--name <repo>', 'Override the repo name.')\n .option('--provider <name>', 'Cloud provider.')\n .action(async (raw: CommonRaw) => {\n const { provider, repo } = resolve(raw);\n await cloudSession(provider, repo);\n });\n\n cloud\n .command('attach')\n .description('Attach to the box-side tmux home session for this repo.')\n .option('--name <repo>', 'Override the repo name.')\n .option('--provider <name>', 'Cloud provider.')\n .action((raw: CommonRaw) => {\n const { provider, repo } = resolve(raw);\n cloudAttach(provider, repo);\n });\n\n cloud\n .command('start')\n .description('Sync, install, and start the dashboard session in one shot. (Stops short of attach.)')\n .option('--fresh', 'Wipe the box-side dir and `git clone` from origin instead of rsync.')\n .option('-y, --yes', 'Skip the --fresh confirmation prompt.')\n .option('--name <repo>', 'Override the repo name.')\n .option('--provider <name>', 'Cloud provider.')\n .action(async (raw: StartRaw) => {\n const { provider, repo } = resolve(raw);\n await cloudStart(provider, repo, { fresh: raw.fresh === true, yes: raw.yes === true });\n });\n\n cloud\n .command('claude-login')\n .description('Run `claude auth login` on the box (device-code flow; paste the URL into your local browser).')\n .option('--provider <name>', 'Cloud provider.')\n .action((raw: CommonRaw) => {\n const provider = pickProvider(raw.provider);\n cloudClaudeLogin(provider);\n });\n\n cloud\n .command('status')\n .description('Print box-side status for this repo (planted, session running, last sync/install).')\n .option('--name <repo>', 'Override the repo name.')\n .option('--provider <name>', 'Cloud provider.')\n .action((raw: CommonRaw) => {\n const { provider, repo } = resolve(raw);\n cloudStatus(provider, repo);\n });\n}\n","import type { Command } from 'commander';\nimport { rawSend } from '../client.js';\nimport type { Request } from '../../shared/protocol.js';\n\nexport function attachNotify(diagnostic: Command): void {\n const notify = diagnostic\n .command('notify')\n .description('Internal notifications (fire-and-forget)');\n\n notify\n .command('pane-exited')\n .description('Notify daemon that a tmux pane exited')\n .requiredOption('--pane-id <paneId>', 'Pane ID that exited')\n .action(async (opts: { paneId: string }) => {\n try {\n const request: Request = { type: 'pane-exited', paneId: opts.paneId };\n await rawSend(request);\n } catch {\n // Fire-and-forget: daemon may be stopped, socket gone, etc.\n }\n });\n}\n","import { execSync } from 'node:child_process';\nimport { readFileSync, existsSync } from 'node:fs';\nimport type { Command } from 'commander';\nimport { sessionsManifestPath } from '../../shared/paths.js';\n\ninterface ManifestEntry {\n type: 'S' | 'H' | 'O';\n tmuxName: string;\n cwd: string;\n phase: string | null;\n}\n\ninterface Manifest {\n updatedAt: number;\n sessions: ManifestEntry[];\n}\n\nconst DOT_MAP: Record<string, { icon: string; color: string }> = {\n 'orchestrator:processing': { icon: '●', color: '#d4ad6a' },\n 'orchestrator:idle': { icon: '●', color: '#d47766' },\n 'agents:running': { icon: '◆', color: '#d4ad6a' },\n 'between-cycles': { icon: '◆', color: '#5e584e' },\n 'paused': { icon: '○', color: '#d47766' },\n 'completed': { icon: '●', color: '#a9b16e' },\n};\n\nfunction readManifest(): Manifest | null {\n const p = sessionsManifestPath();\n if (!existsSync(p)) return null;\n try {\n return JSON.parse(readFileSync(p, 'utf-8')) as Manifest;\n } catch {\n return null;\n }\n}\n\nfunction tmuxExec(cmd: string): string | null {\n try {\n return execSync(cmd, { encoding: 'utf-8', stdio: ['pipe', 'pipe', 'pipe'] }).trim();\n } catch {\n return null;\n }\n}\n\nexport function attachTmuxSessions(diagnostic: Command): void {\n diagnostic\n .command('tmux-sessions')\n .description('Output sisyphus session list for tmux status bar')\n .action(() => {\n const manifest = readManifest();\n if (!manifest) return;\n\n const currentSession = tmuxExec(\"tmux display-message -p '#{session_name}'\");\n\n // Find the cwd of the current session from the manifest\n const currentEntry = manifest.sessions.find(s => s.tmuxName === currentSession);\n if (!currentEntry) return;\n const cwd = currentEntry.cwd;\n\n // Filter to sessions matching this cwd\n const entries = manifest.sessions.filter(s => s.cwd === cwd);\n if (entries.length <= 1) return;\n\n const parts = entries.map(e => {\n const dot = e.phase ? DOT_MAP[e.phase] : null;\n const dotStr = dot ? ` #[fg=${dot.color}]${dot.icon}` : '';\n const displayName = e.tmuxName.replace(/^ssyph_[^_]+_/, '');\n const isCurrent = e.tmuxName === currentSession;\n\n if (isCurrent) {\n return `#[fg=#e2d9c6,bold]${displayName}${dotStr}#[default]`;\n }\n return `#[fg=#5e584e]${displayName}${dotStr}#[default]`;\n });\n\n process.stdout.write(parts.join('#[fg=#3a3d42] │ '));\n });\n}\n"],"mappings":"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,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,EACF;AAAA,EACA,eAAe;AAAA,IACb;AAAA,IACA;A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","names":["randomUUID","dirname","join","renameSync","writeFileSync","resolve","chmodSync","existsSync","mkdirSync","readFileSync","createInterface","resolve","existsSync","mkdirSync","readFileSync","dirname","join","fileURLToPath","execSync","basename","resolve","execSync","existsSync","mkdirSync","readFileSync","unlinkSync","writeFileSync","connect","homedir","join","homedir","join","sep","join","join","args","homedir","resolve","execSync","readFileSync","readFileSync","homedir","join","join","homedir","readFileSync","execSync","join","homedir","existsSync","mkdirSync","writeFileSync","execSync","unlinkSync","resolve","connect","readFileSync","rawSend","sleep","resolve","resolve","execSync","execSync","join","execSync","execSync","join","program","basename","execSync","program","execSync","existsSync","readFileSync","session","session","agent","readFileSync","existsSync","execSync","program","basename","RESET","BOLD","DIM","program","readFileSync","readStdin","readFileSync","program","submit","existsSync","readFileSync","homedir","join","ORCH_ALIASES","join","homedir","c","program","session","existsSync","readFileSync","program","existsSync","readFileSync","join","resolve","spawnSync","existsSync","readFileSync","dirname","resolve","existsSync","mkdirSync","readFileSync","readdirSync","mkdirSync","writeFileSync","readFileSync","rmSync","dirname","join","existsSync","mkdirSync","readFileSync","readdirSync","rmSync","statSync","writeFileSync","join","existsSync","readFileSync","writeFileSync","join","readFileSync","session","agent","session","c","agent","writeFileSync","mkdirSync","existsSync","join","homedir","join","homedir","scriptPath","mkdirSync","writeFileSync","existsSync","session","mkdirSync","readFileSync","existsSync","readFileSync","existsSync","execSync","resolve","execSync","program","existsSync","session","readFileSync","join","resolve","program","program","program","program","program","program","program","program","program","program","readFileSync","readdirSync","readFileSync","readFileSync","readdirSync","session","agent","program","session","existsSync","join","resolve","readFileSync","existsSync","readdirSync","homedir","join","basename","readdirSync","basename","readFileSync","join","homedir","resolve","program","join","existsSync","program","program","existsSync","readFileSync","program","existsSync","readFileSync","program","program","program","program","program","execSync","execSync","existsSync","readFileSync","writeFileSync","homedir","dirname","join","fileURLToPath","execSync","plistPath","join","homedir","existsSync","writeFileSync","dirname","fileURLToPath","readFileSync","baleiaInstalled","execSync","program","program","execSync","execSync","execSync","existsSync","statSync","homedir","join","execSync","existsSync","statSync","join","homedir","program","c","existsSync","mkdirSync","writeFileSync","join","DEFAULT_CONFIG","program","createInterface","createInterface","resolve","program","chmodSync","existsSync","mkdirSync","readFileSync","writeFileSync","createInterface","dirname","resolve","program","execSync","dirname","join","fileURLToPath","join","dirname","fileURLToPath","execSync","program","c","args","readdirSync","readFileSync","existsSync","resolve","RESET","BOLD","DIM","existsSync","readdirSync","readFileSync","session","c","resolve","program","execFile","existsSync","readFileSync","mkdirSync","rmSync","writeFileSync","homedir","join","program","session","rmSync","args","session","args","readFileSync","resolve","program","session","persistReq","rmSync","execSync","execSync","program","join","resolve","dirname","existsSync","readFileSync","writeFileSync","renameSync","readdirSync","session","program","c","basename","c","colorize","result","existsSync","mkdirSync","readFileSync","renameSync","writeFileSync","dirname","join","randomUUID","z","existsSync","mkdirSync","readFileSync","renameSync","writeFileSync","randomUUID","dirname","join","existsSync","state","readFileSync","dirname","mkdirSync","join","randomUUID","writeFileSync","renameSync","existsSync","readFileSync","z","writeFileSync","readFileSync","unlinkSync","existsSync","tmpdir","join","resolve","join","tmpdir","resolve","wrapText","writeFileSync","existsSync","unlinkSync","args","readFileSync","basename","program","companion","homedir","join","spawn","spawnSync","copyFileSync","existsSync","mkdirSync","readFileSync","existsSync","readFileSync","unlinkSync","resolve","existsSync","dirname","resolve","fileURLToPath","hostname","args","spawnSync","existsSync","mkdirSync","copyFileSync","readFileSync","confirm","spawn","promptLine","program","join","homedir","spawn","spawn","spawnSync","spawnSync","resolve","spawn","spawnSync","existsSync","basename","join","args","spawnSync","basename","existsSync","join","args","resolve","spawn","resolve","program","diagnostic","rawSend","execSync","readFileSync","existsSync","diagnostic","readFileSync","join","dirname","fileURLToPath","existsSync","mkdirSync"]}
|
|
1
|
+
{"version":3,"sources":["../src/shared/paths.ts","../src/shared/shell.ts","../src/daemon/lib/atomic.ts","../src/shared/env.ts","../src/shared/exec.ts","../src/tui/lib/tmux.ts","../src/cli/deploy/creds.ts","../src/cli/index.ts","../src/cli/commands/start.ts","../src/shared/client.ts","../src/cli/install.ts","../src/cli/tmux-setup.ts","../src/shared/keymap.ts","../src/shared/sisyphus-init-lua.ts","../src/cli/plugins.ts","../src/shared/config.ts","../src/daemon/plugins.ts","../src/cli/client.ts","../src/cli/stdin.ts","../src/cli/tmux.ts","../src/cli/commands/dashboard.ts","../src/cli/commands/status.ts","../src/shared/utils.ts","../src/shared/format.ts","../src/cli/commands/list.ts","../src/cli/commands/tell.ts","../src/cli/commands/read.ts","../src/cli/commands/message.ts","../src/cli/commands/ask.ts","../src/shared/ask-schema.ts","../src/daemon/ask-store.ts","../src/daemon/history.ts","../src/daemon/state.ts","../src/shared/gitignore.ts","../src/shared/types.ts","../src/daemon/notify.ts","../src/cli/commands/kill.ts","../src/cli/commands/delete.ts","../src/cli/commands/resume.ts","../src/cli/commands/continue.ts","../src/cli/commands/complete.ts","../src/cli/commands/rollback.ts","../src/cli/commands/reconnect.ts","../src/cli/commands/clone.ts","../src/cli/commands/update-task.ts","../src/cli/commands/set-effort.ts","../src/cli/commands/set-dangerous.ts","../src/tui/lib/context.ts","../src/tui/lib/reports.ts","../src/cli/commands/print-context.ts","../src/cli/commands/spawn.ts","../src/daemon/frontmatter.ts","../src/cli/commands/submit.ts","../src/cli/commands/report.ts","../src/cli/commands/await.ts","../src/cli/commands/kill-agent.ts","../src/cli/commands/restart-agent.ts","../src/cli/commands/yield.ts","../src/cli/commands/register-segment.ts","../src/cli/commands/unregister-segment.ts","../src/cli/commands/setup.ts","../src/cli/onboard.ts","../src/cli/commands/setup-keybind.ts","../src/cli/commands/check-keybinds.ts","../src/cli/commands/check-statusbar.ts","../src/cli/commands/home-init.ts","../src/cli/commands/doctor.ts","../src/cli/commands/init.ts","../src/cli/commands/uninstall.ts","../src/cli/commands/configure-upload.ts","../src/cli/commands/getting-started.ts","../src/cli/commands/history.ts","../src/shared/session-export.ts","../src/cli/commands/export.ts","../src/cli/commands/upload.ts","../src/shared/upload.ts","../src/shared/manifest.ts","../src/shared/version.ts","../src/cli/commands/scratch.ts","../src/cli/commands/review.ts","../src/cli/commands/companion.ts","../src/shared/companion-render.ts","../src/shared/companion-types.ts","../src/shared/companion-badges.ts","../src/daemon/companion-memory.ts","../src/daemon/haiku.ts","../src/daemon/companion.ts","../src/shared/companion-normalize.ts","../src/daemon/companion-popup.ts","../src/cli/commands/deploy.ts","../src/cli/deploy/runner.ts","../src/cli/deploy/pricing.ts","../src/cli/deploy/runtime.ts","../src/cli/deploy/tailnet.ts","../src/cli/deploy/templates.ts","../src/cli/deploy/tailscale.ts","../src/cli/cloud/runner.ts","../src/cli/deploy/ssh-exec.ts","../src/cli/cloud/grove.ts","../src/cli/cloud/repo.ts","../src/cli/cloud/sidecar.ts","../src/cli/deploy/provider-pick.ts","../src/cli/commands/cloud.ts","../src/cli/commands/notify.ts","../src/cli/commands/tmux-sessions.ts"],"sourcesContent":["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","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 { 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 { 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 { 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';\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 { chmodSync, existsSync, mkdirSync, readFileSync } from 'node:fs';\nimport { createInterface } from 'node:readline';\nimport { atomicWrite } from '../../daemon/lib/atomic.js';\nimport {\n deployCredsPath,\n deployDir,\n deployTailscaleEnvPath,\n} from '../../shared/paths.js';\n\nexport type Provider = 'hetzner' | 'aws';\n\nexport const PROVIDERS: readonly Provider[] = ['hetzner', 'aws'];\n\nexport function isValidProvider(value: string): value is Provider {\n return (PROVIDERS as readonly string[]).includes(value);\n}\n\ninterface CredsSpec {\n provider: Provider;\n required: readonly string[];\n optional?: readonly string[];\n helpUrl: string;\n}\n\nconst SPECS: Record<Provider, CredsSpec> = {\n hetzner: {\n provider: 'hetzner',\n required: ['HCLOUD_TOKEN'],\n helpUrl: 'https://console.hetzner.cloud/projects → API tokens → Generate',\n },\n aws: {\n provider: 'aws',\n required: ['AWS_ACCESS_KEY_ID', 'AWS_SECRET_ACCESS_KEY'],\n optional: ['AWS_REGION', 'AWS_SESSION_TOKEN'],\n helpUrl: 'https://console.aws.amazon.com/iam/home → Users → Security credentials',\n },\n};\n\nexport function ensureDeployDir(): void {\n const dir = deployDir();\n if (!existsSync(dir)) mkdirSync(dir, { recursive: true, mode: 0o700 });\n}\n\nfunction parseEnvFile(text: string): Record<string, string> {\n const out: Record<string, string> = {};\n for (const line of text.split('\\n')) {\n const trimmed = line.trim();\n if (!trimmed || trimmed.startsWith('#')) continue;\n const eq = trimmed.indexOf('=');\n if (eq < 0) continue;\n const key = trimmed.slice(0, eq).trim();\n let value = trimmed.slice(eq + 1).trim();\n if ((value.startsWith('\"') && value.endsWith('\"')) || (value.startsWith(\"'\") && value.endsWith(\"'\"))) {\n value = value.slice(1, -1);\n }\n out[key] = value;\n }\n return out;\n}\n\nfunction serializeEnvFile(values: Record<string, string>): string {\n const lines: string[] = ['# Managed by `sis deploy`. Do not edit unless you know what you are doing.'];\n for (const [k, v] of Object.entries(values)) {\n lines.push(`${k}=${v}`);\n }\n return lines.join('\\n') + '\\n';\n}\n\nfunction readEnvFile(path: string): Record<string, string> | null {\n if (!existsSync(path)) return null;\n return parseEnvFile(readFileSync(path, 'utf-8'));\n}\n\nfunction writeEnvFile(path: string, values: Record<string, string>): void {\n ensureDeployDir();\n atomicWrite(path, serializeEnvFile(values));\n chmodSync(path, 0o600);\n}\n\nasync function promptLine(question: string, hidden: boolean): Promise<string> {\n const rl = createInterface({ input: process.stdin, output: process.stdout, terminal: true });\n // Mute echo for secrets — same trick as `read -s`.\n if (hidden) {\n const stdout = process.stdout as NodeJS.WriteStream & { _writeToOutput?: (s: string) => void };\n const originalWrite = stdout.write.bind(stdout);\n let prompted = false;\n (rl as unknown as { _writeToOutput: (s: string) => void })._writeToOutput = (stringToWrite: string) => {\n if (!prompted) {\n originalWrite(stringToWrite);\n prompted = true;\n }\n // swallow subsequent keystroke echoes\n };\n }\n const answer = await new Promise<string>((resolve) => rl.question(question, resolve));\n rl.close();\n if (hidden) process.stdout.write('\\n');\n return answer.trim();\n}\n\nasync function promptMissing(spec: CredsSpec, existing: Record<string, string>): Promise<Record<string, string>> {\n const next = { ...existing };\n const missing = spec.required.filter((k) => !next[k]);\n if (missing.length === 0) return next;\n\n console.log('');\n console.log(`Provider creds needed for: ${spec.provider}`);\n console.log(`Where to get them: ${spec.helpUrl}`);\n console.log('');\n for (const key of missing) {\n const isSecret = /SECRET|TOKEN|KEY/.test(key) && key !== 'AWS_ACCESS_KEY_ID';\n const value = await promptLine(` ${key}: `, isSecret);\n if (!value) throw new Error(`${key} is required.`);\n next[key] = value;\n }\n return next;\n}\n\n/**\n * Load creds for a provider. If any required keys are missing, prompts the\n * user and persists to `~/.sisyphus/deploy/<provider>.env` (0600). Returns\n * the loaded env vars merged with `process.env`-style record suitable for\n * passing as `env` to a child process.\n */\nexport async function loadProviderCreds(provider: Provider): Promise<Record<string, string>> {\n const spec = SPECS[provider];\n const path = deployCredsPath(provider);\n const existing = readEnvFile(path) ?? {};\n const final = await promptMissing(spec, existing);\n if (final !== existing) writeEnvFile(path, final);\n return final;\n}\n\nexport function maskValue(value: string): string {\n if (value.length <= 8) return '*'.repeat(value.length);\n return value.slice(0, 4) + '*'.repeat(value.length - 8) + value.slice(-4);\n}\n\n// ── Tailscale ─────────────────────────────────────────────────────────────────\n\nexport interface TailscaleEnv {\n // OAuth client (preferred): mints ephemeral, single-use, tagged keys per `up`.\n oauthClientId?: string;\n oauthClientSecret?: string;\n // Fallback: a reusable auth key pasted from the admin UI.\n authKey?: string;\n // Tag applied to minted keys (e.g. \"tag:sisyphus\") — required when using OAuth.\n tag?: string;\n}\n\nexport function readTailscaleEnv(): TailscaleEnv {\n const raw = readEnvFile(deployTailscaleEnvPath()) ?? {};\n return {\n oauthClientId: raw.TS_OAUTH_CLIENT_ID,\n oauthClientSecret: raw.TS_OAUTH_CLIENT_SECRET,\n authKey: raw.TS_AUTHKEY,\n tag: raw.TS_TAG,\n };\n}\n\nexport function writeTailscaleEnv(env: TailscaleEnv): void {\n const values: Record<string, string> = {};\n if (env.oauthClientId) values.TS_OAUTH_CLIENT_ID = env.oauthClientId;\n if (env.oauthClientSecret) values.TS_OAUTH_CLIENT_SECRET = env.oauthClientSecret;\n if (env.authKey) values.TS_AUTHKEY = env.authKey;\n if (env.tag) values.TS_TAG = env.tag;\n writeEnvFile(deployTailscaleEnvPath(), values);\n}\n\nexport { promptLine };\n","const nodeVersion = parseInt(process.versions.node.split('.')[0]!, 10);\nif (nodeVersion < 22) {\n console.error(`Sisyphus requires Node.js v22+ (current: v${process.versions.node})`);\n process.exit(1);\n}\n\nimport { Command } from 'commander';\nimport { existsSync, mkdirSync, readFileSync } from 'node:fs';\nimport { dirname, join } from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport { registerStart } from './commands/start.js';\nimport { registerStatus } from './commands/status.js';\nimport { registerDashboard } from './commands/dashboard.js';\nimport { registerList } from './commands/list.js';\nimport { registerTell } from './commands/tell.js';\nimport { registerRead } from './commands/read.js';\nimport { registerMessage } from './commands/message.js';\nimport { registerAsk } from './commands/ask.js';\nimport { registerKill } from './commands/kill.js';\nimport { registerDelete } from './commands/delete.js';\nimport { registerResume } from './commands/resume.js';\nimport { registerContinue } from './commands/continue.js';\nimport { registerComplete } from './commands/complete.js';\nimport { registerRollback } from './commands/rollback.js';\nimport { registerReconnect } from './commands/reconnect.js';\nimport { registerClone } from './commands/clone.js';\nimport { registerSessionTask } from './commands/update-task.js';\nimport { registerSessionEffort } from './commands/set-effort.js';\nimport { registerSessionDangerous } from './commands/set-dangerous.js';\nimport { registerSessionContext } from './commands/print-context.js';\nimport { registerSpawn } from './commands/spawn.js';\nimport { registerSubmit } from './commands/submit.js';\nimport { registerReport } from './commands/report.js';\nimport { registerAwait } from './commands/await.js';\nimport { registerAgentKill } from './commands/kill-agent.js';\nimport { registerAgentRestart } from './commands/restart-agent.js';\nimport { registerYield } from './commands/yield.js';\nimport { registerSegmentRegister } from './commands/register-segment.js';\nimport { registerSegmentUnregister } from './commands/unregister-segment.js';\nimport { registerSetup } from './commands/setup.js';\nimport { registerSetupKeybind } from './commands/setup-keybind.js';\nimport { registerCheckKeybinds } from './commands/check-keybinds.js';\nimport { registerCheckStatusbar } from './commands/check-statusbar.js';\nimport { registerHomeInit } from './commands/home-init.js';\nimport { registerDoctor } from './commands/doctor.js';\nimport { registerInit } from './commands/init.js';\nimport { registerUninstall } from './commands/uninstall.js';\nimport { registerConfigureUpload } from './commands/configure-upload.js';\nimport { registerGettingStarted } from './commands/getting-started.js';\nimport { registerHistory } from './commands/history.js';\nimport { registerExport } from './commands/export.js';\nimport { registerUpload } from './commands/upload.js';\nimport { registerScratch } from './commands/scratch.js';\nimport { registerReview } from './commands/review.js';\nimport { registerCompanion } from './commands/companion.js';\nimport { registerDeploy } from './commands/deploy.js';\nimport { registerCloud } from './commands/cloud.js';\nimport { attachNotify } from './commands/notify.js';\nimport { attachTmuxSessions } from './commands/tmux-sessions.js';\nimport { globalDir } from '../shared/paths.js';\n\nconst program = new Command();\n\nprogram\n .name('sis')\n .description('tmux-integrated orchestration daemon for Claude Code')\n .version(\n JSON.parse(\n readFileSync(join(dirname(fileURLToPath(import.meta.url)), '..', 'package.json'), 'utf-8'),\n ).version,\n );\n\nprogram.configureHelp({\n sortSubcommands: false,\n});\n\n// Flat hot-path\nregisterStart(program);\nregisterStatus(program);\nregisterDashboard(program);\nregisterList(program);\nregisterTell(program);\nregisterRead(program);\nregisterMessage(program);\nregisterAsk(program);\n\n// session group\nconst session = program.command('session').description('Manage sessions');\nregisterKill(session);\nregisterDelete(session);\nregisterResume(session);\nregisterContinue(session);\nregisterComplete(session);\nregisterRollback(session);\nregisterReconnect(session);\nregisterClone(session);\nregisterSessionTask(session);\nregisterSessionEffort(session);\nregisterSessionDangerous(session);\nregisterSessionContext(session);\n\n// agent group\nconst agent = program.command('agent').description('Manage agents');\nregisterSpawn(agent);\nregisterSubmit(agent);\nregisterReport(agent);\nregisterAwait(agent);\nregisterAgentKill(agent);\nregisterAgentRestart(agent);\n\n// orch group\nconst orch = program.command('orch').description('Orchestrator commands');\nregisterYield(orch);\n\n// segment group\nconst segment = program.command('segment').description('Status-line segments');\nregisterSegmentRegister(segment);\nregisterSegmentUnregister(segment);\n\n// admin group\nconst admin = program.command('admin').description('Admin / setup commands');\nregisterSetup(admin);\nregisterSetupKeybind(admin);\nregisterCheckKeybinds(admin);\nregisterCheckStatusbar(admin);\nregisterHomeInit(admin);\nregisterDoctor(admin);\nregisterInit(admin);\nregisterUninstall(admin);\nregisterConfigureUpload(admin);\nregisterGettingStarted(admin);\nregisterHistory(admin);\nregisterExport(admin);\nregisterUpload(admin);\nregisterScratch(admin);\nregisterReview(admin);\n\n// companion group (root action + memory + popup-test + context)\nregisterCompanion(program);\n\n// deploy group (Terraform-wrapped cloud provisioning)\nregisterDeploy(program);\n\n// cloud group (per-repo workflow on the deployed box)\nregisterCloud(program);\n\n// diagnostic group (hidden)\nconst diagnostic = program.command('diagnostic', { hidden: true });\nattachNotify(diagnostic);\nattachTmuxSessions(diagnostic);\n\nprogram.addHelpText('after', `\nExamples:\n $ sis start \"Implement auth system\" Start a new session\n $ sis start \"Build @reqs.md\" -n auth Start with name + requirements\n $ sis status Check current sessions\n $ sis dashboard Open the TUI\n $ sis admin doctor Verify installation\n\nRun 'sis admin getting-started' for a complete usage guide.\n`);\n\n// Show welcome on first run (before ~/.sisyphus exists)\nconst args = process.argv.slice(2);\nconst firstArg = args[0];\nconst skipWelcome = ['admin', 'help', '--help', '-h', '--version', '-V'];\nif (!existsSync(globalDir()) && firstArg && !skipWelcome.includes(firstArg)) {\n mkdirSync(globalDir(), { recursive: true });\n console.log('');\n console.log(\" Welcome to Sisyphus. Run 'sis admin setup' to get started.\");\n console.log('');\n}\n\nprogram.parseAsync(process.argv).catch((err: Error) => {\n console.error(err.message);\n process.exit(1);\n});\n","import type { Command } from 'commander';\nimport { execSync, spawnSync } from 'node:child_process';\nimport { basename } from 'node:path';\nimport { sendRequest } from '../client.js';\nimport { readStdin } from '../stdin.js';\nimport { getTmuxSessionInfo, isTmuxInstalled } from '../tmux.js';\nimport { shellQuote } from '../../shared/shell.js';\nimport { openDashboardWindow } from './dashboard.js';\nimport type { Request } from '../../shared/protocol.js';\n\n\n/**\n * Get or create a tmux session for the given cwd.\n * Returns the session name. Does NOT attach — caller decides.\n */\nfunction ensureTmuxSessionExists(cwd: string): string {\n const sessionName = `sisyphus-${basename(cwd)}`;\n\n try {\n execSync(`tmux has-session -t ${shellQuote(sessionName)}`, { stdio: 'pipe' });\n } catch {\n execSync(\n `tmux new-session -d -s ${shellQuote(sessionName)} -c ${shellQuote(cwd)}`,\n { stdio: 'pipe' },\n );\n }\n\n return sessionName;\n}\n\n/**\n * Attach the user's terminal to a tmux session.\n * If already inside tmux, switches the client. Otherwise, attaches directly.\n * Attach/switch takes over the terminal — this blocks until detach.\n */\nfunction attachToTmuxSession(sessionName: string): void {\n if (process.env['TMUX']) {\n // Already in tmux — switch to the target session\n spawnSync('tmux', ['switch-client', '-t', sessionName], { stdio: 'inherit' });\n } else {\n // Not in tmux — attach takes over the terminal\n spawnSync('tmux', ['attach-session', '-t', sessionName], { stdio: 'inherit' });\n }\n}\n\n\nexport function registerStart(program: Command): void {\n program\n .command('start')\n .description('Start a new sisyphus session')\n .argument('[task]', 'Task description for the orchestrator (omit when using --stdin)')\n .option('-c, --context <context>', 'Background context for the orchestrator')\n .option('-n, --name <name>', 'Human-readable name for the session')\n .option('--effort <tier>', 'Pipeline effort tier (low|medium|high|xhigh)')\n .option('--no-tmux-check', 'Skip the tmux session check')\n .option('--stdin', 'Read the task description from stdin (avoids shell escaping for long prompts)')\n .option('--context-stdin', 'Read the context from stdin (mutually exclusive with --stdin)')\n .action(async (taskArg: string | undefined, opts: { context?: string; name?: string; effort?: string; tmuxCheck?: boolean; stdin?: boolean; contextStdin?: boolean }) => {\n const cwd = process.env['SISYPHUS_CWD'] ?? process.cwd();\n\n if (opts.stdin && opts.contextStdin) {\n console.error('Error: --stdin and --context-stdin cannot be combined; pipe one and pass the other on argv');\n process.exit(1);\n }\n\n let task: string | undefined = taskArg;\n let context: string | undefined = opts.context;\n\n if (opts.stdin) {\n const piped = await readStdin({ force: true });\n if (!piped) {\n console.error('Error: --stdin set but no input received on stdin');\n process.exit(1);\n }\n if (taskArg !== undefined && taskArg !== '-') {\n console.error('Error: --stdin conflicts with [task] positional; pass one or the other');\n process.exit(1);\n }\n task = piped;\n } else if (taskArg === '-') {\n const piped = await readStdin({ force: true });\n if (!piped) {\n console.error(\"Error: task '-' means read stdin, but no input received\");\n process.exit(1);\n }\n task = piped;\n }\n\n if (opts.contextStdin) {\n const piped = await readStdin({ force: true });\n if (!piped) {\n console.error('Error: --context-stdin set but no input received on stdin');\n process.exit(1);\n }\n if (opts.context !== undefined) {\n console.error('Error: --context-stdin conflicts with -c/--context; use one');\n process.exit(1);\n }\n context = piped;\n }\n\n if (!task) {\n console.error('Error: provide <task> argument, pipe via --stdin, or pass `-` as the task');\n process.exit(1);\n }\n\n if (opts.effort !== undefined) {\n const validTiers = ['low', 'medium', 'high', 'xhigh'];\n if (!validTiers.includes(opts.effort)) {\n console.error(`Error: --effort must be one of: ${validTiers.join(', ')}`);\n process.exit(1);\n }\n }\n\n if (!isTmuxInstalled()) {\n console.error('Error: tmux is not installed. Sisyphus requires tmux for agent panes.');\n console.error(' Install: brew install tmux (macOS) or apt install tmux (Linux)');\n process.exit(1);\n }\n\n // Send the start request — this is just a socket call, no tmux needed\n const effort = opts.effort as 'low' | 'medium' | 'high' | 'xhigh' | undefined;\n const request: Request = { type: 'start', task, context, cwd, name: opts.name, ...(effort !== undefined ? { effort } : {}) };\n const response = await sendRequest(request);\n if (!response.ok) {\n console.error(`Error: ${response.error}`);\n process.exit(1);\n }\n\n const sessionId = response.data?.sessionId as string;\n console.log(`Task handed off to sisyphus orchestrator (session ${sessionId})`);\n\n if (opts.tmuxCheck === false) {\n // --no-tmux-check: print info and exit, don't touch tmux\n const tmuxSessionName = response.data?.tmuxSessionName as string | undefined;\n if (tmuxSessionName) {\n console.log(`Tmux session: ${tmuxSessionName}`);\n console.log(` tmux attach -t ${tmuxSessionName}`);\n }\n console.log(`Monitor: sis status ${sessionId}`);\n return;\n }\n\n // Determine which tmux session to use for the dashboard.\n // If we're already in tmux, use the current session.\n // If not, create a dedicated session for this project.\n let tmuxSession: string;\n let tmuxSessionTarget: string;\n if (process.env['TMUX']) {\n const info = getTmuxSessionInfo();\n tmuxSession = info.name;\n tmuxSessionTarget = info.id;\n } else {\n tmuxSession = ensureTmuxSessionExists(cwd);\n tmuxSessionTarget = tmuxSession;\n }\n\n // Tag the tmux session with the cwd — but don't clobber a tag that\n // already points to a different project. Overwriting would re-home an\n // existing session onto this project, poisoning alt+s cycle groups and\n // C-s h for the original project.\n // Target by $N id when available — tmux -t <name> can substring-match\n // the wrong session under sparse env.\n try {\n const normalizedCwd = cwd.replace(/\\/+$/, '');\n let existing = '';\n try {\n existing = execSync(\n `tmux show-options -t ${shellQuote(tmuxSessionTarget)} -v @sisyphus_cwd`,\n { encoding: 'utf-8', stdio: ['pipe', 'pipe', 'pipe'] },\n ).trim();\n } catch {\n // option unset\n }\n if (!existing || existing === normalizedCwd) {\n execSync(\n `tmux set-option -t ${shellQuote(tmuxSessionTarget)} @sisyphus_cwd ${shellQuote(normalizedCwd)}`,\n { stdio: 'ignore' },\n );\n } else {\n console.error(\n `Note: tmux session \"${tmuxSession}\" is already the home for ${existing}; leaving its @sisyphus_cwd unchanged.`,\n );\n }\n } catch (err) {\n console.error(`Warning: failed to tag tmux session with cwd: ${err instanceof Error ? err.message : String(err)}`);\n }\n\n // Open dashboard in the tmux session\n try {\n openDashboardWindow(tmuxSession, cwd);\n } catch (err) {\n console.error(`Warning: failed to open dashboard window: ${err instanceof Error ? err.message : String(err)}`);\n }\n\n // If we weren't in tmux, attach now — user lands on the dashboard\n if (!process.env['TMUX']) {\n attachToTmuxSession(tmuxSession);\n }\n\n console.log(`Monitor: sis status ${sessionId}`);\n });\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","import { execSync } from 'node:child_process';\nimport { existsSync, mkdirSync, readFileSync, rmSync, unlinkSync, writeFileSync } from 'node:fs';\nimport { connect } from 'node:net';\nimport { homedir } from 'node:os';\nimport { dirname, join, resolve } from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport { daemonLogPath, daemonUpdatingPath, globalDir, socketPath } from '../shared/paths.js';\nimport { type SetupResult, removeTmuxKeybind, setupTmuxKeybind } from './tmux-setup.js';\nimport { ensureRequiredPlugins, ensureSisyphusPluginInstalled, type SisyphusPluginInfo } from './plugins.js';\n\nconst PLIST_LABEL = 'com.sisyphus.daemon';\nconst PLIST_FILENAME = `${PLIST_LABEL}.plist`;\n\nfunction launchAgentDir(): string {\n return join(homedir(), 'Library', 'LaunchAgents');\n}\n\nfunction plistPath(): string {\n return join(launchAgentDir(), PLIST_FILENAME);\n}\n\nfunction daemonBinPath(): string {\n // In bundled output, cli.js and daemon.js are siblings in dist/\n const installDir = dirname(fileURLToPath(import.meta.url));\n return resolve(installDir, 'daemon.js');\n}\n\nfunction generatePlist(nodePath: string, daemonPath: string, logPath: string): string {\n return `<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n <key>Label</key>\n <string>${PLIST_LABEL}</string>\n <key>ProgramArguments</key>\n <array>\n <string>${nodePath}</string>\n <string>${daemonPath}</string>\n </array>\n <key>RunAtLoad</key>\n <true/>\n <key>KeepAlive</key>\n <true/>\n <key>StandardOutPath</key>\n <string>${logPath}</string>\n <key>StandardErrorPath</key>\n <string>${logPath}</string>\n</dict>\n</plist>\n`;\n}\n\nexport function isInstalled(): boolean {\n return existsSync(plistPath());\n}\n\nexport async function ensureDaemonInstalled(): Promise<void> {\n if (process.platform !== 'darwin') return;\n\n // Idempotent: ensures the user-facing slash-command plugin is available.\n // Placed outside the !isInstalled() guard so users whose daemon was installed\n // before this plugin shipped self-heal the next time the daemon is unreachable.\n const sisyphusPlugin = ensureSisyphusPluginInstalled();\n\n if (!isInstalled()) {\n const nodePath = process.execPath;\n const daemonPath = daemonBinPath();\n const logPath = daemonLogPath();\n\n mkdirSync(globalDir(), { recursive: true });\n mkdirSync(launchAgentDir(), { recursive: true });\n\n const plist = generatePlist(nodePath, daemonPath, logPath);\n writeFileSync(plistPath(), plist, 'utf8');\n\n execSync(`launchctl load -w ${plistPath()}`);\n\n const keybindResult = await setupTmuxKeybind();\n\n await ensureRequiredPlugins(process.cwd());\n\n printGettingStarted(keybindResult, sisyphusPlugin);\n }\n\n await waitForDaemon();\n}\n\nexport async function uninstallDaemon(purge: boolean): Promise<void> {\n if (process.platform !== 'darwin') {\n console.log('Auto-install is only supported on macOS.');\n return;\n }\n\n const plist = plistPath();\n if (existsSync(plist)) {\n try {\n execSync(`launchctl unload -w ${plist}`, { stdio: 'pipe' });\n } catch {\n // already unloaded or not registered — ignore\n }\n unlinkSync(plist);\n console.log('Daemon unloaded and plist removed.');\n } else {\n console.log('Daemon is not installed (plist not found).');\n }\n\n removeTmuxKeybind();\n\n if (purge) {\n const dir = globalDir();\n if (existsSync(dir)) {\n rmSync(dir, { recursive: true, force: true });\n console.log(`Removed ${dir}`);\n }\n }\n}\n\nfunction printGettingStarted(\n keybindResult: SetupResult,\n sisyphusPlugin: SisyphusPluginInfo,\n): void {\n const lines = [\n '',\n 'Sisyphus installed — daemon running via launchd.',\n '',\n ];\n\n if (keybindResult.status === 'installed') {\n lines.push(`Tmux keybind: ${keybindResult.message}`, '');\n } else if (keybindResult.status === 'conflict' || keybindResult.status === 'requires-force') {\n lines.push(`Keybind: ${keybindResult.message}`, '');\n lines.push('Run `sis admin check-keybinds` to see options, then `sis admin setup --force`.', '');\n } else if (keybindResult.status === 'conf-modification-declined') {\n lines.push(keybindResult.message, '');\n }\n\n if (sisyphusPlugin.installed && sisyphusPlugin.autoInstalled) {\n lines.push(`Sisyphus plugin installed: sisyphus@sisyphus → ${sisyphusPlugin.installPath}`, '');\n } else if (!sisyphusPlugin.installed) {\n lines.push('Sisyphus plugin: failed to install (run `sis admin setup` to retry; needs `claude` CLI)', '');\n }\n\n lines.push(\n 'Run `sis admin getting-started` for a complete usage guide.',\n '',\n );\n\n console.log(lines.join('\\n'));\n}\n\nfunction testConnection(): Promise<void> {\n return new Promise((resolve, reject) => {\n const sock = connect(socketPath());\n sock.on('connect', () => { sock.destroy(); resolve(); });\n sock.on('error', (err) => { sock.destroy(); reject(err); });\n });\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\nexport async function waitForDaemon(maxWaitMs = 6000): Promise<void> {\n const start = Date.now();\n let updatingLogged = false;\n\n while (Date.now() - start < maxWaitMs) {\n // Extend timeout if daemon is updating\n const updatingPath = daemonUpdatingPath();\n if (existsSync(updatingPath)) {\n if (!updatingLogged) {\n try {\n const version = readFileSync(updatingPath, 'utf-8').trim();\n console.log(`Updating sisyphus to ${version}...`);\n } catch {\n console.log('Updating sisyphus...');\n }\n updatingLogged = true;\n }\n maxWaitMs = Math.max(maxWaitMs, 30000);\n }\n\n if (existsSync(socketPath())) {\n try {\n await testConnection();\n return;\n } catch {\n // not ready yet\n }\n }\n await sleep(300);\n }\n throw new Error(`Daemon did not start within ${maxWaitMs}ms. Check ${daemonLogPath()}`);\n}\n","import { execSync } from 'node:child_process';\nimport { existsSync, mkdirSync, readFileSync, writeFileSync, chmodSync, unlinkSync } from 'node:fs';\nimport { homedir } from 'node:os';\nimport { join } from 'node:path';\nimport { createInterface } from 'node:readline';\nimport { globalDir } from '../shared/paths.js';\nimport { KEYMAP, formatHelpForKeymap, type MenuDef, type MenuItem, type Action } from '../shared/keymap.js';\nimport { ensureSisyphusInitLua } from '../shared/sisyphus-init-lua.js';\n\nexport const DEFAULT_CYCLE_KEY = 'M-s';\nexport const DEFAULT_PREFIX_KEY = 'C-s';\nexport const KEY_TABLE = 'sisyphus';\n\nconst SISYPHUS_CONF_MARKER = '# sisyphus-managed — do not edit';\n\nfunction scriptPath(name: string): string {\n return join(globalDir(), 'bin', name);\n}\n\nexport function cycleScriptPath(): string {\n return scriptPath('sisyphus-cycle');\n}\n\nexport function homeScriptPath(): string {\n return scriptPath('sisyphus-home');\n}\n\nexport function killPaneScriptPath(): string {\n return scriptPath('sisyphus-kill-pane');\n}\n\nexport function newPromptScriptPath(): string {\n return scriptPath('sisyphus-new');\n}\n\nexport function messageScriptPath(): string {\n return scriptPath('sisyphus-msg');\n}\n\nexport function deleteSessionScriptPath(): string {\n return scriptPath('sisyphus-delete-session');\n}\n\nexport function killSessionScriptPath(): string {\n return scriptPath('sisyphus-kill-session');\n}\n\nexport function helpScriptPath(): string {\n return scriptPath('sisyphus-help');\n}\n\nexport function statusPopupScriptPath(): string {\n return scriptPath('sisyphus-status-popup');\n}\n\nexport function pickSessionScriptPath(): string {\n return scriptPath('sisyphus-pick-session');\n}\n\nexport function continueSessionScriptPath(): string {\n return scriptPath('sisyphus-continue-session');\n}\n\nexport function restartAgentScriptPath(): string {\n return scriptPath('sisyphus-restart-agent-popup');\n}\n\nexport function exportSessionScriptPath(): string {\n return scriptPath('sisyphus-export-session');\n}\n\nexport function openRoadmapScriptPath(): string {\n return scriptPath('sisyphus-open-roadmap');\n}\n\nexport function openStrategyScriptPath(): string {\n return scriptPath('sisyphus-open-strategy');\n}\n\nexport function keymapJsonPath(): string {\n return join(globalDir(), 'keymap.json');\n}\n\nexport function writeKeymapJson(): void {\n mkdirSync(globalDir(), { recursive: true });\n writeFileSync(keymapJsonPath(), JSON.stringify(KEYMAP, null, 2), 'utf8');\n}\n\nexport function tmuxVersionAtLeast(major: number, minor: number): boolean {\n try {\n const out = execSync('tmux -V', { stdio: ['pipe', 'pipe', 'pipe'] }).toString().trim();\n const match = out.match(/tmux\\s+(\\d+)\\.(\\d+)/);\n if (!match) return false;\n const v = parseInt(match[1], 10) * 1000 + parseInt(match[2], 10);\n return v >= major * 1000 + minor;\n } catch {\n return false;\n }\n}\n\nfunction menuItemCommand(action: Action, scriptsDir: string): string | null {\n switch (action.type) {\n case 'script':\n return `run-shell ${join(scriptsDir, action.name)}`;\n case 'popup': {\n const { w, h, borderStyle, title, cwd } = action.popup;\n let args = '-E';\n if (w) args += ` -w ${w}`;\n if (h) args += ` -h ${h}`;\n if (borderStyle) args += ` -S '${borderStyle}'`;\n if (title) args += ` -T '${title}'`;\n if (cwd === 'current') args += ` -d '#{pane_current_path}'`;\n return `display-popup ${args} ${join(scriptsDir, action.name)}`;\n }\n case 'submenu':\n return `run-shell ${join(scriptsDir, `sisyphus-menu-${action.ref}`)}`;\n case 'tmux':\n return action.cmd;\n case 'tui':\n return null;\n }\n}\n\nexport function generateMenuLine(item: MenuItem, scriptsDir: string): string {\n const cmd = menuItemCommand(item.action, scriptsDir);\n if (cmd === null) return '';\n const label = item.label.replace(/\"/g, '\\\\\"');\n return `\"${label}\" ${item.key} \"${cmd}\"`;\n}\n\nexport function generateSubmenuScript(submenuId: string, def: MenuDef, scriptsDir: string): string {\n const lines = def.items\n .map(item => generateMenuLine(item, scriptsDir))\n .filter(l => l !== '');\n const args = lines.join(' \\\\\\n ');\n return `#!/bin/bash\nexec tmux display-menu -T '${def.title}' -x R -y S \\\\\n ${args}\n`;\n}\n\nexport function generateTopLevelBinding(prefixKey: string, def: MenuDef, scriptsDir: string): string {\n const args = def.items\n .map(item => generateMenuLine(item, scriptsDir))\n .filter(l => l !== '')\n .join(' ');\n return `bind-key -T root ${prefixKey} display-menu -T '${def.title}' -x R -y S ${args}`;\n}\n\nexport function sisyphusTmuxConfPath(): string {\n return join(globalDir(), 'tmux.conf');\n}\n\nexport function userTmuxConfPath(): string | null {\n const dotfile = join(homedir(), '.tmux.conf');\n const xdg = join(homedir(), '.config', 'tmux', 'tmux.conf');\n if (existsSync(xdg)) return xdg;\n if (existsSync(dotfile)) return dotfile;\n return null;\n}\n\nconst CYCLE_SCRIPT = `#!/bin/bash\n# Target by $N session ID (column 5 in TSV) — tmux -t <name> can substring-match\n# the wrong session under sparse env.\nMANIFEST=\"$HOME/.sisyphus/sessions-manifest.tsv\"\nif [ ! -f \"$MANIFEST\" ]; then\n tmux display-message \"sisyphus: no manifest — daemon running?\"\n exit 0\nfi\ncurrent_id=$(tmux display-message -p '#{session_id}')\ncurrent_name=$(tmux display-message -p '#{session_name}')\ncwd=\"\"\nwhile IFS=$'\\\\t' read -r type name scwd phase sid; do\n [ \"$sid\" = \"$current_id\" ] && { cwd=\"$scwd\"; break; }\ndone < \"$MANIFEST\"\nif [ -z \"$cwd\" ]; then\n tmux display-message \"sisyphus: '$current_name' has no @sisyphus_cwd — run 'sis start' here to register\"\n exit 0\nfi\nsession_ids=()\nwhile IFS=$'\\\\t' read -r type name scwd phase sid; do\n [[ \"$type\" == \"#\"* ]] && continue\n [ \"$scwd\" = \"$cwd\" ] && session_ids+=(\"$sid\")\ndone < \"$MANIFEST\"\nif (( \\${#session_ids[@]} <= 1 )); then\n tmux display-message \"sisyphus: only one session in $cwd — nothing to cycle to\"\n exit 0\nfi\nfor (( i=0; i<\\${#session_ids[@]}; i++ )); do\n if [ \"\\${session_ids[$i]}\" = \"$current_id\" ]; then\n next=$(( (i + 1) % \\${#session_ids[@]} ))\n tmux switch-client -t \"\\${session_ids[$next]}\"\n exit 0\n fi\ndone\ntmux switch-client -t \"\\${session_ids[0]}\"\n`;\n\n// Live tmux query for the home session + its dashboard window ID.\n// Sets HOME_SESSION and HOME_DWID. Returns 0 on success, 1 if no home found.\n// Optional arg: explicit cwd to look up. If omitted, uses @sisyphus_cwd from\n// the current tmux session, falling back to #{pane_current_path}.\n// Sets HOME_SESSION (tmux $N id) and HOME_DWID for the non-ssyph_ session\n// matching the given cwd. Always targets by $N — tmux -t <name> can\n// substring-match under sparse env.\nconst RESOLVE_HOME = `\nHOME_SESSION=\"\"\nHOME_DWID=\"\"\nresolve_home() {\n local target_cwd=\"$1\"\n local current_id sid sname scwd\n if [ -z \"$target_cwd\" ]; then\n current_id=$(tmux display-message -p '#{session_id}')\n target_cwd=$(tmux show-options -t \"$current_id\" -v @sisyphus_cwd 2>/dev/null)\n [ -z \"$target_cwd\" ] && target_cwd=$(tmux display-message -p '#{pane_current_path}')\n fi\n target_cwd=\"\\${target_cwd%/}\"\n [ -z \"$target_cwd\" ] && return 1\n while IFS=$'\\\\t' read -r sid sname; do\n [ -z \"$sid\" ] && continue\n case \"$sname\" in ssyph_*) continue ;; esac\n scwd=$(tmux show-options -t \"$sid\" -v @sisyphus_cwd 2>/dev/null)\n scwd=\"\\${scwd%/}\"\n if [ \"$scwd\" = \"$target_cwd\" ]; then\n HOME_SESSION=\"$sid\"\n HOME_DWID=$(tmux show-options -t \"$sid\" -v @sisyphus_dashboard 2>/dev/null)\n return 0\n fi\n done < <(tmux list-sessions -F '#{session_id}\t#{session_name}')\n return 1\n}`.trim();\n\nfunction homeScript(): string {\n const tuiPath = join(import.meta.dirname, 'tui.js');\n return `#!/bin/bash\n# Jump to the dashboard window for the home session matching this cwd.\n${RESOLVE_HOME}\nif ! resolve_home; then\n tmux display-message \"No sisyphus dashboard for this cwd\"\n exit 0\nfi\n# Validate dashboard window is still alive; clear if stale\nif [ -n \"$HOME_DWID\" ] && ! tmux list-panes -t \"$HOME_DWID\" >/dev/null 2>&1; then\n HOME_DWID=\"\"\nfi\n# Reconcile: if option is unset/stale, scan home session for an existing TUI window\n# (pane running 'node'). This prevents duplicate dashboards when the option drifts.\nif [ -z \"$HOME_DWID\" ]; then\n HOME_DWID=$(tmux list-windows -t \"$HOME_SESSION\" -F '#{window_id} #{pane_current_command}' 2>/dev/null \\\n | awk '$2==\"node\"{print $1; exit}')\n [ -n \"$HOME_DWID\" ] && tmux set-option -t \"$HOME_SESSION\" @sisyphus_dashboard \"$HOME_DWID\"\nfi\nif [ -z \"$HOME_DWID\" ]; then\n # Reopen dashboard: create window, launch TUI, update option\n home_cwd=$(tmux show-options -t \"$HOME_SESSION\" -v @sisyphus_cwd 2>/dev/null)\n [ -z \"$home_cwd\" ] && { tmux display-message \"Home session has no cwd\"; exit 0; }\n HOME_DWID=$(tmux new-window -t \"$HOME_SESSION:\" -n \"sisyphus-dashboard\" -c \"$home_cwd\" -P -F \"#{window_id}\")\n tmux send-keys -t \"$HOME_DWID\" \"node '${tuiPath}' --cwd '$home_cwd'; exit\" Enter\n tmux set-option -t \"$HOME_SESSION\" @sisyphus_dashboard \"$HOME_DWID\"\nfi\ncurrent_id=$(tmux display-message -p '#{session_id}')\n[ \"$current_id\" != \"$HOME_SESSION\" ] && tmux switch-client -t \"$HOME_SESSION\"\ntmux select-window -t \"$HOME_DWID\"\n`;\n}\n\nconst KILL_PANE_SCRIPT = `#!/bin/bash\n# Smart kill-pane invoked via the sisyphus prefix menu (C-s x).\n# If this is the last pane, switch to the home session before killing.\n${RESOLVE_HOME}\nsession_id=$(tmux display-message -p '#{session_id}')\npane_count=$(tmux list-panes -t \"$session_id\" -F '#{pane_id}' | wc -l | tr -d ' ')\n\nif [ \"$pane_count\" -le 1 ]; then\n if resolve_home; then\n tmux switch-client -t \"$HOME_SESSION\"\n [ -n \"$HOME_DWID\" ] && tmux select-window -t \"$HOME_DWID\"\n tmux kill-session -t \"$session_id\"\n exit 0\n fi\n tmux kill-pane\nelse\n tmux kill-pane\n tmux select-layout even-horizontal\nfi\n`;\n\nconst NEW_PROMPT_SCRIPT = `#!/bin/bash\n# Open nvim to compose a new sisyphus task, then start a session\ntmpfile=$(mktemp /tmp/sisyphus-new.XXXXXX)\ntrap 'rm -f \"$tmpfile\"' EXIT\nNVIM_APPNAME=sisyphus nvim \"$tmpfile\"\ngrep -q '[^[:space:]]' \"$tmpfile\" || exit 0\nexec sis start \"$(cat \"$tmpfile\")\"\n`;\n\nconst MESSAGE_SCRIPT = `#!/bin/bash\n# Open nvim to compose a message for the current session's orchestrator\n# Resolve session ID: direct tmux option → manifest lookup.\n# All -t targeting uses $N session id — tmux -t <name> can substring-match under sparse env.\ntmux_sid=$(tmux display-message -p '#{session_id}')\nsession_id=$(tmux show-options -t \"$tmux_sid\" -v @sisyphus_session_id 2>/dev/null)\n\nif [ -z \"$session_id\" ]; then\n MANIFEST=\"$HOME/.sisyphus/sessions-manifest.tsv\"\n [ ! -f \"$MANIFEST\" ] && { echo \"No active sessions found\"; sleep 1; exit 1; }\n cwd=\"\"\n while IFS=$'\\\\t' read -r type name scwd phase sid; do\n [ \"$sid\" = \"$tmux_sid\" ] && { cwd=\"$scwd\"; break; }\n done < \"$MANIFEST\"\n [ -z \"$cwd\" ] && { echo \"Session not in manifest\"; sleep 1; exit 1; }\n while IFS=$'\\\\t' read -r type name scwd phase sid; do\n if [ \"$type\" = \"S\" ] && [ \"$scwd\" = \"$cwd\" ]; then\n session_id=$(tmux show-options -t \"$sid\" -v @sisyphus_session_id 2>/dev/null)\n [ -n \"$session_id\" ] && break\n fi\n done < \"$MANIFEST\"\nfi\n\n[ -z \"$session_id\" ] && { echo \"No active sisyphus session found\"; sleep 1; exit 1; }\n\ntmpfile=$(mktemp /tmp/sisyphus-msg.XXXXXX)\ntrap 'rm -f \"$tmpfile\"' EXIT\nNVIM_APPNAME=sisyphus nvim \"$tmpfile\"\ngrep -q '[^[:space:]]' \"$tmpfile\" || exit 0\nexec sis message --session \"$session_id\" \"$(cat \"$tmpfile\")\"\n`;\n\n// --- Shared session ID + cwd resolution for session-scoped scripts ---\n// All tmux -t targeting uses $N session id — -t <name> can substring-match under sparse env.\nconst SESSION_RESOLVE = `\ntmux_sid=$(tmux display-message -p '#{session_id}')\nsession_id=$(tmux show-options -t \"$tmux_sid\" -v @sisyphus_session_id 2>/dev/null)\ncwd=$(tmux show-options -t \"$tmux_sid\" -v @sisyphus_cwd 2>/dev/null)\n\nif [ -z \"$session_id\" ]; then\n MANIFEST=\"$HOME/.sisyphus/sessions-manifest.tsv\"\n [ ! -f \"$MANIFEST\" ] && { echo \"No active sessions found\"; sleep 1; exit 1; }\n if [ -z \"$cwd\" ]; then\n while IFS=$'\\\\t' read -r type name scwd phase sid; do\n [ \"$sid\" = \"$tmux_sid\" ] && { cwd=\"$scwd\"; break; }\n done < \"$MANIFEST\"\n fi\n [ -z \"$cwd\" ] && { echo \"Session not in manifest\"; sleep 1; exit 1; }\n while IFS=$'\\\\t' read -r type name scwd phase sid; do\n if [ \"$type\" = \"S\" ] && [ \"$scwd\" = \"$cwd\" ]; then\n session_id=$(tmux show-options -t \"$sid\" -v @sisyphus_session_id 2>/dev/null)\n [ -n \"$session_id\" ] && break\n fi\n done < \"$MANIFEST\"\nfi\n\n[ -z \"$session_id\" ] && { echo \"No active sisyphus session found\"; sleep 1; exit 1; }\n[ -z \"$cwd\" ] && cwd=$(tmux display-message -p '#{pane_current_path}')`.trim();\n\n// --- Go-home helper used by kill/delete scripts ---\n// Assumes $cwd was captured before the destructive action ran (via SESSION_RESOLVE).\nconst GO_HOME_AFTER = `\n${RESOLVE_HOME}\nif resolve_home \"$cwd\"; then\n tmux switch-client -t \"$HOME_SESSION\"\n [ -n \"$HOME_DWID\" ] && tmux select-window -t \"$HOME_DWID\"\nfi`.trim();\n\nconst KILL_SESSION_SCRIPT = `#!/bin/bash\n# Kill the sisyphus session associated with the current tmux session\n${SESSION_RESOLVE}\n\nsis session kill \"$session_id\" >/dev/null 2>&1\n${GO_HOME_AFTER}\n`;\n\nconst DELETE_SESSION_SCRIPT = `#!/bin/bash\n# Delete the sisyphus session associated with the current tmux session\n${SESSION_RESOLVE}\n\nprintf \"\\\\033[31mType 'yes' to confirm:\\\\033[0m \"\nread -r answer\n[ \"$answer\" = \"yes\" ] || exit 0\nsis session delete \"$session_id\" --cwd \"$cwd\" >/dev/null 2>&1\n${GO_HOME_AFTER}\n`;\n\nconst HELP_SCRIPT = `#!/bin/bash\ncat <<'EOF_HELP'\n${formatHelpForKeymap(KEYMAP)}\nEOF_HELP\nread -n 1 -s -r -p \" Press any key to close\"\n`;\n\n// Open/focus the side companion claude pane. Re-runs are idempotent — the CLI\n// looks for an existing pane with @sisyphus_companion set to this cwd via\n// tmux pane options, so a previously closed pane never leaves stale state.\nconst COMPANION_PANE_SCRIPT = `#!/bin/bash\ntmux_sid=$(tmux display-message -p '#{session_id}')\ncwd=$(tmux show-options -t \"$tmux_sid\" -v @sisyphus_cwd 2>/dev/null)\n[ -z \"$cwd\" ] && cwd=$(tmux display-message -p '#{pane_current_path}')\nexec sis companion pane --cwd \"$cwd\"\n`;\n\nconst STATUS_POPUP_SCRIPT = `#!/bin/bash\n# Show session status — if no sisyphus session here, list all.\n# -t targeting uses $N session id — -t <name> can substring-match under sparse env.\ntmux_sid=$(tmux display-message -p '#{session_id}')\nsession_id=$(tmux show-options -t \"$tmux_sid\" -v @sisyphus_session_id 2>/dev/null)\n\nif [ -z \"$session_id\" ]; then\n MANIFEST=\"$HOME/.sisyphus/sessions-manifest.tsv\"\n if [ -f \"$MANIFEST\" ]; then\n cwd=\"\"\n while IFS=$'\\\\t' read -r type name scwd phase sid; do\n [ \"$sid\" = \"$tmux_sid\" ] && { cwd=\"$scwd\"; break; }\n done < \"$MANIFEST\"\n if [ -n \"$cwd\" ]; then\n while IFS=$'\\\\t' read -r type name scwd phase sid; do\n if [ \"$type\" = \"S\" ] && [ \"$scwd\" = \"$cwd\" ]; then\n session_id=$(tmux show-options -t \"$sid\" -v @sisyphus_session_id 2>/dev/null)\n [ -n \"$session_id\" ] && break\n fi\n done < \"$MANIFEST\"\n fi\n fi\nfi\n\nif [ -n \"$session_id\" ]; then\n sis status \"$session_id\" 2>&1 | less -R\nelse\n sis list 2>&1 | less -R\nfi\n`;\n\nconst PICK_SESSION_SCRIPT = `#!/bin/bash\n# Session picker — switch to a sisyphus session.\n# switch-client -t targets $N session id — -t <name> can substring-match under sparse env.\nMANIFEST=\"$HOME/.sisyphus/sessions-manifest.tsv\"\n[ ! -f \"$MANIFEST\" ] && { echo \"No sessions found\"; sleep 1; exit 0; }\n\ncurrent_id=$(tmux display-message -p '#{session_id}')\ncwd=\"\"\nwhile IFS=$'\\\\t' read -r type name scwd phase sid; do\n [ \"$sid\" = \"$current_id\" ] && { cwd=\"$scwd\"; break; }\ndone < \"$MANIFEST\"\n\ndeclare -a entries=()\ndeclare -a targets=()\nwhile IFS=$'\\\\t' read -r type name scwd phase sid; do\n [[ \"$type\" == \"#\"* ]] && continue\n [ -n \"$cwd\" ] && [ \"$scwd\" != \"$cwd\" ] && continue\n display=\"$name\"\n if [[ \"$name\" == ssyph_* ]]; then\n display=\"\\${name#ssyph_}\"\n display=\"\\${display#*_}\"\n fi\n [ \"$type\" = \"H\" ] && display=\"~ home\"\n marker=\"\"\n [ \"$sid\" = \"$current_id\" ] && marker=\" *\"\n phase_label=\"\\${phase:-—}\"\n entries+=(\"\\${display} [\\${phase_label}]\\${marker}\")\n targets+=(\"$sid\")\ndone < \"$MANIFEST\"\n\n(( \\${#entries[@]} == 0 )) && { echo \"No sessions found\"; sleep 1; exit 0; }\n\nif command -v fzf &>/dev/null; then\n idx=$(for (( i=0; i<\\${#entries[@]}; i++ )); do echo \"$i \\${entries[$i]}\"; done | \\\\\n fzf --height=100% --reverse --with-nth=2.. --prompt=\"Switch to: \" | awk '{print $1}')\n [ -z \"$idx\" ] && exit 0\n tmux switch-client -t \"\\${targets[$idx]}\"\nelse\n for (( i=0; i<\\${#entries[@]}; i++ )); do\n printf \" %d) %s\\\\n\" $((i+1)) \"\\${entries[$i]}\"\n done\n printf \"\\\\nPick session: \"\n read -r choice\n idx=$((choice - 1))\n (( idx >= 0 && idx < \\${#entries[@]} )) || exit 0\n tmux switch-client -t \"\\${targets[$idx]}\"\nfi\n`;\n\nconst CONTINUE_SESSION_SCRIPT = `#!/bin/bash\n# Continue a completed session\n${SESSION_RESOLVE}\n\nshort_id=\"\\${session_id:0:8}\"\nprintf \"\\\\033[33mContinue session %s...?\\\\033[0m (y/n) \" \"$short_id\"\nread -r answer\n[ \"$answer\" = \"y\" ] || [ \"$answer\" = \"yes\" ] || exit 0\nsis session continue --session \"$session_id\"\nsleep 1\n`;\n\nconst OPEN_ROADMAP_SCRIPT = `#!/bin/bash\n# Open roadmap.md for the current session in nvim\n${SESSION_RESOLVE}\n\nfile=\"$cwd/.sisyphus/sessions/$session_id/roadmap.md\"\n[ ! -f \"$file\" ] && { tmux display-message \"No roadmap.md for this session\"; exit 0; }\nexec nvim \"$file\"\n`;\n\nconst OPEN_STRATEGY_SCRIPT = `#!/bin/bash\n# Open strategy.md for the current session in nvim\n${SESSION_RESOLVE}\n\nfile=\"$cwd/.sisyphus/sessions/$session_id/strategy.md\"\n[ ! -f \"$file\" ] && { tmux display-message \"No strategy.md for this session\"; exit 0; }\nexec nvim \"$file\"\n`;\n\nconst EXPORT_SESSION_SCRIPT = `#!/bin/bash\n# Export session data as zip to ~/Downloads\n${SESSION_RESOLVE}\n\necho \"Exporting session \\${session_id:0:8}...\"\nsis admin export \"$session_id\" --cwd \"$cwd\"\necho \"\"\nread -n 1 -s -r -p \"Press a key to close.\"\n`;\n\nconst RESTART_AGENT_SCRIPT = `#!/bin/bash\n# Pick a sisyphus agent and restart it (fzf picker with confirm for running agents).\n# Assumes macOS (fzf optional). Requires \\`sis status --json\\`.\n${SESSION_RESOLVE}\n\ncommand -v jq &>/dev/null || { echo \"jq required\"; sleep 1; exit 1; }\n\nagents_json=$(sis status \"$session_id\" --json 2>/dev/null)\nif [ -z \"$agents_json\" ]; then\n echo \"Failed to read session status\"; sleep 1; exit 1\nfi\n\ndeclare -a entries=()\ndeclare -a ids=()\ndeclare -a statuses=()\nwhile IFS=$'\\\\t' read -r aid aname atype astatus; do\n [ -z \"$aid\" ] && continue\n entries+=(\"$aid $aname ($atype) — $astatus\")\n ids+=(\"$aid\")\n statuses+=(\"$astatus\")\ndone < <(echo \"$agents_json\" | jq -r '.agents[] | [.id, .name, .agentType, .status] | @tsv')\n\n(( \\${#entries[@]} == 0 )) && { echo \"No agents in session\"; sleep 1; exit 0; }\n\nif command -v fzf &>/dev/null; then\n idx=$(for (( i=0; i<\\${#entries[@]}; i++ )); do echo \"$i \\${entries[$i]}\"; done \\\\\n | fzf --reverse --height=100% --with-nth=2.. --prompt=\"Restart: \" | awk '{print $1}')\n [ -z \"$idx\" ] && exit 0\nelse\n for (( i=0; i<\\${#entries[@]}; i++ )); do\n printf \" %d) %s\\\\n\" $((i+1)) \"\\${entries[$i]}\"\n done\n printf \"\\\\nPick agent: \"\n read -r choice\n idx=$((choice - 1))\n (( idx >= 0 && idx < \\${#entries[@]} )) || exit 0\nfi\n\nif [ \"\\${statuses[$idx]}\" = \"running\" ]; then\n printf \"\\\\033[33mAgent is running. Restart anyway? (yes/no): \\\\033[0m\"\n read -r answer\n [ \"$answer\" = \"yes\" ] || exit 0\nfi\n\nsis agent restart \"\\${ids[$idx]}\" --session \"$session_id\"\necho \"\"\nread -n 1 -s -r -p \"Press a key to close.\"\n`;\n\n// === Stage 2 script constants ===\n\nconst OPEN_GOAL_SCRIPT = `#!/bin/bash\n# Open goal.md for the current session in nvim.\n# Run from a sisyphus session pane, not the home dashboard.\n${SESSION_RESOLVE}\n\nfile=\"$cwd/.sisyphus/sessions/$session_id/goal.md\"\n[ ! -f \"$file\" ] && { tmux display-message \"No goal.md for this session\"; exit 0; }\nexec nvim \"$file\"\n`;\n\nconst OPEN_DIR_SCRIPT = `#!/bin/bash\n# Open session dir in Finder (macOS).\n# macOS-only — Linux/Windows port deferred.\n# Run from a sisyphus session pane, not the home dashboard.\n${SESSION_RESOLVE}\n\ndir=\"$cwd/.sisyphus/sessions/$session_id\"\n[ ! -d \"$dir\" ] && { tmux display-message \"Session dir not found: $dir\"; exit 0; }\nexec open \"$dir\"\n`;\n\nconst OPEN_LOGS_SCRIPT = `#!/bin/bash\n# Tail the newest cycle log for this session in a popup.\n# Run from a sisyphus session pane, not the home dashboard.\n${SESSION_RESOLVE}\n\nsession_dir=\"$cwd/.sisyphus/sessions/$session_id\"\ntarget=$(ls -t \"$session_dir/logs/\"cycle-*.md 2>/dev/null | head -1)\n[ -z \"$target\" ] && { tmux display-message \"No logs for this session yet\"; exit 0; }\nexec tail -n 500 -f \"$target\"\n`;\n\nconst RESUME_SESSION_SCRIPT = `#!/bin/bash\n# Resume a paused/completed session with optional follow-up instructions.\n# Run from a sisyphus session pane, not the home dashboard.\n${SESSION_RESOLVE}\n\nshort_id=\"\\${session_id:0:8}\"\n\n# Optional message — leave empty to resume with no extra instructions.\ntmpfile=$(mktemp /tmp/sisyphus-resume.XXXXXX)\ntrap 'rm -f \"$tmpfile\"' EXIT\nprintf \"# Resume session %s\\\\n# (Optional) Add follow-up instructions for the orchestrator below.\\\\n# Save & quit empty to resume with no message.\\\\n\\\\n\" \"$short_id\" > \"$tmpfile\"\nNVIM_APPNAME=sisyphus nvim \"$tmpfile\"\n\n# Strip comment + blank lines to detect empty submission\nbody=$(grep -v '^[[:space:]]*#' \"$tmpfile\" | sed '/^[[:space:]]*$/d')\n\nif [ -z \"$body\" ]; then\n exec sis session resume \"$session_id\"\nelse\n exec sis session resume \"$session_id\" \"$body\"\nfi\n`;\n\nconst ROLLBACK_SESSION_SCRIPT = `#!/bin/bash\n# Roll back session to a chosen cycle. Prompts inline.\n# Run from a sisyphus session pane, not the home dashboard.\n${SESSION_RESOLVE}\n\nshort_id=\"\\${session_id:0:8}\"\nprintf \"Rollback %s to cycle: \" \"$short_id\"\nread -r cycle_input\n\n# Validate: positive integer\ncase \"$cycle_input\" in\n ''|*[!0-9]*)\n echo \"Invalid cycle number\"\n read -n 1 -s -r -p \"Press a key to close.\"\n exit 0\n ;;\nesac\n\nif [ \"$cycle_input\" -lt 1 ]; then\n echo \"Cycle must be >= 1\"\n read -n 1 -s -r -p \"Press a key to close.\"\n exit 0\nfi\n\nsis session rollback \"$session_id\" \"$cycle_input\"\necho \"\"\necho \"Rolled back to cycle $cycle_input — use [C-s S r] to resume.\"\nread -n 1 -s -r -p \"Press a key to close.\"\n`;\n\nconst GO_TO_WINDOW_SCRIPT = `#!/bin/bash\n# Switch to the sisyphus session's tmux window. If the window is dead,\n# fall back to opening the orchestrator's last claude --resume in a popup.\n# Run from a sisyphus session pane, not the home dashboard.\n${SESSION_RESOLVE}\n\ncommand -v jq &>/dev/null || { echo \"jq required\"; sleep 1; exit 1; }\n\n# Walk the manifest for the S-row whose tmux session has @sisyphus_session_id == ours.\n# Manifest format: type\\tname\\tcwd\\tphase\\tsessionId\nMANIFEST=\"$HOME/.sisyphus/sessions-manifest.tsv\"\n[ ! -f \"$MANIFEST\" ] && { tmux display-message \"No manifest\"; exit 0; }\n\ntarget_sid=\"\"\nwhile IFS=$'\\\\t' read -r type name scwd phase sid; do\n [[ \"$type\" == \"#\"* ]] && continue\n [ \"$type\" = \"S\" ] || continue\n [ \"$scwd\" = \"$cwd\" ] || continue\n ssid=$(tmux show-options -t \"$sid\" -v @sisyphus_session_id 2>/dev/null)\n if [ \"$ssid\" = \"$session_id\" ]; then\n target_sid=\"$sid\"\n break\n fi\ndone < \"$MANIFEST\"\n\nif [ -n \"$target_sid\" ] && tmux has-session -t \"$target_sid\" 2>/dev/null; then\n tmux switch-client -t \"$target_sid\"\n exit 0\nfi\n\n# Fallback: orchestrator window is gone. Open last claude session in a popup.\nstate=\"$cwd/.sisyphus/sessions/$session_id/state.json\"\n[ ! -f \"$state\" ] && { tmux display-message \"Window dead and no state.json — try sis session resume\"; exit 0; }\n\nclaude_sid=$(jq -r '[.orchestratorCycles[].claudeSessionId] | last // empty' \"$state\")\n\nif [ -z \"$claude_sid\" ]; then\n tmux display-message \"No orchestrator claude session id found — try sis session resume\"\n exit 0\nfi\n\n# Validate before passing to exec — value must be a safe session id.\n[[ \"$claude_sid\" =~ ^[A-Za-z0-9_-]+$ ]] || { tmux display-message \"Invalid claude session id\"; exit 1; }\n\nexec claude --resume \"$claude_sid\"\n`;\n\nconst SPAWN_AGENT_SCRIPT = `#!/bin/bash\n# Compose an instruction for a new agent and spawn it.\n# Run from a sisyphus session pane, not the home dashboard.\n${SESSION_RESOLVE}\n\ntmpfile=$(mktemp /tmp/sisyphus-spawn.XXXXXX)\ntrap 'rm -f \"$tmpfile\"' EXIT\nprintf \"# Spawn agent in session %s\\\\n# Write the agent's instruction below. Empty = abort.\\\\n\\\\n\" \"\\${session_id:0:8}\" > \"$tmpfile\"\nNVIM_APPNAME=sisyphus nvim \"$tmpfile\"\n\nbody=$(grep -v '^[[:space:]]*#' \"$tmpfile\" | sed '/^[[:space:]]*$/d')\n[ -z \"$body\" ] && exit 0\n\nexec sis agent spawn --session \"$session_id\" --name \"agent\" --instruction \"$body\"\n`;\n\nconst SEARCH_REPORTS_SCRIPT = `#!/bin/bash\n# fzf over reports/*.md across all sessions for the current cwd.\n# Falls back to numbered list if fzf is missing.\n\n# Resolve cwd via tmux option (set by daemon) or fall back.\ntmux_sid=$(tmux display-message -p '#{session_id}')\ncwd=$(tmux show-options -t \"$tmux_sid\" -v @sisyphus_cwd 2>/dev/null)\n[ -z \"$cwd\" ] && cwd=$(tmux display-message -p '#{pane_current_path}')\n\nsessions_dir=\"$cwd/.sisyphus/sessions\"\n[ ! -d \"$sessions_dir\" ] && { tmux display-message \"No sessions in $cwd\"; exit 0; }\n\n# Find all report files. -path filter scopes to */reports/*.md inside any session.\nmapfile -t files < <(find \"$sessions_dir\" -type f -path '*/reports/*.md' 2>/dev/null | sort)\n(( \\${#files[@]} == 0 )) && { tmux display-message \"No reports yet in $cwd\"; exit 0; }\n\nif command -v fzf &>/dev/null; then\n picked=$(printf '%s\\\\n' \"\\${files[@]}\" \\\\\n | sed \"s|$sessions_dir/||\" \\\\\n | fzf --reverse --height=100% --prompt=\"Report: \" \\\\\n --preview 'f={}; cat -- \"'\"$sessions_dir\"'/$f\"' --preview-window=right:60%)\n [ -z \"$picked\" ] && exit 0\n exec nvim \"$sessions_dir/$picked\"\nelse\n for (( i=0; i<\\${#files[@]}; i++ )); do\n rel=\"\\${files[$i]#$sessions_dir/}\"\n printf \" %d) %s\\\\n\" $((i+1)) \"\\${rel}\"\n done\n printf \"\\\\nPick: \"\n read -r choice\n idx=$((choice - 1))\n (( idx >= 0 && idx < \\${#files[@]} )) || exit 0\n exec nvim \"\\${files[$idx]}\"\nfi\n`;\n\n// === end Stage 2 script constants ===\n\n// === Stage 3 script constants ===\n\nconst JUMP_TO_PANE_SCRIPT = `#!/bin/bash\n# Pick a sisyphus agent and jump to its tmux pane.\n# Assumes macOS (pbcopy, fzf optional). Requires \\`sis status --json\\`.\n${SESSION_RESOLVE}\n\ncommand -v jq &>/dev/null || { echo \"jq required\"; sleep 1; exit 1; }\n\nagents_json=$(sis status \"$session_id\" --json 2>/dev/null)\nif [ -z \"$agents_json\" ]; then\n echo \"Failed to read session status\"; sleep 1; exit 1\nfi\n\ndeclare -a entries=()\ndeclare -a ids=()\ndeclare -a panes=()\nwhile IFS=$'\\\\t' read -r aid aname atype astatus pid; do\n [ -z \"$aid\" ] && continue\n entries+=(\"$aid $aname ($atype) — $astatus\")\n ids+=(\"$aid\")\n panes+=(\"$pid\")\ndone < <(echo \"$agents_json\" | jq -r '.agents[] | [.id, .name, .agentType, .status, .paneId] | @tsv')\n\n(( \\${#entries[@]} == 0 )) && { echo \"No agents in session\"; sleep 1; exit 0; }\n\nif command -v fzf &>/dev/null; then\n idx=$(for (( i=0; i<\\${#entries[@]}; i++ )); do echo \"$i \\${entries[$i]}\"; done \\\\\n | fzf --reverse --height=100% --with-nth=2.. --prompt=\"Jump to: \" | awk '{print $1}')\n [ -z \"$idx\" ] && exit 0\nelse\n for (( i=0; i<\\${#entries[@]}; i++ )); do\n printf \" %d) %s\\\\n\" $((i+1)) \"\\${entries[$i]}\"\n done\n printf \"\\\\nPick agent: \"\n read -r choice\n idx=$((choice - 1))\n (( idx >= 0 && idx < \\${#entries[@]} )) || exit 0\nfi\n\ntarget_pane=\"\\${panes[$idx]}\"\n[ -z \"$target_pane\" ] && { echo \"Agent has no active pane\"; sleep 1; exit 1; }\ntarget_session=$(tmux display-message -p -t \"$target_pane\" '#{session_id}' 2>/dev/null)\ntarget_window=$(tmux display-message -p -t \"$target_pane\" '#{window_id}' 2>/dev/null)\n[ -n \"$target_session\" ] && tmux switch-client -t \"$target_session\"\n[ -n \"$target_window\" ] && tmux select-window -t \"$target_window\"\ntmux select-pane -t \"$target_pane\"\n`;\n\nconst MSG_AGENT_SCRIPT = `#!/bin/bash\n# Pick a sisyphus agent and send it a message via nvim.\n# Assumes macOS (fzf optional). Requires \\`sis status --json\\` and \\`--agent\\` on message.\n${SESSION_RESOLVE}\n\ncommand -v jq &>/dev/null || { echo \"jq required\"; sleep 1; exit 1; }\n\nagents_json=$(sis status \"$session_id\" --json 2>/dev/null)\nif [ -z \"$agents_json\" ]; then\n echo \"Failed to read session status\"; sleep 1; exit 1\nfi\n\ndeclare -a entries=()\ndeclare -a ids=()\nwhile IFS=$'\\\\t' read -r aid aname atype astatus; do\n [ -z \"$aid\" ] && continue\n entries+=(\"$aid $aname ($atype) — $astatus\")\n ids+=(\"$aid\")\ndone < <(echo \"$agents_json\" | jq -r '.agents[] | [.id, .name, .agentType, .status] | @tsv')\n\n(( \\${#entries[@]} == 0 )) && { echo \"No agents in session\"; sleep 1; exit 0; }\n\nif command -v fzf &>/dev/null; then\n idx=$(for (( i=0; i<\\${#entries[@]}; i++ )); do echo \"$i \\${entries[$i]}\"; done \\\\\n | fzf --reverse --height=100% --with-nth=2.. --prompt=\"Message agent: \" | awk '{print $1}')\n [ -z \"$idx\" ] && exit 0\nelse\n for (( i=0; i<\\${#entries[@]}; i++ )); do\n printf \" %d) %s\\\\n\" $((i+1)) \"\\${entries[$i]}\"\n done\n printf \"\\\\nPick agent: \"\n read -r choice\n idx=$((choice - 1))\n (( idx >= 0 && idx < \\${#entries[@]} )) || exit 0\nfi\n\ntmpfile=$(mktemp /tmp/sisyphus-msg-agent.XXXXXX)\ntrap 'rm -f \"$tmpfile\"' EXIT\nNVIM_APPNAME=sisyphus nvim \"$tmpfile\"\ngrep -q '[^[:space:]]' \"$tmpfile\" || exit 0\nexec sis message --session \"$session_id\" --agent \"\\${ids[$idx]}\" \"$(cat \"$tmpfile\")\"\n`;\n\nconst RERUN_AGENT_SCRIPT = `#!/bin/bash\n# Pick a sisyphus agent and spawn a retry with its original instruction.\n# Assumes macOS (fzf optional). Requires \\`sis status --json\\`.\n${SESSION_RESOLVE}\n\ncommand -v jq &>/dev/null || { echo \"jq required\"; sleep 1; exit 1; }\n\nagents_json=$(sis status \"$session_id\" --json 2>/dev/null)\nif [ -z \"$agents_json\" ]; then\n echo \"Failed to read session status\"; sleep 1; exit 1\nfi\n\ndeclare -a entries=()\ndeclare -a ids=()\ndeclare -a atypes=()\ndeclare -a anames=()\ndeclare -a instrs=()\nwhile IFS=$'\\\\t' read -r aid aname atype astatus ainstr_b64; do\n [ -z \"$aid\" ] && continue\n entries+=(\"$aid $aname ($atype) — $astatus\")\n ids+=(\"$aid\")\n atypes+=(\"$atype\")\n anames+=(\"$aname\")\n instrs+=(\"$(echo \"$ainstr_b64\" | base64 -d)\")\ndone < <(echo \"$agents_json\" | jq -r '.agents[] | [.id, .name, .agentType, .status, (.instruction // \"\" | @base64)] | @tsv')\n\n(( \\${#entries[@]} == 0 )) && { echo \"No agents in session\"; sleep 1; exit 0; }\n\nif command -v fzf &>/dev/null; then\n idx=$(for (( i=0; i<\\${#entries[@]}; i++ )); do echo \"$i \\${entries[$i]}\"; done \\\\\n | fzf --reverse --height=100% --with-nth=2.. --prompt=\"Rerun: \" | awk '{print $1}')\n [ -z \"$idx\" ] && exit 0\nelse\n for (( i=0; i<\\${#entries[@]}; i++ )); do\n printf \" %d) %s\\\\n\" $((i+1)) \"\\${entries[$i]}\"\n done\n printf \"\\\\nPick agent: \"\n read -r choice\n idx=$((choice - 1))\n (( idx >= 0 && idx < \\${#entries[@]} )) || exit 0\nfi\n\ninstr=\"\\${instrs[$idx]}\"\nif [ \"\\${#instr}\" -lt 20 ]; then\n echo \"Original instruction is shorter than 20 chars — cannot rerun safely.\"\n read -n 1 -s -r -p \"Press a key to close.\"\n exit 1\nfi\n\nexec sis agent spawn --session \"$session_id\" --agent-type \"\\${atypes[$idx]}\" --name \"\\${anames[$idx]}-retry-$(date +%s)\" --instruction \"$instr\"\n`;\n\nconst OPEN_CLAUDE_AGENT_SCRIPT = `#!/bin/bash\n# Pick a sisyphus agent or orchestrator cycle and resume its Claude session.\n# Assumes macOS (fzf optional). Requires \\`sis status --json\\`.\n${SESSION_RESOLVE}\n\ncommand -v jq &>/dev/null || { echo \"jq required\"; sleep 1; exit 1; }\n\nstate=\"$cwd/.sisyphus/sessions/$session_id/state.json\"\n[ ! -f \"$state\" ] && { echo \"No state.json for this session\"; sleep 1; exit 1; }\n\nagents_json=$(sis status \"$session_id\" --json 2>/dev/null)\nif [ -z \"$agents_json\" ]; then\n echo \"Failed to read session status\"; sleep 1; exit 1\nfi\n\ndeclare -a entries=()\ndeclare -a claudes=()\nwhile IFS=$'\\\\t' read -r rid rname rtype rcid; do\n [ -z \"$rid\" ] && continue\n entries+=(\"$rid $rname ($rtype)\")\n claudes+=(\"$rcid\")\ndone < <(echo \"$agents_json\" | jq -r '\n ((.agents // [])[] | [.id, .name, .agentType, (.claudeSessionId // \"\")] | @tsv),\n ((.orchestratorCycles // [])[] | [\"cycle-\" + (.cycle|tostring), \"orchestrator\", \"cycle\", (.claudeSessionId // \"\")] | @tsv)\n')\n\n(( \\${#entries[@]} == 0 )) && { echo \"No agents or cycles in session\"; sleep 1; exit 0; }\n\nif command -v fzf &>/dev/null; then\n idx=$(for (( i=0; i<\\${#entries[@]}; i++ )); do echo \"$i \\${entries[$i]}\"; done \\\\\n | fzf --reverse --height=100% --with-nth=2.. --prompt=\"Open Claude: \" | awk '{print $1}')\n [ -z \"$idx\" ] && exit 0\nelse\n for (( i=0; i<\\${#entries[@]}; i++ )); do\n printf \" %d) %s\\\\n\" $((i+1)) \"\\${entries[$i]}\"\n done\n printf \"\\\\nPick: \"\n read -r choice\n idx=$((choice - 1))\n (( idx >= 0 && idx < \\${#entries[@]} )) || exit 0\nfi\n\ncid=\"\\${claudes[$idx]}\"\n[ -z \"$cid\" ] && { echo \"No Claude session\"; sleep 1; exit 1; }\n[[ \"$cid\" =~ ^[A-Za-z0-9_-]+$ ]] || { echo \"Invalid claude session id\"; sleep 1; exit 1; }\ncd \"$cwd\" && exec claude --resume \"$cid\"\n`;\n\nconst TAIL_AGENT_LOGS_SCRIPT = `#!/bin/bash\n# Pick a sisyphus agent and view its tmux pane scrollback (last 2000 lines) in less.\n# Uses tmux capture-pane — no tail -f, no pipe-pane side effects.\n# Assumes macOS (fzf optional). Requires \\`sis status --json\\`.\n${SESSION_RESOLVE}\n\ncommand -v jq &>/dev/null || { echo \"jq required\"; sleep 1; exit 1; }\n\nagents_json=$(sis status \"$session_id\" --json 2>/dev/null)\nif [ -z \"$agents_json\" ]; then\n echo \"Failed to read session status\"; sleep 1; exit 1\nfi\n\ndeclare -a entries=()\ndeclare -a ids=()\ndeclare -a panes=()\nwhile IFS=$'\\\\t' read -r aid aname atype astatus pid; do\n [ -z \"$aid\" ] && continue\n entries+=(\"$aid $aname ($atype) — $astatus\")\n ids+=(\"$aid\")\n panes+=(\"$pid\")\ndone < <(echo \"$agents_json\" | jq -r '.agents[] | [.id, .name, .agentType, .status, .paneId] | @tsv')\n\n(( \\${#entries[@]} == 0 )) && { echo \"No agents in session\"; sleep 1; exit 0; }\n\nif command -v fzf &>/dev/null; then\n idx=$(for (( i=0; i<\\${#entries[@]}; i++ )); do echo \"$i \\${entries[$i]}\"; done \\\\\n | fzf --reverse --height=100% --with-nth=2.. --prompt=\"Tail logs: \" | awk '{print $1}')\n [ -z \"$idx\" ] && exit 0\nelse\n for (( i=0; i<\\${#entries[@]}; i++ )); do\n printf \" %d) %s\\\\n\" $((i+1)) \"\\${entries[$i]}\"\n done\n printf \"\\\\nPick agent: \"\n read -r choice\n idx=$((choice - 1))\n (( idx >= 0 && idx < \\${#entries[@]} )) || exit 0\nfi\n\ntarget_pane=\"\\${panes[$idx]}\"\n[ -z \"$target_pane\" ] && { echo \"Agent has no active pane\"; sleep 1; exit 1; }\ntmux capture-pane -t \"$target_pane\" -p -S -2000 | less +G\n`;\n\nconst KILL_AGENT_SCRIPT = `#!/bin/bash\n# Pick a sisyphus agent and kill it (with red confirmation prompt).\n# Assumes macOS (fzf optional). Requires \\`sis status --json\\` and \\`sis agent kill\\`.\n${SESSION_RESOLVE}\n\ncommand -v jq &>/dev/null || { echo \"jq required\"; sleep 1; exit 1; }\n\nagents_json=$(sis status \"$session_id\" --json 2>/dev/null)\nif [ -z \"$agents_json\" ]; then\n echo \"Failed to read session status\"; sleep 1; exit 1\nfi\n\ndeclare -a entries=()\ndeclare -a ids=()\nwhile IFS=$'\\\\t' read -r aid aname atype astatus; do\n [ -z \"$aid\" ] && continue\n entries+=(\"$aid $aname ($atype) — $astatus\")\n ids+=(\"$aid\")\ndone < <(echo \"$agents_json\" | jq -r '.agents[] | [.id, .name, .agentType, .status] | @tsv')\n\n(( \\${#entries[@]} == 0 )) && { echo \"No agents in session\"; sleep 1; exit 0; }\n\nif command -v fzf &>/dev/null; then\n idx=$(for (( i=0; i<\\${#entries[@]}; i++ )); do echo \"$i \\${entries[$i]}\"; done \\\\\n | fzf --reverse --height=100% --with-nth=2.. --prompt=\"Kill agent: \" | awk '{print $1}')\n [ -z \"$idx\" ] && exit 0\nelse\n for (( i=0; i<\\${#entries[@]}; i++ )); do\n printf \" %d) %s\\\\n\" $((i+1)) \"\\${entries[$i]}\"\n done\n printf \"\\\\nPick agent: \"\n read -r choice\n idx=$((choice - 1))\n (( idx >= 0 && idx < \\${#entries[@]} )) || exit 0\nfi\n\nprintf '\\\\033[31mKill %s? (yes/no): \\\\033[0m' \"\\${ids[$idx]}\"\nread -r answer\n[ \"$answer\" = \"yes\" ] || exit 0\nsis agent kill \"\\${ids[$idx]}\" --session \"$session_id\"\necho \"\"\nread -n 1 -s -r -p \"Press a key to close.\"\n`;\n\nconst COPY_AGENT_ID_SCRIPT = `#!/bin/bash\n# Pick a sisyphus agent and copy its ID to clipboard.\n# Assumes macOS (pbcopy, fzf optional). Requires \\`sis status --json\\`.\n${SESSION_RESOLVE}\n\ncommand -v jq &>/dev/null || { echo \"jq required\"; sleep 1; exit 1; }\n\nagents_json=$(sis status \"$session_id\" --json 2>/dev/null)\nif [ -z \"$agents_json\" ]; then\n echo \"Failed to read session status\"; sleep 1; exit 1\nfi\n\ndeclare -a entries=()\ndeclare -a ids=()\nwhile IFS=$'\\\\t' read -r aid aname atype astatus; do\n [ -z \"$aid\" ] && continue\n entries+=(\"$aid $aname ($atype) — $astatus\")\n ids+=(\"$aid\")\ndone < <(echo \"$agents_json\" | jq -r '.agents[] | [.id, .name, .agentType, .status] | @tsv')\n\n(( \\${#entries[@]} == 0 )) && { echo \"No agents in session\"; sleep 1; exit 0; }\n\nif command -v fzf &>/dev/null; then\n idx=$(for (( i=0; i<\\${#entries[@]}; i++ )); do echo \"$i \\${entries[$i]}\"; done \\\\\n | fzf --reverse --height=100% --with-nth=2.. --prompt=\"Copy agent ID: \" | awk '{print $1}')\n [ -z \"$idx\" ] && exit 0\nelse\n for (( i=0; i<\\${#entries[@]}; i++ )); do\n printf \" %d) %s\\\\n\" $((i+1)) \"\\${entries[$i]}\"\n done\n printf \"\\\\nPick agent: \"\n read -r choice\n idx=$((choice - 1))\n (( idx >= 0 && idx < \\${#entries[@]} )) || exit 0\nfi\n\naid=\"\\${ids[$idx]}\"\nprintf '%s' \"$aid\" | pbcopy\ntmux display-message \"Copied $aid\"\n`;\n\nconst COPY_LOGS_SCRIPT = `#!/bin/bash\n# Copy last 200 lines of the newest cycle log to clipboard.\n# Assumes macOS (pbcopy).\n${SESSION_RESOLVE}\n\ndir=\"$cwd/.sisyphus/sessions/$session_id/logs\"\n[ -d \"$dir\" ] || { tmux display-message \"No logs dir\"; exit 0; }\nlatest=$(ls -t \"$dir\"/cycle-*.md 2>/dev/null | head -1)\n[ -z \"$latest\" ] && { tmux display-message \"No cycle logs yet\"; exit 0; }\ntail -n 200 \"$latest\" | pbcopy\ntmux display-message \"Copied last 200 lines of $(basename \"$latest\")\"\n`;\n\nconst COPY_LATEST_REPORT_SCRIPT = `#!/bin/bash\n# Copy the newest report file to clipboard.\n# Assumes macOS (pbcopy).\n${SESSION_RESOLVE}\n\ndir=\"$cwd/.sisyphus/sessions/$session_id/reports\"\n[ -d \"$dir\" ] || { tmux display-message \"No reports dir\"; exit 0; }\nlatest=$(ls -t \"$dir\" 2>/dev/null | head -1)\n[ -z \"$latest\" ] && { tmux display-message \"No reports yet\"; exit 0; }\ncat \"$dir/$latest\" | pbcopy\ntmux display-message \"Copied $latest\"\n`;\n\nconst COPY_PATH_SCRIPT = `#!/bin/bash\n# Copy the session directory path to clipboard.\n# Assumes macOS (pbcopy).\n${SESSION_RESOLVE}\n\nprintf '%s' \"$cwd/.sisyphus/sessions/$session_id\" | pbcopy\ntmux display-message \"Copied session path\"\n`;\n\nconst COPY_ID_SCRIPT = `#!/bin/bash\n# Copy the session ID to clipboard.\n# Assumes macOS (pbcopy).\n${SESSION_RESOLVE}\n\nprintf '%s' \"$session_id\" | pbcopy\ntmux display-message \"Copied session ID\"\n`;\n\nconst COPY_CONTEXT_SCRIPT = `#!/bin/bash\n# Copy the session context XML to clipboard.\n# Assumes macOS (pbcopy). Requires \\`sis session context\\`.\n${SESSION_RESOLVE}\n\nsis session context \"$session_id\" --cwd \"$cwd\" | pbcopy\ntmux display-message \"Copied session context (XML)\"\n`;\n\nconst EDIT_CONTEXT_FILE_SCRIPT = `#!/bin/bash\n# Pick a context file for the current session and open it in nvim.\n# Excludes archive/ subdirectory. Assumes macOS (fzf optional).\n${SESSION_RESOLVE}\n\nctx_dir=\"$cwd/.sisyphus/sessions/$session_id/context\"\n[ -d \"$ctx_dir\" ] || { echo \"No context dir for this session\"; read -n 1 -s -r -p \"Press a key to close.\"; exit 0; }\n\nmapfile -t files < <(find \"$ctx_dir\" -type f -not -path '*/archive/*' | sort)\n(( \\${#files[@]} == 0 )) && { echo \"No context files yet\"; read -n 1 -s -r -p \"Press a key to close.\"; exit 0; }\n\nif command -v fzf &>/dev/null; then\n picked=$(printf '%s\\\\n' \"\\${files[@]}\" | sed \"s|$ctx_dir/||\" \\\\\n | fzf --reverse --height=100% --prompt=\"Context file: \")\n [ -z \"$picked\" ] && exit 0\nelse\n declare -a display_files=()\n for f in \"\\${files[@]}\"; do\n display_files+=(\"\\${f#$ctx_dir/}\")\n done\n for (( i=0; i<\\${#display_files[@]}; i++ )); do\n printf \" %d) %s\\\\n\" $((i+1)) \"\\${display_files[$i]}\"\n done\n printf \"\\\\nPick file: \"\n read -r choice\n idx=$((choice - 1))\n (( idx >= 0 && idx < \\${#display_files[@]} )) || exit 0\n picked=\"\\${display_files[$idx]}\"\nfi\n\nfile=\"$ctx_dir/$picked\"\nexec nvim \"$file\"\n`;\n\n// === end Stage 3 script constants ===\n\n// === Stage 4 script constants ===\n\nconst QUICK_SPAWN_EXPLORE_SCRIPT = `#!/bin/bash\n# Spawn an Explore agent with the macOS clipboard contents as the instruction.\n# macOS only — pbpaste hard dependency.\n${SESSION_RESOLVE}\n\nif ! command -v pbpaste >/dev/null 2>&1; then\n echo \"pbpaste not found — macOS only for now\"\n read -n 1 -s -r -p \"Press a key to close.\"\n exit 1\nfi\n\ninstruction=$(pbpaste)\nif [ -z \"\\${instruction// }\" ]; then\n echo \"Clipboard is empty — copy a task description first\"\n read -n 1 -s -r -p \"Press a key to close.\"\n exit 1\nfi\n\nif [ \"\\${#instruction}\" -lt 20 ]; then\n echo \"Clipboard text too short (\\${#instruction} chars; spawn requires 20+)\"\n read -n 1 -s -r -p \"Press a key to close.\"\n exit 1\nfi\n\nname=\"explore-$(date +%s)\"\nsis agent spawn \\\\\n --agent-type sisyphus:explore \\\\\n --name \"$name\" \\\\\n --session \"$session_id\" \\\\\n --instruction \"$instruction\"\nexit_code=$?\n[ $exit_code -ne 0 ] && read -n 1 -s -r -p \"Press a key to close.\"\nexit $exit_code\n`;\n\nconst QUICK_SPAWN_DEBUG_SCRIPT = `#!/bin/bash\n# Spawn a Debug agent with the macOS clipboard contents as the instruction.\n# macOS only — pbpaste hard dependency.\n${SESSION_RESOLVE}\n\nif ! command -v pbpaste >/dev/null 2>&1; then\n echo \"pbpaste not found — macOS only for now\"\n read -n 1 -s -r -p \"Press a key to close.\"\n exit 1\nfi\n\ninstruction=$(pbpaste)\nif [ -z \"\\${instruction// }\" ]; then\n echo \"Clipboard is empty — copy a task description first\"\n read -n 1 -s -r -p \"Press a key to close.\"\n exit 1\nfi\n\nif [ \"\\${#instruction}\" -lt 20 ]; then\n echo \"Clipboard text too short (\\${#instruction} chars; spawn requires 20+)\"\n read -n 1 -s -r -p \"Press a key to close.\"\n exit 1\nfi\n\nname=\"debug-$(date +%s)\"\nsis agent spawn \\\\\n --agent-type sisyphus:debug \\\\\n --name \"$name\" \\\\\n --session \"$session_id\" \\\\\n --instruction \"$instruction\"\nexit_code=$?\n[ $exit_code -ne 0 ] && read -n 1 -s -r -p \"Press a key to close.\"\nexit $exit_code\n`;\n\nconst OPEN_LATEST_REPORT_SCRIPT = `#!/bin/bash\n# Open the most-recently-modified file in the current session's reports/ in nvim.\n${SESSION_RESOLVE}\n\nreports_dir=\"$cwd/.sisyphus/sessions/$session_id/reports\"\nif [ ! -d \"$reports_dir\" ]; then\n echo \"No reports/ directory for this session\"\n read -n 1 -s -r -p \"Press a key to close.\"\n exit 0\nfi\n\nlatest=$(ls -t \"$reports_dir\"/*.md 2>/dev/null | head -1)\nif [ -z \"$latest\" ]; then\n echo \"No reports yet\"\n read -n 1 -s -r -p \"Press a key to close.\"\n exit 0\nfi\n\nexec nvim \"$latest\"\n`;\n\nconst CLONE_SESSION_SCRIPT = `#!/bin/bash\n# Clone the current session into a new independent session.\n# Orchestrator-only — the underlying CLI rejects calls from other panes/agents.\n${SESSION_RESOLVE}\n\nprintf \"Goal for cloned session: \"\nread -e goal\n[ -z \"\\${goal// }\" ] && exit 0\n\nprintf \"Optional name (blank to skip): \"\nread -e clone_name\n\nprintf \"Copy strategy.md? (y/N): \"\nread -r copy_strategy\n\nargs=()\n[ -n \"$clone_name\" ] && args+=(--name \"$clone_name\")\n[ \"$copy_strategy\" = \"y\" ] || [ \"$copy_strategy\" = \"Y\" ] && args+=(--strategy)\n\nsis session clone \"\\${args[@]}\" \"$goal\"\nexit_code=$?\nread -n 1 -s -r -p \"Press a key to close.\"\nexit $exit_code\n`;\n\nconst HISTORY_SCRIPT = `#!/bin/bash\n# Show rich session detail (history command's per-session view) in a popup.\n${SESSION_RESOLVE}\nsis admin history \"$session_id\" 2>&1 | less -R\n`;\n\nconst RECONNECT_SCRIPT = `#!/bin/bash\n# Reconnect daemon to an orphaned tmux session for the current cwd.\n${SESSION_RESOLVE}\nsis session reconnect \"$session_id\"\nexit_code=$?\nread -n 1 -s -r -p \"Press a key to close.\"\nexit $exit_code\n`;\n\nconst OPEN_SCRATCH_SCRIPT = `#!/bin/bash\n# Open a standalone Claude scratch window in the home tmux session for this cwd.\n# scratch resolves the home session itself via @sisyphus_cwd; no session_id needed.\nexec sis admin scratch\n`;\n\n// === end Stage 4 script constants ===\n\nfunction installScript(name: string, content: string): void {\n mkdirSync(join(globalDir(), 'bin'), { recursive: true });\n const path = scriptPath(name);\n writeFileSync(path, content, 'utf8');\n chmodSync(path, 0o755);\n}\n\nfunction installAllScripts(): void {\n // Compose flows (in-session message scripts) launch `NVIM_APPNAME=sisyphus nvim`,\n // which needs ~/.config/sisyphus/init.lua to exist before first use.\n ensureSisyphusInitLua();\n\n // Existing scripts with real content\n installScript('sisyphus-cycle', CYCLE_SCRIPT);\n installScript('sisyphus-home', homeScript());\n installScript('sisyphus-kill-pane', KILL_PANE_SCRIPT);\n installScript('sisyphus-new', NEW_PROMPT_SCRIPT);\n installScript('sisyphus-msg', MESSAGE_SCRIPT);\n installScript('sisyphus-kill-session', KILL_SESSION_SCRIPT);\n installScript('sisyphus-delete-session', DELETE_SESSION_SCRIPT);\n installScript('sisyphus-status-popup', STATUS_POPUP_SCRIPT);\n installScript('sisyphus-pick-session', PICK_SESSION_SCRIPT);\n installScript('sisyphus-continue-session', CONTINUE_SESSION_SCRIPT);\n installScript('sisyphus-restart-agent-popup', RESTART_AGENT_SCRIPT);\n installScript('sisyphus-open-roadmap', OPEN_ROADMAP_SCRIPT);\n installScript('sisyphus-open-strategy', OPEN_STRATEGY_SCRIPT);\n installScript('sisyphus-export-session', EXPORT_SESSION_SCRIPT);\n\n // === Stage 1 (descriptor + generator + stub installs) ===\n const scriptsDir = join(globalDir(), 'bin');\n\n // Submenu dispatch scripts — one per submenu, generated from descriptor\n for (const [id, def] of Object.entries(KEYMAP.submenus)) {\n installScript(`sisyphus-menu-${id}`, generateSubmenuScript(id, def, scriptsDir));\n }\n // === end Stage 1 ===\n\n // === Stage 2 (tmux submenu scripts) ===\n installScript('sisyphus-open-goal', OPEN_GOAL_SCRIPT);\n installScript('sisyphus-open-dir', OPEN_DIR_SCRIPT);\n installScript('sisyphus-open-logs', OPEN_LOGS_SCRIPT);\n installScript('sisyphus-resume-session', RESUME_SESSION_SCRIPT);\n installScript('sisyphus-rollback-session', ROLLBACK_SESSION_SCRIPT);\n installScript('sisyphus-go-to-window', GO_TO_WINDOW_SCRIPT);\n installScript('sisyphus-spawn-agent', SPAWN_AGENT_SCRIPT);\n installScript('sisyphus-search-reports', SEARCH_REPORTS_SCRIPT);\n // === end Stage 2 ===\n\n // === Stage 3 (cursor pickers) ===\n installScript('sisyphus-jump-to-pane', JUMP_TO_PANE_SCRIPT);\n installScript('sisyphus-msg-agent', MSG_AGENT_SCRIPT);\n installScript('sisyphus-rerun-agent', RERUN_AGENT_SCRIPT);\n installScript('sisyphus-open-claude-agent', OPEN_CLAUDE_AGENT_SCRIPT);\n installScript('sisyphus-tail-agent-logs', TAIL_AGENT_LOGS_SCRIPT);\n installScript('sisyphus-kill-agent', KILL_AGENT_SCRIPT);\n installScript('sisyphus-copy-agent-id', COPY_AGENT_ID_SCRIPT);\n installScript('sisyphus-copy-logs', COPY_LOGS_SCRIPT);\n installScript('sisyphus-copy-latest-report', COPY_LATEST_REPORT_SCRIPT);\n installScript('sisyphus-copy-path', COPY_PATH_SCRIPT);\n installScript('sisyphus-copy-id', COPY_ID_SCRIPT);\n installScript('sisyphus-copy-context', COPY_CONTEXT_SCRIPT);\n installScript('sisyphus-edit-context-file', EDIT_CONTEXT_FILE_SCRIPT);\n // === end Stage 3 ===\n\n // === Stage 4 (creative additions) ===\n installScript('sisyphus-quick-spawn-explore', QUICK_SPAWN_EXPLORE_SCRIPT);\n installScript('sisyphus-quick-spawn-debug', QUICK_SPAWN_DEBUG_SCRIPT);\n installScript('sisyphus-open-latest-report', OPEN_LATEST_REPORT_SCRIPT);\n installScript('sisyphus-clone-session', CLONE_SESSION_SCRIPT);\n installScript('sisyphus-history', HISTORY_SCRIPT);\n installScript('sisyphus-reconnect', RECONNECT_SCRIPT);\n installScript('sisyphus-open-scratch', OPEN_SCRATCH_SCRIPT);\n // === end Stage 4 ===\n\n // === Stage 6 (help script override) ===\n installScript('sisyphus-help', HELP_SCRIPT);\n // === end Stage 6 ===\n\n // Side claude pane (direct leader action). Re-runs are idempotent — the CLI\n // detects an existing companion pane for the cwd via the @sisyphus_companion\n // pane marker and focuses it instead of creating a duplicate.\n installScript('sisyphus-companion-pane', COMPANION_PANE_SCRIPT);\n}\n\nexport function getExistingBinding(key: string, table: string = 'root'): string | null {\n try {\n const output = execSync(`tmux list-keys -T ${table}`, { stdio: ['pipe', 'pipe', 'pipe'] }).toString();\n for (const line of output.split('\\n')) {\n if (line.includes(key)) {\n const parts = line.trim().split(/\\s+/);\n const keyIdx = parts.indexOf(key);\n if (keyIdx !== -1) {\n return line.trim();\n }\n }\n }\n return null;\n } catch {\n return null;\n }\n}\n\nexport function isSisyphusBinding(binding: string): boolean {\n return binding.includes('sisyphus');\n}\n\nexport type SetupResult =\n | { status: 'installed'; message: string }\n | { status: 'already-installed'; message: string }\n | { status: 'conflict'; message: string; existingBinding: string; conflictKey: string }\n | { status: 'unsupported-tmux'; message: string }\n | { status: 'requires-force'; message: string; reason: 'would-modify-user-conf'; userConf: string; manualLine: string }\n | { status: 'conf-modification-declined'; message: string; manualLine: string; userConf: string };\n\nexport interface SetupOptions {\n /** Skip the y/N prompt before appending to the user's tmux.conf. */\n assumeYes?: boolean;\n /**\n * Override safety refusals: silently overwrite any existing root-table binding on\n * cycle/prefix keys AND auto-append the source-file line to the user's tmux.conf\n * (implies assumeYes for the conf-append path).\n */\n force?: boolean;\n}\n\nasync function confirmConfAppend(userConf: string, line: string): Promise<boolean> {\n // Don't block scripted/non-TTY callers; they can opt in with assumeYes.\n if (!process.stdin.isTTY || !process.stdout.isTTY) return false;\n\n const rl = createInterface({ input: process.stdin, output: process.stdout });\n return new Promise((resolve) => {\n const question =\n `\\nSisyphus needs to append one line to ${userConf} so its tmux keybindings persist:\\n` +\n ` ${line}\\n\\n` +\n `Append it now? (y/N) `;\n rl.question(question, (answer) => {\n rl.close();\n resolve(answer.trim().toLowerCase() === 'y');\n });\n });\n}\n\nexport async function setupTmuxKeybind(\n cycleKey: string = DEFAULT_CYCLE_KEY,\n prefixKey: string = DEFAULT_PREFIX_KEY,\n opts: SetupOptions = {},\n): Promise<SetupResult> {\n installAllScripts();\n\n // Version check — hard requirement for display-menu flags used\n if (!tmuxVersionAtLeast(3, 2)) {\n let version = 'unknown';\n try { version = execSync('tmux -V', { stdio: ['pipe', 'pipe', 'pipe'] }).toString().trim(); } catch {}\n return {\n status: 'unsupported-tmux',\n message: `tmux 3.2+ required for sisyphus keybindings; got ${version}`,\n };\n }\n\n // Check for existing bindings before writing anything. With --force, we overwrite\n // them silently (tmux bind-key replaces in place); otherwise refuse so the user can\n // pick alternate keys or explicitly opt in.\n if (!opts.force) {\n for (const [label, key] of [['cycle', cycleKey], ['prefix', prefixKey]] as const) {\n const existing = getExistingBinding(key);\n if (existing !== null && !isSisyphusBinding(existing)) {\n return {\n status: 'conflict',\n message: `Tmux key ${key} (${label}) is already bound to something else. Re-run with --force to overwrite, or pass an alternate cycle key (e.g. \"sis admin setup-keybind M-w\").`,\n existingBinding: existing,\n conflictKey: key,\n };\n }\n }\n }\n\n // Detect whether we'd modify the user's tmux.conf BEFORE writing any sisyphus-managed\n // file. Without --force (or --yes), refuse so the user can decide explicitly.\n const userConfPreview = userTmuxConfPath();\n const sisyphusConfPathPreview = sisyphusTmuxConfPath();\n const markedSourceLinePreview = `source-file ${sisyphusConfPathPreview} ${SISYPHUS_CONF_MARKER}`;\n if (userConfPreview !== null && !opts.force && !opts.assumeYes) {\n let alreadySources = false;\n try {\n alreadySources = readFileSync(userConfPreview, 'utf8').includes(sisyphusConfPathPreview);\n } catch {\n /* unreadable — treat as not-sourcing so we err on the side of refusing */\n }\n if (!alreadySources) {\n return {\n status: 'requires-force',\n reason: 'would-modify-user-conf',\n userConf: userConfPreview,\n manualLine: markedSourceLinePreview,\n message:\n `Refusing to modify ${userConfPreview} without explicit consent.\\n` +\n `Re-run with --force (persist) or --yes (same effect, conf-append only) to append:\\n` +\n ` ${markedSourceLinePreview}\\n` +\n `Or run \"sis admin check-keybinds\" for the full decision tree (live-only install is also an option).`,\n };\n }\n }\n\n writeKeymapJson();\n\n const scriptsDir = join(globalDir(), 'bin');\n const bindings = [\n // C-s → display-menu top-level (descriptor-driven)\n generateTopLevelBinding(prefixKey, KEYMAP.topLevel, scriptsDir),\n // M-s → cycle (unchanged)\n `bind-key -T root ${cycleKey} run-shell ${cycleScriptPath()}`,\n // smart-kill is reachable via the sisyphus prefix menu (C-s x) — see KEYMAP.topLevel.\n // We deliberately don't override `prefix x` so users keep their default tmux kill-pane.\n ];\n\n const confPath = sisyphusTmuxConfPath();\n writeFileSync(confPath, `${SISYPHUS_CONF_MARKER}\\n${bindings.join('\\n')}\\n`, 'utf8');\n\n // Append source line to tmux.conf if not already there\n const userConf = userTmuxConfPath();\n const markedSourceLine = `source-file ${confPath} ${SISYPHUS_CONF_MARKER}`;\n let persistedToConf = false;\n let appendDeclined = false;\n\n if (userConf !== null) {\n const contents = readFileSync(userConf, 'utf8');\n if (contents.includes(confPath)) {\n persistedToConf = true;\n } else {\n const shouldAppend = opts.assumeYes || opts.force\n ? true\n : await confirmConfAppend(userConf, markedSourceLine);\n if (shouldAppend) {\n const separator = contents.endsWith('\\n') ? '' : '\\n';\n writeFileSync(userConf, `${contents}${separator}${markedSourceLine}\\n`, 'utf8');\n persistedToConf = true;\n } else {\n appendDeclined = true;\n }\n }\n }\n\n // Apply bindings live\n try {\n for (const b of bindings) {\n execSync(`tmux ${b}`, { stdio: 'pipe' });\n }\n } catch {\n // tmux not running\n }\n\n if (appendDeclined && userConf !== null) {\n return {\n status: 'conf-modification-declined',\n message:\n `Tmux keybindings applied to the live session, but not persisted.\\n` +\n `To persist them, add this line to ${userConf}:\\n ${markedSourceLine}`,\n manualLine: markedSourceLine,\n userConf,\n };\n }\n\n if (getExistingBinding(cycleKey) !== null && isSisyphusBinding(getExistingBinding(cycleKey)!)) {\n return {\n status: 'already-installed',\n message: `Tmux keybindings already configured: ${cycleKey} (cycle), ${prefixKey}+key (?=help for full list).`,\n };\n }\n\n const persistNote = persistedToConf\n ? ''\n : `\\nNote: No tmux.conf found. Add this to your tmux config for persistence:\\n source-file ${confPath}`;\n return {\n status: 'installed',\n message: `Tmux keybindings set: ${cycleKey} cycles, ${prefixKey}+key (?=help for full list)${persistNote}`,\n };\n}\n\nexport function removeTmuxKeybind(): void {\n const confPath = sisyphusTmuxConfPath();\n for (const candidate of [join(homedir(), '.tmux.conf'), join(homedir(), '.config', 'tmux', 'tmux.conf')]) {\n if (existsSync(candidate)) {\n const contents = readFileSync(candidate, 'utf8');\n const filtered = contents\n .split('\\n')\n .filter((line) => !line.includes(confPath))\n .join('\\n');\n if (filtered !== contents) {\n writeFileSync(candidate, filtered, 'utf8');\n }\n }\n }\n\n if (existsSync(confPath)) {\n unlinkSync(confPath);\n }\n\n // Unbind live\n try {\n execSync(`tmux unbind-key -T root ${DEFAULT_CYCLE_KEY}`, { stdio: 'pipe' });\n execSync(`tmux unbind-key -T root ${DEFAULT_PREFIX_KEY}`, { stdio: 'pipe' });\n const output = execSync(`tmux list-keys -T ${KEY_TABLE}`, { stdio: ['pipe', 'pipe', 'pipe'] }).toString();\n for (const line of output.split('\\n')) {\n const parts = line.trim().split(/\\s+/);\n if (parts.length >= 4 && parts[2] === KEY_TABLE) {\n execSync(`tmux unbind-key -T ${KEY_TABLE} ${parts[3]}`, { stdio: 'pipe' });\n }\n }\n } catch {\n // tmux not running\n }\n\n // Remove keymap.json\n const kmPath = keymapJsonPath();\n if (existsSync(kmPath)) unlinkSync(kmPath);\n\n // Remove scripts\n const scripts = [\n 'sisyphus-cycle', 'sisyphus-home', 'sisyphus-kill-pane', 'sisyphus-new', 'sisyphus-msg',\n 'sisyphus-kill-session', 'sisyphus-delete-session', 'sisyphus-help', 'sisyphus-status-popup',\n 'sisyphus-pick-session', 'sisyphus-continue-session', 'sisyphus-restart-agent-popup',\n 'sisyphus-open-roadmap', 'sisyphus-open-strategy', 'sisyphus-export-session',\n // Stage 1: submenu dispatch scripts\n ...Object.keys(KEYMAP.submenus).map(id => `sisyphus-menu-${id}`),\n // Stage 1: new stub scripts\n 'sisyphus-copy-path', 'sisyphus-copy-id', 'sisyphus-copy-context',\n 'sisyphus-copy-logs', 'sisyphus-copy-latest-report', 'sisyphus-copy-agent-id',\n 'sisyphus-open-goal', 'sisyphus-open-dir', 'sisyphus-open-logs',\n 'sisyphus-open-latest-report', 'sisyphus-open-scratch', 'sisyphus-edit-context-file',\n 'sisyphus-spawn-agent', 'sisyphus-msg-agent', 'sisyphus-rerun-agent',\n 'sisyphus-jump-to-pane', 'sisyphus-open-claude-agent', 'sisyphus-tail-agent-logs',\n 'sisyphus-kill-agent', 'sisyphus-quick-spawn-explore', 'sisyphus-quick-spawn-debug',\n 'sisyphus-resume-session', 'sisyphus-rollback-session', 'sisyphus-go-to-window',\n 'sisyphus-clone-session', 'sisyphus-history', 'sisyphus-reconnect',\n 'sisyphus-search-reports',\n ];\n for (const name of scripts) {\n const path = scriptPath(name);\n if (existsSync(path)) unlinkSync(path);\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 { 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","import { execSync } from 'node:child_process';\nimport { loadConfig } from '../shared/config.js';\nimport { resolveInstalledPlugin } from '../daemon/plugins.js';\n\nexport interface SisyphusPluginInfo {\n installed: boolean;\n autoInstalled: boolean;\n installPath: string | null;\n}\n\nfunction exec(cmd: string): string {\n try {\n return execSync(cmd, { encoding: 'utf-8', stdio: ['pipe', 'pipe', 'pipe'] }).trim();\n } catch {\n return '';\n }\n}\n\nfunction isMarketplaceInstalled(marketplace: string): boolean {\n const output = exec('claude plugins marketplace list');\n return output.includes(marketplace);\n}\n\nfunction installMarketplace(marketplace: string, owner = 'CaptainCrouton89'): void {\n console.log(`Adding marketplace: ${owner}/${marketplace}`);\n execSync(`claude plugins marketplace add ${owner}/${marketplace}`, { stdio: 'inherit' });\n}\n\nfunction installPlugin(key: string): void {\n console.log(`Installing plugin: ${key}`);\n execSync(`claude plugins install ${key} --scope user`, { stdio: 'inherit' });\n}\n\nconst SISYPHUS_PLUGIN_KEY = 'sisyphus@sisyphus';\nconst SISYPHUS_MARKETPLACE = 'sisyphus';\nconst SISYPHUS_OWNER = 'crouton-labs';\n\n/**\n * Ensures the user-facing sisyphus plugin (slash commands: /sisyphus:begin,\n * /sisyphus:autopsy, /sisyphus:configure-upload) is installed in the user's\n * Claude Code workspace. Adds the marketplace if needed.\n */\nexport function ensureSisyphusPluginInstalled(): SisyphusPluginInfo {\n const existing = resolveInstalledPlugin(SISYPHUS_PLUGIN_KEY);\n if (existing) {\n return { installed: true, autoInstalled: false, installPath: existing };\n }\n\n try {\n if (!isMarketplaceInstalled(SISYPHUS_MARKETPLACE)) {\n installMarketplace(SISYPHUS_MARKETPLACE, SISYPHUS_OWNER);\n }\n installPlugin(SISYPHUS_PLUGIN_KEY);\n } catch (err) {\n console.warn(`Warning: failed to install ${SISYPHUS_PLUGIN_KEY} — ${(err as Error).message}`);\n return { installed: false, autoInstalled: false, installPath: null };\n }\n\n const installPath = resolveInstalledPlugin(SISYPHUS_PLUGIN_KEY);\n return { installed: installPath !== null, autoInstalled: installPath !== null, installPath };\n}\n\nexport async function ensureRequiredPlugins(cwd: string): Promise<void> {\n const config = loadConfig(cwd);\n const required = config.requiredPlugins;\n if (!required || required.length === 0) return;\n\n for (const plugin of required) {\n const key = `${plugin.name}@${plugin.marketplace}`;\n const existing = resolveInstalledPlugin(key);\n if (existing) continue;\n\n console.log(`Required plugin ${key} not found — installing...`);\n\n if (!isMarketplaceInstalled(plugin.marketplace)) {\n installMarketplace(plugin.marketplace);\n }\n\n installPlugin(key);\n\n // Verify\n const verified = resolveInstalledPlugin(key);\n if (verified) {\n console.log(`Installed ${key} → ${verified}`);\n } else {\n console.warn(`Warning: failed to verify ${key} installation`);\n }\n }\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 { readFileSync } from 'node:fs';\nimport { execFileSync } from 'node:child_process';\nimport { homedir } from 'node:os';\nimport { join } from 'node:path';\nimport { loadConfig } from '../shared/config.js';\n\ninterface PluginEntry {\n scope: string;\n installPath: string;\n version: string;\n installedAt: string;\n lastUpdated: string;\n}\n\ninterface InstalledPlugins {\n version: number;\n plugins: Record<string, PluginEntry[]>;\n}\n\nfunction installedPluginsPath(): string {\n return join(homedir(), '.claude', 'plugins', 'installed_plugins.json');\n}\n\nexport function resolveInstalledPlugin(name: string): string | null {\n let data: InstalledPlugins;\n try {\n data = JSON.parse(readFileSync(installedPluginsPath(), 'utf-8'));\n } catch {\n return null;\n }\n\n const entries = data.plugins?.[name];\n if (!entries || entries.length === 0) return null;\n\n // Prefer user-scoped entry\n const userEntry = entries.find(e => e.scope === 'user');\n return (userEntry ?? entries[0])!.installPath;\n}\n\n/**\n * Auto-install a plugin if not already present.\n * key format: \"name@marketplace\" (e.g. \"termrender@crouton-kit\")\n */\nfunction ensurePluginInstalled(key: string): string | null {\n const existing = resolveInstalledPlugin(key);\n if (existing) return existing;\n\n console.log(`[sisyphus] Auto-installing plugin ${key}...`);\n try {\n execFileSync('claude', ['plugin', 'install', key], {\n stdio: 'pipe',\n timeout: 60_000,\n });\n } catch (err) {\n console.log(`[sisyphus] Warning: failed to install plugin ${key} — ${(err as Error).message}`);\n return null;\n }\n\n // Re-read registry after install\n const installed = resolveInstalledPlugin(key);\n if (!installed) {\n console.log(`[sisyphus] Warning: plugin ${key} installed but not found in registry`);\n }\n return installed;\n}\n\nexport function resolveRequiredPluginDirs(cwd: string): string[] {\n const config = loadConfig(cwd);\n const required = config.requiredPlugins;\n if (!required || required.length === 0) return [];\n\n const dirs: string[] = [];\n for (const plugin of required) {\n const key = `${plugin.name}@${plugin.marketplace}`;\n const path = ensurePluginInstalled(key);\n if (path) {\n dirs.push(path);\n } else {\n console.log(`[sisyphus] Warning: required plugin ${key} not available — skipping`);\n }\n }\n return dirs;\n}\n\n/**\n * Resolve per-agent-type plugin dirs from frontmatter `plugins` field.\n * Auto-installs missing plugins. Keys are \"name@marketplace\" strings.\n */\nexport function resolveAgentPluginDirs(plugins: string[] | undefined): string[] {\n if (!plugins || plugins.length === 0) return [];\n\n const dirs: string[] = [];\n for (const key of plugins) {\n const path = ensurePluginInstalled(key);\n if (path) {\n dirs.push(path);\n }\n }\n return dirs;\n}\n","import type { Request, Response } from '../shared/protocol.js';\nimport { rawSend as sharedRawSend } from '../shared/client.js';\nimport { ensureDaemonInstalled, waitForDaemon } from './install.js';\n\nexport function rawSend(request: Request, timeoutMs = 10_000): Promise<Response> {\n return sharedRawSend(request, timeoutMs);\n}\n\nexport async function sendRequest(request: Request, timeoutMs?: number): Promise<Response> {\n const sleep = (ms: number) => new Promise<void>((resolve) => setTimeout(resolve, ms));\n const MAX_ATTEMPTS = 5;\n const RETRY_DELAY_MS = 2000;\n let installedDaemon = false;\n let lastErr: unknown;\n\n for (let attempt = 1; attempt <= MAX_ATTEMPTS; attempt++) {\n try {\n return await rawSend(request, timeoutMs);\n } catch (err) {\n lastErr = err;\n const code = (err as NodeJS.ErrnoException).code;\n if (code !== 'ENOENT' && code !== 'ECONNREFUSED') {\n throw err;\n }\n\n if (attempt === MAX_ATTEMPTS) break;\n\n if (process.platform === 'darwin' && !installedDaemon) {\n installedDaemon = true;\n await ensureDaemonInstalled();\n await waitForDaemon(5000);\n } else {\n process.stderr.write(`Daemon not ready, retrying (${attempt}/${MAX_ATTEMPTS - 1})...\\n`);\n await sleep(RETRY_DELAY_MS);\n }\n }\n }\n\n if (process.platform !== 'darwin') {\n const lines = [`Sisyphus daemon is not running.`];\n if (process.platform === 'linux') {\n lines.push(\n '',\n ' Start options:',\n ' sisyphusd & # Run in background',\n ' nohup sisyphusd > ~/.sisyphus/daemon.log 2>&1 & # Persist after logout',\n '',\n ' For systemd (recommended):',\n ' # Create ~/.config/systemd/user/sisyphus.service with:',\n ' # [Unit]',\n ' # Description=Sisyphus Daemon',\n ' # [Service]',\n ' # ExecStart=/usr/bin/env node <path-to-sisyphusd>',\n ' # Restart=always',\n ' # [Install]',\n ' # WantedBy=default.target',\n ' systemctl --user enable --now sisyphus',\n );\n } else {\n lines.push(\n '',\n ' Start it manually: sisyphusd &',\n );\n }\n lines.push(\n '',\n ' Diagnose: sis admin doctor',\n ' Logs: tail -f ~/.sisyphus/daemon.log',\n );\n throw new Error(lines.join('\\n'));\n }\n throw lastErr;\n}\n","export function readStdin(opts: { force?: boolean } = {}): Promise<string | null> {\n // Without `force`, skip stdin if attached to a TTY — caller is interactive,\n // not piping. With `force`, read regardless: user explicitly asked via `--stdin`.\n if (!opts.force && process.stdin.isTTY) return Promise.resolve(null);\n\n return new Promise((resolve, reject) => {\n const chunks: Buffer[] = [];\n process.stdin.on('data', (chunk: Buffer) => chunks.push(chunk));\n process.stdin.on('end', () => {\n const text = Buffer.concat(chunks).toString('utf-8').trim();\n resolve(text || null);\n });\n process.stdin.on('error', reject);\n });\n}\n","import { execSync } from 'node:child_process';\n\nexport function isTmuxInstalled(): boolean {\n try {\n execSync('which tmux', { stdio: 'pipe' });\n return true;\n } catch {\n return false;\n }\n}\n\nexport function assertTmux(): void {\n if (!process.env.TMUX) {\n throw new Error('Not running inside a tmux pane. Sisyphus requires tmux.');\n }\n}\n\nexport function getTmuxSession(): string {\n assertTmux();\n return execSync('tmux display-message -p \"#{session_name}\"', { encoding: 'utf8' }).trim();\n}\n\n/**\n * Current tmux session's $N id and name. Always prefer the id for `-t` targeting\n * — tmux -t <name> silently substring-matches other sessions under sparse env.\n */\nexport function getTmuxSessionInfo(): { id: string; name: string } {\n assertTmux();\n const out = execSync('tmux display-message -p \"#{session_id}|#{session_name}\"', { encoding: 'utf8' }).trim();\n const pipeIdx = out.indexOf('|');\n return { id: out.slice(0, pipeIdx), name: out.slice(pipeIdx + 1) };\n}\n\n","import type { Command } from 'commander';\nimport { join } from 'node:path';\nimport { execSync } from 'node:child_process';\nimport { assertTmux, getTmuxSession } from '../tmux.js';\nimport { shellQuote } from '../../shared/shell.js';\n\n\n/**\n * Opens the dashboard in a new tmux window (for background use, e.g. from `start`).\n *\n * Tracks the window by its tmux window ID stored in the @sisyphus_dashboard\n * session option — not by window name, which is fragile (renames, collisions).\n * The \"; exit\" suffix closes the window when the TUI exits.\n *\n * Returns true if a new dashboard was created, false if an existing one was focused.\n */\nexport function openDashboardWindow(tmuxSession: string, cwd: string): boolean {\n // Check for existing dashboard by stored window ID\n try {\n const storedId = execSync(\n `tmux show-option -t ${shellQuote(tmuxSession)} -v @sisyphus_dashboard`,\n { encoding: 'utf-8', stdio: ['pipe', 'pipe', 'pipe'] },\n ).trim();\n\n if (storedId) {\n try {\n execSync(\n `tmux display-message -t ${shellQuote(storedId)} -p \"#{window_id}\"`,\n { stdio: 'pipe' },\n );\n execSync(`tmux select-window -t ${shellQuote(storedId)}`, { stdio: 'pipe' });\n return false;\n } catch {\n // Window is gone — fall through to create a new one\n }\n }\n } catch {\n // Option not set — fall through to create\n }\n\n const tuiPath = join(import.meta.dirname, 'tui.js');\n\n const windowId = execSync(\n `tmux new-window -t ${shellQuote(tmuxSession + ':')} -n \"sisyphus-dashboard\" -c ${shellQuote(cwd)} -P -F \"#{window_id}\"`,\n { encoding: 'utf-8' },\n ).trim();\n\n const cmd = `node ${shellQuote(tuiPath)} --cwd ${shellQuote(cwd)}; exit`;\n execSync(\n `tmux send-keys -t ${shellQuote(windowId)} ${shellQuote(cmd)} Enter`,\n );\n\n execSync(\n `tmux set-option -t ${shellQuote(tmuxSession)} @sisyphus_dashboard ${shellQuote(windowId)}`,\n { stdio: 'pipe' },\n );\n\n return true;\n}\n\nexport function registerDashboard(program: Command): void {\n program\n .command('dashboard')\n .description('Launch the TUI dashboard for monitoring and managing sessions')\n .action(async () => {\n assertTmux();\n const tuiPath = join(import.meta.dirname, 'tui.js');\n execSync(`node ${shellQuote(tuiPath)} --cwd ${shellQuote(process.cwd())}`, {\n stdio: 'inherit',\n });\n });\n}\n","import { execSync } from 'node:child_process';\nimport { existsSync, readFileSync } from 'node:fs';\nimport type { Command } from 'commander';\nimport { sendRequest } from '../client.js';\nimport type { Request } from '../../shared/protocol.js';\nimport type { Session, Agent, OrchestratorCycle } from '../../shared/types.js';\nimport { computeActiveTimeMs } from '../../shared/utils.js';\nimport { roadmapPath, cycleLogPath } from '../../shared/paths.js';\nimport { formatDuration, statusColor } from '../../shared/format.js';\n\nconst COLOR_CODES: Record<string, string> = {\n green: '\\x1b[32m', yellow: '\\x1b[33m', cyan: '\\x1b[36m',\n red: '\\x1b[31m', gray: '\\x1b[90m', white: '\\x1b[37m',\n};\nconst RESET = '\\x1b[0m';\nconst BOLD = '\\x1b[1m';\nconst DIM = '\\x1b[2m';\n\nfunction colorize(text: string, status: string): string {\n const colorName = statusColor(status);\n const code = COLOR_CODES[colorName];\n if (!code) return `${text}\\x1b[0m`;\n return `${code}${text}\\x1b[0m`;\n}\n\nfunction inferOrchestratorPhase(session: Session): string {\n const cycles = session.orchestratorCycles;\n if (cycles.length === 0) return 'planning';\n const lastCycle = cycles[cycles.length - 1];\n\n if (!lastCycle.completedAt) {\n // Orchestrator pane is alive\n const elapsed = Date.now() - new Date(lastCycle.timestamp).getTime();\n if (elapsed < 5000 || lastCycle.agentsSpawned.length === 0) return 'planning';\n return 'spawning';\n } else {\n // Orchestrator yielded\n const runningAgents = session.agents.filter(\n a => lastCycle.agentsSpawned.includes(a.id) && a.status === 'running'\n );\n if (runningAgents.length > 0) {\n return `waiting on ${runningAgents.map(a => a.id).join(', ')}`;\n }\n return 'starting';\n }\n}\n\nfunction formatAgent(agent: Agent, verbose: boolean): string {\n const status = colorize(agent.status, agent.status);\n const name = `${BOLD}${agent.name}${RESET}`;\n const type = `${DIM}(${agent.agentType})${RESET}`;\n const duration = formatDuration(agent.activeMs);\n let line = ` ${agent.id} ${name} ${type} — ${status} ${DIM}(${duration})${RESET}`;\n if (verbose && agent.instruction) {\n const truncated = agent.instruction.length > 200 ? agent.instruction.slice(0, 200) + '...' : agent.instruction;\n line += `\\n ${DIM}Instruction: ${truncated}${RESET}`;\n }\n if (agent.reports.length > 0) {\n for (const r of agent.reports) {\n const label = r.type === 'final' ? 'Final' : 'Update';\n line += `\\n ${label}: ${r.summary}`;\n }\n }\n if (agent.killedReason) {\n line += `\\n Reason: ${agent.killedReason}`;\n }\n return line;\n}\n\nfunction formatCycle(cycle: OrchestratorCycle, phase?: string): string {\n let duration: string;\n if (cycle.completedAt) {\n duration = ` ${DIM}(${formatDuration(cycle.activeMs)})${RESET}`;\n } else {\n const elapsed = formatDuration(cycle.activeMs);\n duration = ` ${DIM}(running, ${elapsed})${RESET}`;\n }\n const agents = cycle.agentsSpawned.length > 0\n ? ` — agents: ${cycle.agentsSpawned.join(', ')}`\n : '';\n const phaseStr = phase ? ` — orchestrator: ${phase}` : '';\n return ` Cycle ${cycle.cycle}${duration}${agents}${phaseStr}`;\n}\n\nfunction computeLastActivity(session: Session): Date | null {\n const timestamps: number[] = [];\n\n for (const cycle of session.orchestratorCycles) {\n timestamps.push(new Date(cycle.timestamp).getTime());\n if (cycle.completedAt) timestamps.push(new Date(cycle.completedAt).getTime());\n }\n\n for (const agent of session.agents) {\n timestamps.push(new Date(agent.spawnedAt).getTime());\n if (agent.completedAt) timestamps.push(new Date(agent.completedAt).getTime());\n for (const r of agent.reports) {\n timestamps.push(new Date(r.timestamp).getTime());\n }\n }\n\n if (timestamps.length === 0) return null;\n return new Date(Math.max(...timestamps));\n}\n\nfunction readRoadmap(cwd: string, sessionId: string): string | null {\n try {\n return readFileSync(roadmapPath(cwd, sessionId), 'utf8');\n } catch {\n return null;\n }\n}\n\nfunction readCycleLog(cwd: string, sessionId: string, cycle: number): string | null {\n try {\n const path = cycleLogPath(cwd, sessionId, cycle);\n if (!existsSync(path)) return null;\n return readFileSync(path, 'utf8');\n } catch {\n return null;\n }\n}\n\nfunction capturePaneOutput(paneId: string, lines: number = 50): string | null {\n try {\n return execSync(\n `tmux capture-pane -t \"${paneId}\" -p -S -${lines}`,\n { encoding: 'utf-8', stdio: ['pipe', 'pipe', 'pipe'] },\n ).trimEnd();\n } catch {\n return null;\n }\n}\n\nfunction printSession(session: Session, verbose: boolean): void {\n const status = colorize(session.status, session.status);\n const sessionDuration = formatDuration(session.createdAt, session.completedAt);\n console.log(`\\n${BOLD}Session: ${session.id}${RESET}`);\n console.log(` Status: ${status}`);\n const effortLabel = session.effort != null ? session.effort : 'high (default)';\n console.log(` Effort: ${effortLabel}`);\n console.log(` Task: ${session.task}`);\n if (session.context) {\n const truncated = !verbose && session.context.length > 120 ? session.context.slice(0, 120) + '...' : session.context;\n console.log(` Context: ${truncated}`);\n }\n console.log(` CWD: ${session.cwd}`);\n console.log(` Created: ${session.createdAt}`);\n const activeTime = formatDuration(computeActiveTimeMs(session));\n console.log(` Duration: ${sessionDuration}${session.completedAt ? '' : ' (ongoing)'} (${activeTime} active)`);\n\n const lastActivity = computeLastActivity(session);\n if (lastActivity) {\n console.log(` Last activity: ${formatDuration(Date.now() - lastActivity.getTime())} ago`);\n }\n\n console.log(` Orchestrator cycles: ${session.orchestratorCycles.length}`);\n\n // Active agents block\n const runningAgents = session.agents.filter(a => a.status === 'running');\n if (runningAgents.length > 0) {\n console.log(`\\n${BOLD}Active agents (${runningAgents.length}):${RESET}`);\n for (const agent of runningAgents) {\n const name = `${BOLD}${agent.name}${RESET}`;\n const type = `${DIM}(${agent.agentType})${RESET}`;\n const duration = formatDuration(agent.activeMs);\n console.log(` ${agent.id} ${name} ${type} running ${duration}`);\n if (verbose && agent.instruction) {\n const truncated = agent.instruction.length > 200 ? agent.instruction.slice(0, 200) + '...' : agent.instruction;\n console.log(` ${DIM}Instruction: ${truncated}${RESET}`);\n }\n }\n }\n\n // Roadmap\n const roadmap = readRoadmap(session.cwd, session.id);\n if (roadmap) {\n console.log(`\\n${BOLD}Roadmap:${RESET}`);\n console.log(roadmap);\n }\n\n if (session.orchestratorCycles.length > 0) {\n console.log(`\\n ${BOLD}Cycles:${RESET}`);\n const cycles = session.orchestratorCycles;\n for (let i = 0; i < cycles.length; i++) {\n const isLast = i === cycles.length - 1;\n const phase = isLast && session.status === 'active' ? inferOrchestratorPhase(session) : undefined;\n console.log(formatCycle(cycles[i], phase));\n\n // Verbose: show cycle log\n if (verbose) {\n const log = readCycleLog(session.cwd, session.id, cycles[i].cycle);\n if (log) {\n const lines = log.split('\\n');\n const preview = lines.slice(0, 20).join('\\n');\n console.log(` ${DIM}--- cycle log ---${RESET}`);\n for (const line of preview.split('\\n')) {\n console.log(` ${DIM}${line}${RESET}`);\n }\n if (lines.length > 20) {\n console.log(` ${DIM}... (${lines.length - 20} more lines)${RESET}`);\n }\n }\n }\n }\n }\n\n if (session.agents.length > 0) {\n console.log(`\\n ${BOLD}Agents:${RESET}`);\n for (const agent of session.agents) {\n console.log(formatAgent(agent, verbose));\n }\n }\n\n // Verbose: capture live pane output\n if (verbose) {\n // Orchestrator pane (from last running cycle)\n const lastCycle = session.orchestratorCycles[session.orchestratorCycles.length - 1];\n if (lastCycle && !lastCycle.completedAt && lastCycle.paneId) {\n const output = capturePaneOutput(lastCycle.paneId);\n if (output) {\n console.log(`\\n<orchestrator-pane-output lines=\"50\">`);\n console.log(output);\n console.log(`</orchestrator-pane-output>`);\n }\n }\n\n // Running agent panes\n for (const agent of runningAgents) {\n if (agent.paneId) {\n const output = capturePaneOutput(agent.paneId, 30);\n if (output) {\n console.log(`\\n<agent-pane-output agent=\"${agent.id}\" name=\"${agent.name}\" lines=\"30\">`);\n console.log(output);\n console.log(`</agent-pane-output>`);\n }\n }\n }\n }\n\n // Completion report\n if (verbose && session.completionReport) {\n console.log(`\\n${BOLD}Completion Report:${RESET}`);\n console.log(session.completionReport);\n }\n}\n\nexport function registerStatus(program: Command): void {\n program\n .command('status')\n .description('Show session status')\n .argument('[session-id]', 'Session ID (defaults to SISYPHUS_SESSION_ID env)')\n .option('-v, --verbose', 'Show detailed output (roadmap, pane output, agent instructions)')\n .option('-j, --json', 'Output raw JSON instead of formatted text')\n .action(async (sessionIdArg?: string, opts?: { verbose?: boolean; json?: boolean }) => {\n const sessionId = sessionIdArg ?? process.env.SISYPHUS_SESSION_ID;\n const verbose = opts?.verbose ?? false;\n const json = opts?.json ?? false;\n const cwd = process.env['SISYPHUS_CWD'] ?? process.cwd();\n\n const request: Request = { type: 'status', sessionId, cwd };\n const response = await sendRequest(request);\n if (response.ok) {\n const session = response.data?.session as Session | undefined;\n if (session) {\n if (json) {\n console.log(JSON.stringify(session));\n } else {\n printSession(session, verbose);\n }\n } else {\n console.log('No session found');\n }\n } else {\n console.error(`Error: ${response.error}`);\n process.exit(1);\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","/** 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 type { Command } from 'commander';\nimport { sendRequest } from '../client.js';\nimport type { Request } from '../../shared/protocol.js';\nimport { basename } from 'node:path';\n\ninterface SessionSummary {\n id: string;\n name?: string;\n task: string;\n status: string;\n agentCount: number;\n createdAt: string;\n cwd?: string;\n}\n\nconst STATUS_COLORS: Record<string, string> = {\n active: '\\x1b[32m',\n paused: '\\x1b[33m',\n completed: '\\x1b[36m',\n};\nconst RESET = '\\x1b[0m';\nconst BOLD = '\\x1b[1m';\nconst DIM = '\\x1b[2m';\n\nfunction truncateTask(task: string, max: number): string {\n if (task.length <= max) return task;\n return task.slice(0, max - 1) + '…';\n}\n\nexport function registerList(program: Command): void {\n program\n .command('list')\n .description('List sessions (defaults to current project)')\n .option('-a, --all', 'Show sessions from all projects')\n .option('--cwd <path>', 'Project directory to list sessions for (overrides SISYPHUS_CWD)')\n .action(async (opts: { all?: boolean; cwd?: string }) => {\n const cwd = opts.cwd ?? process.env['SISYPHUS_CWD'] ?? process.cwd();\n const request: Request = { type: 'list', cwd, all: opts.all };\n const response = await sendRequest(request);\n if (response.ok) {\n const sessions = (response.data?.sessions ?? []) as SessionSummary[];\n const totalCount = response.data?.totalCount as number | undefined;\n const filtered = response.data?.filtered as boolean | undefined;\n\n if (sessions.length === 0) {\n if (filtered && totalCount && totalCount > 0) {\n console.log(`No sessions in this project. ${totalCount} session(s) in other projects.`);\n console.log(`${DIM}Run ${RESET}sis list --all${DIM} to show all.${RESET}`);\n } else {\n console.log('No sessions');\n }\n return;\n }\n\n for (const s of sessions) {\n const color = STATUS_COLORS[s.status] ?? '';\n const status = `${color}${s.status}${RESET}`;\n const agents = `${DIM}${s.agentCount} agent(s)${RESET}`;\n const task = truncateTask(s.task, 60);\n const label = s.name ? `${s.name} ${DIM}(${s.id.slice(0, 8)})${RESET}` : s.id;\n const cwdLabel = opts.all && s.cwd ? ` ${DIM}${basename(s.cwd)}${RESET}` : '';\n console.log(` ${BOLD}${label}${RESET} ${status} ${agents} ${task}${cwdLabel}`);\n }\n\n if (filtered && totalCount && totalCount > sessions.length) {\n const otherCount = totalCount - sessions.length;\n console.log(`\\n${DIM}${otherCount} more session(s) in other projects. Run ${RESET}sis list --all${DIM} to show all.${RESET}`);\n }\n } else {\n console.error(`Error: ${response.error}`);\n process.exit(1);\n }\n });\n}\n","import { readFileSync } from 'node:fs';\nimport type { Command } from 'commander';\nimport { sendRequest } from '../client.js';\nimport type { Request } from '../../shared/protocol.js';\nimport type { MessageSource } from '../../shared/types.js';\n\ninterface TellOptions {\n session?: string;\n // Commander exposes `--no-submit` as `opts.submit`, defaulting to true.\n submit?: boolean;\n stdin?: boolean;\n}\n\nconst ORCH_ALIASES = new Set(['orchestrator', 'orch', 'o']);\n\nfunction parseTarget(raw: string): { kind: 'orchestrator' } | { kind: 'agent'; agentId: string } | null {\n if (ORCH_ALIASES.has(raw)) return { kind: 'orchestrator' };\n if (/^agent-\\d+$/i.test(raw)) return { kind: 'agent', agentId: raw };\n return null;\n}\n\nfunction readStdin(): string {\n // Synchronous read of all stdin. Same pattern as other CLI commands that take piped input.\n return readFileSync(0, 'utf-8');\n}\n\nexport function registerTell(program: Command): void {\n program\n .command('tell <target> [text]')\n .description('Type a prompt directly into a running pane (orchestrator or agent-NNN). Submits immediately unlike `message`.')\n .option('--session <sessionId>', 'Session ID (defaults to SISYPHUS_SESSION_ID)')\n .option('--no-submit', 'Paste text but do not press Enter (caller can review/submit manually)')\n .option('--stdin', 'Read prompt body from stdin instead of the [text] argument (avoids shell escaping)')\n .action(async (targetRaw: string, textArg: string | undefined, opts: TellOptions) => {\n const sessionId = opts.session ?? process.env.SISYPHUS_SESSION_ID;\n if (!sessionId) {\n console.error('Error: provide --session or set SISYPHUS_SESSION_ID');\n process.exit(1);\n }\n\n const target = parseTarget(targetRaw);\n if (!target) {\n console.error(`Error: target must be 'orchestrator' (or 'o'/'orch') or 'agent-NNN', got: ${targetRaw}`);\n process.exit(1);\n }\n\n let text: string;\n if (opts.stdin) {\n text = readStdin();\n if (text === '') {\n console.error('Error: --stdin set but stdin was empty');\n process.exit(1);\n }\n if (textArg != null && textArg !== '') {\n console.error('Error: --stdin conflicts with [text] argument; pass one source');\n process.exit(1);\n }\n } else {\n if (textArg == null || textArg === '') {\n console.error('Error: provide [text] argument or use --stdin');\n process.exit(1);\n }\n text = textArg;\n }\n\n const source: MessageSource | undefined = process.env.SISYPHUS_AGENT_ID\n ? { type: 'agent' as const, agentId: process.env.SISYPHUS_AGENT_ID }\n : undefined;\n\n const submit = opts.submit !== false;\n const request: Request = {\n type: 'tell',\n sessionId,\n target,\n text,\n submit,\n ...(source ? { source } : {}),\n };\n const response = await sendRequest(request);\n if (response.ok) {\n console.log(`Sent to ${targetRaw}${submit ? '' : ' (not submitted)'}`);\n } else {\n console.error(`Error: ${response.error}`);\n process.exit(1);\n }\n });\n}\n","import { existsSync, readFileSync } from 'node:fs';\nimport { homedir } from 'node:os';\nimport { join } from 'node:path';\nimport type { Command } from 'commander';\nimport { sendRequest } from '../client.js';\nimport type { Request } from '../../shared/protocol.js';\nimport type { Session, OrchestratorCycle } from '../../shared/types.js';\n\ninterface ReadOptions {\n session?: string;\n cycle?: string;\n tail?: string;\n head?: string;\n raw?: boolean;\n summary?: boolean;\n toolDetail?: boolean;\n}\n\nconst ORCH_ALIASES = new Set(['orchestrator', 'orch', 'o']);\nconst TURN_TYPES = new Set(['user', 'assistant']);\n\ninterface JsonlEntry {\n type?: string;\n timestamp?: string;\n message?: { role?: string; content?: unknown };\n}\n\ninterface ContentBlock {\n type?: string;\n text?: string;\n thinking?: string;\n name?: string;\n input?: unknown;\n content?: unknown;\n}\n\nfunction projectDirFromCwd(cwd: string): string {\n // Claude Code project encoding: cwd with `/` → `-`. Leading `/` becomes leading `-`.\n return cwd.replace(/\\//g, '-');\n}\n\nfunction transcriptPath(cwd: string, claudeSessionId: string): string {\n return join(homedir(), '.claude', 'projects', projectDirFromCwd(cwd), `${claudeSessionId}.jsonl`);\n}\n\nfunction truncate(s: string, max: number): string {\n if (s.length <= max) return s;\n return s.slice(0, max) + `… (${s.length - max} more chars)`;\n}\n\nfunction formatBlocks(content: unknown, toolDetail: boolean): string {\n if (typeof content === 'string') return content;\n if (!Array.isArray(content)) return JSON.stringify(content);\n const parts: string[] = [];\n for (const block of content as ContentBlock[]) {\n switch (block.type) {\n case 'text':\n parts.push(block.text ?? '');\n break;\n case 'thinking':\n parts.push(`[thinking]\\n${block.thinking ?? ''}`);\n break;\n case 'tool_use': {\n const inputStr = JSON.stringify(block.input ?? {});\n parts.push(`[tool_use: ${block.name}] ${toolDetail ? inputStr : truncate(inputStr, 400)}`);\n break;\n }\n case 'tool_result': {\n const c = typeof block.content === 'string' ? block.content : JSON.stringify(block.content ?? '');\n parts.push(`[tool_result]\\n${toolDetail ? c : truncate(c, 600)}`);\n break;\n }\n default:\n parts.push(`[${block.type ?? 'unknown'}] ${truncate(JSON.stringify(block), 200)}`);\n }\n }\n return parts.join('\\n');\n}\n\nfunction summaryLine(entry: JsonlEntry): string {\n const role = (entry.type ?? '?').toUpperCase().padEnd(9);\n const ts = (entry.timestamp ?? '').slice(11, 19);\n const content = entry.message?.content;\n let preview = '';\n if (typeof content === 'string') {\n preview = content.replace(/\\s+/g, ' ').slice(0, 120);\n } else if (Array.isArray(content)) {\n const blocks = content as ContentBlock[];\n const first = blocks[0];\n if (!first) preview = '(empty)';\n else if (first.type === 'text') preview = (first.text ?? '').replace(/\\s+/g, ' ').slice(0, 120);\n else if (first.type === 'thinking') preview = `[thinking] ${(first.thinking ?? '').replace(/\\s+/g, ' ').slice(0, 100)}`;\n else if (first.type === 'tool_use') preview = `[${first.name}] ${truncate(JSON.stringify(first.input ?? {}), 100)}`;\n else if (first.type === 'tool_result') {\n const c = typeof first.content === 'string' ? first.content : JSON.stringify(first.content ?? '');\n preview = `[tool_result] ${c.replace(/\\s+/g, ' ').slice(0, 100)}`;\n } else preview = `[${first.type ?? '?'}]`;\n if (blocks.length > 1) preview += ` (+${blocks.length - 1} more block${blocks.length - 1 > 1 ? 's' : ''})`;\n }\n return `${role} ${ts} ${preview}`;\n}\n\nexport function registerRead(program: Command): void {\n program\n .command('read <target>')\n .description(\"Print the Claude conversation transcript for a target ('orchestrator' or 'agent-NNN').\")\n .option('--session <sessionId>', 'Session ID (defaults to SISYPHUS_SESSION_ID)')\n .option('--cycle <n>', 'Orchestrator cycle number (default: most recent live, else last completed)')\n .option('--tail <n>', 'Show last N turns', undefined)\n .option('--head <n>', 'Show first N turns', undefined)\n .option('--raw', 'Print raw JSONL (no formatting, no filtering)')\n .option('--summary', 'One-line-per-turn summary instead of full content')\n .option('--tool-detail', 'Include full tool inputs/outputs (default: truncated to 400/600 chars)')\n .action(async (targetRaw: string, opts: ReadOptions) => {\n const sessionId = opts.session ?? process.env.SISYPHUS_SESSION_ID;\n if (!sessionId) {\n console.error('Error: provide --session or set SISYPHUS_SESSION_ID');\n process.exit(1);\n }\n\n const response = await sendRequest({ type: 'status', sessionId, cwd: process.cwd() } as Request);\n if (!response.ok) {\n console.error(`Error: ${response.error}`);\n process.exit(1);\n }\n const session = (response.data as { session?: Session })?.session;\n if (!session) {\n console.error('Error: status response did not include session');\n process.exit(1);\n }\n\n let claudeSessionId: string | undefined;\n let label: string;\n if (ORCH_ALIASES.has(targetRaw)) {\n let cycle: OrchestratorCycle | undefined;\n if (opts.cycle) {\n const n = parseInt(opts.cycle, 10);\n if (!Number.isFinite(n)) {\n console.error(`Error: --cycle must be a number, got: ${opts.cycle}`);\n process.exit(1);\n }\n cycle = session.orchestratorCycles.find(c => c.cycle === n);\n if (!cycle) {\n console.error(`Error: orchestrator cycle ${n} not found in session`);\n process.exit(1);\n }\n } else {\n cycle = [...session.orchestratorCycles].reverse().find(c => !c.completedAt) ?? session.orchestratorCycles.at(-1);\n }\n if (!cycle) {\n console.error('Error: no orchestrator cycles found');\n process.exit(1);\n }\n claudeSessionId = cycle.claudeSessionId;\n label = `orchestrator cycle ${cycle.cycle}${cycle.completedAt ? ' (completed)' : ' (live)'}`;\n } else if (/^agent-\\d+$/i.test(targetRaw)) {\n const ag = session.agents.find(a => a.id === targetRaw);\n if (!ag) {\n console.error(`Error: agent ${targetRaw} not found in session ${sessionId}`);\n process.exit(1);\n }\n claudeSessionId = ag.claudeSessionId;\n label = `agent ${ag.id} — ${ag.name} (${ag.status})`;\n } else {\n console.error(`Error: target must be 'orchestrator' (or 'o'/'orch') or 'agent-NNN', got: ${targetRaw}`);\n process.exit(1);\n }\n\n if (!claudeSessionId) {\n console.error(`Error: no claudeSessionId stored for ${label} — transcript may not exist yet`);\n process.exit(1);\n }\n\n const path = transcriptPath(session.cwd, claudeSessionId);\n if (!existsSync(path)) {\n console.error(`Error: transcript not found at ${path}`);\n process.exit(1);\n }\n\n const raw = readFileSync(path, 'utf-8');\n\n if (opts.raw) {\n process.stdout.write(raw);\n return;\n }\n\n const allEntries: JsonlEntry[] = raw\n .split('\\n')\n .filter(Boolean)\n .map(line => { try { return JSON.parse(line) as JsonlEntry; } catch { return null; } })\n .filter((e): e is JsonlEntry => e !== null);\n\n let entries = allEntries.filter(e => e.type && TURN_TYPES.has(e.type));\n\n const totalTurns = entries.length;\n const head = opts.head ? parseInt(opts.head, 10) : undefined;\n const tail = opts.tail ? parseInt(opts.tail, 10) : undefined;\n let sliceNote = '';\n if (head && Number.isFinite(head)) {\n entries = entries.slice(0, head);\n sliceNote = `first ${head} of ${totalTurns}`;\n }\n if (tail && Number.isFinite(tail)) {\n entries = entries.slice(-tail);\n sliceNote = sliceNote ? `${sliceNote}, then last ${tail}` : `last ${tail} of ${totalTurns}`;\n }\n\n console.log(`=== ${label} — ${entries.length} turn(s)${sliceNote ? ` (${sliceNote})` : ''} ===`);\n console.log(`transcript: ${path}\\n`);\n\n if (opts.summary) {\n for (const e of entries) console.log(summaryLine(e));\n return;\n }\n\n for (const e of entries) {\n const role = (e.type ?? '?').toUpperCase();\n const ts = e.timestamp ?? '';\n const body = formatBlocks(e.message?.content, opts.toolDetail ?? false);\n console.log(`──── ${role} ${ts} ────`);\n console.log(body);\n console.log('');\n }\n });\n}\n","import type { Command } from 'commander';\nimport { sendRequest } from '../client.js';\nimport { readStdin } from '../stdin.js';\nimport type { Request } from '../../shared/protocol.js';\nimport type { MessageSource } from '../../shared/types.js';\n\nexport function registerMessage(program: Command): void {\n program\n .command('message')\n .description('Queue a message for the orchestrator to see on next cycle')\n .argument('[content]', 'Message content (omit when using --stdin or piping)')\n .option('--session <sessionId>', 'Session ID (defaults to SISYPHUS_SESSION_ID env var)')\n .option('--agent <agentId>', 'Route message to a specific agent inbox instead of the orchestrator')\n .option('--stdin', 'Force-read message content from stdin (avoids shell escaping for long prompts)')\n .action(async (contentArg: string | undefined, opts: { session?: string; agent?: string; stdin?: boolean }) => {\n const sessionId = opts.session ?? process.env.SISYPHUS_SESSION_ID;\n if (!sessionId) {\n console.error('Error: provide --session or set SISYPHUS_SESSION_ID environment variable');\n process.exit(1);\n }\n\n let content: string | null | undefined;\n if (opts.stdin) {\n content = await readStdin({ force: true });\n if (!content) {\n console.error('Error: --stdin set but no input received on stdin');\n process.exit(1);\n }\n if (contentArg !== undefined && contentArg !== '-') {\n console.error('Error: --stdin conflicts with [content] argument; pass one source');\n process.exit(1);\n }\n } else if (contentArg === '-' || contentArg === undefined) {\n content = await readStdin();\n if (!content) {\n console.error('Error: provide [content] argument, pipe via stdin, or use --stdin');\n process.exit(1);\n }\n } else {\n content = contentArg;\n }\n\n const source: MessageSource | undefined = process.env.SISYPHUS_AGENT_ID\n ? { type: 'agent' as const, agentId: process.env.SISYPHUS_AGENT_ID }\n : undefined;\n\n const request: Request = { type: 'message', sessionId, content: content!, source, ...(opts.agent ? { agentId: opts.agent } : {}) };\n const response = await sendRequest(request);\n if (response.ok) {\n console.log('Message queued');\n } else {\n console.error(`Error: ${response.error}`);\n process.exit(1);\n }\n });\n}\n","import type { Command } from 'commander';\nimport { existsSync, readFileSync, watchFile, unwatchFile } from 'node:fs';\nimport { join, resolve } from 'node:path';\nimport { ulid } from 'ulid';\nimport { parseDeck } from '../../shared/ask-schema.js';\nimport { createAsk, readMeta, updateMeta, writeDecisions } from '../../daemon/ask-store.js';\nimport { emitHistoryEvent } from '../../daemon/history.js';\nimport { askOutputPath, statePath } from '../../shared/paths.js';\nimport * as state from '../../daemon/state.js';\nimport { ORCHESTRATOR_ASKED_BY } from '../../shared/types.js';\nimport type { AskOutput, AskStatus } from '../../shared/types.js';\nimport { execSafe } from '../../shared/exec.js';\nimport { shellQuote } from '../../shared/shell.js';\n\nconst ULID_RE = /^[0-9A-HJKMNP-TV-Z]{26}$/;\n\nfunction validateAskId(askId: string): void {\n if (!ULID_RE.test(askId)) {\n console.error(`Error: invalid askId format: ${askId}`);\n process.exit(1);\n }\n}\n\nexport function registerAsk(program: Command): void {\n const ask = program\n .command('ask')\n .description('Submit a structured question deck for the user to answer (blocks until answered)')\n .argument('[file]', 'Path to deck JSON (omit for poll/peek subcommands)')\n .option('--session <id>', 'Session id (defaults to SISYPHUS_SESSION_ID)')\n .addHelpText('after', `\nPosts a deck of questions to the user's dashboard inbox. They walk through it and you read the structured JSON back from stdout.\n\nThe CLI always blocks until the user answers (which can take 10+ minutes).\n\n- **Orchestrator:** invoke synchronously so the orchestrator's pane stays alive while the bash blocks. Daemon refuses \\`sis orch yield\\` while orchestrator owns a pending deck; foreground is the supported pattern.\n- **Agents / one-off Claude Code sessions:** invoke through the Bash tool with \\`run_in_background: true\\` and end your turn — the bash completion notification wakes you with stdout ready to parse.\n\nFor guidance on when to use a deck, how to design options the user can actually choose between, and how to bundle related questions into one deck, read the \\`humanloop\\` skill before authoring.\n\nDECK JSON SCHEMA\n { \"title\"?: string, \"interactions\": Interaction[] } // interactions[] non-empty\n\n Interaction:\n id string, /^[A-Za-z0-9_-]+$/, max 64 chars, unique within deck\n title string (required, non-empty)\n subtitle? string\n body? string // markdown rendered in dashboard\n bodyPath? string // path RELATIVE to the deck JSON's directory\n // and must resolve INSIDE that directory\n // (no '..', no symlinks out, no absolute\n // paths pointing elsewhere). Mutually\n // exclusive with 'body'. To use bodyPath,\n // write the deck JSON next to the markdown\n // file (e.g. both in\n // \\$SISYPHUS_SESSION_DIR/context/) and pass\n // a basename like \"summary.md\".\n kind? \"notify\" | \"validation\" | \"decision\" | \"context\" | \"error\"\n // display hint for inbox icon/sort weight.\n // No other values accepted.\n options Option[] // 2–4 options recommended (see humanloop)\n allowFreetext? boolean\n freetextLabel? string\n\n Option:\n id string (required)\n label string (required)\n description? string\n shortcut? string\n\nOUTPUT\n On answer, stdout is one line of JSON:\n { \"responses\": [{ \"id\", \"selectedOptionId\"?, \"freetext\"? }, ...], \"completedAt\" }\n Branch on each response by its interaction \\`id\\`.\n\nValidation errors at submit are precise — read them, don't guess.\n`)\n .action(async (file: string | undefined, opts: { session?: string }) => {\n if (!file) {\n ask.help();\n return;\n }\n await submit(file, opts);\n });\n\n ask\n .command('poll <askId>')\n .description('Block until <askId> is answered, then print output JSON')\n .option('--session <id>', 'Session id (defaults to SISYPHUS_SESSION_ID)')\n .action(async (askId: string, opts: { session?: string }) => poll(askId, opts));\n\n ask\n .command('peek <askId>')\n .description('Print {askId, status, completedAt?, output?} for <askId> without blocking')\n .option('--session <id>', 'Session id (defaults to SISYPHUS_SESSION_ID)')\n .action(async (askId: string, opts: { session?: string }) => peek(askId, opts));\n}\n\nfunction mintAskId(): string {\n return ulid();\n}\n\nfunction resolveClaudeSessionId(cwd: string, sessionId: string, askedBy: string): string | undefined {\n if (!existsSync(statePath(cwd, sessionId))) return undefined;\n const session = state.getSession(cwd, sessionId);\n if (askedBy === ORCHESTRATOR_ASKED_BY) {\n const last = session.orchestratorCycles[session.orchestratorCycles.length - 1];\n return last?.claudeSessionId;\n }\n return session.agents.find(a => a.id === askedBy)?.claudeSessionId;\n}\n\nfunction resolveSessionEnv(opts: { session?: string }): { cwd: string; sessionId: string } {\n const sessionId = opts.session ?? process.env.SISYPHUS_SESSION_ID;\n const cwd = process.env.SISYPHUS_CWD ?? process.cwd();\n if (!sessionId) {\n console.error('Error: provide --session or set SISYPHUS_SESSION_ID');\n process.exit(1);\n }\n return { cwd, sessionId };\n}\n\n/**\n * Idempotently mark an ask answered: stamp meta.completedAt, emit `ask-answered`,\n * and credit `userBlockedMs` on the session/cycle if the ask was blocking.\n * Re-entrant: the `meta.completedAt` check ensures only the first observer credits the wait.\n */\nasync function markAnswered(cwd: string, sessionId: string, askId: string): Promise<void> {\n const meta = readMeta(cwd, sessionId, askId);\n if (!meta || meta.completedAt) return;\n\n const completedAt = new Date().toISOString();\n const durationMs = new Date(completedAt).getTime() - new Date(meta.askedAt).getTime();\n\n try {\n await updateMeta(cwd, sessionId, askId, { status: 'answered', completedAt });\n } catch {\n // updateMeta throws if the meta file vanished mid-flight; treat as best-effort.\n return;\n }\n\n emitHistoryEvent(sessionId, 'ask-answered', {\n askId,\n askedBy: meta.askedBy,\n blocking: meta.blocking,\n durationMs,\n askedAt: meta.askedAt,\n completedAt,\n });\n\n if (meta.blocking && durationMs > 0) {\n try {\n if (existsSync(statePath(cwd, sessionId))) {\n await state.incrementUserBlockedMs(cwd, sessionId, durationMs, meta.askedAt, meta.askedBy);\n }\n } catch {\n // State increment is best-effort — history event is the source of truth for autopsy.\n }\n }\n}\n\nfunction waitForOutput(cwd: string, sessionId: string, askId: string, initialPpid?: number): Promise<AskOutput> {\n const outputPath = askOutputPath(cwd, sessionId, askId);\n\n if (existsSync(outputPath)) {\n return Promise.resolve(JSON.parse(readFileSync(outputPath, 'utf-8')) as AskOutput);\n }\n\n return new Promise((res, _rej) => {\n let ppidWatcher: ReturnType<typeof setInterval> | undefined;\n\n const cleanup = () => {\n unwatchFile(outputPath, onChange);\n if (ppidWatcher !== undefined) clearInterval(ppidWatcher);\n process.removeListener('SIGINT', onSigint);\n };\n\n const onChange = () => {\n if (!existsSync(outputPath)) return;\n try {\n const out = JSON.parse(readFileSync(outputPath, 'utf-8')) as AskOutput;\n cleanup();\n res(out);\n } catch (err) {\n const code = (err as NodeJS.ErrnoException).code;\n if (code === 'ENOENT' || err instanceof SyntaxError) {\n // File disappeared mid-read or atomic rename not yet complete — next tick will retry\n return;\n }\n throw err;\n }\n };\n watchFile(outputPath, { interval: 250 }, onChange);\n\n if (initialPpid !== undefined && initialPpid !== 1) {\n ppidWatcher = setInterval(() => {\n if (process.ppid !== initialPpid || process.ppid === 1) {\n cleanup();\n process.exit(0);\n }\n }, 250);\n }\n\n const onSigint = () => {\n cleanup();\n process.exit(130);\n };\n process.once('SIGINT', onSigint);\n });\n}\n\n/**\n * Spawn a tmux pane next to the caller showing the deck so the user can answer\n * inline without leaving the agent's pane. The dashboard inbox remains a valid\n * second surface — both write through the same on-disk ask-store paths.\n *\n * No-op outside tmux, when the user opts out, or if the split fails (the\n * dashboard is still a valid answering surface, so we never want to break the\n * ask itself for a UX nicety).\n */\nfunction maybeSpawnAskPane(cwd: string, sessionId: string, askId: string): void {\n const callerPane = process.env.TMUX_PANE;\n if (!callerPane) return;\n if (process.env.SISYPHUS_DISABLE_ASK_PANE === '1') return;\n\n const tuiPath = join(import.meta.dirname, 'tui.js');\n const cmd = `node ${shellQuote(tuiPath)} --cwd ${shellQuote(cwd)} --session-id ${shellQuote(sessionId)} --ask ${shellQuote(askId)}`;\n\n // -d: don't auto-focus the new pane (caller stays focused)\n // -h: horizontal split (new pane sits to the right)\n // -t: target the caller's pane so the split is adjacent\n execSafe(`tmux split-window -d -h -t ${shellQuote(callerPane)} -c ${shellQuote(cwd)} ${shellQuote(cmd)}`);\n}\n\nasync function submit(file: string, opts: { session?: string }): Promise<void> {\n const { cwd, sessionId } = resolveSessionEnv(opts);\n const askedBy = process.env.SISYPHUS_AGENT_ID ?? ORCHESTRATOR_ASKED_BY;\n\n const deckPath = resolve(file);\n if (!existsSync(deckPath)) {\n console.error(`Error: deck file not found: ${deckPath}`);\n process.exit(1);\n }\n\n let decisions;\n try {\n decisions = parseDeck(deckPath);\n } catch (err) {\n console.error(`Error: ${(err as Error).message}`);\n process.exit(1);\n }\n\n const initialPpid = process.ppid;\n const claudeSessionId = resolveClaudeSessionId(cwd, sessionId, askedBy);\n const askId = mintAskId();\n\n const q0 = decisions.interactions[0];\n createAsk(cwd, sessionId, {\n askId,\n askedBy,\n blocking: true,\n pid: process.pid,\n claudeSessionId,\n cwd,\n title: decisions.title !== undefined ? decisions.title : q0?.title,\n subtitle: q0?.subtitle,\n kind: q0?.kind,\n });\n writeDecisions(cwd, sessionId, askId, decisions);\n\n maybeSpawnAskPane(cwd, sessionId, askId);\n\n const output = await waitForOutput(cwd, sessionId, askId, initialPpid);\n await markAnswered(cwd, sessionId, askId);\n process.stdout.write(JSON.stringify(output) + '\\n');\n}\n\nasync function poll(askId: string, opts: { session?: string }): Promise<void> {\n validateAskId(askId);\n const { cwd, sessionId } = resolveSessionEnv(opts);\n const meta = readMeta(cwd, sessionId, askId);\n if (!meta) {\n console.error(`Error: askId not found: ${askId}`);\n process.exit(1);\n }\n const output = await waitForOutput(cwd, sessionId, askId);\n await markAnswered(cwd, sessionId, askId);\n process.stdout.write(JSON.stringify(output) + '\\n');\n}\n\nasync function peek(askId: string, opts: { session?: string }): Promise<void> {\n validateAskId(askId);\n const { cwd, sessionId } = resolveSessionEnv(opts);\n const meta = readMeta(cwd, sessionId, askId);\n if (!meta) {\n process.stdout.write(JSON.stringify({ askId, status: 'not-found' satisfies AskStatus }) + '\\n');\n return;\n }\n const outputPath = askOutputPath(cwd, sessionId, askId);\n const result: { askId: string; status: AskStatus; completedAt?: string; output?: AskOutput } = {\n askId,\n status: meta.status,\n };\n if (meta.completedAt) result.completedAt = meta.completedAt;\n try {\n if (existsSync(outputPath)) {\n result.output = JSON.parse(readFileSync(outputPath, 'utf-8')) as AskOutput;\n }\n } catch (err) {\n if (!(err instanceof SyntaxError)) throw err;\n // output.json mid-write (atomic rename in progress); leave output key absent\n }\n process.stdout.write(JSON.stringify(result) + '\\n');\n}\n","import { spawnSync } from 'node:child_process';\nimport { existsSync, lstatSync, readFileSync, realpathSync } from 'node:fs';\nimport { dirname, resolve, sep } from 'node:path';\nimport { z } from 'zod';\nimport type { Deck } from './types.js';\n\n// ── zod v4 building blocks ────────────────────────────────────────────────────\n// v4 notes: .nonempty() → .min(1); error messages use {error: 'string'} per check.\n\nexport const interactionOptionSchema = z.object({\n id: z.string().min(1),\n label: z.string().min(1),\n description: z.string().optional(),\n shortcut: z.string().optional(),\n});\n\nconst interactionSchema = z.object({\n id: z.string().regex(/^[A-Za-z0-9_-]+$/, { error: 'interaction id must match /^[A-Za-z0-9_-]+$/' }).min(1).max(64),\n title: z.string().min(1, { error: 'title must be non-empty' }),\n subtitle: z.string().min(1, { error: 'subtitle must be non-empty when present' }).optional(),\n body: z.string().optional(),\n bodyPath: z.string().optional(),\n options: z.array(interactionOptionSchema),\n allowFreetext: z.boolean().optional(),\n freetextLabel: z.string().optional(),\n kind: z.enum(['notify', 'validation', 'decision', 'context', 'error']).optional(),\n});\n\nconst deckSourceSchema = z.object({\n sessionName: z.string().optional(),\n askedBy: z.string().optional(),\n blockedSince: z.string().optional(),\n});\n\nexport const deckSchema = z.object({\n title: z.string().optional(),\n source: deckSourceSchema.optional(),\n interactions: z.array(interactionSchema).min(1, { error: 'interactions[] must be non-empty' }),\n}).superRefine((input, ctx) => {\n const seen = new Map<string, number>();\n for (let i = 0; i < input.interactions.length; i++) {\n const interaction = input.interactions[i];\n if (interaction.body !== undefined && interaction.bodyPath !== undefined) {\n ctx.addIssue({\n code: 'custom',\n message: 'body and bodyPath are mutually exclusive',\n path: ['interactions', i],\n });\n }\n const prev = seen.get(interaction.id);\n if (prev !== undefined) {\n ctx.addIssue({\n code: 'custom',\n message: `duplicate interaction id \"${interaction.id}\" at indices ${prev} and ${i}`,\n path: ['interactions', i, 'id'],\n });\n }\n seen.set(interaction.id, i);\n }\n});\n\n// ── termrender invocation ─────────────────────────────────────────────────────\nfunction runTermrenderCheck(content: string): { ok: true } | { ok: false; error: string } {\n const result = spawnSync('termrender', ['--check'], {\n input: content,\n encoding: 'utf-8',\n timeout: 5000,\n });\n if (result.error) {\n return { ok: false, error: `termrender invocation failed: ${result.error.message}` };\n }\n if (result.status !== 0) {\n return { ok: false, error: `termrender --check exited ${result.status}: ${result.stderr.trim()}` };\n }\n return { ok: true };\n}\n\n// ── C2 bodyPath defense + inlining ────────────────────────────────────────────\nfunction inlineBodyPath(deckPath: string, bodyPath: string): string {\n const deckDir = dirname(deckPath);\n const joined = resolve(deckDir, bodyPath);\n\n // STEP 1: existence + lstat BEFORE realpath to catch symlinks and directories.\n if (!existsSync(joined)) {\n throw new Error(\n `bodyPath does not exist: '${bodyPath}' (resolved against deck dir '${deckDir}'). bodyPath is interpreted relative to the deck JSON's directory; place the body file there and use a relative path (e.g. \"completion-summary.md\").`,\n );\n }\n const stat = lstatSync(joined);\n if (!stat.isFile()) {\n // Catches symlinks, directories, FIFOs — lstat does not follow symlinks.\n throw new Error(`bodyPath must be a regular file (not a symlink, directory, or special file): ${bodyPath}`);\n }\n\n // STEP 2: realpath both sides, prefix-check (defense-in-depth for .. traversal).\n // realpathSync is safe here: lstat already confirmed the path exists.\n const realResolved = realpathSync(joined);\n const realDeckDir = realpathSync(deckDir);\n const prefix = realDeckDir + sep;\n if (realResolved !== realDeckDir && !realResolved.startsWith(prefix)) {\n throw new Error(\n `bodyPath '${bodyPath}' escapes the deck's directory ('${realDeckDir}'). bodyPath is resolved relative to the deck JSON file and must stay inside its directory (no '..', absolute paths pointing elsewhere, or symlinks out). Fix: write the deck JSON next to the body file (e.g. both inside $SISYPHUS_SESSION_DIR/context/) and use a relative path like \"completion-summary.md\".`,\n );\n }\n\n // STEP 3: read. lstat confirmed regular file; realpath confirmed in-tree.\n return readFileSync(joined, 'utf-8');\n}\n\n// ── public entry point ────────────────────────────────────────────────────────\nexport function parseDeck(deckPath: string): Deck {\n const raw = readFileSync(deckPath, 'utf-8');\n let json: unknown;\n try {\n json = JSON.parse(raw);\n } catch {\n throw new Error('deck is not valid JSON');\n }\n\n const parsed = deckSchema.parse(json);\n\n const inlinedInteractions = parsed.interactions.map(interaction => {\n let body = interaction.body;\n if (interaction.bodyPath !== undefined) {\n body = inlineBodyPath(deckPath, interaction.bodyPath);\n }\n if (body !== undefined) {\n const check = runTermrenderCheck(body);\n if (!check.ok) {\n throw new Error(check.error);\n }\n }\n // Drop bodyPath from persisted decisions.json (recipe §1.8).\n const { bodyPath: _drop, ...rest } = interaction;\n return body !== undefined ? { ...rest, body } : { ...rest };\n });\n\n return { ...parsed, interactions: inlinedInteractions };\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';\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 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 { 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 { 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","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\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\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 { 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 type { Command } from 'commander';\nimport { sendRequest } from '../client.js';\nimport type { Request } from '../../shared/protocol.js';\n\nexport function registerKill(program: Command): void {\n program\n .command('kill <sessionId>')\n .description('Kill a running session and all its agents')\n .action(async (sessionId: string) => {\n const request: Request = { type: 'kill', sessionId };\n const response = await sendRequest(request);\n if (response.ok) {\n console.log(`Session ${sessionId} killed.`);\n if (response.data) {\n const { killedAgents } = response.data as { killedAgents: number };\n console.log(`Cleaned up: ${killedAgents} agent(s) killed, tmux window removed.`);\n }\n } else {\n console.error(`Error: ${response.error}`);\n process.exit(1);\n }\n });\n}\n","import type { Command } from 'commander';\nimport { sendRequest } from '../client.js';\nimport type { Request } from '../../shared/protocol.js';\n\nexport function registerDelete(program: Command): void {\n program\n .command('delete <sessionId>')\n .description('Delete a session and all its data')\n .option('--cwd <path>', 'Project directory', process.env.SISYPHUS_CWD || process.cwd())\n .action(async (sessionId: string, opts: { cwd: string }) => {\n const request: Request = { type: 'delete', sessionId, cwd: opts.cwd };\n const response = await sendRequest(request);\n if (response.ok) {\n console.log(`Session ${sessionId} deleted.`);\n } else {\n console.error(`Error: ${response.error}`);\n process.exit(1);\n }\n });\n}\n","import type { Command } from 'commander';\nimport { sendRequest } from '../client.js';\nimport { readStdin } from '../stdin.js';\nimport type { Request } from '../../shared/protocol.js';\n\nexport function registerResume(program: Command): void {\n program\n .command('resume')\n .description('Respawn orchestrator with new instructions (for paused/completed sessions)')\n .addHelpText('after', '\\n Use `resume` to restart a paused or completed session with new instructions.\\n Use `continue` to keep working on a completed session without new instructions.\\n')\n .argument('<session-id>', 'Session ID to resume')\n .argument('[message]', 'Additional instructions for the orchestrator (omit when using --stdin)')\n .option('--stdin', 'Read message from stdin (avoids shell escaping for long prompts)')\n .action(async (sessionId: string, messageArg: string | undefined, opts: { stdin?: boolean }) => {\n const cwd = process.env['SISYPHUS_CWD'] ?? process.cwd();\n\n let message: string | undefined = messageArg;\n if (opts.stdin) {\n const piped = await readStdin({ force: true });\n if (!piped) {\n console.error('Error: --stdin set but no input received on stdin');\n process.exit(1);\n }\n if (messageArg !== undefined && messageArg !== '-') {\n console.error('Error: --stdin conflicts with [message] argument; pass one source');\n process.exit(1);\n }\n message = piped;\n } else if (messageArg === '-') {\n const piped = await readStdin({ force: true });\n if (!piped) {\n console.error(\"Error: message '-' means read stdin, but no input received\");\n process.exit(1);\n }\n message = piped;\n }\n\n const request: Request = { type: 'resume', sessionId, cwd, message };\n const response = await sendRequest(request);\n if (response.ok) {\n const tmuxSessionName = response.data?.tmuxSessionName as string | undefined;\n console.log(`Session ${sessionId} resumed`);\n if (tmuxSessionName) {\n console.log(`Tmux session: ${tmuxSessionName}`);\n console.log(` tmux attach -t ${tmuxSessionName}`);\n }\n } else {\n console.error(`Error: ${response.error}`);\n process.exit(1);\n }\n });\n}\n","import type { Command } from 'commander';\nimport { sendRequest } from '../client.js';\nimport type { Request } from '../../shared/protocol.js';\nimport { assertTmux } from '../tmux.js';\n\nexport function registerContinue(program: Command): void {\n program\n .command('continue')\n .description('Clear roadmap and continue working on a completed session (stays in current cycle)')\n .addHelpText('after', '\\n Use `continue` when a session completed but you want to add more work.\\n Use `resume` when you want to restart with specific new instructions.\\n')\n .option('--session <sessionId>', 'Session ID (defaults to SISYPHUS_SESSION_ID env var)')\n .action(async (opts: { session?: string }) => {\n assertTmux();\n const sessionId = opts.session ?? process.env.SISYPHUS_SESSION_ID;\n if (!sessionId) {\n console.error('Error: provide --session or set SISYPHUS_SESSION_ID environment variable');\n process.exit(1);\n }\n\n const request: Request = { type: 'continue', sessionId };\n const response = await sendRequest(request);\n if (response.ok) {\n console.log('Session reactivated. Roadmap cleared.');\n console.log('\\nThe previous roadmap has been wiped — you are starting fresh.');\n console.log('Consider writing a new roadmap before spawning agents.');\n } else {\n console.error(`Error: ${response.error}`);\n process.exit(1);\n }\n });\n}\n","import type { Command } from 'commander';\nimport { sendRequest } from '../client.js';\nimport type { Request } from '../../shared/protocol.js';\nimport { assertTmux } from '../tmux.js';\n\nexport function registerComplete(program: Command): void {\n program\n .command('complete')\n .description('Mark session as completed (orchestrator only)')\n .requiredOption('--report <report>', 'Final completion report')\n .option('--session <sessionId>', 'Session ID (defaults to SISYPHUS_SESSION_ID env var)')\n .action(async (opts: { report: string; session?: string }) => {\n assertTmux();\n const sessionId = opts.session ?? process.env.SISYPHUS_SESSION_ID;\n if (!sessionId) {\n console.error('Error: provide --session or set SISYPHUS_SESSION_ID environment variable');\n process.exit(1);\n }\n\n const request: Request = { type: 'complete', sessionId, report: opts.report };\n const response = await sendRequest(request);\n if (response.ok) {\n console.log('Session completed.');\n console.log(`\\nTo keep working in this session:`);\n console.log(` sis session continue # reactivate session and clear roadmap for new work`);\n } else {\n console.error(`Error: ${response.error}`);\n process.exit(1);\n }\n });\n}\n","import type { Command } from 'commander';\nimport { sendRequest } from '../client.js';\nimport type { Request } from '../../shared/protocol.js';\n\nexport function registerRollback(program: Command): void {\n program\n .command('rollback <sessionId> <cycle>')\n .description('Roll back a session to a previous cycle boundary')\n .action(async (sessionId: string, cycleStr: string) => {\n const toCycle = parseInt(cycleStr, 10);\n if (isNaN(toCycle) || toCycle < 1) {\n console.error('Error: cycle must be a positive integer');\n process.exit(1);\n }\n\n const cwd = process.env['SISYPHUS_CWD'] ?? process.cwd();\n const request: Request = { type: 'rollback', sessionId, cwd, toCycle };\n const response = await sendRequest(request);\n if (response.ok) {\n const data = response.data as { restoredToCycle: number };\n console.log(`Session ${sessionId} rolled back to cycle ${data.restoredToCycle}.`);\n console.log(`Session is now paused. Use 'sis session resume ${sessionId}' to respawn the orchestrator.`);\n } else {\n console.error(`Error: ${response.error}`);\n process.exit(1);\n }\n });\n}\n","import type { Command } from 'commander';\nimport { sendRequest } from '../client.js';\nimport type { Request } from '../../shared/protocol.js';\n\nexport function registerReconnect(program: Command): void {\n program\n .command('reconnect')\n .description('Reconnect daemon to an orphaned tmux session (no state change, no orchestrator spawn)')\n .argument('<session-id>', 'Session ID to reconnect')\n .action(async (sessionId: string) => {\n const cwd = process.env['SISYPHUS_CWD'] ?? process.cwd();\n const request: Request = { type: 'reconnect', sessionId, cwd };\n const response = await sendRequest(request);\n if (response.ok) {\n const tmuxSessionName = response.data?.tmuxSessionName as string;\n const tmuxWindowId = response.data?.tmuxWindowId as string;\n console.log(`Reconnected to ${tmuxSessionName} (window ${tmuxWindowId})`);\n } else {\n console.error(`Error: ${response.error}`);\n process.exit(1);\n }\n });\n}\n","import type { Command } from 'commander';\nimport { sendRequest } from '../client.js';\nimport type { Request } from '../../shared/protocol.js';\nimport { assertTmux } from '../tmux.js';\n\nexport function registerClone(program: Command): void {\n program\n .command('clone')\n .description('Clone the current session into a new independent session with a different goal')\n .argument('<goal>', 'Goal for the cloned session')\n .option('-c, --context <text>', 'Additional context for the clone')\n .option('--strategy', 'Copy strategy.md from the source session')\n .option('-n, --name <name>', 'Name for the cloned session')\n .action(async (goal: string, opts: { context?: string; strategy?: boolean; name?: string }) => {\n assertTmux();\n\n const sessionId = process.env.SISYPHUS_SESSION_ID;\n if (!sessionId) {\n console.error('Error: SISYPHUS_SESSION_ID not set. Run this from an orchestrator or agent pane.');\n process.exit(1);\n }\n\n const agentId = process.env.SISYPHUS_AGENT_ID;\n if (agentId !== 'orchestrator') {\n console.error('Error: clone can only be called by the orchestrator. Use sis message to ask the orchestrator to clone.');\n process.exit(1);\n }\n\n const request: Request = {\n type: 'clone',\n sessionId,\n goal,\n context: opts.context,\n name: opts.name,\n strategy: opts.strategy,\n };\n\n const response = await sendRequest(request);\n if (response.ok) {\n const data = response.data as { sessionId: string; tmuxSessionName: string };\n console.log('Session cloned successfully.');\n console.log(` Clone: ${data.sessionId}`);\n console.log(` Tmux: ${data.tmuxSessionName}`);\n console.log('');\n console.log(`The cloned session now owns: \"${goal}\"`);\n console.log('This is the other session\\'s responsibility. You do not need to monitor it.');\n console.log('');\n console.log('Update your scope:');\n console.log('- Remove cloned work from goal.md');\n console.log('- Update roadmap.md to reflect reduced scope');\n console.log('- Update strategy.md if approach changes');\n } else {\n console.error(`Error: ${response.error}`);\n process.exit(1);\n }\n });\n}\n","import type { Command } from 'commander';\nimport { sendRequest } from '../client.js';\nimport type { Request } from '../../shared/protocol.js';\n\nexport function registerSessionTask(program: Command): void {\n program\n .command('task <task>')\n .description('Update the session task/goal')\n .option('--session <sessionId>', 'Session ID (defaults to SISYPHUS_SESSION_ID env var)')\n .action(async (task: string, opts: { session?: string }) => {\n const sessionId = opts.session ?? process.env.SISYPHUS_SESSION_ID;\n if (!sessionId) {\n console.error('Error: provide --session or set SISYPHUS_SESSION_ID environment variable');\n process.exit(1);\n }\n\n const request: Request = { type: 'update-task', sessionId, task };\n const response = await sendRequest(request);\n if (response.ok) {\n console.log('Task updated');\n } else {\n console.error(`Error: ${response.error}`);\n process.exit(1);\n }\n });\n}\n","import type { Command } from 'commander';\nimport { sendRequest } from '../client.js';\nimport type { Request } from '../../shared/protocol.js';\n\nconst VALID_TIERS = ['low', 'medium', 'high', 'xhigh'] as const;\ntype EffortTier = typeof VALID_TIERS[number];\n\nexport function registerSessionEffort(program: Command): void {\n program\n .command('effort <sessionId> <tier>')\n .description('Set the pipeline effort tier for a session (future cycles only; running agents keep their original prompt)')\n .action(async (sessionId: string, tier: string) => {\n if (!VALID_TIERS.includes(tier as EffortTier)) {\n console.error(`Error: tier must be one of: ${VALID_TIERS.join(', ')}`);\n process.exit(1);\n }\n\n const request: Request = { type: 'set-effort', sessionId, effort: tier as EffortTier };\n const response = await sendRequest(request);\n if (response.ok) {\n console.log(`Effort tier set to '${tier}' for session ${sessionId}`);\n console.log('Note: Future cycles only — running agents keep their original prompt.');\n } else {\n console.error(`Error: ${response.error}`);\n process.exit(1);\n }\n });\n}\n","import type { Command } from 'commander';\nimport { sendRequest } from '../client.js';\nimport type { Request } from '../../shared/protocol.js';\nimport type { Session } from '../../shared/types.js';\n\nconst VALID_STATES = ['on', 'off', 'toggle'] as const;\ntype State = typeof VALID_STATES[number];\n\nexport function registerSessionDangerous(program: Command): void {\n program\n .command('dangerous [sessionId] [state]')\n .description(\"Toggle dangerous mode (auto-accept first option for every ask). state: on|off|toggle (default: toggle)\")\n .action(async (sessionIdArg?: string, stateArg?: string) => {\n let sessionId: string;\n if (sessionIdArg) {\n sessionId = sessionIdArg;\n } else if (process.env.SISYPHUS_SESSION_ID) {\n sessionId = process.env.SISYPHUS_SESSION_ID;\n } else {\n console.error('Error: provide <sessionId> or set SISYPHUS_SESSION_ID environment variable');\n process.exit(1);\n }\n\n let state: State;\n if (!stateArg) {\n state = 'toggle';\n } else {\n const stateInput = stateArg.toLowerCase();\n if (!VALID_STATES.includes(stateInput as State)) {\n console.error(`Error: state must be one of: ${VALID_STATES.join(', ')}`);\n process.exit(1);\n }\n state = stateInput as State;\n }\n\n let enabled: boolean;\n if (state === 'toggle') {\n const cwd = process.env['SISYPHUS_CWD'] ? process.env['SISYPHUS_CWD'] : process.cwd();\n const statusResp = await sendRequest({ type: 'status', sessionId, cwd });\n if (!statusResp.ok) {\n console.error(`Error: ${statusResp.error}`);\n process.exit(1);\n }\n const session = statusResp.data?.session as Session | undefined;\n if (!session) {\n console.error(`Error: session ${sessionId} not found`);\n process.exit(1);\n }\n enabled = !session.dangerousMode;\n } else {\n enabled = state === 'on';\n }\n\n const request: Request = { type: 'set-dangerous-mode', sessionId, enabled };\n const response = await sendRequest(request);\n if (response.ok) {\n const flushedRaw = response.data?.flushed;\n const flushed = typeof flushedRaw === 'number' ? flushedRaw : 0;\n const label = enabled ? 'ON' : 'OFF';\n let msg = `DANGEROUS mode ${label} for session ${sessionId}`;\n if (enabled && flushed > 0) {\n msg += ` — ${flushed} pending ask${flushed === 1 ? '' : 's'} auto-resolved`;\n }\n console.log(msg);\n } else {\n console.error(`Error: ${response.error}`);\n process.exit(1);\n }\n });\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 function buildCompanionContext(cwd: string): string {\n let sessionDirs: string[];\n try {\n sessionDirs = readdirSync(sessionsDir(cwd));\n } catch {\n return '<sessions>No sessions found.</sessions>';\n }\n\n const now = Date.now();\n const sevenDaysMs = 7 * 24 * 60 * 60 * 1000;\n const sessionBlocks: string[] = [];\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 // Skip completed sessions older than 7 days\n if (session.status === 'completed' && session.completedAt) {\n if (now - new Date(session.completedAt).getTime() > sevenDaysMs) continue;\n }\n\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 // Agent summary by status\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 // Goal: first meaningful line\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 // Roadmap unchecked todos (up to 5)\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 sessionBlocks.push(lines.join('\\n'));\n }\n\n if (sessionBlocks.length === 0) {\n return '<sessions>No sessions found.</sessions>';\n }\n\n return ['<sessions>', ...sessionBlocks, '</sessions>'].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 { 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 type { Command } from 'commander';\nimport { sendRequest } from '../client.js';\nimport type { Request } from '../../shared/protocol.js';\nimport type { Session } from '../../shared/types.js';\nimport { buildSessionContext } from '../../tui/lib/context.js';\n\nexport function registerSessionContext(program: Command): void {\n program\n .command('context <sessionId>')\n .description('Print session context XML (same as dashboard space y C)')\n .requiredOption('--cwd <path>', 'Working directory of the session')\n .action(async (sessionId: string, opts: { cwd: string }) => {\n const request: Request = { type: 'status', sessionId, cwd: opts.cwd };\n const response = await sendRequest(request);\n if (!response.ok) {\n console.error(`Error: ${response.error}`);\n process.exit(1);\n }\n const session = response.data?.session as Session | undefined;\n if (!session) {\n console.error('Error: Session not found');\n process.exit(1);\n }\n process.stdout.write(buildSessionContext(session, opts.cwd));\n });\n}\n","import type { Command } from 'commander';\nimport { existsSync } from 'node:fs';\nimport { join, resolve } from 'node:path';\nimport { sendRequest } from '../client.js';\nimport type { Request } from '../../shared/protocol.js';\nimport { readStdin } from '../stdin.js';\nimport { assertTmux } from '../tmux.js';\nimport { discoverAgentTypes } from '../../daemon/frontmatter.js';\n\nfunction listTypes(): void {\n const cwd = process.env['SISYPHUS_CWD'] ?? process.cwd();\n const pluginDir = resolve(import.meta.dirname, '..', 'templates', 'agent-plugin');\n const types = discoverAgentTypes(pluginDir, cwd);\n\n if (types.length === 0) {\n console.log('No agent types found.');\n return;\n }\n\n const maxName = Math.max(...types.map(t => t.qualifiedName.length), 4);\n const maxSource = Math.max(...types.map(t => t.source.length), 6);\n\n console.log(`${'TYPE'.padEnd(maxName)} ${'SOURCE'.padEnd(maxSource)} DESCRIPTION`);\n for (const t of types) {\n const desc = t.description ?? '';\n console.log(`${t.qualifiedName.padEnd(maxName)} ${t.source.padEnd(maxSource)} ${desc}`);\n }\n}\n\nexport function registerSpawn(program: Command): void {\n program\n .command('spawn')\n .description('Spawn a new agent (orchestrator only)')\n .argument('[instruction]', 'Task instruction for the agent')\n .option('--agent-type <type>', 'Agent type (e.g. sisyphus:debug, sisyphus:explore)', 'worker')\n .option('--name <name>', 'Agent name')\n .option('--instruction <instruction>', 'Task instruction for the agent (or pipe via stdin)')\n .option('--stdin', 'Force-read instruction from stdin (avoids shell escaping for long prompts)')\n .option('--repo <name>', 'Repo subdirectory to use for this agent')\n .option('--session <sessionId>', 'Session ID (defaults to SISYPHUS_SESSION_ID env var)')\n .option('--list-types', 'List available agent types and exit')\n .action(async (positionalInstruction: string | undefined, opts: { agentType: string; name?: string; instruction?: string; stdin?: boolean; repo?: string; session?: string; listTypes?: boolean }) => {\n if (opts.listTypes) {\n listTypes();\n return;\n }\n\n if (!opts.name) {\n console.error('Error: required option --name <name> not specified');\n process.exit(1);\n }\n\n assertTmux();\n const sessionId = opts.session ?? process.env.SISYPHUS_SESSION_ID;\n if (!sessionId) {\n console.error('Error: provide --session or set SISYPHUS_SESSION_ID environment variable');\n process.exit(1);\n }\n\n const positional = positionalInstruction === '-' ? undefined : positionalInstruction;\n let instruction: string | null | undefined;\n if (opts.stdin) {\n instruction = await readStdin({ force: true });\n if (!instruction) {\n console.error('Error: --stdin set but no input received on stdin');\n process.exit(1);\n }\n if (opts.instruction || positional) {\n console.error('Error: --stdin conflicts with --instruction / [instruction]; pass one source');\n process.exit(1);\n }\n } else {\n instruction = opts.instruction ?? positional ?? await readStdin();\n }\n if (!instruction) {\n console.error('Error: --instruction is required (or pipe via stdin / use --stdin)');\n process.exit(1);\n }\n if (instruction.trim().length < 20) {\n console.error(`Error: instruction too short (${instruction.trim().length} chars). Did you mean to pipe via stdin? Use '-' as the positional or omit it entirely.`);\n process.exit(1);\n }\n\n const sisyphusCwd = process.env['SISYPHUS_CWD'] ?? process.cwd();\n\n if (opts.repo && (opts.repo.includes('/') || opts.repo.includes('..') || opts.repo.includes('\\\\'))) {\n console.error('Error: --repo must be a directory name, not a path');\n process.exit(1);\n }\n\n if (opts.repo && opts.repo !== '.') {\n const repoPath = join(sisyphusCwd, opts.repo);\n if (!existsSync(repoPath)) {\n console.error(`Error: repo directory does not exist: ${repoPath}`);\n process.exit(1);\n }\n }\n\n const request: Request = {\n type: 'spawn',\n sessionId,\n agentType: opts.agentType,\n name: opts.name,\n instruction,\n ...(opts.repo ? { repo: opts.repo } : {}),\n };\n const response = await sendRequest(request);\n if (response.ok) {\n const agentId = response.data?.agentId as string;\n console.log(`Agent spawned: ${agentId}`);\n console.log(`Tip: \\`sis agent await ${agentId}\\` blocks for the report and consumes it inline (won't appear in next cycle).`);\n console.log(\"Run `sis orch yield` when done spawning agents.\");\n } else {\n console.error(`Error: ${response.error}`);\n if (response.error?.includes(\"Unknown session\")) console.error(\"Hint: run `sis list` to see active sessions.\");\n process.exit(1);\n }\n });\n}\n","import { readFileSync, existsSync, readdirSync } from 'node:fs';\nimport { homedir } from 'node:os';\nimport { join, basename } from 'node:path';\nimport type { Provider } from '../shared/types.js';\nimport { projectAgentPluginDir, userAgentPluginDir } from '../shared/paths.js';\n\nexport interface AgentTypeFrontmatter {\n name?: string;\n model?: string;\n fallbackModel?: string;\n color?: string;\n description?: string;\n skills?: string[];\n plugins?: string[];\n permissionMode?: string;\n effort?: string;\n interactive?: boolean;\n systemPrompt?: 'append' | 'replace';\n}\n\nexport { type Provider } from '../shared/types.js';\n\nexport function detectProvider(model: string | undefined): Provider {\n if (!model) return 'anthropic';\n if (/^(gpt-|codex-)/.test(model)) return 'openai';\n return 'anthropic';\n}\n\nexport function parseAgentFrontmatter(content: string): AgentTypeFrontmatter {\n const match = content.match(/^---\\n([\\s\\S]*?)\\n---/);\n if (!match) return {};\n\n const block = match[1]!;\n const fm: AgentTypeFrontmatter = {};\n\n const str = (key: string): string | undefined => {\n const m = block.match(new RegExp(`^${key}:\\\\s*(.+)$`, 'm'));\n return m ? m[1]!.trim() : undefined;\n };\n\n fm.name = str('name');\n fm.model = str('model');\n fm.fallbackModel = str('fallbackModel');\n fm.color = str('color');\n fm.description = str('description');\n fm.permissionMode = str('permissionMode');\n fm.effort = str('effort');\n\n const interactive = str('interactive');\n if (interactive === 'true') fm.interactive = true;\n\n const systemPrompt = str('systemPrompt');\n if (systemPrompt === 'append' || systemPrompt === 'replace') fm.systemPrompt = systemPrompt;\n\n // Parse YAML lists (skills, plugins)\n for (const key of ['skills', 'plugins'] as const) {\n const listMatch = block.match(new RegExp(`^${key}:\\\\s*\\\\n((?:\\\\s+-\\\\s+.+\\\\n?)*)`, 'm'));\n if (listMatch) {\n (fm as Record<string, unknown>)[key] = listMatch[1]!\n .split('\\n')\n .map(line => line.replace(/^\\s+-\\s+/, '').trim())\n .filter(Boolean);\n }\n // Also support inline YAML array: plugins: [a, b]\n const inlineMatch = block.match(new RegExp(`^${key}:\\\\s*\\\\[([^\\\\]]+)\\\\]`, 'm'));\n if (inlineMatch && !(fm as Record<string, unknown>)[key]) {\n (fm as Record<string, unknown>)[key] = inlineMatch[1]!\n .split(',')\n .map(s => s.trim())\n .filter(Boolean);\n }\n }\n\n return fm;\n}\n\nexport function extractAgentBody(content: string): string {\n const match = content.match(/^---\\n[\\s\\S]*?\\n---\\n?([\\s\\S]*)$/);\n return match ? match[1]!.trim() : content.trim();\n}\n\nfunction findPluginInstallPath(namespace: string): string | null {\n try {\n const registryPath = join(homedir(), '.claude', 'plugins', 'installed_plugins.json');\n const registry = JSON.parse(readFileSync(registryPath, 'utf-8'));\n for (const key of Object.keys(registry)) {\n if (key.startsWith(`${namespace}@`)) {\n return registry[key].installPath ?? null;\n }\n }\n } catch {\n // File missing, parse error, or no match\n }\n return null;\n}\n\nexport function resolveAgentTypePath(agentType: string, pluginDir: string, cwd: string): string | null {\n if (!agentType) return null;\n\n let namespace: string | undefined;\n let name: string;\n\n if (agentType.includes(':')) {\n [namespace, name] = agentType.split(':', 2) as [string, string];\n } else {\n name = agentType;\n }\n\n const searchPaths: string[] = [];\n\n if (namespace) {\n // Bundled (handles sisyphus:* via pluginDir)\n searchPaths.push(join(pluginDir, 'agents', `${name}.md`));\n // Installed plugin\n const installPath = findPluginInstallPath(namespace);\n if (installPath) {\n searchPaths.push(join(installPath, 'agents', `${name}.md`));\n }\n } else {\n // Project-local sisyphus extension (carries hooks/skills, not just agent body)\n searchPaths.push(join(projectAgentPluginDir(cwd), 'agents', `${name}.md`));\n // User-global sisyphus extension\n searchPaths.push(join(userAgentPluginDir(), 'agents', `${name}.md`));\n // Project-local Claude convention\n searchPaths.push(join(cwd, '.claude', 'agents', `${name}.md`));\n // User-global Claude convention\n searchPaths.push(join(homedir(), '.claude', 'agents', `${name}.md`));\n // Bundled\n searchPaths.push(join(pluginDir, 'agents', `${name}.md`));\n }\n\n for (const path of searchPaths) {\n if (existsSync(path)) return path;\n }\n\n return null;\n}\n\nexport interface DiscoveredAgentType {\n qualifiedName: string;\n source: 'bundled' | 'plugin' | 'project' | 'user' | 'project-sis' | 'user-sis';\n description?: string;\n model?: string;\n}\n\nexport function discoverAgentTypes(pluginDir: string, cwd: string): DiscoveredAgentType[] {\n const seen = new Set<string>();\n const results: DiscoveredAgentType[] = [];\n\n function scanDir(dir: string, prefix: string | null, source: DiscoveredAgentType['source']): void {\n let files: string[];\n try {\n files = readdirSync(dir);\n } catch {\n return;\n }\n for (const file of files) {\n if (!file.endsWith('.md') || file === 'CLAUDE.md') continue;\n const name = basename(file, '.md');\n const qualifiedName = prefix ? `${prefix}:${name}` : name;\n if (seen.has(qualifiedName)) continue;\n seen.add(qualifiedName);\n\n try {\n const content = readFileSync(join(dir, file), 'utf-8');\n const fm = parseAgentFrontmatter(content);\n results.push({ qualifiedName, source, description: fm.description, model: fm.model });\n } catch {\n results.push({ qualifiedName, source });\n }\n }\n }\n\n // Priority order: project-sis > user-sis > project > user > bundled > plugins\n scanDir(join(projectAgentPluginDir(cwd), 'agents'), null, 'project-sis');\n scanDir(join(userAgentPluginDir(), 'agents'), null, 'user-sis');\n scanDir(join(cwd, '.claude', 'agents'), null, 'project');\n scanDir(join(homedir(), '.claude', 'agents'), null, 'user');\n scanDir(join(pluginDir, 'agents'), 'sisyphus', 'bundled');\n\n // Installed plugins (handles v1 flat and v2 nested formats)\n try {\n const registryPath = join(homedir(), '.claude', 'plugins', 'installed_plugins.json');\n const registry = JSON.parse(readFileSync(registryPath, 'utf-8'));\n const pluginEntries = registry.plugins ?? registry;\n for (const key of Object.keys(pluginEntries)) {\n const atIdx = key.indexOf('@');\n if (atIdx < 1) continue;\n const namespace = key.slice(0, atIdx);\n const entry = pluginEntries[key];\n const installPath = Array.isArray(entry) ? entry[0]?.installPath : entry?.installPath;\n if (installPath) {\n scanDir(join(installPath, 'agents'), namespace, 'plugin');\n }\n }\n } catch {\n // Registry missing or unparseable\n }\n\n return results;\n}\n\nexport interface ResolvedAgentConfig {\n frontmatter: AgentTypeFrontmatter;\n body: string;\n filePath: string;\n}\n\nexport function resolveAgentConfig(agentType: string, pluginDir: string, cwd: string): ResolvedAgentConfig | null {\n const filePath = resolveAgentTypePath(agentType, pluginDir, cwd);\n if (!filePath) return null;\n\n try {\n const content = readFileSync(filePath, 'utf-8');\n return {\n frontmatter: parseAgentFrontmatter(content),\n body: extractAgentBody(content),\n filePath,\n };\n } catch {\n return null;\n }\n}\n","import type { Command } from 'commander';\nimport { sendRequest } from '../client.js';\nimport type { Request } from '../../shared/protocol.js';\nimport { readStdin } from '../stdin.js';\nimport { assertTmux } from '../tmux.js';\n\nexport function registerSubmit(program: Command): void {\n program\n .command('submit')\n .description('Submit work report and exit (agent only)')\n .option('--report <report>', 'Work report (or pipe via stdin)')\n .option('--stdin', 'Force-read report from stdin (avoids shell escaping for long prompts)')\n .option('--session <sessionId>', 'Session ID (defaults to SISYPHUS_SESSION_ID env var)')\n .action(async (opts: { report?: string; stdin?: boolean; session?: string }) => {\n assertTmux();\n const sessionId = opts.session ?? process.env.SISYPHUS_SESSION_ID;\n const agentId = process.env.SISYPHUS_AGENT_ID;\n if (!sessionId || !agentId) {\n console.error('Error: provide --session or set SISYPHUS_SESSION_ID (and SISYPHUS_AGENT_ID) environment variables');\n process.exit(1);\n }\n\n let report: string | null | undefined;\n if (opts.stdin) {\n report = await readStdin({ force: true });\n if (!report) {\n console.error('Error: --stdin set but no input received on stdin');\n process.exit(1);\n }\n if (opts.report) {\n console.error('Error: --stdin conflicts with --report; pass one source');\n process.exit(1);\n }\n } else {\n report = opts.report ?? await readStdin();\n }\n if (!report) {\n console.error('Error: provide --report, pipe content via stdin, or use --stdin');\n process.exit(1);\n }\n\n const request: Request = { type: 'submit', sessionId, agentId, report };\n const response = await sendRequest(request);\n if (response.ok) {\n console.log('Report submitted successfully');\n console.log('Your pane will close. The orchestrator resumes when all agents finish.');\n } else {\n console.error(`Error: ${response.error}`);\n process.exit(1);\n }\n });\n}\n","import type { Command } from 'commander';\nimport { sendRequest } from '../client.js';\nimport type { Request } from '../../shared/protocol.js';\nimport { readStdin } from '../stdin.js';\nimport { assertTmux } from '../tmux.js';\n\nexport function registerReport(program: Command): void {\n program\n .command('report')\n .description('Send a progress report without exiting (agent only)')\n .option('--message <message>', 'Progress report content')\n .option('--stdin', 'Force-read message from stdin (avoids shell escaping for long prompts)')\n .option('--session <sessionId>', 'Session ID (defaults to SISYPHUS_SESSION_ID env var)')\n .action(async (opts: { message?: string; stdin?: boolean; session?: string }) => {\n assertTmux();\n const sessionId = opts.session ?? process.env.SISYPHUS_SESSION_ID;\n const agentId = process.env.SISYPHUS_AGENT_ID;\n if (!sessionId || !agentId) {\n console.error('Error: provide --session or set SISYPHUS_SESSION_ID (and SISYPHUS_AGENT_ID) environment variables');\n process.exit(1);\n }\n\n let content: string | null | undefined;\n if (opts.stdin) {\n content = await readStdin({ force: true });\n if (!content) {\n console.error('Error: --stdin set but no input received on stdin');\n process.exit(1);\n }\n if (opts.message) {\n console.error('Error: --stdin conflicts with --message; pass one source');\n process.exit(1);\n }\n } else {\n content = opts.message ?? await readStdin();\n }\n if (!content) {\n console.error('Error: provide --message, pipe content via stdin, or use --stdin');\n process.exit(1);\n }\n\n const request: Request = { type: 'report', sessionId, agentId, content };\n const response = await sendRequest(request);\n if (response.ok) {\n console.log('Progress report recorded');\n } else {\n console.error(`Error: ${response.error}`);\n process.exit(1);\n }\n });\n}\n","import type { Command } from 'commander';\nimport { existsSync, readFileSync } from 'node:fs';\nimport { sendRequest } from '../client.js';\nimport type { Request } from '../../shared/protocol.js';\nimport { assertTmux } from '../tmux.js';\n\n// Daemon-side handleAwait blocks until the agent reaches a terminal status.\n// Use a long socket timeout so realistic agent runtimes don't trip the default 10s.\nconst AWAIT_TIMEOUT_MS = 24 * 60 * 60 * 1000;\n\nexport function registerAwait(program: Command): void {\n program\n .command('await')\n .description('Block until an agent reaches a terminal status, then print its final report inline. Marks the agent as consumed-inline so its report is suppressed from the next cycle.')\n .argument('<agentId>', 'Agent ID to await')\n .option('--session <sessionId>', 'Session ID (defaults to SISYPHUS_SESSION_ID env var)')\n .action(async (agentId: string, opts: { session?: string }) => {\n assertTmux();\n const sessionId = opts.session ?? process.env.SISYPHUS_SESSION_ID;\n if (!sessionId) {\n console.error('Error: provide --session or set SISYPHUS_SESSION_ID environment variable');\n process.exit(1);\n }\n\n const request: Request = { type: 'await', sessionId, agentId };\n const response = await sendRequest(request, AWAIT_TIMEOUT_MS);\n if (!response.ok) {\n console.error(`Error: ${response.error}`);\n process.exit(1);\n }\n\n const data = response.data ?? {};\n const status = data.status as string;\n const reportPath = data.reportPath as string | null;\n const agentName = data.agentName as string;\n const agentType = data.agentType as string;\n\n const shortType = agentType && agentType !== 'worker' ? agentType.replace(/^sisyphus:/, '') : '';\n const label = shortType ? `${shortType}-${agentName}` : agentName;\n console.log(`[${status}] ${agentId} (${label})`);\n if (reportPath && existsSync(reportPath)) {\n try {\n const body = readFileSync(reportPath, 'utf-8');\n if (body.length > 0) {\n // Avoid double newline: file usually ends with \\n already.\n process.stdout.write(body.endsWith('\\n') ? body : body + '\\n');\n }\n } catch (err) {\n console.error(`Warning: could not read report at ${reportPath}: ${err instanceof Error ? err.message : err}`);\n }\n }\n });\n}\n","import type { Command } from 'commander';\nimport { sendRequest } from '../client.js';\nimport type { Request } from '../../shared/protocol.js';\n\nexport function registerAgentKill(program: Command): void {\n program\n .command('kill <agentId>')\n .description('Kill a running agent')\n .option('-s, --session <sessionId>', 'Session ID (defaults to SISYPHUS_SESSION_ID)')\n .action(async (agentId: string, opts: { session?: string }) => {\n const sessionId = opts.session ?? process.env.SISYPHUS_SESSION_ID;\n if (!sessionId) {\n console.error('Error: No session ID. Use --session or set SISYPHUS_SESSION_ID.');\n process.exit(1);\n }\n\n const request: Request = { type: 'kill-agent', sessionId, agentId };\n const response = await sendRequest(request);\n if (response.ok) {\n console.log(`Agent ${agentId} killed.`);\n } else {\n console.error(`Error: ${response.error}`);\n process.exit(1);\n }\n });\n}\n","import type { Command } from 'commander';\nimport { sendRequest } from '../client.js';\nimport type { Request } from '../../shared/protocol.js';\n\nexport function registerAgentRestart(program: Command): void {\n program\n .command('restart <agentId>')\n .description('Restart a failed/killed/lost agent in a new tmux pane')\n .option('-s, --session <sessionId>', 'Session ID (defaults to SISYPHUS_SESSION_ID)')\n .action(async (agentId: string, opts: { session?: string }) => {\n const sessionId = opts.session ?? process.env.SISYPHUS_SESSION_ID;\n if (!sessionId) {\n console.error('Error: No session ID. Use --session or set SISYPHUS_SESSION_ID.');\n process.exit(1);\n }\n\n const request: Request = { type: 'restart-agent', sessionId, agentId };\n const response = await sendRequest(request);\n if (response.ok) {\n console.log(`Agent ${agentId} restarted.`);\n } else {\n console.error(`Error: ${response.error}`);\n process.exit(1);\n }\n });\n}\n","import type { Command } from 'commander';\nimport { sendRequest } from '../client.js';\nimport type { Request } from '../../shared/protocol.js';\nimport { readStdin } from '../stdin.js';\nimport { assertTmux } from '../tmux.js';\n\nexport function registerYield(program: Command): void {\n program\n .command('yield')\n .description('Yield control back to daemon (orchestrator only)')\n .option('--prompt <text>', 'Short orienting nudge for the next cycle (or pipe via stdin) — name what just happened; leave tactical decisions to the fresh read of the reports')\n .option('--stdin', 'Force-read prompt from stdin (avoids shell escaping for long prompts)')\n .option('--mode <mode>', 'System prompt mode for next cycle (discovery, planning, implementation, validation, completion)')\n .option('--session <sessionId>', 'Session ID (defaults to SISYPHUS_SESSION_ID env var)')\n .action(async (opts: { prompt?: string; stdin?: boolean; mode?: string; session?: string }) => {\n assertTmux();\n const sessionId = opts.session ?? process.env.SISYPHUS_SESSION_ID;\n if (!sessionId) {\n console.error('Error: provide --session or set SISYPHUS_SESSION_ID environment variable');\n process.exit(1);\n }\n\n let nextPrompt: string | undefined;\n if (opts.stdin) {\n const piped = await readStdin({ force: true });\n if (!piped) {\n console.error('Error: --stdin set but no input received on stdin');\n process.exit(1);\n }\n if (opts.prompt) {\n console.error('Error: --stdin conflicts with --prompt; pass one source');\n process.exit(1);\n }\n nextPrompt = piped;\n } else {\n nextPrompt = opts.prompt ?? await readStdin() ?? undefined;\n }\n\n const request: Request = { type: 'yield', sessionId, agentId: 'orchestrator', nextPrompt, mode: opts.mode };\n const response = await sendRequest(request);\n if (response.ok) {\n console.log('Yielded. Waiting for agents to complete.');\n } else {\n console.error(`Error: ${response.error}`);\n process.exit(1);\n }\n });\n}\n","import type { Command } from 'commander';\nimport { sendRequest } from '../client.js';\nimport type { Request } from '../../shared/protocol.js';\n\nexport function registerSegmentRegister(program: Command): void {\n program\n .command('register')\n .description('Register or update an external status bar segment')\n .requiredOption('--id <id>', 'Segment identifier')\n .requiredOption('--side <side>', 'Side to render on: left or right')\n .requiredOption('--priority <n>', 'Priority (lower = further from center)', parseInt)\n .requiredOption('--bg <color>', 'Background hex color (e.g. #2d2f33)')\n .requiredOption('--content <content>', 'tmux format string content')\n .action(async (opts: { id: string; side: string; priority: number; bg: string; content: string }) => {\n if (opts.side !== 'left' && opts.side !== 'right') {\n console.error('Error: --side must be \"left\" or \"right\"');\n process.exit(1);\n }\n const request: Request = {\n type: 'register-segment',\n id: opts.id,\n side: opts.side as 'left' | 'right',\n priority: opts.priority,\n bg: opts.bg,\n content: opts.content,\n };\n const response = await sendRequest(request);\n if (response.ok) {\n console.log(`Segment '${opts.id}' registered.`);\n } else {\n console.error(`Error: ${response.error}`);\n process.exit(1);\n }\n });\n}\n","import type { Command } from 'commander';\nimport { sendRequest } from '../client.js';\nimport type { Request } from '../../shared/protocol.js';\n\nexport function registerSegmentUnregister(program: Command): void {\n program\n .command('unregister')\n .description('Remove an external status bar segment')\n .requiredOption('--id <id>', 'Segment identifier to remove')\n .action(async (opts: { id: string }) => {\n const request: Request = { type: 'unregister-segment', id: opts.id };\n const response = await sendRequest(request);\n if (response.ok) {\n console.log(`Segment '${opts.id}' unregistered.`);\n } else {\n console.error(`Error: ${response.error}`);\n process.exit(1);\n }\n });\n}\n","import { execSync } from 'node:child_process';\nimport type { Command } from 'commander';\nimport { runOnboarding, type OnboardResult } from '../onboard.js';\nimport { ensureDaemonInstalled, isInstalled } from '../install.js';\nimport { setupTmuxKeybind, DEFAULT_CYCLE_KEY, DEFAULT_PREFIX_KEY } from '../tmux-setup.js';\n\nfunction getTmuxVersion(): string {\n try {\n return execSync('tmux -V', { encoding: 'utf-8', stdio: 'pipe' }).trim();\n } catch {\n return 'installed';\n }\n}\n\nfunction printResults(result: OnboardResult, daemonOk: boolean, keybindMsg: string): void {\n console.log('');\n console.log('Setting up Sisyphus...');\n console.log('');\n\n // tmux\n if (result.tmuxInstalled) {\n const detail = getTmuxVersion();\n console.log(` \\u2713 tmux: ${detail}${result.tmuxAutoInstalled ? ' (just installed)' : ''}`);\n } else {\n const hint = process.platform === 'darwin'\n ? 'Install Homebrew (https://brew.sh) then: brew install tmux'\n : 'apt install tmux (Debian/Ubuntu) or your package manager';\n console.log(` \\u2717 tmux: Not installed \\u2014 ${hint}`);\n }\n\n // tmux config\n if (result.tmuxDefaultsWritten) {\n console.log(' \\u2713 tmux config: Sensible defaults written to ~/.tmux.conf');\n }\n\n // Terminal\n if (process.platform === 'darwin') {\n if (result.terminal.isIterm) {\n console.log(` \\u2713 Terminal: ${result.terminal.name}`);\n } else {\n const name = result.terminal.name ? result.terminal.name : 'unknown';\n console.log(` \\u26a0 Terminal: ${name} \\u2014 iTerm2 recommended (https://iterm2.com)`);\n }\n }\n\n // iTerm option key\n if (result.itermOptionKey.checked) {\n if (result.itermOptionKey.allCorrect) {\n console.log(' \\u2713 Right Option Key: Esc+');\n } else {\n const profiles = result.itermOptionKey.incorrectProfiles.map((p) => `\"${p}\"`).join(', ');\n console.log(` \\u26a0 Right Option Key: Not set to Esc+ for ${profiles}`);\n console.log(' Fix: iTerm2 \\u2192 Settings \\u2192 Profiles \\u2192 Keys \\u2192 Right Option Key \\u2192 Esc+');\n }\n }\n\n // Daemon\n if (daemonOk) {\n console.log(' \\u2713 Daemon: Running');\n } else {\n console.log(' \\u2717 Daemon: Failed to start');\n }\n\n // Keybindings\n console.log(` \\u2713 Keybindings: ${keybindMsg}`);\n\n // Session bar\n console.log(' \\u2713 Status bar: daemon-rendered via @sisyphus_left / @sisyphus_right');\n console.log(' status-left: #{E:@sisyphus_left}');\n console.log(' status-right: #{E:@sisyphus_right}');\n\n // Sisyphus user plugin (slash commands: /sisyphus:begin, /sisyphus:autopsy, /sisyphus:configure-upload)\n if (result.sisyphusPlugin.installed && result.sisyphusPlugin.installPath) {\n const suffix = result.sisyphusPlugin.autoInstalled ? ' (just installed)' : '';\n console.log(` \\u2713 sisyphus@sisyphus plugin: ${result.sisyphusPlugin.installPath}${suffix}`);\n } else {\n console.log(' \\u2717 sisyphus@sisyphus plugin: Failed to install (needs `claude` CLI)');\n }\n\n // Nvim\n if (result.nvim.installed) {\n const extra = result.nvim.autoInstalled ? ' (just installed)' : '';\n console.log(` \\u2713 Editor: nvim ${result.nvim.version}${extra}`);\n if (result.nvim.lazyVimInstalled) {\n console.log(' \\u2713 LazyVim: Starter config installed to ~/.config/nvim/');\n }\n if (result.nvim.baleiaInstalled) {\n console.log(' \\u2713 ANSI colors: baleia.nvim plugin configured (auto-detects escape codes)');\n }\n } else {\n console.log(' \\u26a0 Editor: nvim not installed');\n if (process.platform === 'darwin') {\n console.log(' Install: brew install neovim');\n }\n }\n\n console.log('');\n console.log(\"Run 'sis admin getting-started' for a usage guide.\");\n console.log('');\n}\n\nexport function registerSetup(program: Command): void {\n program\n .command('setup')\n .description('One-time setup: install dependencies, daemon, keybindings, and commands')\n .option('-y, --yes', 'Skip the y/N prompt before modifying ~/.tmux.conf')\n .option('-f, --force', 'Override safety refusals: overwrite existing key bindings AND auto-append source-file to ~/.tmux.conf')\n .action(async (opts: { yes?: boolean; force?: boolean }) => {\n // 1. Onboarding (tmux, terminal, iterm, nvim, plugin)\n const result = runOnboarding();\n\n // 2. Daemon\n let daemonOk = false;\n try {\n await ensureDaemonInstalled();\n daemonOk = true;\n } catch {\n daemonOk = isInstalled();\n }\n\n // 3. Keybindings — refuses without --force if it would conflict or modify the\n // user's tmux.conf. Surface the refusal clearly so the user knows to re-run.\n const keybindResult = await setupTmuxKeybind(\n DEFAULT_CYCLE_KEY,\n DEFAULT_PREFIX_KEY,\n { assumeYes: opts.yes, force: opts.force },\n );\n let keybindMsg: string;\n if (keybindResult.status === 'installed' || keybindResult.status === 'already-installed') {\n keybindMsg = `${DEFAULT_CYCLE_KEY} cycle, ${DEFAULT_PREFIX_KEY} prefix (h=dashboard, x=kill)`;\n } else if (keybindResult.status === 'requires-force' || keybindResult.status === 'conflict') {\n keybindMsg =\n `${keybindResult.message}\\n` +\n ` Run \"sis admin check-keybinds\" for the full decision tree, then re-run \"sis admin setup --force\" to proceed.`;\n process.exitCode = 1;\n } else {\n keybindMsg = keybindResult.message;\n }\n\n printResults(result, daemonOk, keybindMsg);\n });\n}\n","import { execSync } from 'node:child_process';\nimport { existsSync, readFileSync, writeFileSync } from 'node:fs';\nimport { homedir } from 'node:os';\nimport { dirname, join } from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport { ensureSisyphusPluginInstalled, type SisyphusPluginInfo } from './plugins.js';\nimport { sisyphusTmuxConfPath } from './tmux-setup.js';\n\nexport interface TerminalInfo {\n name: string;\n isIterm: boolean;\n}\n\nexport interface ItermOptionKeyResult {\n checked: boolean;\n allCorrect: boolean;\n incorrectProfiles: string[];\n}\n\nexport interface NvimInfo {\n installed: boolean;\n autoInstalled: boolean;\n version: string;\n lazyVimInstalled: boolean;\n baleiaInstalled: boolean;\n}\n\nexport interface TermrenderInfo {\n installed: boolean;\n autoInstalled: boolean;\n}\n\nexport interface OnboardResult {\n tmuxInstalled: boolean;\n tmuxAutoInstalled: boolean;\n terminal: TerminalInfo;\n itermOptionKey: ItermOptionKeyResult;\n tmuxDefaultsWritten: boolean;\n nvim: NvimInfo;\n sisyphusPlugin: SisyphusPluginInfo;\n termrender: TermrenderInfo;\n}\n\nexport function detectTerminal(): TerminalInfo {\n const termProgram = process.env['TERM_PROGRAM'] || '';\n const isIterm = termProgram === 'iTerm.app' || !!process.env['ITERM_SESSION_ID'];\n return { name: termProgram || 'unknown', isIterm };\n}\n\nfunction isTmuxAvailable(): boolean {\n try {\n execSync('which tmux', { stdio: 'pipe' });\n return true;\n } catch {\n return false;\n }\n}\n\nfunction isBrewAvailable(): boolean {\n try {\n execSync('which brew', { stdio: 'pipe' });\n return true;\n } catch {\n return false;\n }\n}\n\nfunction tryAutoInstallTmux(): boolean {\n if (!isBrewAvailable()) return false;\n try {\n console.log(' Installing tmux via Homebrew...');\n execSync('brew install tmux', { stdio: 'inherit' });\n return isTmuxAvailable();\n } catch {\n return false;\n }\n}\n\nexport function checkItermOptionKey(): ItermOptionKeyResult {\n if (process.platform !== 'darwin') {\n return { checked: false, allCorrect: true, incorrectProfiles: [] };\n }\n\n const plistPath = join(homedir(), 'Library', 'Preferences', 'com.googlecode.iterm2.plist');\n if (!existsSync(plistPath)) {\n return { checked: false, allCorrect: false, incorrectProfiles: [] };\n }\n\n try {\n const json = execSync(\n `plutil -extract \"New Bookmarks\" json -o - \"${plistPath}\"`,\n { encoding: 'utf-8', stdio: ['pipe', 'pipe', 'pipe'] },\n );\n const profiles = JSON.parse(json) as Array<Record<string, unknown>>;\n const currentProfile = process.env['ITERM_PROFILE'];\n const incorrect: string[] = [];\n for (const profile of profiles) {\n const name = (profile['Name'] as string) || 'Unnamed';\n // Only check the current profile (or all if we can't detect which)\n if (currentProfile && name !== currentProfile) continue;\n // 0 = Normal, 1 = Meta, 2 = Esc+\n if (profile['Right Option Key Sends'] !== 2) {\n incorrect.push(name);\n }\n }\n return { checked: true, allCorrect: incorrect.length === 0, incorrectProfiles: incorrect };\n } catch {\n return { checked: false, allCorrect: false, incorrectProfiles: [] };\n }\n}\n\nfunction hasExistingTmuxConf(): boolean {\n return (\n existsSync(join(homedir(), '.tmux.conf')) ||\n existsSync(join(homedir(), '.config', 'tmux', 'tmux.conf'))\n );\n}\n\nconst SISYPHUS_DEFAULTS_MARKER = '# sisyphus-managed — do not edit';\n\nfunction buildTmuxDefaults(): string {\n const sisyphusConf = sisyphusTmuxConfPath();\n return `# Sensible tmux defaults (installed by sisyphus)\n# Customize freely — sisyphus won't overwrite this file.\n\n# Enable mouse (click panes, scroll, resize)\nset -g mouse on\n\n# Scrollback history\nset -g history-limit 100000\n\n# 256 color + true color support\nset -g default-terminal \"tmux-256color\"\nset -as terminal-overrides \",*:Tc\"\n\n# Low escape delay (keeps Option/Meta keybindings responsive)\nset -sg escape-time 10\n\n# Window numbering from 1\nset -g base-index 1\nsetw -g pane-base-index 1\n\n# Renumber windows when one closes\nset -g renumber-windows on\n\n# Clipboard integration\nset -g set-clipboard on\n\n# Focus events (for editors)\nset -g focus-events on\n\n# Don't detach the client when the last session is destroyed\nset -g detach-on-destroy off\n\n# Vim-style copy mode\nsetw -g mode-keys vi\nbind -T copy-mode-vi v send-keys -X begin-selection\nbind -T copy-mode-vi y send-keys -X copy-selection-and-cancel\n\n# --- Pane navigation (no prefix needed) ---\nbind -n C-h select-pane -L\nbind -n C-l select-pane -R\n\n# --- Window navigation (no prefix needed) ---\nbind -n C-n next-window\nbind -n C-p previous-window\n\n# --- Splits / new window / new session in current directory ---\nbind '\"' split-window -v -c \"#{pane_current_path}\"\nbind % split-window -h -c \"#{pane_current_path}\" \\\\; select-layout even-horizontal\nbind -n M-= split-window -h -c \"#{pane_current_path}\" \\\\; select-layout even-horizontal\nbind n new-window -c \"#{pane_current_path}\"\nbind N new-session -c \"#{pane_current_path}\"\n\n# --- Kill pane + rebalance ---\nbind x kill-pane \\\\; select-layout even-horizontal\nbind -n M-- kill-pane \\\\; select-layout even-horizontal\n\n# --- Auto-rebalance on pane close ---\nset-hook -g after-kill-pane \"select-layout even-horizontal\"\nset-hook -g pane-exited \"select-layout even-horizontal\"\n\n# --- Manual re-tile ---\nbind = select-layout even-horizontal\n\n# --- Resize panes (repeatable with prefix) ---\nbind -r H resize-pane -L 5\nbind -r J resize-pane -D 5\nbind -r K resize-pane -U 5\nbind -r L resize-pane -R 5\n\n# --- Reload config (prefix + Ctrl-r) ---\nbind C-r source-file ~/.tmux.conf \\\\; display \"Reloaded!\"\n\n# --- Half-page scroll (no prefix; -e exits copy mode at bottom) ---\nbind -n C-u copy-mode -e \\\\; send-keys -X halfpage-up\nbind -n C-d copy-mode -e \\\\; send-keys -X halfpage-down\n\n# --- Line scroll (no prefix; -e exits copy mode at bottom) ---\nbind -n C-k copy-mode -e \\\\; send -X scroll-up\nbind -n C-j copy-mode -e \\\\; send -X scroll-down\nbind -T copy-mode-vi C-k send -X scroll-up\nbind -T copy-mode-vi C-j send -X scroll-down\n\n# --- Status bar (gloam palette) ---\nset -g status on\nset -g status-style \"bg=#1d1e21,fg=#d4cbb8\"\nset -g status-position bottom\nset -g status-left \"#{E:@sisyphus_left}\"\nset -g status-left-length 250\nset -g status-right \"#{E:@sisyphus_right}#[fg=#2d2f33]#[bg=#2d2f33,fg=#b0a898] %H:%M \"\nset -g status-right-length 250\nset -g status-interval 2\n\n# Hide window list (session name on left + sisyphus pills on right cover it)\nset -g window-status-format \"\"\nset -g window-status-current-format \"\"\nset -g window-status-separator \"\"\n\n# --- Pane borders ---\nset -g pane-border-style fg=default\nset -g pane-active-border-style fg=green\n\n# Source the sisyphus-managed conf (C-s prefix menu, M-s session cycle)\n# -q so missing file is silent if sisyphus hasn't been set up yet\nsource-file -q ${sisyphusConf} ${SISYPHUS_DEFAULTS_MARKER}\n`;\n}\n\nfunction writeTmuxDefaults(): void {\n const confPath = join(homedir(), '.tmux.conf');\n writeFileSync(confPath, buildTmuxDefaults(), 'utf8');\n}\n\nexport function isNvimAvailable(): boolean {\n try {\n execSync('which nvim', { stdio: 'pipe' });\n return true;\n } catch {\n return false;\n }\n}\n\nfunction getNvimVersion(): string {\n try {\n return execSync('nvim --version', { encoding: 'utf-8', stdio: 'pipe' }).split('\\n')[0]?.replace('NVIM ', '') || 'unknown';\n } catch {\n return 'unknown';\n }\n}\n\nfunction hasLazyVimConfig(): boolean {\n return existsSync(join(homedir(), '.config', 'nvim', 'lazy-lock.json'));\n}\n\nfunction bundledBaleiaPluginPath(): string {\n const distDir = dirname(fileURLToPath(import.meta.url));\n return join(distDir, 'templates', 'baleia.lua');\n}\n\nfunction installBaleiaPlugin(): boolean {\n const pluginsDir = join(homedir(), '.config', 'nvim', 'lua', 'plugins');\n if (!existsSync(pluginsDir)) return false;\n\n const dest = join(pluginsDir, 'sisyphus-baleia.lua');\n if (existsSync(dest)) return true; // already installed\n\n const src = bundledBaleiaPluginPath();\n if (!existsSync(src)) return false;\n\n try {\n writeFileSync(dest, readFileSync(src, 'utf-8'), 'utf8');\n return true;\n } catch {\n return false;\n }\n}\n\nexport function tryAutoInstallNvim(): NvimInfo {\n if (isNvimAvailable()) {\n const baleiaInstalled = installBaleiaPlugin();\n return { installed: true, autoInstalled: false, version: getNvimVersion(), lazyVimInstalled: hasLazyVimConfig(), baleiaInstalled };\n }\n if (!isBrewAvailable()) {\n return { installed: false, autoInstalled: false, version: '', lazyVimInstalled: false, baleiaInstalled: false };\n }\n try {\n console.log(' Installing neovim via Homebrew...');\n execSync('brew install neovim', { stdio: 'inherit' });\n } catch {\n return { installed: false, autoInstalled: false, version: '', lazyVimInstalled: false, baleiaInstalled: false };\n }\n if (!isNvimAvailable()) {\n return { installed: false, autoInstalled: false, version: '', lazyVimInstalled: false, baleiaInstalled: false };\n }\n // Clone LazyVim starter config if no nvim config exists.\n // Neutralize global LFS filters and hooks — users with stale `git-lfs` config\n // (filter installed, binary missing) or broken `core.hooksPath` would otherwise\n // hit \"git-lfs: command not found\" or hook errors during clone.\n const nvimConfigDir = join(homedir(), '.config', 'nvim');\n let lazyVimInstalled = false;\n if (!existsSync(nvimConfigDir)) {\n const cloneCmd = [\n 'git',\n '-c core.hooksPath=/dev/null',\n '-c filter.lfs.smudge=cat',\n '-c filter.lfs.process=',\n '-c filter.lfs.required=false',\n 'clone --depth=1 https://github.com/LazyVim/starter',\n nvimConfigDir,\n ].join(' ');\n try {\n console.log(' Cloning LazyVim starter config...');\n execSync(cloneCmd, {\n stdio: 'inherit',\n env: { ...process.env, GIT_LFS_SKIP_SMUDGE: '1' },\n });\n const gitDir = join(nvimConfigDir, '.git');\n if (existsSync(gitDir)) {\n execSync(`rm -rf \"${gitDir}\"`, { stdio: 'pipe' });\n }\n lazyVimInstalled = true;\n } catch (err) {\n const detail = err instanceof Error && err.message ? err.message : String(err);\n console.warn(` ⚠ LazyVim starter clone failed: ${detail.split('\\n')[0]}`);\n console.warn(' nvim is installed; clone manually:');\n console.warn(` git clone https://github.com/LazyVim/starter ${nvimConfigDir}`);\n }\n }\n const baleiaInstalled = installBaleiaPlugin();\n return { installed: true, autoInstalled: true, version: getNvimVersion(), lazyVimInstalled, baleiaInstalled };\n}\n\nexport function isTermrenderAvailable(): boolean {\n try {\n execSync('which termrender', { stdio: 'pipe' });\n return true;\n } catch {\n return false;\n }\n}\n\nfunction isPipxAvailable(): boolean {\n try {\n execSync('which pipx', { stdio: 'pipe' });\n return true;\n } catch {\n return false;\n }\n}\n\nfunction isPipAvailable(): boolean {\n try {\n execSync('which pip3', { stdio: 'pipe' });\n return true;\n } catch {\n try {\n execSync('which pip', { stdio: 'pipe' });\n return true;\n } catch {\n return false;\n }\n }\n}\n\nfunction tryAutoInstallTermrender(): TermrenderInfo {\n if (isTermrenderAvailable()) {\n return { installed: true, autoInstalled: false };\n }\n // Prefer pipx (isolated install), fall back to pip\n if (isPipxAvailable()) {\n try {\n console.log(' Installing termrender via pipx...');\n execSync('pipx install termrender', { stdio: 'inherit' });\n if (isTermrenderAvailable()) return { installed: true, autoInstalled: true };\n } catch { /* fall through */ }\n }\n if (isPipAvailable()) {\n try {\n console.log(' Installing termrender via pip...');\n const pip = (() => { try { execSync('which pip3', { stdio: 'pipe' }); return 'pip3'; } catch { return 'pip'; } })();\n execSync(`${pip} install termrender`, { stdio: 'inherit' });\n if (isTermrenderAvailable()) return { installed: true, autoInstalled: true };\n } catch { /* fall through */ }\n }\n return { installed: false, autoInstalled: false };\n}\n\nexport function runOnboarding(): OnboardResult {\n const terminal = detectTerminal();\n const tmuxAlreadyInstalled = isTmuxAvailable();\n\n let tmuxInstalled = tmuxAlreadyInstalled;\n let tmuxAutoInstalled = false;\n let tmuxDefaultsWritten = false;\n\n // Auto-install tmux if missing\n if (!tmuxAlreadyInstalled && process.platform === 'darwin') {\n tmuxAutoInstalled = tryAutoInstallTmux();\n tmuxInstalled = tmuxAutoInstalled;\n\n // Write sensible defaults only for fresh tmux installs (don't touch existing configs)\n if (tmuxAutoInstalled && !hasExistingTmuxConf()) {\n writeTmuxDefaults();\n tmuxDefaultsWritten = true;\n }\n }\n\n // Check iTerm2 right option key\n let itermOptionKey: ItermOptionKeyResult = { checked: false, allCorrect: true, incorrectProfiles: [] };\n if (terminal.isIterm) {\n itermOptionKey = checkItermOptionKey();\n }\n\n // Nvim\n const nvim = tryAutoInstallNvim();\n\n // User-facing slash commands ship as a Claude Code plugin from the\n // `sisyphus@sisyphus` marketplace. Best-effort: failures warn but don't abort setup.\n const sisyphusPlugin = ensureSisyphusPluginInstalled();\n\n // termrender (markdown rendering for TUI)\n const termrender = tryAutoInstallTermrender();\n\n return { tmuxInstalled, tmuxAutoInstalled, terminal, itermOptionKey, tmuxDefaultsWritten, nvim, sisyphusPlugin, termrender };\n}\n\nexport function formatOnboardingMessages(result: OnboardResult): string[] {\n const lines: string[] = [];\n\n // Terminal recommendation (macOS only)\n if (process.platform === 'darwin' && !result.terminal.isIterm) {\n lines.push(\n ` Terminal: ${result.terminal.name || 'unknown'}`,\n ' Tip: iTerm2 is recommended for the best experience with sisyphus.',\n ' Download: https://iterm2.com',\n '',\n );\n }\n\n // tmux status\n if (result.tmuxAutoInstalled) {\n lines.push(' \\u2713 tmux installed via Homebrew.');\n if (result.tmuxDefaultsWritten) {\n lines.push(' \\u2713 Default tmux config written to ~/.tmux.conf');\n }\n lines.push('');\n } else if (!result.tmuxInstalled) {\n const installHint = process.platform === 'darwin'\n ? ' Install Homebrew (https://brew.sh) then run: brew install tmux'\n : ' Install: apt install tmux (Debian/Ubuntu) or your package manager';\n lines.push(\n ' \\u2717 tmux is required but could not be installed automatically.',\n installHint,\n '',\n );\n }\n\n // termrender\n if (result.termrender.autoInstalled) {\n lines.push(' \\u2713 termrender installed (markdown rendering for TUI).', '');\n } else if (!result.termrender.installed) {\n lines.push(\n ' \\u26a0 termrender not installed (rich markdown rendering unavailable).',\n ' Install: pipx install termrender (or: pip install termrender)',\n '',\n );\n }\n\n // iTerm2 right option key\n if (result.itermOptionKey.checked && !result.itermOptionKey.allCorrect) {\n const profiles = result.itermOptionKey.incorrectProfiles;\n lines.push(\n ' \\u26a0 Right Option Key is not sending Esc+ in iTerm2:',\n ...profiles.map((p) => ` \\u2022 Profile \"${p}\"`),\n '',\n ' Sisyphus uses Option keybindings (e.g., Option-s to cycle sessions).',\n ' Fix: iTerm2 \\u2192 Settings \\u2192 Profiles \\u2192 Keys \\u2192 Right Option Key \\u2192 Esc+',\n '',\n );\n }\n\n return lines;\n}\n","import type { Command } from 'commander';\nimport { DEFAULT_CYCLE_KEY, setupTmuxKeybind } from '../tmux-setup.js';\n\nexport function registerSetupKeybind(program: Command): void {\n program\n .command('setup-keybind [cycle-key]')\n .description('Install sisyphus tmux keybindings (default: M-s cycle, C-s prefix)')\n .option('-y, --yes', 'Auto-accept the y/N prompt before appending source-file to ~/.tmux.conf')\n .option('-f, --force', 'Override safety refusals: overwrite existing key bindings AND auto-append the source-file line')\n .action(async (key: string | undefined, opts: { yes?: boolean; force?: boolean }) => {\n const resolvedKey = key === undefined ? DEFAULT_CYCLE_KEY : key;\n const result = await setupTmuxKeybind(resolvedKey, undefined, {\n assumeYes: opts.yes,\n force: opts.force,\n });\n\n switch (result.status) {\n case 'installed':\n console.log(result.message);\n console.log('Note: requires tmux 3.2+ for display-menu keybindings.');\n break;\n case 'already-installed':\n console.log(result.message);\n break;\n case 'conflict':\n console.log(`Key ${result.conflictKey} is already bound:`);\n console.log(` ${result.existingBinding}`);\n console.log('');\n console.log('Options:');\n console.log(' - Pick a different cycle key: sis admin setup-keybind M-w');\n console.log(' - Run \"sis admin check-keybinds\" for a full breakdown');\n console.log(' - Override and overwrite: sis admin setup-keybind --force');\n process.exitCode = 1;\n break;\n case 'unsupported-tmux':\n console.log(result.message);\n process.exitCode = 1;\n break;\n case 'requires-force':\n console.log(result.message);\n console.log('');\n console.log('Run \"sis admin check-keybinds\" first if you want the full decision tree before deciding.');\n process.exitCode = 1;\n break;\n case 'conf-modification-declined':\n console.log(result.message);\n console.log('');\n console.log('Re-run with --force to append automatically.');\n break;\n }\n });\n}\n","import { execSync } from 'node:child_process';\nimport { readFileSync } from 'node:fs';\nimport type { Command } from 'commander';\nimport {\n DEFAULT_CYCLE_KEY,\n DEFAULT_PREFIX_KEY,\n getExistingBinding,\n isSisyphusBinding,\n sisyphusTmuxConfPath,\n tmuxVersionAtLeast,\n userTmuxConfPath,\n} from '../tmux-setup.js';\n\ntype KeyState =\n | { kind: 'sisyphus'; binding: string }\n | { kind: 'conflict'; binding: string }\n | { kind: 'unbound' };\n\ninterface CheckResult {\n tmuxInstalled: boolean;\n tmuxServerRunning: boolean;\n tmuxVersion: string | null;\n tmuxVersionOk: boolean;\n inTmux: boolean;\n cycleKey: { key: string } & KeyState;\n prefixKey: { key: string } & KeyState;\n // tmux's *prefix* setting (set -g prefix). Hidden conflict: if user set prefix to C-s,\n // a root-table bind on C-s would silently shadow it.\n tmuxPrefix: string | null;\n prefixCollision: boolean;\n userConfPath: string | null;\n userConfAlreadySources: boolean;\n sisyphusConfPath: string;\n}\n\nfunction isTmuxInstalled(): boolean {\n try {\n execSync('which tmux', { stdio: 'pipe' });\n return true;\n } catch {\n return false;\n }\n}\n\nfunction getTmuxVersion(): string | null {\n try {\n return execSync('tmux -V', { stdio: ['pipe', 'pipe', 'pipe'] }).toString().trim();\n } catch {\n return null;\n }\n}\n\nfunction isTmuxServerRunning(): boolean {\n try {\n // `tmux list-sessions` errors with \"no server running\" when no server is up\n execSync('tmux list-sessions', { stdio: ['pipe', 'pipe', 'pipe'] });\n return true;\n } catch {\n return false;\n }\n}\n\nfunction getTmuxPrefix(): string | null {\n try {\n return execSync('tmux show-options -gv prefix', { stdio: ['pipe', 'pipe', 'pipe'] })\n .toString()\n .trim() || null;\n } catch {\n return null;\n }\n}\n\nfunction classifyKey(key: string, serverRunning: boolean): KeyState {\n if (!serverRunning) return { kind: 'unbound' };\n const binding = getExistingBinding(key);\n if (binding === null) return { kind: 'unbound' };\n if (isSisyphusBinding(binding)) return { kind: 'sisyphus', binding };\n return { kind: 'conflict', binding };\n}\n\nfunction runCheck(): CheckResult {\n const tmuxInstalled = isTmuxInstalled();\n const tmuxVersion = tmuxInstalled ? getTmuxVersion() : null;\n const tmuxVersionOk = tmuxInstalled ? tmuxVersionAtLeast(3, 2) : false;\n const tmuxServerRunning = tmuxInstalled ? isTmuxServerRunning() : false;\n const inTmux = !!process.env['TMUX'];\n const cycleKey = { key: DEFAULT_CYCLE_KEY, ...classifyKey(DEFAULT_CYCLE_KEY, tmuxServerRunning) };\n const prefixKey = { key: DEFAULT_PREFIX_KEY, ...classifyKey(DEFAULT_PREFIX_KEY, tmuxServerRunning) };\n const tmuxPrefix = tmuxServerRunning ? getTmuxPrefix() : null;\n const prefixCollision = tmuxPrefix !== null && tmuxPrefix === DEFAULT_PREFIX_KEY;\n\n const sisyphusConfPath = sisyphusTmuxConfPath();\n const userConfPath = userTmuxConfPath();\n let userConfAlreadySources = false;\n if (userConfPath !== null) {\n try {\n userConfAlreadySources = readFileSync(userConfPath, 'utf-8').includes(sisyphusConfPath);\n } catch {\n /* unreadable conf — treat as not-sourcing */\n }\n }\n\n return {\n tmuxInstalled,\n tmuxServerRunning,\n tmuxVersion,\n tmuxVersionOk,\n inTmux,\n cycleKey,\n prefixKey,\n tmuxPrefix,\n prefixCollision,\n userConfPath,\n userConfAlreadySources,\n sisyphusConfPath,\n };\n}\n\nfunction fmtKeyState(k: { key: string } & KeyState): string {\n switch (k.kind) {\n case 'sisyphus':\n return `${k.key}: sisyphus (${k.binding})`;\n case 'conflict':\n return `${k.key}: CONFLICT — already bound: ${k.binding}`;\n case 'unbound':\n return `${k.key}: unbound`;\n }\n}\n\nfunction printInstructions(r: CheckResult): void {\n const bothSisyphus = r.cycleKey.kind === 'sisyphus' && r.prefixKey.kind === 'sisyphus';\n const anyConflict = r.cycleKey.kind === 'conflict' || r.prefixKey.kind === 'conflict';\n const wouldModifyUserConf = r.userConfPath !== null && !r.userConfAlreadySources;\n const safeAutoInstall = !anyConflict && !r.prefixCollision && !wouldModifyUserConf;\n\n const tmuxVersionLabel = r.tmuxVersion === null ? '(none)' : r.tmuxVersion;\n const tmuxPrefixLabel = r.tmuxPrefix === null ? '(default C-b)' : r.tmuxPrefix;\n const userConfLabel = r.userConfPath === null ? '(none found)' : r.userConfPath;\n const userConfForCopy = r.userConfPath === null ? '~/.tmux.conf' : r.userConfPath;\n\n console.log(`\n<claude-instructions>\n# Sisyphus Keybind Precheck\n\nRun this BEFORE asking the user to try any sisyphus keybind (e.g. \\`Right Option+s\\`,\n\\`C-s h\\`, \\`C-s ?\\`). If the keybinds aren't actually wired up, the user will press\nthe key and nothing will happen — confusing, looks broken.\n\n## Environment Data\n- tmuxInstalled: ${r.tmuxInstalled}\n- tmuxVersion: ${tmuxVersionLabel}\n- tmuxVersionOk: ${r.tmuxVersionOk} (sisyphus needs 3.2+ for display-menu)\n- tmuxServerRunning: ${r.tmuxServerRunning}\n- inTmux (\\$TMUX set): ${r.inTmux}\n- ${fmtKeyState(r.cycleKey)}\n- ${fmtKeyState(r.prefixKey)}\n- tmuxPrefix (\\`set -g prefix\\`): ${tmuxPrefixLabel}\n- prefixCollision: ${r.prefixCollision} (true = user's tmux prefix is ${DEFAULT_PREFIX_KEY}; binding it in root would shadow it)\n- userConfPath: ${userConfLabel}\n- userConfAlreadySources: ${r.userConfAlreadySources}\n- sisyphusConfPath: ${r.sisyphusConfPath}\n\n## Decision\n\nPick exactly one path. Do NOT proceed past this check until both keys read \"sisyphus\".\n\n### Path A — All wired, proceed\n**Trigger:** cycleKey is \"sisyphus\" AND prefixKey is \"sisyphus\".\n**Action:** ${bothSisyphus ? '✓ THIS IS YOUR PATH.' : '(not applicable)'} Confirm briefly and continue with the onboarding step that needs keybinds.\n\n### Path B — Safe to auto-install\n**Trigger:** No conflicts, no prefix collision, AND (no user tmux.conf OR it already sources sisyphus).\n**Action:** ${safeAutoInstall && !bothSisyphus ? '✓ THIS IS YOUR PATH.' : '(not applicable)'} Run:\n\\`\\`\\`\nsis admin setup-keybind --yes\n\\`\\`\\`\nThis installs the helper scripts in ~/.sisyphus/bin/ and applies the bindings to the live\ntmux server. No user files are clobbered (none to clobber, or already wired).\n\n### Path C — Would append a line to the user's tmux.conf\n**Trigger:** No conflicts, no prefix collision, but ${userConfForCopy} exists and doesn't yet source ${r.sisyphusConfPath}.\n**Action:** ${!safeAutoInstall && !anyConflict && !r.prefixCollision && wouldModifyUserConf && !bothSisyphus ? '✓ THIS IS YOUR PATH.' : '(not applicable)'} Ask the user to choose:\n\n 1. **Persistent (recommended).** \"I'll add one line to ${userConfForCopy} so the bindings survive tmux restarts. The line is marked \\`# sisyphus-managed — do not edit\\` and is grep-removable later.\"\n Run: \\`sis admin setup-keybind --yes\\`\n\n 2. **Live only, no file changes.** \"I'll wire the bindings into your current tmux server without touching any config file. They'll vanish when you restart tmux, and you can re-run \\`sis admin setup-keybind\\` anytime to make them stick.\"\n Run: \\`sis admin setup-keybind\\` (no --yes; non-TTY auto-declines the conf prompt while still applying live bindings + installing helper scripts)\n\n### Path D — Conflict on ${DEFAULT_CYCLE_KEY} or ${DEFAULT_PREFIX_KEY}\n**Trigger:** cycleKey or prefixKey is \"CONFLICT\".\n**Action:** ${anyConflict ? '✓ THIS IS YOUR PATH.' : '(not applicable)'} The user already has these keys bound to something else. Show them the conflicting bindings (above) and offer:\n\n 1. **Pick alternate keys.** Re-run with a different cycle key — e.g. \\`M-S\\`, \\`M-w\\`, \\`M-j\\`, \\`M-\\\\\\`\\`:\n \\`\\`\\`\n sis admin setup-keybind M-w\n \\`\\`\\`\n This still uses C-s for the prefix; if the prefix also conflicts, you'll need to wire\n directly (option 3 below), since setup-keybind only takes a custom cycle key.\n\n 2. **Skip keybinds entirely.** The user can drive sisyphus from the CLI: \\`sis dashboard\\`,\n \\`sis status\\`, \\`sis start\\`, \\`sis session resume\\`. Lose tmux quick-actions, keep\n existing bindings.\n\n 3. **Wire commands directly (advanced).** Bypass setup-keybind and bind individual\n sisyphus actions to keys the user picks. Helper scripts must already exist — if\n ~/.sisyphus/bin/sisyphus-cycle is missing, you cannot use this path until setup-keybind\n has run at least once successfully (try option 1 first).\n \\`\\`\\`\n # cycle sessions on a key the user chooses (replace M-w):\n tmux bind-key -T root M-w run-shell \"$HOME/.sisyphus/bin/sisyphus-cycle\"\n\n # open the dashboard directly on a key (replace M-h):\n tmux bind-key -T root M-h run-shell \"$HOME/.sisyphus/bin/sisyphus-home\"\n \\`\\`\\`\n These apply only to the running tmux server. To persist, append the same lines to\n ${userConfForCopy}.\n\n### Path E — Hidden prefix collision\n**Trigger:** prefixCollision is true (the user's \\`set -g prefix\\` is already ${DEFAULT_PREFIX_KEY}).\n**Action:** ${r.prefixCollision ? '✓ THIS IS YOUR PATH.' : '(not applicable)'} \\`tmux list-keys\\` won't surface this as a binding conflict, but installing the C-s root-table menu would shadow the user's prefix. Tell the user:\n\n > \"Your tmux prefix is set to ${DEFAULT_PREFIX_KEY}. Sisyphus wants to bind ${DEFAULT_PREFIX_KEY} in the root table for its menu, which would shadow your prefix. Options: (a) move your prefix (e.g. \\`set -g prefix C-a\\`) and let sisyphus take ${DEFAULT_PREFIX_KEY}, or (b) skip the menu binding — only \\`${DEFAULT_CYCLE_KEY}\\` cycle gets installed.\"\n\n For (b), wire just the cycle key directly:\n \\`\\`\\`\n sis admin setup-keybind ${DEFAULT_CYCLE_KEY}\n # then unbind C-s if setup-keybind ended up taking it:\n tmux unbind-key -T root ${DEFAULT_PREFIX_KEY}\n \\`\\`\\`\n\n### Path F — tmux not ready\n**Trigger:** any of: tmuxInstalled=false, tmuxVersionOk=false, tmuxServerRunning=false.\n**Action:** ${(!r.tmuxInstalled || !r.tmuxVersionOk || !r.tmuxServerRunning) ? '✓ THIS IS YOUR PATH.' : '(not applicable)'} Don't install keybinds yet. Fix the precondition:\n- tmuxInstalled=false → \\`brew install tmux\\` (macOS) or your package manager\n- tmuxVersionOk=false → upgrade tmux to 3.2+\n- tmuxServerRunning=false → user needs to run \\`tmux\\` (or attach to an existing session) before live bindings can be installed or tested\n\nAfter fixing, re-run \\`sis admin check-keybinds\\`.\n\n## After acting\nRe-run \\`sis admin check-keybinds\\` to confirm both keys read \"sisyphus\", THEN ask the\nuser to try the keybind. Don't skip the verification — \\`setup-keybind\\` can fail silently\nif the tmux server dies between commands.\n</claude-instructions>\n`);\n}\n\nexport function registerCheckKeybinds(program: Command): void {\n program\n .command('check-keybinds')\n .description('Verify tmux keybind state before asking the user to try a sisyphus keybind')\n .option('--json', 'Print raw JSON state instead of Claude instructions')\n .action((opts: { json?: boolean }) => {\n const result = runCheck();\n if (opts.json) {\n console.log(JSON.stringify(result, null, 2));\n return;\n }\n printInstructions(result);\n });\n}\n","import { execSync } from 'node:child_process';\nimport { existsSync, readFileSync } from 'node:fs';\nimport { homedir } from 'node:os';\nimport { join } from 'node:path';\nimport type { Command } from 'commander';\nimport { globalConfigPath, daemonPidPath } from '../../shared/paths.js';\nimport type { StatusBarConfig } from '../../shared/types.js';\n\nconst SISYPHUS_LEFT_TOKEN = '@sisyphus_left';\nconst SISYPHUS_RIGHT_TOKEN = '@sisyphus_right';\n// tmux's compiled-in defaults (vary slightly by version, but these are the canonical\n// strings new users see). Used for \"is the user on stock tmux?\" detection.\nconst TMUX_DEFAULT_STATUS_LEFT = '[#S] ';\nconst TMUX_DEFAULT_STATUS_RIGHT_PREFIX = '\"#{=21:pane_title}\"'; // matches default tmux right\n\ninterface TmuxOptionSnapshot {\n status: string | null;\n statusLeft: string | null;\n statusRight: string | null;\n statusPosition: string | null;\n statusStyle: string | null;\n statusInterval: string | null;\n}\n\ninterface UserConfState {\n path: string | null;\n setsStatusLeft: boolean;\n setsStatusRight: boolean;\n sourcesSisyphusManaged: boolean;\n}\n\ntype StatusBarState =\n | 'wired'\n | 'partial-left-only'\n | 'partial-right-only'\n | 'custom-no-sisyphus'\n | 'tmux-default'\n | 'disabled'\n | 'tmux-not-ready';\n\ninterface CheckResult {\n tmuxInstalled: boolean;\n tmuxServerRunning: boolean;\n daemonRunning: boolean;\n tmuxOptions: TmuxOptionSnapshot;\n userConf: UserConfState;\n globalConfig: StatusBarConfig | null;\n state: StatusBarState;\n // Convenience for the renderer.\n referencesSisyphusLeft: boolean;\n referencesSisyphusRight: boolean;\n}\n\nfunction isTmuxInstalled(): boolean {\n try {\n execSync('which tmux', { stdio: 'pipe' });\n return true;\n } catch {\n return false;\n }\n}\n\nfunction isTmuxServerRunning(): boolean {\n try {\n execSync('tmux list-sessions', { stdio: ['pipe', 'pipe', 'pipe'] });\n return true;\n } catch {\n return false;\n }\n}\n\nfunction isDaemonRunning(): boolean {\n const pidFile = daemonPidPath();\n if (!existsSync(pidFile)) return false;\n try {\n const pid = parseInt(readFileSync(pidFile, 'utf-8').trim(), 10);\n if (Number.isNaN(pid) || pid <= 0) return false;\n // Signal 0 — checks existence without sending a real signal. Throws if process is gone.\n process.kill(pid, 0);\n return true;\n } catch {\n return false;\n }\n}\n\nfunction showOption(name: string): string | null {\n try {\n const out = execSync(`tmux show-options -g ${name}`, { stdio: ['pipe', 'pipe', 'pipe'] })\n .toString()\n .trim();\n if (out.length === 0) return null;\n // tmux output: `<name> \"<value>\"` or `<name> <value>`\n const prefix = `${name} `;\n const stripped = out.startsWith(prefix) ? out.slice(prefix.length) : out;\n // Strip surrounding quotes if present.\n if (stripped.startsWith('\"') && stripped.endsWith('\"') && stripped.length >= 2) {\n return stripped.slice(1, -1);\n }\n return stripped;\n } catch {\n return null;\n }\n}\n\nfunction probeTmuxOptions(serverRunning: boolean): TmuxOptionSnapshot {\n if (!serverRunning) {\n return {\n status: null,\n statusLeft: null,\n statusRight: null,\n statusPosition: null,\n statusStyle: null,\n statusInterval: null,\n };\n }\n return {\n status: showOption('status'),\n statusLeft: showOption('status-left'),\n statusRight: showOption('status-right'),\n statusPosition: showOption('status-position'),\n statusStyle: showOption('status-style'),\n statusInterval: showOption('status-interval'),\n };\n}\n\nfunction findUserTmuxConf(): string | null {\n const xdg = join(homedir(), '.config', 'tmux', 'tmux.conf');\n const dotfile = join(homedir(), '.tmux.conf');\n if (existsSync(xdg)) return xdg;\n if (existsSync(dotfile)) return dotfile;\n return null;\n}\n\nfunction probeUserConf(): UserConfState {\n const path = findUserTmuxConf();\n if (path === null) {\n return { path: null, setsStatusLeft: false, setsStatusRight: false, sourcesSisyphusManaged: false };\n }\n let contents = '';\n try {\n contents = readFileSync(path, 'utf-8');\n } catch {\n return { path, setsStatusLeft: false, setsStatusRight: false, sourcesSisyphusManaged: false };\n }\n // Match \"set -g status-left\" or \"set-option -g status-left\" (loose grep, ignore commented lines).\n const lines = contents.split('\\n').filter((line) => !line.trim().startsWith('#'));\n const setsStatusLeft = lines.some((line) => /^\\s*(set|set-option)\\s+-g(?:\\s+-\\w+)*\\s+status-left\\b/.test(line));\n const setsStatusRight = lines.some((line) => /^\\s*(set|set-option)\\s+-g(?:\\s+-\\w+)*\\s+status-right\\b/.test(line));\n const sourcesSisyphusManaged = contents.includes(join(homedir(), '.sisyphus', 'tmux.conf'));\n return { path, setsStatusLeft, setsStatusRight, sourcesSisyphusManaged };\n}\n\nfunction loadGlobalSisyphusConfig(): StatusBarConfig | null {\n const path = globalConfigPath();\n if (!existsSync(path)) return null;\n try {\n const parsed = JSON.parse(readFileSync(path, 'utf-8')) as { statusBar?: StatusBarConfig };\n return parsed.statusBar === undefined ? null : parsed.statusBar;\n } catch {\n return null;\n }\n}\n\nfunction classifyState(opts: TmuxOptionSnapshot, serverRunning: boolean): {\n state: StatusBarState;\n referencesSisyphusLeft: boolean;\n referencesSisyphusRight: boolean;\n} {\n if (!serverRunning) {\n return { state: 'tmux-not-ready', referencesSisyphusLeft: false, referencesSisyphusRight: false };\n }\n if (opts.status === 'off') {\n return { state: 'disabled', referencesSisyphusLeft: false, referencesSisyphusRight: false };\n }\n const referencesSisyphusLeft = opts.statusLeft !== null && opts.statusLeft.includes(SISYPHUS_LEFT_TOKEN);\n const referencesSisyphusRight = opts.statusRight !== null && opts.statusRight.includes(SISYPHUS_RIGHT_TOKEN);\n if (referencesSisyphusLeft && referencesSisyphusRight) {\n return { state: 'wired', referencesSisyphusLeft, referencesSisyphusRight };\n }\n if (referencesSisyphusLeft) {\n return { state: 'partial-left-only', referencesSisyphusLeft, referencesSisyphusRight };\n }\n if (referencesSisyphusRight) {\n return { state: 'partial-right-only', referencesSisyphusLeft, referencesSisyphusRight };\n }\n // Distinguish stock tmux vs user-customized.\n const isStock =\n (opts.statusLeft === TMUX_DEFAULT_STATUS_LEFT || opts.statusLeft === null) &&\n (opts.statusRight === null || opts.statusRight.includes(TMUX_DEFAULT_STATUS_RIGHT_PREFIX));\n return {\n state: isStock ? 'tmux-default' : 'custom-no-sisyphus',\n referencesSisyphusLeft,\n referencesSisyphusRight,\n };\n}\n\nfunction runCheck(): CheckResult {\n const tmuxInstalled = isTmuxInstalled();\n const tmuxServerRunning = tmuxInstalled ? isTmuxServerRunning() : false;\n const tmuxOptions = probeTmuxOptions(tmuxServerRunning);\n const userConf = probeUserConf();\n const globalConfig = loadGlobalSisyphusConfig();\n const daemonRunning = isDaemonRunning();\n const { state, referencesSisyphusLeft, referencesSisyphusRight } = classifyState(tmuxOptions, tmuxServerRunning);\n return {\n tmuxInstalled,\n tmuxServerRunning,\n daemonRunning,\n tmuxOptions,\n userConf,\n globalConfig,\n state,\n referencesSisyphusLeft,\n referencesSisyphusRight,\n };\n}\n\nfunction fmtOption(value: string | null): string {\n if (value === null) return '(unset)';\n return JSON.stringify(value);\n}\n\nfunction renderConfigSummary(cfg: StatusBarConfig | null): string {\n if (cfg === null) return '(no statusBar block in ~/.sisyphus/config.json — defaults apply)';\n const parts: string[] = [];\n if (cfg.enabled === false) parts.push('enabled: false (DISABLED)');\n if (cfg.left !== undefined) parts.push(`left: [${cfg.left.join(', ')}]`);\n if (cfg.right !== undefined) parts.push(`right: [${cfg.right.join(', ')}]`);\n if (cfg.colors !== undefined) parts.push(`colors: ${JSON.stringify(cfg.colors)}`);\n if (cfg.segments !== undefined) {\n const segNames = Object.keys(cfg.segments);\n if (segNames.length > 0) parts.push(`per-segment overrides: ${segNames.join(', ')}`);\n }\n if (parts.length === 0) return '(statusBar block exists but is empty — defaults apply)';\n return parts.join('\\n ');\n}\n\nfunction printInstructions(r: CheckResult): void {\n const userConfPath = r.userConf.path === null ? '~/.tmux.conf (none found)' : r.userConf.path;\n const userConfForCopy = r.userConf.path === null ? '~/.tmux.conf' : r.userConf.path;\n\n console.log(`\n<claude-instructions>\n# Sisyphus Statusbar Helper\n\nThis is a READ-ONLY check. Use it to figure out how to help the user improve their\ntmux statusbar with sisyphus segments WITHOUT clobbering their existing setup. The\nuser's tmux config is theirs — never overwrite it. Append, suggest snippets, or\nnudge them to edit ~/.sisyphus/config.json.\n\n## Environment Data\n- tmuxInstalled: ${r.tmuxInstalled}\n- tmuxServerRunning: ${r.tmuxServerRunning}\n- daemonRunning: ${r.daemonRunning} (false = @sisyphus_left/@sisyphus_right won't get populated, statusbar will look broken until daemon is up)\n\n### Live tmux options\n- status: ${fmtOption(r.tmuxOptions.status)}\n- status-left: ${fmtOption(r.tmuxOptions.statusLeft)}\n- status-right: ${fmtOption(r.tmuxOptions.statusRight)}\n- status-position: ${fmtOption(r.tmuxOptions.statusPosition)}\n- status-style: ${fmtOption(r.tmuxOptions.statusStyle)}\n- status-interval: ${fmtOption(r.tmuxOptions.statusInterval)}\n- referencesSisyphusLeft: ${r.referencesSisyphusLeft}\n- referencesSisyphusRight: ${r.referencesSisyphusRight}\n\n### User tmux config\n- path: ${userConfPath}\n- setsStatusLeft: ${r.userConf.setsStatusLeft}\n- setsStatusRight: ${r.userConf.setsStatusRight}\n- sourcesSisyphusManaged: ${r.userConf.sourcesSisyphusManaged} (sources ~/.sisyphus/tmux.conf — keybinds, NOT statusbar; included for context)\n\n### Sisyphus statusbar config (~/.sisyphus/config.json → statusBar)\n ${renderConfigSummary(r.globalConfig)}\n\n### Available segments\n- session-name (left default) — current tmux session name\n- windows (left default) — tmux window list with active highlight\n- sessions (right default) — all tmux sessions with claude-state colors\n- sisyphus-sessions (right default) — sisyphus-managed sessions with phase indicators\n- companion (right default) — companion mood/state pill\n- clock — separate %H:%M (NOT a sisyphus segment; tmux renders it inline; the default\n ~/.tmux.conf appends \\`#[fg=...]#[bg=...] %H:%M \\` after #{E:@sisyphus_right})\n\n## Detected state: **${r.state}**\n\nPick exactly one path. Each path tells you what to ask the user and what to do.\n\n### Path A — Already wired (state: wired)\n**Trigger:** status-left and status-right both reference @sisyphus_left/@sisyphus_right.\n**Action:** ${r.state === 'wired' ? '✓ THIS IS YOUR PATH.' : '(not applicable)'}\n\nThe plumbing is correct. ${r.daemonRunning ? '' : 'BUT daemon is not running — run `sisyphusd start` (or restart) so the @sisyphus_* options get populated. '}Now offer to **customize** what's shown:\n\n 1. **Reorder or hide segments.** Edit \\`~/.sisyphus/config.json\\`, set \\`statusBar.left\\` / \\`statusBar.right\\` to the array of segment ids you want (in order). Example to hide windows and reorder:\n \\`\\`\\`json\n {\n \"statusBar\": {\n \"left\": [\"session-name\"],\n \"right\": [\"sisyphus-sessions\", \"companion\"]\n }\n }\n \\`\\`\\`\n 2. **Recolor.** \\`statusBar.colors\\` overrides processing/stopped/idle/activeBg/activeText/inactiveText. \\`statusBar.segments.<id>.bg\\` overrides per-segment band background.\n 3. **Disable a single segment.** Remove its id from the left/right arrays.\n 4. **Disable the whole bar.** \\`statusBar.enabled: false\\` — daemon stops writing the options; the user's status-left/right will then render as literal \\`#{E:@sisyphus_left}\\` (which tmux silently treats as empty).\n 5. **Restart the daemon** after any config change: \\`sisyphusd restart\\`. Changes don't auto-apply.\n\nAsk the user what they want to change. Edit \\`~/.sisyphus/config.json\\` for them — that file is sisyphus-managed config, safe to edit. Don't touch their \\`~/.tmux.conf\\`.\n\n### Path B — Partial wiring (state: partial-left-only or partial-right-only)\n**Trigger:** Only one side references sisyphus.\n**Action:** ${r.state === 'partial-left-only' || r.state === 'partial-right-only' ? '✓ THIS IS YOUR PATH.' : '(not applicable)'}\n\nTheir config is half-wired. Show them the missing side:\n - Missing left → suggest adding \\`set -g status-left \"#{E:@sisyphus_left}\"\\` to ${userConfForCopy}\n - Missing right → suggest adding \\`set -g status-right \"#{E:@sisyphus_right}#[fg=#2d2f33]#[bg=#2d2f33,fg=#b0a898] %H:%M \"\\`\n\nDon't auto-edit their config — present the snippet and ask if they want you to append it.\n\n### Path C — Stock tmux statusbar (state: tmux-default)\n**Trigger:** status-left/right are tmux defaults; user has no custom statusbar.\n**Action:** ${r.state === 'tmux-default' ? '✓ THIS IS YOUR PATH.' : '(not applicable)'}\n\nEasiest case. Two options to offer:\n\n 1. **Full sisyphus statusbar.** Append these lines to ${userConfForCopy} (NOT a clobber — pure additive):\n \\`\\`\\`tmux\n # --- Sisyphus statusbar ---\n set -g status on\n set -g status-style \"bg=#1d1e21,fg=#d4cbb8\"\n set -g status-position bottom\n set -g status-left \"#{E:@sisyphus_left}\"\n set -g status-left-length 250\n set -g status-right \"#{E:@sisyphus_right}#[fg=#2d2f33]#[bg=#2d2f33,fg=#b0a898] %H:%M \"\n set -g status-right-length 250\n set -g status-interval 2\n set -g window-status-format \"\"\n set -g window-status-current-format \"\"\n set -g window-status-separator \"\"\n \\`\\`\\`\n ${r.userConf.path === null ? `Note: no tmux config exists yet. Create ${userConfForCopy} with these lines.` : ''}\n\n 2. **Minimal sisyphus pill on the right.** If they want to keep the stock left side and just add a single sisyphus pill on the right:\n \\`\\`\\`tmux\n set -g status-right \"#{E:@sisyphus_right}#[default] %H:%M \"\n set -g status-right-length 200\n \\`\\`\\`\n\nAfter appending, run \\`tmux source-file ${userConfForCopy}\\` so the change takes effect immediately.\n\n### Path D — User has a custom statusbar (state: custom-no-sisyphus)\n**Trigger:** status-left/right are user-customized but don't reference sisyphus tokens.\n**Action:** ${r.state === 'custom-no-sisyphus' ? '✓ THIS IS YOUR PATH.' : '(not applicable)'}\n\nThis is the most delicate case — they care enough to have customized their bar. **Do not overwrite.** Show them the current contents and offer additive integration:\n\nTheir current right side is currently:\n \\`\\`\\`\n ${r.tmuxOptions.statusRight === null ? '(unset)' : r.tmuxOptions.statusRight}\n \\`\\`\\`\nAnd left side:\n \\`\\`\\`\n ${r.tmuxOptions.statusLeft === null ? '(unset)' : r.tmuxOptions.statusLeft}\n \\`\\`\\`\n\nOffer three integration patterns and let the user pick:\n\n 1. **Append sisyphus to the right side** (most common — leaves their left alone):\n \\`\\`\\`tmux\n set -g status-right \"${r.tmuxOptions.statusRight === null ? '' : r.tmuxOptions.statusRight}#{E:@sisyphus_right}\"\n \\`\\`\\`\n Or prepend it (sisyphus content appears first/leftmost):\n \\`\\`\\`tmux\n set -g status-right \"#{E:@sisyphus_right}${r.tmuxOptions.statusRight === null ? '' : r.tmuxOptions.statusRight}\"\n \\`\\`\\`\n\n 2. **Append to the left side** (if they want session/windows pills at the start):\n \\`\\`\\`tmux\n set -g status-left \"${r.tmuxOptions.statusLeft === null ? '' : r.tmuxOptions.statusLeft}#{E:@sisyphus_left}\"\n \\`\\`\\`\n\n 3. **Slim sisyphus only.** If they only want one specific signal (e.g., just sisyphus-sessions), they can set \\`statusBar.right: [\"sisyphus-sessions\"]\\` in \\`~/.sisyphus/config.json\\` and then append \\`#{E:@sisyphus_right}\\` to their existing right side. The composed string will only contain that one segment.\n\nImportant: the user's existing string may include format conditionals or special characters; use the exact value above when proposing the snippet (do not retype). Confirm with the user before editing ${userConfForCopy} — present the diff first.\n\n### Path E — Statusbar is disabled (state: disabled)\n**Trigger:** \\`set -g status off\\`.\n**Action:** ${r.state === 'disabled' ? '✓ THIS IS YOUR PATH.' : '(not applicable)'}\n\nThe user explicitly turned off the statusbar. Don't enable it without asking. Suggest:\n - \"I noticed you have the statusbar disabled (\\`set -g status off\\` in your config). Sisyphus needs it on to show session state. Want me to enable it and add a minimal sisyphus pill, or leave it as-is?\"\n\nIf they say yes → fall through to Path C, option 2 (minimal pill).\n\n### Path F — tmux not ready (state: tmux-not-ready)\n**Trigger:** tmux isn't installed or no server is running.\n**Action:** ${r.state === 'tmux-not-ready' ? '✓ THIS IS YOUR PATH.' : '(not applicable)'}\n\nDon't propose statusbar changes yet:\n - tmuxInstalled=false → install tmux first (\\`brew install tmux\\` on macOS)\n - tmuxServerRunning=false → user needs to run \\`tmux\\` (or attach to a session)\n\nRe-run \\`sis admin check-statusbar\\` once tmux is up.\n\n## Daemon reminder\nEven with status-left/right perfectly wired, the bar will show literal \\`#{E:@sisyphus_left}\\` (rendered as empty) until the daemon is running and has populated the option at least once. Always end this flow by checking \\`daemonRunning: true\\` above; if false, run \\`sisyphusd start\\` (or \\`sisyphusd restart\\` if it's stuck).\n\n## After acting\nRe-run \\`sis admin check-statusbar\\` to verify the new state. If anything looks wrong, the JSON form (\\`sis admin check-statusbar --json\\`) is easier to diff against expected values.\n</claude-instructions>\n`);\n}\n\nexport function registerCheckStatusbar(program: Command): void {\n program\n .command('check-statusbar')\n .description('Inspect tmux statusbar state and emit a Claude decision tree for non-clobbering integration')\n .option('--json', 'Print raw JSON state instead of Claude instructions')\n .action((opts: { json?: boolean }) => {\n const result = runCheck();\n if (opts.json) {\n console.log(JSON.stringify(result, null, 2));\n return;\n }\n printInstructions(result);\n });\n}\n","import type { Command } from 'commander';\nimport { execSync } from 'node:child_process';\nimport { shellQuote } from '../../shared/shell.js';\nimport { openDashboardWindow } from './dashboard.js';\n\n/**\n * `sis admin home-init <name> <cwd>`\n *\n * Bootstrap a tmux home session — a regular (non-`ssyph_`-prefixed) session\n * with `@sisyphus_cwd` set, hosting the dashboard in window 1. Idempotent:\n * re-running on an existing session is a no-op aside from re-focusing the\n * dashboard window.\n *\n * Designed to run on the cloud box itself (over SSH) so `import.meta.dirname`\n * resolves to the box's installed sisyphi `tui.js`. Does not require a tmux\n * client — talks to the tmux server directly with `-t` targeting.\n */\nexport function registerHomeInit(parent: Command): void {\n parent\n .command('home-init <name> <cwd>')\n .description('Bootstrap a tmux home session with the sisyphus dashboard.')\n .action((name: string, cwd: string) => {\n ensureSession(name, cwd);\n setSessionCwd(name, cwd);\n openDashboardWindow(name, cwd);\n });\n}\n\nfunction sessionExists(name: string): boolean {\n try {\n execSync(`tmux has-session -t ${shellQuote(name)}`, { stdio: 'pipe' });\n return true;\n } catch {\n return false;\n }\n}\n\nfunction ensureSession(name: string, cwd: string): void {\n if (sessionExists(name)) return;\n execSync(\n `tmux new-session -d -s ${shellQuote(name)} -c ${shellQuote(cwd)}`,\n { stdio: 'pipe' },\n );\n}\n\nfunction setSessionCwd(name: string, cwd: string): void {\n execSync(\n `tmux set-option -t ${shellQuote(name)} @sisyphus_cwd ${shellQuote(cwd.replace(/\\/+$/, ''))}`,\n { stdio: 'pipe' },\n );\n}\n","import { execSync } from 'node:child_process';\nimport { existsSync, statSync } from 'node:fs';\nimport { homedir } from 'node:os';\nimport { join } from 'node:path';\nimport type { Command } from 'commander';\nimport { daemonLogPath, daemonPidPath, globalDir, socketPath } from '../../shared/paths.js';\nimport { isInstalled } from '../install.js';\nimport { detectTerminal, checkItermOptionKey, isNvimAvailable, isTermrenderAvailable } from '../onboard.js';\nimport { resolveInstalledPlugin } from '../../daemon/plugins.js';\nimport { cycleScriptPath, DEFAULT_CYCLE_KEY, getExistingBinding, isSisyphusBinding, sisyphusTmuxConfPath } from '../tmux-setup.js';\n\ninterface Check {\n name: string;\n status: 'ok' | 'warn' | 'fail';\n detail: string;\n fix?: string;\n}\n\nfunction checkNodeVersion(): Check {\n const major = parseInt(process.versions.node.split('.')[0]!, 10);\n if (major < 22) {\n return { name: 'Node.js', status: 'fail', detail: `v${process.versions.node} (v22+ required)`, fix: 'Install Node.js 22+: https://nodejs.org' };\n }\n return { name: 'Node.js', status: 'ok', detail: `v${process.versions.node}` };\n}\n\nfunction checkClaudeCli(): Check {\n try {\n execSync('which claude', { stdio: 'pipe' });\n return { name: 'Claude CLI', status: 'ok', detail: 'Found on PATH' };\n } catch {\n return {\n name: 'Claude CLI',\n status: 'fail',\n detail: 'Not found on PATH',\n fix: 'Install Claude Code: https://docs.anthropic.com/en/docs/claude-code/overview',\n };\n }\n}\n\nfunction checkGit(): Check {\n try {\n const version = execSync('git --version', { encoding: 'utf-8', stdio: 'pipe' }).trim();\n return { name: 'git', status: 'ok', detail: version };\n } catch {\n return { name: 'git', status: 'fail', detail: 'Not found on PATH', fix: 'Install git: https://git-scm.com/downloads' };\n }\n}\n\nfunction checkTmuxVersion(): Check {\n try {\n const version = execSync('tmux -V', { encoding: 'utf-8', stdio: 'pipe' }).trim();\n // Parse \"tmux X.Y\" or \"tmux next-X.Y\"\n const match = version.match(/(\\d+\\.\\d+)/);\n if (!match) return { name: 'tmux version', status: 'warn', detail: `Could not parse version: ${version}` };\n const ver = parseFloat(match[1]);\n if (ver < 3.2) {\n const upgradeHint = process.platform === 'darwin' ? 'brew install tmux (or upgrade)' : 'apt install tmux (Debian/Ubuntu) or your package manager';\n return { name: 'tmux version', status: 'warn', detail: `${version} (3.2+ recommended for popup support)`, fix: upgradeHint };\n }\n return { name: 'tmux version', status: 'ok', detail: version };\n } catch {\n return { name: 'tmux version', status: 'warn', detail: 'Could not determine version' };\n }\n}\n\nfunction checkDaemonInstalled(): Check {\n if (process.platform === 'darwin') {\n if (isInstalled()) {\n return { name: 'Daemon plist', status: 'ok', detail: 'Installed in LaunchAgents' };\n }\n return {\n name: 'Daemon plist',\n status: 'fail',\n detail: 'Not installed',\n fix: 'Run any sis command to auto-install, or: sis start \"test\"',\n };\n }\n // Linux: check if PID file exists (daemon started manually)\n const pid = daemonPidPath();\n if (existsSync(pid)) {\n return { name: 'Daemon setup', status: 'ok', detail: `PID file found at ${pid}` };\n }\n return {\n name: 'Daemon setup',\n status: 'fail',\n detail: 'Daemon not running (no PID file)',\n fix: 'Start manually: sisyphusd & — or configure via systemd',\n };\n}\n\nfunction checkDaemonRunning(): Check {\n const pid = daemonPidPath();\n if (!existsSync(pid)) {\n const fix = process.platform === 'darwin'\n ? 'launchctl load -w ~/Library/LaunchAgents/com.sisyphus.daemon.plist'\n : 'sisyphusd & — or check if the process is running';\n return {\n name: 'Daemon process',\n status: 'fail',\n detail: 'No PID file found',\n fix,\n };\n }\n try {\n const sock = socketPath();\n execSync(`test -S \"${sock}\"`, { stdio: 'pipe' });\n return { name: 'Daemon process', status: 'ok', detail: `Socket at ${sock}` };\n } catch {\n return {\n name: 'Daemon process',\n status: 'warn',\n detail: 'PID file exists but socket not found',\n fix: `Check logs: tail -20 ${daemonLogPath()}`,\n };\n }\n}\n\nfunction checkTmux(): Check {\n try {\n execSync('which tmux', { stdio: 'pipe' });\n } catch {\n const installHint = process.platform === 'darwin' ? 'brew install tmux' : 'apt install tmux (Debian/Ubuntu) or your package manager';\n return { name: 'tmux', status: 'fail', detail: 'Not found on PATH', fix: installHint };\n }\n try {\n execSync('tmux list-sessions', { stdio: 'pipe' });\n return { name: 'tmux', status: 'ok', detail: 'Running' };\n } catch {\n return { name: 'tmux', status: 'warn', detail: 'Installed but no server running' };\n }\n}\n\nfunction checkCycleScript(): Check {\n const path = cycleScriptPath();\n if (!existsSync(path)) {\n return {\n name: 'Cycle script',\n status: 'fail',\n detail: `Not found at ${path}`,\n fix: 'sis admin setup-keybind',\n };\n }\n try {\n const mode = statSync(path).mode;\n if ((mode & 0o111) === 0) {\n return {\n name: 'Cycle script',\n status: 'fail',\n detail: 'Not executable',\n fix: `chmod +x ${path}`,\n };\n }\n } catch { /* ignore stat errors */ }\n return { name: 'Cycle script', status: 'ok', detail: path };\n}\n\nfunction checkTmuxKeybind(): Check {\n const existing = getExistingBinding(DEFAULT_CYCLE_KEY);\n if (existing === null) {\n // Also check if the sisyphus tmux.conf exists (binding might be configured but tmux not running)\n if (existsSync(sisyphusTmuxConfPath())) {\n return {\n name: `Tmux keybind (${DEFAULT_CYCLE_KEY})`,\n status: 'warn',\n detail: 'Configured in sisyphus tmux.conf but not active (tmux may not be running)',\n };\n }\n return {\n name: `Tmux keybind (${DEFAULT_CYCLE_KEY})`,\n status: 'fail',\n detail: 'Not bound',\n fix: 'sis admin setup-keybind',\n };\n }\n if (isSisyphusBinding(existing)) {\n return { name: `Tmux keybind (${DEFAULT_CYCLE_KEY})`, status: 'ok', detail: 'Bound to sisyphus-cycle' };\n }\n return {\n name: `Tmux keybind (${DEFAULT_CYCLE_KEY})`,\n status: 'warn',\n detail: `Bound to something else: ${existing}`,\n fix: 'sis admin setup-keybind M-S (or another free key)',\n };\n}\n\nfunction checkGlobalDir(): Check {\n const dir = globalDir();\n if (existsSync(dir)) {\n return { name: 'Data directory', status: 'ok', detail: dir };\n }\n return { name: 'Data directory', status: 'warn', detail: `${dir} does not exist (created on first use)` };\n}\n\nfunction checkTerminal(): Check {\n if (process.platform !== 'darwin') {\n return { name: 'Terminal', status: 'ok', detail: 'Non-macOS (skipped)' };\n }\n const terminal = detectTerminal();\n if (terminal.isIterm) {\n return { name: 'Terminal', status: 'ok', detail: terminal.name };\n }\n return {\n name: 'Terminal',\n status: 'warn',\n detail: terminal.name ? terminal.name : 'unknown',\n fix: 'iTerm2 recommended for best experience: https://iterm2.com',\n };\n}\n\nfunction checkItermRightOptionKey(): Check | null {\n if (process.platform !== 'darwin') return null;\n const terminal = detectTerminal();\n if (!terminal.isIterm) return null;\n const result = checkItermOptionKey();\n if (!result.checked) return null;\n if (result.allCorrect) {\n return { name: 'Right Option Key', status: 'ok', detail: 'Esc+' };\n }\n const profiles = result.incorrectProfiles.map((p) => `\"${p}\"`).join(', ');\n return {\n name: 'Right Option Key',\n status: 'warn',\n detail: `Not Esc+ for ${profiles}`,\n fix: 'iTerm2 \\u2192 Settings \\u2192 Profiles \\u2192 Keys \\u2192 Right Option Key \\u2192 Esc+',\n };\n}\n\nfunction checkSisyphusPlugin(): Check {\n const installPath = resolveInstalledPlugin('sisyphus@sisyphus');\n if (installPath) {\n return { name: 'sisyphus@sisyphus plugin', status: 'ok', detail: installPath };\n }\n return {\n name: 'sisyphus@sisyphus plugin',\n status: 'warn',\n detail: 'Not installed (slash commands /sisyphus:begin, /sisyphus:autopsy, /sisyphus:configure-upload unavailable)',\n fix: 'sis admin setup',\n };\n}\n\nfunction checkTermrender(): Check {\n if (isTermrenderAvailable()) {\n try {\n const version = execSync('termrender --version', { encoding: 'utf-8', stdio: 'pipe' }).trim();\n return { name: 'termrender', status: 'ok', detail: version };\n } catch {\n return { name: 'termrender', status: 'ok', detail: 'installed' };\n }\n }\n return {\n name: 'termrender',\n status: 'warn',\n detail: 'Not installed (rich markdown rendering unavailable)',\n fix: 'pipx install termrender (or: pip install termrender)',\n };\n}\n\nfunction checkNvim(): Check {\n if (!isNvimAvailable()) {\n const fix = process.platform === 'darwin' ? 'brew install neovim' : 'Install neovim from https://neovim.io';\n return { name: 'nvim', status: 'warn', detail: 'Not installed', fix };\n }\n try {\n const version = execSync('nvim --version', { encoding: 'utf-8', stdio: 'pipe' }).split('\\n')[0]?.replace('NVIM ', '');\n return { name: 'nvim', status: 'ok', detail: version ?? 'installed' };\n } catch {\n return { name: 'nvim', status: 'ok', detail: 'installed' };\n }\n}\n\nfunction checkNotifyBinary(): Check | null {\n if (process.platform !== 'darwin') return null;\n const binary = join(homedir(), '.sisyphus', 'SisyphusNotify.app', 'Contents', 'MacOS', 'sisyphus-notify');\n if (existsSync(binary)) {\n return { name: 'Notifications', status: 'ok', detail: 'SisyphusNotify.app built' };\n }\n return {\n name: 'Notifications',\n status: 'warn',\n detail: 'SisyphusNotify.app not built (click-to-switch unavailable)',\n fix: 'Requires Xcode CLI tools: xcode-select --install, then reinstall sisyphus',\n };\n}\n\nconst SYMBOLS = { ok: '\\u2713', warn: '!', fail: '\\u2717' } as const;\n\nexport function registerDoctor(program: Command): void {\n program\n .command('doctor')\n .description('Check sisyphus installation health')\n .action(() => {\n const itermCheck = checkItermRightOptionKey();\n const notifyCheck = checkNotifyBinary();\n const checks: Check[] = [\n checkNodeVersion(),\n checkClaudeCli(),\n checkGit(),\n checkTmux(),\n checkTmuxVersion(),\n checkTerminal(),\n ...(itermCheck ? [itermCheck] : []),\n checkGlobalDir(),\n checkDaemonInstalled(),\n checkDaemonRunning(),\n checkCycleScript(),\n checkTmuxKeybind(),\n checkSisyphusPlugin(),\n checkNvim(),\n ...(notifyCheck ? [notifyCheck] : []),\n checkTermrender(),\n ];\n\n let hasIssues = false;\n for (const c of checks) {\n const sym = SYMBOLS[c.status];\n console.log(` ${sym} ${c.name}: ${c.detail}`);\n if (c.status !== 'ok') hasIssues = true;\n }\n\n // Print fixes\n const fixable = checks.filter((c) => c.fix && c.status !== 'ok');\n if (fixable.length > 0) {\n console.log('\\nFixes:');\n for (const c of fixable) {\n console.log(` ${c.name}: ${c.fix}`);\n }\n }\n\n if (!hasIssues) {\n console.log('\\nAll checks passed.');\n }\n });\n}\n","import type { Command } from 'commander';\nimport { existsSync, mkdirSync, writeFileSync } from 'node:fs';\nimport { join } from 'node:path';\n\nconst DEFAULT_CONFIG = {};\n\nconst ORCHESTRATOR_TEMPLATE = `# Custom Orchestrator Prompt\n\n<!-- This file overrides the default orchestrator system prompt. -->\n<!-- Delete this file to use the built-in prompt. -->\n<!-- See: https://github.com/silasrhyneer/sisyphi for details. -->\n`;\n\nexport function registerInit(program: Command): void {\n program\n .command('init')\n .description('Initialize sisyphus configuration for this project')\n .option('--orchestrator', 'Also create a custom orchestrator prompt template')\n .action((opts: { orchestrator?: boolean }) => {\n const cwd = process.cwd();\n const sisDir = join(cwd, '.sisyphus');\n const configPath = join(sisDir, 'config.json');\n\n if (existsSync(configPath)) {\n console.log(`Already initialized: ${configPath}`);\n return;\n }\n\n mkdirSync(sisDir, { recursive: true });\n writeFileSync(configPath, JSON.stringify(DEFAULT_CONFIG, null, 2) + '\\n', 'utf-8');\n console.log(`Created ${configPath}`);\n\n if (opts.orchestrator) {\n const orchPath = join(sisDir, 'orchestrator.md');\n if (!existsSync(orchPath)) {\n writeFileSync(orchPath, ORCHESTRATOR_TEMPLATE, 'utf-8');\n console.log(`Created ${orchPath}`);\n }\n }\n\n console.log('');\n console.log('Configuration options (add to .sisyphus/config.json):');\n console.log(' orchestratorEffort — \"low\" | \"medium\" | \"high\" | \"xhigh\" | \"max\" (default: \"xhigh\")');\n console.log(' agentEffort — \"low\" | \"medium\" | \"high\" | \"xhigh\" | \"max\" (default: \"medium\")');\n console.log(' pollIntervalMs — Daemon poll interval in ms (default: 5000)');\n console.log(' autoUpdate — Auto-update daemon on restart (default: true)');\n console.log(' notifications — { enabled: boolean, sound: string } (default: enabled, Hero.aiff)');\n console.log(' companionPopup — Show companion commentary as tmux popup (default: true)');\n });\n}\n","import type { Command } from 'commander';\nimport { createInterface } from 'node:readline';\nimport { uninstallDaemon } from '../install.js';\n\nasync function confirm(question: string): Promise<boolean> {\n const rl = createInterface({ input: process.stdin, output: process.stdout });\n return new Promise((resolve) => {\n rl.question(question, (answer) => {\n rl.close();\n resolve(answer.trim().toLowerCase() === 'y');\n });\n });\n}\n\nexport function registerUninstall(program: Command): void {\n program\n .command('uninstall')\n .description('Unload the sisyphus daemon from launchd and remove the plist')\n .option('--purge', 'Also remove all session data in ~/.sisyphus')\n .option('-y, --yes', 'Skip confirmation prompt for --purge')\n .action(async (opts: { purge?: boolean; yes?: boolean }) => {\n const purge = opts.purge ?? false;\n\n if (purge && !opts.yes) {\n const ok = await confirm('This will delete all session data in ~/.sisyphus. Continue? (y/N) ');\n if (!ok) {\n console.log('Aborted.');\n return;\n }\n }\n\n await uninstallDaemon(purge);\n });\n}\n","import { chmodSync, existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';\nimport { createInterface } from 'node:readline';\nimport { dirname } from 'node:path';\nimport type { Command } from 'commander';\nimport { globalConfigPath } from '../../shared/paths.js';\n\nasync function readUrlFromInput(interactive: boolean): Promise<string> {\n if (interactive) {\n return new Promise((resolve) => {\n const rl = createInterface({ input: process.stdin, output: process.stdout });\n rl.question('Paste the upload URL (with embedded ?token=): ', (answer) => {\n rl.close();\n resolve(answer.trim());\n });\n });\n }\n return new Promise((resolve) => {\n const chunks: string[] = [];\n process.stdin.setEncoding('utf-8');\n process.stdin.on('data', (chunk: string) => { chunks.push(chunk); });\n process.stdin.on('end', () => { resolve(chunks.join('').trim()); });\n });\n}\n\nexport function registerConfigureUpload(program: Command): void {\n program\n .command('configure-upload')\n .description('Configure the upload proxy from a token-bearing URL (writes ~/.sisyphus/config.json)')\n .argument('[url]', 'Worker URL with embedded ?token= query (https://worker/upload?token=sisyphus_pat_...); omit to read from stdin')\n .option('--stdin', 'Read URL from stdin (pipe-friendly: pbpaste | sis admin configure-upload --stdin)')\n .action(async (urlArg: string | undefined, opts: { stdin?: boolean }) => {\n let rawUrl: string;\n\n const fromStdin = opts.stdin || urlArg === '-' || (!urlArg && process.stdin.isTTY === false);\n const fromInteractive = !urlArg && !opts.stdin && process.stdin.isTTY === true;\n\n if (fromStdin || fromInteractive) {\n rawUrl = await readUrlFromInput(fromInteractive);\n } else {\n rawUrl = urlArg!;\n console.warn(\n 'warning: passing the token on argv exposes it via `ps` and shell history; pipe it on stdin instead: `pbpaste | sis admin configure-upload --stdin`',\n );\n }\n\n let parsed: URL;\n try {\n parsed = new URL(rawUrl);\n } catch {\n console.error('Error: Invalid URL');\n process.exit(1);\n }\n\n const token = parsed.searchParams.get('token');\n if (!token) {\n console.error('Error: URL is missing ?token=... query param');\n process.exit(1);\n }\n\n if (!token.startsWith('sisyphus_pat_')) {\n console.error('Error: token does not start with sisyphus_pat_ — refusing to write');\n process.exit(1);\n }\n\n parsed.searchParams.delete('token');\n\n // Strip /upload if it's the trailing segment — upload.ts appends /upload itself\n const strippedPath = parsed.pathname.replace(/\\/upload\\/?$/, '');\n const url = parsed.origin + (strippedPath.length > 0 ? strippedPath : '');\n\n // Always write to ~/.sisyphus/config.json — `loadConfig` only honors `upload`\n // from the global config (project-local upload blocks are silently stripped\n // as a security measure; see src/shared/config.ts).\n const configPath = globalConfigPath();\n\n let existing: Record<string, unknown> = {};\n if (existsSync(configPath)) {\n try {\n existing = JSON.parse(readFileSync(configPath, 'utf-8')) as Record<string, unknown>;\n } catch {\n console.error(`Error: ${configPath} could not be parsed — fix or delete it first`);\n process.exit(1);\n }\n }\n\n const merged = { ...existing, upload: { url, token } };\n mkdirSync(dirname(configPath), { recursive: true });\n writeFileSync(configPath, JSON.stringify(merged, null, 2) + '\\n', 'utf-8');\n chmodSync(configPath, 0o600);\n\n console.log(`✓ upload configured (${configPath})`);\n });\n}\n","import { execSync } from 'node:child_process';\nimport { dirname, join } from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport type { Command } from 'commander';\nimport { isTmuxInstalled } from '../tmux.js';\nimport { isNvimAvailable, detectTerminal, checkItermOptionKey } from '../onboard.js';\n\nfunction templatePath(name: string): string {\n return join(dirname(fileURLToPath(import.meta.url)), 'templates', name);\n}\n\nfunction isClaudeCode(): boolean {\n return !!process.env['CLAUDECODE'];\n}\n\nfunction printNonClaudeMessage(): void {\n console.log(`\n ╔══════════════════════════════════════════════════╗\n ║ sis admin getting-started — Interactive Tutorial ║\n ╚══════════════════════════════════════════════════╝\n\n This command provides an interactive tutorial best experienced\n inside Claude Code. Claude will walk you through setup step by step.\n\n To start:\n 1. Open Claude Code: claude\n 2. Run: sis admin getting-started\n\n If you just want the quick reference, run:\n sis --help\n sis admin doctor\n`);\n}\n\nfunction printStep0(): void {\n const tmuxInstalled = isTmuxInstalled();\n const inTmux = !!process.env['TMUX'];\n let tmuxSession: string | null = null;\n if (process.env['TMUX']) {\n const segments = process.env['TMUX'].split(',');\n const pathPart = segments[0];\n if (pathPart) {\n const parts = pathPart.split('/');\n tmuxSession = parts[parts.length - 1] || null;\n }\n }\n\n console.log(`\n<claude-instructions>\n# Sisyphus Getting Started — Step 0: Entry & Tmux Gate\n\n## Environment Data\n- tmuxInstalled: ${tmuxInstalled}\n- inTmux: ${inTmux}\n- tmuxSession: ${tmuxSession ?? 'none'}\n\n## Tutorial Overview\n\nThis tutorial has 6 steps. Share this overview so the user knows what's coming and can skip ahead:\n\n| Step | Topic | Command |\n|------|-------|---------|\n| 0 | Entry & tmux gate (you are here) | \\`sis admin getting-started\\` |\n| 1 | Tmux basics — sessions, panes, navigation | \\`--tutorial 1\\` |\n| 2 | Nvim basics — open, save, quit (optional) | \\`--tutorial 2\\` |\n| 3 | Sisyphus concepts — session model & keybinds | \\`--tutorial 3\\` |\n| 4 | Live demo — launch and observe a real session | \\`--tutorial 4\\` |\n| 5 | What's next — real usage guidance & suggestions | \\`--tutorial 5\\` |\n\nTell the user they can skip to any step with \\`sis admin getting-started --tutorial <N>\\`.\n\n## Instructions for Claude\n\nYou are guiding a user through the Sisyphus interactive tutorial.\n\n### First: Ask if they want the tutorial\n\nAsk the user if they'd like the interactive walkthrough. If they decline, give this quick summary and stop:\n\n> Sisyphus is a multi-agent orchestrator for Claude Code. Start a session with \\`sis start \"task\"\\`,\n> monitor with \\`sis dashboard\\`, and check health with \\`sis admin doctor\\`.\n\n### If they want the tutorial:\n\n**Case 1: tmux is NOT installed (tmuxInstalled: false)**\n- Explain what tmux is in 2-3 sentences: \"tmux is a terminal multiplexer — it lets you split your terminal into multiple panes and keep sessions running in the background. Sisyphus uses it to give each agent its own workspace.\"\n- Show this ASCII diagram:\n\n\\`\\`\\`\n Regular terminal: With tmux:\n ┌──────────────┐ ┌──────┬──────┐\n │ │ │ Agent│ Agent│\n │ one view │ │ 001 │ 002 │\n │ │ ├──────┼──────┤\n │ │ │ Agent│ Orch │\n └──────────────┘ │ 003 │ │\n └──────┴──────┘\n\\`\\`\\`\n\n- Tell them to install tmux:\n - macOS: \\`brew install tmux\\`\n - Linux: \\`apt install tmux\\` or their package manager\n- After install, re-run: \\`sis admin getting-started --tutorial 0\\` to verify\n\n**Case 2: tmux installed but NOT in a tmux session (inTmux: false)**\n- Tell the user they need to be inside a tmux session for the tutorial\n- Have them run: \\`tmux new-session\\`\n- Then resume the conversation with Claude in the new tmux session: \\`claude\\`\n- Then re-run: \\`sis admin getting-started --tutorial 0\\` to verify\n\n**Case 3: In tmux (inTmux: true)**\n- Tell the user they're all set — tmux is running\n- Proceed by running: \\`sis admin getting-started --tutorial 1\\`\n</claude-instructions>\n`);\n}\n\nfunction printStep1(): void {\n console.log(`\n<claude-instructions>\n# Sisyphus Getting Started — Step 1: Tmux Basics\n\n## Instructions for Claude\n\nTeach the user tmux fundamentals. Be conversational and encouraging.\n\n### 1. Explain the concepts with diagrams\n\n**Sessions, Windows, and Panes:**\n\n\\`\\`\\`\ntmux session \"work\"\n├── window 1: \"code\"\n│ ┌──────────┬──────────┐\n│ │ pane 1 │ pane 2 │\n│ │ (editor)│ (tests) │\n│ └──────────┴──────────┘\n└── window 2: \"servers\"\n ┌──────────────────────┐\n │ pane 1 │\n │ (dev server) │\n └──────────────────────┘\n\\`\\`\\`\n\n- **Session**: A collection of windows. Persists even if you close the terminal.\n- **Window**: Like a tab. Each window fills the screen.\n- **Pane**: A split within a window. Sisyphus puts each agent in its own pane.\n\n### 2. Hands-on: Create a test split\n\nRun this command for the user:\n\\`\\`\\`\ntmux split-window -h\n\\`\\`\\`\n\nTell them: \"I just split your terminal. You should see two panes side by side.\"\n\nExplain navigation:\n- \\`Ctrl+l\\`: move to the right pane\n- \\`Ctrl+h\\`: move to the left pane\n- \\`Ctrl+j\\`: move to the pane below\n- \\`Ctrl+k\\`: move to the pane above\n- No prefix key needed — just hold Ctrl and press the direction letter\n- For windows: \\`Ctrl+n\\` next window, \\`Ctrl+p\\` previous window\n\nAsk them to try navigating between panes.\n\n### 3. Clean up the test pane\n\nOnce they confirm they can navigate, close the extra pane:\n\\`\\`\\`\ntmux kill-pane -t {the other pane}\n\\`\\`\\`\n\nOr tell them they can type \\`exit\\` in the extra pane to close it.\n\n### 4. Teach essential commands\n\n- **Detach**: \\`Ctrl-b d\\` — leaves tmux running in background, returns to normal terminal\n- **Reattach**: \\`tmux attach\\` (or \\`tmux a\\`) — reconnects to the running session\n- **Scroll up/down**: \\`Ctrl+u\\` / \\`Ctrl+d\\` — scroll half-page up/down (no prefix needed). Press \\`q\\` to exit scroll mode.\n- **New window**: \\`Ctrl-b n\\` — opens a new window in the current directory\n- **Kill pane**: \\`Ctrl-b x\\` — closes the current pane and rebalances layout\n- **Re-tile**: \\`Ctrl-b =\\` — rebalance all panes to equal widths\n\n### 5. Verification\n\nAsk the user to confirm: \"Can you navigate between panes with Ctrl+h and Ctrl+l?\"\n\nOnce confirmed, proceed:\n\\`\\`\\`\nsis admin getting-started --tutorial 2\n\\`\\`\\`\n</claude-instructions>\n`);\n}\n\nfunction printStep2(): void {\n const nvimInstalled = isNvimAvailable();\n\n console.log(`\n<claude-instructions>\n# Sisyphus Getting Started — Step 2: Nvim Basics\n\n## Environment Data\n- nvimInstalled: ${nvimInstalled}\n\n## Instructions for Claude\n\nThis step is OPTIONAL. Nvim is useful for reviewing and editing files when you jump into agent panes, but not required.\n\nNote: The sisyphus dashboard has keys that auto-open files in nvim — users don't need to know how to open files from the command line. Focus on what they'll need once they're INSIDE nvim.\n\n### If nvim is NOT installed (nvimInstalled: false)\n\nAsk the user: \"Neovim is handy for reviewing and editing files in tmux panes. Want me to install it, or skip this step?\"\n\n- **Install**: Run \\`brew install neovim\\` (macOS) or suggest their package manager\n- **Skip**: That's fine — they can use \\`cat\\`, \\`less\\`, or any editor they prefer. Proceed to step 3.\n\n### If nvim IS installed (nvimInstalled: true)\n\nBriefly explain the key concept — nvim has two modes:\n\n- **Normal mode** (default): Keys are commands, not text. This is where you navigate.\n- **Insert mode**: Press \\`i\\` to enter. Now you type normally. \\`Esc\\` goes back to normal.\n\nTell them the basics they need once they're inside nvim: \\`i\\` to enter insert mode, \\`Esc\\` to return to normal mode, \\`:w\\` to save, \\`:q\\` to quit, \\`:wq\\` to save and quit.\n\n### Verification\n\nAsk if they were able to edit and save the file (or if they skipped).\n\nProceed:\n\\`\\`\\`\nsis admin getting-started --tutorial 3\n\\`\\`\\`\n</claude-instructions>\n`);\n}\n\nfunction printStep3(): void {\n // Detect iTerm Right Option Key status for environment data\n let rightOptionKeyStatus = 'unknown';\n const terminal = detectTerminal();\n if (!terminal.isIterm) {\n rightOptionKeyStatus = 'not-iterm';\n } else {\n const result = checkItermOptionKey();\n if (!result.checked) {\n rightOptionKeyStatus = 'could-not-check';\n } else if (result.allCorrect) {\n rightOptionKeyStatus = 'ok';\n } else {\n rightOptionKeyStatus = `incorrect:${result.incorrectProfiles.join(',')}`;\n }\n }\n\n console.log(`\n<claude-instructions>\n# Sisyphus Getting Started — Step 3: Sisyphus Concepts & Keybinds\n\n## Environment Data\n- rightOptionKeyStatus: ${rightOptionKeyStatus}\n\n## Instructions for Claude\n\n### 1. CRITICAL FIRST: Right Option Key Setup\n\n**This must be done before anything else.** Sisyphus keybinds use the Option key as \"Meta\". By default, macOS terminals send special characters when you press Option (e.g., Option+s types \\`ß\\`). We need the RIGHT Option key to send escape sequences instead.\n\n**Check the environment data above:**\n\n- **rightOptionKeyStatus: ok** — They're all set, briefly confirm and move on.\n\n- **rightOptionKeyStatus: incorrect:ProfileName** — Walk them through the fix:\n\n > Your Right Option key isn't configured correctly yet. Here's how to fix it:\n >\n > 1. Open **iTerm2 Settings** (Cmd+,)\n > 2. Go to **Profiles** → select your profile (shown above)\n > 3. Click the **Keys** tab\n > 4. At the bottom, find **Right Option Key**\n > 5. Change it from **Normal** to **Esc+**\n >\n > \\`\\`\\`\n > ┌─ iTerm2 Settings ──────────────────────────┐\n > │ Profiles > Keys │\n > │ │\n > │ Right Option Key: │\n > │ ○ Normal (sends special chars like ß) │\n > │ ● Esc+ (sends escape sequences) ← ✓ │\n > └─────────────────────────────────────────────┘\n > \\`\\`\\`\n >\n > **Why right and not left?** You'll still want the left Option key for\n > typing special characters (accents, symbols). The right Option key\n > becomes your \"Meta\" key for tmux/sisyphus keybinds.\n\n After they change it, have them verify by re-running \\`sis admin doctor\\` — look for \"Right Option Key: Esc+\".\n\n- **rightOptionKeyStatus: not-iterm** — They're not using iTerm2. Explain:\n > Sisyphus keybinds use Option as Meta. In iTerm2 this is configured via\n > \"Right Option Key → Esc+\". For your terminal, look for a similar setting\n > like \"Option sends Meta\" or \"Option sends Esc+\". Without this, pressing\n > Option+s will type a special character instead of triggering the keybind.\n\n- **rightOptionKeyStatus: could-not-check** or **unknown** — Ask them to manually check:\n > Press Option+s in your terminal. If you see \\`ß\\` (or another special character),\n > your Option key needs to be reconfigured. In iTerm2: Settings → Profiles → Keys →\n > Right Option Key → Esc+.\n\n### 2. Explain the session model\n\nThis is the KEY concept. Use the diagram and be clear:\n\n\\`\\`\\`\n YOUR tmux session (\"work\") Sisyphus tmux session (\"sisyphus-abc123\")\n ┌─────────────────────┐ ┌──────────┬──────────┬──────────┐\n │ │ │ Orch │ Agent │ Agent │\n │ Your normal work │ ←──→ │ (yellow)│ (blue) │ (green) │\n │ + dashboard │ │ │ │ │\n │ │ │ Plans & │ Writes │ Writes │\n │ │ │ assigns │ code │ tests │\n └─────────────────────┘ └──────────┴──────────┴──────────┘\n\\`\\`\\`\n\nKey points:\n- Sisyphus creates its OWN tmux session — it doesn't clutter yours\n- The **orchestrator** (yellow pane) plans work and spawns agents\n- **Agents** (colored panes) work in parallel on subtasks\n- Your session stays clean — you get a **dashboard** for monitoring\n- You can jump between your session and the sisyphus session to observe\n\n### 3. Teach keybinds\n\nTwo keybinds to remember (both use the RIGHT Option key):\n\n| Keybind | Action |\n|---------|--------|\n| Right Option + s | Cycle through sisyphus sessions |\n| Right Option + Shift + s | Jump back to dashboard |\n\n### 4. Verify keybinds are installed (REQUIRED before step 5)\n\nRun \\`sis admin check-keybinds\\` and follow the decision tree it emits. The output is\nstructured for you — it tells you the current state and which path to take (Path A\nthrough Path F). Do NOT skip this and do NOT ask the user to test a keybind until\nboth \\`M-s\\` and \\`C-s\\` read \"sisyphus\" in that command's output.\n\nCommon paths:\n- **Path A (already wired):** confirm and move on.\n- **Path B (safe auto-install):** run \\`sis admin setup-keybind --yes\\`.\n- **Path C (would touch user's tmux.conf):** ask the user — persistent (\\`--force\\`) or\n live-only (no flag, non-TTY auto-declines the conf write).\n- **Path D (binding conflict):** pick alternate keys or wire directly.\n- **Path E (hidden prefix collision):** their tmux prefix is C-s; explain and offer\n alternatives.\n- **Path F (tmux not ready):** fix the precondition first.\n\nAfter acting, re-run \\`sis admin check-keybinds\\` to confirm success.\n\n### 5. Test the keybind\n\nOnce check-keybinds reports both keys as \"sisyphus\", have the user try pressing\nRight Option + s. Nothing should happen yet (no sisyphus session running) — and that's\nfine. The important thing is no special character appears.\n\nIf they see \\`ß\\` or similar, circle back to the Right Option Key setup above.\n\n### 6. Verification\n\nConfirm:\n- They understand the two-session model (their session vs sisyphus session)\n- \\`sis admin doctor\\` shows keybinds installed AND Right Option Key: Esc+\n- Right Option + s doesn't produce a special character\n\nProceed:\n\\`\\`\\`\nsis admin getting-started --tutorial 4\n\\`\\`\\`\n</claude-instructions>\n`);\n}\n\nfunction printStep4(): void {\n console.log(`\n<claude-instructions>\n# Sisyphus Getting Started — Step 4: Demo Session\n\n## Instructions for Claude\n\nThis is the grand finale — a live demo session.\n\n### 1. Health check\n\nRun \\`sis admin doctor\\` first. If any checks are failing, help the user fix them before proceeding.\nAll core checks (tmux, daemon, keybinds) should be ✓.\n\n### 2. BEFORE launching: Teach navigation\n\n**This is critical.** When \\`sis start\\` runs, it auto-opens the dashboard in a new tmux window. The user will suddenly be looking at the dashboard and may feel \"stuck\". Teach them how to navigate BEFORE launching:\n\nExplain clearly:\n\n> Before we launch, you need to know how to move between tmux windows. Right now you're in a window with Claude. When sisyphus starts, it'll open a dashboard in a new window. Think of windows like tabs:\n>\n> \\`\\`\\`\n> Window 1 (you are here) Window 2 (dashboard)\n> ┌──────────────────┐ ┌──────────────────┐\n> │ Claude Code │ │ Sisyphus │\n> │ (this session) │ → │ Dashboard │\n> └──────────────────┘ └──────────────────┘\n> Ctrl+n → ← Ctrl+p\n> \\`\\`\\`\n>\n> - **\\`Ctrl+n\\`** — next window (go to dashboard)\n> - **\\`Ctrl+p\\`** — previous window (come back here)\n>\n> And remember from step 3:\n> - **Right Option + s** — jump to the sisyphus agent session (where you can watch agents work live)\n> - **Right Option + Shift + s** — jump back to dashboard\n\nHave the user confirm they understand these keybinds before proceeding.\n\n### 3. Set expectations, copy demo app, and launch\n\nFirst, copy the demo todo app to a temp directory and init a git repo (sisyphus needs git):\n\\`\\`\\`\nrm -rf /tmp/sisyphus-tutorial-demo\ncp -r ${templatePath('tutorial-demo')} /tmp/sisyphus-tutorial-demo\ngit -C /tmp/sisyphus-tutorial-demo init\ngit -C /tmp/sisyphus-tutorial-demo add -A\ngit -C /tmp/sisyphus-tutorial-demo commit -m \"Initial todo app\"\n\\`\\`\\`\n\nTell the user:\n\n> I've set up a small todo app in /tmp/sisyphus-tutorial-demo — a Node.js API\n> with a few files. I'm going to launch sisyphus on it. Here's what will happen:\n> 1. The dashboard opens automatically (you'll be switched to it)\n> 2. Press **Ctrl+p** to come back here to Claude — I'll guide you through what to watch\n> 3. The session takes a few minutes. You can watch agents work live!\n\nThen launch from the demo directory:\n\\`\\`\\`\ncd /tmp/sisyphus-tutorial-demo && sis start \"Add three improvements to this todo app: (1) add a priority field (high/medium/low) to todos, (2) add a GET /todos/stats endpoint that returns counts of total/done/pending todos, (3) add tests for the new features. Explain your thinking at each step.\" -c \"TUTORIAL DEMO: A user is watching this session to learn how sisyphus works. Be EXTRA VERBOSE — explain your reasoning, narrate what you're doing, and make your planning visible. When spawning agents, give each agent context that this is a tutorial demo and they should explain their work clearly. Keep scope small: 2-3 agents, 1-2 cycles.\"\n\\`\\`\\`\n\nAfter launching, tell them:\n\n> The dashboard just opened. Press **Ctrl+p** to come back here — I'll provide live commentary as the session runs so you know what's happening.\n\nWait for them to confirm they're back, then start live commentary.\n\n### 4. Live commentary loop\n\n**This is the most important part of the demo.** Don't just launch and wait — actively narrate.\n\nOnce the user is back, start a polling loop. Every ~45 seconds, run \\`sis status --verbose <session-id>\\` and provide SHORT, contextual commentary about what's happening. The \\`--verbose\\` flag shows agent instructions, full roadmap, cycle logs, and live pane output from the orchestrator and running agents — use this rich data to narrate what's actually happening, not just phase names.\n\n**How to narrate each phase:**\n\n- **Cycle 1, no agents yet**: \"The orchestrator is reading the codebase and planning. It's figuring out how to split the work. Check the dashboard (\\`Ctrl+n\\`) — you'll see the roadmap updating.\"\n\n- **Agents spawning**: \"Agents just spawned! You should see new panes appearing. Try \\`Right Option + s\\` to jump to the sisyphus session and watch them work. Each colored pane is an independent Claude instance.\"\n\n- **Agents working**: \"Agent-001 is working on [X], Agent-002 is on [Y]. They're working in parallel — this is the key advantage of sisyphus. Jump over and watch if you like (\\`Right Option + s\\`).\"\n\n- **Agents submitting**: \"Agent-001 just submitted its report! [N] more to go. When all agents finish, the orchestrator will respawn to review.\"\n\n- **Between cycles**: \"All agents done. The orchestrator is respawning with fresh context to review the reports and decide what's next. This is the cycle boundary — the orchestrator never runs out of context because it starts fresh each time.\"\n\n- **Completion**: \"The session is complete! Let me show you the results.\"\n\n**Important:**\n- Keep commentary to 1-3 sentences per check — don't wall-of-text\n- Remind them of navigation keys when relevant (\"jump over with Right Option + s to see this live\")\n- If agents are still working with no change, say so briefly (\"Still working... Agent-001 is the furthest along\")\n- Reference specific agent names and tasks from the status output\n- Stop polling when status shows \"completed\"\n\nBetween polls, encourage the user to explore:\n> \"While we wait, try jumping around: \\`Ctrl+n\\` for dashboard, \\`Right Option + s\\` for the agent session, \\`Right Option + Shift + s\\` to jump back. I'll keep narrating here.\"\n\n### 5. After completion\n\nOnce the session shows \"completed\":\n\n- Show them what the agents built: \\`cd /tmp/sisyphus-tutorial-demo && git log --oneline\\`\n- Run the tests to prove the work: \\`cd /tmp/sisyphus-tutorial-demo && node --test test.js\\`\n- Show the session artifacts: find the session dir in \\`.sisyphus/sessions/\\` and show \\`roadmap.md\\`\n- Explain: \"Every session creates a roadmap, agent reports, and logs — all stored in .sisyphus/sessions/\"\n\n### 6. Proceed to wrap-up\n\nTell the user the demo is done. Then run:\n\\`\\`\\`\nsis admin getting-started --tutorial 5\n\\`\\`\\`\n</claude-instructions>\n`);\n}\n\nfunction printStep5(): void {\n // Gather codebase context for suggestions\n let recentCommits = '';\n let topLevelFiles = '';\n try {\n recentCommits = execSync('git log --oneline -15 2>/dev/null', { encoding: 'utf-8' }).trim();\n } catch { /* not in a git repo */ }\n try {\n topLevelFiles = execSync('ls -1 2>/dev/null', { encoding: 'utf-8' }).trim();\n } catch { /* ignore */ }\n\n console.log(`\n<claude-instructions>\n# Sisyphus Getting Started — Step 5: What's Next\n\n## Codebase Context\n<recent-commits>\n${recentCommits || '(no git repo detected)'}\n</recent-commits>\n\n<top-level-files>\n${topLevelFiles || '(could not list)'}\n</top-level-files>\n\n## Instructions for Claude\n\n### 1. Congratulate them\n\nTell them they've completed the tutorial and recap what they learned:\n- tmux basics (sessions, panes, navigation)\n- nvim basics for reviewing files\n- The sisyphus session model (separate tmux session for orchestrator + agents)\n- Monitoring with dashboard and keybinds\n- A live session lifecycle\n\n### 2. Navigation cheat sheet\n\n| Key | Action |\n|-----|--------|\n| \\`Ctrl+n\\` / \\`Ctrl+p\\` | Next/previous tmux window |\n| \\`Ctrl+h/j/k/l\\` | Navigate between panes |\n| \\`Right Option + s\\` | Jump to sisyphus agent session |\n| \\`Right Option + Shift + s\\` | Jump to dashboard |\n\n### 3. How to use sisyphus for REAL work\n\nThis is the most important part. Explain clearly:\n\n> **Sisyphus is for big, end-to-end features — the kind that need exploration,\n> planning, and parallel implementation across multiple systems.**\n>\n> You don't need to define the task precisely. Broad is fine — the orchestrator\n> will explore the codebase, write specs, plan phases, and break it down itself.\n\n**Real sisyphus sessions (from production use):**\n- \"Design and implement a human-in-the-loop agent inbox system\" — exploration, spec writing, DB schema, API endpoints, UI components, webhook integration, e2e validation\n- \"Build multi-user organization features — invites, privilege gating, org switcher, workspace sharing, credit tracking\" — touched auth, DB, API, UI, billing, permissions\n- \"Rework all 5 worker onboarding templates to match production pipeline patterns\" — mapped existing patterns, designed new architecture, implemented across templates, validated with e2e tests\n- \"Autonomous failure detection system across 8 sequential phases\" — monitoring, alerting, recovery, dashboard, with each phase building on the last\n- \"Comprehensive code quality audit — find and fix dead code, null handling, useless fallbacks\" — systematic codebase-wide analysis and cleanup\n- \"Implement @requirements.md\" — point it at a spec and let it go\n\n**NOT good for sisyphus:**\n- Five unrelated small tasks bundled together (\"fix the login bug, update the README, add a loading spinner\") — these aren't one feature, they're a todo list\n- Something Claude Code in plan mode would handle — plan mode already handles substantial single-engineer work. If it fits in one Claude session, just do it directly.\n- Quick fixes, bug fixes, small refactors — use regular Claude Code\n\n**How to start:**\nThe easiest way is the \\`/sisyphus:begin\\` slash command inside Claude Code. Just tell Claude\nwhat you want to build and it'll hand it off to sisyphus with the right context.\n\nOr directly: \\`sis start \"your task\" -c \"any background context\"\\`\n\n### 4. Suggest real tasks for THEIR codebase\n\nLook at the recent commits and top-level files above. Based on what you can see of their project, suggest 2-3 concrete sisyphus-scale tasks they could try. Be specific to their codebase — reference actual directories, patterns, or areas you can see.\n\nIf there are no commits or files (e.g., they ran this from /tmp), skip this section.\n\nFormat as:\n> Based on your codebase, here are some tasks sisyphus would be great for:\n> - \"...\"\n> - \"...\"\n\n### 5. There's more to learn\n\nTell them:\n\n> There's actually a lot of depth to how sisyphus works — the design is intentional\n> and there's real reasoning behind why it does things the way it does. If you want\n> to understand the philosophy, or you want a deeper rundown on the dashboard,\n> monitoring, configuration, or how to steer sessions — just ask and I'll explain.\n\nIf the user says yes or asks to learn more, run \\`sis admin getting-started --explain\\`\nand use its output to explain the system to them conversationally. Don't dump the whole\nthing — answer what they're curious about, using the reference as your source material.\n</claude-instructions>\n`);\n}\n\nfunction buildCommandTable(program: Command): string {\n const lines: string[] = ['| Command | Purpose |', '|---------|---------|'];\n for (const cmd of program.commands) {\n if ((cmd as unknown as { _hidden: boolean })._hidden) continue;\n if (cmd.name() === 'help') continue;\n const subs = cmd.commands.filter(c => !(c as unknown as { _hidden: boolean })._hidden && c.name() !== 'help');\n const hasOwnAction = (cmd as unknown as { _actionHandler?: unknown })._actionHandler != null;\n const fmtArgs = (c: typeof cmd) =>\n c.registeredArguments.map(a => a.required ? `<${a.name()}>` : `[${a.name()}]`).join(' ');\n if (subs.length === 0) {\n // flat or argument-only command\n const args = fmtArgs(cmd);\n const usage = args ? `sis ${cmd.name()} ${args}` : `sis ${cmd.name()}`;\n lines.push(`| \\`${usage}\\` | ${cmd.description()} |`);\n } else {\n // group: if it has its own root action (e.g. `companion`), emit a row for the bare invocation first\n if (hasOwnAction) {\n const args = fmtArgs(cmd);\n const usage = args ? `sis ${cmd.name()} ${args}` : `sis ${cmd.name()}`;\n lines.push(`| \\`${usage}\\` | ${cmd.description()} |`);\n }\n // then one row per subcommand\n for (const sub of subs) {\n const args = fmtArgs(sub);\n const usage = args ? `sis ${cmd.name()} ${sub.name()} ${args}` : `sis ${cmd.name()} ${sub.name()}`;\n lines.push(`| \\`${usage}\\` | ${sub.description()} |`);\n }\n }\n }\n return lines.join('\\n');\n}\n\nfunction printExplain(program: Command): void {\n console.log(`\n<claude-instructions>\n# Sisyphus — Comprehensive Reference\n\nThis is a detailed reference for how sisyphus works. The user asked to understand\nsisyphus more deeply. Use this to answer their questions conversationally — don't dump\nthe whole thing. Read through it, then respond to what they're curious about.\n\n## Design Philosophy\n\nSisyphus is built on specific insights about how to get the best work out of LLM agents.\nThese aren't arbitrary — each design decision solves a real failure mode.\n\n### 1. The Orchestrator as \"Human-in-the-Loop\"\n\nWhen you use Claude Code effectively, YOU are the orchestrator — you review work,\nsteer direction, break problems down, and assign the next piece. Sisyphus automates\nthat human role. The orchestrator does what a skilled developer does when prompting\nClaude: explore the codebase, understand the problem, write specs, plan phases,\nassign focused work, review results, and iterate.\n\nThe strategy layer mirrors how developers actually work on end-to-end features:\nexplore, understand, spec, plan, implement, review, validate. The orchestrator\nfollows this same workflow, but runs it with parallel agents.\n\n### 2. Fresh Context Kills Shortcuts\n\nThe orchestrator is KILLED after every cycle and respawned fresh. This is the most\nimportant design decision.\n\nWhen an LLM accumulates context over a long session, it starts taking shortcuts.\nIt \"knows\" what it did earlier, so it skips re-reading, assumes things still hold,\nand builds on stale understanding. A fresh start forces honest reassessment every\ncycle — the orchestrator reads the actual state, not its memory of it.\n\nThis is inspired by adversarial training (think GANs) — better results come from\nadversarial pressure. Each fresh orchestrator effectively audits the previous cycle's\nwork because it has no stake in defending prior decisions. It sees the roadmap, the\nreports, the code — and judges them with fresh eyes.\n\n### 3. Single-Focus Agents\n\nEach agent gets ONE task with a fully self-contained instruction. No context switching,\nno juggling multiple concerns, no \"also while you're there could you...\"\n\nLLMs perform dramatically better when focused. An agent implementing a priority field\ndoesn't think about the stats endpoint. It reads the relevant context, does its one\nthing well, and reports back. The orchestrator handles decomposition — agents handle\nexecution.\n\n### 4. Shared Context Directory (Saved Research)\n\nEvery session has a context/ directory where agents save research, specs, plans, and\ndesign docs. These files persist across ALL cycles and are visible to the orchestrator\nand subsequent agents.\n\nThis means research is never repeated. Cycle 1 agents explore and write findings to\ncontext/explore-auth-system.md. Cycle 3 agents read those findings and build on them.\nKnowledge accumulates even though the orchestrator itself is stateless.\n\nPlan lead agents save their plans under context/{agent-id}/ so parallel plan agents\ndon't interfere with each other's validation.\n\n### 5. Two-Layer Planning (Strategy + Roadmap)\n\nThe system maintains two documents at different abstraction levels:\n\n**strategy.md** — The high-level problem-solving map. What phases exist, what gates\nbetween them, what backtrack paths exist. Updated every few cycles when the shape of\nwork changes. Helps the orchestrator see the forest.\n\n**roadmap.md** — Working memory. Updated every cycle. Current Stage, Exit Criteria,\nActive Context, Next Steps. The orchestrator reads this first each cycle to understand\nwhere things stand. Helps the orchestrator see the trees.\n\nThis prevents the failure mode where a single document becomes either too abstract\nto act on or too detailed to show the big picture.\n\n### 6. Adversarial Review Is Built In\n\nThe orchestrator doesn't just implement — it runs mandatory critique cycles. After\nimplementation, review agents attack different dimensions: code reuse, quality,\nefficiency, correctness. Fix agents address the findings. Re-review until only nits\nremain. Multiple agents auditing each other produces better results than any single\nagent reviewing its own work.\n\nThe rule: never let 2+ stages complete without critique. Small issues compound into\narchitectural problems if unchecked.\n\n### 7. Evidence Over Assumptions\n\nValidation requires PROOF — command output, test results, HTTP responses. \"The code\nlooks correct\" is not evidence. \"All 14 tests pass\" is. This catches the gap between\ncode that looks right and code that works.\n\n## Architecture Overview\n\n\\`\\`\\`\n┌─────────────────────────────────────────────────────────────────────┐\n│ USER'S TMUX SESSION │\n│ │\n│ ┌─────────────────────────┐ ┌──────────────────────────────────┐ │\n│ │ Window 1: Claude Code │ │ Window 2: Dashboard (TUI) │ │\n│ │ │ │ │ │\n│ │ User's normal work │ │ Real-time session monitor │ │\n│ │ + this conversation │ │ Roadmap, agents, reports │ │\n│ │ │ │ Interactive controls │ │\n│ └─────────────────────────┘ └──────────────────────────────────┘ │\n└──────────────────────────────────┬──────────────────────────────────┘\n │ Right Option+s / Right Option+Shift+s\n ▼\n┌─────────────────────────────────────────────────────────────────────┐\n│ SISYPHUS TMUX SESSION │\n│ (created per sisyphus session) │\n│ │\n│ ┌──────────┬──────────┬──────────┬──────────┐ │\n│ │ Orch │ Agent │ Agent │ Agent │ ← panes │\n│ │ (yellow) │ (blue) │ (green) │ (magenta)│ │\n│ │ │ │ │ │ │\n│ │ Plans, │ Impl │ Tests │ Docs │ ← each is a │\n│ │ assigns, │ feature │ │ │ Claude Code │\n│ │ reviews │ │ │ │ instance │\n│ └──────────┴──────────┴──────────┴──────────┘ │\n└─────────────────────────────────────────────────────────────────────┘\n │\n ▼\n┌─────────────────────────────────────────────────────────────────────┐\n│ DAEMON (sisyphusd) │\n│ Background process via launchd │\n│ │\n│ Listens on ~/.sisyphus/daemon.sock │\n│ Manages session lifecycle, pane monitoring, state persistence │\n│ Polls panes to detect when agents/orchestrator finish │\n└─────────────────────────────────────────────────────────────────────┘\n\\`\\`\\`\n\n## The Session Lifecycle (in detail)\n\n\\`\\`\\`\n ┌──────────────────────────────────────────────────────────────────┐\n │ SESSION LIFECYCLE │\n │ │\n │ sis start \"task\" │\n │ │ │\n │ ▼ │\n │ ┌─────────┐ spawn agents ┌──────────────┐ │\n │ │ Orch │ ──────────────────→ │ Agents work │ │\n │ │ plans │ then yields │ in parallel │ │\n │ └────┬────┘ └──────┬───────┘ │\n │ │ │ each calls │\n │ │ orchestrator │ sis agent submit │\n │ │ is KILLED │ when done │\n │ │ ▼ │\n │ │ ┌──────────────┐ │\n │ │ │ All agents │ │\n │ │ │ finished? │ │\n │ │ └──────┬───────┘ │\n │ │ │ yes │\n │ │ ┌──────────────────────┘ │\n │ │ ▼ │\n │ │ ┌─────────┐ │\n │ └──── │ Respawn │ Fresh orchestrator with full state │\n │ next cycle │ Orch │ Reviews reports, plans next cycle │\n │ └────┬────┘ │\n │ │ │\n │ ▼ │\n │ ┌───────────────┐ ┌───────────┐ │\n │ │ More work │──yes──→ │ Spawn │ → (loop) │\n │ │ needed? │ │ agents │ │\n │ └───────┬───────┘ └───────────┘ │\n │ │ no │\n │ ▼ │\n │ ┌───────────────┐ │\n │ │ sisyphus │ │\n │ │ complete │ │\n │ └───────────────┘ │\n └──────────────────────────────────────────────────────────────────┘\n\\`\\`\\`\n\n**Key insight**: The orchestrator is STATELESS. It gets killed after each yield and\nrespawned fresh with the complete session state (roadmap, agent reports, cycle history).\nThis means it never runs out of context, no matter how many cycles a session takes.\n\n## The Dashboard\n\nThe dashboard is a real-time TUI that shows session state. Launch with \\`sis dashboard\\`\nor it auto-opens when a session starts.\n\n**Dashboard sections:**\n- **Header**: Session ID, status, task description\n- **Roadmap**: Current strategic plan with checked/unchecked items\n- **Agents**: List of all agents with status, duration, and report summaries\n- **Cycles**: Orchestrator cycle history\n- **Messages**: Recent session messages\n\n**Dashboard keys:**\n| Key | Action |\n|-----|--------|\n| \\`m\\` | Message the orchestrator (steer direction mid-session) |\n| \\`w\\` | Jump to the sisyphus tmux session (watch agents work) |\n| \\`k\\` | Kill the session |\n| \\`r\\` | Resume a paused/completed session |\n| \\`q\\` | Quit the dashboard |\n| \\`↑/↓\\` | Scroll through content |\n| \\`Tab\\` | Cycle through sections |\n\n**The \\`m\\` key is the most powerful feature.** You can message the orchestrator at any time\nto course-correct: \"Focus on the API layer first\", \"Skip the tests for now\",\n\"The approach for auth is wrong, use JWT instead\". The orchestrator reads these\nmessages when it respawns each cycle.\n\n## Monitoring Strategy\n\nSisyphus sessions should be actively monitored. Here's what to watch for:\n\n**Things that go wrong:**\n- Agents stuck waiting for user input (they're autonomous — they shouldn't need input)\n- Agents going down rabbit holes or working on the wrong thing\n- Merge conflicts between agents touching the same files\n- Orchestrator spawning too many agents or too few\n- Agents crashing or getting killed unexpectedly\n\n**When to intervene:**\n- Use \\`m\\` in the dashboard to message the orchestrator with corrections\n- Use \\`sis session kill <id>\\` to stop a runaway session\n- Use \\`sis session resume <id> \"new instructions\"\\` to restart with different direction\n\n**Useful monitoring commands:**\n\\`\\`\\`\nsis status <id> # Quick status check\nsis status --verbose <id> # Full detail: roadmap, pane output, agent instructions\nsis dashboard # Interactive TUI\ntail -f ~/.sisyphus/daemon.log # Daemon activity log\n\\`\\`\\`\n\n## The .sisyphus/ Directory\n\nEverything sisyphus does lives in a \\`.sisyphus/\\` directory at the root of your project.\nThis is project-local — each project gets its own. It contains:\n\n\\`\\`\\`\n.sisyphus/\n├── config.json # Project-specific config (model, poll interval, etc.)\n├── orchestrator.md # Optional custom orchestrator prompt override\n└── sessions/\n ├── <session-id-1>/ # Each session gets its own directory\n ├── <session-id-2>/\n └── ...\n\\`\\`\\`\n\nThere's also a global directory at \\`~/.sisyphus/\\` for the daemon socket, PID file,\nlogs, keybind scripts, and global config. But the session state — the roadmaps,\nreports, context files, cycle logs — all lives in your project's \\`.sisyphus/sessions/\\`.\n\n## Session Files\n\nEvery session creates a directory at \\`.sisyphus/sessions/<id>/\\` with:\n\n\\`\\`\\`\n.sisyphus/sessions/<id>/\n├── state.json # Session state (agents, cycles, status)\n├── roadmap.md # Strategic plan (updated by orchestrator each cycle)\n├── goal.md # Original task description\n├── initial-prompt.md # Immutable record of the initial user prompt\n├── strategy.md # High-level strategy notes\n├── logs/\n│ ├── cycle-000.md # What the orchestrator did in cycle 0\n│ ├── cycle-001.md # What it did in cycle 1, etc.\n│ └── ...\n├── reports/\n│ ├── agent-001-final.md # Agent's final report\n│ ├── agent-002-update.md # Agent's progress update\n│ └── ...\n├── prompts/ # System/user prompts sent to orchestrator and agents\n└── context/ # Shared context files for agents\n\\`\\`\\`\n\n## Configuration\n\n**Global config**: \\`~/.sisyphus/config.json\\`\n**Project config**: \\`.sisyphus/config.json\\` (overrides global)\n\nOptions:\n- \\`model\\` — Claude model for orchestrator and agents\n- \\`orchestratorPrompt\\` — Path to custom orchestrator prompt\n- \\`pollIntervalMs\\` — How often daemon checks pane status (default: 2000)\n\n## Starting Sessions — Best Practices\n\n**The /sisyphus:begin slash command** is the recommended way to start. Inside Claude Code:\n\\`\\`\\`\n/sisyphus:begin\n\\`\\`\\`\nThen describe your task. Claude will hand it off with the right context.\n\n**Direct CLI:**\n\\`\\`\\`\nsis start \"task description\" -c \"background context\"\nsis start \"Implement @requirements.md\" -n my-feature\n\\`\\`\\`\n\n**Reference files with @**: \\`sis start \"Build @docs/spec.md\"\\` — the orchestrator\nwill read the referenced file as part of its planning.\n\n**The -c flag** adds background context the orchestrator sees but doesn't act on directly.\nUse it for constraints: \\`-c \"Don't modify the auth module, use the existing API\"\\`\n\n**The -n flag** gives the session a human-readable name for easier tracking.\n\n## CLI Command Reference\n\n${buildCommandTable(program)}\n\n## Troubleshooting\n\n**Daemon not running:**\n\\`\\`\\`\nsisyphusd restart\n\\`\\`\\`\n\n**Keybinds not working (special characters appear):**\niTerm2 → Settings → Profiles → Keys → Right Option Key → Esc+\n\n**Agents stuck:** Check \\`sis status --verbose <id>\\` to see pane output. If an\nagent is waiting for input, kill the session and restart with clearer instructions.\n\n**Dashboard not opening:** Run \\`sis dashboard\\` manually. Must be inside tmux.\n\n**Session seems hung:** Check \\`tail -20 ~/.sisyphus/daemon.log\\` for errors.\nThe daemon polls panes every 2s — if a pane dies unexpectedly, it'll be detected.\n</claude-instructions>\n`);\n}\n\nconst STEPS: Array<() => void> = [printStep0, printStep1, printStep2, printStep3, printStep4, printStep5];\n\nexport function registerGettingStarted(program: Command): void {\n program\n .command('getting-started')\n .description('Interactive tutorial (best with Claude Code)')\n .option('--tutorial <step>', 'Tutorial step (0-5)', parseInt)\n .option('--explain', 'Comprehensive reference for how sisyphus works')\n .action((opts) => {\n if (opts.explain) {\n printExplain(program);\n return;\n }\n if (opts.tutorial !== undefined) {\n const step = opts.tutorial as number;\n if (step < 0 || step > 5 || Number.isNaN(step)) {\n console.error(`Invalid tutorial step: ${opts.tutorial}. Must be 0-5.`);\n process.exit(1);\n }\n STEPS[step]!();\n return;\n }\n if (!isClaudeCode()) {\n printNonClaudeMessage();\n return;\n }\n printStep0();\n });\n}\n","import type { Command } from 'commander';\nimport { readdirSync, readFileSync, existsSync } from 'node:fs';\nimport { join, resolve } from 'node:path';\nimport { historyBaseDir, historySessionDir, historyEventsPath, historySessionSummaryPath, statePath } from '../../shared/paths.js';\nimport { formatDuration, statusColor } from '../../shared/format.js';\nimport type { SessionSummary, SessionSummaryAgent } from '../../shared/history-types.js';\nimport type { HistoryEvent } from '../../shared/history-types.js';\nimport type { Session } from '../../shared/types.js';\n\nconst RESET = '\\x1b[0m';\nconst BOLD = '\\x1b[1m';\nconst DIM = '\\x1b[2m';\nconst COLOR: Record<string, string> = {\n green: '\\x1b[32m', yellow: '\\x1b[33m', cyan: '\\x1b[36m',\n red: '\\x1b[31m', gray: '\\x1b[90m', white: '\\x1b[37m', magenta: '\\x1b[35m',\n};\n\nfunction c(color: string, text: string): string {\n return `${COLOR[color] ?? ''}${text}${RESET}`;\n}\n\n// Agent types that run interactive TUI sessions. Their activeMs includes\n// user think-time while the pane is open — not actual compute. Treat\n// separately from compute-only agent types in efficiency metrics.\nconst INTERACTIVE_AGENT_TYPES = new Set<string>([\n 'sisyphus:requirements',\n 'sisyphus:design',\n 'sisyphus:spec',\n]);\n\nfunction isInteractiveAgent(agentType: string | null | undefined): boolean {\n return agentType != null && INTERACTIVE_AGENT_TYPES.has(agentType);\n}\n\nfunction splitAgentTime(agents: SessionSummaryAgent[]): { computeMs: number; interactiveMs: number; blockedMs: number } {\n let computeMs = 0;\n let interactiveMs = 0;\n let blockedMs = 0;\n for (const a of agents) {\n const blocked = a.userBlockedMs ?? 0;\n const remaining = Math.max(0, a.activeMs - blocked);\n blockedMs += blocked;\n if (isInteractiveAgent(a.agentType)) interactiveMs += remaining;\n else computeMs += remaining;\n }\n return { computeMs, interactiveMs, blockedMs };\n}\n\n// ---------------------------------------------------------------------------\n// Data loading\n// ---------------------------------------------------------------------------\n\nfunction loadAllSummaries(): Array<{ id: string; summary: SessionSummary }> {\n const base = historyBaseDir();\n if (!existsSync(base)) return [];\n\n const results: Array<{ id: string; summary: SessionSummary }> = [];\n for (const name of readdirSync(base)) {\n const summaryPath = historySessionSummaryPath(name);\n if (existsSync(summaryPath)) {\n try {\n const raw = readFileSync(summaryPath, 'utf-8');\n results.push({ id: name, summary: JSON.parse(raw) as SessionSummary });\n continue;\n } catch { /* fall through to live rebuild */ }\n }\n // No session.json — synthesize from live state if session is still in-flight\n const live = buildLiveSummary(name);\n if (live) results.push({ id: name, summary: live });\n }\n // Newest first\n results.sort((a, b) => new Date(b.summary.startedAt).getTime() - new Date(a.summary.startedAt).getTime());\n return results;\n}\n\n/**\n * Synthesize a SessionSummary on demand for an in-flight session (no `session.json` yet).\n * Reads the session's `cwd` from the first `session-start` event, then reads live\n * `state.json` and maps it to the same shape `writeSessionSummary` produces.\n * Fields that are only finalized at completion are marked null/empty.\n * Returns null if events or live state can't be read.\n */\nfunction buildLiveSummary(sessionId: string): SessionSummary | null {\n const eventsPath = historyEventsPath(sessionId);\n if (!existsSync(eventsPath)) return null;\n\n // Extract cwd from the session-start event (only place it's recorded in the history dir)\n let cwd: string | null = null;\n try {\n const lines = readFileSync(eventsPath, 'utf-8').split('\\n');\n for (const line of lines) {\n if (!line.trim()) continue;\n try {\n const ev = JSON.parse(line) as HistoryEvent;\n if (ev.event === 'session-start' && typeof ev.data.cwd === 'string') {\n cwd = ev.data.cwd;\n break;\n }\n } catch { continue; }\n }\n } catch { return null; }\n if (!cwd) return null;\n\n const sPath = statePath(cwd, sessionId);\n if (!existsSync(sPath)) return null;\n\n let session: Session;\n try {\n session = JSON.parse(readFileSync(sPath, 'utf-8')) as Session;\n } catch { return null; }\n\n // Live wall clock: created → now. activeMs is already flushed periodically by the daemon;\n // both may lag the true live value by one poll interval (~seconds), acceptable for a read-only view.\n const liveWallClockMs = Date.now() - new Date(session.createdAt).getTime();\n\n return {\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 ?? null,\n activeMs: session.activeMs,\n wallClockMs: session.wallClockMs ?? liveWallClockMs,\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: liveWallClockMs > 0\n ? Math.max(0, session.activeMs - (session.userBlockedMs ?? 0))\n / Math.max(1, liveWallClockMs - (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: null,\n achievements: [],\n xpGained: 0,\n sentiment: null,\n };\n}\n\nfunction loadEvents(sessionId: string): HistoryEvent[] {\n const eventsPath = historyEventsPath(sessionId);\n if (!existsSync(eventsPath)) return [];\n const lines = readFileSync(eventsPath, 'utf-8').split('\\n').filter(l => l.trim());\n const events: HistoryEvent[] = [];\n for (const line of lines) {\n try { events.push(JSON.parse(line) as HistoryEvent); } catch { continue; }\n }\n return events;\n}\n\nfunction findSession(idOrName: string): { id: string; summary: SessionSummary } | null {\n // Try exact ID match first\n const summaryPath = historySessionSummaryPath(idOrName);\n if (existsSync(summaryPath)) {\n try {\n return { id: idOrName, summary: JSON.parse(readFileSync(summaryPath, 'utf-8')) as SessionSummary };\n } catch { /* fall through */ }\n }\n // Exact-ID path with no session.json — try live rebuild before falling back to search\n if (existsSync(historySessionDir(idOrName))) {\n const live = buildLiveSummary(idOrName);\n if (live) return { id: idOrName, summary: live };\n }\n // Search by name or partial ID (loadAllSummaries handles live rebuild for in-flight sessions)\n const all = loadAllSummaries();\n return all.find(s =>\n s.id.startsWith(idOrName) ||\n s.summary.name === idOrName ||\n s.summary.name?.includes(idOrName),\n ) ?? null;\n}\n\n// ---------------------------------------------------------------------------\n// Duration parsing\n// ---------------------------------------------------------------------------\n\nfunction parseSince(since: string): number {\n const match = since.match(/^(\\d+)\\s*(d|h|m|w)$/);\n if (!match) {\n console.error(`Error: invalid --since format \"${since}\". Use e.g. 7d, 24h, 30m, 2w`);\n process.exit(1);\n }\n const n = parseInt(match[1]!, 10);\n const unit = match[2]!;\n const ms = { d: 86400000, h: 3600000, m: 60000, w: 604800000 }[unit]!;\n return Date.now() - n * ms;\n}\n\n// ---------------------------------------------------------------------------\n// Formatters\n// ---------------------------------------------------------------------------\n\nfunction fmtStatus(status: string): string {\n return c(statusColor(status), status);\n}\n\nfunction fmtDate(iso: string): string {\n const d = new Date(iso);\n return d.toLocaleDateString('en-US', { month: 'short', day: 'numeric' }) + ' ' +\n d.toLocaleTimeString('en-US', { hour: '2-digit', minute: '2-digit', hour12: false });\n}\n\nfunction fmtProject(cwd: string): string {\n const parts = cwd.split('/');\n return parts.slice(-2).join('/');\n}\n\n// ---------------------------------------------------------------------------\n// Subcommands\n// ---------------------------------------------------------------------------\n\nfunction listSessions(opts: {\n cwd?: string; status?: string; since?: string; search?: string;\n limit: number; json: boolean;\n}): void {\n let sessions = loadAllSummaries();\n\n if (opts.cwd) {\n const abs = resolve(opts.cwd);\n sessions = sessions.filter(s => s.summary.cwd === abs);\n }\n if (opts.status) {\n sessions = sessions.filter(s => s.summary.status === opts.status);\n }\n if (opts.since) {\n const cutoff = parseSince(opts.since);\n sessions = sessions.filter(s => new Date(s.summary.startedAt).getTime() >= cutoff);\n }\n if (opts.search) {\n const q = opts.search.toLowerCase();\n sessions = sessions.filter(s =>\n s.summary.task.toLowerCase().includes(q) ||\n (s.summary.name ?? '').toLowerCase().includes(q) ||\n s.summary.messages.some(m => m.content.toLowerCase().includes(q)),\n );\n }\n\n sessions = sessions.slice(0, opts.limit);\n\n if (opts.json) {\n console.log(JSON.stringify(sessions.map(s => s.summary), null, 2));\n return;\n }\n\n if (sessions.length === 0) {\n console.log(c('gray', 'No sessions found.'));\n return;\n }\n\n for (const { summary: s } of sessions) {\n const name = s.name ? c('white', s.name) : c('gray', s.sessionId.slice(0, 8));\n const status = fmtStatus(s.status);\n const date = c('gray', fmtDate(s.startedAt));\n const dur = formatDuration(s.activeMs);\n const proj = c('gray', fmtProject(s.cwd));\n const agents = s.agentCount > 0 ? `${s.agentCount} agents` : '';\n const cycles = s.cycleCount > 0 ? `${s.cycleCount} cycles` : '';\n const meta = [agents, cycles, dur].filter(Boolean).join(', ');\n\n console.log(`${date} ${status} ${name} ${DIM}${meta}${RESET} ${proj}`);\n\n const taskPreview = s.task.length > 100 ? s.task.slice(0, 100) + '...' : s.task;\n console.log(` ${DIM}${taskPreview}${RESET}`);\n console.log('');\n }\n\n const total = loadAllSummaries().length;\n if (total > sessions.length) {\n console.log(c('gray', ` Showing ${sessions.length} of ${total} sessions. Use --limit or filters to see more.`));\n }\n}\n\nfunction showSession(idOrName: string, opts: { json: boolean; events: boolean }): void {\n const found = findSession(idOrName);\n if (!found) {\n console.error(`Error: session \"${idOrName}\" not found`);\n process.exit(1);\n }\n\n const { id, summary: s } = found;\n\n if (opts.json && !opts.events) {\n console.log(JSON.stringify(s, null, 2));\n return;\n }\n\n if (opts.events) {\n const events = loadEvents(id);\n if (opts.json) {\n console.log(JSON.stringify(events, null, 2));\n return;\n }\n if (events.length === 0) {\n console.log(c('gray', 'No events recorded.'));\n return;\n }\n for (const e of events) {\n const time = c('gray', fmtDate(e.ts));\n const event = c('cyan', e.event.padEnd(18));\n const data = formatEventData(e);\n console.log(`${time} ${event} ${data}`);\n }\n return;\n }\n\n // Detail view\n const inProgress = s.completedAt == null;\n const inProgressTag = inProgress ? ` ${c('yellow', '(in progress)')}` : '';\n console.log(`${BOLD}${s.name ?? s.sessionId.slice(0, 8)}${RESET} ${fmtStatus(s.status)}${inProgressTag}`);\n console.log(`${DIM}ID:${RESET} ${s.sessionId}`);\n console.log(`${DIM}Project:${RESET} ${s.cwd}`);\n console.log(`${DIM}Model:${RESET} ${s.model ?? 'default'}`);\n console.log(`${DIM}Started:${RESET} ${fmtDate(s.startedAt)}`);\n console.log(`${DIM}Ended:${RESET} ${s.completedAt ? fmtDate(s.completedAt) : c('gray', '— still running')}`);\n const { computeMs, interactiveMs } = splitAgentTime(s.agents);\n const wallStr = s.wallClockMs ? formatDuration(s.wallClockMs) : '—';\n console.log(`${DIM}Active:${RESET} ${formatDuration(s.activeMs)} ${DIM}Wall:${RESET} ${wallStr}`);\n if (interactiveMs > 0) {\n console.log(`${DIM}Compute:${RESET} ${formatDuration(computeMs)} ${DIM}Interactive:${RESET} ${formatDuration(interactiveMs)} ${DIM}(TUI wait time, not compute)${RESET}`);\n }\n if (s.userBlockedMs > 0) {\n console.log(`${DIM}Waiting on user:${RESET} ${formatDuration(s.userBlockedMs)} ${DIM}(blocked on sis ask, not compute)${RESET}`);\n }\n console.log('');\n\n // Task\n console.log(`${BOLD}Task${RESET}`);\n console.log(s.task);\n console.log('');\n\n // Context\n if (s.context) {\n console.log(`${BOLD}Context${RESET}`);\n console.log(s.context.length > 500 ? s.context.slice(0, 500) + '...' : s.context);\n console.log('');\n }\n\n // Agents\n if (s.agents.length > 0) {\n console.log(`${BOLD}Agents${RESET} (${s.agents.length})`);\n for (const a of s.agents) {\n const name = a.nickname ? `${a.name} \"${a.nickname}\"` : a.name;\n const type = a.agentType ? c('gray', ` [${a.agentType}]`) : '';\n const interactive = isInteractiveAgent(a.agentType) ? c('yellow', ' (interactive)') : '';\n const blocked = a.userBlockedMs ?? 0;\n const waiting = blocked > 0 ? ` ${DIM}· ${formatDuration(blocked)} waiting${RESET}` : '';\n console.log(` ${fmtStatus(a.status)} ${name}${type}${interactive} ${DIM}${formatDuration(a.activeMs)}${RESET}${waiting}`);\n }\n console.log('');\n }\n\n // Cycles\n if (s.cycles.length > 0) {\n console.log(`${BOLD}Cycles${RESET} (${s.cycles.length})`);\n for (const cy of s.cycles) {\n const mode = cy.mode ? c('magenta', cy.mode) : '';\n const blocked = cy.userBlockedMs ?? 0;\n const waiting = blocked > 0 ? ` ${DIM}· ${formatDuration(blocked)} waiting${RESET}` : '';\n console.log(` ${DIM}#${cy.cycle}${RESET} ${mode} ${cy.agentsSpawned} agents ${DIM}${formatDuration(cy.activeMs)}${RESET}${waiting}`);\n }\n console.log('');\n }\n\n // Messages\n if (s.messages.length > 0) {\n console.log(`${BOLD}Messages${RESET} (${s.messages.length})`);\n for (const m of s.messages) {\n const src = c('gray', m.source);\n const preview = m.content.length > 120 ? m.content.slice(0, 120) + '...' : m.content;\n console.log(` ${src} ${preview}`);\n }\n console.log('');\n }\n\n // Completion report\n if (s.completionReport) {\n console.log(`${BOLD}Completion Report${RESET}`);\n console.log(s.completionReport);\n console.log('');\n }\n\n // Achievements\n if (s.achievements.length > 0) {\n console.log(`${BOLD}Achievements Unlocked${RESET}`);\n console.log(` ${s.achievements.join(', ')}`);\n console.log('');\n }\n\n // Final mood signals\n if (s.finalMoodSignals) {\n const sig = s.finalMoodSignals;\n const parts = [\n sig.recentCrashes > 0 ? c('red', `${sig.recentCrashes} crashes`) : null,\n `${sig.activeAgentCount ?? 0} active agents`,\n `cycle ${sig.cycleCount ?? 0}`,\n `hour ${sig.hourOfDay}`,\n sig.idleDurationMs > 60000 ? `idle ${formatDuration(sig.idleDurationMs)}` : null,\n ].filter(Boolean);\n console.log(`${DIM}Final signals: ${parts.join(' · ')}${RESET}`);\n }\n}\n\nfunction formatEventData(e: HistoryEvent): string {\n const d = e.data;\n switch (e.event) {\n case 'session-start':\n return `${c('white', (d.task as string).slice(0, 80))} ${c('gray', fmtProject(d.cwd as string))}`;\n case 'session-named':\n return c('white', d.name as string);\n case 'agent-spawned':\n return `${c('white', d.agentId as string)} ${d.agentType ?? ''} ${DIM}${(d.instruction as string)?.slice(0, 60) ?? ''}...${RESET}`;\n case 'agent-nicknamed':\n return `${d.agentId} \"${c('white', d.nickname as string)}\"`;\n case 'agent-completed':\n return `${d.agentId} ${DIM}${formatDuration(d.activeMs as number)}${RESET} ${DIM}${(d.reportSummary as string)?.slice(0, 60) ?? ''}${RESET}`;\n case 'agent-exited':\n return `${d.agentId} ${fmtStatus(d.status as string)} ${d.reason ?? ''}`;\n case 'cycle-boundary':\n return `#${d.cycle} ${d.mode ? c('magenta', d.mode as string) : ''} ${d.agentsSpawned} agents`;\n case 'signals-snapshot': {\n const sig = d.signals as Record<string, unknown> | undefined;\n return `${d.from} → ${c('white', d.to as string)} ${sig ? `crashes=${sig.recentCrashes} agents=${sig.activeAgentCount ?? 0}` : ''}`;\n }\n case 'message':\n return `${c('gray', d.source as string)} ${(d.content as string).slice(0, 80)}`;\n case 'review-started': {\n const fileParts = typeof d.filePath === 'string' ? d.filePath.split('/').slice(-2).join('/') : '';\n return `${c('cyan', d.type as string)} ${c('gray', fileParts)}`;\n }\n case 'agent-killed':\n return `${d.agentId} ${fmtStatus(d.status as string)} ${DIM}${formatDuration(d.activeMs as number)}${RESET} ${d.reason ?? ''}`;\n case 'agent-restarted':\n return `${d.agentId} restart #${d.restartCount} ${DIM}was ${d.previousStatus}${RESET}`;\n case 'rollback':\n return `cycle ${d.fromCycle} → ${d.toCycle} ${d.killedAgentCount} agents killed`;\n case 'session-resumed':\n return `was ${fmtStatus(d.previousStatus as string)} ${d.lostAgentCount} agents lost`;\n case 'session-continued':\n return `${d.cycleCount} cycles ${DIM}${formatDuration(d.activeMs as number)}${RESET}`;\n case 'session-end':\n return `${fmtStatus(d.status as string)} ${formatDuration(d.activeMs as number)} ${d.agentCount} agents ${d.cycleCount} cycles`;\n default:\n return JSON.stringify(d);\n }\n}\n\nfunction showStats(opts: { cwd?: string; since?: string; json: boolean }): void {\n // Exclude in-flight sessions — their activeMs/wallClockMs are live snapshots that\n // would skew aggregate averages, efficiency, and percentiles.\n let sessions = loadAllSummaries().filter(s => s.summary.completedAt != null);\n\n if (opts.cwd) {\n const abs = resolve(opts.cwd);\n sessions = sessions.filter(s => s.summary.cwd === abs);\n }\n if (opts.since) {\n const cutoff = parseSince(opts.since);\n sessions = sessions.filter(s => new Date(s.summary.startedAt).getTime() >= cutoff);\n }\n\n if (sessions.length === 0) {\n console.log(c('gray', 'No sessions found.'));\n return;\n }\n\n const completed = sessions.filter(s => s.summary.status === 'completed');\n const killed = sessions.filter(s => s.summary.status === 'killed');\n const totalActiveMs = sessions.reduce((sum, s) => sum + s.summary.activeMs, 0);\n const totalAgents = sessions.reduce((sum, s) => sum + s.summary.agentCount, 0);\n const totalCycles = sessions.reduce((sum, s) => sum + s.summary.cycleCount, 0);\n const totalMessages = sessions.reduce((sum, s) => sum + s.summary.messages.length, 0);\n\n // Per-project breakdown\n const byProject = new Map<string, { count: number; activeMs: number; agents: number }>();\n for (const { summary: s } of sessions) {\n const proj = s.cwd;\n const entry = byProject.get(proj) ?? { count: 0, activeMs: 0, agents: 0 };\n entry.count++;\n entry.activeMs += s.activeMs;\n entry.agents += s.agentCount;\n byProject.set(proj, entry);\n }\n\n // Avg session duration\n const avgMs = totalActiveMs / sessions.length;\n\n // Efficiency\n const efficiencyValues: number[] = [];\n for (const { summary: s } of sessions) {\n const eff = s.efficiency ?? (s.wallClockMs\n ? Math.max(0, s.activeMs - (s.userBlockedMs ?? 0))\n / Math.max(1, s.wallClockMs - (s.userBlockedMs ?? 0))\n : null);\n if (eff != null) efficiencyValues.push(eff);\n }\n const avgEfficiency = efficiencyValues.length > 0\n ? efficiencyValues.reduce((a, b) => a + b, 0) / efficiencyValues.length\n : null;\n\n // Duration distributions (p50/p90)\n const sortedActiveMs = sessions.map(s => s.summary.activeMs).sort((a, b) => a - b);\n const n = sortedActiveMs.length;\n const p50Ms = n >= 3 ? sortedActiveMs[Math.ceil(50 / 100 * n) - 1]! : null;\n const p90Ms = n >= 3 ? sortedActiveMs[Math.ceil(90 / 100 * n) - 1]! : null;\n\n // Per-agent-type performance\n const agentTypeMap = new Map<string, { count: number; totalMs: number; crashed: number; completed: number }>();\n for (const { summary: s } of sessions) {\n for (const a of s.agents) {\n const type = a.agentType ?? 'untyped';\n const entry = agentTypeMap.get(type) ?? { count: 0, totalMs: 0, crashed: 0, completed: 0 };\n entry.count++;\n entry.totalMs += a.activeMs;\n if (a.status === 'crashed') entry.crashed++;\n if (a.status === 'completed') entry.completed++;\n agentTypeMap.set(type, entry);\n }\n }\n\n // Temporal patterns\n const hourBlocks = new Map<string, number>();\n const dayCounts = new Map<string, number>();\n const dayNames = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'];\n for (const { summary: s } of sessions) {\n const d = new Date(s.startedAt);\n const hour = d.getHours();\n const blockStart = hour - (hour % 2);\n const blockLabel = `${String(blockStart).padStart(2, '0')}:00–${String(blockStart + 2).padStart(2, '0')}:00`;\n hourBlocks.set(blockLabel, (hourBlocks.get(blockLabel) ?? 0) + 1);\n const day = dayNames[d.getDay()]!;\n dayCounts.set(day, (dayCounts.get(day) ?? 0) + 1);\n }\n\n if (opts.json) {\n console.log(JSON.stringify({\n total: sessions.length,\n completed: completed.length,\n killed: killed.length,\n totalActiveMs,\n avgActiveMs: Math.round(avgMs),\n avgEfficiency,\n p50Ms,\n p90Ms,\n totalAgents,\n totalCycles,\n totalMessages,\n byProject: Object.fromEntries([...byProject.entries()].map(([k, v]) => [k, v])),\n agentTypes: Object.fromEntries([...agentTypeMap.entries()].map(([k, v]) => [k, {\n ...v,\n avgMs: Math.round(v.totalMs / v.count),\n crashRate: v.count > 0 ? v.crashed / v.count : 0,\n completionRate: v.count > 0 ? v.completed / v.count : 0,\n }])),\n temporalPatterns: sessions.length >= 5 ? {\n hourBlocks: Object.fromEntries(hourBlocks),\n dayOfWeek: Object.fromEntries(dayCounts),\n } : null,\n }, null, 2));\n return;\n }\n\n console.log(`${BOLD}Session History Stats${RESET}`);\n console.log('');\n console.log(` ${BOLD}Sessions:${RESET} ${sessions.length} total ${c('cyan', `${completed.length} completed`)} ${c('red', `${killed.length} killed`)}`);\n const timeLine = ` ${BOLD}Time:${RESET} ${formatDuration(totalActiveMs)} total ${formatDuration(avgMs)} avg` +\n (p50Ms != null && p90Ms != null ? ` ${DIM}p50=${formatDuration(p50Ms)} p90=${formatDuration(p90Ms)}${RESET}` : '');\n console.log(timeLine);\n if (avgEfficiency != null) {\n const effColor = avgEfficiency >= 0.7 ? 'green' : avgEfficiency >= 0.4 ? 'yellow' : 'red';\n console.log(` ${BOLD}Efficiency:${RESET} ${c(effColor, (avgEfficiency * 100).toFixed(1) + '%')} ${DIM}(${efficiencyValues.length} sessions with data)${RESET}`);\n }\n console.log(` ${BOLD}Agents:${RESET} ${totalAgents} spawned (${(totalAgents / sessions.length).toFixed(1)} avg/session)`);\n console.log(` ${BOLD}Cycles:${RESET} ${totalCycles} total (${(totalCycles / sessions.length).toFixed(1)} avg/session)`);\n console.log(` ${BOLD}Messages:${RESET} ${totalMessages} total`);\n console.log('');\n\n console.log(`${BOLD}By Project${RESET}`);\n const sorted = [...byProject.entries()].sort((a, b) => b[1].count - a[1].count);\n for (const [proj, data] of sorted) {\n console.log(` ${c('gray', fmtProject(proj))} ${data.count} sessions ${formatDuration(data.activeMs)} ${data.agents} agents`);\n }\n\n // Per-agent-type performance table\n if (agentTypeMap.size > 0) {\n console.log('');\n console.log(`${BOLD}By Agent Type${RESET}`);\n const typeHeader = ` ${'Type'.padEnd(20)} ${'Count'.padStart(6)} ${'Avg Time'.padStart(10)} ${'Crash %'.padStart(8)} ${'Done %'.padStart(8)}`;\n console.log(`${DIM}${typeHeader}${RESET}`);\n const sortedTypes = [...agentTypeMap.entries()].sort((a, b) => b[1].count - a[1].count);\n for (const [type, data] of sortedTypes) {\n const avgTime = formatDuration(data.totalMs / data.count);\n const crashRate = data.count > 0 ? ((data.crashed / data.count) * 100).toFixed(0) + '%' : '0%';\n const completionRate = data.count > 0 ? ((data.completed / data.count) * 100).toFixed(0) + '%' : '0%';\n const crashColor = data.crashed > 0 ? 'red' : 'green';\n console.log(` ${type.padEnd(20)} ${String(data.count).padStart(6)} ${avgTime.padStart(10)} ${c(crashColor, crashRate.padStart(8))} ${c('cyan', completionRate.padStart(8))}`);\n }\n }\n\n // Temporal patterns\n if (sessions.length >= 5) {\n console.log('');\n console.log(`${BOLD}Temporal Patterns${RESET}`);\n const topBlocks = [...hourBlocks.entries()].sort((a, b) => b[1] - a[1]).slice(0, 3);\n console.log(` ${DIM}Busiest times:${RESET} ${topBlocks.map(([label, count]) => `${label} (${count})`).join(' ')}`);\n const dayOrder = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'];\n const dayParts = dayOrder.map(d => `${d} ${dayCounts.get(d) ?? 0}`);\n console.log(` ${DIM}By day:${RESET} ${dayParts.join(' ')}`);\n }\n}\n\n// ---------------------------------------------------------------------------\n// Registration\n// ---------------------------------------------------------------------------\n\nexport function registerHistory(program: Command): void {\n program\n .command('history')\n .description('Browse session history and metrics')\n .argument('[session]', 'Session ID or name to inspect')\n .option('--cwd <path>', 'Filter by project directory')\n .option('--status <status>', 'Filter by status (completed, killed)')\n .option('--since <duration>', 'Filter by recency (e.g. 7d, 24h, 2w)')\n .option('--search <query>', 'Search task text and messages')\n .option('--events', 'Show raw event timeline')\n .option('--stats', 'Show aggregate statistics')\n .option('--json', 'Output as JSON')\n .option('-n, --limit <n>', 'Max sessions to show', '20')\n .action(async (session: string | undefined, opts: {\n cwd?: string; status?: string; since?: string; search?: string;\n events?: boolean; stats?: boolean; json?: boolean; limit: string;\n }) => {\n const limit = parseInt(opts.limit, 10) || 20;\n const json = opts.json ?? false;\n\n if (opts.stats) {\n showStats({ cwd: opts.cwd, since: opts.since, json });\n return;\n }\n\n if (session) {\n showSession(session, { json, events: opts.events ?? false });\n return;\n }\n\n listSessions({\n cwd: opts.cwd,\n status: opts.status,\n since: opts.since,\n search: opts.search,\n limit,\n json,\n });\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 type { Command } from 'commander';\nimport { sendRequest } from '../client.js';\nimport type { Request } from '../../shared/protocol.js';\nimport type { Session } from '../../shared/types.js';\nimport { exportSessionToZip } from '../../shared/session-export.js';\n\nexport { exportSessionToZip };\n\nexport function registerExport(program: Command): void {\n program\n .command('export')\n .description('Export session data as zip to ~/Downloads')\n .argument('[session-id]', 'Session ID (defaults to SISYPHUS_SESSION_ID or active session)')\n .option('--cwd <path>', 'Project directory override')\n .action(async (sessionIdArg?: string, opts?: { cwd?: string }) => {\n let sessionId = sessionIdArg ?? process.env.SISYPHUS_SESSION_ID;\n const cwd = opts?.cwd ?? process.env['SISYPHUS_CWD'] ?? process.cwd();\n\n if (!sessionId) {\n const request: Request = { type: 'status', cwd };\n const response = await sendRequest(request);\n if (response.ok) {\n const session = response.data?.session as Session | undefined;\n if (session) {\n sessionId = session.id;\n }\n }\n }\n\n if (!sessionId) {\n console.error('Error: No session ID provided and no active session found.');\n console.error('Usage: sis admin export [session-id]');\n process.exit(1);\n }\n\n try {\n const outputPath = await exportSessionToZip(sessionId, cwd);\n console.log(`Exported to ${outputPath}`);\n } catch (err) {\n console.error(`Error: ${(err as Error).message}`);\n process.exit(1);\n }\n });\n}\n","import type { Command } from 'commander';\nimport { rmSync } from 'node:fs';\nimport { tmpdir } from 'node:os';\nimport { sendRequest } from '../client.js';\nimport type { Request } from '../../shared/protocol.js';\nimport type { Session } from '../../shared/types.js';\nimport { loadConfig } from '../../shared/config.js';\nimport { exportSessionToZip } from '../../shared/session-export.js';\nimport { uploadSession, isUploadConfigured } from '../../shared/upload.js';\nimport { buildManifest } from '../../shared/manifest.js';\nimport { getSession } from '../../daemon/state.js';\nimport { getSisyphusVersion } from '../../shared/version.js';\n\nexport function registerUpload(program: Command): void {\n program\n .command('upload')\n .description('Upload a session zip to the configured upload endpoint')\n .argument('[session-id]', 'Session ID (defaults to SISYPHUS_SESSION_ID or active session)')\n .option('--cwd <path>', 'Project directory override')\n .action(async (sessionIdArg?: string, opts?: { cwd?: string }) => {\n let sessionId = sessionIdArg ?? process.env.SISYPHUS_SESSION_ID;\n const cwd = opts?.cwd ?? process.env['SISYPHUS_CWD'] ?? process.cwd();\n\n if (!sessionId) {\n const request: Request = { type: 'status', cwd };\n const response = await sendRequest(request);\n if (response.ok) {\n const session = response.data?.session as Session | undefined;\n if (session) {\n sessionId = session.id;\n }\n }\n }\n\n if (!sessionId) {\n console.error('Error: No session ID provided and no active session found.');\n console.error('Usage: sis admin upload [session-id]');\n process.exit(1);\n }\n\n const config = loadConfig(cwd);\n if (!isUploadConfigured(config.upload)) {\n console.error(\n \"Error: upload not configured. Run 'sis admin configure-upload <url-with-token>' or set { upload: { url, token } } in .sisyphus/config.json.\",\n );\n process.exit(1);\n }\n\n let zipPath: string;\n try {\n zipPath = await exportSessionToZip(sessionId, cwd, { reveal: false, outputDir: tmpdir() });\n } catch (err) {\n console.error(`Error: ${(err as Error).message}`);\n process.exit(1);\n }\n\n try {\n const session = getSession(cwd, sessionId);\n if (session.status !== 'completed') {\n console.warn(`warning: session ${sessionId} is not completed (status: ${session.status}); uploading anyway`);\n }\n\n const manifest = buildManifest({ session, status: 'completed', config, sisyphusVersion: getSisyphusVersion() });\n\n let result: Awaited<ReturnType<typeof uploadSession>>;\n try {\n result = await uploadSession({ config: config.upload, zipPath, manifest });\n } catch (err) {\n const errMsg = (err as Error).message;\n const persistReq: Request = {\n type: 'set-upload-status',\n sessionId,\n cwd,\n status: 'failed',\n error: errMsg,\n };\n try {\n await sendRequest(persistReq);\n } catch {\n // daemon unreachable — best-effort\n }\n console.error(`Upload failed: ${errMsg}`);\n process.exit(1);\n }\n\n const persistReq: Request = {\n type: 'set-upload-status',\n sessionId,\n cwd,\n status: 'uploaded',\n storageKey: result!.storageKey,\n };\n try {\n const resp = await sendRequest(persistReq);\n if (!resp.ok) {\n console.warn(`warning: could not persist upload status (${resp.error ? resp.error : 'no error detail'})`);\n }\n } catch {\n console.warn('warning: daemon unreachable — upload status not persisted to session state');\n }\n\n console.log(`Uploaded to ${result!.storageKey}`);\n } finally {\n rmSync(zipPath!, { force: true });\n }\n });\n}\n","import { readFile } from 'node:fs/promises';\nimport type { SessionManifest } from './manifest.js';\nimport type { UploadConfig } from './config.js';\n\nexport type { UploadConfig };\n\nexport interface UploadResult {\n storageKey: string;\n userId: string;\n uploadedAt: string;\n}\n\nfunction parseWorkerError(body: string): string {\n try {\n const parsed = JSON.parse(body);\n if (parsed && typeof parsed.error === 'string') return parsed.error;\n } catch { /* fall through */ }\n return body;\n}\n\nexport class UploadError extends Error {\n constructor(public readonly status: number, rawBody: string) {\n const parsed = parseWorkerError(rawBody);\n super(`HTTP ${status}: ${parsed}`);\n }\n}\n\nexport function isUploadConfigured(upload: UploadConfig | undefined): upload is UploadConfig {\n return !!upload && upload.url.length > 0 && upload.token.length > 0;\n}\n\nexport async function uploadSession(args: {\n config: UploadConfig;\n zipPath: string;\n manifest: SessionManifest;\n}): Promise<UploadResult> {\n const { config, zipPath, manifest } = args;\n\n const formData = new FormData();\n formData.append('manifest', new Blob([JSON.stringify(manifest)], { type: 'application/json' }));\n formData.append('bundle', new Blob([await readFile(zipPath)], { type: 'application/zip' }), `${manifest.sessionId}.zip`);\n\n const res = await fetch(`${config.url}/upload`, {\n method: 'POST',\n headers: { Authorization: `Bearer ${config.token}` },\n body: formData,\n });\n\n if (!res.ok) {\n const rawBody = await res.text();\n const body = rawBody.length > 4096 ? rawBody.slice(0, 4096) + '… [truncated]' : rawBody;\n throw new UploadError(res.status, body);\n }\n\n return res.json() as Promise<UploadResult>;\n}\n","import os from 'node:os';\nimport type { Session } from './types.js';\nimport type { Config, EffortLevel } from './config.js';\n\nexport type ManifestStatus = 'completed' | 'failed' | 'cancelled';\nexport type ManifestEffortTier = 'low' | 'medium' | 'high' | 'xhigh';\n\nexport interface SessionManifest {\n // userId is omitted on the wire — Worker injects from token\n userId?: string;\n sessionId: string;\n sisyphusVersion: string;\n hostname: string;\n platform: NodeJS.Platform;\n status: ManifestStatus;\n completedAt: string;\n durationMs: number;\n wallClockMs: number;\n model: string;\n effortTier: ManifestEffortTier;\n cycleCount: number;\n agentCount: number;\n goal: string;\n}\n\n// 'max' is Config's wider effort level; collapse to 'xhigh' for the manifest's narrower union\nfunction mapEffortFallback(level: EffortLevel | undefined): ManifestEffortTier | undefined {\n if (level === undefined) return undefined;\n if (level === 'max') return 'xhigh';\n return level;\n}\n\nfunction resolveEffortTier(session: Session, config: Config): ManifestEffortTier {\n if (session.effort) return session.effort;\n const fromConfig = mapEffortFallback(config.orchestratorEffort);\n if (fromConfig) return fromConfig;\n return 'medium';\n}\n\nexport function buildManifest(args: {\n session: Session;\n // explicit — Session.status ('active' | 'paused' | 'completed') doesn't overlap with ManifestStatus\n status: ManifestStatus;\n config: Config;\n sisyphusVersion: string;\n}): SessionManifest {\n const { session, status, config, sisyphusVersion } = args;\n return {\n sessionId: session.id,\n sisyphusVersion,\n hostname: os.hostname(),\n platform: process.platform,\n status,\n completedAt: session.completedAt ?? new Date().toISOString(),\n durationMs: session.activeMs,\n wallClockMs: session.wallClockMs ?? 0,\n model: session.model ?? config.model ?? '',\n effortTier: resolveEffortTier(session, config),\n cycleCount: session.orchestratorCycles.length,\n agentCount: session.agents.length,\n goal: session.task.slice(0, 200),\n };\n}\n","import { readFileSync } from 'node:fs';\nimport { resolve } from 'node:path';\n\nfunction readSisyphusVersion(): string {\n // Bundled: dist/daemon.js → ../package.json\n // Source (tsx): src/shared/version.ts → ../../package.json\n for (const rel of ['../package.json', '../../package.json']) {\n try {\n const raw = readFileSync(resolve(import.meta.dirname, rel), 'utf-8');\n const pkg = JSON.parse(raw) as { name?: string; version?: string };\n if (pkg.name === 'sisyphi' && pkg.version) return pkg.version;\n } catch {}\n }\n return '0.0.0';\n}\n\nconst cachedVersion = readSisyphusVersion();\n\nexport function getSisyphusVersion(): string {\n return cachedVersion;\n}\n","import type { Command } from 'commander';\nimport { execSync } from 'node:child_process';\nimport { assertTmux } from '../tmux.js';\nimport { shellQuote } from '../../shared/shell.js';\n\n/**\n * Find the home session (non-ssyph_ session with matching @sisyphus_cwd).\n * Returns the tmux session name, or null if none found.\n *\n * Queries by $N session ID — tmux's -t <name> can substring-match the wrong\n * session under sparse env, and scratch may run from any shell context.\n */\nfunction findHomeSession(cwd: string): string | null {\n const normalizedCwd = cwd.replace(/\\/+$/, '');\n let output: string;\n try {\n output = execSync('tmux list-sessions -F \"#{session_id}|#{session_name}\"', {\n encoding: 'utf-8',\n stdio: ['pipe', 'pipe', 'pipe'],\n }).trim();\n } catch {\n return null;\n }\n for (const line of output.split('\\n').filter(Boolean)) {\n const pipeIdx = line.indexOf('|');\n if (pipeIdx < 0) continue;\n const sessId = line.slice(0, pipeIdx);\n const name = line.slice(pipeIdx + 1);\n if (name.startsWith('ssyph_')) continue;\n try {\n const val = execSync(\n `tmux show-options -t ${shellQuote(sessId)} -v @sisyphus_cwd`,\n { encoding: 'utf-8', stdio: ['pipe', 'pipe', 'pipe'] },\n ).trim();\n if (val === normalizedCwd) return name;\n } catch {\n // Option not set — skip\n }\n }\n return null;\n}\n\nexport function registerScratch(program: Command): void {\n program\n .command('scratch [prompt...]')\n .description('Open a standalone Claude Code session in the home tmux session')\n .option('-c, --cwd <path>', 'Working directory for the Claude session')\n .action((promptParts: string[], opts: { cwd?: string }) => {\n assertTmux();\n\n const cwd = opts.cwd ?? process.env['SISYPHUS_CWD'] ?? process.cwd();\n const homeSession = findHomeSession(cwd);\n\n if (!homeSession) {\n // Fall back to current tmux session\n const current = execSync('tmux display-message -p \"#{session_name}\"', {\n encoding: 'utf-8',\n }).trim();\n openScratchWindow(current, cwd, promptParts.join(' '));\n return;\n }\n\n openScratchWindow(homeSession, cwd, promptParts.join(' '));\n });\n}\n\nfunction openScratchWindow(tmuxSession: string, cwd: string, prompt: string): void {\n const windowId = execSync(\n `tmux new-window -t ${shellQuote(tmuxSession + ':')} -n \"scratch\" -c ${shellQuote(cwd)} -P -F \"#{window_id}\"`,\n { encoding: 'utf-8' },\n ).trim();\n\n let cmd = 'claude --dangerously-skip-permissions';\n if (prompt) {\n cmd += ` -p ${shellQuote(prompt)}`;\n }\n\n execSync(\n `tmux send-keys -t ${shellQuote(windowId)} ${shellQuote(cmd)} Enter`,\n );\n\n console.log(`Scratch session opened in ${tmuxSession}`);\n}\n","import type { Command } from 'commander';\nimport { join, resolve, dirname } from 'node:path';\nimport { existsSync, readFileSync, writeFileSync, renameSync, readdirSync } from 'node:fs';\nimport { contextDir, sessionsDir } from '../../shared/paths.js';\nimport type { RequirementStatus } from '../../shared/requirements-types.js';\n\n// Keeps the JSON Schema enum in sync with the TS union.\nconst _statusCheck: RequirementStatus[] = ['draft', 'question', 'approved', 'rejected', 'deferred'];\n\nfunction resolveContextArtifact(\n file: string | undefined,\n opts: { sessionId?: string; cwd?: string },\n filename: string,\n notFoundMessage: string,\n): string {\n const cwd = opts.cwd || process.env.SISYPHUS_CWD || process.cwd();\n if (file) return resolve(file);\n\n const sessionId = opts.sessionId || process.env.SISYPHUS_SESSION_ID;\n if (sessionId) {\n const target = join(contextDir(cwd, sessionId), filename);\n if (!existsSync(target)) {\n console.error(`Error: File not found: ${target}`);\n process.exit(1);\n }\n return target;\n }\n\n const dir = sessionsDir(cwd);\n if (existsSync(dir)) {\n const sessions = readdirSync(dir);\n for (const session of sessions.reverse()) {\n const candidate = join(dir, session, 'context', filename);\n if (existsSync(candidate)) return candidate;\n }\n }\n\n console.error(`Error: ${notFoundMessage}`);\n process.exit(1);\n}\n\nexport function registerReview(program: Command): void {\n program\n .command('requirements')\n .description('Export and inspect EARS requirements produced by `sisyphus:spec` (or compatible writers)')\n .argument('[file]', 'Path to requirements.json (auto-detected from session if omitted)')\n .option('--session-id <id>', 'Session ID to find requirements for')\n .option('--cwd <path>', 'Project directory')\n .option('--schema', 'Print the requirements.json schema and exit')\n .option('--annotated', 'Print the schema with writing guidance annotations and exit')\n .option('--export', 'Render requirements.json into requirements.md (no LLM tokens; overwrites existing requirements.md)')\n .option('--force', 'With --export: overwrite existing requirements.md even if hand-edited; existing file is moved to requirements.md.bak before overwrite')\n .addHelpText('after', `\nFile resolution (first match wins):\n 1. Positional [file] argument\n 2. --session-id (or SISYPHUS_SESSION_ID env) → .sisyphus/sessions/<id>/context/requirements.json\n 3. Most recent session with a requirements.json\n\nExamples:\n $ sis admin requirements Auto-detect from current session\n $ sis admin requirements path/to/requirements.json Open a specific file\n $ sis admin requirements --session-id abc123 Target a specific session\n $ sis admin requirements --schema Print the JSON schema\n $ sis admin requirements --annotated Print schema with writing guidance\n $ sis admin requirements --export Render requirements.md from JSON\n $ sis admin requirements --export --session-id abc123 Target a specific session\n $ sis admin requirements --export --force Overwrite even if hand-edited\n`)\n .action(async (file, opts) => {\n if (opts.force && !opts.export) {\n console.error('Error: --force requires --export');\n process.exit(1);\n }\n if (opts.export && opts.schema) {\n console.error('Error: --export cannot be combined with --schema');\n process.exit(1);\n }\n if (opts.export && opts.annotated) {\n console.error('Error: --export cannot be combined with --annotated');\n process.exit(1);\n }\n if (opts.export) {\n const targetPath = resolveContextArtifact(\n file,\n opts,\n 'requirements.json',\n 'No requirements.json found. Provide a path or use --session-id.',\n );\n\n if (!existsSync(targetPath)) {\n console.error(`Error: File not found: ${targetPath}`);\n process.exit(1);\n }\n\n const parsed = JSON.parse(readFileSync(targetPath, 'utf-8')) as Record<string, unknown>;\n const rendered = renderRequirementsMarkdown(parsed);\n const outPath = join(dirname(targetPath), 'requirements.md');\n const tmpPath = outPath + '.tmp';\n\n if (existsSync(outPath)) {\n const existing = readFileSync(outPath, 'utf-8');\n if (existing !== rendered) {\n if (!opts.force) {\n process.stderr.write(\n `Error: ${outPath} has been hand-edited (differs from rendered output).\\n` +\n `Use --force to overwrite (existing file backed up to requirements.md.bak).\\n`,\n );\n process.exit(1);\n }\n const bakPath = outPath + '.bak';\n renameSync(outPath, bakPath);\n process.stderr.write(`Note: Existing requirements.md backed up to ${bakPath}\\n`);\n }\n }\n\n writeFileSync(tmpPath, rendered, 'utf-8');\n renameSync(tmpPath, outPath);\n process.stdout.write(resolve(outPath) + '\\n');\n return;\n }\n if (opts.schema) {\n process.stdout.write(JSON.stringify(REQUIREMENTS_SCHEMA, null, 2) + '\\n');\n return;\n }\n if (opts.annotated) {\n process.stdout.write(REQUIREMENTS_ANNOTATED + '\\n');\n return;\n }\n });\n\n}\n\n// ── Requirements schema ──────────────────────────────────────────────\n\nconst REQUIREMENTS_SCHEMA = {\n $schema: 'https://json-schema.org/draft/2020-12/schema',\n $defs: {\n requirementItem: {\n type: 'object',\n required: ['id', 'title', 'ears', 'criteria', 'status'],\n additionalProperties: false,\n properties: {\n id: { type: 'string', pattern: '^REQ-\\\\d{3}$' },\n title: { type: 'string' },\n ears: {\n type: 'object',\n required: ['shall'],\n properties: {\n when: { type: 'string' },\n while: { type: 'string' },\n if: { type: 'string' },\n where: { type: 'string' },\n shall: { type: 'string' },\n },\n oneOf: [\n { required: ['when', 'shall'] },\n { required: ['while', 'shall'] },\n { required: ['if', 'shall'] },\n { required: ['where', 'shall'] },\n ],\n },\n criteria: {\n type: 'array',\n items: {\n type: 'object',\n required: ['text', 'checked'],\n properties: {\n text: { type: 'string' },\n checked: { type: 'boolean' },\n },\n },\n },\n status: { type: 'string', enum: _statusCheck },\n agentNotes: { type: 'string' },\n userNotes: { type: 'string' },\n },\n },\n },\n title: 'Sisyphus Requirements',\n description: 'EARS-format behavioral requirements',\n type: 'object',\n required: ['meta', 'groups'],\n properties: {\n meta: {\n type: 'object',\n required: ['lastModified'],\n additionalProperties: false,\n properties: {\n title: { type: 'string' },\n subtitle: { type: 'string' },\n summary: { type: 'string' },\n version: { type: 'integer' },\n lastModified: { type: 'string', format: 'date-time' },\n draft: { type: 'integer', minimum: 1 },\n stage: { type: 'string', enum: ['stage-2-in-progress', 'stage-2-verdict-pending', 'writer-redispatch-pending', 'stage-2-done', 'stage-3-done'] },\n bounceIterations: { type: 'integer', minimum: 0 },\n openAskId: { type: 'string' },\n writerRedispatchIterations: { type: 'integer' },\n },\n },\n groups: {\n type: 'array',\n items: {\n type: 'object',\n required: ['id', 'name', 'description', 'requirements'],\n additionalProperties: false,\n properties: {\n id: { type: 'string', pattern: '^[a-z0-9-]+$' },\n name: { type: 'string' },\n description: { type: 'string' },\n context: { type: 'string' },\n requirements: {\n type: 'array',\n items: { $ref: '#/$defs/requirementItem' },\n },\n safeAssumptions: {\n type: 'array',\n items: { $ref: '#/$defs/requirementItem' },\n },\n },\n },\n },\n },\n};\n\nconst REQUIREMENTS_ANNOTATED = `# requirements.json — Annotated Writing Guide\n#\n# This is NOT valid JSON — it's a reference showing every field with\n# inline guidance. Run \\`sis admin requirements --schema\\` for the raw\n# JSON Schema.\n#\n# Safe assumptions must satisfy the same EARS shape requirements as\n# regular requirements.\n#\n# ── BEHAVIORAL ONLY ──\n# Each requirement describes what the system does at its boundary —\n# what the user, caller, or tester observes. The design (already\n# approved) is the technical contract; the plan phase (later) handles\n# implementation breakdown. Do not write requirements that name files,\n# functions, libraries, data structures, or algorithms.\n\n{\n \"meta\": {\n \"title\": \"Feature Name Requirements\",\n // ^ Human-readable title.\n\n \"subtitle\": \"EARS Behavioral Spec\",\n // ^ Secondary label. Usually \"EARS Behavioral Spec\".\n\n \"summary\": \"2-3 sentences: what is being built, who it's for, and the key constraint.\",\n // ^ Orients the reviewer before they see individual items.\n // Lead with the user-facing outcome only. The implementation\n // belongs in design.md (technical) and plan.md (steps).\n\n \"version\": 1,\n // ^ Always 1. Reserved for future schema versioning.\n\n \"lastModified\": \"2026-04-04T12:00:00Z\",\n // ^ ISO 8601 timestamp. Update on each save.\n\n \"draft\": 1\n // ^ Increment on each revision cycle (1, 2, 3...).\n\n // ── Spec lead state-machine fields (do NOT write unless you are the spec lead) ──\n // \"stage\": \"stage-2-in-progress\" | \"stage-2-verdict-pending\" | \"writer-redispatch-pending\" | \"stage-2-done\" | \"stage-3-done\"\n // \"bounceIterations\": number — bounce-loop counter, never decrements\n // \"openAskId\": string — background ask id for active Stage 2 review deck\n // \"writerRedispatchIterations\": number — writer re-dispatch counter, never decrements\n },\n\n \"groups\": [\n // Each group is a thematic area (e.g., \"Session Creation\", \"Error Recovery\").\n // Aim for 3-7 groups. Present them in narrative order.\n {\n \"id\": \"kebab-case-group-id\",\n // ^ Unique, stable across drafts. Use kebab-case.\n\n \"name\": \"Group Display Name\",\n // ^ Short label shown as the group header.\n\n \"description\": \"What this group covers — one sentence.\",\n // ^ Shown below the group name. Keep it scannable.\n\n \"context\": \"Rich introduction paragraph for this group.\\\\n\\\\nInclude ASCII diagrams:\\\\n\\\\n User ──► Action ──► Response\\\\n │\\\\n ┌─────┴─────┐\\\\n ▼ ▼\\\\n Success Failure\",\n // ^ Use ASCII diagrams for flows, state transitions, architecture.\n // Newlines are literal \\\\n in JSON.\n\n \"requirements\": [\n {\n \"id\": \"REQ-001\",\n // ^ Sequential within the file. REQ-001, REQ-002, etc.\n // Unique across ALL groups, not just this one.\n\n \"title\": \"Short requirement title\",\n // ^ One line.\n\n \"ears\": {\n // ── EARS pattern object ──\n // Exactly ONE condition key + \"shall\". Never a flat string.\n //\n // Pick the matching pattern:\n // Event-driven: { \"when\": \"When [trigger]\", \"shall\": \"...\" }\n // State-driven: { \"while\": \"While [condition]\", \"shall\": \"...\" }\n // Unwanted: { \"if\": \"If [bad condition]\", \"shall\": \"...\" }\n // Optional: { \"where\": \"Where [feature flag]\", \"shall\": \"...\" }\n\n \"when\": \"When the user runs \\`start\\` with a task description\",\n // ^ Start with the EARS keyword: When/While/If/Where.\n\n \"shall\": \"the system shall return a session ID and surface the orchestrator's first response\"\n // ^ Observable behavior — what the caller sees at the boundary.\n // Not \"spawn\", \"instantiate\", \"import\", or any verb that\n // requires reading code to verify.\n },\n\n \"criteria\": [\n // Acceptance criteria — checkable assertions.\n {\n \"text\": \"Session ID is returned to the caller\",\n // ^ One testable statement per criterion.\n\n \"checked\": false\n // ^ Always false when you write it.\n }\n ],\n\n \"status\": \"draft\",\n // ^ Your control. Values:\n // \"draft\" — new or revised, needs review\n // \"question\" — blocked on user input, won't proceed without answer\n // \"approved\" — user approved\n // \"rejected\" — user rejected\n // \"deferred\" — postponed, skip for now\n //\n // Approved items are skipped on re-entry.\n\n \"agentNotes\": \"Context for the reviewer — why this requirement exists, caveats, trade-offs.\",\n // ^ Explain anything non-obvious. Link to code if relevant.\n\n \"userNotes\": \"\"\n // ^ Leave empty. The user writes back to you here.\n }\n ],\n\n /*\n * safeAssumptions — items the writer is confident the user will accept without\n * discussion: defaults, conventions, and obviously-correct behaviors that follow\n * directly from the design.\n *\n * NOT safe assumptions: anything novel, anything the writer is uncertain about,\n * or anything that would change with a small design tweak.\n *\n * Field shape: identical to a requirements item — same id pattern (REQ-NNN), same\n * ears structure, same criteria, same agentNotes. Use agentNotes to briefly justify\n * why each item qualifies as safe.\n */\n \"safeAssumptions\": [\n {\n \"id\": \"REQ-010\",\n \"title\": \"Default session timeout is 30 minutes\",\n \"ears\": {\n \"where\": \"Where no custom timeout is configured\",\n \"shall\": \"the system shall expire idle sessions after 30 minutes\"\n },\n \"criteria\": [\n { \"text\": \"Session expires after 30 minutes of inactivity\", \"checked\": false }\n ],\n \"status\": \"draft\",\n \"agentNotes\": \"Safe assumption: 30-minute idle timeout is a near-universal default and the design doc does not specify an alternative.\",\n \"userNotes\": \"\"\n }\n ]\n }\n ]\n}`;\n\n// ── Requirements markdown renderer ───────────────────────────────────\n\nfunction renderRequirementItem(out: string[], req: Record<string, unknown>): void {\n const item: string[] = [];\n\n item.push(`### ${req.id}: ${req.title}`);\n item.push('');\n item.push(`**Status:** ${req.status}`);\n item.push('');\n\n const ears = req.ears as Record<string, string> | undefined;\n if (ears) {\n const earsClauses: string[] = [];\n if (ears.when) earsClauses.push(ears.when);\n if (ears.while) earsClauses.push(ears.while);\n if (ears.if) earsClauses.push(ears.if);\n if (ears.where) earsClauses.push(ears.where);\n if (ears.shall) earsClauses.push(ears.shall);\n if (earsClauses.length > 0) {\n item.push(earsClauses.join(', '));\n item.push('');\n }\n }\n\n const criteria = req.criteria as Array<{ text: string; checked: boolean }> | undefined;\n if (criteria && criteria.length > 0) {\n item.push('**Acceptance Criteria:**');\n item.push('');\n for (const c of criteria) {\n item.push(`- [${c.checked ? 'x' : ' '}] ${c.text}`);\n }\n item.push('');\n }\n\n const agentNotes = req.agentNotes ? String(req.agentNotes).trim() : '';\n if (agentNotes) {\n item.push('**Agent Notes:**');\n item.push('');\n item.push(agentNotes);\n item.push('');\n }\n\n const userNotes = req.userNotes ? String(req.userNotes).trim() : '';\n if (userNotes) {\n item.push('**User Notes:**');\n item.push('');\n item.push(userNotes);\n item.push('');\n }\n\n while (item.length > 0 && item[item.length - 1] === '') item.pop();\n out.push(...item);\n}\n\nfunction renderRequirementsMarkdown(json: Record<string, unknown>): string {\n const meta = json.meta as Record<string, unknown>;\n const groups = json.groups as Array<Record<string, unknown>>;\n const out: string[] = [];\n\n const title = meta.title ? String(meta.title) : undefined;\n if (title) {\n out.push(`# ${title}`);\n out.push('');\n }\n if (meta.subtitle) {\n out.push(`*${meta.subtitle}*`);\n out.push('');\n }\n const draftParts: string[] = [];\n if (meta.draft) draftParts.push(`Draft ${meta.draft}`);\n if (meta.lastModified) draftParts.push(String(meta.lastModified));\n if (draftParts.length > 0) {\n out.push(draftParts.join(' — '));\n out.push('');\n }\n if (title || draftParts.length > 0) {\n out.push('---');\n out.push('');\n }\n if (meta.summary) {\n out.push(String(meta.summary));\n out.push('');\n }\n\n for (let gi = 0; gi < groups.length; gi++) {\n const group = groups[gi];\n\n if (gi > 0) {\n out.push('');\n out.push('');\n }\n\n out.push(`## ${group.name}`);\n out.push('');\n\n if (group.description) {\n out.push(String(group.description));\n out.push('');\n }\n\n if (group.context) {\n out.push(String(group.context));\n out.push('');\n }\n\n const requirements = group.requirements as Array<Record<string, unknown>>;\n for (let ri = 0; ri < requirements.length; ri++) {\n if (ri > 0) out.push('');\n renderRequirementItem(out, requirements[ri]);\n }\n\n const safeAssumptions = group.safeAssumptions as Array<Record<string, unknown>> | undefined;\n if (safeAssumptions && safeAssumptions.length > 0) {\n out.push('');\n out.push('### Safe Assumptions');\n out.push('');\n for (let si = 0; si < safeAssumptions.length; si++) {\n if (si > 0) out.push('');\n renderRequirementItem(out, safeAssumptions[si]);\n }\n }\n }\n\n return out.join('\\n') + '\\n';\n}\n","import type { Command } from 'commander';\nimport { basename } from 'node:path';\nimport { sendRequest } from '../client.js';\nimport { buildCompanionContext } from '../../tui/lib/context.js';\nimport { renderCompanion } from '../../shared/companion-render.js';\nimport { ACHIEVEMENTS } from '../../shared/companion-types.js';\nimport type { CompanionState, CompanionMemoryState, ObservationCategory, ObservationRecord } from '../../shared/companion-types.js';\nimport { MemoryStoreParseError } from '../../shared/companion-types.js';\nimport { createBadgeGallery, renderBadgeCard } from '../../shared/companion-badges.js';\nimport { loadMemoryStrict, sanitizeForDisplay } from '../../daemon/companion-memory.js';\nimport { showCommentaryPopup } from '../../daemon/companion-popup.js';\n\nconst CATEGORY_LABELS: Record<string, string> = {\n milestone: 'Milestone',\n session: 'Session',\n time: 'Time',\n behavioral: 'Behavioral',\n};\n\nconst CATEGORY_ORDER: Array<[ObservationCategory, string]> = [\n ['session-sentiments', 'Session Sentiments'],\n ['repo-impressions', 'Repo Impressions'],\n ['user-patterns', 'User Patterns'],\n ['notable-moments', 'Notable Moments'],\n];\n\nfunction formatTimestamp(iso: string): string {\n const d = new Date(iso);\n const hh = String(d.getHours()).padStart(2, '0');\n const mm = String(d.getMinutes()).padStart(2, '0');\n const ss = String(d.getSeconds()).padStart(2, '0');\n const yyyy = d.getFullYear();\n const mon = String(d.getMonth() + 1).padStart(2, '0');\n const dd = String(d.getDate()).padStart(2, '0');\n return `${hh}:${mm}:${ss} ${yyyy}-${mon}-${dd}`;\n}\n\nasync function runCompanionMemory(opts: { repo?: string }): Promise<void> {\n let state: CompanionMemoryState;\n try {\n state = loadMemoryStrict();\n } catch (err) {\n if (err instanceof MemoryStoreParseError) {\n process.stderr.write(`${err.message}\\n`);\n process.exitCode = 1;\n return;\n }\n throw err;\n }\n console.log(renderMemory(state, opts.repo));\n}\n\nexport function renderMemory(state: CompanionMemoryState, repo?: string): string {\n let observations: ObservationRecord[] = state.observations;\n if (repo !== undefined) {\n observations = observations.filter(obs => obs.repo === repo);\n }\n\n const grouped = new Map<ObservationCategory, ObservationRecord[]>();\n for (const [cat] of CATEGORY_ORDER) grouped.set(cat, []);\n for (const obs of observations) grouped.get(obs.category)?.push(obs);\n for (const [, recs] of grouped) recs.sort((a, b) => b.timestamp.localeCompare(a.timestamp));\n\n const lines: string[] = [];\n for (const [cat, label] of CATEGORY_ORDER) {\n const recs = grouped.get(cat) ?? [];\n if (recs.length > 0) {\n lines.push(`${label} (${recs.length})`);\n for (const rec of recs) {\n const ts = formatTimestamp(rec.timestamp);\n const src = `(${rec.source})`.padEnd(7);\n const text = sanitizeForDisplay(rec.text);\n const repoStr = rec.repo !== null ? `[${sanitizeForDisplay(basename(rec.repo))}]` : '[—]';\n lines.push(` [${ts}] ${src} ${text} ${repoStr}`);\n }\n } else {\n lines.push(label);\n lines.push(' (none)');\n }\n lines.push('');\n }\n if (lines[lines.length - 1] === '') lines.pop();\n\n const prunedStr = state.prunedAt !== null\n ? state.prunedAt.slice(0, 10)\n : 'never';\n lines.push('');\n lines.push(`${observations.length} observations total, last pruned ${prunedStr}`);\n\n return lines.join('\\n');\n}\n\nexport function registerCompanion(program: Command): void {\n const companion = program\n .command('companion')\n .description('Show companion profile and stats');\n\n // Default action — preserves existing bare `sis companion` behavior\n companion\n .option('--name <name>', 'Set companion name')\n .option('--badges', 'Show badge gallery')\n .action(async (opts: { name?: string; badges?: boolean }) => {\n const res = await sendRequest({ type: 'companion', name: opts.name });\n if (!res.ok) {\n console.error(res.error);\n process.exit(1);\n }\n const companion = res.data as unknown as CompanionState;\n\n // Header: face + identity\n const face = renderCompanion(companion, ['face', 'boulder'], { color: true });\n const displayName = companion.name !== null ? companion.name : '(unnamed)';\n console.log();\n console.log(` ${face}`);\n console.log();\n console.log(` ${displayName} · Level ${companion.level} ${companion.title}`);\n console.log(` Mood: ${companion.mood} · XP: ${companion.xp}`);\n console.log();\n\n // Stats\n const s = companion.stats;\n const endH = Math.floor(s.endurance / 3_600_000);\n console.log(' Stats');\n console.log(` Strength ${s.strength} sessions`);\n console.log(` Endurance ${endH}h total active`);\n console.log(` Wisdom ${s.wisdom} efficient sessions`);\n console.log(` Patience ${s.patience} persistence score`);\n console.log();\n\n if (opts.badges) {\n // Full badge gallery\n const gallery = createBadgeGallery(companion.achievements);\n console.log(` Badges ${companion.achievements.length}/${ACHIEVEMENTS.length} earned`);\n console.log();\n\n for (let i = 0; i < gallery.total; i++) {\n const def = gallery.achievements[i]!;\n const unlock = gallery.unlocked.get(def.id) ?? null;\n const card = renderBadgeCard(def, unlock);\n for (const line of card.lines) {\n console.log(` ${line}`);\n }\n console.log();\n }\n } else {\n // Compact achievement list\n const unlocked = new Set(companion.achievements.map(a => a.id));\n const byCategory = new Map<string, typeof ACHIEVEMENTS>();\n for (const def of ACHIEVEMENTS) {\n const group = byCategory.get(def.category) ?? [];\n group.push(def);\n byCategory.set(def.category, group);\n }\n\n console.log(` Achievements ${companion.achievements.length}/${ACHIEVEMENTS.length} (use --badges for gallery)`);\n for (const [category, defs] of byCategory) {\n const label = CATEGORY_LABELS[category] ?? category;\n const unlockedCount = defs.filter(d => unlocked.has(d.id)).length;\n console.log(` ${label} (${unlockedCount}/${defs.length})`);\n for (const def of defs) {\n const icon = unlocked.has(def.id) ? '✓' : '·';\n console.log(` ${icon} ${def.name} — ${def.description}`);\n }\n }\n console.log();\n }\n\n // Repos\n const repos = Object.entries(companion.repos);\n if (repos.length > 0) {\n repos.sort(([, a], [, b]) => b.visits - a.visits);\n console.log(' Repositories');\n for (const [path, mem] of repos.slice(0, 10)) {\n const nick = mem.nickname ? ` \"${mem.nickname}\"` : '';\n const parts = [`${mem.visits} visits`, `${mem.completions} completions`];\n if (mem.crashes > 0) parts.push(`${mem.crashes} crashes`);\n console.log(` ${path}${nick}`);\n console.log(` ${parts.join(' · ')}`);\n }\n if (repos.length > 10) {\n console.log(` … and ${repos.length - 10} more`);\n }\n console.log();\n }\n\n // Commentary\n if (companion.lastCommentary) {\n console.log(` \"${companion.lastCommentary.text}\"`);\n console.log();\n }\n });\n\n // New: memory subcommand\n companion\n .command('memory')\n .description('Show accumulated companion observations grouped by category')\n .option('--repo <path>', 'Filter observations by repo path')\n .action(async (opts: { repo?: string }) => {\n await runCompanionMemory(opts);\n });\n\n companion\n .command('context')\n .description('Output session context JSON for companion hook')\n .option('--cwd <path>', 'Project directory', process.cwd())\n .action((opts: { cwd: string }) => {\n const context = buildCompanionContext(opts.cwd);\n process.stdout.write(JSON.stringify({ additionalContext: context }));\n });\n\n companion\n .command('pane')\n .description('Open (or focus) a side claude pane next to the dashboard')\n .option('--cwd <path>', 'Project directory', process.cwd())\n .action(async (opts: { cwd: string }) => {\n const { openCompanionPane } = await import('../../tui/lib/tmux.js');\n openCompanionPane(opts.cwd);\n });\n\n companion\n .command('popup-test')\n .description('Show a test commentary popup to validate feedback key handling')\n .option('--text <text>', 'Custom popup text', 'Cycle complete. Everything went exactly as planned. Nothing suspicious here.')\n .action((opts: { text: string }) => {\n const feedback = showCommentaryPopup(opts.text);\n if (feedback === null) {\n console.error('No feedback received (popup suppressed or not in tmux).');\n process.exitCode = 1;\n return;\n }\n if (feedback.rating === 'comment' && feedback.comment !== undefined) {\n console.log(`rating: comment \"${feedback.comment}\"`);\n } else {\n console.log(`rating: ${feedback.rating}${feedback.comment !== undefined ? ` comment: ${feedback.comment}` : ''}`);\n }\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 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 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 { 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 { 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 { writeFileSync, readFileSync, unlinkSync, existsSync } from 'node:fs';\nimport { tmpdir } from 'node:os';\nimport { join, resolve } from 'node:path';\nimport { getMoodFace, getMoodTmuxColor } from '../shared/companion-render.js';\nimport type { FeedbackRating } from '../shared/companion-types.js';\nimport { loadCompanion } from './companion.js';\nimport { loadConfig } from '../shared/config.js';\nimport { execSafe } from '../shared/exec.js';\nimport { shellQuote } from '../shared/shell.js';\n\nconst POPUP_WIDTH = 38;\nconst INNER_WIDTH = POPUP_WIDTH - 6; // 2 border + 2 padding each side\nconst POPUP_DURATION = 15;\nconst POPUP_TMP_PREFIX = join(tmpdir(), 'sisyphus-popup');\nconst POPUP_SCRIPT = join(tmpdir(), 'sisyphus-popup.sh');\nconst POPUP_RESULT_PREFIX = join(tmpdir(), 'sisyphus-popup-result');\nconst WHIP_ANIMATION_PATH = resolve(import.meta.dirname, '../templates/whip-animation.sh');\nconst WHIP_ANIMATION_ROWS = 12; // canvas height baked into whip-frames.json\n\nexport interface PopupPage {\n text: string;\n title?: string; // overrides default face title\n}\n\nfunction wrapText(text: string, width: number): string[] {\n const words = text.split(' ');\n const lines: string[] = [];\n let current = '';\n for (const word of words) {\n if (current && current.length + 1 + word.length > width) {\n lines.push(current);\n current = word;\n } else {\n current = current ? `${current} ${word}` : word;\n }\n }\n if (current) lines.push(current);\n return lines;\n}\n\n/** Show a single commentary popup (convenience wrapper). */\nexport function showCommentaryPopup(text: string): { rating: FeedbackRating; comment?: string } | null {\n return showCommentaryPopupQueue([{ text }]);\n}\n\n/** Show one or more popup pages in sequence. Enter advances; last Enter closes. */\nexport function showCommentaryPopupQueue(pages: PopupPage[]): { rating: FeedbackRating; comment?: string } | null {\n if (pages.length === 0) return null;\n\n try {\n const config = loadConfig(process.cwd());\n if (config.companionPopup === false) return null;\n\n const companion = loadCompanion();\n const intensity = companion.debugMood?.scores[companion.mood] ?? 0;\n const face = getMoodFace(companion.mood, intensity);\n const moodColor = getMoodTmuxColor(companion.mood);\n const defaultTitle = ` (${face}) `;\n\n let maxContentHeight = 0;\n\n // Write each page's content file\n for (let i = 0; i < pages.length; i++) {\n const lines = wrapText(pages[i].text, INNER_WIDTH);\n const isLast = i === pages.length - 1;\n const hint = isLast ? '[0:ok 1:good 2:bad 3:whip]' : '[enter:next 0-3:rate]';\n const hintPad = Math.max(0, Math.floor((INNER_WIDTH - hint.length) / 2));\n const hintLine = ' '.repeat(hintPad + 2) + hint;\n const content = '\\n\\n' + lines.map(l => ` ${l}`).join('\\n') + '\\n\\n' + hintLine + '\\n';\n const contentLineCount = content.split('\\n').length - 1; // trailing \\n artifact\n const contentHeight = Math.max(contentLineCount + 2, 5);\n if (contentHeight > maxContentHeight) maxContentHeight = contentHeight;\n writeFileSync(`${POPUP_TMP_PREFIX}-${i}.txt`, content);\n }\n\n // Popup must fit the whip animation's 12-row canvas (+2 for border) since '3:whip' is always available.\n const whipAvailable = existsSync(WHIP_ANIMATION_PATH);\n if (whipAvailable && maxContentHeight < WHIP_ANIMATION_ROWS + 2) {\n maxContentHeight = WHIP_ANIMATION_ROWS + 2;\n }\n\n const initialTitle = pages[0].title ?? defaultTitle;\n\n const script = `#!/bin/sh\nprintf '\\\\033[?25l'\nstty -echo 2>/dev/null\nRESULT_FILE=${shellQuote(POPUP_RESULT_PREFIX)}\nPAGE=0\nTOTAL=${pages.length}\n\nshow_page() {\n printf '\\\\033[2J\\\\033[H'\n cat ${shellQuote(POPUP_TMP_PREFIX)}-$PAGE.txt\n}\n\nshow_page\nwhile IFS= read -r -n1 -t ${POPUP_DURATION} k; do\n case \"$k\" in\n 0) printf 'neutral' > \"$RESULT_FILE\"; break ;;\n 1) printf 'good' > \"$RESULT_FILE\"; break ;;\n 2) printf 'bad' > \"$RESULT_FILE\"; break ;;\n 3) printf 'whip' > \"$RESULT_FILE\"\n ${whipAvailable ? `bash ${shellQuote(WHIP_ANIMATION_PATH)}` : ':'}\n break ;;\n c|C)\n stty echo\n printf '\\\\033[2J\\\\033[H> '\n IFS= read -r -t 30 line\n printf 'comment:%s' \"$line\" > \"$RESULT_FILE\"\n break\n ;;\n '')\n PAGE=$((PAGE + 1))\n if [ $PAGE -ge $TOTAL ]; then\n printf 'neutral' > \"$RESULT_FILE\"\n break\n fi\n show_page\n ;;\n esac\ndone\nif [ ! -f \"$RESULT_FILE\" ]; then\n printf 'neutral' > \"$RESULT_FILE\"\nfi\n`;\n writeFileSync(POPUP_SCRIPT, script, { mode: 0o755 });\n\n // Delete stale result file before running popups\n try { unlinkSync(POPUP_RESULT_PREFIX); } catch { /* ignore */ }\n\n // Daemon runs outside tmux — target each attached client\n const clientsRaw = execSafe('tmux list-clients -F \"#{client_name} #{client_width}\"');\n if (!clientsRaw) return null;\n for (const line of clientsRaw.split('\\n').filter(Boolean)) {\n const lastSpace = line.lastIndexOf(' ');\n const client = line.slice(0, lastSpace);\n const clientWidth = parseInt(line.slice(lastSpace + 1), 10);\n if (!clientWidth) continue;\n const x = Math.max(0, clientWidth - POPUP_WIDTH);\n const args = [\n `-c ${shellQuote(client)}`,\n '-E -b rounded',\n `-T ${shellQuote(initialTitle)}`,\n `-S \"fg=${moodColor}\"`,\n `-s \"fg=${moodColor}\"`,\n `-x ${x} -y 0`,\n `-w ${POPUP_WIDTH} -h ${maxContentHeight}`,\n shellQuote(POPUP_SCRIPT),\n ].join(' ');\n execSafe(`tmux display-popup ${args}`);\n }\n\n // Read feedback written by the last client's popup\n let raw: string;\n try {\n raw = readFileSync(POPUP_RESULT_PREFIX, 'utf8').trim();\n } catch {\n return null;\n } finally {\n try { unlinkSync(POPUP_RESULT_PREFIX); } catch { /* ignore */ }\n }\n\n if (raw.startsWith('comment:')) {\n return { rating: 'comment', comment: raw.slice('comment:'.length) };\n }\n const validRatings: FeedbackRating[] = ['neutral', 'good', 'bad', 'whip'];\n const rating = validRatings.includes(raw as FeedbackRating) ? (raw as FeedbackRating) : 'neutral';\n return { rating };\n } catch { /* non-fatal */ }\n return null;\n}\n","import { homedir } from 'node:os';\nimport { join } from 'node:path';\nimport type { Command } from 'commander';\nimport {\n deployDown,\n deployListProviders,\n deployLogs,\n deploySsh,\n deployStatus,\n deployUp,\n deployUpdate,\n type UpOptions,\n} from '../deploy/runner.js';\nimport { PROVIDERS, type Provider } from '../deploy/creds.js';\nimport { authTailscale } from '../deploy/tailscale.js';\n\ninterface RawUpOptions {\n region?: string;\n arch?: string;\n size?: string;\n sshKey?: string;\n chromium?: boolean; // commander exposes --no-chromium as opts.chromium = false\n autoUpdate?: boolean;\n name?: string;\n yes?: boolean;\n}\n\ninterface DownOptions {\n yes?: boolean;\n}\n\nfunction assertArch(raw: string): 'arm' | 'x86' {\n if (raw === 'arm' || raw === 'x86') return raw;\n throw new Error(`Invalid --arch: ${raw}. Must be 'arm' or 'x86'.`);\n}\n\nfunction defaultRegion(provider: Provider): string {\n return provider === 'hetzner' ? 'nbg1' : 'us-east-1';\n}\n\nfunction resolveUpOptions(provider: Provider, raw: RawUpOptions): UpOptions {\n // arch/name/sshKey carry commander-supplied defaults — guaranteed defined.\n if (!raw.arch || !raw.name || !raw.sshKey) {\n throw new Error('Internal error: commander failed to apply defaults for --arch/--name/--ssh-key.');\n }\n const arch = assertArch(raw.arch);\n // --region's default is provider-specific, so commander can't supply it.\n const region = raw.region === undefined ? defaultRegion(provider) : raw.region;\n // --size has no default — undefined means \"fall through to the Terraform module's arch-based default\".\n const size = raw.size === undefined ? null : raw.size;\n // commander: --no-chromium → chromium === false; absent → undefined (default install on)\n const withChromium = raw.chromium !== false;\n const enableAutoUpdate = raw.autoUpdate !== false;\n const yes = raw.yes === true;\n return { region, arch, size, sshKey: raw.sshKey, name: raw.name, withChromium, enableAutoUpdate, yes };\n}\n\nexport function registerDeploy(program: Command): void {\n const deploy = program\n .command('deploy')\n .description('Provision a Tailscale-only sisyphus box on Hetzner or AWS via Terraform.');\n\n deploy\n .option('--providers', 'List available providers and provisioning status.')\n .action((opts: { providers?: boolean }) => {\n if (opts.providers) {\n deployListProviders();\n return;\n }\n deploy.help();\n });\n\n // sisyphus deploy auth tailscale — one-time OAuth client setup\n const auth = deploy.command('auth').description('Configure deploy credentials.');\n auth\n .command('tailscale')\n .description('Configure Tailscale OAuth client or fallback auth key.')\n .action(async () => {\n await authTailscale();\n });\n\n for (const provider of PROVIDERS) {\n const sub = deploy.command(provider).description(`${provider} commands.`);\n\n sub\n .command('up')\n .description(`Provision the ${provider} box (terraform init → plan → apply).`)\n .option('--region <region>', `Provider region (defaults: hetzner=nbg1, aws=us-east-1).`)\n .option('--arch <arch>', \"'arm' (default) or 'x86'. Picks the default --size and image.\", 'arm')\n .option('--size <size>', 'Instance type override (defaults follow --arch).')\n .option('--ssh-key <path>', 'Path to SSH public key.', join(homedir(), '.ssh', 'id_ed25519.pub'))\n .option('--no-chromium', 'Skip headless Chromium install.')\n .option('--no-auto-update', 'Skip the daily auto-update systemd timer.')\n .option('--name <name>', 'Box hostname / Tailscale node name.', 'sisyphus')\n .option('-y, --yes', 'Skip the re-provision confirmation prompt when state already exists.')\n .action(async (raw: RawUpOptions) => {\n const opts = resolveUpOptions(provider, raw);\n await deployUp(provider, opts);\n });\n\n sub\n .command('down')\n .description(`Destroy the ${provider} box (terraform destroy).`)\n .option('-y, --yes', 'Skip confirmation prompt.')\n .action(async (opts: DownOptions) => {\n await deployDown(provider, { yes: opts.yes === true });\n });\n\n sub\n .command('status')\n .description(`Print current ${provider} outputs (IP, hostname, instance type, est. cost).`)\n .action(() => {\n deployStatus(provider);\n });\n\n sub\n .command('ssh [remoteCmd...]')\n .description(`SSH (or mosh, if available) into the ${provider} box via Tailscale.`)\n .action((remoteCmd: string[]) => {\n deploySsh(provider, remoteCmd);\n });\n\n sub\n .command('logs')\n .description(`Tail cloud-init + daemon logs from the ${provider} box.`)\n .action(() => {\n deployLogs(provider);\n });\n\n sub\n .command('update')\n .description(`Run \\`npm i -g sisyphi@latest && systemctl --user restart sisyphusd\\` on the ${provider} box.`)\n .action(() => {\n deployUpdate(provider);\n });\n }\n\n}\n","import { spawn, spawnSync } from 'node:child_process';\nimport { copyFileSync, existsSync, mkdirSync, readFileSync } from 'node:fs';\nimport {\n deployProviderDir,\n deployStateBackupPath,\n deployStatePath,\n} from '../../shared/paths.js';\nimport { EXEC_ENV } from '../../shared/exec.js';\nimport { ensureDeployDir, loadProviderCreds, type Provider } from './creds.js';\nimport { formatCostLine } from './pricing.js';\nimport { clearRuntimeState, readRuntimeState, writeRuntimeState } from './runtime.js';\nimport { discoverNodeWithRetry, isTailscaleAvailable } from './tailnet.js';\nimport { providerModuleDir } from './templates.js';\nimport { mintTailscaleKey } from './tailscale.js';\n\n/**\n * UpOptions is the fully-resolved option struct passed to deployUp.\n * Defaults are applied at the commander layer (deploy.ts) so this\n * module can assume every field is populated.\n */\nexport interface UpOptions {\n region: string;\n arch: 'arm' | 'x86';\n size: string | null;\n sshKey: string;\n name: string;\n withChromium: boolean;\n enableAutoUpdate: boolean;\n yes: boolean;\n}\n\nexport interface DeployOutputs {\n ipv4: string;\n tailscale_hostname: string;\n ssh_command: string;\n instance_type: string;\n}\n\n/**\n * Run `terraform <args>` in the provider's working directory, streaming\n * output to the user. Returns exit code; throws on spawn failure.\n *\n * Working directory is the bundled provider module (read-only). State\n * is written to `~/.sisyphus/deploy/<provider>/terraform.tfstate` via\n * the `-state` flag, keeping the bundled module immutable across\n * provisions.\n */\nfunction runTerraform(provider: Provider, args: string[], extraEnv: Record<string, string>): number {\n ensureProviderStateDir(provider);\n ensureTerraformInstalled();\n\n const result = spawnSync('terraform', args, {\n cwd: providerModuleDir(provider),\n stdio: 'inherit',\n env: { ...EXEC_ENV, ...extraEnv },\n });\n if (result.error) throw result.error;\n // status is null when the process was killed by a signal — treat as failure.\n return result.status === null ? 1 : result.status;\n}\n\nfunction ensureTerraformInstalled(): void {\n const result = spawnSync('terraform', ['version'], { stdio: 'pipe', env: EXEC_ENV });\n if (result.error || result.status !== 0) {\n const platform = process.platform;\n const hint = platform === 'darwin'\n ? 'brew install terraform'\n : 'See https://developer.hashicorp.com/terraform/install';\n throw new Error(`terraform binary not found on PATH. Install: ${hint}`);\n }\n}\n\nfunction ensureProviderStateDir(provider: Provider): void {\n ensureDeployDir();\n const dir = deployProviderDir(provider);\n if (!existsSync(dir)) mkdirSync(dir, { recursive: true, mode: 0o700 });\n}\n\nfunction backupState(provider: Provider): void {\n const src = deployStatePath(provider);\n if (existsSync(src)) copyFileSync(src, deployStateBackupPath(provider));\n}\n\nfunction readSshPubkey(path: string): string {\n if (!existsSync(path)) {\n const privateKeyPath = path.replace(/\\.pub$/, '');\n throw new Error(\n `SSH pubkey not found at ${path}. Generate one with:\\n ssh-keygen -t ed25519 -f ${privateKeyPath}\\nor pass --ssh-key <path>.`,\n );\n }\n return readFileSync(path, 'utf-8').trim();\n}\n\nfunction readOutputs(provider: Provider): DeployOutputs | null {\n const result = spawnSync('terraform', ['output', '-json', `-state=${deployStatePath(provider)}`], {\n cwd: providerModuleDir(provider),\n encoding: 'utf-8',\n env: EXEC_ENV,\n });\n if (result.status !== 0) return null;\n\n try {\n const parsed = JSON.parse(result.stdout) as Record<string, { value: unknown }>;\n if (Object.keys(parsed).length === 0) return null;\n const required: Array<keyof DeployOutputs> = ['ipv4', 'tailscale_hostname', 'ssh_command', 'instance_type'];\n for (const k of required) {\n if (parsed[k]?.value === undefined) return null;\n }\n return {\n ipv4: String(parsed.ipv4!.value),\n tailscale_hostname: String(parsed.tailscale_hostname!.value),\n ssh_command: String(parsed.ssh_command!.value),\n instance_type: String(parsed.instance_type!.value),\n };\n } catch {\n return null;\n }\n}\n\nexport function isProvisioned(provider: Provider): boolean {\n if (!existsSync(deployStatePath(provider))) return false;\n return readOutputs(provider) !== null;\n}\n\n// ── Actions ──────────────────────────────────────────────────────────────────\n\nexport async function deployUp(provider: Provider, opts: UpOptions): Promise<void> {\n // Bail before minting a Tailscale key — re-running `up` on a live box has\n // surprising provider-specific behavior, and a single-use OAuth key would\n // be wasted if the user backs out.\n if (isProvisioned(provider) && !(await confirmReprovision(provider, opts.yes))) {\n return;\n }\n\n const sshPubkey = readSshPubkey(opts.sshKey);\n\n const creds = await loadProviderCreds(provider);\n const tsAuthKey = await mintTailscaleKey({ hostname: opts.name });\n\n const tfvars: Record<string, string> = {\n name: opts.name,\n region: opts.region,\n arch: opts.arch,\n ssh_pubkey: sshPubkey,\n ts_authkey: tsAuthKey,\n with_chromium: String(opts.withChromium),\n enable_auto_update: String(opts.enableAutoUpdate),\n };\n if (opts.size !== null) tfvars.size = opts.size;\n\n const tfvarArgs = Object.entries(tfvars).flatMap(([k, v]) => ['-var', `${k}=${v}`]);\n\n console.log(`\\n→ terraform init (${provider})...\\n`);\n let code = runTerraform(provider, ['init', '-input=false'], creds);\n if (code !== 0) throw new Error(`terraform init failed (exit ${code})`);\n\n backupState(provider);\n\n console.log(`\\n→ terraform plan (${provider})...\\n`);\n code = runTerraform(\n provider,\n ['plan', '-input=false', `-state=${deployStatePath(provider)}`, ...tfvarArgs],\n creds,\n );\n if (code !== 0) throw new Error(`terraform plan failed (exit ${code})`);\n\n console.log(`\\n→ terraform apply (${provider})...\\n`);\n code = runTerraform(\n provider,\n ['apply', '-input=false', '-auto-approve', `-state=${deployStatePath(provider)}`, ...tfvarArgs],\n creds,\n );\n if (code !== 0) throw new Error(`terraform apply failed (exit ${code})`);\n\n const outputs = readOutputs(provider);\n if (!outputs) {\n console.log(`\\nApplied — but could not parse outputs. Run \\`sis deploy ${provider} status\\`.`);\n return;\n }\n\n console.log('');\n console.log('Box provisioned. Cloud-init will run for ~3–5 minutes before the daemon is reachable.');\n console.log('');\n console.log(` Public IP: ${outputs.ipv4}`);\n console.log(` Requested hostname: ${outputs.tailscale_hostname}`);\n\n // Discover the box on the user's tailnet so subsequent ssh/logs/update\n // calls reach the right node even if Tailscale suffixed the hostname\n // (`sisyphus-1`) due to a stale offline node squatting the requested\n // name. Skip silently when local Tailscale isn't available.\n if (isTailscaleAvailable()) {\n process.stdout.write(' Waiting for tailnet join...');\n const node = await discoverNodeWithRetry(opts.name);\n if (node) {\n writeRuntimeState(provider, {\n tailscaleHostname: node.shortName,\n tailscaleFqdn: node.magicDnsName,\n tailscaleIpv4: node.ipv4,\n discoveredAt: new Date().toISOString(),\n });\n process.stdout.write(` joined as ${node.shortName} (${node.ipv4})\\n`);\n if (node.shortName !== opts.name) {\n console.log(` Note: Tailscale suffixed the hostname because \"${opts.name}\" was already`);\n console.log(' claimed by an offline node. Delete the stale node at');\n console.log(' https://login.tailscale.com/admin/machines to reuse the original name.');\n }\n } else {\n process.stdout.write(' no peer matched after 60s\\n');\n console.log(' (Cloud-init may still be installing Tailscale. Re-run `status` later.)');\n }\n } else {\n console.log(' (Local `tailscale` CLI not on PATH — skipping tailnet discovery.)');\n }\n\n console.log('');\n console.log(` Tail provisioning: sis deploy ${provider} logs`);\n console.log(` Verify daemon: sis deploy ${provider} ssh -- sis admin doctor`);\n console.log('');\n}\n\nexport async function deployDown(provider: Provider, opts: { yes: boolean }): Promise<void> {\n if (!existsSync(deployStatePath(provider))) {\n console.log(`No ${provider} state found at ${deployStatePath(provider)}. Nothing to destroy.`);\n return;\n }\n\n if (!opts.yes) {\n const outputs = readOutputs(provider);\n if (outputs) {\n console.log(`About to destroy ${provider} box \"${outputs.tailscale_hostname}\" (${outputs.instance_type}, ${outputs.ipv4}).`);\n } else {\n console.log(`About to destroy ${provider} state at ${deployStatePath(provider)}.`);\n }\n const confirmed = await confirm('Type \"yes\" to continue:');\n if (!confirmed) {\n console.log('Aborted.');\n return;\n }\n }\n\n const creds = await loadProviderCreds(provider);\n backupState(provider);\n // terraform destroy still parses the config; required vars must be set\n // even though their values don't affect the deletion API calls. Pass\n // placeholders — the actual values are already baked into state.\n const destroyVarArgs = [\n '-var', 'ssh_pubkey=destroy',\n '-var', 'ts_authkey=destroy',\n ];\n const code = runTerraform(\n provider,\n ['destroy', '-input=false', '-auto-approve', `-state=${deployStatePath(provider)}`, ...destroyVarArgs],\n creds,\n );\n if (code !== 0) throw new Error(`terraform destroy failed (exit ${code})`);\n clearRuntimeState(provider);\n console.log(`\\n${provider} box destroyed.`);\n}\n\nexport function deployStatus(provider: Provider): void {\n if (!isProvisioned(provider)) {\n console.log(`${provider}: not provisioned.`);\n return;\n }\n const outputs = readOutputs(provider);\n if (!outputs) {\n console.log(`${provider}: state present but outputs unreadable. Try \\`sis deploy ${provider} up\\` to reconcile.`);\n return;\n }\n const runtime = readRuntimeState(provider);\n const effectiveHost = runtime ? runtime.tailscaleHostname : outputs.tailscale_hostname;\n\n console.log(`${provider}: provisioned`);\n console.log(` Public IP: ${outputs.ipv4}`);\n console.log(` Tailscale hostname: ${effectiveHost}`);\n if (runtime) {\n console.log(` Tailscale IPv4: ${runtime.tailscaleIpv4}`);\n console.log(` MagicDNS FQDN: ${runtime.tailscaleFqdn}`);\n if (runtime.tailscaleHostname !== outputs.tailscale_hostname) {\n console.log(` (Requested \"${outputs.tailscale_hostname}\" but Tailscale assigned \"${runtime.tailscaleHostname}\".)`);\n }\n } else {\n console.log(' (No tailnet runtime state — re-run `up` or check that local tailscale is logged in.)');\n }\n console.log(` SSH: ssh sisyphus@${effectiveHost}`);\n console.log(` Instance type: ${outputs.instance_type}`);\n console.log(` ${formatCostLine(provider, outputs.instance_type)}`);\n}\n\nexport function deployListProviders(): void {\n const providers: Provider[] = ['hetzner', 'aws'];\n for (const p of providers) {\n const status = isProvisioned(p) ? 'provisioned' : 'not provisioned';\n console.log(` ${p.padEnd(10)} ${status}`);\n }\n}\n\n// ── ssh / logs / update ──────────────────────────────────────────────────────\n\n/**\n * Pick the host to SSH to: runtime state's discovered hostname (handles\n * Tailscale `-1` suffix) when present, otherwise the Terraform output.\n */\nexport function effectiveSshTarget(provider: Provider): string {\n const runtime = readRuntimeState(provider);\n if (runtime) return `sisyphus@${runtime.tailscaleHostname}`;\n\n const outputs = readOutputs(provider);\n if (!outputs) {\n throw new Error(`${provider} not provisioned. Run \\`sis deploy ${provider} up\\`.`);\n }\n return `sisyphus@${outputs.tailscale_hostname}`;\n}\n\nexport function deploySsh(provider: Provider, remoteCmd: string[]): void {\n const target = effectiveSshTarget(provider);\n\n const moshAvailable = spawnSync('mosh', ['--version'], { stdio: 'pipe', env: EXEC_ENV }).status === 0;\n const bin = moshAvailable && remoteCmd.length === 0 ? 'mosh' : 'ssh';\n const args = remoteCmd.length > 0 ? [target, ...remoteCmd] : [target];\n\n const child = spawn(bin, args, { stdio: 'inherit', env: EXEC_ENV });\n child.on('exit', (code) => process.exit(code === null ? 1 : code));\n}\n\nexport function deployLogs(provider: Provider): void {\n const target = effectiveSshTarget(provider);\n // tail -F survives log rotation; -n 200 gives recent context.\n const remoteCmd = 'tail -F -n 200 /var/log/cloud-init-output.log ~/.sisyphus/daemon.log 2>/dev/null';\n const child = spawn('ssh', [target, remoteCmd], { stdio: 'inherit', env: EXEC_ENV });\n child.on('exit', (code) => process.exit(code === null ? 1 : code));\n}\n\nexport function deployUpdate(provider: Provider): void {\n const target = effectiveSshTarget(provider);\n const remoteCmd = 'sudo npm i -g sisyphi@latest && systemctl --user restart sisyphusd && sisyphusd --version || true';\n const child = spawn('ssh', [target, remoteCmd], { stdio: 'inherit', env: EXEC_ENV });\n child.on('exit', (code) => process.exit(code === null ? 1 : code));\n}\n\n// ── helpers ──────────────────────────────────────────────────────────────────\n\nasync function confirm(prompt: string): Promise<boolean> {\n const { promptLine } = await import('./creds.js');\n const answer = await promptLine(`${prompt} `, false);\n return answer.toLowerCase() === 'yes';\n}\n\n/**\n * Warn before re-running `up` on an already-provisioned box. Behavior is\n * very different per provider:\n * - Hetzner: `user_data` is ForceNew, so a fresh `ts_authkey` triggers\n * destroy-and-recreate. All on-box state is lost.\n * - AWS: `user_data` updates in place by default; cloud-init won't re-run\n * on a live instance, so the freshly-minted Tailscale key is wasted.\n * Either way, `update` is the right tool for software pushes and `down`\n * + `up` is the right tool for an explicit rebuild.\n */\nasync function confirmReprovision(provider: Provider, yes: boolean): Promise<boolean> {\n const outputs = readOutputs(provider);\n console.log('');\n if (outputs) {\n console.log(`${provider} is already provisioned: \"${outputs.tailscale_hostname}\" (${outputs.instance_type}, ${outputs.ipv4}).`);\n } else {\n console.log(`${provider} state already exists at ${deployStatePath(provider)}.`);\n }\n if (provider === 'hetzner') {\n console.log('Re-running `up` on Hetzner will DESTROY and RECREATE the box (user_data is ForceNew).');\n console.log('All on-box state — daemon history, sessions, anything not in your repo — will be lost.');\n } else {\n console.log('Re-running `up` on AWS updates user_data in state but does NOT recreate the instance.');\n console.log('Cloud-init won\\'t re-run on the live box, and the freshly-minted Tailscale key will be wasted.');\n }\n console.log('');\n console.log(`To push a new sisyphus version: sis deploy ${provider} update`);\n console.log(`To rebuild from scratch: sis deploy ${provider} down && sis deploy ${provider} up`);\n console.log('');\n if (yes) return true;\n const confirmed = await confirm('Type \"yes\" to proceed anyway:');\n if (!confirmed) console.log('Aborted.');\n return confirmed;\n}\n","// Hardcoded monthly cost estimates (USD) for the instance types sisyphus\n// deploy provisions. Verified against provider list pricing on the date\n// below; users should treat the figure as informational, not authoritative.\n//\n// Bump LAST_VERIFIED whenever you re-check the table.\nexport const LAST_VERIFIED = '2026-05-06';\n\ninterface Price {\n monthlyUsd: number;\n arch: 'arm' | 'x86';\n}\n\nconst TABLE: Record<string, Price> = {\n // Hetzner Cloud — list pricing in EUR converted at ~1.08 USD/EUR.\n // EU-only (cax = ARM, cx = Intel x86):\n 'hetzner:cax11': { monthlyUsd: 4.00, arch: 'arm' },\n 'hetzner:cax21': { monthlyUsd: 7.00, arch: 'arm' },\n 'hetzner:cx22': { monthlyUsd: 4.50, arch: 'x86' },\n 'hetzner:cx32': { monthlyUsd: 8.00, arch: 'x86' },\n // US (ash / hil) — AMD x86 only (cpx series):\n 'hetzner:cpx11': { monthlyUsd: 4.85, arch: 'x86' },\n 'hetzner:cpx21': { monthlyUsd: 8.85, arch: 'x86' },\n\n // AWS EC2 us-east-1, on-demand, 730h/mo.\n 'aws:t4g.medium': { monthlyUsd: 24.40, arch: 'arm' },\n 'aws:t4g.large': { monthlyUsd: 48.91, arch: 'arm' },\n 'aws:t3.medium': { monthlyUsd: 30.37, arch: 'x86' },\n 'aws:t3.large': { monthlyUsd: 60.74, arch: 'x86' },\n};\n\nexport function lookupMonthlyCost(provider: string, instanceType: string): number | null {\n const entry = TABLE[`${provider}:${instanceType}`];\n return entry ? entry.monthlyUsd : null;\n}\n\nexport function formatCostLine(provider: string, instanceType: string): string {\n const cost = lookupMonthlyCost(provider, instanceType);\n if (cost === null) {\n return `Estimated cost: unknown for ${provider}:${instanceType} (not in pricing table). Verify against your bill.`;\n }\n return `Estimated cost: ~$${cost.toFixed(2)}/mo (pricing last verified ${LAST_VERIFIED}; verify against your bill for current rates).`;\n}\n","import { existsSync, readFileSync, unlinkSync } from 'node:fs';\nimport { atomicWrite } from '../../daemon/lib/atomic.js';\nimport { deployRuntimePath } from '../../shared/paths.js';\nimport type { Provider } from './creds.js';\n\n/**\n * Per-provider runtime state — facts learned *after* `terraform apply`\n * that aren't (or can't be) Terraform outputs. Currently just the\n * post-tailnet-discovery hostname/IP, which the runner uses for all\n * subsequent ssh/logs/update calls because the requested `--name` may\n * have been suffixed by Tailscale to avoid collisions with stale\n * offline nodes.\n *\n * Lives at `~/.sisyphus/deploy/<provider>/runtime.json`. Cleared on\n * `down`. Independent of Terraform state.\n */\nexport interface RuntimeState {\n /** Short MagicDNS label, e.g. \"sisyphus-1\". */\n tailscaleHostname: string;\n /** Full MagicDNS FQDN, e.g. \"sisyphus-1.taildaec87.ts.net\". */\n tailscaleFqdn: string;\n tailscaleIpv4: string;\n discoveredAt: string;\n}\n\nexport function readRuntimeState(provider: Provider): RuntimeState | null {\n const path = deployRuntimePath(provider);\n if (!existsSync(path)) return null;\n try {\n return JSON.parse(readFileSync(path, 'utf-8')) as RuntimeState;\n } catch {\n return null;\n }\n}\n\nexport function writeRuntimeState(provider: Provider, state: RuntimeState): void {\n atomicWrite(deployRuntimePath(provider), JSON.stringify(state, null, 2) + '\\n');\n}\n\nexport function clearRuntimeState(provider: Provider): void {\n const path = deployRuntimePath(provider);\n if (existsSync(path)) unlinkSync(path);\n}\n","import { execSafe } from '../../shared/exec.js';\n\nexport interface DiscoveredNode {\n /** Short MagicDNS label (e.g. \"sisyphus-1\"). May differ from requested name when Tailscale suffixes to avoid collisions with offline nodes. */\n shortName: string;\n /** Fully-qualified MagicDNS name (e.g. \"sisyphus-1.taildaec87.ts.net\"). */\n magicDnsName: string;\n /** Tailscale IPv4 (always present). */\n ipv4: string;\n /** Tailscale IPv6 if exposed. */\n ipv6: string | null;\n}\n\ninterface TailscalePeer {\n HostName?: string;\n DNSName?: string;\n TailscaleIPs?: string[];\n Online?: boolean;\n Created?: string;\n}\n\ninterface TailscaleStatus {\n Peer?: Record<string, TailscalePeer>;\n}\n\n/**\n * Locate a freshly-joined sisyphus box on the user's tailnet by reading\n * `tailscale status --json` locally.\n *\n * Tailscale appends `-1`, `-2`, ... to the MagicDNS label when the\n * requested hostname collides with an existing (even offline) node, so\n * the actual short name may not match `requestedName`. We match peers by\n * the OS-level `HostName` (which is what we passed to `tailscale up\n * --hostname=...` and is preserved verbatim) and require `Online=true`\n * to disambiguate from stale offline nodes.\n */\nexport function discoverNode(requestedName: string): DiscoveredNode | null {\n const json = execSafe('tailscale status --json');\n if (!json) return null;\n\n let status: TailscaleStatus;\n try {\n status = JSON.parse(json) as TailscaleStatus;\n } catch {\n return null;\n }\n\n const peers = status.Peer === undefined ? [] : Object.values(status.Peer);\n const candidates = peers.filter(\n (p) => p.HostName === requestedName && p.Online === true,\n );\n if (candidates.length === 0) return null;\n\n // Multiple online peers with the same OS hostname shouldn't happen, but\n // pick the most recently created defensively.\n candidates.sort((a, b) => {\n const ac = a.Created === undefined ? '' : a.Created;\n const bc = b.Created === undefined ? '' : b.Created;\n return bc.localeCompare(ac);\n });\n const peer = candidates[0]!;\n\n const dnsRaw = peer.DNSName === undefined ? '' : peer.DNSName;\n const dns = dnsRaw.replace(/\\.$/, '');\n if (!dns) return null;\n const shortName = dns.split('.')[0]!;\n\n const ips = peer.TailscaleIPs === undefined ? [] : peer.TailscaleIPs;\n const ipv4 = ips.find((ip) => /^\\d+\\.\\d+\\.\\d+\\.\\d+$/.test(ip));\n if (!ipv4) return null;\n const ipv6 = ips.find((ip) => ip.includes(':')) ?? null;\n\n return { shortName, magicDnsName: dns, ipv4, ipv6 };\n}\n\n/**\n * Poll for the new box on the tailnet. Tailscale propagation typically\n * completes within 5–15s but can take longer on a busy tailnet, hence\n * the generous default of 60s.\n */\nexport async function discoverNodeWithRetry(\n requestedName: string,\n maxRetries = 30,\n intervalMs = 2000,\n): Promise<DiscoveredNode | null> {\n for (let i = 0; i < maxRetries; i++) {\n const node = discoverNode(requestedName);\n if (node) return node;\n if (i < maxRetries - 1) {\n await new Promise((resolve) => setTimeout(resolve, intervalMs));\n }\n }\n return null;\n}\n\n/**\n * Cheap pre-flight check: is `tailscale` on PATH and reachable? Used to\n * decide whether to attempt discovery at all (vs. silently skipping when\n * the user doesn't run Tailscale locally).\n */\nexport function isTailscaleAvailable(): boolean {\n return execSafe('tailscale version') !== null;\n}\n","import { existsSync } from 'node:fs';\nimport { dirname, resolve } from 'node:path';\nimport { fileURLToPath } from 'node:url';\n\n/**\n * Resolve the bundled `deploy/` directory shipped with the npm package.\n *\n * Layout in the published package:\n * dist/cli.js (this file at runtime, after tsup bundle)\n * deploy/ (sibling of dist/, copied via tsup onSuccess)\n *\n * Layout in the source repo:\n * src/cli/deploy/templates.ts (this file)\n * deploy/ (sibling of src/, root of repo)\n */\nexport function deployRoot(): string {\n const here = dirname(fileURLToPath(import.meta.url));\n\n // Bundled: dist/cli.js → ../deploy\n const bundled = resolve(here, '..', 'deploy');\n if (existsSync(bundled)) return bundled;\n\n // Source: src/cli/deploy/ → ../../../deploy\n const sourceRoot = resolve(here, '..', '..', '..', 'deploy');\n if (existsSync(sourceRoot)) return sourceRoot;\n\n throw new Error(\n `Could not locate deploy/ templates. Looked at:\\n ${bundled}\\n ${sourceRoot}\\n` +\n 'This usually means the npm package was built without the deploy/ tree. ' +\n \"Confirm package.json `files` includes 'deploy' and tsup.config.ts copies it into dist/.\",\n );\n}\n\nexport function providerModuleDir(provider: string): string {\n return resolve(deployRoot(), provider);\n}\n","import {\n promptLine,\n readTailscaleEnv,\n writeTailscaleEnv,\n type TailscaleEnv,\n} from './creds.js';\n\ninterface MintOptions {\n hostname: string;\n}\n\ninterface OAuthTokenResponse {\n access_token: string;\n token_type: string;\n expires_in: number;\n}\n\ninterface CreateKeyResponse {\n id: string;\n key: string;\n expires: string;\n}\n\nconst TS_API = 'https://api.tailscale.com/api/v2';\nconst KEY_EXPIRY_SECONDS = 90 * 24 * 60 * 60;\n\n/**\n * Mint a Tailscale auth key for the box being provisioned. Two paths:\n *\n * 1. OAuth client (preferred): mints an ephemeral, single-use, tagged\n * key via API. No human-readable key sits in Terraform state plain\n * text.\n * 2. Manual auth key (fallback): user pastes a reusable key from the\n * admin UI. Less secure, but zero-config.\n *\n * If neither is configured, prompts the user to choose and persists.\n */\nexport async function mintTailscaleKey(opts: MintOptions): Promise<string> {\n let env = readTailscaleEnv();\n\n if (!env.oauthClientId && !env.authKey) {\n env = await firstRunPrompt();\n writeTailscaleEnv(env);\n }\n\n if (env.oauthClientId && env.oauthClientSecret) {\n if (!env.tag) {\n throw new Error('Tailscale tag is missing from ~/.sisyphus/deploy/tailscale.env. Re-run `sis deploy auth tailscale`.');\n }\n return mintViaOAuth(env.oauthClientId, env.oauthClientSecret, env.tag, opts.hostname);\n }\n\n if (env.authKey) {\n return env.authKey;\n }\n\n throw new Error('Tailscale not configured. Run `sis deploy auth tailscale`.');\n}\n\nasync function firstRunPrompt(): Promise<TailscaleEnv> {\n console.log('');\n console.log('Tailscale credentials not configured. Pick one:');\n console.log('');\n console.log(' 1) OAuth client (recommended) — mints fresh ephemeral keys per box');\n console.log(' and auto-cleans stale offline nodes so hostnames don\\'t get suffixed.');\n console.log(' Create at https://login.tailscale.com/admin/settings/oauth');\n console.log(' with scopes `auth_keys:write` + `devices:write` and tag `tag:sisyphus`.');\n console.log(' 2) Reusable auth key (simpler) — paste from');\n console.log(' https://login.tailscale.com/admin/settings/keys');\n console.log('');\n const choice = (await promptLine('Choice [1/2]: ', false)).trim();\n\n if (choice === '1') {\n const clientId = await promptLine(' TS_OAUTH_CLIENT_ID: ', false);\n const clientSecret = await promptLine(' TS_OAUTH_CLIENT_SECRET: ', true);\n if (!clientId || !clientSecret) throw new Error('OAuth client ID and secret are required.');\n const tagInput = await promptLine(' Tag for minted keys [tag:sisyphus]: ', false);\n const tag = tagInput.length > 0 ? tagInput : 'tag:sisyphus';\n return { oauthClientId: clientId, oauthClientSecret: clientSecret, tag };\n }\n\n if (choice === '2') {\n const key = await promptLine(' TS_AUTHKEY: ', true);\n if (!key) throw new Error('Auth key is required.');\n return { authKey: key };\n }\n\n throw new Error(`Invalid choice: ${choice}`);\n}\n\nasync function mintViaOAuth(\n clientId: string,\n clientSecret: string,\n tag: string,\n hostname: string,\n): Promise<string> {\n const token = await fetchAccessToken(clientId, clientSecret);\n\n // Best-effort: clear out stale offline devices that share the requested\n // hostname so Tailscale doesn't suffix the new node with `-1`. Requires\n // the `devices:write` scope on the OAuth client; failures here are not\n // fatal because the new mint still works (just with a suffix).\n try {\n const removed = await deleteStaleDevicesForHostname(token, hostname);\n if (removed > 0) {\n console.log(`Tailscale: removed ${removed} stale offline node(s) named \"${hostname}\".`);\n }\n } catch (err) {\n console.log(`Tailscale: skipped stale-node cleanup (${(err as Error).message}). Add 'devices:write' scope to clean up automatically.`);\n }\n\n const body = {\n capabilities: {\n devices: {\n create: {\n reusable: false,\n ephemeral: false,\n preauthorized: true,\n tags: [tag],\n },\n },\n },\n expirySeconds: KEY_EXPIRY_SECONDS,\n description: `sisyphus deploy: ${hostname}`,\n };\n\n const res = await fetch(`${TS_API}/tailnet/-/keys`, {\n method: 'POST',\n headers: {\n Authorization: `Bearer ${token}`,\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify(body),\n });\n\n if (!res.ok) {\n const detail = await res.text();\n throw new Error(`Tailscale key mint failed (HTTP ${res.status}): ${detail}`);\n }\n\n const data = (await res.json()) as CreateKeyResponse;\n if (!data.key) throw new Error('Tailscale API returned no key.');\n return data.key;\n}\n\ninterface TailscaleDevice {\n id: string;\n hostname: string;\n lastSeen: string;\n}\n\nasync function deleteStaleDevicesForHostname(token: string, hostname: string): Promise<number> {\n const res = await fetch(`${TS_API}/tailnet/-/devices`, {\n headers: { Authorization: `Bearer ${token}` },\n });\n if (!res.ok) {\n throw new Error(`HTTP ${res.status} listing devices`);\n }\n\n const data = (await res.json()) as { devices: TailscaleDevice[] };\n const STALE_AFTER_MS = 5 * 60 * 1000;\n const now = Date.now();\n const stale = data.devices.filter((d) => {\n if (d.hostname !== hostname) return false;\n const seen = Date.parse(d.lastSeen);\n if (Number.isNaN(seen)) return false;\n return now - seen > STALE_AFTER_MS;\n });\n\n let removed = 0;\n for (const device of stale) {\n const r = await fetch(`${TS_API}/device/${device.id}`, {\n method: 'DELETE',\n headers: { Authorization: `Bearer ${token}` },\n });\n if (r.ok) removed++;\n }\n return removed;\n}\n\nasync function fetchAccessToken(clientId: string, clientSecret: string): Promise<string> {\n const credentials = Buffer.from(`${clientId}:${clientSecret}`).toString('base64');\n const res = await fetch(`${TS_API}/oauth/token`, {\n method: 'POST',\n headers: {\n Authorization: `Basic ${credentials}`,\n 'Content-Type': 'application/x-www-form-urlencoded',\n },\n body: 'grant_type=client_credentials&scope=auth_keys',\n });\n\n if (!res.ok) {\n const detail = await res.text();\n throw new Error(`Tailscale OAuth failed (HTTP ${res.status}): ${detail}`);\n }\n\n const data = (await res.json()) as OAuthTokenResponse;\n if (!data.access_token) throw new Error('Tailscale OAuth returned no access_token.');\n return data.access_token;\n}\n\n/**\n * Interactive setup for `sis deploy auth tailscale`. Walks the user\n * through OAuth client creation or manual key paste, then persists.\n */\nexport async function authTailscale(): Promise<void> {\n const env = await firstRunPrompt();\n writeTailscaleEnv(env);\n\n if (env.oauthClientId) {\n if (!env.oauthClientSecret) {\n throw new Error('OAuth client secret missing after first-run prompt — internal error.');\n }\n console.log('');\n console.log('Verifying credentials...');\n // Let exceptions propagate to the CLI's top-level handler; it logs the\n // message and exits non-zero. We don't catch + re-log because that\n // double-prints the failure to stderr.\n await fetchAccessToken(env.oauthClientId, env.oauthClientSecret);\n console.log('OAuth client verified — `sis deploy <provider> up` will mint ephemeral keys.');\n } else {\n console.log('');\n console.log('Auth key saved. Note: reusable auth keys are less secure than OAuth clients.');\n }\n}\n","import { spawn, spawnSync } from 'node:child_process';\nimport { hostname } from 'node:os';\nimport { boxRepoPath } from '../../shared/paths.js';\nimport { shellQuote, shellQuoteHomePath } from '../../shared/shell.js';\nimport { EXEC_ENV } from '../../shared/exec.js';\nimport { promptLine } from '../deploy/creds.js';\nimport type { Provider } from '../deploy/creds.js';\nimport { effectiveSshTarget } from '../deploy/runner.js';\nimport { runOnBox, runOnBoxStreaming } from '../deploy/ssh-exec.js';\nimport { ensureGroveInstalled, ensureGroveRegistered } from './grove.js';\nimport {\n buildRsyncArgs,\n detectPackageManager,\n getOriginUrl,\n getRepoToplevel,\n packageManagerInstallCmd,\n type PackageManager,\n} from './repo.js';\nimport { readSidecar, writeSidecar, type CloudSidecar } from './sidecar.js';\n\nexport interface SyncOptions {\n fresh: boolean;\n yes: boolean;\n}\n\nexport interface StartOptions {\n fresh: boolean;\n yes: boolean;\n}\n\n// ── sync ─────────────────────────────────────────────────────────────────────\n\nexport async function cloudSync(provider: Provider, repo: string, opts: SyncOptions): Promise<void> {\n const target = effectiveSshTarget(provider);\n const remoteDir = boxRepoPath(repo);\n const localOrigin = getOriginUrl();\n\n ensureGroveInstalled(provider);\n\n const existing = readSidecar(provider, repo);\n if (existing && existing.originUrl && localOrigin && existing.originUrl !== localOrigin) {\n throw new Error(\n `Repo \"${repo}\" on the box is registered to a different origin:\\n` +\n ` box: ${existing.originUrl}\\n` +\n ` local: ${localOrigin}\\n` +\n `Pass --name <slug> to disambiguate, or --fresh to overwrite.`,\n );\n }\n\n if (opts.fresh) {\n if (!localOrigin) {\n throw new Error(\n '--fresh requires an `origin` remote on the local repo. ' +\n 'Not available when running from a non-git parent dir.',\n );\n }\n if (!opts.yes) {\n console.log(`This will wipe ~/projects/${repo} on the box and re-clone from ${localOrigin}.`);\n const confirmed = (await promptLine('Continue? Type \"yes\": ', false)).toLowerCase() === 'yes';\n if (!confirmed) {\n console.log('Aborted.');\n return;\n }\n }\n console.log(`→ wiping ${remoteDir} and cloning ${localOrigin} on box...`);\n const cloneCmd = [\n `rm -rf ${shellQuoteHomePath(remoteDir)}`,\n `mkdir -p ${shellQuoteHomePath('~/projects')}`,\n `git clone ${shellQuote(localOrigin)} ${shellQuoteHomePath(remoteDir)}`,\n ].join(' && ');\n const code = await runOnBoxStreaming(provider, cloneCmd);\n if (code !== 0) throw new Error(`fresh clone failed (exit ${code})`);\n } else {\n // Ensure the remote dir exists — rsync will create it but mkdir is harmless.\n const mkdir = runOnBox(provider, `mkdir -p ${shellQuoteHomePath(remoteDir)}`);\n if (mkdir.exitCode !== 0) {\n throw new Error(`Failed to mkdir on box: ${mkdir.stderr}`);\n }\n const toplevel = getRepoToplevel();\n const args = buildRsyncArgs(toplevel, `${target}:${remoteDir}/`);\n console.log(`→ rsync ${toplevel}/ → ${target}:${remoteDir}/`);\n const code = await runRsync(args);\n if (code !== 0) throw new Error(`rsync failed (exit ${code})`);\n }\n\n ensureGroveRegistered(provider, repo, remoteDir);\n\n const sidecar: CloudSidecar = {\n originUrl: localOrigin,\n localHostname: hostname(),\n lastSync: new Date().toISOString(),\n packageManager: existing?.packageManager,\n lastInstall: existing?.lastInstall,\n };\n writeSidecar(provider, repo, sidecar);\n console.log(`✓ synced ${repo} → ${target}:${remoteDir}/`);\n}\n\nfunction runRsync(args: string[]): Promise<number> {\n return new Promise((resolve, reject) => {\n const child = spawn('rsync', args, { stdio: 'inherit', env: EXEC_ENV });\n child.on('error', reject);\n child.on('exit', (code) => resolve(code === null ? 1 : code));\n });\n}\n\n// ── install ──────────────────────────────────────────────────────────────────\n\nexport async function cloudInstall(provider: Provider, repo: string): Promise<void> {\n const remoteDir = boxRepoPath(repo);\n const toplevel = getRepoToplevel();\n const pm: PackageManager = detectPackageManager(toplevel);\n const cmd = packageManagerInstallCmd(pm);\n if (!cmd) {\n console.log('No lockfile detected — skipping install.');\n return;\n }\n console.log(`→ ${pm} install in ${remoteDir} on box...`);\n // `cd` then run; explicit shell wrapping is fine over ssh.\n const remoteCmd = `cd ${shellQuoteHomePath(remoteDir)} && ${cmd}`;\n const code = await runOnBoxStreaming(provider, remoteCmd);\n if (code !== 0) throw new Error(`${pm} install failed (exit ${code})`);\n\n const existing = readSidecar(provider, repo);\n // Carry forward existing identity fields; only overwrite when missing.\n const sidecar: CloudSidecar = {\n originUrl: existing && existing.originUrl !== undefined ? existing.originUrl : getOriginUrl(),\n localHostname: existing ? existing.localHostname : hostname(),\n lastSync: existing?.lastSync,\n lastInstall: new Date().toISOString(),\n packageManager: pm,\n };\n writeSidecar(provider, repo, sidecar);\n console.log(`✓ installed ${repo} (${pm})`);\n}\n\n// ── session ──────────────────────────────────────────────────────────────────\n\nexport async function cloudSession(provider: Provider, repo: string): Promise<void> {\n const remoteDir = boxRepoPath(repo);\n // home-init is a sisyphus admin subcommand on the box; runs against the\n // local tmux server there. `~` expands in the remote shell.\n const cmd = `sis admin home-init ${shellQuote(repo)} ${shellQuoteHomePath(remoteDir)}`;\n console.log(`→ initializing tmux home session \"${repo}\" on box...`);\n const result = runOnBox(provider, cmd);\n if (result.exitCode !== 0) {\n throw new Error(`home-init failed: ${result.stderr || result.stdout}`);\n }\n if (result.stdout.trim()) console.log(result.stdout.trim());\n console.log(`✓ session \"${repo}\" ready on box`);\n}\n\n// ── attach ───────────────────────────────────────────────────────────────────\n\nexport function cloudAttach(provider: Provider, repo: string): void {\n if (process.env.TMUX) {\n throw new Error(\n 'Refusing to attach from inside tmux — would nest the cloud tmux client.\\n' +\n 'Use a fresh terminal, or run from outside tmux:\\n' +\n ` tmux new-window 'ssh -t ${effectiveSshTarget(provider)} tmux attach -t ${repo}'`,\n );\n }\n const target = effectiveSshTarget(provider);\n const child = spawn('ssh', ['-t', target, `tmux attach-session -t ${shellQuote(repo)}`], {\n stdio: 'inherit',\n env: EXEC_ENV,\n });\n child.on('exit', (code) => process.exit(code === null ? 1 : code));\n}\n\n// ── claude-login ─────────────────────────────────────────────────────────────\n\n/**\n * Open an interactive ssh shell on the box running `claude auth login` so the\n * user can complete the device-code flow (URL prints on box, user pastes the\n * code from their local browser back into the same terminal). Self-heals on\n * boxes provisioned before claude-code was added to cloud-init by installing\n * it on demand.\n */\nexport function cloudClaudeLogin(provider: Provider): void {\n const target = effectiveSshTarget(provider);\n // `command -v` probes for an existing install; npm i -g runs as sisyphus\n // (cloud-init installed it as root, but a per-user fallback also works).\n const remote = [\n 'command -v claude >/dev/null 2>&1',\n '|| sudo npm i -g @anthropic-ai/claude-code',\n '&& claude auth login',\n ].join(' ');\n const child = spawn('ssh', ['-t', target, remote], {\n stdio: 'inherit',\n env: EXEC_ENV,\n });\n child.on('exit', (code) => process.exit(code === null ? 1 : code));\n}\n\n// ── start (umbrella) ─────────────────────────────────────────────────────────\n\nexport async function cloudStart(provider: Provider, repo: string, opts: StartOptions): Promise<void> {\n await cloudSync(provider, repo, { fresh: opts.fresh, yes: opts.yes });\n await cloudInstall(provider, repo);\n await cloudSession(provider, repo);\n console.log('');\n console.log(`Box-side dashboard ready. Attach with:`);\n console.log(` tmux new-window 'ssh -t ${effectiveSshTarget(provider)} tmux attach -t ${repo}'`);\n console.log('(or run inside the slash command, which does this for you.)');\n}\n\n// ── status ───────────────────────────────────────────────────────────────────\n\nexport interface CloudStatus {\n provider: Provider;\n target: string;\n sidecar: CloudSidecar | null;\n sessionRunning: boolean;\n}\n\nexport function cloudStatus(provider: Provider, repo: string): void {\n const target = effectiveSshTarget(provider);\n const sidecar = readSidecar(provider, repo);\n // tmux has-session exits 0 when present.\n const sessionProbe = runOnBox(provider, `tmux has-session -t ${shellQuote(repo)} 2>/dev/null`);\n const sessionRunning = sessionProbe.exitCode === 0;\n\n console.log(`Cloud status for \"${repo}\":`);\n console.log(` Provider: ${provider}`);\n console.log(` Target: ${target}`);\n console.log(` Planted: ${sidecar ? 'yes' : 'no'}`);\n if (sidecar) {\n console.log(` Origin: ${sidecar.originUrl ? sidecar.originUrl : '(none)'}`);\n console.log(` Last sync: ${sidecar.lastSync ? sidecar.lastSync : '(never)'}`);\n console.log(` Last install: ${sidecar.lastInstall ? sidecar.lastInstall : '(never)'}`);\n console.log(` Package manager: ${sidecar.packageManager ? sidecar.packageManager : '(none)'}`);\n }\n console.log(` Session: ${sessionRunning ? 'running' : 'absent'}`);\n if (sessionRunning) {\n console.log(` Attach: tmux new-window 'ssh -t ${target} tmux attach -t ${repo}'`);\n }\n}\n","import { spawn, spawnSync } from 'node:child_process';\nimport { EXEC_ENV } from '../../shared/exec.js';\nimport { effectiveSshTarget } from './runner.js';\nimport type { Provider } from './creds.js';\n\nexport interface RunResult {\n stdout: string;\n stderr: string;\n exitCode: number;\n}\n\n/**\n * Run a command on the box via SSH, capturing stdout/stderr.\n *\n * `EXEC_ENV` is the *local* PATH augmentation (so `ssh` resolves) — it is not\n * forwarded to the remote shell, which uses the box's own `~/.profile`/sshd\n * environment.\n */\nexport function runOnBox(provider: Provider, cmd: string): RunResult {\n const target = effectiveSshTarget(provider);\n const result = spawnSync('ssh', [target, cmd], {\n encoding: 'utf-8',\n env: EXEC_ENV,\n });\n // spawnSync with encoding returns string | null per Node types; null only\n // when stdio for the stream is \"ignore\" (we don't set that). Assert string.\n if (typeof result.stdout !== 'string' || typeof result.stderr !== 'string') {\n throw new Error('Internal: ssh spawn did not capture output as string');\n }\n return {\n stdout: result.stdout,\n stderr: result.stderr,\n // status is null when killed by signal — treat as failure.\n exitCode: result.status === null ? 1 : result.status,\n };\n}\n\n/**\n * Run a command on the box via SSH, streaming stdout/stderr to the user's\n * terminal. Returns the exit code. Use for long-running commands like\n * package-manager installs.\n */\nexport function runOnBoxStreaming(provider: Provider, cmd: string): Promise<number> {\n const target = effectiveSshTarget(provider);\n return new Promise((resolve, reject) => {\n const child = spawn('ssh', [target, cmd], {\n stdio: 'inherit',\n env: EXEC_ENV,\n });\n child.on('error', reject);\n child.on('exit', (code) => resolve(code === null ? 1 : code));\n });\n}\n","import { shellQuote, shellQuoteHomePath } from '../../shared/shell.js';\nimport { runOnBox } from '../deploy/ssh-exec.js';\nimport type { Provider } from '../deploy/creds.js';\n\n/**\n * Pinned grove version installed on the cloud box. Bump intentionally; auto-\n * updates are not wired into the daily sisyphusd-update timer.\n */\nexport const GROVE_VERSION = '0.2.13';\n\n/**\n * Ensure grove is installed on the box. Idempotent: short-circuits if `grove`\n * is already on PATH. Installs globally via `sudo npm i -g` (the deploy box\n * uses the NodeSource APT install with /usr/lib/node_modules root-owned).\n */\nexport function ensureGroveInstalled(provider: Provider): void {\n const probe = runOnBox(provider, 'command -v grove >/dev/null 2>&1');\n if (probe.exitCode === 0) return;\n process.stderr.write('Installing grove on box...\\n');\n const install = runOnBox(provider, `sudo npm i -g @crouton-kit/grove@${GROVE_VERSION}`);\n if (install.exitCode !== 0) {\n throw new Error(`Failed to install grove: ${install.stderr || install.stdout}`);\n }\n}\n\n/**\n * Register a repo path with grove. Uses `--update` for idempotency: re-running\n * with the same name+path is a no-op, and updating the path on a name reuse\n * is intentional (we control the path layout).\n */\nexport function ensureGroveRegistered(\n provider: Provider,\n repo: string,\n instancePath: string,\n): void {\n const cmd = `grove register --update --name ${shellQuote(repo)} ${shellQuoteHomePath(instancePath)}`;\n const result = runOnBox(provider, cmd);\n if (result.exitCode !== 0) {\n throw new Error(`Failed to register grove project ${repo}: ${result.stderr || result.stdout}`);\n }\n}\n","import { spawnSync } from 'node:child_process';\nimport { existsSync } from 'node:fs';\nimport { basename, join } from 'node:path';\nimport { EXEC_ENV } from '../../shared/exec.js';\n\nfunction captureGit(args: string[]): { stdout: string; ok: boolean } {\n const result = spawnSync('git', args, {\n encoding: 'utf-8',\n env: EXEC_ENV,\n });\n if (typeof result.stdout !== 'string') {\n throw new Error('Internal: git spawn did not capture stdout as string');\n }\n return { stdout: result.stdout.trim(), ok: result.status === 0 };\n}\n\n/**\n * Infer the repo name from the local git working tree's top-level dir basename.\n * Falls back to `basename(cwd)` when cwd is not inside a git repo — supports\n * parent dirs that contain repos but aren't themselves a repo.\n */\nexport function inferRepoName(): string {\n const { stdout, ok } = captureGit(['rev-parse', '--show-toplevel']);\n if (ok && stdout) return basename(stdout);\n return basename(process.cwd());\n}\n\n/**\n * Read the local repo's `origin` remote URL. Returns null if no `origin` is\n * configured or cwd is not inside a git repo.\n */\nexport function getOriginUrl(): string | null {\n const { stdout, ok } = captureGit(['remote', 'get-url', 'origin']);\n if (!ok) return null;\n return stdout.length > 0 ? stdout : null;\n}\n\n/**\n * Path to the local git toplevel, or cwd when cwd is not inside a git repo.\n * Non-repo mode is intentional: enables syncing parent dirs that contain\n * multiple child repos (each child's `.git/` rides along via rsync).\n */\nexport function getRepoToplevel(): string {\n const { stdout, ok } = captureGit(['rev-parse', '--show-toplevel']);\n if (ok && stdout) return stdout;\n return process.cwd();\n}\n\n/**\n * Defensive excludes layered on top of `.gitignore` filtering. Most of these\n * are usually gitignored, but listing them prevents accidentally pushing\n * hundreds of MB when a repo's `.gitignore` is incomplete.\n */\nconst DEFAULT_EXCLUDES = [\n '.sisyphus/',\n '.terraform/',\n 'node_modules/',\n 'dist/',\n '.next/',\n '.turbo/',\n 'coverage/',\n 'tmp/',\n '.git/lfs/',\n '.DS_Store',\n];\n\n/**\n * Build the rsync argv for a local→box sync. Includes `.git/` so the user can\n * `git push` from the box.\n */\nexport function buildRsyncArgs(localDir: string, remoteTarget: string): string[] {\n // Trailing slash on source = \"copy contents\", not \"copy dir into dest\".\n const src = localDir.endsWith('/') ? localDir : `${localDir}/`;\n return [\n '-avz',\n '--filter=:- .gitignore',\n ...DEFAULT_EXCLUDES.map((e) => `--exclude=${e}`),\n '-e', 'ssh',\n src,\n remoteTarget,\n ];\n}\n\nexport type PackageManager = 'pnpm' | 'npm' | 'yarn' | 'bun' | null;\n\n/**\n * Detect the package manager used by a repo from its lockfile.\n * Returns null when no known lockfile is present (no install step needed).\n */\nexport function detectPackageManager(toplevel: string): PackageManager {\n if (existsSync(join(toplevel, 'pnpm-lock.yaml'))) return 'pnpm';\n if (existsSync(join(toplevel, 'bun.lockb'))) return 'bun';\n if (existsSync(join(toplevel, 'yarn.lock'))) return 'yarn';\n if (existsSync(join(toplevel, 'package-lock.json'))) return 'npm';\n return null;\n}\n\nexport function packageManagerInstallCmd(pm: PackageManager): string | null {\n switch (pm) {\n case 'pnpm': return 'pnpm install';\n case 'bun': return 'bun install';\n case 'yarn': return 'yarn install';\n case 'npm': return 'npm install';\n default: return null;\n }\n}\n","import { boxCloudSidecarPath, boxCloudSidecarDir } from '../../shared/paths.js';\nimport { shellQuoteHomePath } from '../../shared/shell.js';\nimport { runOnBox } from '../deploy/ssh-exec.js';\nimport type { Provider } from '../deploy/creds.js';\nimport type { PackageManager } from './repo.js';\n\nexport interface CloudSidecar {\n originUrl: string | null;\n localHostname: string;\n lastSync?: string;\n lastInstall?: string;\n packageManager?: PackageManager;\n}\n\n/**\n * Read the per-repo sidecar JSON from the box at `~/.sisyphus/cloud/<repo>.json`.\n * Returns null if the file doesn't exist or is unparseable.\n */\nexport function readSidecar(provider: Provider, repo: string): CloudSidecar | null {\n const path = boxCloudSidecarPath(repo);\n // `cat` returns non-zero if file missing — that's our \"no sidecar\" signal.\n const result = runOnBox(provider, `cat ${shellQuoteHomePath(path)} 2>/dev/null`);\n if (result.exitCode !== 0 || !result.stdout.trim()) return null;\n try {\n const parsed = JSON.parse(result.stdout) as CloudSidecar;\n return parsed;\n } catch {\n return null;\n }\n}\n\n/**\n * Write/replace the sidecar JSON on the box. Creates `~/.sisyphus/cloud/`\n * if needed.\n */\nexport function writeSidecar(provider: Provider, repo: string, data: CloudSidecar): void {\n const dir = boxCloudSidecarDir();\n const path = boxCloudSidecarPath(repo);\n const json = JSON.stringify(data, null, 2);\n // Heredoc with a fixed sentinel keeps the JSON payload from needing further\n // shell escaping. Sentinel is unlikely to appear in real payloads.\n const cmd = [\n `mkdir -p ${shellQuoteHomePath(dir)}`,\n `cat > ${shellQuoteHomePath(path)} <<'SISYPHUS_CLOUD_SIDECAR_EOF'`,\n json,\n 'SISYPHUS_CLOUD_SIDECAR_EOF',\n ].join('\\n');\n const result = runOnBox(provider, cmd);\n if (result.exitCode !== 0) {\n throw new Error(`Failed to write sidecar for ${repo}: ${result.stderr || result.stdout}`);\n }\n}\n","import { isValidProvider, PROVIDERS, type Provider } from './creds.js';\nimport { isProvisioned } from './runner.js';\n\n/**\n * Resolve which provider a `cloud` command should target.\n *\n * - `explicit` set: validate against the known provider list and return.\n * - Exactly one provisioned: return it silently.\n * - Zero provisioned: throw with a hint to run `deploy <provider> up`.\n * - Multiple provisioned: throw with a hint to pass `--provider`.\n */\nexport function pickProvider(explicit?: string): Provider {\n if (explicit) {\n if (!isValidProvider(explicit)) {\n throw new Error(`Unknown provider \"${explicit}\". Valid: ${PROVIDERS.join(', ')}.`);\n }\n return explicit;\n }\n\n const provisioned = PROVIDERS.filter((p) => isProvisioned(p));\n if (provisioned.length === 1) return provisioned[0]!;\n if (provisioned.length === 0) {\n throw new Error(\n 'No cloud provider provisioned. Run `sis deploy <hetzner|aws> up` first.',\n );\n }\n throw new Error(\n `Multiple providers provisioned (${provisioned.join(', ')}). Pass --provider <name>.`,\n );\n}\n","import type { Command } from 'commander';\nimport {\n cloudAttach,\n cloudClaudeLogin,\n cloudInstall,\n cloudSession,\n cloudStart,\n cloudStatus,\n cloudSync,\n} from '../cloud/runner.js';\nimport { inferRepoName } from '../cloud/repo.js';\nimport { pickProvider } from '../deploy/provider-pick.js';\nimport type { Provider } from '../deploy/creds.js';\nimport { validateRepoName } from '../../shared/shell.js';\n\ninterface CommonRaw {\n name?: string;\n provider?: string;\n}\n\ninterface StartRaw extends CommonRaw {\n fresh?: boolean;\n yes?: boolean;\n}\n\nfunction resolve(raw: CommonRaw): { provider: Provider; repo: string } {\n const provider = pickProvider(raw.provider);\n const repo = raw.name ? raw.name : inferRepoName();\n if (!validateRepoName(repo)) {\n throw new Error(`Invalid --name \"${repo}\": must not contain '/' '\\\\' or '..'.`);\n }\n return { provider, repo };\n}\n\nexport function registerCloud(program: Command): void {\n const cloud = program\n .command('cloud')\n .description('Per-repo workflow on the shared cloud box (sync, install, dashboard).');\n\n cloud\n .command('sync')\n .description('Rsync this repo to the cloud box; ensures grove is installed and the repo is registered.')\n .option('--fresh', 'Wipe the box-side dir and `git clone` from origin instead of rsync.')\n .option('-y, --yes', 'Skip the --fresh confirmation prompt.')\n .option('--name <repo>', 'Override the repo name (default: basename of git toplevel).')\n .option('--provider <name>', 'Cloud provider (default: auto-pick if exactly one is provisioned).')\n .action(async (raw: StartRaw) => {\n const { provider, repo } = resolve(raw);\n await cloudSync(provider, repo, { fresh: raw.fresh === true, yes: raw.yes === true });\n });\n\n cloud\n .command('install')\n .description('Run the repo\\'s package-manager install on the box.')\n .option('--name <repo>', 'Override the repo name.')\n .option('--provider <name>', 'Cloud provider.')\n .action(async (raw: CommonRaw) => {\n const { provider, repo } = resolve(raw);\n await cloudInstall(provider, repo);\n });\n\n cloud\n .command('session')\n .description('Create or refresh the box-side tmux home session for this repo.')\n .option('--name <repo>', 'Override the repo name.')\n .option('--provider <name>', 'Cloud provider.')\n .action(async (raw: CommonRaw) => {\n const { provider, repo } = resolve(raw);\n await cloudSession(provider, repo);\n });\n\n cloud\n .command('attach')\n .description('Attach to the box-side tmux home session for this repo.')\n .option('--name <repo>', 'Override the repo name.')\n .option('--provider <name>', 'Cloud provider.')\n .action((raw: CommonRaw) => {\n const { provider, repo } = resolve(raw);\n cloudAttach(provider, repo);\n });\n\n cloud\n .command('start')\n .description('Sync, install, and start the dashboard session in one shot. (Stops short of attach.)')\n .option('--fresh', 'Wipe the box-side dir and `git clone` from origin instead of rsync.')\n .option('-y, --yes', 'Skip the --fresh confirmation prompt.')\n .option('--name <repo>', 'Override the repo name.')\n .option('--provider <name>', 'Cloud provider.')\n .action(async (raw: StartRaw) => {\n const { provider, repo } = resolve(raw);\n await cloudStart(provider, repo, { fresh: raw.fresh === true, yes: raw.yes === true });\n });\n\n cloud\n .command('claude-login')\n .description('Run `claude auth login` on the box (device-code flow; paste the URL into your local browser).')\n .option('--provider <name>', 'Cloud provider.')\n .action((raw: CommonRaw) => {\n const provider = pickProvider(raw.provider);\n cloudClaudeLogin(provider);\n });\n\n cloud\n .command('status')\n .description('Print box-side status for this repo (planted, session running, last sync/install).')\n .option('--name <repo>', 'Override the repo name.')\n .option('--provider <name>', 'Cloud provider.')\n .action((raw: CommonRaw) => {\n const { provider, repo } = resolve(raw);\n cloudStatus(provider, repo);\n });\n}\n","import type { Command } from 'commander';\nimport { rawSend } from '../client.js';\nimport type { Request } from '../../shared/protocol.js';\n\nexport function attachNotify(diagnostic: Command): void {\n const notify = diagnostic\n .command('notify')\n .description('Internal notifications (fire-and-forget)');\n\n notify\n .command('pane-exited')\n .description('Notify daemon that a tmux pane exited')\n .requiredOption('--pane-id <paneId>', 'Pane ID that exited')\n .action(async (opts: { paneId: string }) => {\n try {\n const request: Request = { type: 'pane-exited', paneId: opts.paneId };\n await rawSend(request);\n } catch {\n // Fire-and-forget: daemon may be stopped, socket gone, etc.\n }\n });\n}\n","import { execSync } from 'node:child_process';\nimport { readFileSync, existsSync } from 'node:fs';\nimport type { Command } from 'commander';\nimport { sessionsManifestPath } from '../../shared/paths.js';\n\ninterface ManifestEntry {\n type: 'S' | 'H' | 'O';\n tmuxName: string;\n cwd: string;\n phase: string | null;\n}\n\ninterface Manifest {\n updatedAt: number;\n sessions: ManifestEntry[];\n}\n\nconst DOT_MAP: Record<string, { icon: string; color: string }> = {\n 'orchestrator:processing': { icon: '●', color: '#d4ad6a' },\n 'orchestrator:idle': { icon: '●', color: '#d47766' },\n 'agents:running': { icon: '◆', color: '#d4ad6a' },\n 'between-cycles': { icon: '◆', color: '#5e584e' },\n 'paused': { icon: '○', color: '#d47766' },\n 'completed': { icon: '●', color: '#a9b16e' },\n};\n\nfunction readManifest(): Manifest | null {\n const p = sessionsManifestPath();\n if (!existsSync(p)) return null;\n try {\n return JSON.parse(readFileSync(p, 'utf-8')) as Manifest;\n } catch {\n return null;\n }\n}\n\nfunction tmuxExec(cmd: string): string | null {\n try {\n return execSync(cmd, { encoding: 'utf-8', stdio: ['pipe', 'pipe', 'pipe'] }).trim();\n } catch {\n return null;\n }\n}\n\nexport function attachTmuxSessions(diagnostic: Command): void {\n diagnostic\n .command('tmux-sessions')\n .description('Output sisyphus session list for tmux status bar')\n .action(() => {\n const manifest = readManifest();\n if (!manifest) return;\n\n const currentSession = tmuxExec(\"tmux display-message -p '#{session_name}'\");\n\n // Find the cwd of the current session from the manifest\n const currentEntry = manifest.sessions.find(s => s.tmuxName === currentSession);\n if (!currentEntry) return;\n const cwd = currentEntry.cwd;\n\n // Filter to sessions matching this cwd\n const entries = manifest.sessions.filter(s => s.cwd === cwd);\n if (entries.length <= 1) return;\n\n const parts = entries.map(e => {\n const dot = e.phase ? DOT_MAP[e.phase] : null;\n const dotStr = dot ? ` #[fg=${dot.color}]${dot.icon}` : '';\n const displayName = e.tmuxName.replace(/^ssyph_[^_]+_/, '');\n const isCurrent = e.tmuxName === currentSession;\n\n if (isCurrent) {\n return `#[fg=#e2d9c6,bold]${displayName}${dotStr}#[default]`;\n }\n return `#[fg=#5e584e]${displayName}${dotStr}#[default]`;\n });\n\n process.stdout.write(parts.join('#[fg=#3a3d42] │ '));\n });\n}\n"],"mappings":"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AAA,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,EACF;AAAA,EACA,eAAe;AAAA,IAC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","names":["randomUUID","dirname","join","renameSync","writeFileSync","resolve","resolve","execSync","exec","execSync","join","readFileSync","writeFileSync","rmSync","cpSync","existsSync","mkdirSync","tmpdir","exec","templatePath","args","firstPaneId","chmodSync","existsSync","mkdirSync","readFileSync","createInterface","resolve","existsSync","mkdirSync","readFileSync","dirname","join","fileURLToPath","execSync","basename","resolve","execSync","existsSync","mkdirSync","readFileSync","unlinkSync","writeFileSync","connect","homedir","join","existsSync","mkdirSync","homedir","join","sep","join","homedir","join","join","mkdirSync","args","homedir","existsSync","resolve","execSync","readFileSync","readFileSync","homedir","join","join","homedir","readFileSync","execSync","join","homedir","existsSync","mkdirSync","writeFileSync","execSync","unlinkSync","resolve","connect","readFileSync","rawSend","sleep","resolve","resolve","execSync","execSync","join","execSync","execSync","join","program","basename","execSync","program","tmuxSessionName","execSync","existsSync","readFileSync","session","session","agent","readFileSync","existsSync","execSync","program","basename","RESET","BOLD","DIM","program","readFileSync","readStdin","readFileSync","program","submit","existsSync","readFileSync","homedir","join","ORCH_ALIASES","join","homedir","c","program","session","existsSync","readFileSync","program","existsSync","readFileSync","join","resolve","spawnSync","existsSync","readFileSync","dirname","resolve","existsSync","mkdirSync","readFileSync","readdirSync","mkdirSync","writeFileSync","readFileSync","rmSync","dirname","join","cpSync","existsSync","mkdirSync","readFileSync","readdirSync","rmSync","statSync","writeFileSync","join","existsSync","readFileSync","writeFileSync","join","readFileSync","session","agent","session","c","agent","writeFileSync","mkdirSync","existsSync","join","homedir","scriptPath","session","mkdirSync","readFileSync","existsSync","readFileSync","existsSync","program","existsSync","session","readFileSync","join","resolve","program","program","program","tmuxSessionName","program","program","program","program","tmuxSessionName","program","program","program","program","session","readFileSync","readdirSync","readFileSync","readFileSync","readdirSync","session","agent","program","session","existsSync","join","resolve","readFileSync","existsSync","readdirSync","homedir","join","basename","readdirSync","basename","readFileSync","join","homedir","resolve","program","join","existsSync","program","program","existsSync","readFileSync","program","existsSync","readFileSync","program","program","program","program","program","execSync","execSync","existsSync","readFileSync","writeFileSync","homedir","dirname","join","fileURLToPath","execSync","plistPath","join","homedir","existsSync","writeFileSync","dirname","fileURLToPath","readFileSync","baleiaInstalled","execSync","program","program","execSync","readFileSync","isTmuxInstalled","execSync","getTmuxVersion","readFileSync","program","execSync","existsSync","readFileSync","homedir","join","isTmuxInstalled","isTmuxServerRunning","runCheck","printInstructions","program","execSync","execSync","execSync","existsSync","statSync","homedir","join","execSync","existsSync","statSync","join","homedir","program","c","existsSync","mkdirSync","writeFileSync","join","DEFAULT_CONFIG","program","createInterface","createInterface","resolve","program","chmodSync","existsSync","mkdirSync","readFileSync","writeFileSync","createInterface","dirname","resolve","program","execSync","dirname","join","fileURLToPath","join","dirname","fileURLToPath","execSync","program","c","args","readdirSync","readFileSync","existsSync","resolve","RESET","BOLD","DIM","existsSync","readdirSync","readFileSync","session","c","resolve","program","execFile","existsSync","readFileSync","mkdirSync","rmSync","writeFileSync","homedir","join","program","session","rmSync","args","session","args","readFileSync","resolve","program","session","persistReq","rmSync","execSync","execSync","program","join","resolve","dirname","existsSync","readFileSync","writeFileSync","renameSync","readdirSync","session","program","c","basename","c","colorize","result","existsSync","mkdirSync","readFileSync","renameSync","writeFileSync","dirname","join","randomUUID","z","existsSync","mkdirSync","readFileSync","renameSync","writeFileSync","randomUUID","dirname","join","existsSync","state","readFileSync","dirname","mkdirSync","join","randomUUID","writeFileSync","renameSync","existsSync","readFileSync","z","writeFileSync","readFileSync","unlinkSync","existsSync","tmpdir","join","resolve","join","tmpdir","resolve","wrapText","writeFileSync","existsSync","unlinkSync","args","readFileSync","basename","program","companion","openCompanionPane","homedir","join","spawn","spawnSync","copyFileSync","existsSync","mkdirSync","readFileSync","existsSync","readFileSync","unlinkSync","resolve","existsSync","dirname","resolve","fileURLToPath","hostname","args","spawnSync","existsSync","mkdirSync","copyFileSync","readFileSync","confirm","spawn","promptLine","program","join","homedir","spawn","spawn","spawnSync","spawnSync","resolve","spawn","spawnSync","existsSync","basename","join","args","args","resolve","spawn","resolve","program","diagnostic","rawSend","execSync","readFileSync","existsSync","diagnostic","readFileSync","join","dirname","fileURLToPath","existsSync","mkdirSync"]}
|