@pat-lewczuk/cezar 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. package/README.md +90 -0
  2. package/dist/core/agent-runner.d.ts +95 -0
  3. package/dist/core/agent-runner.js +8 -0
  4. package/dist/core/agent-runner.js.map +1 -0
  5. package/dist/core/backend-detect.d.ts +14 -0
  6. package/dist/core/backend-detect.js +78 -0
  7. package/dist/core/backend-detect.js.map +1 -0
  8. package/dist/core/claude-cli-runner.d.ts +68 -0
  9. package/dist/core/claude-cli-runner.js +424 -0
  10. package/dist/core/claude-cli-runner.js.map +1 -0
  11. package/dist/core/usage.d.ts +11 -0
  12. package/dist/core/usage.js +15 -0
  13. package/dist/core/usage.js.map +1 -0
  14. package/dist/index.d.ts +2 -0
  15. package/dist/index.js +294 -0
  16. package/dist/index.js.map +1 -0
  17. package/dist/runs/store.d.ts +218 -0
  18. package/dist/runs/store.js +286 -0
  19. package/dist/runs/store.js.map +1 -0
  20. package/dist/server/git.d.ts +21 -0
  21. package/dist/server/git.js +54 -0
  22. package/dist/server/git.js.map +1 -0
  23. package/dist/server/open-in-terminal.d.ts +11 -0
  24. package/dist/server/open-in-terminal.js +84 -0
  25. package/dist/server/open-in-terminal.js.map +1 -0
  26. package/dist/server/server.d.ts +12 -0
  27. package/dist/server/server.js +243 -0
  28. package/dist/server/server.js.map +1 -0
  29. package/dist/skills.d.ts +31 -0
  30. package/dist/skills.js +117 -0
  31. package/dist/skills.js.map +1 -0
  32. package/dist/workflows/load.d.ts +15 -0
  33. package/dist/workflows/load.js +58 -0
  34. package/dist/workflows/load.js.map +1 -0
  35. package/dist/workflows/run.d.ts +52 -0
  36. package/dist/workflows/run.js +452 -0
  37. package/dist/workflows/run.js.map +1 -0
  38. package/dist/workflows/types.d.ts +202 -0
  39. package/dist/workflows/types.js +56 -0
  40. package/dist/workflows/types.js.map +1 -0
  41. package/package.json +44 -0
  42. package/scripts/mock-claude.mjs +106 -0
  43. package/web/app.js +634 -0
  44. package/web/index.html +48 -0
  45. package/web/style.css +317 -0
package/dist/index.js ADDED
@@ -0,0 +1,294 @@
1
+ #!/usr/bin/env node
2
+ import { parseArgs } from 'node:util';
3
+ import { spawn } from 'node:child_process';
4
+ import { createServer } from 'node:net';
5
+ import { mkdirSync, writeFileSync, existsSync, readFileSync } from 'node:fs';
6
+ import { dirname, join, resolve } from 'node:path';
7
+ import { fileURLToPath } from 'node:url';
8
+ import { detectEnvironment } from './core/backend-detect.js';
9
+ import { getRepoInfo } from './server/git.js';
10
+ import { RunStore } from './runs/store.js';
11
+ import { RunManager } from './workflows/run.js';
12
+ import { loadWorkflows } from './workflows/load.js';
13
+ import { startServer } from './server/server.js';
14
+ const HELP = `cezar — local cockpit for AI agent tasks in your repo
15
+
16
+ Usage:
17
+ cezar start the cockpit (server + GUI) for the current repo
18
+ cezar run "<task>" run a task headless in the terminal
19
+ cezar init scaffold .ai/cezar/ (example workflow + skill)
20
+
21
+ Options:
22
+ -p, --port <n> cockpit port (default 4321)
23
+ --repo <dir> repo to operate on (default: cwd)
24
+ --workflow <name> workflow for \`run\` (default: quick-task)
25
+ --model <model> model override for \`run\`
26
+ --no-open don't open the browser
27
+ -h, --help show this help
28
+
29
+ Zero config: uses your logged-in \`claude\` CLI (and \`gh\` for GitHub bits).
30
+ Skills live in .ai/skills/ or .ai/cezar/skills/; workflows in .ai/cezar/workflows/.`;
31
+ async function main() {
32
+ const { values, positionals } = parseArgs({
33
+ options: {
34
+ port: { type: 'string', short: 'p', default: '4321' },
35
+ repo: { type: 'string' },
36
+ workflow: { type: 'string' },
37
+ model: { type: 'string' },
38
+ 'no-open': { type: 'boolean', default: false },
39
+ help: { type: 'boolean', short: 'h', default: false },
40
+ },
41
+ allowPositionals: true,
42
+ });
43
+ if (values.help) {
44
+ console.log(HELP);
45
+ return;
46
+ }
47
+ const command = positionals[0] ?? 'serve';
48
+ const cwd = resolve(values.repo ?? process.cwd());
49
+ const repoInfo = await getRepoInfo(cwd);
50
+ const repoRoot = repoInfo?.root ?? cwd;
51
+ switch (command) {
52
+ case 'serve':
53
+ await serveCommand(repoRoot, Number(values.port), !values['no-open']);
54
+ return;
55
+ case 'run':
56
+ await runCommand(repoRoot, positionals.slice(1).join(' ').trim(), values.workflow, values.model);
57
+ return;
58
+ case 'init':
59
+ initCommand(repoRoot);
60
+ return;
61
+ default:
62
+ console.error(`unknown command: ${command}\n`);
63
+ console.log(HELP);
64
+ process.exitCode = 1;
65
+ }
66
+ }
67
+ // ---- serve -----------------------------------------------------------------
68
+ async function serveCommand(repoRoot, preferredPort, openBrowser) {
69
+ const store = openStore(repoRoot);
70
+ const manager = new RunManager(store, repoRoot);
71
+ const version = readOwnVersion();
72
+ const checks = await detectEnvironment();
73
+ const repo = await getRepoInfo(repoRoot);
74
+ const port = await pickPort(preferredPort);
75
+ startServer({ repoRoot, store, manager, version }, port);
76
+ const url = `http://localhost:${port}`;
77
+ console.log(`\n cezar v${version} — ${repoRoot}`);
78
+ console.log(` ${repo ? `branch ${repo.branch}` : 'not a git repository (runs still work, repo view is empty)'}`);
79
+ for (const check of checks) {
80
+ const mark = check.available ? '✓' : '✗';
81
+ const detail = check.available ? (check.version ?? 'ok') : (check.hint ?? 'missing');
82
+ console.log(` ${mark} ${check.name.padEnd(6)} ${detail}`);
83
+ }
84
+ if (port !== preferredPort)
85
+ console.log(` (port ${preferredPort} was busy — using ${port})`);
86
+ console.log(`\n cockpit → ${url}\n`);
87
+ const shutdown = () => {
88
+ store.flush();
89
+ process.exit(0);
90
+ };
91
+ process.on('SIGINT', shutdown);
92
+ process.on('SIGTERM', shutdown);
93
+ // Open the browser only once the server actually answers, so the first
94
+ // paint is the cockpit and never a connection error.
95
+ if (openBrowser) {
96
+ const healthy = await waitForHealth(`${url}/api/health`, 5_000);
97
+ if (healthy)
98
+ openUrl(url);
99
+ }
100
+ }
101
+ /** First free port starting at `start` (the launch.mjs pattern from janitor). */
102
+ async function pickPort(start) {
103
+ for (let port = start; port < start + 50; port++) {
104
+ if (await canListen(port))
105
+ return port;
106
+ }
107
+ return start; // let the server fail loudly if 50 ports are somehow busy
108
+ }
109
+ function canListen(port) {
110
+ return new Promise((resolvePort) => {
111
+ const probe = createServer();
112
+ probe.once('error', () => resolvePort(false));
113
+ probe.once('listening', () => probe.close(() => resolvePort(true)));
114
+ probe.listen(port, '127.0.0.1');
115
+ });
116
+ }
117
+ async function waitForHealth(healthUrl, timeoutMs) {
118
+ const deadline = Date.now() + timeoutMs;
119
+ while (Date.now() < deadline) {
120
+ try {
121
+ const res = await fetch(healthUrl);
122
+ if (res.ok)
123
+ return true;
124
+ }
125
+ catch {
126
+ // not up yet
127
+ }
128
+ await new Promise((r) => setTimeout(r, 150));
129
+ }
130
+ return false;
131
+ }
132
+ // ---- run (headless) ----------------------------------------------------------
133
+ async function runCommand(repoRoot, task, workflowName, model) {
134
+ if (!task) {
135
+ console.error('usage: cezar run "<task>" [--workflow name] [--model model]');
136
+ process.exitCode = 1;
137
+ return;
138
+ }
139
+ const { workflows, issues } = await loadWorkflows(repoRoot);
140
+ for (const issue of issues)
141
+ console.error(`! skipped ${issue.path}: ${issue.message}`);
142
+ const name = workflowName ?? 'quick-task';
143
+ const workflow = workflows.find((w) => w.name === name);
144
+ if (!workflow) {
145
+ console.error(`unknown workflow: ${name} (available: ${workflows.map((w) => w.name).join(', ')})`);
146
+ process.exitCode = 1;
147
+ return;
148
+ }
149
+ const store = openStore(repoRoot);
150
+ const manager = new RunManager(store, repoRoot);
151
+ store.on('event', ({ event }) => {
152
+ switch (event.type) {
153
+ case 'text':
154
+ console.log(String(event.text ?? ''));
155
+ break;
156
+ case 'tool-call':
157
+ console.log(` → ${String(event.tool)} ${previewJson(event.input)}`);
158
+ break;
159
+ case 'tool-result':
160
+ console.log(` ← ${firstLine(String(event.result ?? ''))}`);
161
+ break;
162
+ case 'check-output':
163
+ console.log(String(event.text ?? ''));
164
+ break;
165
+ case 'step-start':
166
+ console.log(`\n── step: ${String(event.name)} ${Number(event.iteration) > 1 ? `(attempt ${event.iteration})` : ''}`);
167
+ break;
168
+ case 'note':
169
+ case 'lifecycle':
170
+ console.log(` · ${String(event.message ?? '')}`);
171
+ break;
172
+ case 'error':
173
+ console.error(` ✗ ${String(event.message ?? '')}`);
174
+ break;
175
+ }
176
+ });
177
+ const run = manager.startRun(workflow, { task, model });
178
+ const final = await new Promise((resolveStatus) => {
179
+ store.on('run', (r) => {
180
+ if (r.id === run.id && ['done', 'failed', 'cancelled'].includes(r.status))
181
+ resolveStatus(r.status);
182
+ });
183
+ });
184
+ store.flush();
185
+ const record = store.getRun(run.id);
186
+ console.log(`\nrun ${final} — ${record?.tokensUsed ?? 0} tokens — details in the cockpit: npx cezar`);
187
+ process.exitCode = final === 'done' ? 0 : 1;
188
+ }
189
+ // ---- init --------------------------------------------------------------------
190
+ function initCommand(repoRoot) {
191
+ const workflowsDir = join(repoRoot, '.ai/cezar', 'workflows');
192
+ const skillsDir = join(repoRoot, '.ai/cezar', 'skills');
193
+ mkdirSync(workflowsDir, { recursive: true });
194
+ mkdirSync(skillsDir, { recursive: true });
195
+ const examples = [
196
+ {
197
+ path: join(workflowsDir, 'fix-and-verify.yaml'),
198
+ content: `name: fix-and-verify
199
+ description: Implement the task, then run your test command; on failure the agent retries with the failing output.
200
+ steps:
201
+ - id: implement
202
+ name: Implement
203
+ prompt: "{{task}}"
204
+ - id: verify
205
+ name: Verify
206
+ command: "echo 'replace me with: npm test / yarn test / pytest'"
207
+ onFail:
208
+ retry: implement
209
+ max: 2
210
+ `,
211
+ },
212
+ {
213
+ path: join(skillsDir, 'project-conventions.md'),
214
+ content: `---
215
+ name: project-conventions
216
+ description: House rules the agent should follow in this repo.
217
+ ---
218
+
219
+ # Project conventions
220
+
221
+ - Describe your stack, style and testing conventions here.
222
+ - Reference this skill from a workflow step via \`skill: project-conventions\`.
223
+ `,
224
+ },
225
+ ];
226
+ for (const example of examples) {
227
+ if (existsSync(example.path)) {
228
+ console.log(` = ${example.path} (exists, left untouched)`);
229
+ }
230
+ else {
231
+ writeFileSync(example.path, example.content, 'utf8');
232
+ console.log(` + ${example.path}`);
233
+ }
234
+ }
235
+ ensureDataGitignore(repoRoot);
236
+ console.log('\nDone. Start the cockpit with: npx cezar');
237
+ }
238
+ // ---- helpers -----------------------------------------------------------------
239
+ function openStore(repoRoot) {
240
+ const dataDir = join(repoRoot, '.ai/cezar');
241
+ const store = RunStore.open(dataDir);
242
+ ensureDataGitignore(repoRoot);
243
+ return store;
244
+ }
245
+ /** Keep run data out of the user's repo history; workflows/skills stay committable. */
246
+ function ensureDataGitignore(repoRoot) {
247
+ const path = join(repoRoot, '.ai/cezar', '.gitignore');
248
+ try {
249
+ mkdirSync(join(repoRoot, '.ai/cezar'), { recursive: true });
250
+ if (!existsSync(path))
251
+ writeFileSync(path, 'runs.json\nruns.json.tmp\nruns/\n', 'utf8');
252
+ }
253
+ catch {
254
+ // non-fatal
255
+ }
256
+ }
257
+ function readOwnVersion() {
258
+ try {
259
+ const here = dirname(fileURLToPath(import.meta.url));
260
+ const pkg = JSON.parse(readFileSync(join(here, '..', 'package.json'), 'utf8'));
261
+ return pkg.version ?? '0.0.0';
262
+ }
263
+ catch {
264
+ return '0.0.0';
265
+ }
266
+ }
267
+ function openUrl(url) {
268
+ const cmd = process.platform === 'darwin' ? 'open' : process.platform === 'win32' ? 'cmd' : 'xdg-open';
269
+ const args = process.platform === 'win32' ? ['/c', 'start', '', url] : [url];
270
+ try {
271
+ spawn(cmd, args, { stdio: 'ignore', detached: true }).unref();
272
+ }
273
+ catch {
274
+ // the printed URL is enough
275
+ }
276
+ }
277
+ function previewJson(input) {
278
+ try {
279
+ const s = JSON.stringify(input);
280
+ return s.length > 120 ? `${s.slice(0, 117)}…` : s;
281
+ }
282
+ catch {
283
+ return '';
284
+ }
285
+ }
286
+ function firstLine(s) {
287
+ const line = s.split('\n')[0] ?? '';
288
+ return line.length > 120 ? `${line.slice(0, 117)}…` : line;
289
+ }
290
+ main().catch((err) => {
291
+ console.error(err instanceof Error ? err.message : String(err));
292
+ process.exit(1);
293
+ });
294
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AACtC,OAAO,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAC3C,OAAO,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AACxC,OAAO,EAAE,SAAS,EAAE,aAAa,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAC7E,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACnD,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAC7D,OAAO,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAC9C,OAAO,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAC3C,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAChD,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAEjD,MAAM,IAAI,GAAG;;;;;;;;;;;;;;;;oFAgBuE,CAAC;AAErF,KAAK,UAAU,IAAI;IACjB,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,GAAG,SAAS,CAAC;QACxC,OAAO,EAAE;YACP,IAAI,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,GAAG,EAAE,OAAO,EAAE,MAAM,EAAE;YACrD,IAAI,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;YACxB,QAAQ,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;YAC5B,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;YACzB,SAAS,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,KAAK,EAAE;YAC9C,IAAI,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,GAAG,EAAE,OAAO,EAAE,KAAK,EAAE;SACtD;QACD,gBAAgB,EAAE,IAAI;KACvB,CAAC,CAAC;IAEH,IAAI,MAAM,CAAC,IAAI,EAAE,CAAC;QAChB,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QAClB,OAAO;IACT,CAAC;IAED,MAAM,OAAO,GAAG,WAAW,CAAC,CAAC,CAAC,IAAI,OAAO,CAAC;IAC1C,MAAM,GAAG,GAAG,OAAO,CAAC,MAAM,CAAC,IAAI,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC;IAClD,MAAM,QAAQ,GAAG,MAAM,WAAW,CAAC,GAAG,CAAC,CAAC;IACxC,MAAM,QAAQ,GAAG,QAAQ,EAAE,IAAI,IAAI,GAAG,CAAC;IAEvC,QAAQ,OAAO,EAAE,CAAC;QAChB,KAAK,OAAO;YACV,MAAM,YAAY,CAAC,QAAQ,EAAE,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC;YACtE,OAAO;QACT,KAAK,KAAK;YACR,MAAM,UAAU,CAAC,QAAQ,EAAE,WAAW,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,MAAM,CAAC,QAAQ,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC;YACjG,OAAO;QACT,KAAK,MAAM;YACT,WAAW,CAAC,QAAQ,CAAC,CAAC;YACtB,OAAO;QACT;YACE,OAAO,CAAC,KAAK,CAAC,oBAAoB,OAAO,IAAI,CAAC,CAAC;YAC/C,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;YAClB,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;IACzB,CAAC;AACH,CAAC;AAED,+EAA+E;AAE/E,KAAK,UAAU,YAAY,CAAC,QAAgB,EAAE,aAAqB,EAAE,WAAoB;IACvF,MAAM,KAAK,GAAG,SAAS,CAAC,QAAQ,CAAC,CAAC;IAClC,MAAM,OAAO,GAAG,IAAI,UAAU,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC;IAChD,MAAM,OAAO,GAAG,cAAc,EAAE,CAAC;IAEjC,MAAM,MAAM,GAAG,MAAM,iBAAiB,EAAE,CAAC;IACzC,MAAM,IAAI,GAAG,MAAM,WAAW,CAAC,QAAQ,CAAC,CAAC;IAEzC,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,aAAa,CAAC,CAAC;IAC3C,WAAW,CAAC,EAAE,QAAQ,EAAE,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,EAAE,IAAI,CAAC,CAAC;IACzD,MAAM,GAAG,GAAG,oBAAoB,IAAI,EAAE,CAAC;IAEvC,OAAO,CAAC,GAAG,CAAC,cAAc,OAAO,MAAM,QAAQ,EAAE,CAAC,CAAC;IACnD,OAAO,CAAC,GAAG,CAAC,KAAK,IAAI,CAAC,CAAC,CAAC,UAAU,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,4DAA4D,EAAE,CAAC,CAAC;IAClH,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC3B,MAAM,IAAI,GAAG,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC;QACzC,MAAM,MAAM,GAAG,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,IAAI,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,IAAI,SAAS,CAAC,CAAC;QACrF,OAAO,CAAC,GAAG,CAAC,KAAK,IAAI,IAAI,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,MAAM,EAAE,CAAC,CAAC;IAC7D,CAAC;IACD,IAAI,IAAI,KAAK,aAAa;QAAE,OAAO,CAAC,GAAG,CAAC,WAAW,aAAa,qBAAqB,IAAI,GAAG,CAAC,CAAC;IAC9F,OAAO,CAAC,GAAG,CAAC,iBAAiB,GAAG,IAAI,CAAC,CAAC;IAEtC,MAAM,QAAQ,GAAG,GAAG,EAAE;QACpB,KAAK,CAAC,KAAK,EAAE,CAAC;QACd,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC,CAAC;IACF,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;IAC/B,OAAO,CAAC,EAAE,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC;IAEhC,uEAAuE;IACvE,qDAAqD;IACrD,IAAI,WAAW,EAAE,CAAC;QAChB,MAAM,OAAO,GAAG,MAAM,aAAa,CAAC,GAAG,GAAG,aAAa,EAAE,KAAK,CAAC,CAAC;QAChE,IAAI,OAAO;YAAE,OAAO,CAAC,GAAG,CAAC,CAAC;IAC5B,CAAC;AACH,CAAC;AAED,iFAAiF;AACjF,KAAK,UAAU,QAAQ,CAAC,KAAa;IACnC,KAAK,IAAI,IAAI,GAAG,KAAK,EAAE,IAAI,GAAG,KAAK,GAAG,EAAE,EAAE,IAAI,EAAE,EAAE,CAAC;QACjD,IAAI,MAAM,SAAS,CAAC,IAAI,CAAC;YAAE,OAAO,IAAI,CAAC;IACzC,CAAC;IACD,OAAO,KAAK,CAAC,CAAC,0DAA0D;AAC1E,CAAC;AAED,SAAS,SAAS,CAAC,IAAY;IAC7B,OAAO,IAAI,OAAO,CAAC,CAAC,WAAW,EAAE,EAAE;QACjC,MAAM,KAAK,GAAG,YAAY,EAAE,CAAC;QAC7B,KAAK,CAAC,IAAI,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC,CAAC;QAC9C,KAAK,CAAC,IAAI,CAAC,WAAW,EAAE,GAAG,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACpE,KAAK,CAAC,MAAM,CAAC,IAAI,EAAE,WAAW,CAAC,CAAC;IAClC,CAAC,CAAC,CAAC;AACL,CAAC;AAED,KAAK,UAAU,aAAa,CAAC,SAAiB,EAAE,SAAiB;IAC/D,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS,CAAC;IACxC,OAAO,IAAI,CAAC,GAAG,EAAE,GAAG,QAAQ,EAAE,CAAC;QAC7B,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,SAAS,CAAC,CAAC;YACnC,IAAI,GAAG,CAAC,EAAE;gBAAE,OAAO,IAAI,CAAC;QAC1B,CAAC;QAAC,MAAM,CAAC;YACP,aAAa;QACf,CAAC;QACD,MAAM,IAAI,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC;IAC/C,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,iFAAiF;AAEjF,KAAK,UAAU,UAAU,CACvB,QAAgB,EAChB,IAAY,EACZ,YAAgC,EAChC,KAAyB;IAEzB,IAAI,CAAC,IAAI,EAAE,CAAC;QACV,OAAO,CAAC,KAAK,CAAC,6DAA6D,CAAC,CAAC;QAC7E,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;QACrB,OAAO;IACT,CAAC;IACD,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,GAAG,MAAM,aAAa,CAAC,QAAQ,CAAC,CAAC;IAC5D,KAAK,MAAM,KAAK,IAAI,MAAM;QAAE,OAAO,CAAC,KAAK,CAAC,aAAa,KAAK,CAAC,IAAI,KAAK,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC;IACvF,MAAM,IAAI,GAAG,YAAY,IAAI,YAAY,CAAC;IAC1C,MAAM,QAAQ,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,IAAI,CAAC,CAAC;IACxD,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,OAAO,CAAC,KAAK,CAAC,qBAAqB,IAAI,gBAAgB,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QACnG,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;QACrB,OAAO;IACT,CAAC;IAED,MAAM,KAAK,GAAG,SAAS,CAAC,QAAQ,CAAC,CAAC;IAClC,MAAM,OAAO,GAAG,IAAI,UAAU,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC;IAEhD,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE;QAC9B,QAAQ,KAAK,CAAC,IAAI,EAAE,CAAC;YACnB,KAAK,MAAM;gBACT,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC,CAAC;gBACtC,MAAM;YACR,KAAK,WAAW;gBACd,OAAO,CAAC,GAAG,CAAC,OAAO,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,WAAW,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;gBACrE,MAAM;YACR,KAAK,aAAa;gBAChB,OAAO,CAAC,GAAG,CAAC,OAAO,SAAS,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC;gBAC5D,MAAM;YACR,KAAK,cAAc;gBACjB,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC,CAAC;gBACtC,MAAM;YACR,KAAK,YAAY;gBACf,OAAO,CAAC,GAAG,CAAC,cAAc,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,MAAM,CAAC,KAAK,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,YAAY,KAAK,CAAC,SAAS,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;gBACrH,MAAM;YACR,KAAK,MAAM,CAAC;YACZ,KAAK,WAAW;gBACd,OAAO,CAAC,GAAG,CAAC,OAAO,MAAM,CAAC,KAAK,CAAC,OAAO,IAAI,EAAE,CAAC,EAAE,CAAC,CAAC;gBAClD,MAAM;YACR,KAAK,OAAO;gBACV,OAAO,CAAC,KAAK,CAAC,OAAO,MAAM,CAAC,KAAK,CAAC,OAAO,IAAI,EAAE,CAAC,EAAE,CAAC,CAAC;gBACpD,MAAM;QACV,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,MAAM,GAAG,GAAG,OAAO,CAAC,QAAQ,CAAC,QAAQ,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;IACxD,MAAM,KAAK,GAAG,MAAM,IAAI,OAAO,CAAS,CAAC,aAAa,EAAE,EAAE;QACxD,KAAK,CAAC,EAAE,CAAC,KAAK,EAAE,CAAC,CAAC,EAAE,EAAE;YACpB,IAAI,CAAC,CAAC,EAAE,KAAK,GAAG,CAAC,EAAE,IAAI,CAAC,MAAM,EAAE,QAAQ,EAAE,WAAW,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC;gBAAE,aAAa,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;QACrG,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IACH,KAAK,CAAC,KAAK,EAAE,CAAC;IACd,MAAM,MAAM,GAAG,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IACpC,OAAO,CAAC,GAAG,CAAC,SAAS,KAAK,MAAM,MAAM,EAAE,UAAU,IAAI,CAAC,6CAA6C,CAAC,CAAC;IACtG,OAAO,CAAC,QAAQ,GAAG,KAAK,KAAK,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC9C,CAAC;AAED,iFAAiF;AAEjF,SAAS,WAAW,CAAC,QAAgB;IACnC,MAAM,YAAY,GAAG,IAAI,CAAC,QAAQ,EAAE,WAAW,EAAE,WAAW,CAAC,CAAC;IAC9D,MAAM,SAAS,GAAG,IAAI,CAAC,QAAQ,EAAE,WAAW,EAAE,QAAQ,CAAC,CAAC;IACxD,SAAS,CAAC,YAAY,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC7C,SAAS,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAE1C,MAAM,QAAQ,GAA6C;QACzD;YACE,IAAI,EAAE,IAAI,CAAC,YAAY,EAAE,qBAAqB,CAAC;YAC/C,OAAO,EAAE;;;;;;;;;;;;CAYd;SACI;QACD;YACE,IAAI,EAAE,IAAI,CAAC,SAAS,EAAE,wBAAwB,CAAC;YAC/C,OAAO,EAAE;;;;;;;;;CASd;SACI;KACF,CAAC;IAEF,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;QAC/B,IAAI,UAAU,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;YAC7B,OAAO,CAAC,GAAG,CAAC,OAAO,OAAO,CAAC,IAAI,2BAA2B,CAAC,CAAC;QAC9D,CAAC;aAAM,CAAC;YACN,aAAa,CAAC,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;YACrD,OAAO,CAAC,GAAG,CAAC,OAAO,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC;QACrC,CAAC;IACH,CAAC;IACD,mBAAmB,CAAC,QAAQ,CAAC,CAAC;IAC9B,OAAO,CAAC,GAAG,CAAC,2CAA2C,CAAC,CAAC;AAC3D,CAAC;AAED,iFAAiF;AAEjF,SAAS,SAAS,CAAC,QAAgB;IACjC,MAAM,OAAO,GAAG,IAAI,CAAC,QAAQ,EAAE,WAAW,CAAC,CAAC;IAC5C,MAAM,KAAK,GAAG,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IACrC,mBAAmB,CAAC,QAAQ,CAAC,CAAC;IAC9B,OAAO,KAAK,CAAC;AACf,CAAC;AAED,uFAAuF;AACvF,SAAS,mBAAmB,CAAC,QAAgB;IAC3C,MAAM,IAAI,GAAG,IAAI,CAAC,QAAQ,EAAE,WAAW,EAAE,YAAY,CAAC,CAAC;IACvD,IAAI,CAAC;QACH,SAAS,CAAC,IAAI,CAAC,QAAQ,EAAE,WAAW,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAC5D,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC;YAAE,aAAa,CAAC,IAAI,EAAE,mCAAmC,EAAE,MAAM,CAAC,CAAC;IAC1F,CAAC;IAAC,MAAM,CAAC;QACP,YAAY;IACd,CAAC;AACH,CAAC;AAED,SAAS,cAAc;IACrB,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;QACrD,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,EAAE,cAAc,CAAC,EAAE,MAAM,CAAC,CAAyB,CAAC;QACvG,OAAO,GAAG,CAAC,OAAO,IAAI,OAAO,CAAC;IAChC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,OAAO,CAAC;IACjB,CAAC;AACH,CAAC;AAED,SAAS,OAAO,CAAC,GAAW;IAC1B,MAAM,GAAG,GACP,OAAO,CAAC,QAAQ,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,QAAQ,KAAK,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,UAAU,CAAC;IAC7F,MAAM,IAAI,GAAG,OAAO,CAAC,QAAQ,KAAK,OAAO,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,OAAO,EAAE,EAAE,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;IAC7E,IAAI,CAAC;QACH,KAAK,CAAC,GAAG,EAAE,IAAI,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,KAAK,EAAE,CAAC;IAChE,CAAC;IAAC,MAAM,CAAC;QACP,4BAA4B;IAC9B,CAAC;AACH,CAAC;AAED,SAAS,WAAW,CAAC,KAAc;IACjC,IAAI,CAAC;QACH,MAAM,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;QAChC,OAAO,CAAC,CAAC,MAAM,GAAG,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;IACpD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC;AAED,SAAS,SAAS,CAAC,CAAS;IAC1B,MAAM,IAAI,GAAG,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;IACpC,OAAO,IAAI,CAAC,MAAM,GAAG,GAAG,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC;AAC7D,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,GAAY,EAAE,EAAE;IAC5B,OAAO,CAAC,KAAK,CAAC,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;IAChE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
@@ -0,0 +1,218 @@
1
+ import { EventEmitter } from 'node:events';
2
+ import { z } from 'zod';
3
+ export type RunStatus = 'queued' | 'running' | 'waiting' | 'done' | 'failed' | 'cancelled';
4
+ export type StepStatus = 'pending' | 'running' | 'waiting' | 'done' | 'failed' | 'cancelled' | 'skipped';
5
+ declare const stepStateSchema: z.ZodObject<{
6
+ id: z.ZodString;
7
+ name: z.ZodString;
8
+ kind: z.ZodEnum<["agent", "check"]>;
9
+ status: z.ZodEnum<["pending", "running", "waiting", "done", "failed", "cancelled", "skipped"]>;
10
+ iterations: z.ZodNumber;
11
+ tokensUsed: z.ZodNumber;
12
+ startedAt: z.ZodOptional<z.ZodString>;
13
+ finishedAt: z.ZodOptional<z.ZodString>;
14
+ error: z.ZodOptional<z.ZodString>;
15
+ /** Latest claude session id — the user can `claude --resume <id>` with it. */
16
+ sessionId: z.ZodOptional<z.ZodString>;
17
+ /** Dollar cost reported by the claude CLI for this step's turns. */
18
+ costUsd: z.ZodOptional<z.ZodNumber>;
19
+ }, "strip", z.ZodTypeAny, {
20
+ name: string;
21
+ status: "running" | "waiting" | "done" | "failed" | "cancelled" | "pending" | "skipped";
22
+ id: string;
23
+ kind: "agent" | "check";
24
+ iterations: number;
25
+ tokensUsed: number;
26
+ startedAt?: string | undefined;
27
+ finishedAt?: string | undefined;
28
+ error?: string | undefined;
29
+ sessionId?: string | undefined;
30
+ costUsd?: number | undefined;
31
+ }, {
32
+ name: string;
33
+ status: "running" | "waiting" | "done" | "failed" | "cancelled" | "pending" | "skipped";
34
+ id: string;
35
+ kind: "agent" | "check";
36
+ iterations: number;
37
+ tokensUsed: number;
38
+ startedAt?: string | undefined;
39
+ finishedAt?: string | undefined;
40
+ error?: string | undefined;
41
+ sessionId?: string | undefined;
42
+ costUsd?: number | undefined;
43
+ }>;
44
+ declare const runRecordSchema: z.ZodObject<{
45
+ id: z.ZodString;
46
+ title: z.ZodString;
47
+ workflow: z.ZodString;
48
+ task: z.ZodString;
49
+ model: z.ZodOptional<z.ZodString>;
50
+ status: z.ZodEnum<["queued", "running", "waiting", "done", "failed", "cancelled"]>;
51
+ createdAt: z.ZodString;
52
+ startedAt: z.ZodOptional<z.ZodString>;
53
+ finishedAt: z.ZodOptional<z.ZodString>;
54
+ tokensUsed: z.ZodNumber;
55
+ costUsd: z.ZodOptional<z.ZodNumber>;
56
+ /** First GitHub PR URL spotted in the transcript (the janitor trick). */
57
+ pullRequestUrl: z.ZodOptional<z.ZodString>;
58
+ archived: z.ZodDefault<z.ZodBoolean>;
59
+ archivedAt: z.ZodOptional<z.ZodString>;
60
+ currentStepId: z.ZodOptional<z.ZodString>;
61
+ error: z.ZodOptional<z.ZodString>;
62
+ steps: z.ZodArray<z.ZodObject<{
63
+ id: z.ZodString;
64
+ name: z.ZodString;
65
+ kind: z.ZodEnum<["agent", "check"]>;
66
+ status: z.ZodEnum<["pending", "running", "waiting", "done", "failed", "cancelled", "skipped"]>;
67
+ iterations: z.ZodNumber;
68
+ tokensUsed: z.ZodNumber;
69
+ startedAt: z.ZodOptional<z.ZodString>;
70
+ finishedAt: z.ZodOptional<z.ZodString>;
71
+ error: z.ZodOptional<z.ZodString>;
72
+ /** Latest claude session id — the user can `claude --resume <id>` with it. */
73
+ sessionId: z.ZodOptional<z.ZodString>;
74
+ /** Dollar cost reported by the claude CLI for this step's turns. */
75
+ costUsd: z.ZodOptional<z.ZodNumber>;
76
+ }, "strip", z.ZodTypeAny, {
77
+ name: string;
78
+ status: "running" | "waiting" | "done" | "failed" | "cancelled" | "pending" | "skipped";
79
+ id: string;
80
+ kind: "agent" | "check";
81
+ iterations: number;
82
+ tokensUsed: number;
83
+ startedAt?: string | undefined;
84
+ finishedAt?: string | undefined;
85
+ error?: string | undefined;
86
+ sessionId?: string | undefined;
87
+ costUsd?: number | undefined;
88
+ }, {
89
+ name: string;
90
+ status: "running" | "waiting" | "done" | "failed" | "cancelled" | "pending" | "skipped";
91
+ id: string;
92
+ kind: "agent" | "check";
93
+ iterations: number;
94
+ tokensUsed: number;
95
+ startedAt?: string | undefined;
96
+ finishedAt?: string | undefined;
97
+ error?: string | undefined;
98
+ sessionId?: string | undefined;
99
+ costUsd?: number | undefined;
100
+ }>, "many">;
101
+ }, "strip", z.ZodTypeAny, {
102
+ status: "queued" | "running" | "waiting" | "done" | "failed" | "cancelled";
103
+ id: string;
104
+ tokensUsed: number;
105
+ title: string;
106
+ workflow: string;
107
+ task: string;
108
+ createdAt: string;
109
+ archived: boolean;
110
+ steps: {
111
+ name: string;
112
+ status: "running" | "waiting" | "done" | "failed" | "cancelled" | "pending" | "skipped";
113
+ id: string;
114
+ kind: "agent" | "check";
115
+ iterations: number;
116
+ tokensUsed: number;
117
+ startedAt?: string | undefined;
118
+ finishedAt?: string | undefined;
119
+ error?: string | undefined;
120
+ sessionId?: string | undefined;
121
+ costUsd?: number | undefined;
122
+ }[];
123
+ startedAt?: string | undefined;
124
+ finishedAt?: string | undefined;
125
+ error?: string | undefined;
126
+ costUsd?: number | undefined;
127
+ model?: string | undefined;
128
+ pullRequestUrl?: string | undefined;
129
+ archivedAt?: string | undefined;
130
+ currentStepId?: string | undefined;
131
+ }, {
132
+ status: "queued" | "running" | "waiting" | "done" | "failed" | "cancelled";
133
+ id: string;
134
+ tokensUsed: number;
135
+ title: string;
136
+ workflow: string;
137
+ task: string;
138
+ createdAt: string;
139
+ steps: {
140
+ name: string;
141
+ status: "running" | "waiting" | "done" | "failed" | "cancelled" | "pending" | "skipped";
142
+ id: string;
143
+ kind: "agent" | "check";
144
+ iterations: number;
145
+ tokensUsed: number;
146
+ startedAt?: string | undefined;
147
+ finishedAt?: string | undefined;
148
+ error?: string | undefined;
149
+ sessionId?: string | undefined;
150
+ costUsd?: number | undefined;
151
+ }[];
152
+ startedAt?: string | undefined;
153
+ finishedAt?: string | undefined;
154
+ error?: string | undefined;
155
+ costUsd?: number | undefined;
156
+ model?: string | undefined;
157
+ pullRequestUrl?: string | undefined;
158
+ archived?: boolean | undefined;
159
+ archivedAt?: string | undefined;
160
+ currentStepId?: string | undefined;
161
+ }>;
162
+ export type StepState = z.infer<typeof stepStateSchema>;
163
+ export type RunRecord = z.infer<typeof runRecordSchema>;
164
+ /** One persisted event line; `type` mirrors AgentEvent plus engine lifecycle. */
165
+ export interface RunEvent {
166
+ seq: number;
167
+ ts: string;
168
+ stepId?: string;
169
+ type: string;
170
+ [key: string]: unknown;
171
+ }
172
+ /**
173
+ * File-backed run store: `runs.json` index (atomic tmp+rename writes, the
174
+ * pattern from @cezar/core's IssueStore) plus one append-only NDJSON event
175
+ * file per run. Also the in-process event bus the SSE endpoints subscribe to:
176
+ * emits `('run', RunRecord)` and `('event', { runId, event: RunEvent })`.
177
+ */
178
+ export declare class RunStore extends EventEmitter {
179
+ private readonly dataDir;
180
+ private runs;
181
+ private saveTimer;
182
+ private constructor();
183
+ static open(dataDir: string): RunStore;
184
+ listRuns(): RunRecord[];
185
+ getRun(id: string): RunRecord | undefined;
186
+ createRun(input: {
187
+ title: string;
188
+ workflow: string;
189
+ task: string;
190
+ model?: string;
191
+ steps: Array<Pick<StepState, 'id' | 'name' | 'kind'>>;
192
+ }): RunRecord;
193
+ updateRun(id: string, patch: Partial<Omit<RunRecord, 'id' | 'steps'>>): RunRecord | undefined;
194
+ /** Append a step to an existing run (used by "Continue" — spec 003). */
195
+ addStep(runId: string, step: Pick<StepState, 'id' | 'name' | 'kind'>): void;
196
+ updateStep(runId: string, stepId: string, patch: Partial<Omit<StepState, 'id'>>): void;
197
+ setArchived(id: string, archived: boolean): RunRecord | undefined;
198
+ /** Bulk-archive every finished run; returns how many were archived. */
199
+ archiveFinished(): number;
200
+ appendEvent(runId: string, event: {
201
+ type: string;
202
+ stepId?: string;
203
+ [key: string]: unknown;
204
+ }): RunEvent;
205
+ readEvents(runId: string): RunEvent[];
206
+ deleteRun(id: string): boolean;
207
+ /** Write the index out now (used on shutdown). */
208
+ flush(): void;
209
+ private seqs;
210
+ private nextSeq;
211
+ private eventsPath;
212
+ private touch;
213
+ private pruneOldRuns;
214
+ /** Debounced so token-usage updates don't rewrite the index per event. */
215
+ private scheduleSave;
216
+ private saveNow;
217
+ }
218
+ export {};