@os-eco/overstory-cli 0.7.0 → 0.7.2

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 (60) hide show
  1. package/README.md +6 -5
  2. package/agents/builder.md +1 -1
  3. package/agents/coordinator.md +12 -11
  4. package/agents/lead.md +6 -6
  5. package/agents/monitor.md +4 -4
  6. package/agents/reviewer.md +1 -1
  7. package/agents/scout.md +5 -5
  8. package/agents/supervisor.md +36 -32
  9. package/package.json +1 -1
  10. package/src/agents/guard-rules.ts +97 -0
  11. package/src/agents/hooks-deployer.ts +7 -90
  12. package/src/agents/overlay.test.ts +7 -7
  13. package/src/agents/overlay.ts +5 -5
  14. package/src/commands/agents.test.ts +5 -0
  15. package/src/commands/clean.test.ts +3 -0
  16. package/src/commands/completions.ts +1 -1
  17. package/src/commands/coordinator.test.ts +1 -0
  18. package/src/commands/coordinator.ts +15 -11
  19. package/src/commands/costs.test.ts +5 -0
  20. package/src/commands/init.test.ts +1 -2
  21. package/src/commands/init.ts +1 -8
  22. package/src/commands/inspect.test.ts +14 -0
  23. package/src/commands/log.test.ts +14 -0
  24. package/src/commands/log.ts +39 -0
  25. package/src/commands/mail.test.ts +5 -0
  26. package/src/commands/monitor.ts +15 -11
  27. package/src/commands/nudge.test.ts +1 -0
  28. package/src/commands/prime.test.ts +2 -0
  29. package/src/commands/prime.ts +6 -2
  30. package/src/commands/run.test.ts +1 -0
  31. package/src/commands/sling.test.ts +15 -1
  32. package/src/commands/sling.ts +44 -21
  33. package/src/commands/status.test.ts +1 -0
  34. package/src/commands/stop.test.ts +1 -0
  35. package/src/commands/supervisor.ts +19 -12
  36. package/src/commands/trace.test.ts +1 -0
  37. package/src/commands/worktree.test.ts +9 -0
  38. package/src/config.ts +29 -0
  39. package/src/doctor/consistency.test.ts +14 -0
  40. package/src/e2e/init-sling-lifecycle.test.ts +3 -5
  41. package/src/index.ts +1 -1
  42. package/src/mail/broadcast.test.ts +1 -0
  43. package/src/merge/resolver.ts +23 -4
  44. package/src/runtimes/claude.test.ts +1 -1
  45. package/src/runtimes/pi-guards.test.ts +433 -0
  46. package/src/runtimes/pi-guards.ts +349 -0
  47. package/src/runtimes/pi.test.ts +620 -0
  48. package/src/runtimes/pi.ts +244 -0
  49. package/src/runtimes/registry.test.ts +33 -0
  50. package/src/runtimes/registry.ts +15 -2
  51. package/src/runtimes/types.ts +63 -0
  52. package/src/schema-consistency.test.ts +1 -0
  53. package/src/sessions/compat.ts +1 -0
  54. package/src/sessions/store.test.ts +31 -0
  55. package/src/sessions/store.ts +37 -4
  56. package/src/types.ts +17 -0
  57. package/src/watchdog/daemon.test.ts +7 -4
  58. package/src/watchdog/daemon.ts +1 -1
  59. package/src/watchdog/health.test.ts +1 -0
  60. package/src/watchdog/triage.ts +14 -4
@@ -207,6 +207,7 @@ describe("checkConsistency", () => {
207
207
  lastActivity: new Date().toISOString(),
208
208
  escalationLevel: 0,
209
209
  stalledSince: null,
210
+ transcriptPath: null,
210
211
  });
211
212
  store.close();
212
213
 
@@ -243,6 +244,7 @@ describe("checkConsistency", () => {
243
244
  lastActivity: new Date().toISOString(),
244
245
  escalationLevel: 0,
245
246
  stalledSince: null,
247
+ transcriptPath: null,
246
248
  });
247
249
  store.close();
248
250
 
@@ -278,6 +280,7 @@ describe("checkConsistency", () => {
278
280
  lastActivity: new Date().toISOString(),
279
281
  escalationLevel: 0,
280
282
  stalledSince: null,
283
+ transcriptPath: null,
281
284
  });
282
285
  store.close();
283
286
 
@@ -314,6 +317,7 @@ describe("checkConsistency", () => {
314
317
  lastActivity: new Date().toISOString(),
315
318
  escalationLevel: 0,
316
319
  stalledSince: null,
320
+ transcriptPath: null,
317
321
  });
318
322
  store.close();
319
323
 
@@ -353,6 +357,7 @@ describe("checkConsistency", () => {
353
357
  lastActivity: new Date().toISOString(),
354
358
  escalationLevel: 0,
355
359
  stalledSince: null,
360
+ transcriptPath: null,
356
361
  });
357
362
  store.close();
358
363
 
@@ -426,6 +431,7 @@ describe("checkConsistency", () => {
426
431
  lastActivity: new Date().toISOString(),
427
432
  escalationLevel: 0,
428
433
  stalledSince: null,
434
+ transcriptPath: null,
429
435
  });
430
436
 
431
437
  store.upsert({
@@ -445,6 +451,7 @@ describe("checkConsistency", () => {
445
451
  lastActivity: new Date().toISOString(),
446
452
  escalationLevel: 0,
447
453
  stalledSince: null,
454
+ transcriptPath: null,
448
455
  });
449
456
  store.close();
450
457
 
@@ -481,6 +488,7 @@ describe("checkConsistency", () => {
481
488
  lastActivity: new Date().toISOString(),
482
489
  escalationLevel: 0,
483
490
  stalledSince: null,
491
+ transcriptPath: null,
484
492
  });
485
493
  }
486
494
 
@@ -501,6 +509,7 @@ describe("checkConsistency", () => {
501
509
  lastActivity: new Date().toISOString(),
502
510
  escalationLevel: 0,
503
511
  stalledSince: null,
512
+ transcriptPath: null,
504
513
  });
505
514
  store.close();
506
515
 
@@ -535,6 +544,7 @@ describe("checkConsistency", () => {
535
544
  lastActivity: new Date().toISOString(),
536
545
  escalationLevel: 0,
537
546
  stalledSince: null,
547
+ transcriptPath: null,
538
548
  });
539
549
 
540
550
  store.upsert({
@@ -554,6 +564,7 @@ describe("checkConsistency", () => {
554
564
  lastActivity: new Date().toISOString(),
555
565
  escalationLevel: 0,
556
566
  stalledSince: null,
567
+ transcriptPath: null,
557
568
  });
558
569
  }
559
570
  store.close();
@@ -597,6 +608,7 @@ describe("checkConsistency", () => {
597
608
  lastActivity: new Date().toISOString(),
598
609
  escalationLevel: 0,
599
610
  stalledSince: null,
611
+ transcriptPath: null,
600
612
  });
601
613
 
602
614
  store.upsert({
@@ -616,6 +628,7 @@ describe("checkConsistency", () => {
616
628
  lastActivity: new Date().toISOString(),
617
629
  escalationLevel: 0,
618
630
  stalledSince: null,
631
+ transcriptPath: null,
619
632
  });
620
633
 
621
634
  // Lead-2 has builders only (bad)
@@ -636,6 +649,7 @@ describe("checkConsistency", () => {
636
649
  lastActivity: new Date().toISOString(),
637
650
  escalationLevel: 0,
638
651
  stalledSince: null,
652
+ transcriptPath: null,
639
653
  });
640
654
  store.close();
641
655
 
@@ -27,7 +27,6 @@ const EXPECTED_AGENT_DEFS = [
27
27
  "monitor.md",
28
28
  "reviewer.md",
29
29
  "scout.md",
30
- "supervisor.md",
31
30
  ];
32
31
 
33
32
  describe("E2E: init→sling lifecycle on external project", () => {
@@ -77,7 +76,7 @@ describe("E2E: init→sling lifecycle on external project", () => {
77
76
  const gitignoreFile = Bun.file(join(overstoryDir, ".gitignore"));
78
77
  expect(await gitignoreFile.exists()).toBe(true);
79
78
 
80
- // agent-defs/ contains all 8 agent definition files
79
+ // agent-defs/ contains all 7 agent definition files (supervisor deprecated)
81
80
  const agentDefsDir = join(overstoryDir, "agent-defs");
82
81
  const agentDefFiles = (await readdir(agentDefsDir)).filter((f) => f.endsWith(".md")).sort();
83
82
  expect(agentDefFiles).toEqual(EXPECTED_AGENT_DEFS);
@@ -109,7 +108,7 @@ describe("E2E: init→sling lifecycle on external project", () => {
109
108
  expect(config.project.name).toBeTruthy();
110
109
  });
111
110
 
112
- test("manifest loads successfully with all 8 agents", async () => {
111
+ test("manifest loads successfully with all 7 agents (supervisor deprecated)", async () => {
113
112
  await initCommand({});
114
113
 
115
114
  const manifestPath = join(tempDir, ".overstory", "agent-manifest.json");
@@ -118,7 +117,7 @@ describe("E2E: init→sling lifecycle on external project", () => {
118
117
 
119
118
  const manifest = await loader.load();
120
119
 
121
- // All 8 agents present
120
+ // All 7 agents present (supervisor removed: deprecated, use lead instead)
122
121
  const agentNames = Object.keys(manifest.agents).sort();
123
122
  expect(agentNames).toEqual([
124
123
  "builder",
@@ -128,7 +127,6 @@ describe("E2E: init→sling lifecycle on external project", () => {
128
127
  "monitor",
129
128
  "reviewer",
130
129
  "scout",
131
- "supervisor",
132
130
  ]);
133
131
 
134
132
  // Each agent has a valid file reference
package/src/index.ts CHANGED
@@ -45,7 +45,7 @@ import { OverstoryError, WorktreeError } from "./errors.ts";
45
45
  import { jsonError } from "./json.ts";
46
46
  import { brand, chalk, muted, setQuiet } from "./logging/color.ts";
47
47
 
48
- export const VERSION = "0.7.0";
48
+ export const VERSION = "0.7.2";
49
49
 
50
50
  const rawArgs = process.argv.slice(2);
51
51
 
@@ -41,6 +41,7 @@ describe("resolveGroupAddress", () => {
41
41
  lastActivity: "2024-01-01T00:01:00Z",
42
42
  escalationLevel: 0,
43
43
  stalledSince: null,
44
+ transcriptPath: null,
44
45
  };
45
46
  }
46
47
 
@@ -13,10 +13,12 @@
13
13
 
14
14
  import { MergeError } from "../errors.ts";
15
15
  import type { MulchClient } from "../mulch/client.ts";
16
+ import { getRuntime } from "../runtimes/registry.ts";
16
17
  import type {
17
18
  ConflictHistory,
18
19
  MergeEntry,
19
20
  MergeResult,
21
+ OverstoryConfig,
20
22
  ParsedConflictPattern,
21
23
  ResolutionTier,
22
24
  } from "../types.ts";
@@ -243,6 +245,7 @@ async function tryAiResolve(
243
245
  conflictFiles: string[],
244
246
  repoRoot: string,
245
247
  pastResolutions?: string[],
248
+ config?: OverstoryConfig,
246
249
  ): Promise<{ success: boolean; remainingConflicts: string[] }> {
247
250
  const remainingConflicts: string[] = [];
248
251
 
@@ -265,7 +268,9 @@ async function tryAiResolve(
265
268
  content,
266
269
  ].join(" ");
267
270
 
268
- const proc = Bun.spawn(["claude", "--print", "-p", prompt], {
271
+ const runtime = getRuntime(config?.runtime?.printCommand ?? config?.runtime?.default, config);
272
+ const argv = runtime.buildPrintCommand(prompt);
273
+ const proc = Bun.spawn(argv, {
269
274
  cwd: repoRoot,
270
275
  stdout: "pipe",
271
276
  stderr: "pipe",
@@ -315,6 +320,7 @@ async function tryReimagine(
315
320
  entry: MergeEntry,
316
321
  canonicalBranch: string,
317
322
  repoRoot: string,
323
+ config?: OverstoryConfig,
318
324
  ): Promise<{ success: boolean }> {
319
325
  // Abort the current merge
320
326
  await runGit(repoRoot, ["merge", "--abort"]);
@@ -348,7 +354,9 @@ async function tryReimagine(
348
354
  branchContent,
349
355
  ].join("");
350
356
 
351
- const proc = Bun.spawn(["claude", "--print", "-p", prompt], {
357
+ const runtime = getRuntime(config?.runtime?.printCommand ?? config?.runtime?.default, config);
358
+ const argv = runtime.buildPrintCommand(prompt);
359
+ const proc = Bun.spawn(argv, {
352
360
  cwd: repoRoot,
353
361
  stdout: "pipe",
354
362
  stderr: "pipe",
@@ -556,6 +564,7 @@ export function createMergeResolver(options: {
556
564
  aiResolveEnabled: boolean;
557
565
  reimagineEnabled: boolean;
558
566
  mulchClient?: MulchClient;
567
+ config?: OverstoryConfig;
559
568
  }): MergeResolver {
560
569
  return {
561
570
  async resolve(
@@ -632,7 +641,12 @@ export function createMergeResolver(options: {
632
641
  // Tier 3: AI-resolve
633
642
  if (options.aiResolveEnabled && !history.skipTiers.includes("ai-resolve")) {
634
643
  lastTier = "ai-resolve";
635
- const aiResult = await tryAiResolve(conflictFiles, repoRoot, history.pastResolutions);
644
+ const aiResult = await tryAiResolve(
645
+ conflictFiles,
646
+ repoRoot,
647
+ history.pastResolutions,
648
+ options.config,
649
+ );
636
650
  if (aiResult.success) {
637
651
  if (options.mulchClient) {
638
652
  recordConflictPattern(options.mulchClient, entry, "ai-resolve", conflictFiles, true);
@@ -651,7 +665,12 @@ export function createMergeResolver(options: {
651
665
  // Tier 4: Re-imagine
652
666
  if (options.reimagineEnabled && !history.skipTiers.includes("reimagine")) {
653
667
  lastTier = "reimagine";
654
- const reimagineResult = await tryReimagine(entry, canonicalBranch, repoRoot);
668
+ const reimagineResult = await tryReimagine(
669
+ entry,
670
+ canonicalBranch,
671
+ repoRoot,
672
+ options.config,
673
+ );
655
674
  if (reimagineResult.success) {
656
675
  if (options.mulchClient) {
657
676
  recordConflictPattern(options.mulchClient, entry, "reimagine", conflictFiles, true);
@@ -611,6 +611,6 @@ describe("ClaudeRuntime integration: registry resolves 'claude' as default", ()
611
611
  test("getRuntime rejects unknown runtimes", async () => {
612
612
  const { getRuntime } = await import("./registry.ts");
613
613
  expect(() => getRuntime("codex")).toThrow('Unknown runtime: "codex"');
614
- expect(() => getRuntime("pi")).toThrow('Unknown runtime: "pi"');
614
+ expect(() => getRuntime("opencode")).toThrow('Unknown runtime: "opencode"');
615
615
  });
616
616
  });