runtape 0.1.0 → 0.1.1
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/README.md +13 -4
- package/dist/index.js +120 -1
- package/dist/index.js.map +1 -1
- package/dist/types.d.ts +48 -48
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -18,15 +18,24 @@ npm install -g runtape
|
|
|
18
18
|
|
|
19
19
|
## Get started
|
|
20
20
|
|
|
21
|
+
One command walks you through the whole setup:
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
runtape setup
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
It asks for your backend (defaults to `https://runtape.dev`), opens the dashboard so you can copy your API key, then installs the Claude Code hooks.
|
|
28
|
+
|
|
29
|
+
After setup, run Claude Code normally and your sessions stream to the dashboard.
|
|
30
|
+
|
|
21
31
|
```bash
|
|
22
|
-
runtape login # paste the API key from your runtape.dev dashboard
|
|
23
|
-
runtape install # add hooks to ~/.claude/settings.json
|
|
24
|
-
# …run Claude Code normally…
|
|
25
|
-
runtape runs # open your dashboard in the browser
|
|
26
32
|
runtape status # buffer state, server reachability, flusher PID
|
|
33
|
+
runtape runs # open your dashboard in the browser
|
|
27
34
|
runtape uninstall # remove the hooks when you're done
|
|
28
35
|
```
|
|
29
36
|
|
|
37
|
+
If you prefer the granular commands instead of the wizard, `runtape login` and `runtape install` are still available — `setup` is just a convenience that chains them.
|
|
38
|
+
|
|
30
39
|
## How it works
|
|
31
40
|
|
|
32
41
|
`runtape install` adds entries to `~/.claude/settings.json` so that Claude Code fires `runtape push --event <HookName>` on every relevant hook event. When installed under any `node_modules` tree (npm-global, pnpm-workspace, etc.), the entry uses the bare command name `runtape` so it survives package upgrades; when run from source (e.g. `tsx bin/runtape.ts` during local development) it uses the absolute path from `process.argv[1]`. Override with the `RUNTAPE_CLI_BIN` env var if you need a specific path. Each invocation appends one validated JSON line to `~/.runtape/buffer/<session_id>.ndjson` (sub-10ms) and lazily spawns a detached flusher daemon. The daemon batches events (up to 100 per POST) and ships them to the backend with exponential backoff on transient failures. It exits after 30s of idle.
|
package/dist/index.js
CHANGED
|
@@ -3,6 +3,9 @@ import {
|
|
|
3
3
|
} from "./chunk-Q4RSBPGN.js";
|
|
4
4
|
|
|
5
5
|
// src/index.ts
|
|
6
|
+
import { readFileSync } from "fs";
|
|
7
|
+
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
8
|
+
import { dirname as dirname6, join as join2 } from "path";
|
|
6
9
|
import { Command } from "commander";
|
|
7
10
|
|
|
8
11
|
// src/commands/login.ts
|
|
@@ -609,6 +612,119 @@ ${url}
|
|
|
609
612
|
return 0;
|
|
610
613
|
}
|
|
611
614
|
|
|
615
|
+
// src/commands/setup.ts
|
|
616
|
+
import { spawn as spawn3 } from "child_process";
|
|
617
|
+
import { platform as platform2 } from "process";
|
|
618
|
+
import { createInterface as createInterface3 } from "readline/promises";
|
|
619
|
+
import { stdin as input3, stdout as output3 } from "process";
|
|
620
|
+
function openCommand2() {
|
|
621
|
+
if (platform2 === "darwin") return { cmd: "open", args: [] };
|
|
622
|
+
if (platform2 === "win32") return { cmd: "cmd", args: ["/c", "start", ""] };
|
|
623
|
+
return { cmd: "xdg-open", args: [] };
|
|
624
|
+
}
|
|
625
|
+
function openInBrowser(url) {
|
|
626
|
+
const { cmd, args } = openCommand2();
|
|
627
|
+
const child = spawn3(cmd, [...args, url], { stdio: "ignore", detached: true });
|
|
628
|
+
child.on("error", () => {
|
|
629
|
+
});
|
|
630
|
+
child.unref();
|
|
631
|
+
}
|
|
632
|
+
async function promptYesNo(rl, question, defaultYes) {
|
|
633
|
+
const suffix = defaultYes ? "(Y/n)" : "(y/N)";
|
|
634
|
+
const answer = (await rl.question(`${question} ${suffix} `)).trim().toLowerCase();
|
|
635
|
+
if (answer === "") return defaultYes;
|
|
636
|
+
return answer === "y" || answer === "yes";
|
|
637
|
+
}
|
|
638
|
+
async function setupCommand(opts) {
|
|
639
|
+
const rl = createInterface3({ input: input3, output: output3 });
|
|
640
|
+
try {
|
|
641
|
+
process.stdout.write("\nRuntape setup\n");
|
|
642
|
+
process.stdout.write("Let's get your Claude Code runs captured.\n\n");
|
|
643
|
+
const existing = await readConfig();
|
|
644
|
+
if (existing) {
|
|
645
|
+
process.stdout.write(`Already logged in to ${existing.server_url}
|
|
646
|
+
`);
|
|
647
|
+
process.stdout.write(`API key: ${existing.api_key.slice(0, 8)}\u2026${existing.api_key.slice(-4)}
|
|
648
|
+
`);
|
|
649
|
+
const reconfigure = await promptYesNo(rl, "Reconfigure?", false);
|
|
650
|
+
if (!reconfigure) {
|
|
651
|
+
process.stdout.write("\nKeeping existing credentials. Moving on to hook install.\n");
|
|
652
|
+
return await installAndFinish(rl, existing.server_url);
|
|
653
|
+
}
|
|
654
|
+
}
|
|
655
|
+
const suggestedUrl = defaultServerUrl();
|
|
656
|
+
process.stdout.write(`Step 1/3 \u2014 Backend
|
|
657
|
+
`);
|
|
658
|
+
const urlInput = (await rl.question(`Server URL [${suggestedUrl}]: `)).trim();
|
|
659
|
+
const serverUrl = urlInput === "" ? suggestedUrl : urlInput;
|
|
660
|
+
const dashboardUrl = `${serverUrl.replace(/\/$/, "")}/dashboard`;
|
|
661
|
+
process.stdout.write(`
|
|
662
|
+
Step 2/3 \u2014 API key
|
|
663
|
+
`);
|
|
664
|
+
process.stdout.write(`Your API key lives in the dashboard:
|
|
665
|
+
${dashboardUrl}
|
|
666
|
+
`);
|
|
667
|
+
if (!opts.noBrowser) {
|
|
668
|
+
openInBrowser(dashboardUrl);
|
|
669
|
+
process.stdout.write("(opened in your browser)\n");
|
|
670
|
+
}
|
|
671
|
+
const apiKey = (await rl.question("\nPaste your API key (rtk_\u2026): ")).trim();
|
|
672
|
+
const validation = Config.shape.api_key.safeParse(apiKey);
|
|
673
|
+
if (!validation.success) {
|
|
674
|
+
process.stderr.write(`
|
|
675
|
+
Invalid API key format. Expected rtk_<64 hex chars>.
|
|
676
|
+
`);
|
|
677
|
+
return 2;
|
|
678
|
+
}
|
|
679
|
+
process.stdout.write(`Validating against ${serverUrl}\u2026
|
|
680
|
+
`);
|
|
681
|
+
const ping = await pingProject(serverUrl, apiKey);
|
|
682
|
+
if (!ping.ok) {
|
|
683
|
+
process.stderr.write(
|
|
684
|
+
`
|
|
685
|
+
Login failed: ${ping.status === 401 ? "unknown API key" : ping.detail ?? "server unreachable"}
|
|
686
|
+
`
|
|
687
|
+
);
|
|
688
|
+
return 1;
|
|
689
|
+
}
|
|
690
|
+
await writeConfig({ api_key: apiKey, server_url: serverUrl });
|
|
691
|
+
process.stdout.write("Credentials saved.\n");
|
|
692
|
+
return await installAndFinish(rl, serverUrl);
|
|
693
|
+
} finally {
|
|
694
|
+
rl.close();
|
|
695
|
+
}
|
|
696
|
+
}
|
|
697
|
+
async function installAndFinish(rl, serverUrl) {
|
|
698
|
+
process.stdout.write(`
|
|
699
|
+
Step 3/3 \u2014 Claude Code hooks
|
|
700
|
+
`);
|
|
701
|
+
const install = await promptYesNo(
|
|
702
|
+
rl,
|
|
703
|
+
"Install Runtape hooks into ~/.claude/settings.json now?",
|
|
704
|
+
true
|
|
705
|
+
);
|
|
706
|
+
if (!install) {
|
|
707
|
+
process.stdout.write("\nSkipped hook install. Run `runtape install` when ready.\n");
|
|
708
|
+
return 0;
|
|
709
|
+
}
|
|
710
|
+
const cliBinPath = resolveCliBinPath();
|
|
711
|
+
const result = await installHooks("user", cliBinPath);
|
|
712
|
+
process.stdout.write(`Updated ${result.settingsPath}
|
|
713
|
+
`);
|
|
714
|
+
if (result.addedHooks.length === 0) {
|
|
715
|
+
process.stdout.write("Hooks already installed \u2014 nothing changed.\n");
|
|
716
|
+
} else {
|
|
717
|
+
process.stdout.write(`Added: ${result.addedHooks.join(", ")}
|
|
718
|
+
`);
|
|
719
|
+
}
|
|
720
|
+
process.stdout.write("\nSetup complete.\n");
|
|
721
|
+
process.stdout.write('Now run `claude -p "any prompt"` from any directory and watch the run land at:\n');
|
|
722
|
+
process.stdout.write(` ${serverUrl.replace(/\/$/, "")}/dashboard
|
|
723
|
+
|
|
724
|
+
`);
|
|
725
|
+
return 0;
|
|
726
|
+
}
|
|
727
|
+
|
|
612
728
|
// src/lib/flusher.ts
|
|
613
729
|
import { appendFile as appendFile2, mkdir as mkdir5, readFile as readFile6, unlink as unlink3, writeFile as writeFile5 } from "fs/promises";
|
|
614
730
|
import { dirname as dirname5 } from "path";
|
|
@@ -730,6 +846,8 @@ async function runFlusher() {
|
|
|
730
846
|
}
|
|
731
847
|
|
|
732
848
|
// src/index.ts
|
|
849
|
+
var pkgPath = join2(dirname6(fileURLToPath2(import.meta.url)), "..", "package.json");
|
|
850
|
+
var PKG_VERSION = JSON.parse(readFileSync(pkgPath, "utf8")).version;
|
|
733
851
|
if (process.argv.includes("--internal-flusher")) {
|
|
734
852
|
void runFlusher().then(
|
|
735
853
|
() => process.exit(0),
|
|
@@ -740,7 +858,8 @@ if (process.argv.includes("--internal-flusher")) {
|
|
|
740
858
|
);
|
|
741
859
|
} else {
|
|
742
860
|
const program = new Command();
|
|
743
|
-
program.name("runtape").description("Flight recorder for AI coding agents.").version(
|
|
861
|
+
program.name("runtape").description("Flight recorder for AI coding agents.").version(PKG_VERSION);
|
|
862
|
+
program.command("setup").description("Guided onboarding: login + install hooks + verify in one flow.").option("--no-browser", "Do not open the dashboard URL in a browser").action(async (opts) => process.exit(await setupCommand(opts)));
|
|
744
863
|
program.command("login").description("Paste your API key from runtape.dev/dashboard and save it locally.").option("-k, --key <key>", "API key (skip the prompt)").option("-s, --server-url <url>", "Override server URL").action(async (opts) => process.exit(await loginCommand(opts)));
|
|
745
864
|
program.command("logout").description("Remove saved credentials.").action(async () => process.exit(await logoutCommand()));
|
|
746
865
|
program.command("install").description("Add Runtape hooks to ~/.claude/settings.json (or project-local with --project).").option("--project", "Install into ./.claude/settings.json instead of user-level").option("-y, --yes", "Skip the confirmation prompt").action(async (opts) => process.exit(await installCommand(opts)));
|
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/lib/flusher.ts"],"sourcesContent":["import { 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 { runFlusher } from './lib/flusher.js';\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('0.1.2');\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 { 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":["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","appendFile","mkdir","readFile","unlink","writeFile","dirname","mkdir","dirname","appendFile","readFile","writeFile","unlink","resolve"]}
|
|
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":";;;;;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,EACnE,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;;;ADfO,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;AAUO,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;AACH,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,MACvB;AACA;AAAA,IACF,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;;;ADlGA,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;;;AFtFA,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;AACzC,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;;;AG5EA,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,+CAAgD;AAGrE,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,KAAK,GAAG,KAAK;AAC5E,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;;;ACzHA,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;;;AjB3IA,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","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"]}
|
package/dist/types.d.ts
CHANGED
|
@@ -13,21 +13,21 @@ declare const SessionStartEvent: z.ZodObject<{
|
|
|
13
13
|
type: z.ZodLiteral<"session_start">;
|
|
14
14
|
source: z.ZodString;
|
|
15
15
|
}, "strip", z.ZodTypeAny, {
|
|
16
|
-
type: "session_start";
|
|
17
16
|
session_id: string;
|
|
18
17
|
transcript_path: string;
|
|
19
18
|
cwd: string;
|
|
20
19
|
hook_event_name: string;
|
|
20
|
+
type: "session_start";
|
|
21
21
|
wall_ts: string;
|
|
22
22
|
sequence: number;
|
|
23
23
|
source: string;
|
|
24
24
|
permission_mode?: string | undefined;
|
|
25
25
|
}, {
|
|
26
|
-
type: "session_start";
|
|
27
26
|
session_id: string;
|
|
28
27
|
transcript_path: string;
|
|
29
28
|
cwd: string;
|
|
30
29
|
hook_event_name: string;
|
|
30
|
+
type: "session_start";
|
|
31
31
|
wall_ts: string;
|
|
32
32
|
sequence: number;
|
|
33
33
|
source: string;
|
|
@@ -46,21 +46,21 @@ declare const UserPromptEvent: z.ZodObject<{
|
|
|
46
46
|
type: z.ZodLiteral<"user_prompt">;
|
|
47
47
|
prompt: z.ZodString;
|
|
48
48
|
}, "strip", z.ZodTypeAny, {
|
|
49
|
-
type: "user_prompt";
|
|
50
49
|
session_id: string;
|
|
51
50
|
transcript_path: string;
|
|
52
51
|
cwd: string;
|
|
53
52
|
hook_event_name: string;
|
|
53
|
+
type: "user_prompt";
|
|
54
54
|
wall_ts: string;
|
|
55
55
|
sequence: number;
|
|
56
56
|
prompt: string;
|
|
57
57
|
permission_mode?: string | undefined;
|
|
58
58
|
}, {
|
|
59
|
-
type: "user_prompt";
|
|
60
59
|
session_id: string;
|
|
61
60
|
transcript_path: string;
|
|
62
61
|
cwd: string;
|
|
63
62
|
hook_event_name: string;
|
|
63
|
+
type: "user_prompt";
|
|
64
64
|
wall_ts: string;
|
|
65
65
|
sequence: number;
|
|
66
66
|
prompt: string;
|
|
@@ -81,11 +81,11 @@ declare const ToolAttemptEvent: z.ZodObject<{
|
|
|
81
81
|
tool_input: z.ZodUnknown;
|
|
82
82
|
tool_use_id: z.ZodString;
|
|
83
83
|
}, "strip", z.ZodTypeAny, {
|
|
84
|
-
type: "tool_attempt";
|
|
85
84
|
session_id: string;
|
|
86
85
|
transcript_path: string;
|
|
87
86
|
cwd: string;
|
|
88
87
|
hook_event_name: string;
|
|
88
|
+
type: "tool_attempt";
|
|
89
89
|
wall_ts: string;
|
|
90
90
|
sequence: number;
|
|
91
91
|
tool_name: string;
|
|
@@ -93,11 +93,11 @@ declare const ToolAttemptEvent: z.ZodObject<{
|
|
|
93
93
|
permission_mode?: string | undefined;
|
|
94
94
|
tool_input?: unknown;
|
|
95
95
|
}, {
|
|
96
|
-
type: "tool_attempt";
|
|
97
96
|
session_id: string;
|
|
98
97
|
transcript_path: string;
|
|
99
98
|
cwd: string;
|
|
100
99
|
hook_event_name: string;
|
|
100
|
+
type: "tool_attempt";
|
|
101
101
|
wall_ts: string;
|
|
102
102
|
sequence: number;
|
|
103
103
|
tool_name: string;
|
|
@@ -122,11 +122,11 @@ declare const ToolCallEvent: z.ZodObject<{
|
|
|
122
122
|
tool_use_id: z.ZodString;
|
|
123
123
|
duration_ms: z.ZodNumber;
|
|
124
124
|
}, "strip", z.ZodTypeAny, {
|
|
125
|
-
type: "tool_call";
|
|
126
125
|
session_id: string;
|
|
127
126
|
transcript_path: string;
|
|
128
127
|
cwd: string;
|
|
129
128
|
hook_event_name: string;
|
|
129
|
+
type: "tool_call";
|
|
130
130
|
wall_ts: string;
|
|
131
131
|
sequence: number;
|
|
132
132
|
tool_name: string;
|
|
@@ -136,11 +136,11 @@ declare const ToolCallEvent: z.ZodObject<{
|
|
|
136
136
|
tool_input?: unknown;
|
|
137
137
|
tool_response?: unknown;
|
|
138
138
|
}, {
|
|
139
|
-
type: "tool_call";
|
|
140
139
|
session_id: string;
|
|
141
140
|
transcript_path: string;
|
|
142
141
|
cwd: string;
|
|
143
142
|
hook_event_name: string;
|
|
143
|
+
type: "tool_call";
|
|
144
144
|
wall_ts: string;
|
|
145
145
|
sequence: number;
|
|
146
146
|
tool_name: string;
|
|
@@ -167,11 +167,11 @@ declare const SubagentEndEvent: z.ZodObject<{
|
|
|
167
167
|
last_assistant_message: z.ZodString;
|
|
168
168
|
stop_hook_active: z.ZodOptional<z.ZodBoolean>;
|
|
169
169
|
}, "strip", z.ZodTypeAny, {
|
|
170
|
-
type: "subagent_end";
|
|
171
170
|
session_id: string;
|
|
172
171
|
transcript_path: string;
|
|
173
172
|
cwd: string;
|
|
174
173
|
hook_event_name: string;
|
|
174
|
+
type: "subagent_end";
|
|
175
175
|
wall_ts: string;
|
|
176
176
|
sequence: number;
|
|
177
177
|
agent_id: string;
|
|
@@ -181,11 +181,11 @@ declare const SubagentEndEvent: z.ZodObject<{
|
|
|
181
181
|
permission_mode?: string | undefined;
|
|
182
182
|
stop_hook_active?: boolean | undefined;
|
|
183
183
|
}, {
|
|
184
|
-
type: "subagent_end";
|
|
185
184
|
session_id: string;
|
|
186
185
|
transcript_path: string;
|
|
187
186
|
cwd: string;
|
|
188
187
|
hook_event_name: string;
|
|
188
|
+
type: "subagent_end";
|
|
189
189
|
wall_ts: string;
|
|
190
190
|
sequence: number;
|
|
191
191
|
agent_id: string;
|
|
@@ -209,22 +209,22 @@ declare const SessionEndEvent: z.ZodObject<{
|
|
|
209
209
|
last_assistant_message: z.ZodOptional<z.ZodString>;
|
|
210
210
|
stop_hook_active: z.ZodOptional<z.ZodBoolean>;
|
|
211
211
|
}, "strip", z.ZodTypeAny, {
|
|
212
|
-
type: "session_end";
|
|
213
212
|
session_id: string;
|
|
214
213
|
transcript_path: string;
|
|
215
214
|
cwd: string;
|
|
216
215
|
hook_event_name: string;
|
|
216
|
+
type: "session_end";
|
|
217
217
|
wall_ts: string;
|
|
218
218
|
sequence: number;
|
|
219
219
|
permission_mode?: string | undefined;
|
|
220
220
|
last_assistant_message?: string | undefined;
|
|
221
221
|
stop_hook_active?: boolean | undefined;
|
|
222
222
|
}, {
|
|
223
|
-
type: "session_end";
|
|
224
223
|
session_id: string;
|
|
225
224
|
transcript_path: string;
|
|
226
225
|
cwd: string;
|
|
227
226
|
hook_event_name: string;
|
|
227
|
+
type: "session_end";
|
|
228
228
|
wall_ts: string;
|
|
229
229
|
sequence: number;
|
|
230
230
|
permission_mode?: string | undefined;
|
|
@@ -244,21 +244,21 @@ declare const RuntapeEvent: z.ZodDiscriminatedUnion<"type", [z.ZodObject<{
|
|
|
244
244
|
type: z.ZodLiteral<"session_start">;
|
|
245
245
|
source: z.ZodString;
|
|
246
246
|
}, "strip", z.ZodTypeAny, {
|
|
247
|
-
type: "session_start";
|
|
248
247
|
session_id: string;
|
|
249
248
|
transcript_path: string;
|
|
250
249
|
cwd: string;
|
|
251
250
|
hook_event_name: string;
|
|
251
|
+
type: "session_start";
|
|
252
252
|
wall_ts: string;
|
|
253
253
|
sequence: number;
|
|
254
254
|
source: string;
|
|
255
255
|
permission_mode?: string | undefined;
|
|
256
256
|
}, {
|
|
257
|
-
type: "session_start";
|
|
258
257
|
session_id: string;
|
|
259
258
|
transcript_path: string;
|
|
260
259
|
cwd: string;
|
|
261
260
|
hook_event_name: string;
|
|
261
|
+
type: "session_start";
|
|
262
262
|
wall_ts: string;
|
|
263
263
|
sequence: number;
|
|
264
264
|
source: string;
|
|
@@ -276,21 +276,21 @@ declare const RuntapeEvent: z.ZodDiscriminatedUnion<"type", [z.ZodObject<{
|
|
|
276
276
|
type: z.ZodLiteral<"user_prompt">;
|
|
277
277
|
prompt: z.ZodString;
|
|
278
278
|
}, "strip", z.ZodTypeAny, {
|
|
279
|
-
type: "user_prompt";
|
|
280
279
|
session_id: string;
|
|
281
280
|
transcript_path: string;
|
|
282
281
|
cwd: string;
|
|
283
282
|
hook_event_name: string;
|
|
283
|
+
type: "user_prompt";
|
|
284
284
|
wall_ts: string;
|
|
285
285
|
sequence: number;
|
|
286
286
|
prompt: string;
|
|
287
287
|
permission_mode?: string | undefined;
|
|
288
288
|
}, {
|
|
289
|
-
type: "user_prompt";
|
|
290
289
|
session_id: string;
|
|
291
290
|
transcript_path: string;
|
|
292
291
|
cwd: string;
|
|
293
292
|
hook_event_name: string;
|
|
293
|
+
type: "user_prompt";
|
|
294
294
|
wall_ts: string;
|
|
295
295
|
sequence: number;
|
|
296
296
|
prompt: string;
|
|
@@ -310,11 +310,11 @@ declare const RuntapeEvent: z.ZodDiscriminatedUnion<"type", [z.ZodObject<{
|
|
|
310
310
|
tool_input: z.ZodUnknown;
|
|
311
311
|
tool_use_id: z.ZodString;
|
|
312
312
|
}, "strip", z.ZodTypeAny, {
|
|
313
|
-
type: "tool_attempt";
|
|
314
313
|
session_id: string;
|
|
315
314
|
transcript_path: string;
|
|
316
315
|
cwd: string;
|
|
317
316
|
hook_event_name: string;
|
|
317
|
+
type: "tool_attempt";
|
|
318
318
|
wall_ts: string;
|
|
319
319
|
sequence: number;
|
|
320
320
|
tool_name: string;
|
|
@@ -322,11 +322,11 @@ declare const RuntapeEvent: z.ZodDiscriminatedUnion<"type", [z.ZodObject<{
|
|
|
322
322
|
permission_mode?: string | undefined;
|
|
323
323
|
tool_input?: unknown;
|
|
324
324
|
}, {
|
|
325
|
-
type: "tool_attempt";
|
|
326
325
|
session_id: string;
|
|
327
326
|
transcript_path: string;
|
|
328
327
|
cwd: string;
|
|
329
328
|
hook_event_name: string;
|
|
329
|
+
type: "tool_attempt";
|
|
330
330
|
wall_ts: string;
|
|
331
331
|
sequence: number;
|
|
332
332
|
tool_name: string;
|
|
@@ -350,11 +350,11 @@ declare const RuntapeEvent: z.ZodDiscriminatedUnion<"type", [z.ZodObject<{
|
|
|
350
350
|
tool_use_id: z.ZodString;
|
|
351
351
|
duration_ms: z.ZodNumber;
|
|
352
352
|
}, "strip", z.ZodTypeAny, {
|
|
353
|
-
type: "tool_call";
|
|
354
353
|
session_id: string;
|
|
355
354
|
transcript_path: string;
|
|
356
355
|
cwd: string;
|
|
357
356
|
hook_event_name: string;
|
|
357
|
+
type: "tool_call";
|
|
358
358
|
wall_ts: string;
|
|
359
359
|
sequence: number;
|
|
360
360
|
tool_name: string;
|
|
@@ -364,11 +364,11 @@ declare const RuntapeEvent: z.ZodDiscriminatedUnion<"type", [z.ZodObject<{
|
|
|
364
364
|
tool_input?: unknown;
|
|
365
365
|
tool_response?: unknown;
|
|
366
366
|
}, {
|
|
367
|
-
type: "tool_call";
|
|
368
367
|
session_id: string;
|
|
369
368
|
transcript_path: string;
|
|
370
369
|
cwd: string;
|
|
371
370
|
hook_event_name: string;
|
|
371
|
+
type: "tool_call";
|
|
372
372
|
wall_ts: string;
|
|
373
373
|
sequence: number;
|
|
374
374
|
tool_name: string;
|
|
@@ -394,11 +394,11 @@ declare const RuntapeEvent: z.ZodDiscriminatedUnion<"type", [z.ZodObject<{
|
|
|
394
394
|
last_assistant_message: z.ZodString;
|
|
395
395
|
stop_hook_active: z.ZodOptional<z.ZodBoolean>;
|
|
396
396
|
}, "strip", z.ZodTypeAny, {
|
|
397
|
-
type: "subagent_end";
|
|
398
397
|
session_id: string;
|
|
399
398
|
transcript_path: string;
|
|
400
399
|
cwd: string;
|
|
401
400
|
hook_event_name: string;
|
|
401
|
+
type: "subagent_end";
|
|
402
402
|
wall_ts: string;
|
|
403
403
|
sequence: number;
|
|
404
404
|
agent_id: string;
|
|
@@ -408,11 +408,11 @@ declare const RuntapeEvent: z.ZodDiscriminatedUnion<"type", [z.ZodObject<{
|
|
|
408
408
|
permission_mode?: string | undefined;
|
|
409
409
|
stop_hook_active?: boolean | undefined;
|
|
410
410
|
}, {
|
|
411
|
-
type: "subagent_end";
|
|
412
411
|
session_id: string;
|
|
413
412
|
transcript_path: string;
|
|
414
413
|
cwd: string;
|
|
415
414
|
hook_event_name: string;
|
|
415
|
+
type: "subagent_end";
|
|
416
416
|
wall_ts: string;
|
|
417
417
|
sequence: number;
|
|
418
418
|
agent_id: string;
|
|
@@ -435,22 +435,22 @@ declare const RuntapeEvent: z.ZodDiscriminatedUnion<"type", [z.ZodObject<{
|
|
|
435
435
|
last_assistant_message: z.ZodOptional<z.ZodString>;
|
|
436
436
|
stop_hook_active: z.ZodOptional<z.ZodBoolean>;
|
|
437
437
|
}, "strip", z.ZodTypeAny, {
|
|
438
|
-
type: "session_end";
|
|
439
438
|
session_id: string;
|
|
440
439
|
transcript_path: string;
|
|
441
440
|
cwd: string;
|
|
442
441
|
hook_event_name: string;
|
|
442
|
+
type: "session_end";
|
|
443
443
|
wall_ts: string;
|
|
444
444
|
sequence: number;
|
|
445
445
|
permission_mode?: string | undefined;
|
|
446
446
|
last_assistant_message?: string | undefined;
|
|
447
447
|
stop_hook_active?: boolean | undefined;
|
|
448
448
|
}, {
|
|
449
|
-
type: "session_end";
|
|
450
449
|
session_id: string;
|
|
451
450
|
transcript_path: string;
|
|
452
451
|
cwd: string;
|
|
453
452
|
hook_event_name: string;
|
|
453
|
+
type: "session_end";
|
|
454
454
|
wall_ts: string;
|
|
455
455
|
sequence: number;
|
|
456
456
|
permission_mode?: string | undefined;
|
|
@@ -472,21 +472,21 @@ declare const IngestionRequest: z.ZodObject<{
|
|
|
472
472
|
type: z.ZodLiteral<"session_start">;
|
|
473
473
|
source: z.ZodString;
|
|
474
474
|
}, "strip", z.ZodTypeAny, {
|
|
475
|
-
type: "session_start";
|
|
476
475
|
session_id: string;
|
|
477
476
|
transcript_path: string;
|
|
478
477
|
cwd: string;
|
|
479
478
|
hook_event_name: string;
|
|
479
|
+
type: "session_start";
|
|
480
480
|
wall_ts: string;
|
|
481
481
|
sequence: number;
|
|
482
482
|
source: string;
|
|
483
483
|
permission_mode?: string | undefined;
|
|
484
484
|
}, {
|
|
485
|
-
type: "session_start";
|
|
486
485
|
session_id: string;
|
|
487
486
|
transcript_path: string;
|
|
488
487
|
cwd: string;
|
|
489
488
|
hook_event_name: string;
|
|
489
|
+
type: "session_start";
|
|
490
490
|
wall_ts: string;
|
|
491
491
|
sequence: number;
|
|
492
492
|
source: string;
|
|
@@ -504,21 +504,21 @@ declare const IngestionRequest: z.ZodObject<{
|
|
|
504
504
|
type: z.ZodLiteral<"user_prompt">;
|
|
505
505
|
prompt: z.ZodString;
|
|
506
506
|
}, "strip", z.ZodTypeAny, {
|
|
507
|
-
type: "user_prompt";
|
|
508
507
|
session_id: string;
|
|
509
508
|
transcript_path: string;
|
|
510
509
|
cwd: string;
|
|
511
510
|
hook_event_name: string;
|
|
511
|
+
type: "user_prompt";
|
|
512
512
|
wall_ts: string;
|
|
513
513
|
sequence: number;
|
|
514
514
|
prompt: string;
|
|
515
515
|
permission_mode?: string | undefined;
|
|
516
516
|
}, {
|
|
517
|
-
type: "user_prompt";
|
|
518
517
|
session_id: string;
|
|
519
518
|
transcript_path: string;
|
|
520
519
|
cwd: string;
|
|
521
520
|
hook_event_name: string;
|
|
521
|
+
type: "user_prompt";
|
|
522
522
|
wall_ts: string;
|
|
523
523
|
sequence: number;
|
|
524
524
|
prompt: string;
|
|
@@ -538,11 +538,11 @@ declare const IngestionRequest: z.ZodObject<{
|
|
|
538
538
|
tool_input: z.ZodUnknown;
|
|
539
539
|
tool_use_id: z.ZodString;
|
|
540
540
|
}, "strip", z.ZodTypeAny, {
|
|
541
|
-
type: "tool_attempt";
|
|
542
541
|
session_id: string;
|
|
543
542
|
transcript_path: string;
|
|
544
543
|
cwd: string;
|
|
545
544
|
hook_event_name: string;
|
|
545
|
+
type: "tool_attempt";
|
|
546
546
|
wall_ts: string;
|
|
547
547
|
sequence: number;
|
|
548
548
|
tool_name: string;
|
|
@@ -550,11 +550,11 @@ declare const IngestionRequest: z.ZodObject<{
|
|
|
550
550
|
permission_mode?: string | undefined;
|
|
551
551
|
tool_input?: unknown;
|
|
552
552
|
}, {
|
|
553
|
-
type: "tool_attempt";
|
|
554
553
|
session_id: string;
|
|
555
554
|
transcript_path: string;
|
|
556
555
|
cwd: string;
|
|
557
556
|
hook_event_name: string;
|
|
557
|
+
type: "tool_attempt";
|
|
558
558
|
wall_ts: string;
|
|
559
559
|
sequence: number;
|
|
560
560
|
tool_name: string;
|
|
@@ -578,11 +578,11 @@ declare const IngestionRequest: z.ZodObject<{
|
|
|
578
578
|
tool_use_id: z.ZodString;
|
|
579
579
|
duration_ms: z.ZodNumber;
|
|
580
580
|
}, "strip", z.ZodTypeAny, {
|
|
581
|
-
type: "tool_call";
|
|
582
581
|
session_id: string;
|
|
583
582
|
transcript_path: string;
|
|
584
583
|
cwd: string;
|
|
585
584
|
hook_event_name: string;
|
|
585
|
+
type: "tool_call";
|
|
586
586
|
wall_ts: string;
|
|
587
587
|
sequence: number;
|
|
588
588
|
tool_name: string;
|
|
@@ -592,11 +592,11 @@ declare const IngestionRequest: z.ZodObject<{
|
|
|
592
592
|
tool_input?: unknown;
|
|
593
593
|
tool_response?: unknown;
|
|
594
594
|
}, {
|
|
595
|
-
type: "tool_call";
|
|
596
595
|
session_id: string;
|
|
597
596
|
transcript_path: string;
|
|
598
597
|
cwd: string;
|
|
599
598
|
hook_event_name: string;
|
|
599
|
+
type: "tool_call";
|
|
600
600
|
wall_ts: string;
|
|
601
601
|
sequence: number;
|
|
602
602
|
tool_name: string;
|
|
@@ -622,11 +622,11 @@ declare const IngestionRequest: z.ZodObject<{
|
|
|
622
622
|
last_assistant_message: z.ZodString;
|
|
623
623
|
stop_hook_active: z.ZodOptional<z.ZodBoolean>;
|
|
624
624
|
}, "strip", z.ZodTypeAny, {
|
|
625
|
-
type: "subagent_end";
|
|
626
625
|
session_id: string;
|
|
627
626
|
transcript_path: string;
|
|
628
627
|
cwd: string;
|
|
629
628
|
hook_event_name: string;
|
|
629
|
+
type: "subagent_end";
|
|
630
630
|
wall_ts: string;
|
|
631
631
|
sequence: number;
|
|
632
632
|
agent_id: string;
|
|
@@ -636,11 +636,11 @@ declare const IngestionRequest: z.ZodObject<{
|
|
|
636
636
|
permission_mode?: string | undefined;
|
|
637
637
|
stop_hook_active?: boolean | undefined;
|
|
638
638
|
}, {
|
|
639
|
-
type: "subagent_end";
|
|
640
639
|
session_id: string;
|
|
641
640
|
transcript_path: string;
|
|
642
641
|
cwd: string;
|
|
643
642
|
hook_event_name: string;
|
|
643
|
+
type: "subagent_end";
|
|
644
644
|
wall_ts: string;
|
|
645
645
|
sequence: number;
|
|
646
646
|
agent_id: string;
|
|
@@ -663,22 +663,22 @@ declare const IngestionRequest: z.ZodObject<{
|
|
|
663
663
|
last_assistant_message: z.ZodOptional<z.ZodString>;
|
|
664
664
|
stop_hook_active: z.ZodOptional<z.ZodBoolean>;
|
|
665
665
|
}, "strip", z.ZodTypeAny, {
|
|
666
|
-
type: "session_end";
|
|
667
666
|
session_id: string;
|
|
668
667
|
transcript_path: string;
|
|
669
668
|
cwd: string;
|
|
670
669
|
hook_event_name: string;
|
|
670
|
+
type: "session_end";
|
|
671
671
|
wall_ts: string;
|
|
672
672
|
sequence: number;
|
|
673
673
|
permission_mode?: string | undefined;
|
|
674
674
|
last_assistant_message?: string | undefined;
|
|
675
675
|
stop_hook_active?: boolean | undefined;
|
|
676
676
|
}, {
|
|
677
|
-
type: "session_end";
|
|
678
677
|
session_id: string;
|
|
679
678
|
transcript_path: string;
|
|
680
679
|
cwd: string;
|
|
681
680
|
hook_event_name: string;
|
|
681
|
+
type: "session_end";
|
|
682
682
|
wall_ts: string;
|
|
683
683
|
sequence: number;
|
|
684
684
|
permission_mode?: string | undefined;
|
|
@@ -687,31 +687,31 @@ declare const IngestionRequest: z.ZodObject<{
|
|
|
687
687
|
}>]>, "many">;
|
|
688
688
|
}, "strip", z.ZodTypeAny, {
|
|
689
689
|
events: ({
|
|
690
|
-
type: "session_start";
|
|
691
690
|
session_id: string;
|
|
692
691
|
transcript_path: string;
|
|
693
692
|
cwd: string;
|
|
694
693
|
hook_event_name: string;
|
|
694
|
+
type: "session_start";
|
|
695
695
|
wall_ts: string;
|
|
696
696
|
sequence: number;
|
|
697
697
|
source: string;
|
|
698
698
|
permission_mode?: string | undefined;
|
|
699
699
|
} | {
|
|
700
|
-
type: "user_prompt";
|
|
701
700
|
session_id: string;
|
|
702
701
|
transcript_path: string;
|
|
703
702
|
cwd: string;
|
|
704
703
|
hook_event_name: string;
|
|
704
|
+
type: "user_prompt";
|
|
705
705
|
wall_ts: string;
|
|
706
706
|
sequence: number;
|
|
707
707
|
prompt: string;
|
|
708
708
|
permission_mode?: string | undefined;
|
|
709
709
|
} | {
|
|
710
|
-
type: "tool_attempt";
|
|
711
710
|
session_id: string;
|
|
712
711
|
transcript_path: string;
|
|
713
712
|
cwd: string;
|
|
714
713
|
hook_event_name: string;
|
|
714
|
+
type: "tool_attempt";
|
|
715
715
|
wall_ts: string;
|
|
716
716
|
sequence: number;
|
|
717
717
|
tool_name: string;
|
|
@@ -719,11 +719,11 @@ declare const IngestionRequest: z.ZodObject<{
|
|
|
719
719
|
permission_mode?: string | undefined;
|
|
720
720
|
tool_input?: unknown;
|
|
721
721
|
} | {
|
|
722
|
-
type: "tool_call";
|
|
723
722
|
session_id: string;
|
|
724
723
|
transcript_path: string;
|
|
725
724
|
cwd: string;
|
|
726
725
|
hook_event_name: string;
|
|
726
|
+
type: "tool_call";
|
|
727
727
|
wall_ts: string;
|
|
728
728
|
sequence: number;
|
|
729
729
|
tool_name: string;
|
|
@@ -733,11 +733,11 @@ declare const IngestionRequest: z.ZodObject<{
|
|
|
733
733
|
tool_input?: unknown;
|
|
734
734
|
tool_response?: unknown;
|
|
735
735
|
} | {
|
|
736
|
-
type: "subagent_end";
|
|
737
736
|
session_id: string;
|
|
738
737
|
transcript_path: string;
|
|
739
738
|
cwd: string;
|
|
740
739
|
hook_event_name: string;
|
|
740
|
+
type: "subagent_end";
|
|
741
741
|
wall_ts: string;
|
|
742
742
|
sequence: number;
|
|
743
743
|
agent_id: string;
|
|
@@ -747,11 +747,11 @@ declare const IngestionRequest: z.ZodObject<{
|
|
|
747
747
|
permission_mode?: string | undefined;
|
|
748
748
|
stop_hook_active?: boolean | undefined;
|
|
749
749
|
} | {
|
|
750
|
-
type: "session_end";
|
|
751
750
|
session_id: string;
|
|
752
751
|
transcript_path: string;
|
|
753
752
|
cwd: string;
|
|
754
753
|
hook_event_name: string;
|
|
754
|
+
type: "session_end";
|
|
755
755
|
wall_ts: string;
|
|
756
756
|
sequence: number;
|
|
757
757
|
permission_mode?: string | undefined;
|
|
@@ -760,31 +760,31 @@ declare const IngestionRequest: z.ZodObject<{
|
|
|
760
760
|
})[];
|
|
761
761
|
}, {
|
|
762
762
|
events: ({
|
|
763
|
-
type: "session_start";
|
|
764
763
|
session_id: string;
|
|
765
764
|
transcript_path: string;
|
|
766
765
|
cwd: string;
|
|
767
766
|
hook_event_name: string;
|
|
767
|
+
type: "session_start";
|
|
768
768
|
wall_ts: string;
|
|
769
769
|
sequence: number;
|
|
770
770
|
source: string;
|
|
771
771
|
permission_mode?: string | undefined;
|
|
772
772
|
} | {
|
|
773
|
-
type: "user_prompt";
|
|
774
773
|
session_id: string;
|
|
775
774
|
transcript_path: string;
|
|
776
775
|
cwd: string;
|
|
777
776
|
hook_event_name: string;
|
|
777
|
+
type: "user_prompt";
|
|
778
778
|
wall_ts: string;
|
|
779
779
|
sequence: number;
|
|
780
780
|
prompt: string;
|
|
781
781
|
permission_mode?: string | undefined;
|
|
782
782
|
} | {
|
|
783
|
-
type: "tool_attempt";
|
|
784
783
|
session_id: string;
|
|
785
784
|
transcript_path: string;
|
|
786
785
|
cwd: string;
|
|
787
786
|
hook_event_name: string;
|
|
787
|
+
type: "tool_attempt";
|
|
788
788
|
wall_ts: string;
|
|
789
789
|
sequence: number;
|
|
790
790
|
tool_name: string;
|
|
@@ -792,11 +792,11 @@ declare const IngestionRequest: z.ZodObject<{
|
|
|
792
792
|
permission_mode?: string | undefined;
|
|
793
793
|
tool_input?: unknown;
|
|
794
794
|
} | {
|
|
795
|
-
type: "tool_call";
|
|
796
795
|
session_id: string;
|
|
797
796
|
transcript_path: string;
|
|
798
797
|
cwd: string;
|
|
799
798
|
hook_event_name: string;
|
|
799
|
+
type: "tool_call";
|
|
800
800
|
wall_ts: string;
|
|
801
801
|
sequence: number;
|
|
802
802
|
tool_name: string;
|
|
@@ -806,11 +806,11 @@ declare const IngestionRequest: z.ZodObject<{
|
|
|
806
806
|
tool_input?: unknown;
|
|
807
807
|
tool_response?: unknown;
|
|
808
808
|
} | {
|
|
809
|
-
type: "subagent_end";
|
|
810
809
|
session_id: string;
|
|
811
810
|
transcript_path: string;
|
|
812
811
|
cwd: string;
|
|
813
812
|
hook_event_name: string;
|
|
813
|
+
type: "subagent_end";
|
|
814
814
|
wall_ts: string;
|
|
815
815
|
sequence: number;
|
|
816
816
|
agent_id: string;
|
|
@@ -820,11 +820,11 @@ declare const IngestionRequest: z.ZodObject<{
|
|
|
820
820
|
permission_mode?: string | undefined;
|
|
821
821
|
stop_hook_active?: boolean | undefined;
|
|
822
822
|
} | {
|
|
823
|
-
type: "session_end";
|
|
824
823
|
session_id: string;
|
|
825
824
|
transcript_path: string;
|
|
826
825
|
cwd: string;
|
|
827
826
|
hook_event_name: string;
|
|
827
|
+
type: "session_end";
|
|
828
828
|
wall_ts: string;
|
|
829
829
|
sequence: number;
|
|
830
830
|
permission_mode?: string | undefined;
|