@os-eco/overstory-cli 0.6.4 → 0.6.6

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 (117) hide show
  1. package/README.md +61 -61
  2. package/agents/builder.md +16 -16
  3. package/agents/coordinator.md +57 -57
  4. package/agents/issue-reviews.md +71 -0
  5. package/agents/lead.md +43 -42
  6. package/agents/merger.md +15 -15
  7. package/agents/monitor.md +37 -37
  8. package/agents/pr-reviews.md +60 -0
  9. package/agents/prioritize.md +110 -0
  10. package/agents/release.md +56 -0
  11. package/agents/reviewer.md +15 -15
  12. package/agents/scout.md +18 -18
  13. package/agents/supervisor.md +78 -78
  14. package/package.json +1 -1
  15. package/src/agents/checkpoint.test.ts +2 -2
  16. package/src/agents/hooks-deployer.test.ts +59 -25
  17. package/src/agents/hooks-deployer.ts +24 -6
  18. package/src/agents/identity.test.ts +27 -27
  19. package/src/agents/identity.ts +10 -10
  20. package/src/agents/lifecycle.test.ts +6 -6
  21. package/src/agents/lifecycle.ts +2 -2
  22. package/src/agents/overlay.test.ts +14 -14
  23. package/src/agents/overlay.ts +14 -14
  24. package/src/commands/agents.test.ts +5 -5
  25. package/src/commands/agents.ts +10 -9
  26. package/src/commands/clean.test.ts +5 -5
  27. package/src/commands/clean.ts +5 -5
  28. package/src/commands/completions.test.ts +10 -10
  29. package/src/commands/completions.ts +26 -28
  30. package/src/commands/coordinator.test.ts +4 -4
  31. package/src/commands/coordinator.ts +13 -13
  32. package/src/commands/costs.test.ts +45 -45
  33. package/src/commands/costs.ts +1 -1
  34. package/src/commands/dashboard.ts +11 -11
  35. package/src/commands/doctor.ts +4 -4
  36. package/src/commands/errors.ts +1 -1
  37. package/src/commands/feed.ts +1 -1
  38. package/src/commands/group.ts +3 -3
  39. package/src/commands/hooks.test.ts +7 -7
  40. package/src/commands/hooks.ts +7 -7
  41. package/src/commands/init.test.ts +6 -2
  42. package/src/commands/init.ts +19 -19
  43. package/src/commands/inspect.test.ts +16 -16
  44. package/src/commands/inspect.ts +19 -19
  45. package/src/commands/log.test.ts +21 -21
  46. package/src/commands/log.ts +10 -10
  47. package/src/commands/logs.ts +1 -1
  48. package/src/commands/mail.test.ts +7 -7
  49. package/src/commands/mail.ts +28 -11
  50. package/src/commands/merge.test.ts +8 -8
  51. package/src/commands/merge.ts +15 -15
  52. package/src/commands/metrics.test.ts +7 -7
  53. package/src/commands/metrics.ts +3 -3
  54. package/src/commands/monitor.test.ts +5 -5
  55. package/src/commands/monitor.ts +5 -5
  56. package/src/commands/nudge.test.ts +1 -1
  57. package/src/commands/nudge.ts +1 -1
  58. package/src/commands/prime.test.ts +5 -5
  59. package/src/commands/prime.ts +8 -8
  60. package/src/commands/replay.ts +1 -1
  61. package/src/commands/run.test.ts +1 -1
  62. package/src/commands/run.ts +2 -2
  63. package/src/commands/sling.test.ts +89 -7
  64. package/src/commands/sling.ts +109 -18
  65. package/src/commands/spec.test.ts +2 -2
  66. package/src/commands/spec.ts +13 -14
  67. package/src/commands/status.test.ts +99 -3
  68. package/src/commands/status.ts +19 -20
  69. package/src/commands/stop.test.ts +1 -1
  70. package/src/commands/stop.ts +2 -2
  71. package/src/commands/supervisor.test.ts +10 -10
  72. package/src/commands/supervisor.ts +14 -14
  73. package/src/commands/trace.test.ts +7 -7
  74. package/src/commands/trace.ts +10 -10
  75. package/src/commands/watch.ts +5 -5
  76. package/src/commands/worktree.test.ts +208 -32
  77. package/src/commands/worktree.ts +56 -18
  78. package/src/doctor/consistency.test.ts +14 -14
  79. package/src/doctor/dependencies.test.ts +5 -5
  80. package/src/doctor/dependencies.ts +2 -2
  81. package/src/doctor/logs.ts +1 -1
  82. package/src/doctor/merge-queue.test.ts +4 -4
  83. package/src/doctor/structure.test.ts +1 -1
  84. package/src/doctor/structure.ts +1 -1
  85. package/src/doctor/version.test.ts +3 -3
  86. package/src/doctor/version.ts +1 -1
  87. package/src/e2e/init-sling-lifecycle.test.ts +8 -4
  88. package/src/errors.ts +1 -1
  89. package/src/index.ts +13 -11
  90. package/src/mail/broadcast.test.ts +1 -1
  91. package/src/mail/client.test.ts +7 -7
  92. package/src/mail/client.ts +2 -2
  93. package/src/mail/store.test.ts +3 -3
  94. package/src/merge/queue.test.ts +12 -12
  95. package/src/merge/queue.ts +2 -2
  96. package/src/merge/resolver.test.ts +159 -7
  97. package/src/merge/resolver.ts +46 -2
  98. package/src/metrics/store.test.ts +44 -44
  99. package/src/metrics/store.ts +2 -2
  100. package/src/metrics/summary.test.ts +35 -35
  101. package/src/mulch/client.test.ts +1 -1
  102. package/src/mulch/client.ts +1 -1
  103. package/src/sessions/compat.test.ts +3 -3
  104. package/src/sessions/compat.ts +1 -1
  105. package/src/sessions/store.test.ts +4 -4
  106. package/src/sessions/store.ts +2 -2
  107. package/src/types.ts +14 -14
  108. package/src/watchdog/daemon.test.ts +10 -10
  109. package/src/watchdog/daemon.ts +1 -1
  110. package/src/watchdog/health.test.ts +1 -1
  111. package/src/worktree/manager.test.ts +20 -20
  112. package/src/worktree/manager.ts +120 -4
  113. package/src/worktree/tmux.test.ts +8 -3
  114. package/src/worktree/tmux.ts +19 -18
  115. package/templates/CLAUDE.md.tmpl +27 -27
  116. package/templates/hooks.json.tmpl +15 -11
  117. package/templates/overlay.md.tmpl +7 -7
@@ -22,7 +22,7 @@ import { costsCommand } from "./costs.ts";
22
22
  function makeMetrics(overrides: Partial<SessionMetrics> = {}): SessionMetrics {
23
23
  return {
24
24
  agentName: "builder-1",
25
- beadId: "task-001",
25
+ taskId: "task-001",
26
26
  capability: "builder",
27
27
  startedAt: new Date().toISOString(),
28
28
  completedAt: new Date().toISOString(),
@@ -142,8 +142,8 @@ describe("costsCommand", () => {
142
142
  test("outputs valid JSON array with sessions", async () => {
143
143
  const dbPath = join(tempDir, ".overstory", "metrics.db");
144
144
  const store = createMetricsStore(dbPath);
145
- store.recordSession(makeMetrics({ agentName: "builder-1", beadId: "t1" }));
146
- store.recordSession(makeMetrics({ agentName: "scout-1", beadId: "t2", capability: "scout" }));
145
+ store.recordSession(makeMetrics({ agentName: "builder-1", taskId: "t1" }));
146
+ store.recordSession(makeMetrics({ agentName: "scout-1", taskId: "t2", capability: "scout" }));
147
147
  store.close();
148
148
 
149
149
  await costsCommand(["--json"]);
@@ -160,7 +160,7 @@ describe("costsCommand", () => {
160
160
  store.recordSession(
161
161
  makeMetrics({
162
162
  agentName: "builder-1",
163
- beadId: "t1",
163
+ taskId: "t1",
164
164
  inputTokens: 100,
165
165
  outputTokens: 50,
166
166
  cacheReadTokens: 30,
@@ -187,7 +187,7 @@ describe("costsCommand", () => {
187
187
  test("JSON output returns empty array when no sessions match", async () => {
188
188
  const dbPath = join(tempDir, ".overstory", "metrics.db");
189
189
  const store = createMetricsStore(dbPath);
190
- store.recordSession(makeMetrics({ agentName: "builder-1", beadId: "t1" }));
190
+ store.recordSession(makeMetrics({ agentName: "builder-1", taskId: "t1" }));
191
191
  store.close();
192
192
 
193
193
  await costsCommand(["--json", "--agent", "nonexistent"]);
@@ -203,7 +203,7 @@ describe("costsCommand", () => {
203
203
  store.recordSession(
204
204
  makeMetrics({
205
205
  agentName: "builder-1",
206
- beadId: "t1",
206
+ taskId: "t1",
207
207
  capability: "builder",
208
208
  inputTokens: 100,
209
209
  }),
@@ -211,7 +211,7 @@ describe("costsCommand", () => {
211
211
  store.recordSession(
212
212
  makeMetrics({
213
213
  agentName: "scout-1",
214
- beadId: "t2",
214
+ taskId: "t2",
215
215
  capability: "scout",
216
216
  inputTokens: 50,
217
217
  }),
@@ -238,7 +238,7 @@ describe("costsCommand", () => {
238
238
  test("shows Cost Summary header", async () => {
239
239
  const dbPath = join(tempDir, ".overstory", "metrics.db");
240
240
  const store = createMetricsStore(dbPath);
241
- store.recordSession(makeMetrics({ agentName: "builder-1", beadId: "t1" }));
241
+ store.recordSession(makeMetrics({ agentName: "builder-1", taskId: "t1" }));
242
242
  store.close();
243
243
 
244
244
  await costsCommand([]);
@@ -250,7 +250,7 @@ describe("costsCommand", () => {
250
250
  test("shows column headers", async () => {
251
251
  const dbPath = join(tempDir, ".overstory", "metrics.db");
252
252
  const store = createMetricsStore(dbPath);
253
- store.recordSession(makeMetrics({ agentName: "builder-1", beadId: "t1" }));
253
+ store.recordSession(makeMetrics({ agentName: "builder-1", taskId: "t1" }));
254
254
  store.close();
255
255
 
256
256
  await costsCommand([]);
@@ -270,7 +270,7 @@ describe("costsCommand", () => {
270
270
  store.recordSession(
271
271
  makeMetrics({
272
272
  agentName: "builder-1",
273
- beadId: "t1",
273
+ taskId: "t1",
274
274
  capability: "builder",
275
275
  }),
276
276
  );
@@ -286,7 +286,7 @@ describe("costsCommand", () => {
286
286
  test("shows separator line", async () => {
287
287
  const dbPath = join(tempDir, ".overstory", "metrics.db");
288
288
  const store = createMetricsStore(dbPath);
289
- store.recordSession(makeMetrics({ agentName: "builder-1", beadId: "t1" }));
289
+ store.recordSession(makeMetrics({ agentName: "builder-1", taskId: "t1" }));
290
290
  store.close();
291
291
 
292
292
  await costsCommand([]);
@@ -298,7 +298,7 @@ describe("costsCommand", () => {
298
298
  test("shows Total row", async () => {
299
299
  const dbPath = join(tempDir, ".overstory", "metrics.db");
300
300
  const store = createMetricsStore(dbPath);
301
- store.recordSession(makeMetrics({ agentName: "builder-1", beadId: "t1" }));
301
+ store.recordSession(makeMetrics({ agentName: "builder-1", taskId: "t1" }));
302
302
  store.close();
303
303
 
304
304
  await costsCommand([]);
@@ -329,7 +329,7 @@ describe("costsCommand", () => {
329
329
  store.recordSession(
330
330
  makeMetrics({
331
331
  agentName: "builder-1",
332
- beadId: "t1",
332
+ taskId: "t1",
333
333
  inputTokens: 12345,
334
334
  outputTokens: 5678,
335
335
  }),
@@ -349,7 +349,7 @@ describe("costsCommand", () => {
349
349
  store.recordSession(
350
350
  makeMetrics({
351
351
  agentName: "builder-1",
352
- beadId: "t1",
352
+ taskId: "t1",
353
353
  estimatedCostUsd: 0.42,
354
354
  }),
355
355
  );
@@ -367,7 +367,7 @@ describe("costsCommand", () => {
367
367
  store.recordSession(
368
368
  makeMetrics({
369
369
  agentName: "builder-1",
370
- beadId: "t1",
370
+ taskId: "t1",
371
371
  inputTokens: 0,
372
372
  outputTokens: 0,
373
373
  cacheReadTokens: 0,
@@ -389,7 +389,7 @@ describe("costsCommand", () => {
389
389
  store.recordSession(
390
390
  makeMetrics({
391
391
  agentName: "builder-1",
392
- beadId: "t1",
392
+ taskId: "t1",
393
393
  estimatedCostUsd: null,
394
394
  }),
395
395
  );
@@ -408,8 +408,8 @@ describe("costsCommand", () => {
408
408
  test("filters sessions by agent name", async () => {
409
409
  const dbPath = join(tempDir, ".overstory", "metrics.db");
410
410
  const store = createMetricsStore(dbPath);
411
- store.recordSession(makeMetrics({ agentName: "builder-1", beadId: "t1", inputTokens: 100 }));
412
- store.recordSession(makeMetrics({ agentName: "scout-1", beadId: "t2", inputTokens: 200 }));
411
+ store.recordSession(makeMetrics({ agentName: "builder-1", taskId: "t1", inputTokens: 100 }));
412
+ store.recordSession(makeMetrics({ agentName: "scout-1", taskId: "t2", inputTokens: 200 }));
413
413
  store.close();
414
414
 
415
415
  await costsCommand(["--json", "--agent", "builder-1"]);
@@ -423,7 +423,7 @@ describe("costsCommand", () => {
423
423
  test("returns empty for non-existent agent", async () => {
424
424
  const dbPath = join(tempDir, ".overstory", "metrics.db");
425
425
  const store = createMetricsStore(dbPath);
426
- store.recordSession(makeMetrics({ agentName: "builder-1", beadId: "t1" }));
426
+ store.recordSession(makeMetrics({ agentName: "builder-1", taskId: "t1" }));
427
427
  store.close();
428
428
 
429
429
  await costsCommand(["--json", "--agent", "nonexistent"]);
@@ -441,12 +441,12 @@ describe("costsCommand", () => {
441
441
  const dbPath = join(tempDir, ".overstory", "metrics.db");
442
442
  const store = createMetricsStore(dbPath);
443
443
  store.recordSession(
444
- makeMetrics({ agentName: "builder-1", beadId: "task-001", runId: "run-2026-01-01" }),
444
+ makeMetrics({ agentName: "builder-1", taskId: "task-001", runId: "run-2026-01-01" }),
445
445
  );
446
446
  store.recordSession(
447
447
  makeMetrics({
448
448
  agentName: "scout-1",
449
- beadId: "task-002",
449
+ taskId: "task-002",
450
450
  capability: "scout",
451
451
  runId: "run-other",
452
452
  }),
@@ -465,7 +465,7 @@ describe("costsCommand", () => {
465
465
  const dbPath = join(tempDir, ".overstory", "metrics.db");
466
466
  const store = createMetricsStore(dbPath);
467
467
  store.recordSession(
468
- makeMetrics({ agentName: "builder-1", beadId: "t1", runId: "run-2026-01-01" }),
468
+ makeMetrics({ agentName: "builder-1", taskId: "t1", runId: "run-2026-01-01" }),
469
469
  );
470
470
  store.close();
471
471
 
@@ -484,7 +484,7 @@ describe("costsCommand", () => {
484
484
  const dbPath = join(tempDir, ".overstory", "metrics.db");
485
485
  const store = createMetricsStore(dbPath);
486
486
  store.recordSession(
487
- makeMetrics({ agentName: "builder-1", beadId: "t1", capability: "builder" }),
487
+ makeMetrics({ agentName: "builder-1", taskId: "t1", capability: "builder" }),
488
488
  );
489
489
  store.close();
490
490
 
@@ -498,7 +498,7 @@ describe("costsCommand", () => {
498
498
  const dbPath = join(tempDir, ".overstory", "metrics.db");
499
499
  const store = createMetricsStore(dbPath);
500
500
  store.recordSession(
501
- makeMetrics({ agentName: "builder-1", beadId: "t1", capability: "builder" }),
501
+ makeMetrics({ agentName: "builder-1", taskId: "t1", capability: "builder" }),
502
502
  );
503
503
  store.close();
504
504
 
@@ -514,7 +514,7 @@ describe("costsCommand", () => {
514
514
  store.recordSession(
515
515
  makeMetrics({
516
516
  agentName: "builder-1",
517
- beadId: "t1",
517
+ taskId: "t1",
518
518
  capability: "builder",
519
519
  inputTokens: 1000,
520
520
  }),
@@ -522,7 +522,7 @@ describe("costsCommand", () => {
522
522
  store.recordSession(
523
523
  makeMetrics({
524
524
  agentName: "builder-2",
525
- beadId: "t2",
525
+ taskId: "t2",
526
526
  capability: "builder",
527
527
  inputTokens: 2000,
528
528
  }),
@@ -530,7 +530,7 @@ describe("costsCommand", () => {
530
530
  store.recordSession(
531
531
  makeMetrics({
532
532
  agentName: "scout-1",
533
- beadId: "t3",
533
+ taskId: "t3",
534
534
  capability: "scout",
535
535
  inputTokens: 500,
536
536
  }),
@@ -548,10 +548,10 @@ describe("costsCommand", () => {
548
548
  test("shows correct session count per capability", async () => {
549
549
  const dbPath = join(tempDir, ".overstory", "metrics.db");
550
550
  const store = createMetricsStore(dbPath);
551
- store.recordSession(makeMetrics({ agentName: "b1", beadId: "t1", capability: "builder" }));
552
- store.recordSession(makeMetrics({ agentName: "b2", beadId: "t2", capability: "builder" }));
553
- store.recordSession(makeMetrics({ agentName: "b3", beadId: "t3", capability: "builder" }));
554
- store.recordSession(makeMetrics({ agentName: "s1", beadId: "t4", capability: "scout" }));
551
+ store.recordSession(makeMetrics({ agentName: "b1", taskId: "t1", capability: "builder" }));
552
+ store.recordSession(makeMetrics({ agentName: "b2", taskId: "t2", capability: "builder" }));
553
+ store.recordSession(makeMetrics({ agentName: "b3", taskId: "t3", capability: "builder" }));
554
+ store.recordSession(makeMetrics({ agentName: "s1", taskId: "t4", capability: "scout" }));
555
555
  store.close();
556
556
 
557
557
  await costsCommand(["--json", "--by-capability"]);
@@ -584,7 +584,7 @@ describe("costsCommand", () => {
584
584
  const dbPath = join(tempDir, ".overstory", "metrics.db");
585
585
  const store = createMetricsStore(dbPath);
586
586
  for (let i = 0; i < 10; i++) {
587
- store.recordSession(makeMetrics({ agentName: `agent-${i}`, beadId: `t-${i}` }));
587
+ store.recordSession(makeMetrics({ agentName: `agent-${i}`, taskId: `t-${i}` }));
588
588
  }
589
589
  store.close();
590
590
 
@@ -599,7 +599,7 @@ describe("costsCommand", () => {
599
599
  const dbPath = join(tempDir, ".overstory", "metrics.db");
600
600
  const store = createMetricsStore(dbPath);
601
601
  for (let i = 0; i < 25; i++) {
602
- store.recordSession(makeMetrics({ agentName: `agent-${i}`, beadId: `t-${i}` }));
602
+ store.recordSession(makeMetrics({ agentName: `agent-${i}`, taskId: `t-${i}` }));
603
603
  }
604
604
  store.close();
605
605
 
@@ -620,7 +620,7 @@ describe("costsCommand", () => {
620
620
  store.recordSession(
621
621
  makeMetrics({
622
622
  agentName: "builder-1",
623
- beadId: "t1",
623
+ taskId: "t1",
624
624
  inputTokens: 0,
625
625
  outputTokens: 0,
626
626
  cacheReadTokens: 0,
@@ -644,7 +644,7 @@ describe("costsCommand", () => {
644
644
  store.recordSession(
645
645
  makeMetrics({
646
646
  agentName: "builder-1",
647
- beadId: "t1",
647
+ taskId: "t1",
648
648
  estimatedCostUsd: null,
649
649
  }),
650
650
  );
@@ -664,7 +664,7 @@ describe("costsCommand", () => {
664
664
  store.recordSession(
665
665
  makeMetrics({
666
666
  agentName: "builder-1",
667
- beadId: "t1",
667
+ taskId: "t1",
668
668
  cacheReadTokens: 8000,
669
669
  cacheCreationTokens: 901,
670
670
  }),
@@ -684,7 +684,7 @@ describe("costsCommand", () => {
684
684
  store.recordSession(
685
685
  makeMetrics({
686
686
  agentName: "builder-1",
687
- beadId: "t1",
687
+ taskId: "t1",
688
688
  inputTokens: 100,
689
689
  outputTokens: 50,
690
690
  estimatedCostUsd: 0.1,
@@ -693,7 +693,7 @@ describe("costsCommand", () => {
693
693
  store.recordSession(
694
694
  makeMetrics({
695
695
  agentName: "scout-1",
696
- beadId: "t2",
696
+ taskId: "t2",
697
697
  capability: "scout",
698
698
  inputTokens: 200,
699
699
  outputTokens: 100,
@@ -716,10 +716,10 @@ describe("costsCommand", () => {
716
716
  const dbPath = join(tempDir, ".overstory", "metrics.db");
717
717
  const store = createMetricsStore(dbPath);
718
718
  store.recordSession(
719
- makeMetrics({ agentName: "builder-1", beadId: "t1", capability: "builder" }),
719
+ makeMetrics({ agentName: "builder-1", taskId: "t1", capability: "builder" }),
720
720
  );
721
721
  store.recordSession(
722
- makeMetrics({ agentName: "builder-2", beadId: "t2", capability: "builder" }),
722
+ makeMetrics({ agentName: "builder-2", taskId: "t2", capability: "builder" }),
723
723
  );
724
724
  store.close();
725
725
 
@@ -759,7 +759,7 @@ describe("costsCommand", () => {
759
759
  capability: "builder",
760
760
  worktreePath: "/tmp/wt1",
761
761
  branchName: "feat/task1",
762
- beadId: "task-001",
762
+ taskId: "task-001",
763
763
  tmuxSession: "tmux-001",
764
764
  state: "working",
765
765
  pid: 12345,
@@ -815,7 +815,7 @@ describe("costsCommand", () => {
815
815
  capability: "builder",
816
816
  worktreePath: "/tmp/wt1",
817
817
  branchName: "feat/task1",
818
- beadId: "task-001",
818
+ taskId: "task-001",
819
819
  tmuxSession: "tmux-001",
820
820
  state: "working",
821
821
  pid: 12345,
@@ -879,7 +879,7 @@ describe("costsCommand", () => {
879
879
  capability: "builder",
880
880
  worktreePath: "/tmp/wt1",
881
881
  branchName: "feat/task1",
882
- beadId: "task-001",
882
+ taskId: "task-001",
883
883
  tmuxSession: "tmux-001",
884
884
  state: "working",
885
885
  pid: 12345,
@@ -897,7 +897,7 @@ describe("costsCommand", () => {
897
897
  capability: "scout",
898
898
  worktreePath: "/tmp/wt2",
899
899
  branchName: "feat/task2",
900
- beadId: "task-002",
900
+ taskId: "task-002",
901
901
  tmuxSession: "tmux-002",
902
902
  state: "working",
903
903
  pid: 12346,
@@ -956,7 +956,7 @@ describe("costsCommand", () => {
956
956
  capability: "builder",
957
957
  worktreePath: "/tmp/wt1",
958
958
  branchName: "feat/task1",
959
- beadId: "task-001",
959
+ taskId: "task-001",
960
960
  tmuxSession: "tmux-001",
961
961
  state: "working",
962
962
  pid: 12345,
@@ -1,5 +1,5 @@
1
1
  /**
2
- * CLI command: overstory costs [--agent <name>] [--run <id>] [--by-capability] [--last <n>] [--self] [--json]
2
+ * CLI command: ov costs [--agent <name>] [--run <id>] [--by-capability] [--last <n>] [--self] [--json]
3
3
  *
4
4
  * Shows token/cost analysis and breakdown for agent sessions.
5
5
  * Data source: metrics.db via createMetricsStore().
@@ -1,5 +1,5 @@
1
1
  /**
2
- * CLI command: overstory dashboard [--interval <ms>] [--all]
2
+ * CLI command: ov dashboard [--interval <ms>] [--all]
3
3
  *
4
4
  * Rich terminal dashboard using raw ANSI escape codes (zero runtime deps).
5
5
  * Polls existing data sources and renders multi-panel layout with agent status,
@@ -402,7 +402,7 @@ async function loadDashboardData(
402
402
  * Render the header bar (line 1).
403
403
  */
404
404
  function renderHeader(width: number, interval: number, currentRunId?: string | null): string {
405
- const left = color.bold(`overstory dashboard v${PKG_VERSION}`);
405
+ const left = color.bold(`ov dashboard v${PKG_VERSION}`);
406
406
  const now = new Date().toLocaleTimeString();
407
407
  const scope = currentRunId ? ` [run: ${currentRunId.slice(0, 8)}]` : " [all runs]";
408
408
  const right = `${now}${scope} | refresh: ${interval}ms`;
@@ -438,15 +438,15 @@ function getStateColor(state: string): ColorFn {
438
438
  function getStateIcon(state: string): string {
439
439
  switch (state) {
440
440
  case "working":
441
- return "";
441
+ return ">";
442
442
  case "booting":
443
- return "";
443
+ return "-";
444
444
  case "stalled":
445
- return "";
445
+ return "!";
446
446
  case "zombie":
447
- return "";
447
+ return "x";
448
448
  case "completed":
449
- return "";
449
+ return "x";
450
450
  default:
451
451
  return "?";
452
452
  }
@@ -470,7 +470,7 @@ function renderAgentPanel(
470
470
  output += `${CURSOR.cursorTo(startRow, 1)}${headerLine}${headerPadding}${BOX.vertical}\n`;
471
471
 
472
472
  // Column headers
473
- const colHeaders = `${BOX.vertical} St Name Capability State Bead ID Duration Tmux ${BOX.vertical}`;
473
+ const colHeaders = `${BOX.vertical} St Name Capability State Task ID Duration Tmux ${BOX.vertical}`;
474
474
  output += `${CURSOR.cursorTo(startRow + 1, 1)}${colHeaders}\n`;
475
475
 
476
476
  // Separator
@@ -500,7 +500,7 @@ function renderAgentPanel(
500
500
  const name = pad(truncate(agent.agentName, 15), 15);
501
501
  const capability = pad(truncate(agent.capability, 12), 12);
502
502
  const state = pad(agent.state, 10);
503
- const beadId = pad(truncate(agent.beadId, 16), 16);
503
+ const taskId = pad(truncate(agent.taskId, 16), 16);
504
504
  const endTime =
505
505
  agent.state === "completed" || agent.state === "zombie"
506
506
  ? new Date(agent.lastActivity).getTime()
@@ -508,9 +508,9 @@ function renderAgentPanel(
508
508
  const duration = formatDuration(endTime - new Date(agent.startedAt).getTime());
509
509
  const durationPadded = pad(duration, 9);
510
510
  const tmuxAlive = data.status.tmuxSessions.some((s) => s.name === agent.tmuxSession);
511
- const tmuxDot = tmuxAlive ? color.green("") : color.red("");
511
+ const tmuxDot = tmuxAlive ? color.green(">") : color.red("x");
512
512
 
513
- const line = `${BOX.vertical} ${stateColor(icon)} ${name} ${capability} ${stateColor(state)} ${beadId} ${durationPadded} ${tmuxDot} ${BOX.vertical}`;
513
+ const line = `${BOX.vertical} ${stateColor(icon)} ${name} ${capability} ${stateColor(state)} ${taskId} ${durationPadded} ${tmuxDot} ${BOX.vertical}`;
514
514
  output += `${CURSOR.cursorTo(startRow + 3 + i, 1)}${line}\n`;
515
515
  }
516
516
 
@@ -1,5 +1,5 @@
1
1
  /**
2
- * CLI command: overstory doctor [options]
2
+ * CLI command: ov doctor [options]
3
3
  *
4
4
  * Runs health checks on overstory subsystems and reports problems.
5
5
  */
@@ -77,10 +77,10 @@ function printHumanReadable(
77
77
 
78
78
  const icon =
79
79
  check.status === "pass"
80
- ? color.green("")
80
+ ? color.green("-")
81
81
  : check.status === "warn"
82
- ? color.yellow("")
83
- : color.red("");
82
+ ? color.yellow("!")
83
+ : color.red("x");
84
84
 
85
85
  w(` ${icon} ${check.message}\n`);
86
86
 
@@ -1,5 +1,5 @@
1
1
  /**
2
- * CLI command: overstory errors [--agent <name>] [--run <id>] [--json] [--since <ts>] [--until <ts>] [--limit <n>]
2
+ * CLI command: ov errors [--agent <name>] [--run <id>] [--json] [--since <ts>] [--until <ts>] [--limit <n>]
3
3
  *
4
4
  * Shows aggregated error-level events across all agents.
5
5
  * Errors can be filtered by agent name, run ID, or time range.
@@ -1,5 +1,5 @@
1
1
  /**
2
- * CLI command: overstory feed [--follow] [--agent <name>...] [--run <id>]
2
+ * CLI command: ov feed [--follow] [--agent <name>...] [--run <id>]
3
3
  * [--since <ts>] [--limit <n>] [--interval <ms>] [--json]
4
4
  *
5
5
  * Unified real-time event stream across all agents — like `tail -f` for the fleet.
@@ -1,5 +1,5 @@
1
1
  /**
2
- * CLI command: overstory group create|status|add|remove|list
2
+ * CLI command: ov group create|status|add|remove|list
3
3
  *
4
4
  * Manages TaskGroups for batch work coordination. Groups track collections
5
5
  * of beads issues and auto-close when all member issues are closed.
@@ -297,7 +297,7 @@ function printGroupProgress(progress: TaskGroupProgress): void {
297
297
  }
298
298
 
299
299
  /**
300
- * Create the Commander command for `overstory group`.
300
+ * Create the Commander command for `ov group`.
301
301
  */
302
302
  export function createGroupCommand(): Command {
303
303
  const cmd = new Command("group").description("Manage task groups for batch coordination");
@@ -472,7 +472,7 @@ export function createGroupCommand(): Command {
472
472
  }
473
473
 
474
474
  /**
475
- * Entry point for `overstory group <subcommand>`.
475
+ * Entry point for `ov group <subcommand>`.
476
476
  */
477
477
  export async function groupCommand(args: string[]): Promise<void> {
478
478
  const cmd = createGroupCommand();
@@ -22,13 +22,13 @@ const SAMPLE_HOOKS = {
22
22
  SessionStart: [
23
23
  {
24
24
  matcher: "",
25
- hooks: [{ type: "command", command: "overstory prime --agent orchestrator" }],
25
+ hooks: [{ type: "command", command: "ov prime --agent orchestrator" }],
26
26
  },
27
27
  ],
28
28
  Stop: [
29
29
  {
30
30
  matcher: "",
31
- hooks: [{ type: "command", command: "overstory log session-end --agent orchestrator" }],
31
+ hooks: [{ type: "command", command: "ov log session-end --agent orchestrator" }],
32
32
  },
33
33
  ],
34
34
  },
@@ -106,7 +106,7 @@ describe("hooks install", () => {
106
106
  const content = await Bun.file(targetPath).text();
107
107
  const parsed = JSON.parse(content) as Record<string, unknown>;
108
108
  expect(parsed.hooks).toBeDefined();
109
- expect(content).toContain("overstory prime");
109
+ expect(content).toContain("ov prime");
110
110
  });
111
111
 
112
112
  test("preserves existing non-hooks keys in settings.local.json", async () => {
@@ -182,7 +182,7 @@ describe("hooks install", () => {
182
182
  // Existing user hook is preserved
183
183
  expect(content).toContain("user-hook");
184
184
  // Overstory hooks are added
185
- expect(content).toContain("overstory prime");
185
+ expect(content).toContain("ov prime");
186
186
  });
187
187
 
188
188
  test("throws when .overstory/hooks.json does not exist", async () => {
@@ -284,7 +284,7 @@ describe("hooks install merge behavior", () => {
284
284
  // User's PreToolUse hook preserved
285
285
  expect(content).toContain("user-write-hook");
286
286
  // Overstory's SessionStart hook added
287
- expect(content).toContain("overstory prime");
287
+ expect(content).toContain("ov prime");
288
288
  // Both event types present
289
289
  expect(parsed.hooks.PreToolUse).toBeDefined();
290
290
  expect(parsed.hooks.SessionStart).toBeDefined();
@@ -361,7 +361,7 @@ describe("hooks install merge behavior", () => {
361
361
  const parsed = JSON.parse(content) as { hooks: Record<string, unknown[]> };
362
362
  expect(parsed.hooks.SessionStart).toBeDefined();
363
363
  expect(parsed.hooks.Stop).toBeDefined();
364
- expect(content).toContain("overstory prime");
364
+ expect(content).toContain("ov prime");
365
365
  });
366
366
 
367
367
  describe("mergeHooksByEventType unit tests", () => {
@@ -424,7 +424,7 @@ describe("hooks status", () => {
424
424
  const output = await captureStdout(() => hooksCommand(["status"]));
425
425
  expect(output).toContain("present");
426
426
  expect(output).toContain("no");
427
- expect(output).toContain("overstory hooks install");
427
+ expect(output).toContain("ov hooks install");
428
428
  });
429
429
 
430
430
  test("reports installed:true when hooks present in .claude/", async () => {
@@ -1,13 +1,13 @@
1
1
  /**
2
- * CLI command: overstory hooks install|uninstall|status
2
+ * CLI command: ov hooks install|uninstall|status
3
3
  *
4
4
  * Manages orchestrator hooks in .claude/settings.local.json.
5
- * Hooks are sourced from .overstory/hooks.json (generated by overstory init).
5
+ * Hooks are sourced from .overstory/hooks.json (generated by ov init).
6
6
  *
7
7
  * This keeps the canonical hook configuration in .overstory/ while placing
8
8
  * a minimal copy in .claude/ only when the user explicitly opts in.
9
- * Running `overstory init` alone does NOT modify .claude/ — the user must
10
- * run `overstory hooks install` as a separate step.
9
+ * Running `ov init` alone does NOT modify .claude/ — the user must
10
+ * run `ov hooks install` as a separate step.
11
11
  */
12
12
 
13
13
  import { mkdir, unlink } from "node:fs/promises";
@@ -80,7 +80,7 @@ async function installHooks(force: boolean): Promise<void> {
80
80
  const sourcePath = join(projectRoot, ".overstory", "hooks.json");
81
81
  const sourceFile = Bun.file(sourcePath);
82
82
  if (!(await sourceFile.exists())) {
83
- throw new ValidationError("No hooks.json found in .overstory/. Run 'overstory init' first.", {
83
+ throw new ValidationError("No hooks.json found in .overstory/. Run 'ov init' first.", {
84
84
  field: "source",
85
85
  });
86
86
  }
@@ -199,7 +199,7 @@ async function statusHooks(json: boolean): Promise<void> {
199
199
  `Hooks installed (.claude/settings.local.json): ${installed ? "yes" : "no"}\n`,
200
200
  );
201
201
  if (!installed && sourceExists) {
202
- process.stdout.write(`\nRun 'overstory hooks install' to install.\n`);
202
+ process.stdout.write(`\nRun 'ov hooks install' to install.\n`);
203
203
  }
204
204
  }
205
205
  }
@@ -234,7 +234,7 @@ export function createHooksCommand(): Command {
234
234
  }
235
235
 
236
236
  /**
237
- * Entry point for `overstory hooks <subcommand>`.
237
+ * Entry point for `ov hooks <subcommand>`.
238
238
  */
239
239
  export async function hooksCommand(args: string[]): Promise<void> {
240
240
  const cmd = createHooksCommand();
@@ -20,6 +20,10 @@ const AGENT_DEF_FILES = [
20
20
  "supervisor.md",
21
21
  "coordinator.md",
22
22
  "monitor.md",
23
+ "issue-reviews.md",
24
+ "pr-reviews.md",
25
+ "prioritize.md",
26
+ "release.md",
23
27
  ];
24
28
 
25
29
  /** Resolve the source agents directory (same logic as init.ts). */
@@ -46,7 +50,7 @@ describe("initCommand: agent-defs deployment", () => {
46
50
  await cleanupTempDir(tempDir);
47
51
  });
48
52
 
49
- test("creates .overstory/agent-defs/ with all 8 agent definition files", async () => {
53
+ test("creates .overstory/agent-defs/ with all 12 agent definition files", async () => {
50
54
  await initCommand({});
51
55
 
52
56
  const agentDefsDir = join(tempDir, ".overstory", "agent-defs");
@@ -100,7 +104,7 @@ describe("initCommand: agent-defs deployment", () => {
100
104
  const stopHooks = parsed.hooks.Stop[0].hooks;
101
105
 
102
106
  expect(stopHooks.length).toBe(2);
103
- expect(stopHooks[0].command).toContain("overstory log session-end");
107
+ expect(stopHooks[0].command).toContain("ov log session-end");
104
108
  expect(stopHooks[1].command).toBe("mulch learn");
105
109
  });
106
110