runtape 0.4.0 → 0.6.0

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/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/commands/login.ts","../src/lib/config.ts","../src/lib/paths.ts","../src/lib/api.ts","../src/commands/logout.ts","../src/commands/install.ts","../src/lib/hooks-installer.ts","../src/lib/hook-mapping.ts","../src/lib/cli-bin.ts","../src/commands/uninstall.ts","../src/commands/push.ts","../src/lib/sequence.ts","../src/lib/buffer.ts","../src/lib/transcript.ts","../src/lib/subagent-transcript.ts","../src/commands/status.ts","../src/commands/runs.ts","../src/commands/setup.ts","../src/lib/flusher.ts"],"sourcesContent":["import { readFileSync } from 'node:fs';\nimport { fileURLToPath } from 'node:url';\nimport { dirname, join } from 'node:path';\nimport { Command } from 'commander';\nimport { loginCommand } from './commands/login.js';\nimport { logoutCommand } from './commands/logout.js';\nimport { installCommand } from './commands/install.js';\nimport { uninstallCommand } from './commands/uninstall.js';\nimport { pushCommand } from './commands/push.js';\nimport { statusCommand } from './commands/status.js';\nimport { runsCommand } from './commands/runs.js';\nimport { setupCommand } from './commands/setup.js';\nimport { runFlusher } from './lib/flusher.js';\n\n// Read package.json at runtime so --version can never desync from the publish.\nconst pkgPath = join(dirname(fileURLToPath(import.meta.url)), '..', 'package.json');\nconst PKG_VERSION = (JSON.parse(readFileSync(pkgPath, 'utf8')) as { version: string }).version;\n\n// Internal flag for the detached flusher daemon — not a user-facing subcommand.\n// Goes before commander.parse so we can short-circuit before commander sees argv.\nif (process.argv.includes('--internal-flusher')) {\n void runFlusher().then(\n () => process.exit(0),\n (err: unknown) => {\n console.error(err);\n process.exit(1);\n },\n );\n} else {\n const program = new Command();\n\n program\n .name('runtape')\n .description('Flight recorder for AI coding agents.')\n .version(PKG_VERSION);\n\n program\n .command('setup')\n .description('Guided onboarding: login + install hooks + verify in one flow.')\n .option('--no-browser', 'Do not open the dashboard URL in a browser')\n .action(async (opts) => process.exit(await setupCommand(opts)));\n\n program\n .command('login')\n .description('Paste your API key from runtape.dev/dashboard and save it locally.')\n .option('-k, --key <key>', 'API key (skip the prompt)')\n .option('-s, --server-url <url>', 'Override server URL')\n .action(async (opts) => process.exit(await loginCommand(opts)));\n\n program\n .command('logout')\n .description('Remove saved credentials.')\n .action(async () => process.exit(await logoutCommand()));\n\n program\n .command('install')\n .description('Add Runtape hooks to ~/.claude/settings.json (or project-local with --project).')\n .option('--project', 'Install into ./.claude/settings.json instead of user-level')\n .option('-y, --yes', 'Skip the confirmation prompt')\n .action(async (opts) => process.exit(await installCommand(opts)));\n\n program\n .command('uninstall')\n .description('Remove Runtape hooks from Claude settings.')\n .option('--project', 'Operate on ./.claude/settings.json instead of user-level')\n .action(async (opts) => process.exit(await uninstallCommand(opts)));\n\n program\n .command('push')\n .description('Internal: invoked by Claude Code hooks. Reads stdin and buffers an event.')\n .requiredOption('--event <name>', 'Claude hook event name (SessionStart, PostToolUse, …)')\n .action(async (opts) => process.exit(await pushCommand(opts)));\n\n program\n .command('status')\n .description('Show current login, buffer state, and server reachability.')\n .action(async () => process.exit(await statusCommand()));\n\n program\n .command('runs')\n .description('Open your Runtape dashboard in the default browser.')\n .action(async () => process.exit(await runsCommand()));\n\n program.parseAsync(process.argv).catch((err) => {\n console.error(err);\n process.exit(1);\n });\n}\n","import { createInterface } from 'node:readline/promises';\nimport { stdin as input, stdout as output } from 'node:process';\nimport { Config, defaultServerUrl, writeConfig } from '../lib/config.js';\nimport { pingProject } from '../lib/api.js';\n\nexport async function loginCommand(opts: { key?: string; serverUrl?: string }): Promise<number> {\n const serverUrl = opts.serverUrl ?? defaultServerUrl();\n\n let apiKey = opts.key;\n if (!apiKey) {\n const rl = createInterface({ input, output });\n apiKey = (await rl.question('Paste your Runtape API key (rtk_…): ')).trim();\n rl.close();\n }\n\n const validation = Config.shape.api_key.safeParse(apiKey);\n if (!validation.success) {\n process.stderr.write(`Invalid API key format. Expected rtk_<64 hex chars>.\\n`);\n return 2;\n }\n\n process.stdout.write(`Validating against ${serverUrl}…\\n`);\n const ping = await pingProject(serverUrl, apiKey);\n if (!ping.ok) {\n process.stderr.write(`Login failed: ${ping.status === 401 ? 'unknown API key' : ping.detail ?? 'server unreachable'}\\n`);\n return 1;\n }\n\n await writeConfig({ api_key: apiKey, server_url: serverUrl });\n process.stdout.write(`Saved. You can now run: runtape install\\n`);\n return 0;\n}\n","import { chmod, mkdir, readFile, writeFile, unlink } from 'node:fs/promises';\nimport { dirname } from 'node:path';\nimport { z } from 'zod';\nimport { paths } from './paths.js';\n\nexport const Config = z.object({\n api_key: z.string().regex(/^rtk_[a-f0-9]{64}$/, 'api_key must be rtk_ followed by 64 hex chars'),\n server_url: z.string().url(),\n});\n\nexport type Config = z.infer<typeof Config>;\n\nconst DEFAULT_SERVER_URL = process.env.RUNTAPE_API_URL ?? 'https://runtape.dev';\n\nexport async function readConfig(): Promise<Config | null> {\n let raw: string;\n try {\n raw = await readFile(paths.config, 'utf8');\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === 'ENOENT') return null;\n throw err;\n }\n const parsed = Config.safeParse(JSON.parse(raw));\n if (!parsed.success) {\n throw new Error(`Invalid config at ${paths.config}: ${parsed.error.message}`);\n }\n return parsed.data;\n}\n\nexport async function writeConfig(c: Config): Promise<void> {\n await mkdir(dirname(paths.config), { recursive: true });\n await writeFile(paths.config, JSON.stringify(c, null, 2) + '\\n', { mode: 0o600 });\n // writeFile's `mode` is only applied on create. Re-chmod explicitly so a re-login\n // tightens permissions if the file was previously loosened (e.g. `chmod 644`).\n await chmod(paths.config, 0o600);\n}\n\nexport async function clearConfig(): Promise<void> {\n try {\n await unlink(paths.config);\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === 'ENOENT') return;\n throw err;\n }\n}\n\nexport function defaultServerUrl(): string {\n return DEFAULT_SERVER_URL;\n}\n","import { homedir } from 'node:os';\nimport { join } from 'node:path';\n\nconst RUNTAPE_HOME = process.env.RUNTAPE_HOME ?? join(homedir(), '.runtape');\n\nexport const paths = {\n home: RUNTAPE_HOME,\n config: join(RUNTAPE_HOME, 'config.json'),\n bufferDir: join(RUNTAPE_HOME, 'buffer'),\n seqDir: join(RUNTAPE_HOME, 'seq'),\n flusherPid: join(RUNTAPE_HOME, 'flusher.pid'),\n flusherLog: join(RUNTAPE_HOME, 'flusher.log'),\n bufferFile: (sessionId: string) => join(RUNTAPE_HOME, 'buffer', `${sessionId}.ndjson`),\n seqFile: (sessionId: string) => join(RUNTAPE_HOME, 'seq', sessionId),\n // Per-session marker recording the last assistant message uuid we've\n // emitted from the transcript. Lets transcript scans be idempotent across\n // hook invocations without re-reading + re-emitting everything.\n transcriptCursorFile: (sessionId: string) => join(RUNTAPE_HOME, 'transcript', sessionId),\n transcriptDir: join(RUNTAPE_HOME, 'transcript'),\n claudeSettings: (scope: 'user' | 'project') =>\n scope === 'user' ? join(homedir(), '.claude', 'settings.json') : join(process.cwd(), '.claude', 'settings.json'),\n claudeSettingsBackup: (scope: 'user' | 'project') =>\n scope === 'user'\n ? join(homedir(), '.claude', 'settings.json.runtape-backup')\n : join(process.cwd(), '.claude', 'settings.json.runtape-backup'),\n};\n","import type { RuntapeEvent } from '../types.js';\n\nexport type PostResult =\n | { ok: true; accepted: number; errors: Array<{ index: number; reason: string }> }\n | { ok: false; status: number; error: string; retryable: boolean };\n\nfunction isRetryableStatus(status: number): boolean {\n // 408 timeout, 425 too-early, 429 rate-limited, 5xx — retry. 4xx — drop (poison).\n return status === 408 || status === 425 || status === 429 || status >= 500;\n}\n\nexport async function postEvents(\n serverUrl: string,\n apiKey: string,\n events: RuntapeEvent[],\n): Promise<PostResult> {\n let response: Response;\n try {\n response = await fetch(`${serverUrl.replace(/\\/$/, '')}/api/v1/events`, {\n method: 'POST',\n headers: {\n 'content-type': 'application/json',\n authorization: `Bearer ${apiKey}`,\n },\n body: JSON.stringify({ events }),\n });\n } catch (err) {\n // Network failure (ENOTFOUND, ECONNREFUSED, fetch abort). Retryable.\n return {\n ok: false,\n status: 0,\n error: err instanceof Error ? err.message : String(err),\n retryable: true,\n };\n }\n\n if (response.ok) {\n const body = (await response.json()) as {\n accepted: number;\n errors: Array<{ index: number; reason: string }>;\n };\n return { ok: true, accepted: body.accepted, errors: body.errors };\n }\n\n let detail = '';\n try {\n detail = await response.text();\n } catch {\n /* ignore */\n }\n return {\n ok: false,\n status: response.status,\n error: detail || response.statusText,\n retryable: isRetryableStatus(response.status),\n };\n}\n\nexport async function pingProject(serverUrl: string, apiKey: string): Promise<{ ok: boolean; status: number; detail?: string }> {\n // We don't have a dedicated /me endpoint yet (we may add one in Task 3b).\n // For now, \"ping\" = POST /api/v1/events with an empty events array and inspect the response.\n // Server returns 400 invalid_request_body (events must be ≥1) on success — that proves auth works.\n // 401 = bad key; 5xx = server problem.\n let response: Response;\n try {\n response = await fetch(`${serverUrl.replace(/\\/$/, '')}/api/v1/events`, {\n method: 'POST',\n headers: {\n 'content-type': 'application/json',\n authorization: `Bearer ${apiKey}`,\n },\n body: JSON.stringify({ events: [] }),\n });\n } catch (err) {\n return { ok: false, status: 0, detail: err instanceof Error ? err.message : String(err) };\n }\n\n if (response.status === 400) return { ok: true, status: 400 };\n if (response.status === 401) return { ok: false, status: 401, detail: 'invalid api key' };\n return { ok: false, status: response.status, detail: response.statusText };\n}\n","import { clearConfig } from '../lib/config.js';\n\nexport async function logoutCommand(): Promise<number> {\n await clearConfig();\n process.stdout.write('Logged out. Config removed.\\n');\n return 0;\n}\n","import { createInterface } from 'node:readline/promises';\nimport { stdin as input, stdout as output } from 'node:process';\nimport { readConfig } from '../lib/config.js';\nimport { installHooks } from '../lib/hooks-installer.js';\nimport { resolveCliBinPath } from '../lib/cli-bin.js';\n\nexport async function installCommand(opts: { project?: boolean; yes?: boolean }): Promise<number> {\n const cfg = await readConfig();\n if (!cfg) {\n process.stderr.write('Not logged in. Run `runtape login` first.\\n');\n return 1;\n }\n\n const scope: 'user' | 'project' = opts.project ? 'project' : 'user';\n const cliBinPath = resolveCliBinPath();\n\n if (!opts.yes) {\n const rl = createInterface({ input, output });\n const answer = (await rl.question(`Install Runtape hooks into ${scope} settings (yes/no)? `)).trim().toLowerCase();\n rl.close();\n if (answer !== 'y' && answer !== 'yes') {\n process.stdout.write('Aborted.\\n');\n return 0;\n }\n }\n\n const result = await installHooks(scope, cliBinPath);\n process.stdout.write(`Updated ${result.settingsPath}\\n`);\n process.stdout.write(`Backup: ${result.backupPath}\\n`);\n if (result.addedHooks.length === 0) {\n process.stdout.write('Hooks already installed — nothing changed.\\n');\n } else {\n process.stdout.write(`Added: ${result.addedHooks.join(', ')}\\n`);\n }\n return 0;\n}\n","import { copyFile, mkdir, readFile, writeFile } from 'node:fs/promises';\nimport { dirname } from 'node:path';\nimport { paths } from './paths.js';\nimport { SUPPORTED_HOOKS } from './hook-mapping.js';\n\nconst RUNTAPE_MARKER = 'runtape:managed';\n\ntype HookEntry = { type: 'command'; command: string; [k: string]: unknown };\ntype HookMatcher = { matcher: string; hooks: HookEntry[]; [k: string]: unknown };\ntype HooksBlock = Record<string, HookMatcher[]>;\ntype ClaudeSettings = { hooks?: HooksBlock; [k: string]: unknown };\n\nfunction runtapeEntry(hookName: string, cliBinPath: string): HookEntry {\n return {\n type: 'command',\n command: `${cliBinPath} push --event ${hookName}`,\n [RUNTAPE_MARKER]: true,\n };\n}\n\nasync function readSettings(file: string): Promise<ClaudeSettings> {\n try {\n const raw = await readFile(file, 'utf8');\n return JSON.parse(raw) as ClaudeSettings;\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === 'ENOENT') return {};\n throw err;\n }\n}\n\nasync function writeSettings(file: string, data: ClaudeSettings): Promise<void> {\n await mkdir(dirname(file), { recursive: true });\n await writeFile(file, JSON.stringify(data, null, 2) + '\\n');\n}\n\nexport type InstallResult = {\n settingsPath: string;\n backupPath: string;\n addedHooks: string[];\n};\n\nexport async function installHooks(scope: 'user' | 'project', cliBinPath: string): Promise<InstallResult> {\n const settingsPath = paths.claudeSettings(scope);\n const backupPath = paths.claudeSettingsBackup(scope);\n\n // Backup (no-op if settings doesn't exist yet — we still create the dir).\n try {\n await copyFile(settingsPath, backupPath);\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code !== 'ENOENT') throw err;\n }\n\n const settings = await readSettings(settingsPath);\n settings.hooks = settings.hooks ?? {};\n\n const added: string[] = [];\n for (const hookName of SUPPORTED_HOOKS) {\n const matchers = (settings.hooks[hookName] = settings.hooks[hookName] ?? []);\n // Find or create a matcher: \"*\". Append our entry there.\n let star = matchers.find((m) => m.matcher === '*');\n if (!star) {\n star = { matcher: '*', hooks: [] };\n matchers.push(star);\n }\n star.hooks = star.hooks ?? [];\n const already = star.hooks.some((h) => (h as HookEntry)[RUNTAPE_MARKER] === true);\n if (!already) {\n star.hooks.push(runtapeEntry(hookName, cliBinPath));\n added.push(hookName);\n }\n }\n\n await writeSettings(settingsPath, settings);\n return { settingsPath, backupPath, addedHooks: added };\n}\n\nexport type UninstallResult = {\n settingsPath: string;\n removedHooks: string[];\n};\n\nexport async function uninstallHooks(scope: 'user' | 'project'): Promise<UninstallResult> {\n const settingsPath = paths.claudeSettings(scope);\n const settings = await readSettings(settingsPath);\n const removed: string[] = [];\n\n if (settings.hooks) {\n for (const hookName of Object.keys(settings.hooks)) {\n const matchers = settings.hooks[hookName];\n for (const matcher of matchers) {\n if (!Array.isArray(matcher.hooks)) continue;\n const before = matcher.hooks.length;\n matcher.hooks = matcher.hooks.filter((h) => (h as HookEntry)[RUNTAPE_MARKER] !== true);\n if (matcher.hooks.length < before) removed.push(hookName);\n }\n // Clean up matchers that are now empty.\n settings.hooks[hookName] = matchers.filter((m) => Array.isArray(m.hooks) && m.hooks.length > 0);\n if (settings.hooks[hookName].length === 0) delete settings.hooks[hookName];\n }\n if (Object.keys(settings.hooks).length === 0) delete settings.hooks;\n }\n\n await writeSettings(settingsPath, settings);\n return { settingsPath, removedHooks: Array.from(new Set(removed)) };\n}\n","import { z } from 'zod';\nimport { RuntapeEvent } from '../types.js';\n\n// The seven Claude Code hook names we register, plus a sentinel \"drop\" for unknown events.\n// Validated 2026-05-14 against Claude Code 2.1.128 — see spike findings spec.\nexport type ClaudeHookName =\n | 'SessionStart'\n | 'UserPromptSubmit'\n | 'PreToolUse'\n | 'PostToolUse'\n | 'Stop'\n | 'SubagentStop'\n | 'SessionEnd'\n | 'Notification';\n\nexport const SUPPORTED_HOOKS: ClaudeHookName[] = [\n 'SessionStart',\n 'UserPromptSubmit',\n 'PreToolUse',\n 'PostToolUse',\n 'Stop',\n 'SubagentStop',\n 'SessionEnd',\n];\n\nexport type MappedEvent = z.infer<typeof RuntapeEvent>;\n\nexport type MapResult =\n | { kind: 'event'; event: MappedEvent }\n | { kind: 'drop'; reason: string };\n\n// PostToolUse tool_response shapes vary by tool. We look at the canonical\n// signals each tool emits and collapse them into a uniform (is_error, message)\n// pair so the server doesn't need per-tool knowledge.\n// - Anthropic-tagged: { is_error: true, content: [{text}] } (the official\n// content-block error form used by some Claude Code tools).\n// - Bash: { interrupted, stdout, stderr, output, ... }. Non-zero exits also\n// surface in stderr and an explicit `exitCode` when available.\n// - Edit/Write/MultiEdit: success returns a structured payload; errors\n// return `{ error: '...' }`.\nfunction inspectToolResponse(tool_response: unknown): { is_error: boolean; error_message?: string } {\n if (!tool_response || typeof tool_response !== 'object') return { is_error: false };\n const r = tool_response as Record<string, unknown>;\n if (r.is_error === true) {\n const content = r.content;\n if (Array.isArray(content)) {\n for (const block of content) {\n if (block && typeof block === 'object' && 'text' in block) {\n const t = (block as { text?: unknown }).text;\n if (typeof t === 'string') return { is_error: true, error_message: t };\n }\n }\n }\n if (typeof r.message === 'string') return { is_error: true, error_message: r.message };\n return { is_error: true };\n }\n if (typeof r.error === 'string' && r.error.trim() !== '') {\n return { is_error: true, error_message: r.error };\n }\n if (r.interrupted === true) {\n return { is_error: true, error_message: 'Interrupted' };\n }\n return { is_error: false };\n}\n\n// Maps a Claude hook payload + the hook name we were invoked with into a RuntapeEvent.\n// Returns { kind: 'drop' } for Notification or unknown events (we just exit cleanly).\nexport function mapHookPayload(\n hookName: string,\n payload: Record<string, unknown>,\n augment: { wall_ts: string; sequence: number },\n): MapResult {\n // Shared envelope every Claude hook carries.\n const base = {\n session_id: payload.session_id,\n transcript_path: payload.transcript_path,\n cwd: payload.cwd,\n hook_event_name: payload.hook_event_name ?? hookName,\n permission_mode: payload.permission_mode,\n wall_ts: augment.wall_ts,\n sequence: augment.sequence,\n };\n\n let candidate: Record<string, unknown>;\n switch (hookName) {\n case 'SessionStart':\n candidate = { ...base, type: 'session_start', source: payload.source ?? 'startup' };\n break;\n case 'UserPromptSubmit':\n candidate = { ...base, type: 'user_prompt', prompt: payload.prompt };\n break;\n case 'PreToolUse':\n candidate = {\n ...base,\n type: 'tool_attempt',\n tool_name: payload.tool_name,\n tool_input: payload.tool_input,\n tool_use_id: payload.tool_use_id,\n };\n break;\n case 'PostToolUse': {\n const err = inspectToolResponse(payload.tool_response);\n candidate = {\n ...base,\n type: 'tool_call',\n tool_name: payload.tool_name,\n tool_input: payload.tool_input,\n tool_response: payload.tool_response,\n tool_use_id: payload.tool_use_id,\n duration_ms: payload.duration_ms,\n is_error: err.is_error,\n error_message: err.error_message,\n };\n break;\n }\n case 'Stop':\n // Despite the event type literal, this is \"turn end\" — Stop fires every\n // time the assistant yields back to the user. Server treats it as\n // 'run is idle'. Real session close uses SessionEnd → 'session_close'.\n candidate = {\n ...base,\n type: 'session_end',\n last_assistant_message: payload.last_assistant_message,\n stop_hook_active: payload.stop_hook_active,\n };\n break;\n case 'SessionEnd':\n candidate = {\n ...base,\n type: 'session_close',\n reason: payload.reason,\n };\n break;\n case 'SubagentStop':\n candidate = {\n ...base,\n type: 'subagent_end',\n agent_id: payload.agent_id,\n agent_type: payload.agent_type,\n agent_transcript_path: payload.agent_transcript_path,\n last_assistant_message: payload.last_assistant_message,\n stop_hook_active: payload.stop_hook_active,\n };\n break;\n default:\n return { kind: 'drop', reason: `unsupported hook: ${hookName}` };\n }\n\n const parsed = RuntapeEvent.safeParse(candidate);\n if (!parsed.success) {\n return { kind: 'drop', reason: `validation failed: ${parsed.error.issues.map((i) => i.path.join('.') + ': ' + i.message).join('; ')}` };\n }\n return { kind: 'event', event: parsed.data };\n}\n","import { fileURLToPath } from 'node:url';\nimport { dirname, resolve, sep } from 'node:path';\n\n// Returns an absolute path to the `runtape` binary the user just invoked.\n// This is what we write into `~/.claude/settings.json` so the hooks call the same install.\n// Falls back to \"runtape\" (on PATH) if we can't resolve it — useful when users want a\n// non-pinned reference and have the CLI installed globally.\nexport function resolveCliBinPath(): string {\n if (process.env.RUNTAPE_CLI_BIN) return process.env.RUNTAPE_CLI_BIN;\n\n const argv1 = process.argv[1];\n if (argv1) {\n // If we live under a node_modules tree, the absolute path embeds the\n // package's extraction location, which changes on `npm install -g <newer>`.\n // Writing that path into ~/.claude/settings.json would break the hook on\n // the next upgrade. Fall back to the bare command name — `runtape` is on\n // PATH after `npm install -g`, and a fresh install re-points the symlink.\n if (argv1.includes(`${sep}node_modules${sep}`)) return 'runtape';\n try {\n return resolve(argv1);\n } catch {\n /* fall through */\n }\n }\n // Last resort: assume \"runtape\" is on PATH.\n return 'runtape';\n}\n\n// Exported for tests — turns a relative path into something we can stick in JSON.\nexport function moduleFileFromImportMeta(metaUrl: string): string {\n return fileURLToPath(metaUrl);\n}\n\n// Suppress unused-import warning for `dirname`.\nvoid dirname;\n","import { uninstallHooks } from '../lib/hooks-installer.js';\n\nexport async function uninstallCommand(opts: { project?: boolean }): Promise<number> {\n const scope: 'user' | 'project' = opts.project ? 'project' : 'user';\n const result = await uninstallHooks(scope);\n if (result.removedHooks.length === 0) {\n process.stdout.write(`No Runtape hooks found in ${result.settingsPath}.\\n`);\n } else {\n process.stdout.write(`Removed Runtape entries from: ${result.removedHooks.join(', ')}\\n`);\n }\n return 0;\n}\n","import { spawn } from 'node:child_process';\nimport { mapHookPayload } from '../lib/hook-mapping.js';\nimport { nextSequence } from '../lib/sequence.js';\nimport { appendEvent } from '../lib/buffer.js';\nimport { readConfig } from '../lib/config.js';\nimport { resolveCliBinPath } from '../lib/cli-bin.js';\nimport { readNewAssistantTurns, persistCursor } from '../lib/transcript.js';\nimport { readNewSubagentEvents, persistSubagentCursor } from '../lib/subagent-transcript.js';\nimport type { RuntapeEvent } from '../types.js';\n\nasync function readStdin(): Promise<string> {\n if (process.stdin.isTTY) return '';\n const chunks: Buffer[] = [];\n for await (const chunk of process.stdin) {\n chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));\n }\n return Buffer.concat(chunks).toString('utf8');\n}\n\nfunction spawnFlusher(cliBinPath: string): void {\n // Detached so it survives this process exit. stdio:'ignore' so the daemon\n // doesn't inherit the hook's stdin/stdout (Claude Code reads hook stdout!).\n const child = spawn(cliBinPath, ['--internal-flusher'], {\n detached: true,\n stdio: 'ignore',\n env: process.env,\n });\n child.unref();\n}\n\nexport async function pushCommand(opts: { event: string }): Promise<number> {\n // The contract is: never block the hook. If we can't parse/auth/whatever, exit 0 quietly\n // (printing to stderr is fine; printing to stdout could be parsed by Claude Code).\n try {\n const cfg = await readConfig();\n if (!cfg) {\n process.stderr.write('runtape: not logged in — skipping event\\n');\n return 0;\n }\n\n const raw = await readStdin();\n if (!raw.trim()) {\n // SessionStart in some Claude Code versions may invoke hooks with no stdin; ignore.\n return 0;\n }\n\n let payload: Record<string, unknown>;\n try {\n payload = JSON.parse(raw) as Record<string, unknown>;\n } catch (err) {\n process.stderr.write(`runtape: invalid JSON on stdin: ${err instanceof Error ? err.message : String(err)}\\n`);\n return 0;\n }\n\n const sessionId = typeof payload.session_id === 'string' ? payload.session_id : null;\n if (!sessionId) {\n process.stderr.write('runtape: missing session_id on hook payload\\n');\n return 0;\n }\n\n const sequence = await nextSequence(sessionId);\n const result = mapHookPayload(opts.event, payload, {\n wall_ts: new Date().toISOString(),\n sequence,\n });\n\n if (result.kind === 'drop') {\n // Notification, unknown hook, or validation failure. Quiet log + exit clean.\n process.stderr.write(`runtape: dropped ${opts.event}: ${result.reason}\\n`);\n return 0;\n }\n\n await appendEvent(sessionId, result.event);\n\n // After the primary event lands in the buffer, scan the transcript for any\n // new assistant turns and emit one assistant_turn event per uuid we haven't\n // seen. PostToolUse and Stop are the hooks that follow assistant output;\n // scanning on other hooks is cheap (no new turns) and harmless.\n if (opts.event === 'PostToolUse' || opts.event === 'Stop' || opts.event === 'SubagentStop') {\n const transcriptPath = typeof payload.transcript_path === 'string' ? payload.transcript_path : '';\n if (transcriptPath !== '') {\n try {\n const { turns, seen } = await readNewAssistantTurns(sessionId, transcriptPath);\n const newlyEmitted: string[] = [];\n for (const t of turns) {\n const seq = await nextSequence(sessionId);\n const ev: RuntapeEvent = {\n type: 'assistant_turn',\n session_id: sessionId,\n transcript_path: transcriptPath,\n cwd: typeof payload.cwd === 'string' ? payload.cwd : '',\n hook_event_name: opts.event,\n permission_mode: typeof payload.permission_mode === 'string' ? payload.permission_mode : undefined,\n wall_ts: new Date().toISOString(),\n sequence: seq,\n message_uuid: t.message_uuid,\n model: t.model,\n input_tokens: t.input_tokens,\n output_tokens: t.output_tokens,\n cache_read_tokens: t.cache_read_tokens,\n cache_creation_tokens: t.cache_creation_tokens,\n text: t.text,\n };\n await appendEvent(sessionId, ev);\n newlyEmitted.push(t.message_uuid);\n }\n if (newlyEmitted.length > 0) {\n await persistCursor(sessionId, seen, newlyEmitted);\n }\n } catch (err) {\n // Transcript scan failures must never fail the hook.\n process.stderr.write(`runtape: transcript scan failed: ${err instanceof Error ? err.message : String(err)}\\n`);\n }\n }\n }\n\n // On SubagentStop, ALSO scan the subagent's own transcript and synthesize\n // the full event stream of its internal session — user prompt, assistant\n // turns with model+usage, plus tool_attempt/tool_call pairs. Tag every\n // synthesized event with agent_tool_use_id so the server can resolve the\n // parent Agent step and stamp parent_step_id deterministically.\n if (opts.event === 'SubagentStop') {\n const subTranscript = typeof payload.agent_transcript_path === 'string' ? payload.agent_transcript_path : '';\n const agentToolUseId = typeof payload.agent_id === 'string' ? payload.agent_id : '';\n if (subTranscript !== '' && agentToolUseId !== '') {\n try {\n const { emits, seen } = await readNewSubagentEvents(sessionId, agentToolUseId, subTranscript);\n const newlyEmitted: string[] = [];\n const cwd = typeof payload.cwd === 'string' ? payload.cwd : '';\n for (const e of emits) {\n const seq = await nextSequence(sessionId);\n const baseEnvelope = {\n session_id: sessionId,\n transcript_path: subTranscript,\n cwd,\n hook_event_name: opts.event,\n permission_mode: typeof payload.permission_mode === 'string' ? payload.permission_mode : undefined,\n wall_ts: new Date().toISOString(),\n sequence: seq,\n agent_tool_use_id: agentToolUseId,\n };\n let ev: RuntapeEvent | null = null;\n if (e.kind === 'user_prompt') {\n ev = { ...baseEnvelope, type: 'user_prompt', prompt: e.prompt };\n } else if (e.kind === 'assistant_turn') {\n ev = {\n ...baseEnvelope,\n type: 'assistant_turn',\n message_uuid: e.message_uuid,\n model: e.model,\n input_tokens: e.input_tokens,\n output_tokens: e.output_tokens,\n cache_read_tokens: e.cache_read_tokens,\n cache_creation_tokens: e.cache_creation_tokens,\n text: e.text,\n };\n } else if (e.kind === 'tool_attempt') {\n ev = {\n ...baseEnvelope,\n type: 'tool_attempt',\n tool_name: e.tool_name,\n tool_input: e.tool_input,\n tool_use_id: e.tool_use_id,\n };\n } else if (e.kind === 'tool_call') {\n ev = {\n ...baseEnvelope,\n type: 'tool_call',\n tool_name: e.tool_name,\n tool_input: null,\n tool_response: e.tool_response,\n tool_use_id: e.tool_use_id,\n duration_ms: 0,\n is_error: e.is_error,\n error_message: e.error_message,\n };\n }\n if (ev) {\n await appendEvent(sessionId, ev);\n newlyEmitted.push(e.uuid);\n }\n }\n if (newlyEmitted.length > 0) {\n await persistSubagentCursor(sessionId, agentToolUseId, seen, newlyEmitted);\n }\n } catch (err) {\n process.stderr.write(`runtape: subagent transcript scan failed: ${err instanceof Error ? err.message : String(err)}\\n`);\n }\n }\n }\n\n spawnFlusher(resolveCliBinPath());\n return 0;\n } catch (err) {\n process.stderr.write(`runtape: push error: ${err instanceof Error ? err.message : String(err)}\\n`);\n return 0; // Never fail the hook.\n }\n}\n","import { mkdir, readFile, writeFile } from 'node:fs/promises';\nimport { dirname } from 'node:path';\nimport { paths } from './paths.js';\n\n// Per-session monotonic counter. Persisted as a single integer in seq/<session_id>.\n// Hooks fire one-at-a-time per session (Claude Code waits for the hook to exit before\n// firing the next), so we do NOT need cross-process locking — but we DO need the value\n// to survive across hook invocations, since each `runtape push` is a separate process.\nexport async function nextSequence(sessionId: string): Promise<number> {\n const file = paths.seqFile(sessionId);\n await mkdir(dirname(file), { recursive: true });\n\n let current = 0;\n try {\n const raw = await readFile(file, 'utf8');\n const parsed = Number.parseInt(raw.trim(), 10);\n if (Number.isFinite(parsed) && parsed >= 0) current = parsed;\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code !== 'ENOENT') throw err;\n }\n\n const next = current + 1;\n await writeFile(file, String(next));\n return next - 1; // First call returns 0 (matching the Zod schema's nonnegative invariant).\n}\n","import { appendFile, mkdir, readFile, readdir, writeFile, unlink, stat } from 'node:fs/promises';\nimport type { RuntapeEvent } from '../types.js';\nimport { paths } from './paths.js';\n\n// Atomic append-as-line. POSIX guarantees a single write() of <PIPE_BUF bytes (≥512) is\n// atomic, and we further constrain ourselves to one line per call. Two concurrent\n// appenders (e.g. two Claude Code instances writing to the same session — impossible\n// today, but cheap defense) cannot interleave a single line.\nexport async function appendEvent(sessionId: string, event: RuntapeEvent): Promise<void> {\n await mkdir(paths.bufferDir, { recursive: true });\n const line = JSON.stringify(event) + '\\n';\n await appendFile(paths.bufferFile(sessionId), line, { encoding: 'utf8' });\n}\n\nexport type BufferedSession = {\n sessionId: string;\n events: RuntapeEvent[];\n raw: string[]; // Raw lines, so we can rewrite exactly what we read on partial-flush.\n};\n\nexport async function listBufferedSessions(): Promise<string[]> {\n let entries: string[];\n try {\n entries = await readdir(paths.bufferDir);\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === 'ENOENT') return [];\n throw err;\n }\n return entries.filter((e) => e.endsWith('.ndjson')).map((e) => e.slice(0, -'.ndjson'.length));\n}\n\nexport async function readBufferedSession(sessionId: string): Promise<BufferedSession | null> {\n let raw: string;\n try {\n raw = await readFile(paths.bufferFile(sessionId), 'utf8');\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === 'ENOENT') return null;\n throw err;\n }\n const lines = raw.split('\\n').filter((l) => l.length > 0);\n const events: RuntapeEvent[] = [];\n for (const line of lines) {\n try {\n events.push(JSON.parse(line) as RuntapeEvent);\n } catch {\n // Skip malformed lines — they could only get there via a half-written disk; drop them.\n }\n }\n return { sessionId, events, raw: lines };\n}\n\n// Atomic truncate-after-flush: write a temp file with the unflushed remainder, then rename.\n// If `unflushedLines` is empty, delete the buffer file entirely.\nexport async function rewriteBufferedSession(sessionId: string, unflushedLines: string[]): Promise<void> {\n const file = paths.bufferFile(sessionId);\n if (unflushedLines.length === 0) {\n try {\n await unlink(file);\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code !== 'ENOENT') throw err;\n }\n return;\n }\n const tmp = file + '.tmp';\n await writeFile(tmp, unflushedLines.map((l) => l + '\\n').join(''));\n // rename is atomic within the same filesystem; both paths are in ~/.runtape/buffer.\n const { rename } = await import('node:fs/promises');\n await rename(tmp, file);\n}\n\nexport async function bufferSize(sessionId: string): Promise<number> {\n try {\n const s = await stat(paths.bufferFile(sessionId));\n return s.size;\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === 'ENOENT') return 0;\n throw err;\n }\n}\n\nexport function bufferDirPath(): string {\n return paths.bufferDir;\n}\n\n// Used by tests + future GC: stat-mtime in ms for the buffer file.\nexport async function bufferMtimeMs(sessionId: string): Promise<number | null> {\n try {\n const s = await stat(paths.bufferFile(sessionId));\n return s.mtimeMs;\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === 'ENOENT') return null;\n throw err;\n }\n}\n\n// Re-export for callers that want to know where the file lives without importing paths twice.\nexport function bufferFilePath(sessionId: string): string {\n return paths.bufferFile(sessionId);\n}\n","import { mkdir, readFile, writeFile } from 'node:fs/promises';\nimport { dirname } from 'node:path';\nimport { paths } from './paths.js';\n\n// Claude Code maintains a JSONL transcript at `transcript_path`. Every line is\n// a single message object with at minimum `uuid`, `type` (user|assistant|...)\n// and a `message` payload. Assistant messages additionally carry the model\n// identifier and Anthropic API usage block — the *only* place either datum\n// appears in the hook emit chain.\n//\n// We scan the transcript on every PostToolUse/Stop hook and emit one\n// AssistantTurn event per assistant message whose uuid is not in our seen\n// set. The cursor file persists the seen set across hook invocations.\n//\n// The transcript is append-only within a session so the scan is cheap; we\n// only ever read the file once per hook fire.\n\nexport type TranscriptUsage = {\n message_uuid: string;\n model: string;\n input_tokens: number;\n output_tokens: number;\n cache_read_tokens: number;\n cache_creation_tokens: number;\n text?: string;\n};\n\ntype AssistantLine = {\n uuid?: unknown;\n type?: unknown;\n message?: {\n role?: unknown;\n model?: unknown;\n content?: unknown;\n usage?: {\n input_tokens?: unknown;\n output_tokens?: unknown;\n cache_read_input_tokens?: unknown;\n cache_creation_input_tokens?: unknown;\n };\n };\n};\n\nfunction asInt(x: unknown): number {\n if (typeof x === 'number' && Number.isFinite(x) && x >= 0) return Math.trunc(x);\n return 0;\n}\n\nfunction extractAssistantText(content: unknown): string | undefined {\n // Anthropic content blocks: [{ type: 'text', text: '...' }, { type: 'tool_use', ... }]\n if (!Array.isArray(content)) return undefined;\n const parts: string[] = [];\n for (const block of content) {\n if (block && typeof block === 'object' && 'type' in block) {\n const b = block as { type: unknown; text?: unknown };\n if (b.type === 'text' && typeof b.text === 'string') parts.push(b.text);\n }\n }\n const joined = parts.join('\\n').trim();\n return joined === '' ? undefined : joined;\n}\n\n// Parses the transcript and returns assistant turns whose uuid is not in\n// `seenUuids`. The seen set is read from the cursor file; the caller is\n// responsible for persisting it after the events have been buffered.\nexport async function readNewAssistantTurns(\n sessionId: string,\n transcriptPath: string,\n): Promise<{ turns: TranscriptUsage[]; seen: Set<string> }> {\n const seen = await readCursor(sessionId);\n\n let raw: string;\n try {\n raw = await readFile(transcriptPath, 'utf8');\n } catch {\n return { turns: [], seen };\n }\n\n const turns: TranscriptUsage[] = [];\n for (const line of raw.split('\\n')) {\n const trimmed = line.trim();\n if (trimmed === '') continue;\n let parsed: AssistantLine;\n try {\n parsed = JSON.parse(trimmed) as AssistantLine;\n } catch {\n // Truncated or partial line at the tail — skip silently. The next hook\n // fire will see the full line once Claude Code has finished writing it.\n continue;\n }\n if (parsed.type !== 'assistant') continue;\n const uuid = typeof parsed.uuid === 'string' ? parsed.uuid : '';\n if (uuid === '' || seen.has(uuid)) continue;\n const msg = parsed.message ?? {};\n const model = typeof msg.model === 'string' ? msg.model : '';\n // Claude Code emits placeholder turns with model \"<synthetic>\" (compaction\n // summaries, internal markers) that always have zero usage. Skip them —\n // they add noise without information.\n if (model === '' || model === '<synthetic>') continue;\n const usage = msg.usage ?? {};\n turns.push({\n message_uuid: uuid,\n model,\n input_tokens: asInt(usage.input_tokens),\n output_tokens: asInt(usage.output_tokens),\n cache_read_tokens: asInt(usage.cache_read_input_tokens),\n cache_creation_tokens: asInt(usage.cache_creation_input_tokens),\n text: extractAssistantText(msg.content),\n });\n }\n\n return { turns, seen };\n}\n\n// Cursor file is a newline-separated list of uuids. Trim to the most recent\n// 200 — the seen set only needs to cover the tail of the transcript that the\n// next hook might re-scan, not the full history.\nconst CURSOR_KEEP = 200;\n\nasync function readCursor(sessionId: string): Promise<Set<string>> {\n try {\n const raw = await readFile(paths.transcriptCursorFile(sessionId), 'utf8');\n return new Set(\n raw\n .split('\\n')\n .map((s) => s.trim())\n .filter((s) => s !== ''),\n );\n } catch {\n return new Set();\n }\n}\n\nexport async function persistCursor(\n sessionId: string,\n seen: Set<string>,\n newlyEmitted: string[],\n): Promise<void> {\n for (const u of newlyEmitted) seen.add(u);\n const file = paths.transcriptCursorFile(sessionId);\n await mkdir(dirname(file), { recursive: true });\n // Keep only the tail so the file doesn't grow unbounded over long sessions.\n const arr = [...seen];\n const trimmed = arr.length > CURSOR_KEEP ? arr.slice(arr.length - CURSOR_KEEP) : arr;\n await writeFile(file, trimmed.join('\\n') + '\\n');\n}\n","import { mkdir, readFile, writeFile } from 'node:fs/promises';\nimport { dirname } from 'node:path';\nimport { paths } from './paths.js';\n\n// The subagent transcript is a separate JSONL Claude Code keeps for each\n// subagent it spawns via the Task tool. Format mirrors the main transcript:\n//\n// { uuid, type: 'user', message: { content: [...] } }\n// { uuid, type: 'assistant', message: { model, content: [...], usage: {...} } }\n//\n// We unpack it into a richer stream than the main transcript reader because\n// the subagent's internal life is what we're trying to expose:\n// - user entries with text content -> user_prompt\n// - user entries with tool_result blks -> tool_call (one per result)\n// - assistant entries -> assistant_turn (model + usage)\n// - tool_use blocks inside assistant -> tool_attempt (one per block)\n//\n// Cursor lives at ~/.runtape/transcript/subagent-<parent_session>-<agent_tool_use_id>\n// and tracks per-uuid emission idempotency.\n\nexport type SubagentEmit =\n | {\n kind: 'user_prompt';\n uuid: string;\n prompt: string;\n }\n | {\n kind: 'assistant_turn';\n uuid: string;\n message_uuid: string;\n model: string;\n input_tokens: number;\n output_tokens: number;\n cache_read_tokens: number;\n cache_creation_tokens: number;\n text?: string;\n }\n | {\n kind: 'tool_attempt';\n uuid: string;\n tool_use_id: string;\n tool_name: string;\n tool_input: unknown;\n }\n | {\n kind: 'tool_call';\n uuid: string;\n tool_use_id: string;\n tool_name: string;\n tool_response: unknown;\n is_error: boolean;\n error_message?: string;\n };\n\ntype TranscriptLine = {\n uuid?: unknown;\n type?: unknown;\n message?: {\n role?: unknown;\n model?: unknown;\n content?: unknown;\n usage?: {\n input_tokens?: unknown;\n output_tokens?: unknown;\n cache_read_input_tokens?: unknown;\n cache_creation_input_tokens?: unknown;\n };\n };\n};\n\nfunction asInt(x: unknown): number {\n if (typeof x === 'number' && Number.isFinite(x) && x >= 0) return Math.trunc(x);\n return 0;\n}\n\nfunction textFromBlocks(content: unknown): string | undefined {\n if (!Array.isArray(content)) return typeof content === 'string' ? content : undefined;\n const parts: string[] = [];\n for (const block of content) {\n if (block && typeof block === 'object' && 'type' in block) {\n const b = block as { type: unknown; text?: unknown };\n if (b.type === 'text' && typeof b.text === 'string') parts.push(b.text);\n }\n }\n const joined = parts.join('\\n').trim();\n return joined === '' ? undefined : joined;\n}\n\nfunction summarizeToolResult(content: unknown): { is_error: boolean; error_message?: string } {\n if (!Array.isArray(content)) {\n if (typeof content === 'string') return { is_error: false };\n return { is_error: false };\n }\n // Anthropic tool_result blocks can carry their own is_error flag.\n let isError = false;\n const texts: string[] = [];\n for (const block of content) {\n if (block && typeof block === 'object') {\n const b = block as { type?: unknown; text?: unknown; is_error?: unknown };\n if (b.is_error === true) isError = true;\n if (typeof b.text === 'string') texts.push(b.text);\n }\n }\n if (isError && texts.length > 0) return { is_error: true, error_message: texts.join('\\n').slice(0, 500) };\n if (isError) return { is_error: true };\n return { is_error: false };\n}\n\nexport async function readNewSubagentEvents(\n parentSessionId: string,\n agentToolUseId: string,\n transcriptPath: string,\n): Promise<{ emits: SubagentEmit[]; seen: Set<string> }> {\n const seen = await readCursor(parentSessionId, agentToolUseId);\n\n let raw: string;\n try {\n raw = await readFile(transcriptPath, 'utf8');\n } catch {\n return { emits: [], seen };\n }\n\n const emits: SubagentEmit[] = [];\n // Map tool_use_id -> tool_name learned from assistant tool_use blocks so we\n // can echo it back on the corresponding tool_call (the tool_result echo\n // doesn't carry the tool name itself).\n const toolNameByUseId = new Map<string, string>();\n\n for (const line of raw.split('\\n')) {\n const trimmed = line.trim();\n if (trimmed === '') continue;\n let parsed: TranscriptLine;\n try {\n parsed = JSON.parse(trimmed) as TranscriptLine;\n } catch {\n continue;\n }\n const uuid = typeof parsed.uuid === 'string' ? parsed.uuid : '';\n if (uuid === '' || seen.has(uuid)) continue;\n\n const msg = parsed.message ?? {};\n\n if (parsed.type === 'user') {\n // Two flavors of user entries: real user prompts vs. tool_result echoes.\n const content = msg.content;\n const hasToolResults =\n Array.isArray(content) &&\n content.some(\n (b) => b && typeof b === 'object' && (b as { type?: unknown }).type === 'tool_result',\n );\n if (hasToolResults) {\n for (const block of content as unknown[]) {\n if (!block || typeof block !== 'object') continue;\n const b = block as { type?: unknown; tool_use_id?: unknown; content?: unknown };\n if (b.type !== 'tool_result') continue;\n const tuid = typeof b.tool_use_id === 'string' ? b.tool_use_id : '';\n if (tuid === '') continue;\n const { is_error, error_message } = summarizeToolResult(b.content);\n emits.push({\n kind: 'tool_call',\n uuid: `${uuid}:${tuid}`,\n tool_use_id: tuid,\n tool_name: toolNameByUseId.get(tuid) ?? 'unknown',\n tool_response: b.content,\n is_error,\n error_message,\n });\n }\n } else {\n const text = textFromBlocks(content);\n if (text !== undefined) {\n emits.push({ kind: 'user_prompt', uuid, prompt: text });\n }\n }\n continue;\n }\n\n if (parsed.type === 'assistant') {\n const model = typeof msg.model === 'string' ? msg.model : '';\n // Synthetic placeholders carry no useful information.\n if (model === '' || model === '<synthetic>') continue;\n const usage = msg.usage ?? {};\n emits.push({\n kind: 'assistant_turn',\n uuid,\n message_uuid: uuid,\n model,\n input_tokens: asInt(usage.input_tokens),\n output_tokens: asInt(usage.output_tokens),\n cache_read_tokens: asInt(usage.cache_read_input_tokens),\n cache_creation_tokens: asInt(usage.cache_creation_input_tokens),\n text: textFromBlocks(msg.content),\n });\n // Emit one tool_attempt per tool_use block embedded in this assistant\n // message. The matching tool_result will land in the next user entry.\n if (Array.isArray(msg.content)) {\n for (const block of msg.content) {\n if (!block || typeof block !== 'object') continue;\n const b = block as { type?: unknown; id?: unknown; name?: unknown; input?: unknown };\n if (b.type !== 'tool_use') continue;\n const tuid = typeof b.id === 'string' ? b.id : '';\n const tname = typeof b.name === 'string' ? b.name : '';\n if (tuid === '' || tname === '') continue;\n toolNameByUseId.set(tuid, tname);\n emits.push({\n kind: 'tool_attempt',\n uuid: `${uuid}:${tuid}`,\n tool_use_id: tuid,\n tool_name: tname,\n tool_input: b.input,\n });\n }\n }\n continue;\n }\n }\n\n return { emits, seen };\n}\n\nconst CURSOR_KEEP = 500;\n\nasync function readCursor(parentSessionId: string, agentToolUseId: string): Promise<Set<string>> {\n try {\n const raw = await readFile(cursorFile(parentSessionId, agentToolUseId), 'utf8');\n return new Set(\n raw\n .split('\\n')\n .map((s) => s.trim())\n .filter((s) => s !== ''),\n );\n } catch {\n return new Set();\n }\n}\n\nfunction cursorFile(parentSessionId: string, agentToolUseId: string): string {\n // Two-level encoding so different parents and different agent invocations\n // keep independent cursors even if their uuids overlap by accident.\n return `${paths.transcriptDir}/subagent-${parentSessionId}-${agentToolUseId}`;\n}\n\nexport async function persistSubagentCursor(\n parentSessionId: string,\n agentToolUseId: string,\n seen: Set<string>,\n newlyEmitted: string[],\n): Promise<void> {\n for (const u of newlyEmitted) seen.add(u);\n const file = cursorFile(parentSessionId, agentToolUseId);\n await mkdir(dirname(file), { recursive: true });\n const arr = [...seen];\n const trimmed = arr.length > CURSOR_KEEP ? arr.slice(arr.length - CURSOR_KEEP) : arr;\n await writeFile(file, trimmed.join('\\n') + '\\n');\n}\n","import { readFile } from 'node:fs/promises';\nimport { readConfig } from '../lib/config.js';\nimport { listBufferedSessions, bufferSize, bufferMtimeMs } from '../lib/buffer.js';\nimport { paths } from '../lib/paths.js';\nimport { pingProject } from '../lib/api.js';\n\nasync function readFlusherPid(): Promise<number | null> {\n try {\n const raw = await readFile(paths.flusherPid, 'utf8');\n const n = Number.parseInt(raw.trim(), 10);\n return Number.isFinite(n) ? n : null;\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === 'ENOENT') return null;\n throw err;\n }\n}\n\nexport async function statusCommand(): Promise<number> {\n const cfg = await readConfig();\n if (!cfg) {\n process.stdout.write('Not logged in. Run `runtape login`.\\n');\n return 0;\n }\n\n process.stdout.write(`Server: ${cfg.server_url}\\n`);\n process.stdout.write(`API key: ${cfg.api_key.slice(0, 8)}…${cfg.api_key.slice(-4)}\\n`);\n\n const ping = await pingProject(cfg.server_url, cfg.api_key);\n process.stdout.write(`Reachable: ${ping.ok ? 'yes' : `no (${ping.detail ?? ping.status})`}\\n`);\n\n const sessions = await listBufferedSessions();\n if (sessions.length === 0) {\n process.stdout.write('Buffer: empty.\\n');\n } else {\n process.stdout.write(`Buffer: ${sessions.length} session(s) pending.\\n`);\n for (const s of sessions) {\n const size = await bufferSize(s);\n const mtime = await bufferMtimeMs(s);\n const ageSec = mtime ? Math.round((Date.now() - mtime) / 1000) : null;\n process.stdout.write(` ${s}: ${size} bytes${ageSec !== null ? `, updated ${ageSec}s ago` : ''}\\n`);\n }\n }\n\n const flusherPid = await readFlusherPid();\n if (flusherPid !== null) {\n process.stdout.write(`Flusher: PID ${flusherPid}\\n`);\n } else {\n process.stdout.write('Flusher: not running.\\n');\n }\n\n return 0;\n}\n","import { spawn } from 'node:child_process';\nimport { platform } from 'node:process';\nimport { readConfig } from '../lib/config.js';\n\nfunction openCommand(): { cmd: string; args: string[] } {\n // Cross-platform \"open this URL in the default browser\".\n // macOS: `open <url>`. Linux: `xdg-open <url>`. Windows: `cmd /c start \"\" <url>`.\n if (platform === 'darwin') return { cmd: 'open', args: [] };\n if (platform === 'win32') return { cmd: 'cmd', args: ['/c', 'start', ''] };\n return { cmd: 'xdg-open', args: [] };\n}\n\nexport async function runsCommand(): Promise<number> {\n const cfg = await readConfig();\n if (!cfg) {\n process.stderr.write('Not logged in. Run `runtape login` first.\\n');\n return 1;\n }\n\n const url = `${cfg.server_url.replace(/\\/$/, '')}/dashboard/runs`;\n const { cmd, args } = openCommand();\n\n const child = spawn(cmd, [...args, url], { stdio: 'ignore', detached: true });\n child.on('error', (err) => {\n process.stderr.write(`Could not launch browser (${err.message}). Open this manually:\\n${url}\\n`);\n });\n child.unref();\n\n process.stdout.write(`Opening ${url}\\n`);\n return 0;\n}\n","import { spawn } from 'node:child_process';\nimport { platform } from 'node:process';\nimport { createInterface } from 'node:readline/promises';\nimport { stdin as input, stdout as output } from 'node:process';\nimport { Config, defaultServerUrl, readConfig, writeConfig } from '../lib/config.js';\nimport { pingProject } from '../lib/api.js';\nimport { installHooks } from '../lib/hooks-installer.js';\nimport { resolveCliBinPath } from '../lib/cli-bin.js';\n\nfunction openCommand(): { cmd: string; args: string[] } {\n if (platform === 'darwin') return { cmd: 'open', args: [] };\n if (platform === 'win32') return { cmd: 'cmd', args: ['/c', 'start', ''] };\n return { cmd: 'xdg-open', args: [] };\n}\n\nfunction openInBrowser(url: string): void {\n const { cmd, args } = openCommand();\n const child = spawn(cmd, [...args, url], { stdio: 'ignore', detached: true });\n child.on('error', () => {\n /* swallow — caller already printed the URL to fall back on */\n });\n child.unref();\n}\n\nasync function promptYesNo(rl: Awaited<ReturnType<typeof createInterface>>, question: string, defaultYes: boolean): Promise<boolean> {\n const suffix = defaultYes ? '(Y/n)' : '(y/N)';\n const answer = (await rl.question(`${question} ${suffix} `)).trim().toLowerCase();\n if (answer === '') return defaultYes;\n return answer === 'y' || answer === 'yes';\n}\n\nexport async function setupCommand(opts: { noBrowser?: boolean }): Promise<number> {\n const rl = createInterface({ input, output });\n\n try {\n process.stdout.write('\\nRuntape setup\\n');\n process.stdout.write('Let\\'s get your Claude Code runs captured.\\n');\n process.stdout.write('(Press Enter at any prompt to accept the default shown in [brackets].)\\n\\n');\n\n // Step 1 — short-circuit if already configured\n const existing = await readConfig();\n if (existing) {\n process.stdout.write(`Already logged in to ${existing.server_url}\\n`);\n process.stdout.write(`API key: ${existing.api_key.slice(0, 8)}…${existing.api_key.slice(-4)}\\n`);\n const reconfigure = await promptYesNo(rl, 'Reconfigure?', false);\n if (!reconfigure) {\n process.stdout.write('\\nKeeping existing credentials. Moving on to hook install.\\n');\n return await installAndFinish(rl, existing.server_url);\n }\n }\n\n // Step 2 — server URL\n const suggestedUrl = defaultServerUrl();\n process.stdout.write(`Step 1/3 — Backend\\n`);\n const urlInput = (await rl.question(`Server URL [${suggestedUrl}] (Enter to use this): `)).trim();\n const serverUrl = urlInput === '' ? suggestedUrl : urlInput;\n\n // Step 3 — open dashboard for the user to grab their key\n const dashboardUrl = `${serverUrl.replace(/\\/$/, '')}/dashboard`;\n process.stdout.write(`\\nStep 2/3 — API key\\n`);\n process.stdout.write(`Your API key lives in the dashboard:\\n ${dashboardUrl}\\n`);\n if (!opts.noBrowser) {\n openInBrowser(dashboardUrl);\n process.stdout.write('(opened in your browser)\\n');\n }\n\n // Step 4 — paste + validate\n const apiKey = (await rl.question('\\nPaste your API key (rtk_…): ')).trim();\n const validation = Config.shape.api_key.safeParse(apiKey);\n if (!validation.success) {\n process.stderr.write(`\\nInvalid API key format. Expected rtk_<64 hex chars>.\\n`);\n return 2;\n }\n\n process.stdout.write(`Validating against ${serverUrl}…\\n`);\n const ping = await pingProject(serverUrl, apiKey);\n if (!ping.ok) {\n process.stderr.write(\n `\\nLogin failed: ${ping.status === 401 ? 'unknown API key' : ping.detail ?? 'server unreachable'}\\n`,\n );\n return 1;\n }\n\n await writeConfig({ api_key: apiKey, server_url: serverUrl });\n process.stdout.write('Credentials saved.\\n');\n\n // Step 5 — install hooks\n return await installAndFinish(rl, serverUrl);\n } finally {\n rl.close();\n }\n}\n\nasync function installAndFinish(\n rl: Awaited<ReturnType<typeof createInterface>>,\n serverUrl: string,\n): Promise<number> {\n process.stdout.write(`\\nStep 3/3 — Claude Code hooks\\n`);\n const install = await promptYesNo(\n rl,\n 'Install Runtape hooks into ~/.claude/settings.json now?',\n true,\n );\n\n if (!install) {\n process.stdout.write('\\nSkipped hook install. Run `runtape install` when ready.\\n');\n return 0;\n }\n\n const cliBinPath = resolveCliBinPath();\n const result = await installHooks('user', cliBinPath);\n process.stdout.write(`Updated ${result.settingsPath}\\n`);\n if (result.addedHooks.length === 0) {\n process.stdout.write('Hooks already installed — nothing changed.\\n');\n } else {\n process.stdout.write(`Added: ${result.addedHooks.join(', ')}\\n`);\n }\n\n process.stdout.write('\\nSetup complete.\\n');\n process.stdout.write('Now run `claude -p \"any prompt\"` from any directory and watch the run land at:\\n');\n process.stdout.write(` ${serverUrl.replace(/\\/$/, '')}/dashboard\\n\\n`);\n return 0;\n}\n","import { appendFile, mkdir, readFile, unlink, writeFile } from 'node:fs/promises';\nimport { dirname } from 'node:path';\nimport { readConfig } from './config.js';\nimport { listBufferedSessions, readBufferedSession, rewriteBufferedSession } from './buffer.js';\nimport { postEvents } from './api.js';\nimport { paths } from './paths.js';\n\nconst POLL_INTERVAL_MS = 1500;\nconst IDLE_EXIT_MS = 30_000;\nconst BATCH_MAX = 100;\nconst BACKOFF_STEPS_MS = [1000, 2000, 4000, 8000, 16_000, 32_000, 60_000];\n\nasync function log(line: string): Promise<void> {\n try {\n await mkdir(dirname(paths.flusherLog), { recursive: true });\n await appendFile(paths.flusherLog, `${new Date().toISOString()} ${line}\\n`);\n } catch {\n /* never throw out of logging */\n }\n}\n\nasync function isProcessAlive(pid: number): Promise<boolean> {\n try {\n process.kill(pid, 0); // Signal 0 = existence check, doesn't actually signal.\n return true;\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === 'ESRCH') return false;\n if ((err as NodeJS.ErrnoException).code === 'EPERM') return true; // Exists, owned by someone else.\n return false;\n }\n}\n\n// Acquire-or-detect-running. Returns true if we became the flusher; false if one is already running.\nexport async function acquirePidLock(): Promise<boolean> {\n await mkdir(dirname(paths.flusherPid), { recursive: true });\n try {\n const existing = await readFile(paths.flusherPid, 'utf8');\n const pid = Number.parseInt(existing.trim(), 10);\n if (Number.isFinite(pid) && (await isProcessAlive(pid))) {\n return false; // Another flusher is alive.\n }\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code !== 'ENOENT') throw err;\n }\n await writeFile(paths.flusherPid, String(process.pid));\n return true;\n}\n\nasync function releasePidLock(): Promise<void> {\n try {\n await unlink(paths.flusherPid);\n } catch {\n /* ignore */\n }\n}\n\nfunction delay(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\n// Drain a single session's buffer in batches of up to BATCH_MAX. Returns true if any\n// events were successfully flushed.\nasync function drainSession(sessionId: string, serverUrl: string, apiKey: string): Promise<boolean> {\n const snapshot = await readBufferedSession(sessionId);\n if (!snapshot || snapshot.events.length === 0) {\n await rewriteBufferedSession(sessionId, []);\n return false;\n }\n\n let cursor = 0;\n let anyFlushed = false;\n while (cursor < snapshot.events.length) {\n const slice = snapshot.events.slice(cursor, cursor + BATCH_MAX);\n const result = await postEvents(serverUrl, apiKey, slice);\n\n if (result.ok) {\n cursor += slice.length;\n anyFlushed = true;\n continue;\n }\n\n if (!result.retryable) {\n // Poison batch — log + drop the slice to prevent stuck buffer. 4xx is on us (or stale CLI vs server).\n await log(`drop_poison session=${sessionId} status=${result.status} error=${result.error.slice(0, 200)}`);\n cursor += slice.length;\n anyFlushed = true; // We've made forward progress (toward emptying the buffer), so don't backoff.\n continue;\n }\n\n // Retryable — stop draining this session, leave the rest for next poll cycle.\n await log(`retryable session=${sessionId} status=${result.status} cursor=${cursor} error=${result.error.slice(0, 200)}`);\n break;\n }\n\n const remaining = snapshot.raw.slice(cursor);\n await rewriteBufferedSession(sessionId, remaining);\n return anyFlushed;\n}\n\nexport async function runFlusher(): Promise<void> {\n const acquired = await acquirePidLock();\n if (!acquired) {\n await log('exit_already_running');\n return;\n }\n\n await log(`start pid=${process.pid}`);\n\n let lastActivityMs = Date.now();\n let backoffIdx = 0;\n\n try {\n while (true) {\n const cfg = await readConfig();\n if (!cfg) {\n // No config yet — we shouldn't have been spawned. Exit cleanly.\n await log('exit_no_config');\n return;\n }\n\n const sessions = await listBufferedSessions();\n let flushedThisCycle = false;\n for (const sessionId of sessions) {\n const flushed = await drainSession(sessionId, cfg.server_url, cfg.api_key);\n flushedThisCycle = flushedThisCycle || flushed;\n }\n\n if (flushedThisCycle) {\n lastActivityMs = Date.now();\n backoffIdx = 0;\n }\n\n // Idle exit.\n const remaining = await listBufferedSessions();\n const idleMs = Date.now() - lastActivityMs;\n if (remaining.length === 0 && idleMs >= IDLE_EXIT_MS) {\n await log(`exit_idle idle_ms=${idleMs}`);\n return;\n }\n\n // Backoff when buffer is non-empty but we couldn't drain anything (server down).\n // Reset backoff when we made progress.\n const wait =\n remaining.length > 0 && !flushedThisCycle\n ? BACKOFF_STEPS_MS[Math.min(backoffIdx++, BACKOFF_STEPS_MS.length - 1)]\n : POLL_INTERVAL_MS;\n await delay(wait);\n }\n } catch (err) {\n await log(`crash error=${err instanceof Error ? err.message : String(err)}`);\n throw err;\n } finally {\n await releasePidLock();\n }\n}\n"],"mappings":"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","names":["fileURLToPath","dirname","join","createInterface","input","output","mkdir","readFile","writeFile","dirname","readFile","mkdir","dirname","writeFile","dirname","createInterface","input","output","mkdir","readFile","writeFile","dirname","mkdir","dirname","readFile","writeFile","mkdir","readFile","writeFile","unlink","mkdir","readFile","unlink","writeFile","mkdir","readFile","writeFile","dirname","readFile","mkdir","dirname","writeFile","mkdir","readFile","writeFile","dirname","asInt","readCursor","readFile","CURSOR_KEEP","mkdir","dirname","writeFile","readFile","readFile","spawn","spawn","spawn","platform","createInterface","input","output","openCommand","platform","spawn","createInterface","input","output","appendFile","mkdir","readFile","unlink","writeFile","dirname","mkdir","dirname","appendFile","readFile","writeFile","unlink","resolve","join","dirname","fileURLToPath"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/commands/login.ts","../src/lib/config.ts","../src/lib/paths.ts","../src/lib/api.ts","../src/commands/logout.ts","../src/commands/install.ts","../src/lib/hooks-installer.ts","../src/lib/hook-mapping.ts","../src/lib/cli-bin.ts","../src/commands/uninstall.ts","../src/commands/push.ts","../src/lib/sequence.ts","../src/lib/buffer.ts","../src/lib/transcript.ts","../src/lib/subagent-transcript.ts","../src/lib/watch.ts","../src/commands/status.ts","../src/commands/runs.ts","../src/commands/setup.ts","../src/commands/watch.ts","../src/lib/flusher.ts"],"sourcesContent":["import { readFileSync } from 'node:fs';\nimport { fileURLToPath } from 'node:url';\nimport { dirname, join } from 'node:path';\nimport { Command } from 'commander';\nimport { loginCommand } from './commands/login.js';\nimport { logoutCommand } from './commands/logout.js';\nimport { installCommand } from './commands/install.js';\nimport { uninstallCommand } from './commands/uninstall.js';\nimport { pushCommand } from './commands/push.js';\nimport { statusCommand } from './commands/status.js';\nimport { runsCommand } from './commands/runs.js';\nimport { setupCommand } from './commands/setup.js';\nimport {\n watchListCommand,\n watchIgnoreCommand,\n watchOnlyCommand,\n watchUnignoreCommand,\n watchResetCommand,\n} from './commands/watch.js';\nimport { runFlusher } from './lib/flusher.js';\n\n// Read package.json at runtime so --version can never desync from the publish.\nconst pkgPath = join(dirname(fileURLToPath(import.meta.url)), '..', 'package.json');\nconst PKG_VERSION = (JSON.parse(readFileSync(pkgPath, 'utf8')) as { version: string }).version;\n\n// Internal flag for the detached flusher daemon — not a user-facing subcommand.\n// Goes before commander.parse so we can short-circuit before commander sees argv.\nif (process.argv.includes('--internal-flusher')) {\n void runFlusher().then(\n () => process.exit(0),\n (err: unknown) => {\n console.error(err);\n process.exit(1);\n },\n );\n} else {\n const program = new Command();\n\n program\n .name('runtape')\n .description('Flight recorder for AI coding agents.')\n .version(PKG_VERSION);\n\n program\n .command('setup')\n .description('Guided onboarding: login + install hooks + verify in one flow.')\n .option('--no-browser', 'Do not open the dashboard URL in a browser')\n .action(async (opts) => process.exit(await setupCommand(opts)));\n\n program\n .command('login')\n .description('Paste your API key from runtape.dev/dashboard and save it locally.')\n .option('-k, --key <key>', 'API key (skip the prompt)')\n .option('-s, --server-url <url>', 'Override server URL')\n .action(async (opts) => process.exit(await loginCommand(opts)));\n\n program\n .command('logout')\n .description('Remove saved credentials.')\n .action(async () => process.exit(await logoutCommand()));\n\n program\n .command('install')\n .description('Add Runtape hooks to ~/.claude/settings.json (or project-local with --project).')\n .option('--project', 'Install into ./.claude/settings.json instead of user-level')\n .option('-y, --yes', 'Skip the confirmation prompt')\n .action(async (opts) => process.exit(await installCommand(opts)));\n\n program\n .command('uninstall')\n .description('Remove Runtape hooks from Claude settings.')\n .option('--project', 'Operate on ./.claude/settings.json instead of user-level')\n .action(async (opts) => process.exit(await uninstallCommand(opts)));\n\n program\n .command('push')\n .description('Internal: invoked by Claude Code hooks. Reads stdin and buffers an event.')\n .requiredOption('--event <name>', 'Claude hook event name (SessionStart, PostToolUse, …)')\n .action(async (opts) => process.exit(await pushCommand(opts)));\n\n program\n .command('status')\n .description('Show current login, buffer state, and server reachability.')\n .action(async () => process.exit(await statusCommand()));\n\n program\n .command('runs')\n .description('Open your Runtape dashboard in the default browser.')\n .action(async () => process.exit(await runsCommand()));\n\n const watch = program\n .command('watch')\n .description('Control which directories the hooks capture (allow / deny lists).');\n watch\n .command('list')\n .description('Show the current watch mode and paths.')\n .action(async () => process.exit(await watchListCommand()));\n watch\n .command('ignore <path>')\n .description('Stop capturing sessions whose cwd is under <path>. Switches mode to deny_list.')\n .action(async (path: string) => process.exit(await watchIgnoreCommand(path)));\n watch\n .command('only <path>')\n .description('Capture ONLY sessions whose cwd is under <path>. Switches mode to allow_list.')\n .action(async (path: string) => process.exit(await watchOnlyCommand(path)));\n watch\n .command('unignore <path>')\n .description('Remove <path> from the current watch list.')\n .action(async (path: string) => process.exit(await watchUnignoreCommand(path)));\n watch\n .command('reset')\n .description('Capture every session (clear all watch settings).')\n .action(async () => process.exit(await watchResetCommand()));\n\n program.parseAsync(process.argv).catch((err) => {\n console.error(err);\n process.exit(1);\n });\n}\n","import { createInterface } from 'node:readline/promises';\nimport { stdin as input, stdout as output } from 'node:process';\nimport { Config, defaultServerUrl, writeConfig } from '../lib/config.js';\nimport { pingProject } from '../lib/api.js';\n\nexport async function loginCommand(opts: { key?: string; serverUrl?: string }): Promise<number> {\n const serverUrl = opts.serverUrl ?? defaultServerUrl();\n\n let apiKey = opts.key;\n if (!apiKey) {\n const rl = createInterface({ input, output });\n apiKey = (await rl.question('Paste your Runtape API key (rtk_…): ')).trim();\n rl.close();\n }\n\n const validation = Config.shape.api_key.safeParse(apiKey);\n if (!validation.success) {\n process.stderr.write(`Invalid API key format. Expected rtk_<64 hex chars>.\\n`);\n return 2;\n }\n\n process.stdout.write(`Validating against ${serverUrl}…\\n`);\n const ping = await pingProject(serverUrl, apiKey);\n if (!ping.ok) {\n process.stderr.write(`Login failed: ${ping.status === 401 ? 'unknown API key' : ping.detail ?? 'server unreachable'}\\n`);\n return 1;\n }\n\n await writeConfig({ api_key: apiKey, server_url: serverUrl });\n process.stdout.write(`Saved. You can now run: runtape install\\n`);\n return 0;\n}\n","import { chmod, mkdir, readFile, writeFile, unlink } from 'node:fs/promises';\nimport { dirname } from 'node:path';\nimport { z } from 'zod';\nimport { paths } from './paths.js';\n\n// Path watcher: controls which directories get captured by the CLI hooks.\n// allow_all — capture every session (default; equivalent to no `watch` key).\n// deny_list — capture every session EXCEPT cwds matching `paths`.\n// allow_list — capture ONLY cwds matching `paths`.\n// Matching is prefix-based on absolute, normalized paths.\nexport const WatchMode = z.enum(['allow_all', 'deny_list', 'allow_list']);\nexport type WatchMode = z.infer<typeof WatchMode>;\n\nexport const WatchConfig = z.object({\n mode: WatchMode.default('allow_all'),\n paths: z.array(z.string()).default([]),\n});\nexport type WatchConfig = z.infer<typeof WatchConfig>;\n\nexport const Config = z.object({\n api_key: z.string().regex(/^rtk_[a-f0-9]{64}$/, 'api_key must be rtk_ followed by 64 hex chars'),\n server_url: z.string().url(),\n // Optional so any existing 0.5.x config keeps parsing — push.ts treats\n // missing/undefined as allow_all.\n watch: WatchConfig.optional(),\n});\n\nexport type Config = z.infer<typeof Config>;\n\nconst DEFAULT_SERVER_URL = process.env.RUNTAPE_API_URL ?? 'https://runtape.dev';\n\nexport async function readConfig(): Promise<Config | null> {\n let raw: string;\n try {\n raw = await readFile(paths.config, 'utf8');\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === 'ENOENT') return null;\n throw err;\n }\n const parsed = Config.safeParse(JSON.parse(raw));\n if (!parsed.success) {\n throw new Error(`Invalid config at ${paths.config}: ${parsed.error.message}`);\n }\n return parsed.data;\n}\n\nexport async function writeConfig(c: Config): Promise<void> {\n await mkdir(dirname(paths.config), { recursive: true });\n await writeFile(paths.config, JSON.stringify(c, null, 2) + '\\n', { mode: 0o600 });\n // writeFile's `mode` is only applied on create. Re-chmod explicitly so a re-login\n // tightens permissions if the file was previously loosened (e.g. `chmod 644`).\n await chmod(paths.config, 0o600);\n}\n\nexport async function clearConfig(): Promise<void> {\n try {\n await unlink(paths.config);\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === 'ENOENT') return;\n throw err;\n }\n}\n\nexport function defaultServerUrl(): string {\n return DEFAULT_SERVER_URL;\n}\n","import { homedir } from 'node:os';\nimport { join } from 'node:path';\n\nconst RUNTAPE_HOME = process.env.RUNTAPE_HOME ?? join(homedir(), '.runtape');\n\nexport const paths = {\n home: RUNTAPE_HOME,\n config: join(RUNTAPE_HOME, 'config.json'),\n bufferDir: join(RUNTAPE_HOME, 'buffer'),\n seqDir: join(RUNTAPE_HOME, 'seq'),\n flusherPid: join(RUNTAPE_HOME, 'flusher.pid'),\n flusherLog: join(RUNTAPE_HOME, 'flusher.log'),\n bufferFile: (sessionId: string) => join(RUNTAPE_HOME, 'buffer', `${sessionId}.ndjson`),\n seqFile: (sessionId: string) => join(RUNTAPE_HOME, 'seq', sessionId),\n // Per-session marker recording the last assistant message uuid we've\n // emitted from the transcript. Lets transcript scans be idempotent across\n // hook invocations without re-reading + re-emitting everything.\n transcriptCursorFile: (sessionId: string) => join(RUNTAPE_HOME, 'transcript', sessionId),\n transcriptDir: join(RUNTAPE_HOME, 'transcript'),\n claudeSettings: (scope: 'user' | 'project') =>\n scope === 'user' ? join(homedir(), '.claude', 'settings.json') : join(process.cwd(), '.claude', 'settings.json'),\n claudeSettingsBackup: (scope: 'user' | 'project') =>\n scope === 'user'\n ? join(homedir(), '.claude', 'settings.json.runtape-backup')\n : join(process.cwd(), '.claude', 'settings.json.runtape-backup'),\n};\n","import type { RuntapeEvent } from '../types.js';\n\nexport type PostResult =\n | { ok: true; accepted: number; errors: Array<{ index: number; reason: string }> }\n | { ok: false; status: number; error: string; retryable: boolean };\n\nfunction isRetryableStatus(status: number): boolean {\n // 408 timeout, 425 too-early, 429 rate-limited, 5xx — retry. 4xx — drop (poison).\n return status === 408 || status === 425 || status === 429 || status >= 500;\n}\n\nexport async function postEvents(\n serverUrl: string,\n apiKey: string,\n events: RuntapeEvent[],\n): Promise<PostResult> {\n let response: Response;\n try {\n response = await fetch(`${serverUrl.replace(/\\/$/, '')}/api/v1/events`, {\n method: 'POST',\n headers: {\n 'content-type': 'application/json',\n authorization: `Bearer ${apiKey}`,\n },\n body: JSON.stringify({ events }),\n });\n } catch (err) {\n // Network failure (ENOTFOUND, ECONNREFUSED, fetch abort). Retryable.\n return {\n ok: false,\n status: 0,\n error: err instanceof Error ? err.message : String(err),\n retryable: true,\n };\n }\n\n if (response.ok) {\n const body = (await response.json()) as {\n accepted: number;\n errors: Array<{ index: number; reason: string }>;\n };\n return { ok: true, accepted: body.accepted, errors: body.errors };\n }\n\n let detail = '';\n try {\n detail = await response.text();\n } catch {\n /* ignore */\n }\n return {\n ok: false,\n status: response.status,\n error: detail || response.statusText,\n retryable: isRetryableStatus(response.status),\n };\n}\n\nexport async function pingProject(serverUrl: string, apiKey: string): Promise<{ ok: boolean; status: number; detail?: string }> {\n // We don't have a dedicated /me endpoint yet (we may add one in Task 3b).\n // For now, \"ping\" = POST /api/v1/events with an empty events array and inspect the response.\n // Server returns 400 invalid_request_body (events must be ≥1) on success — that proves auth works.\n // 401 = bad key; 5xx = server problem.\n let response: Response;\n try {\n response = await fetch(`${serverUrl.replace(/\\/$/, '')}/api/v1/events`, {\n method: 'POST',\n headers: {\n 'content-type': 'application/json',\n authorization: `Bearer ${apiKey}`,\n },\n body: JSON.stringify({ events: [] }),\n });\n } catch (err) {\n return { ok: false, status: 0, detail: err instanceof Error ? err.message : String(err) };\n }\n\n if (response.status === 400) return { ok: true, status: 400 };\n if (response.status === 401) return { ok: false, status: 401, detail: 'invalid api key' };\n return { ok: false, status: response.status, detail: response.statusText };\n}\n","import { clearConfig } from '../lib/config.js';\n\nexport async function logoutCommand(): Promise<number> {\n await clearConfig();\n process.stdout.write('Logged out. Config removed.\\n');\n return 0;\n}\n","import { createInterface } from 'node:readline/promises';\nimport { stdin as input, stdout as output } from 'node:process';\nimport { readConfig } from '../lib/config.js';\nimport { installHooks } from '../lib/hooks-installer.js';\nimport { resolveCliBinPath } from '../lib/cli-bin.js';\n\nexport async function installCommand(opts: { project?: boolean; yes?: boolean }): Promise<number> {\n const cfg = await readConfig();\n if (!cfg) {\n process.stderr.write('Not logged in. Run `runtape login` first.\\n');\n return 1;\n }\n\n const scope: 'user' | 'project' = opts.project ? 'project' : 'user';\n const cliBinPath = resolveCliBinPath();\n\n if (!opts.yes) {\n const rl = createInterface({ input, output });\n const answer = (await rl.question(`Install Runtape hooks into ${scope} settings (yes/no)? `)).trim().toLowerCase();\n rl.close();\n if (answer !== 'y' && answer !== 'yes') {\n process.stdout.write('Aborted.\\n');\n return 0;\n }\n }\n\n const result = await installHooks(scope, cliBinPath);\n process.stdout.write(`Updated ${result.settingsPath}\\n`);\n process.stdout.write(`Backup: ${result.backupPath}\\n`);\n if (result.addedHooks.length === 0) {\n process.stdout.write('Hooks already installed — nothing changed.\\n');\n } else {\n process.stdout.write(`Added: ${result.addedHooks.join(', ')}\\n`);\n }\n return 0;\n}\n","import { copyFile, mkdir, readFile, writeFile } from 'node:fs/promises';\nimport { dirname } from 'node:path';\nimport { paths } from './paths.js';\nimport { SUPPORTED_HOOKS } from './hook-mapping.js';\n\nconst RUNTAPE_MARKER = 'runtape:managed';\n\ntype HookEntry = { type: 'command'; command: string; [k: string]: unknown };\ntype HookMatcher = { matcher: string; hooks: HookEntry[]; [k: string]: unknown };\ntype HooksBlock = Record<string, HookMatcher[]>;\ntype ClaudeSettings = { hooks?: HooksBlock; [k: string]: unknown };\n\nfunction runtapeEntry(hookName: string, cliBinPath: string): HookEntry {\n return {\n type: 'command',\n command: `${cliBinPath} push --event ${hookName}`,\n [RUNTAPE_MARKER]: true,\n };\n}\n\nasync function readSettings(file: string): Promise<ClaudeSettings> {\n try {\n const raw = await readFile(file, 'utf8');\n return JSON.parse(raw) as ClaudeSettings;\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === 'ENOENT') return {};\n throw err;\n }\n}\n\nasync function writeSettings(file: string, data: ClaudeSettings): Promise<void> {\n await mkdir(dirname(file), { recursive: true });\n await writeFile(file, JSON.stringify(data, null, 2) + '\\n');\n}\n\nexport type InstallResult = {\n settingsPath: string;\n backupPath: string;\n addedHooks: string[];\n};\n\nexport async function installHooks(scope: 'user' | 'project', cliBinPath: string): Promise<InstallResult> {\n const settingsPath = paths.claudeSettings(scope);\n const backupPath = paths.claudeSettingsBackup(scope);\n\n // Backup (no-op if settings doesn't exist yet — we still create the dir).\n try {\n await copyFile(settingsPath, backupPath);\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code !== 'ENOENT') throw err;\n }\n\n const settings = await readSettings(settingsPath);\n settings.hooks = settings.hooks ?? {};\n\n const added: string[] = [];\n for (const hookName of SUPPORTED_HOOKS) {\n const matchers = (settings.hooks[hookName] = settings.hooks[hookName] ?? []);\n // Find or create a matcher: \"*\". Append our entry there.\n let star = matchers.find((m) => m.matcher === '*');\n if (!star) {\n star = { matcher: '*', hooks: [] };\n matchers.push(star);\n }\n star.hooks = star.hooks ?? [];\n const already = star.hooks.some((h) => (h as HookEntry)[RUNTAPE_MARKER] === true);\n if (!already) {\n star.hooks.push(runtapeEntry(hookName, cliBinPath));\n added.push(hookName);\n }\n }\n\n await writeSettings(settingsPath, settings);\n return { settingsPath, backupPath, addedHooks: added };\n}\n\nexport type UninstallResult = {\n settingsPath: string;\n removedHooks: string[];\n};\n\nexport async function uninstallHooks(scope: 'user' | 'project'): Promise<UninstallResult> {\n const settingsPath = paths.claudeSettings(scope);\n const settings = await readSettings(settingsPath);\n const removed: string[] = [];\n\n if (settings.hooks) {\n for (const hookName of Object.keys(settings.hooks)) {\n const matchers = settings.hooks[hookName];\n for (const matcher of matchers) {\n if (!Array.isArray(matcher.hooks)) continue;\n const before = matcher.hooks.length;\n matcher.hooks = matcher.hooks.filter((h) => (h as HookEntry)[RUNTAPE_MARKER] !== true);\n if (matcher.hooks.length < before) removed.push(hookName);\n }\n // Clean up matchers that are now empty.\n settings.hooks[hookName] = matchers.filter((m) => Array.isArray(m.hooks) && m.hooks.length > 0);\n if (settings.hooks[hookName].length === 0) delete settings.hooks[hookName];\n }\n if (Object.keys(settings.hooks).length === 0) delete settings.hooks;\n }\n\n await writeSettings(settingsPath, settings);\n return { settingsPath, removedHooks: Array.from(new Set(removed)) };\n}\n","import { z } from 'zod';\nimport { RuntapeEvent } from '../types.js';\n\n// The seven Claude Code hook names we register, plus a sentinel \"drop\" for unknown events.\n// Validated 2026-05-14 against Claude Code 2.1.128 — see spike findings spec.\nexport type ClaudeHookName =\n | 'SessionStart'\n | 'UserPromptSubmit'\n | 'PreToolUse'\n | 'PostToolUse'\n | 'Stop'\n | 'SubagentStop'\n | 'SessionEnd'\n | 'Notification';\n\nexport const SUPPORTED_HOOKS: ClaudeHookName[] = [\n 'SessionStart',\n 'UserPromptSubmit',\n 'PreToolUse',\n 'PostToolUse',\n 'Stop',\n 'SubagentStop',\n 'SessionEnd',\n];\n\nexport type MappedEvent = z.infer<typeof RuntapeEvent>;\n\nexport type MapResult =\n | { kind: 'event'; event: MappedEvent }\n | { kind: 'drop'; reason: string };\n\n// PostToolUse tool_response shapes vary by tool. We look at the canonical\n// signals each tool emits and collapse them into a uniform (is_error, message)\n// pair so the server doesn't need per-tool knowledge.\n// - Anthropic-tagged: { is_error: true, content: [{text}] } (the official\n// content-block error form used by some Claude Code tools).\n// - Bash: { interrupted, stdout, stderr, output, ... }. Non-zero exits also\n// surface in stderr and an explicit `exitCode` when available.\n// - Edit/Write/MultiEdit: success returns a structured payload; errors\n// return `{ error: '...' }`.\nfunction inspectToolResponse(tool_response: unknown): { is_error: boolean; error_message?: string } {\n if (!tool_response || typeof tool_response !== 'object') return { is_error: false };\n const r = tool_response as Record<string, unknown>;\n if (r.is_error === true) {\n const content = r.content;\n if (Array.isArray(content)) {\n for (const block of content) {\n if (block && typeof block === 'object' && 'text' in block) {\n const t = (block as { text?: unknown }).text;\n if (typeof t === 'string') return { is_error: true, error_message: t };\n }\n }\n }\n if (typeof r.message === 'string') return { is_error: true, error_message: r.message };\n return { is_error: true };\n }\n if (typeof r.error === 'string' && r.error.trim() !== '') {\n return { is_error: true, error_message: r.error };\n }\n if (r.interrupted === true) {\n return { is_error: true, error_message: 'Interrupted' };\n }\n return { is_error: false };\n}\n\n// Maps a Claude hook payload + the hook name we were invoked with into a RuntapeEvent.\n// Returns { kind: 'drop' } for Notification or unknown events (we just exit cleanly).\nexport function mapHookPayload(\n hookName: string,\n payload: Record<string, unknown>,\n augment: { wall_ts: string; sequence: number },\n): MapResult {\n // Shared envelope every Claude hook carries.\n const base = {\n session_id: payload.session_id,\n transcript_path: payload.transcript_path,\n cwd: payload.cwd,\n hook_event_name: payload.hook_event_name ?? hookName,\n permission_mode: payload.permission_mode,\n wall_ts: augment.wall_ts,\n sequence: augment.sequence,\n };\n\n let candidate: Record<string, unknown>;\n switch (hookName) {\n case 'SessionStart':\n candidate = { ...base, type: 'session_start', source: payload.source ?? 'startup' };\n break;\n case 'UserPromptSubmit':\n candidate = { ...base, type: 'user_prompt', prompt: payload.prompt };\n break;\n case 'PreToolUse':\n candidate = {\n ...base,\n type: 'tool_attempt',\n tool_name: payload.tool_name,\n tool_input: payload.tool_input,\n tool_use_id: payload.tool_use_id,\n };\n break;\n case 'PostToolUse': {\n const err = inspectToolResponse(payload.tool_response);\n candidate = {\n ...base,\n type: 'tool_call',\n tool_name: payload.tool_name,\n tool_input: payload.tool_input,\n tool_response: payload.tool_response,\n tool_use_id: payload.tool_use_id,\n duration_ms: payload.duration_ms,\n is_error: err.is_error,\n error_message: err.error_message,\n };\n break;\n }\n case 'Stop':\n // Despite the event type literal, this is \"turn end\" — Stop fires every\n // time the assistant yields back to the user. Server treats it as\n // 'run is idle'. Real session close uses SessionEnd → 'session_close'.\n candidate = {\n ...base,\n type: 'session_end',\n last_assistant_message: payload.last_assistant_message,\n stop_hook_active: payload.stop_hook_active,\n };\n break;\n case 'SessionEnd':\n candidate = {\n ...base,\n type: 'session_close',\n reason: payload.reason,\n };\n break;\n case 'SubagentStop':\n candidate = {\n ...base,\n type: 'subagent_end',\n agent_id: payload.agent_id,\n agent_type: payload.agent_type,\n agent_transcript_path: payload.agent_transcript_path,\n last_assistant_message: payload.last_assistant_message,\n stop_hook_active: payload.stop_hook_active,\n };\n break;\n default:\n return { kind: 'drop', reason: `unsupported hook: ${hookName}` };\n }\n\n const parsed = RuntapeEvent.safeParse(candidate);\n if (!parsed.success) {\n return { kind: 'drop', reason: `validation failed: ${parsed.error.issues.map((i) => i.path.join('.') + ': ' + i.message).join('; ')}` };\n }\n return { kind: 'event', event: parsed.data };\n}\n","import { fileURLToPath } from 'node:url';\nimport { dirname, resolve, sep } from 'node:path';\n\n// Returns an absolute path to the `runtape` binary the user just invoked.\n// This is what we write into `~/.claude/settings.json` so the hooks call the same install.\n// Falls back to \"runtape\" (on PATH) if we can't resolve it — useful when users want a\n// non-pinned reference and have the CLI installed globally.\nexport function resolveCliBinPath(): string {\n if (process.env.RUNTAPE_CLI_BIN) return process.env.RUNTAPE_CLI_BIN;\n\n const argv1 = process.argv[1];\n if (argv1) {\n // If we live under a node_modules tree, the absolute path embeds the\n // package's extraction location, which changes on `npm install -g <newer>`.\n // Writing that path into ~/.claude/settings.json would break the hook on\n // the next upgrade. Fall back to the bare command name — `runtape` is on\n // PATH after `npm install -g`, and a fresh install re-points the symlink.\n if (argv1.includes(`${sep}node_modules${sep}`)) return 'runtape';\n try {\n return resolve(argv1);\n } catch {\n /* fall through */\n }\n }\n // Last resort: assume \"runtape\" is on PATH.\n return 'runtape';\n}\n\n// Exported for tests — turns a relative path into something we can stick in JSON.\nexport function moduleFileFromImportMeta(metaUrl: string): string {\n return fileURLToPath(metaUrl);\n}\n\n// Suppress unused-import warning for `dirname`.\nvoid dirname;\n","import { uninstallHooks } from '../lib/hooks-installer.js';\n\nexport async function uninstallCommand(opts: { project?: boolean }): Promise<number> {\n const scope: 'user' | 'project' = opts.project ? 'project' : 'user';\n const result = await uninstallHooks(scope);\n if (result.removedHooks.length === 0) {\n process.stdout.write(`No Runtape hooks found in ${result.settingsPath}.\\n`);\n } else {\n process.stdout.write(`Removed Runtape entries from: ${result.removedHooks.join(', ')}\\n`);\n }\n return 0;\n}\n","import { spawn } from 'node:child_process';\nimport { mapHookPayload } from '../lib/hook-mapping.js';\nimport { nextSequence } from '../lib/sequence.js';\nimport { appendEvent } from '../lib/buffer.js';\nimport { readConfig } from '../lib/config.js';\nimport { resolveCliBinPath } from '../lib/cli-bin.js';\nimport { readNewAssistantTurns, persistCursor } from '../lib/transcript.js';\nimport { readNewSubagentEvents, persistSubagentCursor } from '../lib/subagent-transcript.js';\nimport { isCaptureAllowed } from '../lib/watch.js';\nimport type { RuntapeEvent } from '../types.js';\n\nfunction isDisabledByEnv(): boolean {\n // Surgical opt-out for individual sessions:\n // `RUNTAPE_DISABLE=1 claude` skips capture entirely.\n // Accept `1`, `true`, `yes` (case-insensitive) so any reasonable truthy\n // value works. Empty / \"0\" / \"false\" → not disabled.\n const v = (process.env.RUNTAPE_DISABLE ?? '').trim().toLowerCase();\n return v === '1' || v === 'true' || v === 'yes';\n}\n\nasync function readStdin(): Promise<string> {\n if (process.stdin.isTTY) return '';\n const chunks: Buffer[] = [];\n for await (const chunk of process.stdin) {\n chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));\n }\n return Buffer.concat(chunks).toString('utf8');\n}\n\nfunction spawnFlusher(cliBinPath: string): void {\n // Detached so it survives this process exit. stdio:'ignore' so the daemon\n // doesn't inherit the hook's stdin/stdout (Claude Code reads hook stdout!).\n const child = spawn(cliBinPath, ['--internal-flusher'], {\n detached: true,\n stdio: 'ignore',\n env: process.env,\n });\n child.unref();\n}\n\nexport async function pushCommand(opts: { event: string }): Promise<number> {\n // The contract is: never block the hook. If we can't parse/auth/whatever, exit 0 quietly\n // (printing to stderr is fine; printing to stdout could be parsed by Claude Code).\n try {\n // Earliest opt-out: env var fully bypasses the CLI. Cheap, no I/O.\n if (isDisabledByEnv()) return 0;\n\n const cfg = await readConfig();\n if (!cfg) {\n process.stderr.write('runtape: not logged in — skipping event\\n');\n return 0;\n }\n\n const raw = await readStdin();\n if (!raw.trim()) {\n // SessionStart in some Claude Code versions may invoke hooks with no stdin; ignore.\n return 0;\n }\n\n let payload: Record<string, unknown>;\n try {\n payload = JSON.parse(raw) as Record<string, unknown>;\n } catch (err) {\n process.stderr.write(`runtape: invalid JSON on stdin: ${err instanceof Error ? err.message : String(err)}\\n`);\n return 0;\n }\n\n const sessionId = typeof payload.session_id === 'string' ? payload.session_id : null;\n if (!sessionId) {\n process.stderr.write('runtape: missing session_id on hook payload\\n');\n return 0;\n }\n\n // Watch list gate: if the user has configured allow_list / deny_list and\n // this cwd doesn't pass, silently no-op the hook. Nothing hits the buffer,\n // nothing flushes — the server never sees a byte from this session.\n const cwd = typeof payload.cwd === 'string' ? payload.cwd : '';\n if (cwd && !isCaptureAllowed(cfg.watch, cwd)) {\n return 0;\n }\n\n const sequence = await nextSequence(sessionId);\n const result = mapHookPayload(opts.event, payload, {\n wall_ts: new Date().toISOString(),\n sequence,\n });\n\n if (result.kind === 'drop') {\n // Notification, unknown hook, or validation failure. Quiet log + exit clean.\n process.stderr.write(`runtape: dropped ${opts.event}: ${result.reason}\\n`);\n return 0;\n }\n\n await appendEvent(sessionId, result.event);\n\n // After the primary event lands in the buffer, scan the transcript for any\n // new assistant turns and emit one assistant_turn event per uuid we haven't\n // seen. PostToolUse and Stop are the hooks that follow assistant output;\n // scanning on other hooks is cheap (no new turns) and harmless.\n if (opts.event === 'PostToolUse' || opts.event === 'Stop' || opts.event === 'SubagentStop') {\n const transcriptPath = typeof payload.transcript_path === 'string' ? payload.transcript_path : '';\n if (transcriptPath !== '') {\n try {\n const { turns, seen } = await readNewAssistantTurns(sessionId, transcriptPath);\n const newlyEmitted: string[] = [];\n for (const t of turns) {\n const seq = await nextSequence(sessionId);\n const ev: RuntapeEvent = {\n type: 'assistant_turn',\n session_id: sessionId,\n transcript_path: transcriptPath,\n cwd: typeof payload.cwd === 'string' ? payload.cwd : '',\n hook_event_name: opts.event,\n permission_mode: typeof payload.permission_mode === 'string' ? payload.permission_mode : undefined,\n wall_ts: new Date().toISOString(),\n sequence: seq,\n message_uuid: t.message_uuid,\n model: t.model,\n input_tokens: t.input_tokens,\n output_tokens: t.output_tokens,\n cache_read_tokens: t.cache_read_tokens,\n cache_creation_tokens: t.cache_creation_tokens,\n text: t.text,\n };\n await appendEvent(sessionId, ev);\n newlyEmitted.push(t.message_uuid);\n }\n if (newlyEmitted.length > 0) {\n await persistCursor(sessionId, seen, newlyEmitted);\n }\n } catch (err) {\n // Transcript scan failures must never fail the hook.\n process.stderr.write(`runtape: transcript scan failed: ${err instanceof Error ? err.message : String(err)}\\n`);\n }\n }\n }\n\n // On SubagentStop, ALSO scan the subagent's own transcript and synthesize\n // the full event stream of its internal session — user prompt, assistant\n // turns with model+usage, plus tool_attempt/tool_call pairs. Tag every\n // synthesized event with agent_tool_use_id so the server can resolve the\n // parent Agent step and stamp parent_step_id deterministically.\n if (opts.event === 'SubagentStop') {\n const subTranscript = typeof payload.agent_transcript_path === 'string' ? payload.agent_transcript_path : '';\n const agentToolUseId = typeof payload.agent_id === 'string' ? payload.agent_id : '';\n if (subTranscript !== '' && agentToolUseId !== '') {\n try {\n const { emits, seen } = await readNewSubagentEvents(sessionId, agentToolUseId, subTranscript);\n const newlyEmitted: string[] = [];\n const cwd = typeof payload.cwd === 'string' ? payload.cwd : '';\n for (const e of emits) {\n const seq = await nextSequence(sessionId);\n const baseEnvelope = {\n session_id: sessionId,\n transcript_path: subTranscript,\n cwd,\n hook_event_name: opts.event,\n permission_mode: typeof payload.permission_mode === 'string' ? payload.permission_mode : undefined,\n wall_ts: new Date().toISOString(),\n sequence: seq,\n agent_tool_use_id: agentToolUseId,\n };\n let ev: RuntapeEvent | null = null;\n if (e.kind === 'user_prompt') {\n ev = { ...baseEnvelope, type: 'user_prompt', prompt: e.prompt };\n } else if (e.kind === 'assistant_turn') {\n ev = {\n ...baseEnvelope,\n type: 'assistant_turn',\n message_uuid: e.message_uuid,\n model: e.model,\n input_tokens: e.input_tokens,\n output_tokens: e.output_tokens,\n cache_read_tokens: e.cache_read_tokens,\n cache_creation_tokens: e.cache_creation_tokens,\n text: e.text,\n };\n } else if (e.kind === 'tool_attempt') {\n ev = {\n ...baseEnvelope,\n type: 'tool_attempt',\n tool_name: e.tool_name,\n tool_input: e.tool_input,\n tool_use_id: e.tool_use_id,\n };\n } else if (e.kind === 'tool_call') {\n ev = {\n ...baseEnvelope,\n type: 'tool_call',\n tool_name: e.tool_name,\n tool_input: null,\n tool_response: e.tool_response,\n tool_use_id: e.tool_use_id,\n duration_ms: 0,\n is_error: e.is_error,\n error_message: e.error_message,\n };\n }\n if (ev) {\n await appendEvent(sessionId, ev);\n newlyEmitted.push(e.uuid);\n }\n }\n if (newlyEmitted.length > 0) {\n await persistSubagentCursor(sessionId, agentToolUseId, seen, newlyEmitted);\n }\n } catch (err) {\n process.stderr.write(`runtape: subagent transcript scan failed: ${err instanceof Error ? err.message : String(err)}\\n`);\n }\n }\n }\n\n spawnFlusher(resolveCliBinPath());\n return 0;\n } catch (err) {\n process.stderr.write(`runtape: push error: ${err instanceof Error ? err.message : String(err)}\\n`);\n return 0; // Never fail the hook.\n }\n}\n","import { mkdir, readFile, writeFile } from 'node:fs/promises';\nimport { dirname } from 'node:path';\nimport { paths } from './paths.js';\n\n// Per-session monotonic counter. Persisted as a single integer in seq/<session_id>.\n// Hooks fire one-at-a-time per session (Claude Code waits for the hook to exit before\n// firing the next), so we do NOT need cross-process locking — but we DO need the value\n// to survive across hook invocations, since each `runtape push` is a separate process.\nexport async function nextSequence(sessionId: string): Promise<number> {\n const file = paths.seqFile(sessionId);\n await mkdir(dirname(file), { recursive: true });\n\n let current = 0;\n try {\n const raw = await readFile(file, 'utf8');\n const parsed = Number.parseInt(raw.trim(), 10);\n if (Number.isFinite(parsed) && parsed >= 0) current = parsed;\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code !== 'ENOENT') throw err;\n }\n\n const next = current + 1;\n await writeFile(file, String(next));\n return next - 1; // First call returns 0 (matching the Zod schema's nonnegative invariant).\n}\n","import { appendFile, mkdir, readFile, readdir, writeFile, unlink, stat } from 'node:fs/promises';\nimport type { RuntapeEvent } from '../types.js';\nimport { paths } from './paths.js';\n\n// Atomic append-as-line. POSIX guarantees a single write() of <PIPE_BUF bytes (≥512) is\n// atomic, and we further constrain ourselves to one line per call. Two concurrent\n// appenders (e.g. two Claude Code instances writing to the same session — impossible\n// today, but cheap defense) cannot interleave a single line.\nexport async function appendEvent(sessionId: string, event: RuntapeEvent): Promise<void> {\n await mkdir(paths.bufferDir, { recursive: true });\n const line = JSON.stringify(event) + '\\n';\n await appendFile(paths.bufferFile(sessionId), line, { encoding: 'utf8' });\n}\n\nexport type BufferedSession = {\n sessionId: string;\n events: RuntapeEvent[];\n raw: string[]; // Raw lines, so we can rewrite exactly what we read on partial-flush.\n};\n\nexport async function listBufferedSessions(): Promise<string[]> {\n let entries: string[];\n try {\n entries = await readdir(paths.bufferDir);\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === 'ENOENT') return [];\n throw err;\n }\n return entries.filter((e) => e.endsWith('.ndjson')).map((e) => e.slice(0, -'.ndjson'.length));\n}\n\nexport async function readBufferedSession(sessionId: string): Promise<BufferedSession | null> {\n let raw: string;\n try {\n raw = await readFile(paths.bufferFile(sessionId), 'utf8');\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === 'ENOENT') return null;\n throw err;\n }\n const lines = raw.split('\\n').filter((l) => l.length > 0);\n const events: RuntapeEvent[] = [];\n for (const line of lines) {\n try {\n events.push(JSON.parse(line) as RuntapeEvent);\n } catch {\n // Skip malformed lines — they could only get there via a half-written disk; drop them.\n }\n }\n return { sessionId, events, raw: lines };\n}\n\n// Atomic truncate-after-flush: write a temp file with the unflushed remainder, then rename.\n// If `unflushedLines` is empty, delete the buffer file entirely.\nexport async function rewriteBufferedSession(sessionId: string, unflushedLines: string[]): Promise<void> {\n const file = paths.bufferFile(sessionId);\n if (unflushedLines.length === 0) {\n try {\n await unlink(file);\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code !== 'ENOENT') throw err;\n }\n return;\n }\n const tmp = file + '.tmp';\n await writeFile(tmp, unflushedLines.map((l) => l + '\\n').join(''));\n // rename is atomic within the same filesystem; both paths are in ~/.runtape/buffer.\n const { rename } = await import('node:fs/promises');\n await rename(tmp, file);\n}\n\nexport async function bufferSize(sessionId: string): Promise<number> {\n try {\n const s = await stat(paths.bufferFile(sessionId));\n return s.size;\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === 'ENOENT') return 0;\n throw err;\n }\n}\n\nexport function bufferDirPath(): string {\n return paths.bufferDir;\n}\n\n// Used by tests + future GC: stat-mtime in ms for the buffer file.\nexport async function bufferMtimeMs(sessionId: string): Promise<number | null> {\n try {\n const s = await stat(paths.bufferFile(sessionId));\n return s.mtimeMs;\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === 'ENOENT') return null;\n throw err;\n }\n}\n\n// Re-export for callers that want to know where the file lives without importing paths twice.\nexport function bufferFilePath(sessionId: string): string {\n return paths.bufferFile(sessionId);\n}\n","import { mkdir, readFile, writeFile } from 'node:fs/promises';\nimport { dirname } from 'node:path';\nimport { paths } from './paths.js';\n\n// Claude Code maintains a JSONL transcript at `transcript_path`. Every line is\n// a single message object with at minimum `uuid`, `type` (user|assistant|...)\n// and a `message` payload. Assistant messages additionally carry the model\n// identifier and Anthropic API usage block — the *only* place either datum\n// appears in the hook emit chain.\n//\n// We scan the transcript on every PostToolUse/Stop hook and emit one\n// AssistantTurn event per assistant message whose uuid is not in our seen\n// set. The cursor file persists the seen set across hook invocations.\n//\n// The transcript is append-only within a session so the scan is cheap; we\n// only ever read the file once per hook fire.\n\nexport type TranscriptUsage = {\n message_uuid: string;\n model: string;\n input_tokens: number;\n output_tokens: number;\n cache_read_tokens: number;\n cache_creation_tokens: number;\n text?: string;\n};\n\ntype AssistantLine = {\n uuid?: unknown;\n type?: unknown;\n message?: {\n role?: unknown;\n model?: unknown;\n content?: unknown;\n usage?: {\n input_tokens?: unknown;\n output_tokens?: unknown;\n cache_read_input_tokens?: unknown;\n cache_creation_input_tokens?: unknown;\n };\n };\n};\n\nfunction asInt(x: unknown): number {\n if (typeof x === 'number' && Number.isFinite(x) && x >= 0) return Math.trunc(x);\n return 0;\n}\n\nfunction extractAssistantText(content: unknown): string | undefined {\n // Anthropic content blocks: [{ type: 'text', text: '...' }, { type: 'tool_use', ... }]\n if (!Array.isArray(content)) return undefined;\n const parts: string[] = [];\n for (const block of content) {\n if (block && typeof block === 'object' && 'type' in block) {\n const b = block as { type: unknown; text?: unknown };\n if (b.type === 'text' && typeof b.text === 'string') parts.push(b.text);\n }\n }\n const joined = parts.join('\\n').trim();\n return joined === '' ? undefined : joined;\n}\n\n// Parses the transcript and returns assistant turns whose uuid is not in\n// `seenUuids`. The seen set is read from the cursor file; the caller is\n// responsible for persisting it after the events have been buffered.\nexport async function readNewAssistantTurns(\n sessionId: string,\n transcriptPath: string,\n): Promise<{ turns: TranscriptUsage[]; seen: Set<string> }> {\n const seen = await readCursor(sessionId);\n\n let raw: string;\n try {\n raw = await readFile(transcriptPath, 'utf8');\n } catch {\n return { turns: [], seen };\n }\n\n const turns: TranscriptUsage[] = [];\n for (const line of raw.split('\\n')) {\n const trimmed = line.trim();\n if (trimmed === '') continue;\n let parsed: AssistantLine;\n try {\n parsed = JSON.parse(trimmed) as AssistantLine;\n } catch {\n // Truncated or partial line at the tail — skip silently. The next hook\n // fire will see the full line once Claude Code has finished writing it.\n continue;\n }\n if (parsed.type !== 'assistant') continue;\n const uuid = typeof parsed.uuid === 'string' ? parsed.uuid : '';\n if (uuid === '' || seen.has(uuid)) continue;\n const msg = parsed.message ?? {};\n const model = typeof msg.model === 'string' ? msg.model : '';\n // Claude Code emits placeholder turns with model \"<synthetic>\" (compaction\n // summaries, internal markers) that always have zero usage. Skip them —\n // they add noise without information.\n if (model === '' || model === '<synthetic>') continue;\n const usage = msg.usage ?? {};\n turns.push({\n message_uuid: uuid,\n model,\n input_tokens: asInt(usage.input_tokens),\n output_tokens: asInt(usage.output_tokens),\n cache_read_tokens: asInt(usage.cache_read_input_tokens),\n cache_creation_tokens: asInt(usage.cache_creation_input_tokens),\n text: extractAssistantText(msg.content),\n });\n }\n\n return { turns, seen };\n}\n\n// Cursor file is a newline-separated list of uuids. Trim to the most recent\n// 200 — the seen set only needs to cover the tail of the transcript that the\n// next hook might re-scan, not the full history.\nconst CURSOR_KEEP = 200;\n\nasync function readCursor(sessionId: string): Promise<Set<string>> {\n try {\n const raw = await readFile(paths.transcriptCursorFile(sessionId), 'utf8');\n return new Set(\n raw\n .split('\\n')\n .map((s) => s.trim())\n .filter((s) => s !== ''),\n );\n } catch {\n return new Set();\n }\n}\n\nexport async function persistCursor(\n sessionId: string,\n seen: Set<string>,\n newlyEmitted: string[],\n): Promise<void> {\n for (const u of newlyEmitted) seen.add(u);\n const file = paths.transcriptCursorFile(sessionId);\n await mkdir(dirname(file), { recursive: true });\n // Keep only the tail so the file doesn't grow unbounded over long sessions.\n const arr = [...seen];\n const trimmed = arr.length > CURSOR_KEEP ? arr.slice(arr.length - CURSOR_KEEP) : arr;\n await writeFile(file, trimmed.join('\\n') + '\\n');\n}\n","import { mkdir, readFile, writeFile } from 'node:fs/promises';\nimport { dirname } from 'node:path';\nimport { paths } from './paths.js';\n\n// The subagent transcript is a separate JSONL Claude Code keeps for each\n// subagent it spawns via the Task tool. Format mirrors the main transcript:\n//\n// { uuid, type: 'user', message: { content: [...] } }\n// { uuid, type: 'assistant', message: { model, content: [...], usage: {...} } }\n//\n// We unpack it into a richer stream than the main transcript reader because\n// the subagent's internal life is what we're trying to expose:\n// - user entries with text content -> user_prompt\n// - user entries with tool_result blks -> tool_call (one per result)\n// - assistant entries -> assistant_turn (model + usage)\n// - tool_use blocks inside assistant -> tool_attempt (one per block)\n//\n// Cursor lives at ~/.runtape/transcript/subagent-<parent_session>-<agent_tool_use_id>\n// and tracks per-uuid emission idempotency.\n\nexport type SubagentEmit =\n | {\n kind: 'user_prompt';\n uuid: string;\n prompt: string;\n }\n | {\n kind: 'assistant_turn';\n uuid: string;\n message_uuid: string;\n model: string;\n input_tokens: number;\n output_tokens: number;\n cache_read_tokens: number;\n cache_creation_tokens: number;\n text?: string;\n }\n | {\n kind: 'tool_attempt';\n uuid: string;\n tool_use_id: string;\n tool_name: string;\n tool_input: unknown;\n }\n | {\n kind: 'tool_call';\n uuid: string;\n tool_use_id: string;\n tool_name: string;\n tool_response: unknown;\n is_error: boolean;\n error_message?: string;\n };\n\ntype TranscriptLine = {\n uuid?: unknown;\n type?: unknown;\n message?: {\n role?: unknown;\n model?: unknown;\n content?: unknown;\n usage?: {\n input_tokens?: unknown;\n output_tokens?: unknown;\n cache_read_input_tokens?: unknown;\n cache_creation_input_tokens?: unknown;\n };\n };\n};\n\nfunction asInt(x: unknown): number {\n if (typeof x === 'number' && Number.isFinite(x) && x >= 0) return Math.trunc(x);\n return 0;\n}\n\nfunction textFromBlocks(content: unknown): string | undefined {\n if (!Array.isArray(content)) return typeof content === 'string' ? content : undefined;\n const parts: string[] = [];\n for (const block of content) {\n if (block && typeof block === 'object' && 'type' in block) {\n const b = block as { type: unknown; text?: unknown };\n if (b.type === 'text' && typeof b.text === 'string') parts.push(b.text);\n }\n }\n const joined = parts.join('\\n').trim();\n return joined === '' ? undefined : joined;\n}\n\nfunction summarizeToolResult(content: unknown): { is_error: boolean; error_message?: string } {\n if (!Array.isArray(content)) {\n if (typeof content === 'string') return { is_error: false };\n return { is_error: false };\n }\n // Anthropic tool_result blocks can carry their own is_error flag.\n let isError = false;\n const texts: string[] = [];\n for (const block of content) {\n if (block && typeof block === 'object') {\n const b = block as { type?: unknown; text?: unknown; is_error?: unknown };\n if (b.is_error === true) isError = true;\n if (typeof b.text === 'string') texts.push(b.text);\n }\n }\n if (isError && texts.length > 0) return { is_error: true, error_message: texts.join('\\n').slice(0, 500) };\n if (isError) return { is_error: true };\n return { is_error: false };\n}\n\nexport async function readNewSubagentEvents(\n parentSessionId: string,\n agentToolUseId: string,\n transcriptPath: string,\n): Promise<{ emits: SubagentEmit[]; seen: Set<string> }> {\n const seen = await readCursor(parentSessionId, agentToolUseId);\n\n let raw: string;\n try {\n raw = await readFile(transcriptPath, 'utf8');\n } catch {\n return { emits: [], seen };\n }\n\n const emits: SubagentEmit[] = [];\n // Map tool_use_id -> tool_name learned from assistant tool_use blocks so we\n // can echo it back on the corresponding tool_call (the tool_result echo\n // doesn't carry the tool name itself).\n const toolNameByUseId = new Map<string, string>();\n\n for (const line of raw.split('\\n')) {\n const trimmed = line.trim();\n if (trimmed === '') continue;\n let parsed: TranscriptLine;\n try {\n parsed = JSON.parse(trimmed) as TranscriptLine;\n } catch {\n continue;\n }\n const uuid = typeof parsed.uuid === 'string' ? parsed.uuid : '';\n if (uuid === '' || seen.has(uuid)) continue;\n\n const msg = parsed.message ?? {};\n\n if (parsed.type === 'user') {\n // Two flavors of user entries: real user prompts vs. tool_result echoes.\n const content = msg.content;\n const hasToolResults =\n Array.isArray(content) &&\n content.some(\n (b) => b && typeof b === 'object' && (b as { type?: unknown }).type === 'tool_result',\n );\n if (hasToolResults) {\n for (const block of content as unknown[]) {\n if (!block || typeof block !== 'object') continue;\n const b = block as { type?: unknown; tool_use_id?: unknown; content?: unknown };\n if (b.type !== 'tool_result') continue;\n const tuid = typeof b.tool_use_id === 'string' ? b.tool_use_id : '';\n if (tuid === '') continue;\n const { is_error, error_message } = summarizeToolResult(b.content);\n emits.push({\n kind: 'tool_call',\n uuid: `${uuid}:${tuid}`,\n tool_use_id: tuid,\n tool_name: toolNameByUseId.get(tuid) ?? 'unknown',\n tool_response: b.content,\n is_error,\n error_message,\n });\n }\n } else {\n const text = textFromBlocks(content);\n if (text !== undefined) {\n emits.push({ kind: 'user_prompt', uuid, prompt: text });\n }\n }\n continue;\n }\n\n if (parsed.type === 'assistant') {\n const model = typeof msg.model === 'string' ? msg.model : '';\n // Synthetic placeholders carry no useful information.\n if (model === '' || model === '<synthetic>') continue;\n const usage = msg.usage ?? {};\n emits.push({\n kind: 'assistant_turn',\n uuid,\n message_uuid: uuid,\n model,\n input_tokens: asInt(usage.input_tokens),\n output_tokens: asInt(usage.output_tokens),\n cache_read_tokens: asInt(usage.cache_read_input_tokens),\n cache_creation_tokens: asInt(usage.cache_creation_input_tokens),\n text: textFromBlocks(msg.content),\n });\n // Emit one tool_attempt per tool_use block embedded in this assistant\n // message. The matching tool_result will land in the next user entry.\n if (Array.isArray(msg.content)) {\n for (const block of msg.content) {\n if (!block || typeof block !== 'object') continue;\n const b = block as { type?: unknown; id?: unknown; name?: unknown; input?: unknown };\n if (b.type !== 'tool_use') continue;\n const tuid = typeof b.id === 'string' ? b.id : '';\n const tname = typeof b.name === 'string' ? b.name : '';\n if (tuid === '' || tname === '') continue;\n toolNameByUseId.set(tuid, tname);\n emits.push({\n kind: 'tool_attempt',\n uuid: `${uuid}:${tuid}`,\n tool_use_id: tuid,\n tool_name: tname,\n tool_input: b.input,\n });\n }\n }\n continue;\n }\n }\n\n return { emits, seen };\n}\n\nconst CURSOR_KEEP = 500;\n\nasync function readCursor(parentSessionId: string, agentToolUseId: string): Promise<Set<string>> {\n try {\n const raw = await readFile(cursorFile(parentSessionId, agentToolUseId), 'utf8');\n return new Set(\n raw\n .split('\\n')\n .map((s) => s.trim())\n .filter((s) => s !== ''),\n );\n } catch {\n return new Set();\n }\n}\n\nfunction cursorFile(parentSessionId: string, agentToolUseId: string): string {\n // Two-level encoding so different parents and different agent invocations\n // keep independent cursors even if their uuids overlap by accident.\n return `${paths.transcriptDir}/subagent-${parentSessionId}-${agentToolUseId}`;\n}\n\nexport async function persistSubagentCursor(\n parentSessionId: string,\n agentToolUseId: string,\n seen: Set<string>,\n newlyEmitted: string[],\n): Promise<void> {\n for (const u of newlyEmitted) seen.add(u);\n const file = cursorFile(parentSessionId, agentToolUseId);\n await mkdir(dirname(file), { recursive: true });\n const arr = [...seen];\n const trimmed = arr.length > CURSOR_KEEP ? arr.slice(arr.length - CURSOR_KEEP) : arr;\n await writeFile(file, trimmed.join('\\n') + '\\n');\n}\n","import { homedir } from 'node:os';\nimport { resolve } from 'node:path';\nimport type { WatchConfig } from './config.js';\n\n// Pure decision: should this cwd be captured under the given watch config?\n// Returns true when capture should proceed, false when the hook must silently\n// no-op. Mirrors the semantics of allow_list / deny_list / allow_all.\n//\n// Matching is prefix-based on normalized absolute paths. `/Users/me/work`\n// matches both `/Users/me/work` and `/Users/me/work/repo`, but NOT\n// `/Users/me/work-other` (we anchor the prefix on a path separator boundary).\nexport function isCaptureAllowed(watch: WatchConfig | undefined, cwd: string): boolean {\n if (!watch || watch.mode === 'allow_all') return true;\n if (watch.paths.length === 0) {\n // deny_list with no paths => deny nothing (capture). allow_list with no\n // paths => allow nothing (skip). Either way the semantics are intuitive.\n return watch.mode === 'deny_list';\n }\n const cwdNorm = normalizePath(cwd);\n const matched = watch.paths.some((p) => isPrefixMatch(cwdNorm, normalizePath(p)));\n return watch.mode === 'allow_list' ? matched : !matched;\n}\n\nfunction isPrefixMatch(cwd: string, prefix: string): boolean {\n return cwd === prefix || cwd.startsWith(prefix + '/');\n}\n\n// Normalize a path to an absolute form so comparisons don't break on `~`\n// expansion or trailing slashes. Tilde expansion is best-effort: the user's\n// shell expands it before we ever see it in most flows, but `runtape watch\n// ignore ~/foo` is a likely input from a terminal where the shell didn't.\nexport function normalizePath(input: string): string {\n let expanded = input;\n if (expanded === '~') expanded = homedir();\n else if (expanded.startsWith('~/')) expanded = `${homedir()}/${expanded.slice(2)}`;\n const abs = resolve(expanded);\n return abs.replace(/\\/+$/, '') || '/';\n}\n","import { readFile } from 'node:fs/promises';\nimport { readConfig } from '../lib/config.js';\nimport { listBufferedSessions, bufferSize, bufferMtimeMs } from '../lib/buffer.js';\nimport { paths } from '../lib/paths.js';\nimport { pingProject } from '../lib/api.js';\n\nasync function readFlusherPid(): Promise<number | null> {\n try {\n const raw = await readFile(paths.flusherPid, 'utf8');\n const n = Number.parseInt(raw.trim(), 10);\n return Number.isFinite(n) ? n : null;\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === 'ENOENT') return null;\n throw err;\n }\n}\n\nexport async function statusCommand(): Promise<number> {\n const cfg = await readConfig();\n if (!cfg) {\n process.stdout.write('Not logged in. Run `runtape login`.\\n');\n return 0;\n }\n\n process.stdout.write(`Server: ${cfg.server_url}\\n`);\n process.stdout.write(`API key: ${cfg.api_key.slice(0, 8)}…${cfg.api_key.slice(-4)}\\n`);\n\n const ping = await pingProject(cfg.server_url, cfg.api_key);\n process.stdout.write(`Reachable: ${ping.ok ? 'yes' : `no (${ping.detail ?? ping.status})`}\\n`);\n\n const sessions = await listBufferedSessions();\n if (sessions.length === 0) {\n process.stdout.write('Buffer: empty.\\n');\n } else {\n process.stdout.write(`Buffer: ${sessions.length} session(s) pending.\\n`);\n for (const s of sessions) {\n const size = await bufferSize(s);\n const mtime = await bufferMtimeMs(s);\n const ageSec = mtime ? Math.round((Date.now() - mtime) / 1000) : null;\n process.stdout.write(` ${s}: ${size} bytes${ageSec !== null ? `, updated ${ageSec}s ago` : ''}\\n`);\n }\n }\n\n const flusherPid = await readFlusherPid();\n if (flusherPid !== null) {\n process.stdout.write(`Flusher: PID ${flusherPid}\\n`);\n } else {\n process.stdout.write('Flusher: not running.\\n');\n }\n\n return 0;\n}\n","import { spawn } from 'node:child_process';\nimport { platform } from 'node:process';\nimport { readConfig } from '../lib/config.js';\n\nfunction openCommand(): { cmd: string; args: string[] } {\n // Cross-platform \"open this URL in the default browser\".\n // macOS: `open <url>`. Linux: `xdg-open <url>`. Windows: `cmd /c start \"\" <url>`.\n if (platform === 'darwin') return { cmd: 'open', args: [] };\n if (platform === 'win32') return { cmd: 'cmd', args: ['/c', 'start', ''] };\n return { cmd: 'xdg-open', args: [] };\n}\n\nexport async function runsCommand(): Promise<number> {\n const cfg = await readConfig();\n if (!cfg) {\n process.stderr.write('Not logged in. Run `runtape login` first.\\n');\n return 1;\n }\n\n const url = `${cfg.server_url.replace(/\\/$/, '')}/dashboard/runs`;\n const { cmd, args } = openCommand();\n\n const child = spawn(cmd, [...args, url], { stdio: 'ignore', detached: true });\n child.on('error', (err) => {\n process.stderr.write(`Could not launch browser (${err.message}). Open this manually:\\n${url}\\n`);\n });\n child.unref();\n\n process.stdout.write(`Opening ${url}\\n`);\n return 0;\n}\n","import { spawn } from 'node:child_process';\nimport { platform } from 'node:process';\nimport { createInterface } from 'node:readline/promises';\nimport { stdin as input, stdout as output } from 'node:process';\nimport { Config, defaultServerUrl, readConfig, writeConfig } from '../lib/config.js';\nimport { pingProject } from '../lib/api.js';\nimport { installHooks } from '../lib/hooks-installer.js';\nimport { resolveCliBinPath } from '../lib/cli-bin.js';\n\nfunction openCommand(): { cmd: string; args: string[] } {\n if (platform === 'darwin') return { cmd: 'open', args: [] };\n if (platform === 'win32') return { cmd: 'cmd', args: ['/c', 'start', ''] };\n return { cmd: 'xdg-open', args: [] };\n}\n\nfunction openInBrowser(url: string): void {\n const { cmd, args } = openCommand();\n const child = spawn(cmd, [...args, url], { stdio: 'ignore', detached: true });\n child.on('error', () => {\n /* swallow — caller already printed the URL to fall back on */\n });\n child.unref();\n}\n\nasync function promptYesNo(rl: Awaited<ReturnType<typeof createInterface>>, question: string, defaultYes: boolean): Promise<boolean> {\n const suffix = defaultYes ? '(Y/n)' : '(y/N)';\n const answer = (await rl.question(`${question} ${suffix} `)).trim().toLowerCase();\n if (answer === '') return defaultYes;\n return answer === 'y' || answer === 'yes';\n}\n\nexport async function setupCommand(opts: { noBrowser?: boolean }): Promise<number> {\n const rl = createInterface({ input, output });\n\n try {\n process.stdout.write('\\nRuntape setup\\n');\n process.stdout.write('Let\\'s get your Claude Code runs captured.\\n');\n process.stdout.write('(Press Enter at any prompt to accept the default shown in [brackets].)\\n\\n');\n\n // Step 1 — short-circuit if already configured\n const existing = await readConfig();\n if (existing) {\n process.stdout.write(`Already logged in to ${existing.server_url}\\n`);\n process.stdout.write(`API key: ${existing.api_key.slice(0, 8)}…${existing.api_key.slice(-4)}\\n`);\n const reconfigure = await promptYesNo(rl, 'Reconfigure?', false);\n if (!reconfigure) {\n process.stdout.write('\\nKeeping existing credentials. Moving on to hook install.\\n');\n return await installAndFinish(rl, existing.server_url);\n }\n }\n\n // Step 2 — server URL\n const suggestedUrl = defaultServerUrl();\n process.stdout.write(`Step 1/3 — Backend\\n`);\n const urlInput = (await rl.question(`Server URL [${suggestedUrl}] (Enter to use this): `)).trim();\n const serverUrl = urlInput === '' ? suggestedUrl : urlInput;\n\n // Step 3 — open dashboard for the user to grab their key\n const dashboardUrl = `${serverUrl.replace(/\\/$/, '')}/dashboard`;\n process.stdout.write(`\\nStep 2/3 — API key\\n`);\n process.stdout.write(`Your API key lives in the dashboard:\\n ${dashboardUrl}\\n`);\n if (!opts.noBrowser) {\n openInBrowser(dashboardUrl);\n process.stdout.write('(opened in your browser)\\n');\n }\n\n // Step 4 — paste + validate\n const apiKey = (await rl.question('\\nPaste your API key (rtk_…): ')).trim();\n const validation = Config.shape.api_key.safeParse(apiKey);\n if (!validation.success) {\n process.stderr.write(`\\nInvalid API key format. Expected rtk_<64 hex chars>.\\n`);\n return 2;\n }\n\n process.stdout.write(`Validating against ${serverUrl}…\\n`);\n const ping = await pingProject(serverUrl, apiKey);\n if (!ping.ok) {\n process.stderr.write(\n `\\nLogin failed: ${ping.status === 401 ? 'unknown API key' : ping.detail ?? 'server unreachable'}\\n`,\n );\n return 1;\n }\n\n await writeConfig({ api_key: apiKey, server_url: serverUrl });\n process.stdout.write('Credentials saved.\\n');\n\n // Step 5 — install hooks\n return await installAndFinish(rl, serverUrl);\n } finally {\n rl.close();\n }\n}\n\nasync function installAndFinish(\n rl: Awaited<ReturnType<typeof createInterface>>,\n serverUrl: string,\n): Promise<number> {\n process.stdout.write(`\\nStep 3/3 — Claude Code hooks\\n`);\n const install = await promptYesNo(\n rl,\n 'Install Runtape hooks into ~/.claude/settings.json now?',\n true,\n );\n\n if (!install) {\n process.stdout.write('\\nSkipped hook install. Run `runtape install` when ready.\\n');\n return 0;\n }\n\n const cliBinPath = resolveCliBinPath();\n const result = await installHooks('user', cliBinPath);\n process.stdout.write(`Updated ${result.settingsPath}\\n`);\n if (result.addedHooks.length === 0) {\n process.stdout.write('Hooks already installed — nothing changed.\\n');\n } else {\n process.stdout.write(`Added: ${result.addedHooks.join(', ')}\\n`);\n }\n\n process.stdout.write('\\nSetup complete.\\n');\n process.stdout.write('Now run `claude -p \"any prompt\"` from any directory and watch the run land at:\\n');\n process.stdout.write(` ${serverUrl.replace(/\\/$/, '')}/dashboard\\n\\n`);\n return 0;\n}\n","import { readConfig, writeConfig, type Config, type WatchMode } from '../lib/config.js';\nimport { normalizePath } from '../lib/watch.js';\n\n// Subcommand surface for the path-watcher feature. Mutates the CLI config's\n// `watch` block; no server interaction. Every operation reads → mutates →\n// writeConfig() — that re-applies chmod 600 so the credentials stay locked\n// down even if the user touched the file manually between calls.\n\nfunction modeLabel(mode: WatchMode): string {\n if (mode === 'allow_all') return 'allow_all (capturing every session)';\n if (mode === 'allow_list') return 'allow_list (capturing ONLY listed paths)';\n return 'deny_list (capturing every session EXCEPT listed paths)';\n}\n\nasync function readOrExit(): Promise<Config> {\n const cfg = await readConfig();\n if (!cfg) {\n process.stderr.write('Not logged in. Run `runtape login` first.\\n');\n process.exit(1);\n }\n return cfg;\n}\n\nfunction ensureWatch(cfg: Config): { mode: WatchMode; paths: string[] } {\n return cfg.watch\n ? { mode: cfg.watch.mode, paths: [...cfg.watch.paths] }\n : { mode: 'allow_all', paths: [] };\n}\n\nexport async function watchListCommand(): Promise<number> {\n const cfg = await readOrExit();\n const w = ensureWatch(cfg);\n process.stdout.write(`Mode: ${modeLabel(w.mode)}\\n`);\n if (w.paths.length === 0) {\n process.stdout.write('Paths: (none)\\n');\n } else {\n process.stdout.write('Paths:\\n');\n for (const p of w.paths) process.stdout.write(` ${p}\\n`);\n }\n process.stdout.write('\\nEnv override: set RUNTAPE_DISABLE=1 to skip capture for a single session.\\n');\n return 0;\n}\n\nexport async function watchIgnoreCommand(path: string): Promise<number> {\n const cfg = await readOrExit();\n const w = ensureWatch(cfg);\n if (w.mode === 'allow_list') {\n process.stderr.write(\n \"Current mode is allow_list (only listed paths are captured). `ignore` only makes sense in allow_all/deny_list mode.\\nRun `runtape watch reset` to start over, or use `runtape watch only <path>` to add to the allow list.\\n\",\n );\n return 1;\n }\n const normalized = normalizePath(path);\n if (w.paths.includes(normalized)) {\n process.stdout.write(`Already ignored: ${normalized}\\n`);\n return 0;\n }\n w.paths.push(normalized);\n // Auto-switch: first ignore on a fresh allow_all config flips us into deny_list.\n const next: WatchMode = w.mode === 'allow_all' ? 'deny_list' : w.mode;\n await writeConfig({ ...cfg, watch: { mode: next, paths: w.paths } });\n if (next !== w.mode) process.stdout.write(`Mode switched to deny_list.\\n`);\n process.stdout.write(`Ignoring ${normalized}\\n`);\n return 0;\n}\n\nexport async function watchOnlyCommand(path: string): Promise<number> {\n const cfg = await readOrExit();\n const w = ensureWatch(cfg);\n if (w.mode === 'deny_list') {\n process.stderr.write(\n \"Current mode is deny_list (all except listed paths). `only` would conflict.\\nRun `runtape watch reset` to start over, then `runtape watch only <path>` to switch to allow_list.\\n\",\n );\n return 1;\n }\n const normalized = normalizePath(path);\n if (w.paths.includes(normalized)) {\n process.stdout.write(`Already in allow list: ${normalized}\\n`);\n return 0;\n }\n w.paths.push(normalized);\n const next: WatchMode = w.mode === 'allow_all' ? 'allow_list' : w.mode;\n await writeConfig({ ...cfg, watch: { mode: next, paths: w.paths } });\n if (next !== w.mode) process.stdout.write(`Mode switched to allow_list.\\n`);\n process.stdout.write(`Capturing only: ${normalized}\\n`);\n return 0;\n}\n\nexport async function watchUnignoreCommand(path: string): Promise<number> {\n const cfg = await readOrExit();\n const w = ensureWatch(cfg);\n const normalized = normalizePath(path);\n const filtered = w.paths.filter((p) => p !== normalized);\n if (filtered.length === w.paths.length) {\n process.stdout.write(`Not in the list: ${normalized}\\n`);\n return 0;\n }\n await writeConfig({ ...cfg, watch: { mode: w.mode, paths: filtered } });\n process.stdout.write(`Removed: ${normalized}\\n`);\n return 0;\n}\n\nexport async function watchResetCommand(): Promise<number> {\n const cfg = await readOrExit();\n // We strip the watch key entirely rather than persist `{mode: allow_all, paths: []}`\n // so the config file goes back to its 0.5.x shape — useful for users who\n // downgrade or who inspect the file by hand.\n const { watch: _unused, ...rest } = cfg;\n await writeConfig(rest as Config);\n process.stdout.write('Reset to allow_all. All sessions will be captured.\\n');\n return 0;\n}\n","import { appendFile, mkdir, readFile, unlink, writeFile } from 'node:fs/promises';\nimport { dirname } from 'node:path';\nimport { readConfig } from './config.js';\nimport { listBufferedSessions, readBufferedSession, rewriteBufferedSession } from './buffer.js';\nimport { postEvents } from './api.js';\nimport { paths } from './paths.js';\n\n// Tuned in 0.5.0 to cut PostgREST/Vercel invocation pressure under heavy\n// sessions. A power Claude Code user generates 5-10 events/sec; 500-event\n// batches at a 5s cadence still feel real-time in the dashboard while\n// reducing request count ~5x vs the prior 100-event/1.5s defaults.\nconst POLL_INTERVAL_MS = 5_000;\nconst IDLE_EXIT_MS = 30_000;\nconst BATCH_MAX = 500;\nconst BACKOFF_STEPS_MS = [1000, 2000, 4000, 8000, 16_000, 32_000, 60_000];\n\nasync function log(line: string): Promise<void> {\n try {\n await mkdir(dirname(paths.flusherLog), { recursive: true });\n await appendFile(paths.flusherLog, `${new Date().toISOString()} ${line}\\n`);\n } catch {\n /* never throw out of logging */\n }\n}\n\nasync function isProcessAlive(pid: number): Promise<boolean> {\n try {\n process.kill(pid, 0); // Signal 0 = existence check, doesn't actually signal.\n return true;\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === 'ESRCH') return false;\n if ((err as NodeJS.ErrnoException).code === 'EPERM') return true; // Exists, owned by someone else.\n return false;\n }\n}\n\n// Acquire-or-detect-running. Returns true if we became the flusher; false if one is already running.\nexport async function acquirePidLock(): Promise<boolean> {\n await mkdir(dirname(paths.flusherPid), { recursive: true });\n try {\n const existing = await readFile(paths.flusherPid, 'utf8');\n const pid = Number.parseInt(existing.trim(), 10);\n if (Number.isFinite(pid) && (await isProcessAlive(pid))) {\n return false; // Another flusher is alive.\n }\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code !== 'ENOENT') throw err;\n }\n await writeFile(paths.flusherPid, String(process.pid));\n return true;\n}\n\nasync function releasePidLock(): Promise<void> {\n try {\n await unlink(paths.flusherPid);\n } catch {\n /* ignore */\n }\n}\n\nfunction delay(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\n// Drain a single session's buffer in batches of up to BATCH_MAX. Returns true if any\n// events were successfully flushed.\nasync function drainSession(sessionId: string, serverUrl: string, apiKey: string): Promise<boolean> {\n const snapshot = await readBufferedSession(sessionId);\n if (!snapshot || snapshot.events.length === 0) {\n await rewriteBufferedSession(sessionId, []);\n return false;\n }\n\n let cursor = 0;\n let anyFlushed = false;\n while (cursor < snapshot.events.length) {\n const slice = snapshot.events.slice(cursor, cursor + BATCH_MAX);\n const result = await postEvents(serverUrl, apiKey, slice);\n\n if (result.ok) {\n cursor += slice.length;\n anyFlushed = true;\n continue;\n }\n\n if (!result.retryable) {\n // Poison batch — log + drop the slice to prevent stuck buffer. 4xx is on us (or stale CLI vs server).\n await log(`drop_poison session=${sessionId} status=${result.status} error=${result.error.slice(0, 200)}`);\n cursor += slice.length;\n anyFlushed = true; // We've made forward progress (toward emptying the buffer), so don't backoff.\n continue;\n }\n\n // Retryable — stop draining this session, leave the rest for next poll cycle.\n await log(`retryable session=${sessionId} status=${result.status} cursor=${cursor} error=${result.error.slice(0, 200)}`);\n break;\n }\n\n const remaining = snapshot.raw.slice(cursor);\n await rewriteBufferedSession(sessionId, remaining);\n return anyFlushed;\n}\n\nexport async function runFlusher(): Promise<void> {\n const acquired = await acquirePidLock();\n if (!acquired) {\n await log('exit_already_running');\n return;\n }\n\n await log(`start pid=${process.pid}`);\n\n let lastActivityMs = Date.now();\n let backoffIdx = 0;\n\n try {\n while (true) {\n const cfg = await readConfig();\n if (!cfg) {\n // No config yet — we shouldn't have been spawned. Exit cleanly.\n await log('exit_no_config');\n return;\n }\n\n const sessions = await listBufferedSessions();\n let flushedThisCycle = false;\n for (const sessionId of sessions) {\n const flushed = await drainSession(sessionId, cfg.server_url, cfg.api_key);\n flushedThisCycle = flushedThisCycle || flushed;\n }\n\n if (flushedThisCycle) {\n lastActivityMs = Date.now();\n backoffIdx = 0;\n }\n\n // Idle exit.\n const remaining = await listBufferedSessions();\n const idleMs = Date.now() - lastActivityMs;\n if (remaining.length === 0 && idleMs >= IDLE_EXIT_MS) {\n await log(`exit_idle idle_ms=${idleMs}`);\n return;\n }\n\n // Backoff when buffer is non-empty but we couldn't drain anything (server down).\n // Reset backoff when we made progress.\n const wait =\n remaining.length > 0 && !flushedThisCycle\n ? BACKOFF_STEPS_MS[Math.min(backoffIdx++, BACKOFF_STEPS_MS.length - 1)]\n : POLL_INTERVAL_MS;\n await delay(wait);\n }\n } catch (err) {\n await log(`crash error=${err instanceof Error ? err.message : String(err)}`);\n throw err;\n } finally {\n await releasePidLock();\n }\n}\n"],"mappings":"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","names":["fileURLToPath","dirname","join","createInterface","input","output","mkdir","readFile","writeFile","dirname","readFile","mkdir","dirname","writeFile","dirname","createInterface","input","output","mkdir","readFile","writeFile","dirname","mkdir","dirname","readFile","writeFile","mkdir","readFile","writeFile","unlink","mkdir","readFile","unlink","writeFile","mkdir","readFile","writeFile","dirname","readFile","mkdir","dirname","writeFile","mkdir","readFile","writeFile","dirname","asInt","readCursor","readFile","CURSOR_KEEP","mkdir","dirname","writeFile","homedir","resolve","input","cwd","readFile","readFile","spawn","spawn","spawn","platform","createInterface","input","output","openCommand","platform","spawn","createInterface","input","output","appendFile","mkdir","readFile","unlink","writeFile","dirname","mkdir","dirname","appendFile","readFile","writeFile","unlink","resolve","join","dirname","fileURLToPath"]}