everything-claude-code 1.4.3

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 (57) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +739 -0
  3. package/README.zh-CN.md +523 -0
  4. package/crates/ecc-kernel/Cargo.lock +160 -0
  5. package/crates/ecc-kernel/Cargo.toml +15 -0
  6. package/crates/ecc-kernel/src/main.rs +710 -0
  7. package/docs/ecc.md +117 -0
  8. package/package.json +45 -0
  9. package/packs/blueprint.json +8 -0
  10. package/packs/forge.json +16 -0
  11. package/packs/instinct.json +16 -0
  12. package/packs/orchestra.json +15 -0
  13. package/packs/proof.json +8 -0
  14. package/packs/sentinel.json +8 -0
  15. package/prompts/ecc/patch.md +25 -0
  16. package/prompts/ecc/plan.md +28 -0
  17. package/schemas/ecc.apply.schema.json +35 -0
  18. package/schemas/ecc.config.schema.json +37 -0
  19. package/schemas/ecc.lock.schema.json +34 -0
  20. package/schemas/ecc.patch.schema.json +25 -0
  21. package/schemas/ecc.plan.schema.json +32 -0
  22. package/schemas/ecc.run.schema.json +67 -0
  23. package/schemas/ecc.verify.schema.json +27 -0
  24. package/schemas/hooks.schema.json +81 -0
  25. package/schemas/package-manager.schema.json +17 -0
  26. package/schemas/plugin.schema.json +13 -0
  27. package/scripts/ecc/catalog.js +82 -0
  28. package/scripts/ecc/config.js +43 -0
  29. package/scripts/ecc/diff.js +113 -0
  30. package/scripts/ecc/exec.js +121 -0
  31. package/scripts/ecc/fixtures/basic/patches/impl-core.diff +8 -0
  32. package/scripts/ecc/fixtures/basic/patches/tests.diff +8 -0
  33. package/scripts/ecc/fixtures/basic/plan.json +23 -0
  34. package/scripts/ecc/fixtures/unauthorized/patches/impl-core.diff +8 -0
  35. package/scripts/ecc/fixtures/unauthorized/plan.json +15 -0
  36. package/scripts/ecc/git.js +139 -0
  37. package/scripts/ecc/id.js +37 -0
  38. package/scripts/ecc/install-kernel.js +344 -0
  39. package/scripts/ecc/json-extract.js +301 -0
  40. package/scripts/ecc/json.js +26 -0
  41. package/scripts/ecc/kernel.js +144 -0
  42. package/scripts/ecc/lock.js +36 -0
  43. package/scripts/ecc/paths.js +28 -0
  44. package/scripts/ecc/plan.js +57 -0
  45. package/scripts/ecc/project.js +37 -0
  46. package/scripts/ecc/providers/codex.js +168 -0
  47. package/scripts/ecc/providers/index.js +23 -0
  48. package/scripts/ecc/providers/mock.js +49 -0
  49. package/scripts/ecc/report.js +127 -0
  50. package/scripts/ecc/run.js +105 -0
  51. package/scripts/ecc/validate.js +325 -0
  52. package/scripts/ecc/verify.js +125 -0
  53. package/scripts/ecc.js +532 -0
  54. package/scripts/lib/package-manager.js +390 -0
  55. package/scripts/lib/session-aliases.js +432 -0
  56. package/scripts/lib/session-manager.js +396 -0
  57. package/scripts/lib/utils.js +426 -0
package/scripts/ecc.js ADDED
@@ -0,0 +1,532 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * ECC (Engineering Change Conveyor) - Codex-first engineering delivery engine.
4
+ *
5
+ * P0 goals:
6
+ * - Patch-only code sovereignty (providers output JSON/patch only; engine applies)
7
+ * - External worktree isolation for exec/verify
8
+ * - Evidence chain on disk under .ecc/runs/<runId>/
9
+ *
10
+ * Dependency-free by design.
11
+ */
12
+
13
+ const fs = require('fs');
14
+ const path = require('path');
15
+ const { spawnSync } = require('child_process');
16
+
17
+ const { ensureDir } = require('./lib/utils');
18
+
19
+ const catalog = require('./ecc/catalog');
20
+ const configMod = require('./ecc/config');
21
+ const lockMod = require('./ecc/lock');
22
+ const project = require('./ecc/project');
23
+ const runMod = require('./ecc/run');
24
+ const idMod = require('./ecc/id');
25
+ const planMod = require('./ecc/plan');
26
+ const execMod = require('./ecc/exec');
27
+ const verifyMod = require('./ecc/verify');
28
+ const reportMod = require('./ecc/report');
29
+ const git = require('./ecc/git');
30
+ const { readJson } = require('./ecc/json');
31
+ const { validateLock, throwIfErrors } = require('./ecc/validate');
32
+ const { getProvider } = require('./ecc/providers');
33
+ const kernel = require('./ecc/kernel');
34
+
35
+ function parseArgs(argv) {
36
+ const args = { _: [] };
37
+ for (let i = 2; i < argv.length; i++) {
38
+ const a = argv[i];
39
+ if (a === '--help' || a === '-h') {
40
+ args.help = true;
41
+ continue;
42
+ }
43
+ if (a.startsWith('--')) {
44
+ const key = a.slice(2);
45
+ const next = argv[i + 1];
46
+ if (!next || next.startsWith('--')) {
47
+ args[key] = true;
48
+ continue;
49
+ }
50
+ args[key] = next;
51
+ i++;
52
+ continue;
53
+ }
54
+ args._.push(a);
55
+ }
56
+ return args;
57
+ }
58
+
59
+ function usage(exitCode = 0) {
60
+ console.log(`
61
+ ecc (Engineering Change Conveyor)
62
+
63
+ Usage:
64
+ ecc <command> [args...]
65
+ node scripts/ecc.js <command> [args...] # fallback if not installed
66
+
67
+ Commands (P0):
68
+ packs
69
+ init [--backend codex|claude] [--packs a,b,c]
70
+ doctor
71
+ plan "<intent>" [--run-id <id>]
72
+ exec <runId> [--commit] [--worktree-root <path>] [--keep-worktree]
73
+ verify <runId> [--worktree-root <path>]
74
+ run "<intent>" [--commit] [--run-id <id>] [--worktree-root <path>] [--keep-worktree]
75
+
76
+ Environment:
77
+ ECC_PROVIDER=mock|codex Override provider selection (tests use mock)
78
+ ECC_FIXTURE=basic|unauthorized (mock provider fixtures)
79
+ `.trim());
80
+ process.exit(exitCode);
81
+ }
82
+
83
+ function resolveProjectRoot(cwd) {
84
+ try {
85
+ return git.getRepoRoot(cwd) || cwd;
86
+ } catch (_err) {
87
+ return cwd;
88
+ }
89
+ }
90
+
91
+ function ensureEccGitignore(projectRoot) {
92
+ const content = [
93
+ '# ECC runtime artifacts (do not commit)',
94
+ 'runs/',
95
+ 'cache/',
96
+ 'tmp/',
97
+ ''
98
+ ].join('\n');
99
+ ensureDir(project.eccDir(projectRoot));
100
+ fs.writeFileSync(project.gitignorePath(projectRoot), content, 'utf8');
101
+ }
102
+
103
+ function listPacks() {
104
+ const packs = catalog.loadPacks();
105
+ if (!packs.length) {
106
+ console.log('No packs found.');
107
+ return;
108
+ }
109
+
110
+ console.log('Packs\n=====\n');
111
+ for (const p of packs) {
112
+ const tags = p.tags.length ? ` [${p.tags.join(', ')}]` : '';
113
+ console.log(`- ${p.id}: ${p.name}${tags}\n ${p.description}`);
114
+ }
115
+ }
116
+
117
+ function parsePacksArg(arg) {
118
+ if (!arg) return null;
119
+ return String(arg)
120
+ .split(',')
121
+ .map(s => s.trim())
122
+ .filter(Boolean);
123
+ }
124
+
125
+ function validateSelectedPacks(selected) {
126
+ const known = new Set(catalog.loadPacks().map(p => p.id));
127
+ const unknown = selected.filter(p => !known.has(p));
128
+ if (unknown.length) throw new Error(`Unknown packs: ${unknown.join(', ')}`);
129
+ }
130
+
131
+ function cmdInit(args) {
132
+ const cwd = process.cwd();
133
+ const projectRoot = resolveProjectRoot(cwd);
134
+
135
+ const backend = args.backend ? String(args.backend) : 'codex';
136
+ if (!['codex', 'claude'].includes(backend)) {
137
+ throw new Error('init: --backend must be "codex" or "claude"');
138
+ }
139
+
140
+ const packsArg = parsePacksArg(args.packs);
141
+ const selected = packsArg && packsArg.length ? packsArg : catalog.getDefaultPacks();
142
+ validateSelectedPacks(selected);
143
+
144
+ let cfg = configMod.loadConfig(projectRoot);
145
+ const cfgPath = project.configPath(projectRoot);
146
+ const existed = !!cfg;
147
+ if (!cfg) {
148
+ cfg = configMod.createConfig({ backend, packs: selected });
149
+ configMod.saveConfig(projectRoot, cfg);
150
+ }
151
+
152
+ ensureEccGitignore(projectRoot);
153
+ ensureDir(project.locksDir(projectRoot));
154
+ lockMod.writeRegistryLock(projectRoot, { packs: cfg.packs, overwrite: false });
155
+
156
+ console.log(`${existed ? 'Already initialized' : 'Initialized'} ECC: ${path.relative(projectRoot, cfgPath)}`);
157
+ console.log(`Backend: ${cfg.backend}`);
158
+ console.log(`Packs: ${cfg.packs.join(', ')}`);
159
+ }
160
+
161
+ function runCmd(cmd, cmdArgs, opts = {}) {
162
+ const res = spawnSync(cmd, cmdArgs, {
163
+ encoding: 'utf8',
164
+ stdio: ['ignore', 'pipe', 'pipe'],
165
+ ...opts
166
+ });
167
+ return {
168
+ ok: res.status === 0,
169
+ status: res.status,
170
+ stdout: (res.stdout || '').trimEnd(),
171
+ stderr: (res.stderr || '').trimEnd()
172
+ };
173
+ }
174
+
175
+ function cmdDoctor() {
176
+ const cwd = process.cwd();
177
+ const projectRoot = resolveProjectRoot(cwd);
178
+ const checks = [];
179
+
180
+ checks.push({ name: 'node', ok: true, detail: process.version });
181
+
182
+ try {
183
+ const k = kernel.getKernel();
184
+ const detail = k.enabled ? `rust (${k.bin})` : 'js fallback';
185
+ checks.push({ name: 'kernel', ok: true, detail });
186
+ } catch (err) {
187
+ const msg = err && err.message ? err.message : String(err);
188
+ checks.push({ name: 'kernel', ok: false, detail: msg });
189
+ }
190
+
191
+ const gitVer = runCmd('git', ['--version']);
192
+ checks.push({ name: 'git', ok: gitVer.ok, detail: gitVer.ok ? gitVer.stdout : gitVer.stderr });
193
+
194
+ const repoRoot = gitVer.ok ? git.getRepoRoot(projectRoot) : null;
195
+ checks.push({ name: 'repo', ok: !!repoRoot, detail: repoRoot ? repoRoot : 'not a git repo' });
196
+
197
+ if (repoRoot) {
198
+ let clean = false;
199
+ let detail = '';
200
+ try {
201
+ clean = git.isClean(repoRoot);
202
+ detail = clean ? 'clean' : 'dirty';
203
+ } catch (err) {
204
+ clean = false;
205
+ detail = err && err.message ? err.message : String(err);
206
+ }
207
+ checks.push({ name: 'clean', ok: clean, detail });
208
+ }
209
+
210
+ const codex = runCmd('codex', ['--version']);
211
+ checks.push({ name: 'codex', ok: codex.ok, detail: codex.ok ? codex.stdout : codex.stderr });
212
+
213
+ const claude = runCmd('claude', ['--version']);
214
+ checks.push({ name: 'claude', ok: claude.ok, detail: claude.ok ? claude.stdout : claude.stderr });
215
+
216
+ const cfg = configMod.loadConfig(projectRoot);
217
+ checks.push({
218
+ name: 'ecc',
219
+ ok: !!cfg,
220
+ detail: cfg ? `initialized (${path.relative(projectRoot, project.configPath(projectRoot))})` : 'not initialized'
221
+ });
222
+
223
+ if (cfg) {
224
+ try {
225
+ validateSelectedPacks(cfg.packs);
226
+ checks.push({ name: 'packs', ok: true, detail: cfg.packs.join(', ') });
227
+ } catch (err) {
228
+ checks.push({ name: 'packs', ok: false, detail: err.message });
229
+ }
230
+ }
231
+
232
+ const lockPath = project.registryLockPath(projectRoot);
233
+ if (fs.existsSync(lockPath)) {
234
+ try {
235
+ const lock = readJson(lockPath);
236
+ throwIfErrors(validateLock(lock), 'registry lock');
237
+ checks.push({ name: 'lock', ok: true, detail: path.relative(projectRoot, lockPath) });
238
+ } catch (err) {
239
+ checks.push({ name: 'lock', ok: false, detail: err.message });
240
+ }
241
+ } else {
242
+ checks.push({ name: 'lock', ok: false, detail: `missing (${path.relative(projectRoot, lockPath)})` });
243
+ }
244
+
245
+ console.log('ECC Doctor\n==========\n');
246
+ for (const c of checks) {
247
+ const mark = c.ok ? 'OK ' : 'BAD';
248
+ console.log(`${mark} ${c.name.padEnd(8)} ${c.detail}`);
249
+ }
250
+
251
+ const failed = checks.filter(c => !c.ok);
252
+ if (failed.length) process.exit(1);
253
+ }
254
+
255
+ async function cmdPlan(args) {
256
+ const intent = args._[1];
257
+ if (!intent) throw new Error('plan: missing <intent>');
258
+
259
+ const cwd = process.cwd();
260
+ const projectRoot = resolveProjectRoot(cwd);
261
+
262
+ const cfg = configMod.loadConfig(projectRoot);
263
+ if (!cfg) throw new Error('ECC is not initialized (run: ecc init)');
264
+
265
+ const requestedRunId = args['run-id'] ? String(args['run-id']) : null;
266
+ const runIdBase = requestedRunId || idMod.defaultRunId(intent);
267
+ const runId = requestedRunId ? idMod.ensureUniqueRunId(projectRoot, requestedRunId) : idMod.ensureUniqueRunId(projectRoot, runIdBase);
268
+
269
+ const repoRoot = git.getRepoRoot(projectRoot);
270
+ const base = repoRoot
271
+ ? { repoRoot, branch: git.getCurrentBranch(repoRoot), sha: git.getHeadSha(repoRoot) }
272
+ : { repoRoot: projectRoot, branch: '', sha: '' };
273
+
274
+ const { run } = runMod.initRun({
275
+ projectRoot,
276
+ runId,
277
+ intent,
278
+ backend: cfg.backend,
279
+ packs: cfg.packs,
280
+ base
281
+ });
282
+
283
+ const provider = getProvider({ backend: cfg.backend });
284
+ await planMod.generatePlan({ projectRoot, run, provider });
285
+ reportMod.writeReport({ projectRoot, runId });
286
+
287
+ console.log(`Planned runId: ${runId}`);
288
+ console.log(`Artifacts: ${path.relative(projectRoot, runMod.runPaths(projectRoot, runId).root)}`);
289
+ }
290
+
291
+ async function cmdExec(args) {
292
+ const runId = args._[1];
293
+ if (!runId) throw new Error('exec: missing <runId>');
294
+
295
+ const cwd = process.cwd();
296
+ const projectRoot = resolveProjectRoot(cwd);
297
+
298
+ const cfg = configMod.loadConfig(projectRoot);
299
+ if (!cfg) throw new Error('ECC is not initialized (run: ecc init)');
300
+
301
+ const provider = getProvider({ backend: cfg.backend });
302
+ const worktreeRoot = args['worktree-root'] ? path.resolve(String(args['worktree-root'])) : null;
303
+ const keepWorktree = !!args['keep-worktree'];
304
+ const commit = !!args.commit;
305
+
306
+ let execResult;
307
+ try {
308
+ execResult = await execMod.execRun({ projectRoot, runId, provider, worktreeRoot });
309
+ } catch (err) {
310
+ const run = runMod.loadRun(projectRoot, runId);
311
+ if (run) runMod.saveRun(projectRoot, runId, runMod.markRunEnded(run, 'failed'));
312
+ reportMod.writeReport({ projectRoot, runId });
313
+ throw err;
314
+ }
315
+
316
+ const { worktreePath, applyResult, repoRoot } = execResult;
317
+
318
+ console.log(`Worktree: ${worktreePath}`);
319
+
320
+ if (commit) {
321
+ const run = runMod.loadRun(projectRoot, runId);
322
+ if (!run) throw new Error(`unknown runId: ${runId}`);
323
+
324
+ run.status = 'verifying';
325
+ runMod.saveRun(projectRoot, runId, run);
326
+
327
+ const summary = verifyMod.runVerify({
328
+ worktreePath,
329
+ verifyConfig: cfg.verify,
330
+ outDir: runMod.runPaths(projectRoot, runId).verifyDir
331
+ });
332
+
333
+ if (!summary.ok) {
334
+ runMod.saveRun(projectRoot, runId, runMod.markRunEnded(run, 'failed'));
335
+ reportMod.writeReport({ projectRoot, runId });
336
+ process.exit(1);
337
+ }
338
+
339
+ const sha = git.commitAll({ repoRoot: worktreePath, message: `ecc: ${runId}` });
340
+ applyResult.commit = { sha, message: `ecc: ${runId}` };
341
+ throwIfErrors(require('./ecc/validate').validateApplyResult(applyResult), 'apply result');
342
+ require('./ecc/json').writeJson(runMod.runPaths(projectRoot, runId).applyJson, applyResult);
343
+
344
+ runMod.saveRun(projectRoot, runId, runMod.markRunEnded(run, 'succeeded'));
345
+
346
+ if (!keepWorktree) {
347
+ try {
348
+ git.removeWorktree({ repoRoot, worktreePath });
349
+ run.worktree.path = '';
350
+ runMod.saveRun(projectRoot, runId, run);
351
+ } catch (_err) {
352
+ // ignore cleanup failures
353
+ }
354
+ }
355
+ }
356
+
357
+ reportMod.writeReport({ projectRoot, runId });
358
+ }
359
+
360
+ function cmdVerify(args) {
361
+ const runId = args._[1];
362
+ if (!runId) throw new Error('verify: missing <runId>');
363
+
364
+ const cwd = process.cwd();
365
+ const projectRoot = resolveProjectRoot(cwd);
366
+ const worktreeRoot = args['worktree-root'] ? path.resolve(String(args['worktree-root'])) : null;
367
+
368
+ const cfg = configMod.loadConfig(projectRoot);
369
+ if (!cfg) throw new Error('ECC is not initialized (run: ecc init)');
370
+
371
+ const run = runMod.loadRun(projectRoot, runId);
372
+ if (!run) throw new Error(`unknown runId: ${runId}`);
373
+
374
+ if (!run.worktree.path || !fs.existsSync(run.worktree.path)) {
375
+ const applyPath = runMod.runPaths(projectRoot, runId).applyJson;
376
+ const apply = fs.existsSync(applyPath) ? readJson(applyPath) : null;
377
+ const hasCommit = !!(apply && apply.commit && apply.commit.sha);
378
+ if (!hasCommit) {
379
+ throw new Error(
380
+ 'verify: missing worktree and changes were not committed. Re-run: ecc exec <runId> (or use --commit to persist changes).'
381
+ );
382
+ }
383
+
384
+ const repoRoot = git.getRepoRoot(projectRoot);
385
+ if (!repoRoot) throw new Error('verify: requires a git repository');
386
+
387
+ const wt = git.ensureWorktree({
388
+ repoRoot,
389
+ worktreePath: git.defaultWorktreePath({ repoRoot, runId, worktreeRoot }),
390
+ branch: run.worktree.branch,
391
+ baseSha: run.base.sha || git.getHeadSha(repoRoot)
392
+ });
393
+ run.worktree.path = wt;
394
+ runMod.saveRun(projectRoot, runId, run);
395
+ }
396
+
397
+ run.status = 'verifying';
398
+ runMod.saveRun(projectRoot, runId, run);
399
+
400
+ const summary = verifyMod.runVerify({
401
+ worktreePath: run.worktree.path,
402
+ verifyConfig: cfg.verify,
403
+ outDir: runMod.runPaths(projectRoot, runId).verifyDir
404
+ });
405
+
406
+ if (!summary.ok) {
407
+ runMod.saveRun(projectRoot, runId, runMod.markRunEnded(run, 'failed'));
408
+ reportMod.writeReport({ projectRoot, runId });
409
+ process.exit(1);
410
+ }
411
+
412
+ runMod.saveRun(projectRoot, runId, runMod.markRunEnded(run, 'succeeded'));
413
+ reportMod.writeReport({ projectRoot, runId });
414
+ }
415
+
416
+ async function cmdRun(args) {
417
+ const intent = args._[1];
418
+ if (!intent) throw new Error('run: missing <intent>');
419
+
420
+ const cwd = process.cwd();
421
+ const projectRoot = resolveProjectRoot(cwd);
422
+
423
+ const cfg = configMod.loadConfig(projectRoot);
424
+ if (!cfg) throw new Error('ECC is not initialized (run: ecc init)');
425
+
426
+ const requestedRunId = args['run-id'] ? String(args['run-id']) : null;
427
+ const runIdBase = requestedRunId || idMod.defaultRunId(intent);
428
+ const runId = requestedRunId ? idMod.ensureUniqueRunId(projectRoot, requestedRunId) : idMod.ensureUniqueRunId(projectRoot, runIdBase);
429
+
430
+ const repoRoot = git.getRepoRoot(projectRoot);
431
+ const base = repoRoot
432
+ ? { repoRoot, branch: git.getCurrentBranch(repoRoot), sha: git.getHeadSha(repoRoot) }
433
+ : { repoRoot: projectRoot, branch: '', sha: '' };
434
+
435
+ const { run } = runMod.initRun({
436
+ projectRoot,
437
+ runId,
438
+ intent,
439
+ backend: cfg.backend,
440
+ packs: cfg.packs,
441
+ base
442
+ });
443
+
444
+ const provider = getProvider({ backend: cfg.backend });
445
+ await planMod.generatePlan({ projectRoot, run, provider });
446
+ reportMod.writeReport({ projectRoot, runId });
447
+
448
+ const worktreeRoot = args['worktree-root'] ? path.resolve(String(args['worktree-root'])) : null;
449
+ const keepWorktree = !!args['keep-worktree'];
450
+ const commit = !!args.commit;
451
+
452
+ let execResult;
453
+ try {
454
+ execResult = await execMod.execRun({ projectRoot, runId, provider, worktreeRoot });
455
+ } catch (err) {
456
+ const loaded = runMod.loadRun(projectRoot, runId);
457
+ if (loaded) runMod.saveRun(projectRoot, runId, runMod.markRunEnded(loaded, 'failed'));
458
+ reportMod.writeReport({ projectRoot, runId });
459
+ throw err;
460
+ }
461
+
462
+ {
463
+ const loaded = runMod.loadRun(projectRoot, runId);
464
+ if (loaded) {
465
+ loaded.status = 'verifying';
466
+ runMod.saveRun(projectRoot, runId, loaded);
467
+ }
468
+ }
469
+
470
+ const summary = verifyMod.runVerify({
471
+ worktreePath: execResult.worktreePath,
472
+ verifyConfig: cfg.verify,
473
+ outDir: runMod.runPaths(projectRoot, runId).verifyDir
474
+ });
475
+
476
+ if (!summary.ok) {
477
+ const loaded = runMod.loadRun(projectRoot, runId);
478
+ if (loaded) runMod.saveRun(projectRoot, runId, runMod.markRunEnded(loaded, 'failed'));
479
+ reportMod.writeReport({ projectRoot, runId });
480
+ process.exit(1);
481
+ }
482
+
483
+ if (commit) {
484
+ const sha = git.commitAll({ repoRoot: execResult.worktreePath, message: `ecc: ${runId}` });
485
+ execResult.applyResult.commit = { sha, message: `ecc: ${runId}` };
486
+ require('./ecc/json').writeJson(runMod.runPaths(projectRoot, runId).applyJson, execResult.applyResult);
487
+ }
488
+
489
+ const loaded = runMod.loadRun(projectRoot, runId);
490
+ if (loaded) runMod.saveRun(projectRoot, runId, runMod.markRunEnded(loaded, 'succeeded'));
491
+ reportMod.writeReport({ projectRoot, runId });
492
+
493
+ console.log(`RunId: ${runId}`);
494
+ console.log(`Worktree: ${execResult.worktreePath}`);
495
+
496
+ if (commit && !keepWorktree) {
497
+ try {
498
+ git.removeWorktree({ repoRoot: execResult.repoRoot, worktreePath: execResult.worktreePath });
499
+ const loaded2 = runMod.loadRun(projectRoot, runId);
500
+ if (loaded2) {
501
+ loaded2.worktree.path = '';
502
+ runMod.saveRun(projectRoot, runId, loaded2);
503
+ }
504
+ } catch (_err) {
505
+ // ignore cleanup failures
506
+ }
507
+ }
508
+ }
509
+
510
+ async function main() {
511
+ const args = parseArgs(process.argv);
512
+ if (args.help) usage(0);
513
+
514
+ const cmd = args._[0];
515
+ if (!cmd) usage(1);
516
+
517
+ if (cmd === 'packs') return listPacks();
518
+ if (cmd === 'init') return cmdInit(args);
519
+ if (cmd === 'doctor') return cmdDoctor();
520
+ if (cmd === 'plan') return cmdPlan(args);
521
+ if (cmd === 'exec') return cmdExec(args);
522
+ if (cmd === 'verify') return cmdVerify(args);
523
+ if (cmd === 'run') return cmdRun(args);
524
+
525
+ usage(1);
526
+ }
527
+
528
+ main().catch(err => {
529
+ const msg = err && err.message ? err.message : String(err);
530
+ console.error(`ERROR: ${msg}`);
531
+ process.exit(1);
532
+ });