@katyella/legio 0.1.3 → 0.2.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 (112) hide show
  1. package/CHANGELOG.md +61 -3
  2. package/README.md +21 -10
  3. package/agents/builder.md +11 -10
  4. package/agents/coordinator.md +36 -27
  5. package/agents/cto.md +9 -8
  6. package/agents/gateway.md +28 -12
  7. package/agents/lead.md +45 -30
  8. package/agents/merger.md +4 -4
  9. package/agents/monitor.md +10 -9
  10. package/agents/reviewer.md +8 -8
  11. package/agents/scout.md +10 -10
  12. package/agents/supervisor.md +60 -45
  13. package/package.json +2 -2
  14. package/src/agents/hooks-deployer.test.ts +46 -41
  15. package/src/agents/hooks-deployer.ts +10 -9
  16. package/src/agents/manifest.test.ts +6 -2
  17. package/src/agents/overlay.test.ts +9 -7
  18. package/src/agents/overlay.ts +29 -7
  19. package/src/commands/agents.test.ts +1 -5
  20. package/src/commands/clean.test.ts +2 -5
  21. package/src/commands/clean.ts +25 -1
  22. package/src/commands/completions.test.ts +1 -1
  23. package/src/commands/completions.ts +26 -7
  24. package/src/commands/coordinator.test.ts +87 -82
  25. package/src/commands/coordinator.ts +94 -48
  26. package/src/commands/costs.test.ts +2 -6
  27. package/src/commands/dashboard.test.ts +2 -5
  28. package/src/commands/doctor.test.ts +2 -6
  29. package/src/commands/down.ts +3 -3
  30. package/src/commands/errors.test.ts +2 -6
  31. package/src/commands/feed.test.ts +2 -6
  32. package/src/commands/gateway.test.ts +43 -17
  33. package/src/commands/gateway.ts +101 -11
  34. package/src/commands/hooks.test.ts +2 -5
  35. package/src/commands/init.test.ts +4 -13
  36. package/src/commands/inspect.test.ts +2 -6
  37. package/src/commands/log.test.ts +2 -6
  38. package/src/commands/logs.test.ts +2 -9
  39. package/src/commands/mail.test.ts +76 -215
  40. package/src/commands/mail.ts +43 -187
  41. package/src/commands/metrics.test.ts +3 -10
  42. package/src/commands/nudge.ts +15 -0
  43. package/src/commands/prime.test.ts +4 -11
  44. package/src/commands/replay.test.ts +2 -6
  45. package/src/commands/server.test.ts +1 -5
  46. package/src/commands/server.ts +1 -1
  47. package/src/commands/sling.test.ts +6 -1
  48. package/src/commands/sling.ts +42 -17
  49. package/src/commands/spec.test.ts +2 -5
  50. package/src/commands/status.test.ts +2 -4
  51. package/src/commands/stop.test.ts +2 -5
  52. package/src/commands/supervisor.ts +6 -6
  53. package/src/commands/trace.test.ts +2 -6
  54. package/src/commands/up.test.ts +43 -9
  55. package/src/commands/up.ts +15 -11
  56. package/src/commands/watchman.ts +327 -0
  57. package/src/commands/worktree.test.ts +2 -6
  58. package/src/config.test.ts +34 -104
  59. package/src/config.ts +120 -32
  60. package/src/doctor/agents.test.ts +52 -2
  61. package/src/doctor/agents.ts +4 -2
  62. package/src/doctor/config-check.test.ts +7 -2
  63. package/src/doctor/consistency.test.ts +7 -2
  64. package/src/doctor/databases.test.ts +6 -2
  65. package/src/doctor/dependencies.test.ts +18 -13
  66. package/src/doctor/dependencies.ts +23 -94
  67. package/src/doctor/logs.test.ts +7 -2
  68. package/src/doctor/merge-queue.test.ts +6 -2
  69. package/src/doctor/structure.test.ts +7 -2
  70. package/src/doctor/version.test.ts +7 -2
  71. package/src/e2e/init-sling-lifecycle.test.ts +2 -5
  72. package/src/index.ts +7 -7
  73. package/src/mail/pending.ts +120 -0
  74. package/src/mail/store.test.ts +89 -0
  75. package/src/mail/store.ts +11 -0
  76. package/src/merge/resolver.test.ts +518 -489
  77. package/src/server/index.ts +33 -2
  78. package/src/server/public/app.js +3 -3
  79. package/src/server/public/components/message-bubble.js +11 -1
  80. package/src/server/public/components/terminal-panel.js +66 -74
  81. package/src/server/public/views/chat.js +18 -2
  82. package/src/server/public/views/costs.js +5 -5
  83. package/src/server/public/views/dashboard.js +80 -51
  84. package/src/server/public/views/gateway-chat.js +37 -131
  85. package/src/server/public/views/inspect.js +16 -4
  86. package/src/server/public/views/issues.js +16 -12
  87. package/src/server/routes.test.ts +55 -39
  88. package/src/server/routes.ts +38 -26
  89. package/src/test-helpers.ts +6 -3
  90. package/src/tracker/beads.ts +159 -0
  91. package/src/tracker/exec.ts +44 -0
  92. package/src/tracker/factory.test.ts +283 -0
  93. package/src/tracker/factory.ts +59 -0
  94. package/src/tracker/seeds.ts +156 -0
  95. package/src/tracker/types.ts +46 -0
  96. package/src/types.ts +11 -2
  97. package/src/{watchdog → watchman}/daemon.test.ts +421 -515
  98. package/src/watchman/daemon.ts +940 -0
  99. package/src/worktree/tmux.test.ts +2 -1
  100. package/src/worktree/tmux.ts +4 -4
  101. package/templates/hooks.json.tmpl +17 -17
  102. package/src/beads/client.test.ts +0 -210
  103. package/src/commands/merge.test.ts +0 -676
  104. package/src/commands/watch.test.ts +0 -152
  105. package/src/commands/watch.ts +0 -238
  106. package/src/test-helpers.test.ts +0 -97
  107. package/src/watchdog/daemon.ts +0 -533
  108. package/src/watchdog/health.test.ts +0 -371
  109. package/src/watchdog/triage.test.ts +0 -162
  110. package/src/worktree/manager.test.ts +0 -444
  111. /package/src/{watchdog → watchman}/health.ts +0 -0
  112. /package/src/{watchdog → watchman}/triage.ts +0 -0
@@ -14,7 +14,7 @@
14
14
  import { statSync } from "node:fs";
15
15
  import { access, mkdir, readFile, realpath, writeFile } from "node:fs/promises";
16
16
  import { join } from "node:path";
17
- import { afterEach, beforeEach, describe, expect, test } from "vitest";
17
+ import { afterEach, beforeEach, describe, expect, test, vi } from "vitest";
18
18
  import { AgentError, ValidationError } from "../errors.ts";
19
19
  import { openSessionStore } from "../sessions/compat.ts";
20
20
  import { createRunStore } from "../sessions/store.ts";
@@ -42,10 +42,10 @@ interface TmuxCallTracker {
42
42
  sendKeys: Array<{ name: string; keys: string }>;
43
43
  }
44
44
 
45
- // --- Fake Watchdog ---
45
+ // --- Fake Watchman ---
46
46
 
47
- /** Track calls to fake watchdog for assertions. */
48
- interface WatchdogCallTracker {
47
+ /** Track calls to fake watchman for assertions. */
48
+ interface WatchmanCallTracker {
49
49
  start: number;
50
50
  stop: number;
51
51
  isRunning: number;
@@ -99,26 +99,26 @@ function makeFakeTmux(sessionAliveMap: Record<string, boolean> = {}): {
99
99
  }
100
100
 
101
101
  /**
102
- * Build a fake watchdog DI object with configurable behavior.
103
- * @param running - Whether the watchdog should report as running
102
+ * Build a fake watchman DI object with configurable behavior.
103
+ * @param running - Whether the watchman should report as running
104
104
  * @param startSuccess - Whether start() should succeed (return a PID)
105
105
  * @param stopSuccess - Whether stop() should succeed (return true)
106
106
  */
107
- function makeFakeWatchdog(
107
+ function makeFakeWatchman(
108
108
  running = false,
109
109
  startSuccess = true,
110
110
  stopSuccess = true,
111
111
  ): {
112
- watchdog: NonNullable<CoordinatorDeps["_watchdog"]>;
113
- calls: WatchdogCallTracker;
112
+ watchman: NonNullable<CoordinatorDeps["_watchman"]>;
113
+ calls: WatchmanCallTracker;
114
114
  } {
115
- const calls: WatchdogCallTracker = {
115
+ const calls: WatchmanCallTracker = {
116
116
  start: 0,
117
117
  stop: 0,
118
118
  isRunning: 0,
119
119
  };
120
120
 
121
- const watchdog: NonNullable<CoordinatorDeps["_watchdog"]> = {
121
+ const watchman: NonNullable<CoordinatorDeps["_watchman"]> = {
122
122
  async start(): Promise<{ pid: number } | null> {
123
123
  calls.start++;
124
124
  return startSuccess ? { pid: 88888 } : null;
@@ -133,7 +133,7 @@ function makeFakeWatchdog(
133
133
  },
134
134
  };
135
135
 
136
- return { watchdog, calls };
136
+ return { watchman, calls };
137
137
  }
138
138
 
139
139
  /**
@@ -178,7 +178,6 @@ function makeFakeMonitor(
178
178
 
179
179
  let tempDir: string;
180
180
  let legioDir: string;
181
- const originalCwd = process.cwd();
182
181
 
183
182
  /** Save sessions to the SessionStore (sessions.db) for test setup. */
184
183
  function saveSessionsToDb(sessions: AgentSession[]): void {
@@ -203,10 +202,6 @@ function loadSessionsFromDb(): AgentSession[] {
203
202
  }
204
203
 
205
204
  beforeEach(async () => {
206
- // Restore cwd FIRST so createTempGitRepo's git operations don't fail
207
- // if a prior test's tempDir was already cleaned up.
208
- process.chdir(originalCwd);
209
-
210
205
  tempDir = await realpath(await createTempGitRepo());
211
206
  legioDir = join(tempDir, ".legio");
212
207
  await mkdir(legioDir, { recursive: true });
@@ -242,12 +237,10 @@ beforeEach(async () => {
242
237
  );
243
238
  await writeFile(join(agentDefsDir, "coordinator.md"), "# Coordinator\n");
244
239
 
245
- // Override cwd so coordinator commands find our temp project
246
- process.chdir(tempDir);
240
+ vi.spyOn(process, "cwd").mockReturnValue(tempDir);
247
241
  });
248
242
 
249
243
  afterEach(async () => {
250
- process.chdir(originalCwd);
251
244
  await cleanupTempDir(tempDir);
252
245
  });
253
246
 
@@ -291,24 +284,24 @@ async function captureStdout(fn: () => Promise<void>): Promise<string> {
291
284
  return chunks.join("");
292
285
  }
293
286
 
294
- /** Build default CoordinatorDeps with fake tmux, watchdog, and monitor.
287
+ /** Build default CoordinatorDeps with fake tmux, watchman, and monitor.
295
288
  * Always injects fakes for all three to prevent real child_process.spawn(["legio", ...])
296
289
  * calls in tests (legio CLI is not available in CI). */
297
290
  function makeDeps(
298
291
  sessionAliveMap: Record<string, boolean> = {},
299
- watchdogConfig?: { running?: boolean; startSuccess?: boolean; stopSuccess?: boolean },
292
+ watchmanConfig?: { running?: boolean; startSuccess?: boolean; stopSuccess?: boolean },
300
293
  monitorConfig?: { running?: boolean; startSuccess?: boolean; stopSuccess?: boolean },
301
294
  ): {
302
295
  deps: CoordinatorDeps;
303
296
  calls: TmuxCallTracker;
304
- watchdogCalls: WatchdogCallTracker;
297
+ watchmanCalls: WatchmanCallTracker;
305
298
  monitorCalls: MonitorCallTracker;
306
299
  } {
307
300
  const { tmux, calls } = makeFakeTmux(sessionAliveMap);
308
- const { watchdog, calls: watchdogCalls } = makeFakeWatchdog(
309
- watchdogConfig?.running,
310
- watchdogConfig?.startSuccess,
311
- watchdogConfig?.stopSuccess,
301
+ const { watchman, calls: watchmanCalls } = makeFakeWatchman(
302
+ watchmanConfig?.running,
303
+ watchmanConfig?.startSuccess,
304
+ watchmanConfig?.stopSuccess,
312
305
  );
313
306
  const { monitor, calls: monitorCalls } = makeFakeMonitor(
314
307
  monitorConfig?.running,
@@ -318,7 +311,7 @@ function makeDeps(
318
311
 
319
312
  const deps: CoordinatorDeps = {
320
313
  _tmux: tmux,
321
- _watchdog: watchdog,
314
+ _watchman: watchman,
322
315
  _monitor: monitor,
323
316
  _sleep: () => Promise.resolve(),
324
317
  };
@@ -326,7 +319,7 @@ function makeDeps(
326
319
  return {
327
320
  deps,
328
321
  calls,
329
- watchdogCalls,
322
+ watchmanCalls,
330
323
  monitorCalls,
331
324
  };
332
325
  }
@@ -442,7 +435,7 @@ describe("startCoordinator", () => {
442
435
  expect(config.hooks.Stop).toBeDefined();
443
436
  });
444
437
 
445
- test("hooks use coordinator agent name for event logging", async () => {
438
+ test("hooks use LEGIO_AGENT_NAME env var for event logging", async () => {
446
439
  const { deps } = makeDeps();
447
440
 
448
441
  await captureStdout(() => coordinatorCommand(["start", "--no-attach"], deps));
@@ -450,8 +443,8 @@ describe("startCoordinator", () => {
450
443
  const settingsPath = join(tempDir, ".claude", "settings.local.json");
451
444
  const content = await readFile(settingsPath, "utf-8");
452
445
 
453
- // The hooks should reference the coordinator agent name
454
- expect(content).toContain("--agent coordinator");
446
+ // The hooks should use the env var, not a hardcoded agent name
447
+ expect(content).toContain("--agent $LEGIO_AGENT_NAME");
455
448
  });
456
449
 
457
450
  test("hooks include ENV_GUARD to avoid affecting user's Claude Code session", async () => {
@@ -882,8 +875,7 @@ describe("buildCoordinatorBeacon", () => {
882
875
  const beacon = buildCoordinatorBeacon();
883
876
  expect(beacon).toContain("mulch prime");
884
877
  expect(beacon).toContain("legio mail check --agent coordinator");
885
- expect(beacon).toContain("bd ready");
886
- expect(beacon).toContain("legio group status");
878
+ expect(beacon).toContain("legio status");
887
879
  });
888
880
 
889
881
  test("includes hierarchy enforcement instruction", () => {
@@ -898,11 +890,17 @@ describe("buildCoordinatorBeacon", () => {
898
890
  expect(beacon).toContain("spawn a lead who will spawn scouts");
899
891
  });
900
892
 
893
+ test("explains what legio is", () => {
894
+ const beacon = buildCoordinatorBeacon();
895
+ expect(beacon).toContain("legio multi-agent orchestration system");
896
+ expect(beacon).toContain("CLI tool installed on this machine");
897
+ });
898
+
901
899
  test("parts are joined with em-dash separator", () => {
902
900
  const beacon = buildCoordinatorBeacon();
903
- // Should have exactly 4 " — " separators (5 parts)
901
+ // Should have exactly 5 " — " separators (6 parts)
904
902
  const dashes = beacon.split(" — ");
905
- expect(dashes).toHaveLength(5);
903
+ expect(dashes).toHaveLength(6);
906
904
  });
907
905
  });
908
906
 
@@ -934,167 +932,174 @@ describe("resolveAttach", () => {
934
932
  });
935
933
  });
936
934
 
937
- describe("watchdog integration", () => {
938
- describe("startCoordinator with --watchdog", () => {
939
- test("calls watchdog.start() when --watchdog flag is present", async () => {
940
- const { deps, watchdogCalls } = makeDeps({}, { startSuccess: true });
941
- await captureStdout(() => coordinatorCommand(["start", "--watchdog", "--json"], deps));
935
+ describe("watchman integration", () => {
936
+ describe("startCoordinator with --watchman", () => {
937
+ test("calls watchman.start() when --watchman flag is present", async () => {
938
+ const { deps, watchmanCalls } = makeDeps({}, { startSuccess: true });
939
+ await captureStdout(() => coordinatorCommand(["start", "--watchman", "--json"], deps));
942
940
 
943
- expect(watchdogCalls?.start).toBe(1);
941
+ expect(watchmanCalls?.start).toBe(1);
944
942
  });
945
943
 
946
- test("does NOT call watchdog.start() when --watchdog flag is absent", async () => {
947
- const { deps, watchdogCalls } = makeDeps({}, { startSuccess: true });
944
+ test("does NOT call watchman.start() when --watchman flag is absent", async () => {
945
+ const { deps, watchmanCalls } = makeDeps({}, { startSuccess: true });
948
946
  await captureStdout(() => coordinatorCommand(["start", "--json"], deps));
949
947
 
950
- expect(watchdogCalls?.start).toBe(0);
948
+ expect(watchmanCalls?.start).toBe(0);
951
949
  });
952
950
 
953
- test("--json output includes watchdog:false (output written before watchdog starts)", async () => {
951
+ test("--json output includes watchman:false (output written before watchman starts)", async () => {
954
952
  const { deps } = makeDeps({}, { startSuccess: true });
955
953
  const output = await captureStdout(() =>
956
- coordinatorCommand(["start", "--watchdog", "--json"], deps),
954
+ coordinatorCommand(["start", "--watchman", "--json"], deps),
957
955
  );
958
956
 
959
957
  const parsed = JSON.parse(output) as Record<string, unknown>;
960
- expect(parsed.watchdog).toBe(false);
958
+ expect(parsed.watchman).toBe(false);
961
959
  });
962
960
 
963
- test("--json output includes watchdog:false when --watchdog is present but start fails", async () => {
961
+ test("--json output includes watchman:false when --watchman is present but start fails", async () => {
964
962
  const { deps } = makeDeps({}, { startSuccess: false });
965
963
  const output = await captureStdout(() =>
966
- coordinatorCommand(["start", "--watchdog", "--json"], deps),
964
+ coordinatorCommand(["start", "--watchman", "--json"], deps),
967
965
  );
968
966
 
969
967
  const parsed = JSON.parse(output) as Record<string, unknown>;
970
- expect(parsed.watchdog).toBe(false);
968
+ expect(parsed.watchman).toBe(false);
971
969
  });
972
970
 
973
- test("--json output includes watchdog:false when --watchdog is absent", async () => {
971
+ test("--json output includes watchman:false when --watchman is absent", async () => {
974
972
  const { deps } = makeDeps({}, { startSuccess: true });
975
973
  const output = await captureStdout(() => coordinatorCommand(["start", "--json"], deps));
976
974
 
977
975
  const parsed = JSON.parse(output) as Record<string, unknown>;
978
- expect(parsed.watchdog).toBe(false);
976
+ expect(parsed.watchman).toBe(false);
979
977
  });
980
978
 
981
- test("text output includes watchdog PID when --watchdog succeeds", async () => {
979
+ test("text output includes watchman PID when --watchman succeeds", async () => {
982
980
  const { deps } = makeDeps({}, { startSuccess: true });
983
981
  const output = await captureStdout(() =>
984
- coordinatorCommand(["start", "--watchdog", "--no-attach"], deps),
982
+ coordinatorCommand(["start", "--watchman", "--no-attach"], deps),
985
983
  );
986
984
 
987
- expect(output).toContain("Watchdog: started (PID 88888)");
985
+ expect(output).toContain("Watchman: started (PID 88888)");
986
+ });
987
+
988
+ test("--watchdog flag is accepted as alias for --watchman", async () => {
989
+ const { deps, watchmanCalls } = makeDeps({}, { startSuccess: true });
990
+ await captureStdout(() => coordinatorCommand(["start", "--watchdog", "--json"], deps));
991
+
992
+ expect(watchmanCalls?.start).toBe(1);
988
993
  });
989
994
  });
990
995
 
991
- describe("stopCoordinator watchdog cleanup", () => {
992
- test("always calls watchdog.stop() when stopping coordinator", async () => {
996
+ describe("stopCoordinator watchman cleanup", () => {
997
+ test("always calls watchman.stop() when stopping coordinator", async () => {
993
998
  const session = makeCoordinatorSession({ state: "working" });
994
999
  saveSessionsToDb([session]);
995
- const { deps, watchdogCalls } = makeDeps(
1000
+ const { deps, watchmanCalls } = makeDeps(
996
1001
  { "legio-test-project-coordinator": true },
997
1002
  { stopSuccess: true },
998
1003
  );
999
1004
 
1000
1005
  await captureStdout(() => coordinatorCommand(["stop"], deps));
1001
1006
 
1002
- expect(watchdogCalls?.stop).toBe(1);
1007
+ expect(watchmanCalls?.stop).toBe(1);
1003
1008
  });
1004
1009
 
1005
- test("--json output includes watchdogStopped:true when watchdog was running", async () => {
1010
+ test("--json output includes watchmanStopped:true when watchman was running", async () => {
1006
1011
  const session = makeCoordinatorSession({ state: "working" });
1007
1012
  saveSessionsToDb([session]);
1008
1013
  const { deps } = makeDeps({ "legio-test-project-coordinator": true }, { stopSuccess: true });
1009
1014
 
1010
1015
  const output = await captureStdout(() => coordinatorCommand(["stop", "--json"], deps));
1011
1016
  const parsed = JSON.parse(output) as Record<string, unknown>;
1012
- expect(parsed.watchdogStopped).toBe(true);
1017
+ expect(parsed.watchmanStopped).toBe(true);
1013
1018
  });
1014
1019
 
1015
- test("--json output includes watchdogStopped:false when no watchdog was running", async () => {
1020
+ test("--json output includes watchmanStopped:false when no watchman was running", async () => {
1016
1021
  const session = makeCoordinatorSession({ state: "working" });
1017
1022
  saveSessionsToDb([session]);
1018
1023
  const { deps } = makeDeps({ "legio-test-project-coordinator": true }, { stopSuccess: false });
1019
1024
 
1020
1025
  const output = await captureStdout(() => coordinatorCommand(["stop", "--json"], deps));
1021
1026
  const parsed = JSON.parse(output) as Record<string, unknown>;
1022
- expect(parsed.watchdogStopped).toBe(false);
1027
+ expect(parsed.watchmanStopped).toBe(false);
1023
1028
  });
1024
1029
 
1025
- test("text output shows 'Watchdog stopped' when watchdog was running", async () => {
1030
+ test("text output shows 'Watchman stopped' when watchman was running", async () => {
1026
1031
  const session = makeCoordinatorSession({ state: "working" });
1027
1032
  saveSessionsToDb([session]);
1028
1033
  const { deps } = makeDeps({ "legio-test-project-coordinator": true }, { stopSuccess: true });
1029
1034
 
1030
1035
  const output = await captureStdout(() => coordinatorCommand(["stop"], deps));
1031
- expect(output).toContain("Watchdog stopped");
1036
+ expect(output).toContain("Watchman stopped");
1032
1037
  });
1033
1038
 
1034
- test("text output shows 'No watchdog running' when no watchdog was running", async () => {
1039
+ test("text output shows 'No watchman running' when no watchman was running", async () => {
1035
1040
  const session = makeCoordinatorSession({ state: "working" });
1036
1041
  saveSessionsToDb([session]);
1037
1042
  const { deps } = makeDeps({ "legio-test-project-coordinator": true }, { stopSuccess: false });
1038
1043
 
1039
1044
  const output = await captureStdout(() => coordinatorCommand(["stop"], deps));
1040
- expect(output).toContain("No watchdog running");
1045
+ expect(output).toContain("No watchman running");
1041
1046
  });
1042
1047
  });
1043
1048
 
1044
- describe("statusCoordinator watchdog state", () => {
1045
- test("includes watchdogRunning in JSON output when coordinator is running", async () => {
1049
+ describe("statusCoordinator watchman state", () => {
1050
+ test("includes watchmanRunning in JSON output when coordinator is running", async () => {
1046
1051
  const session = makeCoordinatorSession({ state: "working" });
1047
1052
  saveSessionsToDb([session]);
1048
1053
  const { deps } = makeDeps({ "legio-test-project-coordinator": true }, { running: true });
1049
1054
 
1050
1055
  const output = await captureStdout(() => coordinatorCommand(["status", "--json"], deps));
1051
1056
  const parsed = JSON.parse(output) as Record<string, unknown>;
1052
- expect(parsed.watchdogRunning).toBe(true);
1057
+ expect(parsed.watchmanRunning).toBe(true);
1053
1058
  });
1054
1059
 
1055
- test("includes watchdogRunning:false in JSON output when watchdog is not running", async () => {
1060
+ test("includes watchmanRunning:false in JSON output when watchman is not running", async () => {
1056
1061
  const session = makeCoordinatorSession({ state: "working" });
1057
1062
  saveSessionsToDb([session]);
1058
1063
  const { deps } = makeDeps({ "legio-test-project-coordinator": true }, { running: false });
1059
1064
 
1060
1065
  const output = await captureStdout(() => coordinatorCommand(["status", "--json"], deps));
1061
1066
  const parsed = JSON.parse(output) as Record<string, unknown>;
1062
- expect(parsed.watchdogRunning).toBe(false);
1067
+ expect(parsed.watchmanRunning).toBe(false);
1063
1068
  });
1064
1069
 
1065
- test("text output shows watchdog status when coordinator is running", async () => {
1070
+ test("text output shows watchman status when coordinator is running", async () => {
1066
1071
  const session = makeCoordinatorSession({ state: "working" });
1067
1072
  saveSessionsToDb([session]);
1068
1073
  const { deps } = makeDeps({ "legio-test-project-coordinator": true }, { running: true });
1069
1074
 
1070
1075
  const output = await captureStdout(() => coordinatorCommand(["status"], deps));
1071
- expect(output).toContain("Watchdog: running");
1076
+ expect(output).toContain("Watchman: running");
1072
1077
  });
1073
1078
 
1074
- test("text output shows 'not running' when watchdog is not running", async () => {
1079
+ test("text output shows 'not running' when watchman is not running", async () => {
1075
1080
  const session = makeCoordinatorSession({ state: "working" });
1076
1081
  saveSessionsToDb([session]);
1077
1082
  const { deps } = makeDeps({ "legio-test-project-coordinator": true }, { running: false });
1078
1083
 
1079
1084
  const output = await captureStdout(() => coordinatorCommand(["status"], deps));
1080
- expect(output).toContain("Watchdog: not running");
1085
+ expect(output).toContain("Watchman: not running");
1081
1086
  });
1082
1087
 
1083
- test("includes watchdogRunning in JSON output when coordinator is not running", async () => {
1088
+ test("includes watchmanRunning in JSON output when coordinator is not running", async () => {
1084
1089
  const { deps } = makeDeps({}, { running: true });
1085
1090
 
1086
1091
  const output = await captureStdout(() => coordinatorCommand(["status", "--json"], deps));
1087
1092
  const parsed = JSON.parse(output) as Record<string, unknown>;
1088
1093
  expect(parsed.running).toBe(false);
1089
- expect(parsed.watchdogRunning).toBe(true);
1094
+ expect(parsed.watchmanRunning).toBe(true);
1090
1095
  });
1091
1096
  });
1092
1097
 
1093
1098
  describe("COORDINATOR_HELP", () => {
1094
- test("help text includes --watchdog flag", async () => {
1099
+ test("help text includes --watchman flag", async () => {
1095
1100
  const output = await captureStdout(() => coordinatorCommand(["--help"]));
1096
- expect(output).toContain("--watchdog");
1097
- expect(output).toContain("Auto-start watchdog daemon with coordinator");
1101
+ expect(output).toContain("--watchman");
1102
+ expect(output).toContain("Auto-start watchman daemon with coordinator");
1098
1103
  });
1099
1104
  });
1100
1105
  });