runtape 0.1.1 → 0.2.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/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 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 | 'Notification';\n\nexport const SUPPORTED_HOOKS: ClaudeHookName[] = [\n 'SessionStart',\n 'UserPromptSubmit',\n 'PreToolUse',\n 'PostToolUse',\n 'Stop',\n 'SubagentStop',\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// 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 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 };\n break;\n case 'Stop':\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 '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';\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 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 { 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');\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}]: `)).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","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/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 | 'Notification';\n\nexport const SUPPORTED_HOOKS: ClaudeHookName[] = [\n 'SessionStart',\n 'UserPromptSubmit',\n 'PreToolUse',\n 'PostToolUse',\n 'Stop',\n 'SubagentStop',\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 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 '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 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 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 if (model === '') 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 { 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":";;;;;AAAA,SAAS,oBAAoB;AAC7B,SAAS,iBAAAA,sBAAqB;AAC9B,SAAS,WAAAC,UAAS,QAAAC,aAAY;AAC9B,SAAS,eAAe;;;ACHxB,SAAS,uBAAuB;AAChC,SAAS,SAAS,OAAO,UAAU,cAAc;;;ACDjD,SAAS,OAAO,OAAO,UAAU,WAAW,cAAc;AAC1D,SAAS,eAAe;AACxB,SAAS,SAAS;;;ACFlB,SAAS,eAAe;AACxB,SAAS,YAAY;AAErB,IAAM,eAAe,QAAQ,IAAI,gBAAgB,KAAK,QAAQ,GAAG,UAAU;AAEpE,IAAM,QAAQ;AAAA,EACnB,MAAM;AAAA,EACN,QAAQ,KAAK,cAAc,aAAa;AAAA,EACxC,WAAW,KAAK,cAAc,QAAQ;AAAA,EACtC,QAAQ,KAAK,cAAc,KAAK;AAAA,EAChC,YAAY,KAAK,cAAc,aAAa;AAAA,EAC5C,YAAY,KAAK,cAAc,aAAa;AAAA,EAC5C,YAAY,CAAC,cAAsB,KAAK,cAAc,UAAU,GAAG,SAAS,SAAS;AAAA,EACrF,SAAS,CAAC,cAAsB,KAAK,cAAc,OAAO,SAAS;AAAA;AAAA;AAAA;AAAA,EAInE,sBAAsB,CAAC,cAAsB,KAAK,cAAc,cAAc,SAAS;AAAA,EACvF,eAAe,KAAK,cAAc,YAAY;AAAA,EAC9C,gBAAgB,CAAC,UACf,UAAU,SAAS,KAAK,QAAQ,GAAG,WAAW,eAAe,IAAI,KAAK,QAAQ,IAAI,GAAG,WAAW,eAAe;AAAA,EACjH,sBAAsB,CAAC,UACrB,UAAU,SACN,KAAK,QAAQ,GAAG,WAAW,8BAA8B,IACzD,KAAK,QAAQ,IAAI,GAAG,WAAW,8BAA8B;AACrE;;;ADpBO,IAAM,SAAS,EAAE,OAAO;AAAA,EAC7B,SAAS,EAAE,OAAO,EAAE,MAAM,sBAAsB,+CAA+C;AAAA,EAC/F,YAAY,EAAE,OAAO,EAAE,IAAI;AAC7B,CAAC;AAID,IAAM,qBAAqB,QAAQ,IAAI,mBAAmB;AAE1D,eAAsB,aAAqC;AACzD,MAAI;AACJ,MAAI;AACF,UAAM,MAAM,SAAS,MAAM,QAAQ,MAAM;AAAA,EAC3C,SAAS,KAAK;AACZ,QAAK,IAA8B,SAAS,SAAU,QAAO;AAC7D,UAAM;AAAA,EACR;AACA,QAAM,SAAS,OAAO,UAAU,KAAK,MAAM,GAAG,CAAC;AAC/C,MAAI,CAAC,OAAO,SAAS;AACnB,UAAM,IAAI,MAAM,qBAAqB,MAAM,MAAM,KAAK,OAAO,MAAM,OAAO,EAAE;AAAA,EAC9E;AACA,SAAO,OAAO;AAChB;AAEA,eAAsB,YAAY,GAA0B;AAC1D,QAAM,MAAM,QAAQ,MAAM,MAAM,GAAG,EAAE,WAAW,KAAK,CAAC;AACtD,QAAM,UAAU,MAAM,QAAQ,KAAK,UAAU,GAAG,MAAM,CAAC,IAAI,MAAM,EAAE,MAAM,IAAM,CAAC;AAGhF,QAAM,MAAM,MAAM,QAAQ,GAAK;AACjC;AAEA,eAAsB,cAA6B;AACjD,MAAI;AACF,UAAM,OAAO,MAAM,MAAM;AAAA,EAC3B,SAAS,KAAK;AACZ,QAAK,IAA8B,SAAS,SAAU;AACtD,UAAM;AAAA,EACR;AACF;AAEO,SAAS,mBAA2B;AACzC,SAAO;AACT;;;AE1CA,SAAS,kBAAkB,QAAyB;AAElD,SAAO,WAAW,OAAO,WAAW,OAAO,WAAW,OAAO,UAAU;AACzE;AAEA,eAAsB,WACpB,WACA,QACA,QACqB;AACrB,MAAI;AACJ,MAAI;AACF,eAAW,MAAM,MAAM,GAAG,UAAU,QAAQ,OAAO,EAAE,CAAC,kBAAkB;AAAA,MACtE,QAAQ;AAAA,MACR,SAAS;AAAA,QACP,gBAAgB;AAAA,QAChB,eAAe,UAAU,MAAM;AAAA,MACjC;AAAA,MACA,MAAM,KAAK,UAAU,EAAE,OAAO,CAAC;AAAA,IACjC,CAAC;AAAA,EACH,SAAS,KAAK;AAEZ,WAAO;AAAA,MACL,IAAI;AAAA,MACJ,QAAQ;AAAA,MACR,OAAO,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAAA,MACtD,WAAW;AAAA,IACb;AAAA,EACF;AAEA,MAAI,SAAS,IAAI;AACf,UAAM,OAAQ,MAAM,SAAS,KAAK;AAIlC,WAAO,EAAE,IAAI,MAAM,UAAU,KAAK,UAAU,QAAQ,KAAK,OAAO;AAAA,EAClE;AAEA,MAAI,SAAS;AACb,MAAI;AACF,aAAS,MAAM,SAAS,KAAK;AAAA,EAC/B,QAAQ;AAAA,EAER;AACA,SAAO;AAAA,IACL,IAAI;AAAA,IACJ,QAAQ,SAAS;AAAA,IACjB,OAAO,UAAU,SAAS;AAAA,IAC1B,WAAW,kBAAkB,SAAS,MAAM;AAAA,EAC9C;AACF;AAEA,eAAsB,YAAY,WAAmB,QAA2E;AAK9H,MAAI;AACJ,MAAI;AACF,eAAW,MAAM,MAAM,GAAG,UAAU,QAAQ,OAAO,EAAE,CAAC,kBAAkB;AAAA,MACtE,QAAQ;AAAA,MACR,SAAS;AAAA,QACP,gBAAgB;AAAA,QAChB,eAAe,UAAU,MAAM;AAAA,MACjC;AAAA,MACA,MAAM,KAAK,UAAU,EAAE,QAAQ,CAAC,EAAE,CAAC;AAAA,IACrC,CAAC;AAAA,EACH,SAAS,KAAK;AACZ,WAAO,EAAE,IAAI,OAAO,QAAQ,GAAG,QAAQ,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,EAAE;AAAA,EAC1F;AAEA,MAAI,SAAS,WAAW,IAAK,QAAO,EAAE,IAAI,MAAM,QAAQ,IAAI;AAC5D,MAAI,SAAS,WAAW,IAAK,QAAO,EAAE,IAAI,OAAO,QAAQ,KAAK,QAAQ,kBAAkB;AACxF,SAAO,EAAE,IAAI,OAAO,QAAQ,SAAS,QAAQ,QAAQ,SAAS,WAAW;AAC3E;;;AH3EA,eAAsB,aAAa,MAA6D;AAC9F,QAAM,YAAY,KAAK,aAAa,iBAAiB;AAErD,MAAI,SAAS,KAAK;AAClB,MAAI,CAAC,QAAQ;AACX,UAAM,KAAK,gBAAgB,EAAE,OAAO,OAAO,CAAC;AAC5C,cAAU,MAAM,GAAG,SAAS,2CAAsC,GAAG,KAAK;AAC1E,OAAG,MAAM;AAAA,EACX;AAEA,QAAM,aAAa,OAAO,MAAM,QAAQ,UAAU,MAAM;AACxD,MAAI,CAAC,WAAW,SAAS;AACvB,YAAQ,OAAO,MAAM;AAAA,CAAwD;AAC7E,WAAO;AAAA,EACT;AAEA,UAAQ,OAAO,MAAM,sBAAsB,SAAS;AAAA,CAAK;AACzD,QAAM,OAAO,MAAM,YAAY,WAAW,MAAM;AAChD,MAAI,CAAC,KAAK,IAAI;AACZ,YAAQ,OAAO,MAAM,iBAAiB,KAAK,WAAW,MAAM,oBAAoB,KAAK,UAAU,oBAAoB;AAAA,CAAI;AACvH,WAAO;AAAA,EACT;AAEA,QAAM,YAAY,EAAE,SAAS,QAAQ,YAAY,UAAU,CAAC;AAC5D,UAAQ,OAAO,MAAM;AAAA,CAA2C;AAChE,SAAO;AACT;;;AI7BA,eAAsB,gBAAiC;AACrD,QAAM,YAAY;AAClB,UAAQ,OAAO,MAAM,+BAA+B;AACpD,SAAO;AACT;;;ACNA,SAAS,mBAAAC,wBAAuB;AAChC,SAAS,SAASC,QAAO,UAAUC,eAAc;;;ACDjD,SAAS,UAAU,SAAAC,QAAO,YAAAC,WAAU,aAAAC,kBAAiB;AACrD,SAAS,WAAAC,gBAAe;;;ACajB,IAAM,kBAAoC;AAAA,EAC/C;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAiBA,SAAS,oBAAoB,eAAuE;AAClG,MAAI,CAAC,iBAAiB,OAAO,kBAAkB,SAAU,QAAO,EAAE,UAAU,MAAM;AAClF,QAAM,IAAI;AACV,MAAI,EAAE,aAAa,MAAM;AACvB,UAAM,UAAU,EAAE;AAClB,QAAI,MAAM,QAAQ,OAAO,GAAG;AAC1B,iBAAW,SAAS,SAAS;AAC3B,YAAI,SAAS,OAAO,UAAU,YAAY,UAAU,OAAO;AACzD,gBAAM,IAAK,MAA6B;AACxC,cAAI,OAAO,MAAM,SAAU,QAAO,EAAE,UAAU,MAAM,eAAe,EAAE;AAAA,QACvE;AAAA,MACF;AAAA,IACF;AACA,QAAI,OAAO,EAAE,YAAY,SAAU,QAAO,EAAE,UAAU,MAAM,eAAe,EAAE,QAAQ;AACrF,WAAO,EAAE,UAAU,KAAK;AAAA,EAC1B;AACA,MAAI,OAAO,EAAE,UAAU,YAAY,EAAE,MAAM,KAAK,MAAM,IAAI;AACxD,WAAO,EAAE,UAAU,MAAM,eAAe,EAAE,MAAM;AAAA,EAClD;AACA,MAAI,EAAE,gBAAgB,MAAM;AAC1B,WAAO,EAAE,UAAU,MAAM,eAAe,cAAc;AAAA,EACxD;AACA,SAAO,EAAE,UAAU,MAAM;AAC3B;AAIO,SAAS,eACd,UACA,SACA,SACW;AAEX,QAAM,OAAO;AAAA,IACX,YAAY,QAAQ;AAAA,IACpB,iBAAiB,QAAQ;AAAA,IACzB,KAAK,QAAQ;AAAA,IACb,iBAAiB,QAAQ,mBAAmB;AAAA,IAC5C,iBAAiB,QAAQ;AAAA,IACzB,SAAS,QAAQ;AAAA,IACjB,UAAU,QAAQ;AAAA,EACpB;AAEA,MAAI;AACJ,UAAQ,UAAU;AAAA,IAChB,KAAK;AACH,kBAAY,EAAE,GAAG,MAAM,MAAM,iBAAiB,QAAQ,QAAQ,UAAU,UAAU;AAClF;AAAA,IACF,KAAK;AACH,kBAAY,EAAE,GAAG,MAAM,MAAM,eAAe,QAAQ,QAAQ,OAAO;AACnE;AAAA,IACF,KAAK;AACH,kBAAY;AAAA,QACV,GAAG;AAAA,QACH,MAAM;AAAA,QACN,WAAW,QAAQ;AAAA,QACnB,YAAY,QAAQ;AAAA,QACpB,aAAa,QAAQ;AAAA,MACvB;AACA;AAAA,IACF,KAAK,eAAe;AAClB,YAAM,MAAM,oBAAoB,QAAQ,aAAa;AACrD,kBAAY;AAAA,QACV,GAAG;AAAA,QACH,MAAM;AAAA,QACN,WAAW,QAAQ;AAAA,QACnB,YAAY,QAAQ;AAAA,QACpB,eAAe,QAAQ;AAAA,QACvB,aAAa,QAAQ;AAAA,QACrB,aAAa,QAAQ;AAAA,QACrB,UAAU,IAAI;AAAA,QACd,eAAe,IAAI;AAAA,MACrB;AACA;AAAA,IACF;AAAA,IACA,KAAK;AACH,kBAAY;AAAA,QACV,GAAG;AAAA,QACH,MAAM;AAAA,QACN,wBAAwB,QAAQ;AAAA,QAChC,kBAAkB,QAAQ;AAAA,MAC5B;AACA;AAAA,IACF,KAAK;AACH,kBAAY;AAAA,QACV,GAAG;AAAA,QACH,MAAM;AAAA,QACN,UAAU,QAAQ;AAAA,QAClB,YAAY,QAAQ;AAAA,QACpB,uBAAuB,QAAQ;AAAA,QAC/B,wBAAwB,QAAQ;AAAA,QAChC,kBAAkB,QAAQ;AAAA,MAC5B;AACA;AAAA,IACF;AACE,aAAO,EAAE,MAAM,QAAQ,QAAQ,qBAAqB,QAAQ,GAAG;AAAA,EACnE;AAEA,QAAM,SAAS,aAAa,UAAU,SAAS;AAC/C,MAAI,CAAC,OAAO,SAAS;AACnB,WAAO,EAAE,MAAM,QAAQ,QAAQ,sBAAsB,OAAO,MAAM,OAAO,IAAI,CAAC,MAAM,EAAE,KAAK,KAAK,GAAG,IAAI,OAAO,EAAE,OAAO,EAAE,KAAK,IAAI,CAAC,GAAG;AAAA,EACxI;AACA,SAAO,EAAE,MAAM,SAAS,OAAO,OAAO,KAAK;AAC7C;;;ADxIA,IAAM,iBAAiB;AAOvB,SAAS,aAAa,UAAkB,YAA+B;AACrE,SAAO;AAAA,IACL,MAAM;AAAA,IACN,SAAS,GAAG,UAAU,iBAAiB,QAAQ;AAAA,IAC/C,CAAC,cAAc,GAAG;AAAA,EACpB;AACF;AAEA,eAAe,aAAa,MAAuC;AACjE,MAAI;AACF,UAAM,MAAM,MAAMC,UAAS,MAAM,MAAM;AACvC,WAAO,KAAK,MAAM,GAAG;AAAA,EACvB,SAAS,KAAK;AACZ,QAAK,IAA8B,SAAS,SAAU,QAAO,CAAC;AAC9D,UAAM;AAAA,EACR;AACF;AAEA,eAAe,cAAc,MAAc,MAAqC;AAC9E,QAAMC,OAAMC,SAAQ,IAAI,GAAG,EAAE,WAAW,KAAK,CAAC;AAC9C,QAAMC,WAAU,MAAM,KAAK,UAAU,MAAM,MAAM,CAAC,IAAI,IAAI;AAC5D;AAQA,eAAsB,aAAa,OAA2B,YAA4C;AACxG,QAAM,eAAe,MAAM,eAAe,KAAK;AAC/C,QAAM,aAAa,MAAM,qBAAqB,KAAK;AAGnD,MAAI;AACF,UAAM,SAAS,cAAc,UAAU;AAAA,EACzC,SAAS,KAAK;AACZ,QAAK,IAA8B,SAAS,SAAU,OAAM;AAAA,EAC9D;AAEA,QAAM,WAAW,MAAM,aAAa,YAAY;AAChD,WAAS,QAAQ,SAAS,SAAS,CAAC;AAEpC,QAAM,QAAkB,CAAC;AACzB,aAAW,YAAY,iBAAiB;AACtC,UAAM,WAAY,SAAS,MAAM,QAAQ,IAAI,SAAS,MAAM,QAAQ,KAAK,CAAC;AAE1E,QAAI,OAAO,SAAS,KAAK,CAAC,MAAM,EAAE,YAAY,GAAG;AACjD,QAAI,CAAC,MAAM;AACT,aAAO,EAAE,SAAS,KAAK,OAAO,CAAC,EAAE;AACjC,eAAS,KAAK,IAAI;AAAA,IACpB;AACA,SAAK,QAAQ,KAAK,SAAS,CAAC;AAC5B,UAAM,UAAU,KAAK,MAAM,KAAK,CAAC,MAAO,EAAgB,cAAc,MAAM,IAAI;AAChF,QAAI,CAAC,SAAS;AACZ,WAAK,MAAM,KAAK,aAAa,UAAU,UAAU,CAAC;AAClD,YAAM,KAAK,QAAQ;AAAA,IACrB;AAAA,EACF;AAEA,QAAM,cAAc,cAAc,QAAQ;AAC1C,SAAO,EAAE,cAAc,YAAY,YAAY,MAAM;AACvD;AAOA,eAAsB,eAAe,OAAqD;AACxF,QAAM,eAAe,MAAM,eAAe,KAAK;AAC/C,QAAM,WAAW,MAAM,aAAa,YAAY;AAChD,QAAM,UAAoB,CAAC;AAE3B,MAAI,SAAS,OAAO;AAClB,eAAW,YAAY,OAAO,KAAK,SAAS,KAAK,GAAG;AAClD,YAAM,WAAW,SAAS,MAAM,QAAQ;AACxC,iBAAW,WAAW,UAAU;AAC9B,YAAI,CAAC,MAAM,QAAQ,QAAQ,KAAK,EAAG;AACnC,cAAM,SAAS,QAAQ,MAAM;AAC7B,gBAAQ,QAAQ,QAAQ,MAAM,OAAO,CAAC,MAAO,EAAgB,cAAc,MAAM,IAAI;AACrF,YAAI,QAAQ,MAAM,SAAS,OAAQ,SAAQ,KAAK,QAAQ;AAAA,MAC1D;AAEA,eAAS,MAAM,QAAQ,IAAI,SAAS,OAAO,CAAC,MAAM,MAAM,QAAQ,EAAE,KAAK,KAAK,EAAE,MAAM,SAAS,CAAC;AAC9F,UAAI,SAAS,MAAM,QAAQ,EAAE,WAAW,EAAG,QAAO,SAAS,MAAM,QAAQ;AAAA,IAC3E;AACA,QAAI,OAAO,KAAK,SAAS,KAAK,EAAE,WAAW,EAAG,QAAO,SAAS;AAAA,EAChE;AAEA,QAAM,cAAc,cAAc,QAAQ;AAC1C,SAAO,EAAE,cAAc,cAAc,MAAM,KAAK,IAAI,IAAI,OAAO,CAAC,EAAE;AACpE;;;AExGA,SAAS,qBAAqB;AAC9B,SAAS,WAAAC,UAAS,SAAS,WAAW;AAM/B,SAAS,oBAA4B;AAC1C,MAAI,QAAQ,IAAI,gBAAiB,QAAO,QAAQ,IAAI;AAEpD,QAAM,QAAQ,QAAQ,KAAK,CAAC;AAC5B,MAAI,OAAO;AAMT,QAAI,MAAM,SAAS,GAAG,GAAG,eAAe,GAAG,EAAE,EAAG,QAAO;AACvD,QAAI;AACF,aAAO,QAAQ,KAAK;AAAA,IACtB,QAAQ;AAAA,IAER;AAAA,EACF;AAEA,SAAO;AACT;;;AHpBA,eAAsB,eAAe,MAA6D;AAChG,QAAM,MAAM,MAAM,WAAW;AAC7B,MAAI,CAAC,KAAK;AACR,YAAQ,OAAO,MAAM,6CAA6C;AAClE,WAAO;AAAA,EACT;AAEA,QAAM,QAA4B,KAAK,UAAU,YAAY;AAC7D,QAAM,aAAa,kBAAkB;AAErC,MAAI,CAAC,KAAK,KAAK;AACb,UAAM,KAAKC,iBAAgB,EAAE,OAAAC,QAAO,QAAAC,QAAO,CAAC;AAC5C,UAAM,UAAU,MAAM,GAAG,SAAS,8BAA8B,KAAK,sBAAsB,GAAG,KAAK,EAAE,YAAY;AACjH,OAAG,MAAM;AACT,QAAI,WAAW,OAAO,WAAW,OAAO;AACtC,cAAQ,OAAO,MAAM,YAAY;AACjC,aAAO;AAAA,IACT;AAAA,EACF;AAEA,QAAM,SAAS,MAAM,aAAa,OAAO,UAAU;AACnD,UAAQ,OAAO,MAAM,WAAW,OAAO,YAAY;AAAA,CAAI;AACvD,UAAQ,OAAO,MAAM,WAAW,OAAO,UAAU;AAAA,CAAI;AACrD,MAAI,OAAO,WAAW,WAAW,GAAG;AAClC,YAAQ,OAAO,MAAM,mDAA8C;AAAA,EACrE,OAAO;AACL,YAAQ,OAAO,MAAM,UAAU,OAAO,WAAW,KAAK,IAAI,CAAC;AAAA,CAAI;AAAA,EACjE;AACA,SAAO;AACT;;;AIjCA,eAAsB,iBAAiB,MAA8C;AACnF,QAAM,QAA4B,KAAK,UAAU,YAAY;AAC7D,QAAM,SAAS,MAAM,eAAe,KAAK;AACzC,MAAI,OAAO,aAAa,WAAW,GAAG;AACpC,YAAQ,OAAO,MAAM,6BAA6B,OAAO,YAAY;AAAA,CAAK;AAAA,EAC5E,OAAO;AACL,YAAQ,OAAO,MAAM,iCAAiC,OAAO,aAAa,KAAK,IAAI,CAAC;AAAA,CAAI;AAAA,EAC1F;AACA,SAAO;AACT;;;ACXA,SAAS,aAAa;;;ACAtB,SAAS,SAAAC,QAAO,YAAAC,WAAU,aAAAC,kBAAiB;AAC3C,SAAS,WAAAC,gBAAe;AAOxB,eAAsB,aAAa,WAAoC;AACrE,QAAM,OAAO,MAAM,QAAQ,SAAS;AACpC,QAAMC,OAAMC,SAAQ,IAAI,GAAG,EAAE,WAAW,KAAK,CAAC;AAE9C,MAAI,UAAU;AACd,MAAI;AACF,UAAM,MAAM,MAAMC,UAAS,MAAM,MAAM;AACvC,UAAM,SAAS,OAAO,SAAS,IAAI,KAAK,GAAG,EAAE;AAC7C,QAAI,OAAO,SAAS,MAAM,KAAK,UAAU,EAAG,WAAU;AAAA,EACxD,SAAS,KAAK;AACZ,QAAK,IAA8B,SAAS,SAAU,OAAM;AAAA,EAC9D;AAEA,QAAM,OAAO,UAAU;AACvB,QAAMC,WAAU,MAAM,OAAO,IAAI,CAAC;AAClC,SAAO,OAAO;AAChB;;;ACxBA,SAAS,YAAY,SAAAC,QAAO,YAAAC,WAAU,SAAS,aAAAC,YAAW,UAAAC,SAAQ,YAAY;AAQ9E,eAAsB,YAAY,WAAmB,OAAoC;AACvF,QAAMC,OAAM,MAAM,WAAW,EAAE,WAAW,KAAK,CAAC;AAChD,QAAM,OAAO,KAAK,UAAU,KAAK,IAAI;AACrC,QAAM,WAAW,MAAM,WAAW,SAAS,GAAG,MAAM,EAAE,UAAU,OAAO,CAAC;AAC1E;AAQA,eAAsB,uBAA0C;AAC9D,MAAI;AACJ,MAAI;AACF,cAAU,MAAM,QAAQ,MAAM,SAAS;AAAA,EACzC,SAAS,KAAK;AACZ,QAAK,IAA8B,SAAS,SAAU,QAAO,CAAC;AAC9D,UAAM;AAAA,EACR;AACA,SAAO,QAAQ,OAAO,CAAC,MAAM,EAAE,SAAS,SAAS,CAAC,EAAE,IAAI,CAAC,MAAM,EAAE,MAAM,GAAG,CAAC,UAAU,MAAM,CAAC;AAC9F;AAEA,eAAsB,oBAAoB,WAAoD;AAC5F,MAAI;AACJ,MAAI;AACF,UAAM,MAAMC,UAAS,MAAM,WAAW,SAAS,GAAG,MAAM;AAAA,EAC1D,SAAS,KAAK;AACZ,QAAK,IAA8B,SAAS,SAAU,QAAO;AAC7D,UAAM;AAAA,EACR;AACA,QAAM,QAAQ,IAAI,MAAM,IAAI,EAAE,OAAO,CAAC,MAAM,EAAE,SAAS,CAAC;AACxD,QAAM,SAAyB,CAAC;AAChC,aAAW,QAAQ,OAAO;AACxB,QAAI;AACF,aAAO,KAAK,KAAK,MAAM,IAAI,CAAiB;AAAA,IAC9C,QAAQ;AAAA,IAER;AAAA,EACF;AACA,SAAO,EAAE,WAAW,QAAQ,KAAK,MAAM;AACzC;AAIA,eAAsB,uBAAuB,WAAmB,gBAAyC;AACvG,QAAM,OAAO,MAAM,WAAW,SAAS;AACvC,MAAI,eAAe,WAAW,GAAG;AAC/B,QAAI;AACF,YAAMC,QAAO,IAAI;AAAA,IACnB,SAAS,KAAK;AACZ,UAAK,IAA8B,SAAS,SAAU,OAAM;AAAA,IAC9D;AACA;AAAA,EACF;AACA,QAAM,MAAM,OAAO;AACnB,QAAMC,WAAU,KAAK,eAAe,IAAI,CAAC,MAAM,IAAI,IAAI,EAAE,KAAK,EAAE,CAAC;AAEjE,QAAM,EAAE,OAAO,IAAI,MAAM,OAAO,aAAkB;AAClD,QAAM,OAAO,KAAK,IAAI;AACxB;AAEA,eAAsB,WAAW,WAAoC;AACnE,MAAI;AACF,UAAM,IAAI,MAAM,KAAK,MAAM,WAAW,SAAS,CAAC;AAChD,WAAO,EAAE;AAAA,EACX,SAAS,KAAK;AACZ,QAAK,IAA8B,SAAS,SAAU,QAAO;AAC7D,UAAM;AAAA,EACR;AACF;AAOA,eAAsB,cAAc,WAA2C;AAC7E,MAAI;AACF,UAAM,IAAI,MAAM,KAAK,MAAM,WAAW,SAAS,CAAC;AAChD,WAAO,EAAE;AAAA,EACX,SAAS,KAAK;AACZ,QAAK,IAA8B,SAAS,SAAU,QAAO;AAC7D,UAAM;AAAA,EACR;AACF;;;AC7FA,SAAS,SAAAC,QAAO,YAAAC,WAAU,aAAAC,kBAAiB;AAC3C,SAAS,WAAAC,gBAAe;AA0CxB,SAAS,MAAM,GAAoB;AACjC,MAAI,OAAO,MAAM,YAAY,OAAO,SAAS,CAAC,KAAK,KAAK,EAAG,QAAO,KAAK,MAAM,CAAC;AAC9E,SAAO;AACT;AAEA,SAAS,qBAAqB,SAAsC;AAElE,MAAI,CAAC,MAAM,QAAQ,OAAO,EAAG,QAAO;AACpC,QAAM,QAAkB,CAAC;AACzB,aAAW,SAAS,SAAS;AAC3B,QAAI,SAAS,OAAO,UAAU,YAAY,UAAU,OAAO;AACzD,YAAM,IAAI;AACV,UAAI,EAAE,SAAS,UAAU,OAAO,EAAE,SAAS,SAAU,OAAM,KAAK,EAAE,IAAI;AAAA,IACxE;AAAA,EACF;AACA,QAAM,SAAS,MAAM,KAAK,IAAI,EAAE,KAAK;AACrC,SAAO,WAAW,KAAK,SAAY;AACrC;AAKA,eAAsB,sBACpB,WACA,gBAC0D;AAC1D,QAAM,OAAO,MAAM,WAAW,SAAS;AAEvC,MAAI;AACJ,MAAI;AACF,UAAM,MAAMC,UAAS,gBAAgB,MAAM;AAAA,EAC7C,QAAQ;AACN,WAAO,EAAE,OAAO,CAAC,GAAG,KAAK;AAAA,EAC3B;AAEA,QAAM,QAA2B,CAAC;AAClC,aAAW,QAAQ,IAAI,MAAM,IAAI,GAAG;AAClC,UAAM,UAAU,KAAK,KAAK;AAC1B,QAAI,YAAY,GAAI;AACpB,QAAI;AACJ,QAAI;AACF,eAAS,KAAK,MAAM,OAAO;AAAA,IAC7B,QAAQ;AAGN;AAAA,IACF;AACA,QAAI,OAAO,SAAS,YAAa;AACjC,UAAM,OAAO,OAAO,OAAO,SAAS,WAAW,OAAO,OAAO;AAC7D,QAAI,SAAS,MAAM,KAAK,IAAI,IAAI,EAAG;AACnC,UAAM,MAAM,OAAO,WAAW,CAAC;AAC/B,UAAM,QAAQ,OAAO,IAAI,UAAU,WAAW,IAAI,QAAQ;AAC1D,QAAI,UAAU,GAAI;AAClB,UAAM,QAAQ,IAAI,SAAS,CAAC;AAC5B,UAAM,KAAK;AAAA,MACT,cAAc;AAAA,MACd;AAAA,MACA,cAAc,MAAM,MAAM,YAAY;AAAA,MACtC,eAAe,MAAM,MAAM,aAAa;AAAA,MACxC,mBAAmB,MAAM,MAAM,uBAAuB;AAAA,MACtD,uBAAuB,MAAM,MAAM,2BAA2B;AAAA,MAC9D,MAAM,qBAAqB,IAAI,OAAO;AAAA,IACxC,CAAC;AAAA,EACH;AAEA,SAAO,EAAE,OAAO,KAAK;AACvB;AAKA,IAAM,cAAc;AAEpB,eAAe,WAAW,WAAyC;AACjE,MAAI;AACF,UAAM,MAAM,MAAMA,UAAS,MAAM,qBAAqB,SAAS,GAAG,MAAM;AACxE,WAAO,IAAI;AAAA,MACT,IACG,MAAM,IAAI,EACV,IAAI,CAAC,MAAM,EAAE,KAAK,CAAC,EACnB,OAAO,CAAC,MAAM,MAAM,EAAE;AAAA,IAC3B;AAAA,EACF,QAAQ;AACN,WAAO,oBAAI,IAAI;AAAA,EACjB;AACF;AAEA,eAAsB,cACpB,WACA,MACA,cACe;AACf,aAAW,KAAK,aAAc,MAAK,IAAI,CAAC;AACxC,QAAM,OAAO,MAAM,qBAAqB,SAAS;AACjD,QAAMC,OAAMC,SAAQ,IAAI,GAAG,EAAE,WAAW,KAAK,CAAC;AAE9C,QAAM,MAAM,CAAC,GAAG,IAAI;AACpB,QAAM,UAAU,IAAI,SAAS,cAAc,IAAI,MAAM,IAAI,SAAS,WAAW,IAAI;AACjF,QAAMC,WAAU,MAAM,QAAQ,KAAK,IAAI,IAAI,IAAI;AACjD;;;AHrIA,eAAe,YAA6B;AAC1C,MAAI,QAAQ,MAAM,MAAO,QAAO;AAChC,QAAM,SAAmB,CAAC;AAC1B,mBAAiB,SAAS,QAAQ,OAAO;AACvC,WAAO,KAAK,OAAO,SAAS,KAAK,IAAI,QAAQ,OAAO,KAAK,KAAK,CAAC;AAAA,EACjE;AACA,SAAO,OAAO,OAAO,MAAM,EAAE,SAAS,MAAM;AAC9C;AAEA,SAAS,aAAa,YAA0B;AAG9C,QAAM,QAAQ,MAAM,YAAY,CAAC,oBAAoB,GAAG;AAAA,IACtD,UAAU;AAAA,IACV,OAAO;AAAA,IACP,KAAK,QAAQ;AAAA,EACf,CAAC;AACD,QAAM,MAAM;AACd;AAEA,eAAsB,YAAY,MAA0C;AAG1E,MAAI;AACF,UAAM,MAAM,MAAM,WAAW;AAC7B,QAAI,CAAC,KAAK;AACR,cAAQ,OAAO,MAAM,gDAA2C;AAChE,aAAO;AAAA,IACT;AAEA,UAAM,MAAM,MAAM,UAAU;AAC5B,QAAI,CAAC,IAAI,KAAK,GAAG;AAEf,aAAO;AAAA,IACT;AAEA,QAAI;AACJ,QAAI;AACF,gBAAU,KAAK,MAAM,GAAG;AAAA,IAC1B,SAAS,KAAK;AACZ,cAAQ,OAAO,MAAM,mCAAmC,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC;AAAA,CAAI;AAC5G,aAAO;AAAA,IACT;AAEA,UAAM,YAAY,OAAO,QAAQ,eAAe,WAAW,QAAQ,aAAa;AAChF,QAAI,CAAC,WAAW;AACd,cAAQ,OAAO,MAAM,+CAA+C;AACpE,aAAO;AAAA,IACT;AAEA,UAAM,WAAW,MAAM,aAAa,SAAS;AAC7C,UAAM,SAAS,eAAe,KAAK,OAAO,SAAS;AAAA,MACjD,UAAS,oBAAI,KAAK,GAAE,YAAY;AAAA,MAChC;AAAA,IACF,CAAC;AAED,QAAI,OAAO,SAAS,QAAQ;AAE1B,cAAQ,OAAO,MAAM,oBAAoB,KAAK,KAAK,KAAK,OAAO,MAAM;AAAA,CAAI;AACzE,aAAO;AAAA,IACT;AAEA,UAAM,YAAY,WAAW,OAAO,KAAK;AAMzC,QAAI,KAAK,UAAU,iBAAiB,KAAK,UAAU,UAAU,KAAK,UAAU,gBAAgB;AAC1F,YAAM,iBAAiB,OAAO,QAAQ,oBAAoB,WAAW,QAAQ,kBAAkB;AAC/F,UAAI,mBAAmB,IAAI;AACzB,YAAI;AACF,gBAAM,EAAE,OAAO,KAAK,IAAI,MAAM,sBAAsB,WAAW,cAAc;AAC7E,gBAAM,eAAyB,CAAC;AAChC,qBAAW,KAAK,OAAO;AACrB,kBAAM,MAAM,MAAM,aAAa,SAAS;AACxC,kBAAM,KAAmB;AAAA,cACvB,MAAM;AAAA,cACN,YAAY;AAAA,cACZ,iBAAiB;AAAA,cACjB,KAAK,OAAO,QAAQ,QAAQ,WAAW,QAAQ,MAAM;AAAA,cACrD,iBAAiB,KAAK;AAAA,cACtB,iBAAiB,OAAO,QAAQ,oBAAoB,WAAW,QAAQ,kBAAkB;AAAA,cACzF,UAAS,oBAAI,KAAK,GAAE,YAAY;AAAA,cAChC,UAAU;AAAA,cACV,cAAc,EAAE;AAAA,cAChB,OAAO,EAAE;AAAA,cACT,cAAc,EAAE;AAAA,cAChB,eAAe,EAAE;AAAA,cACjB,mBAAmB,EAAE;AAAA,cACrB,uBAAuB,EAAE;AAAA,cACzB,MAAM,EAAE;AAAA,YACV;AACA,kBAAM,YAAY,WAAW,EAAE;AAC/B,yBAAa,KAAK,EAAE,YAAY;AAAA,UAClC;AACA,cAAI,aAAa,SAAS,GAAG;AAC3B,kBAAM,cAAc,WAAW,MAAM,YAAY;AAAA,UACnD;AAAA,QACF,SAAS,KAAK;AAEZ,kBAAQ,OAAO,MAAM,oCAAoC,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC;AAAA,CAAI;AAAA,QAC/G;AAAA,MACF;AAAA,IACF;AAEA,iBAAa,kBAAkB,CAAC;AAChC,WAAO;AAAA,EACT,SAAS,KAAK;AACZ,YAAQ,OAAO,MAAM,wBAAwB,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC;AAAA,CAAI;AACjG,WAAO;AAAA,EACT;AACF;;;AIzHA,SAAS,YAAAC,iBAAgB;AAMzB,eAAe,iBAAyC;AACtD,MAAI;AACF,UAAM,MAAM,MAAMC,UAAS,MAAM,YAAY,MAAM;AACnD,UAAM,IAAI,OAAO,SAAS,IAAI,KAAK,GAAG,EAAE;AACxC,WAAO,OAAO,SAAS,CAAC,IAAI,IAAI;AAAA,EAClC,SAAS,KAAK;AACZ,QAAK,IAA8B,SAAS,SAAU,QAAO;AAC7D,UAAM;AAAA,EACR;AACF;AAEA,eAAsB,gBAAiC;AACrD,QAAM,MAAM,MAAM,WAAW;AAC7B,MAAI,CAAC,KAAK;AACR,YAAQ,OAAO,MAAM,uCAAuC;AAC5D,WAAO;AAAA,EACT;AAEA,UAAQ,OAAO,MAAM,WAAW,IAAI,UAAU;AAAA,CAAI;AAClD,UAAQ,OAAO,MAAM,YAAY,IAAI,QAAQ,MAAM,GAAG,CAAC,CAAC,SAAI,IAAI,QAAQ,MAAM,EAAE,CAAC;AAAA,CAAI;AAErF,QAAM,OAAO,MAAM,YAAY,IAAI,YAAY,IAAI,OAAO;AAC1D,UAAQ,OAAO,MAAM,cAAc,KAAK,KAAK,QAAQ,OAAO,KAAK,UAAU,KAAK,MAAM,GAAG;AAAA,CAAI;AAE7F,QAAM,WAAW,MAAM,qBAAqB;AAC5C,MAAI,SAAS,WAAW,GAAG;AACzB,YAAQ,OAAO,MAAM,kBAAkB;AAAA,EACzC,OAAO;AACL,YAAQ,OAAO,MAAM,WAAW,SAAS,MAAM;AAAA,CAAwB;AACvE,eAAW,KAAK,UAAU;AACxB,YAAM,OAAO,MAAM,WAAW,CAAC;AAC/B,YAAM,QAAQ,MAAM,cAAc,CAAC;AACnC,YAAM,SAAS,QAAQ,KAAK,OAAO,KAAK,IAAI,IAAI,SAAS,GAAI,IAAI;AACjE,cAAQ,OAAO,MAAM,KAAK,CAAC,KAAK,IAAI,SAAS,WAAW,OAAO,aAAa,MAAM,UAAU,EAAE;AAAA,CAAI;AAAA,IACpG;AAAA,EACF;AAEA,QAAM,aAAa,MAAM,eAAe;AACxC,MAAI,eAAe,MAAM;AACvB,YAAQ,OAAO,MAAM,gBAAgB,UAAU;AAAA,CAAI;AAAA,EACrD,OAAO;AACL,YAAQ,OAAO,MAAM,yBAAyB;AAAA,EAChD;AAEA,SAAO;AACT;;;ACnDA,SAAS,SAAAC,cAAa;AACtB,SAAS,gBAAgB;AAGzB,SAAS,cAA+C;AAGtD,MAAI,aAAa,SAAU,QAAO,EAAE,KAAK,QAAQ,MAAM,CAAC,EAAE;AAC1D,MAAI,aAAa,QAAS,QAAO,EAAE,KAAK,OAAO,MAAM,CAAC,MAAM,SAAS,EAAE,EAAE;AACzE,SAAO,EAAE,KAAK,YAAY,MAAM,CAAC,EAAE;AACrC;AAEA,eAAsB,cAA+B;AACnD,QAAM,MAAM,MAAM,WAAW;AAC7B,MAAI,CAAC,KAAK;AACR,YAAQ,OAAO,MAAM,6CAA6C;AAClE,WAAO;AAAA,EACT;AAEA,QAAM,MAAM,GAAG,IAAI,WAAW,QAAQ,OAAO,EAAE,CAAC;AAChD,QAAM,EAAE,KAAK,KAAK,IAAI,YAAY;AAElC,QAAM,QAAQC,OAAM,KAAK,CAAC,GAAG,MAAM,GAAG,GAAG,EAAE,OAAO,UAAU,UAAU,KAAK,CAAC;AAC5E,QAAM,GAAG,SAAS,CAAC,QAAQ;AACzB,YAAQ,OAAO,MAAM,6BAA6B,IAAI,OAAO;AAAA,EAA2B,GAAG;AAAA,CAAI;AAAA,EACjG,CAAC;AACD,QAAM,MAAM;AAEZ,UAAQ,OAAO,MAAM,WAAW,GAAG;AAAA,CAAI;AACvC,SAAO;AACT;;;AC9BA,SAAS,SAAAC,cAAa;AACtB,SAAS,YAAAC,iBAAgB;AACzB,SAAS,mBAAAC,wBAAuB;AAChC,SAAS,SAASC,QAAO,UAAUC,eAAc;AAMjD,SAASC,eAA+C;AACtD,MAAIC,cAAa,SAAU,QAAO,EAAE,KAAK,QAAQ,MAAM,CAAC,EAAE;AAC1D,MAAIA,cAAa,QAAS,QAAO,EAAE,KAAK,OAAO,MAAM,CAAC,MAAM,SAAS,EAAE,EAAE;AACzE,SAAO,EAAE,KAAK,YAAY,MAAM,CAAC,EAAE;AACrC;AAEA,SAAS,cAAc,KAAmB;AACxC,QAAM,EAAE,KAAK,KAAK,IAAID,aAAY;AAClC,QAAM,QAAQE,OAAM,KAAK,CAAC,GAAG,MAAM,GAAG,GAAG,EAAE,OAAO,UAAU,UAAU,KAAK,CAAC;AAC5E,QAAM,GAAG,SAAS,MAAM;AAAA,EAExB,CAAC;AACD,QAAM,MAAM;AACd;AAEA,eAAe,YAAY,IAAiD,UAAkB,YAAuC;AACnI,QAAM,SAAS,aAAa,UAAU;AACtC,QAAM,UAAU,MAAM,GAAG,SAAS,GAAG,QAAQ,IAAI,MAAM,GAAG,GAAG,KAAK,EAAE,YAAY;AAChF,MAAI,WAAW,GAAI,QAAO;AAC1B,SAAO,WAAW,OAAO,WAAW;AACtC;AAEA,eAAsB,aAAa,MAAgD;AACjF,QAAM,KAAKC,iBAAgB,EAAE,OAAAC,QAAO,QAAAC,QAAO,CAAC;AAE5C,MAAI;AACF,YAAQ,OAAO,MAAM,mBAAmB;AACxC,YAAQ,OAAO,MAAM,6CAA8C;AACnE,YAAQ,OAAO,MAAM,4EAA4E;AAGjG,UAAM,WAAW,MAAM,WAAW;AAClC,QAAI,UAAU;AACZ,cAAQ,OAAO,MAAM,wBAAwB,SAAS,UAAU;AAAA,CAAI;AACpE,cAAQ,OAAO,MAAM,aAAa,SAAS,QAAQ,MAAM,GAAG,CAAC,CAAC,SAAI,SAAS,QAAQ,MAAM,EAAE,CAAC;AAAA,CAAI;AAChG,YAAM,cAAc,MAAM,YAAY,IAAI,gBAAgB,KAAK;AAC/D,UAAI,CAAC,aAAa;AAChB,gBAAQ,OAAO,MAAM,8DAA8D;AACnF,eAAO,MAAM,iBAAiB,IAAI,SAAS,UAAU;AAAA,MACvD;AAAA,IACF;AAGA,UAAM,eAAe,iBAAiB;AACtC,YAAQ,OAAO,MAAM;AAAA,CAAsB;AAC3C,UAAM,YAAY,MAAM,GAAG,SAAS,eAAe,YAAY,yBAAyB,GAAG,KAAK;AAChG,UAAM,YAAY,aAAa,KAAK,eAAe;AAGnD,UAAM,eAAe,GAAG,UAAU,QAAQ,OAAO,EAAE,CAAC;AACpD,YAAQ,OAAO,MAAM;AAAA;AAAA,CAAwB;AAC7C,YAAQ,OAAO,MAAM;AAAA,IAA2C,YAAY;AAAA,CAAI;AAChF,QAAI,CAAC,KAAK,WAAW;AACnB,oBAAc,YAAY;AAC1B,cAAQ,OAAO,MAAM,4BAA4B;AAAA,IACnD;AAGA,UAAM,UAAU,MAAM,GAAG,SAAS,qCAAgC,GAAG,KAAK;AAC1E,UAAM,aAAa,OAAO,MAAM,QAAQ,UAAU,MAAM;AACxD,QAAI,CAAC,WAAW,SAAS;AACvB,cAAQ,OAAO,MAAM;AAAA;AAAA,CAA0D;AAC/E,aAAO;AAAA,IACT;AAEA,YAAQ,OAAO,MAAM,sBAAsB,SAAS;AAAA,CAAK;AACzD,UAAM,OAAO,MAAM,YAAY,WAAW,MAAM;AAChD,QAAI,CAAC,KAAK,IAAI;AACZ,cAAQ,OAAO;AAAA,QACb;AAAA,gBAAmB,KAAK,WAAW,MAAM,oBAAoB,KAAK,UAAU,oBAAoB;AAAA;AAAA,MAClG;AACA,aAAO;AAAA,IACT;AAEA,UAAM,YAAY,EAAE,SAAS,QAAQ,YAAY,UAAU,CAAC;AAC5D,YAAQ,OAAO,MAAM,sBAAsB;AAG3C,WAAO,MAAM,iBAAiB,IAAI,SAAS;AAAA,EAC7C,UAAE;AACA,OAAG,MAAM;AAAA,EACX;AACF;AAEA,eAAe,iBACb,IACA,WACiB;AACjB,UAAQ,OAAO,MAAM;AAAA;AAAA,CAAkC;AACvD,QAAM,UAAU,MAAM;AAAA,IACpB;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAEA,MAAI,CAAC,SAAS;AACZ,YAAQ,OAAO,MAAM,6DAA6D;AAClF,WAAO;AAAA,EACT;AAEA,QAAM,aAAa,kBAAkB;AACrC,QAAM,SAAS,MAAM,aAAa,QAAQ,UAAU;AACpD,UAAQ,OAAO,MAAM,WAAW,OAAO,YAAY;AAAA,CAAI;AACvD,MAAI,OAAO,WAAW,WAAW,GAAG;AAClC,YAAQ,OAAO,MAAM,mDAA8C;AAAA,EACrE,OAAO;AACL,YAAQ,OAAO,MAAM,UAAU,OAAO,WAAW,KAAK,IAAI,CAAC;AAAA,CAAI;AAAA,EACjE;AAEA,UAAQ,OAAO,MAAM,qBAAqB;AAC1C,UAAQ,OAAO,MAAM,kFAAkF;AACvG,UAAQ,OAAO,MAAM,KAAK,UAAU,QAAQ,OAAO,EAAE,CAAC;AAAA;AAAA,CAAgB;AACtE,SAAO;AACT;;;AC1HA,SAAS,cAAAC,aAAY,SAAAC,QAAO,YAAAC,WAAU,UAAAC,SAAQ,aAAAC,kBAAiB;AAC/D,SAAS,WAAAC,gBAAe;AAMxB,IAAM,mBAAmB;AACzB,IAAM,eAAe;AACrB,IAAM,YAAY;AAClB,IAAM,mBAAmB,CAAC,KAAM,KAAM,KAAM,KAAM,MAAQ,MAAQ,GAAM;AAExE,eAAe,IAAI,MAA6B;AAC9C,MAAI;AACF,UAAMC,OAAMC,SAAQ,MAAM,UAAU,GAAG,EAAE,WAAW,KAAK,CAAC;AAC1D,UAAMC,YAAW,MAAM,YAAY,IAAG,oBAAI,KAAK,GAAE,YAAY,CAAC,IAAI,IAAI;AAAA,CAAI;AAAA,EAC5E,QAAQ;AAAA,EAER;AACF;AAEA,eAAe,eAAe,KAA+B;AAC3D,MAAI;AACF,YAAQ,KAAK,KAAK,CAAC;AACnB,WAAO;AAAA,EACT,SAAS,KAAK;AACZ,QAAK,IAA8B,SAAS,QAAS,QAAO;AAC5D,QAAK,IAA8B,SAAS,QAAS,QAAO;AAC5D,WAAO;AAAA,EACT;AACF;AAGA,eAAsB,iBAAmC;AACvD,QAAMF,OAAMC,SAAQ,MAAM,UAAU,GAAG,EAAE,WAAW,KAAK,CAAC;AAC1D,MAAI;AACF,UAAM,WAAW,MAAME,UAAS,MAAM,YAAY,MAAM;AACxD,UAAM,MAAM,OAAO,SAAS,SAAS,KAAK,GAAG,EAAE;AAC/C,QAAI,OAAO,SAAS,GAAG,KAAM,MAAM,eAAe,GAAG,GAAI;AACvD,aAAO;AAAA,IACT;AAAA,EACF,SAAS,KAAK;AACZ,QAAK,IAA8B,SAAS,SAAU,OAAM;AAAA,EAC9D;AACA,QAAMC,WAAU,MAAM,YAAY,OAAO,QAAQ,GAAG,CAAC;AACrD,SAAO;AACT;AAEA,eAAe,iBAAgC;AAC7C,MAAI;AACF,UAAMC,QAAO,MAAM,UAAU;AAAA,EAC/B,QAAQ;AAAA,EAER;AACF;AAEA,SAAS,MAAM,IAA2B;AACxC,SAAO,IAAI,QAAQ,CAACC,aAAY,WAAWA,UAAS,EAAE,CAAC;AACzD;AAIA,eAAe,aAAa,WAAmB,WAAmB,QAAkC;AAClG,QAAM,WAAW,MAAM,oBAAoB,SAAS;AACpD,MAAI,CAAC,YAAY,SAAS,OAAO,WAAW,GAAG;AAC7C,UAAM,uBAAuB,WAAW,CAAC,CAAC;AAC1C,WAAO;AAAA,EACT;AAEA,MAAI,SAAS;AACb,MAAI,aAAa;AACjB,SAAO,SAAS,SAAS,OAAO,QAAQ;AACtC,UAAM,QAAQ,SAAS,OAAO,MAAM,QAAQ,SAAS,SAAS;AAC9D,UAAM,SAAS,MAAM,WAAW,WAAW,QAAQ,KAAK;AAExD,QAAI,OAAO,IAAI;AACb,gBAAU,MAAM;AAChB,mBAAa;AACb;AAAA,IACF;AAEA,QAAI,CAAC,OAAO,WAAW;AAErB,YAAM,IAAI,uBAAuB,SAAS,WAAW,OAAO,MAAM,UAAU,OAAO,MAAM,MAAM,GAAG,GAAG,CAAC,EAAE;AACxG,gBAAU,MAAM;AAChB,mBAAa;AACb;AAAA,IACF;AAGA,UAAM,IAAI,qBAAqB,SAAS,WAAW,OAAO,MAAM,WAAW,MAAM,UAAU,OAAO,MAAM,MAAM,GAAG,GAAG,CAAC,EAAE;AACvH;AAAA,EACF;AAEA,QAAM,YAAY,SAAS,IAAI,MAAM,MAAM;AAC3C,QAAM,uBAAuB,WAAW,SAAS;AACjD,SAAO;AACT;AAEA,eAAsB,aAA4B;AAChD,QAAM,WAAW,MAAM,eAAe;AACtC,MAAI,CAAC,UAAU;AACb,UAAM,IAAI,sBAAsB;AAChC;AAAA,EACF;AAEA,QAAM,IAAI,aAAa,QAAQ,GAAG,EAAE;AAEpC,MAAI,iBAAiB,KAAK,IAAI;AAC9B,MAAI,aAAa;AAEjB,MAAI;AACF,WAAO,MAAM;AACX,YAAM,MAAM,MAAM,WAAW;AAC7B,UAAI,CAAC,KAAK;AAER,cAAM,IAAI,gBAAgB;AAC1B;AAAA,MACF;AAEA,YAAM,WAAW,MAAM,qBAAqB;AAC5C,UAAI,mBAAmB;AACvB,iBAAW,aAAa,UAAU;AAChC,cAAM,UAAU,MAAM,aAAa,WAAW,IAAI,YAAY,IAAI,OAAO;AACzE,2BAAmB,oBAAoB;AAAA,MACzC;AAEA,UAAI,kBAAkB;AACpB,yBAAiB,KAAK,IAAI;AAC1B,qBAAa;AAAA,MACf;AAGA,YAAM,YAAY,MAAM,qBAAqB;AAC7C,YAAM,SAAS,KAAK,IAAI,IAAI;AAC5B,UAAI,UAAU,WAAW,KAAK,UAAU,cAAc;AACpD,cAAM,IAAI,qBAAqB,MAAM,EAAE;AACvC;AAAA,MACF;AAIA,YAAM,OACJ,UAAU,SAAS,KAAK,CAAC,mBACrB,iBAAiB,KAAK,IAAI,cAAc,iBAAiB,SAAS,CAAC,CAAC,IACpE;AACN,YAAM,MAAM,IAAI;AAAA,IAClB;AAAA,EACF,SAAS,KAAK;AACZ,UAAM,IAAI,eAAe,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC,EAAE;AAC3E,UAAM;AAAA,EACR,UAAE;AACA,UAAM,eAAe;AAAA,EACvB;AACF;;;AlB3IA,IAAM,UAAUC,MAAKC,SAAQC,eAAc,YAAY,GAAG,CAAC,GAAG,MAAM,cAAc;AAClF,IAAM,cAAe,KAAK,MAAM,aAAa,SAAS,MAAM,CAAC,EAA0B;AAIvF,IAAI,QAAQ,KAAK,SAAS,oBAAoB,GAAG;AAC/C,OAAK,WAAW,EAAE;AAAA,IAChB,MAAM,QAAQ,KAAK,CAAC;AAAA,IACpB,CAAC,QAAiB;AAChB,cAAQ,MAAM,GAAG;AACjB,cAAQ,KAAK,CAAC;AAAA,IAChB;AAAA,EACF;AACF,OAAO;AACL,QAAM,UAAU,IAAI,QAAQ;AAE5B,UACG,KAAK,SAAS,EACd,YAAY,uCAAuC,EACnD,QAAQ,WAAW;AAEtB,UACG,QAAQ,OAAO,EACf,YAAY,gEAAgE,EAC5E,OAAO,gBAAgB,4CAA4C,EACnE,OAAO,OAAO,SAAS,QAAQ,KAAK,MAAM,aAAa,IAAI,CAAC,CAAC;AAEhE,UACG,QAAQ,OAAO,EACf,YAAY,oEAAoE,EAChF,OAAO,mBAAmB,2BAA2B,EACrD,OAAO,0BAA0B,qBAAqB,EACtD,OAAO,OAAO,SAAS,QAAQ,KAAK,MAAM,aAAa,IAAI,CAAC,CAAC;AAEhE,UACG,QAAQ,QAAQ,EAChB,YAAY,2BAA2B,EACvC,OAAO,YAAY,QAAQ,KAAK,MAAM,cAAc,CAAC,CAAC;AAEzD,UACG,QAAQ,SAAS,EACjB,YAAY,iFAAiF,EAC7F,OAAO,aAAa,4DAA4D,EAChF,OAAO,aAAa,8BAA8B,EAClD,OAAO,OAAO,SAAS,QAAQ,KAAK,MAAM,eAAe,IAAI,CAAC,CAAC;AAElE,UACG,QAAQ,WAAW,EACnB,YAAY,4CAA4C,EACxD,OAAO,aAAa,0DAA0D,EAC9E,OAAO,OAAO,SAAS,QAAQ,KAAK,MAAM,iBAAiB,IAAI,CAAC,CAAC;AAEpE,UACG,QAAQ,MAAM,EACd,YAAY,2EAA2E,EACvF,eAAe,kBAAkB,4DAAuD,EACxF,OAAO,OAAO,SAAS,QAAQ,KAAK,MAAM,YAAY,IAAI,CAAC,CAAC;AAE/D,UACG,QAAQ,QAAQ,EAChB,YAAY,4DAA4D,EACxE,OAAO,YAAY,QAAQ,KAAK,MAAM,cAAc,CAAC,CAAC;AAEzD,UACG,QAAQ,MAAM,EACd,YAAY,qDAAqD,EACjE,OAAO,YAAY,QAAQ,KAAK,MAAM,YAAY,CAAC,CAAC;AAEvD,UAAQ,WAAW,QAAQ,IAAI,EAAE,MAAM,CAAC,QAAQ;AAC9C,YAAQ,MAAM,GAAG;AACjB,YAAQ,KAAK,CAAC;AAAA,EAChB,CAAC;AACH;","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","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"]}