@os-eco/overstory-cli 0.6.1 → 0.6.5

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 (110) hide show
  1. package/README.md +8 -7
  2. package/package.json +12 -4
  3. package/src/agents/checkpoint.test.ts +2 -2
  4. package/src/agents/hooks-deployer.test.ts +131 -16
  5. package/src/agents/hooks-deployer.ts +33 -1
  6. package/src/agents/identity.test.ts +27 -27
  7. package/src/agents/identity.ts +10 -10
  8. package/src/agents/lifecycle.test.ts +6 -6
  9. package/src/agents/lifecycle.ts +2 -2
  10. package/src/agents/manifest.test.ts +86 -0
  11. package/src/agents/overlay.test.ts +9 -9
  12. package/src/agents/overlay.ts +4 -4
  13. package/src/commands/agents.test.ts +8 -8
  14. package/src/commands/agents.ts +62 -91
  15. package/src/commands/clean.test.ts +36 -51
  16. package/src/commands/clean.ts +28 -49
  17. package/src/commands/completions.ts +14 -0
  18. package/src/commands/coordinator.test.ts +133 -26
  19. package/src/commands/coordinator.ts +101 -64
  20. package/src/commands/costs.test.ts +47 -47
  21. package/src/commands/costs.ts +96 -75
  22. package/src/commands/dashboard.test.ts +2 -2
  23. package/src/commands/dashboard.ts +75 -95
  24. package/src/commands/doctor.test.ts +2 -2
  25. package/src/commands/doctor.ts +92 -79
  26. package/src/commands/errors.test.ts +2 -2
  27. package/src/commands/errors.ts +56 -50
  28. package/src/commands/feed.test.ts +2 -2
  29. package/src/commands/feed.ts +86 -83
  30. package/src/commands/group.ts +167 -177
  31. package/src/commands/hooks.test.ts +2 -2
  32. package/src/commands/hooks.ts +52 -42
  33. package/src/commands/init.test.ts +19 -19
  34. package/src/commands/init.ts +7 -16
  35. package/src/commands/inspect.test.ts +18 -18
  36. package/src/commands/inspect.ts +55 -58
  37. package/src/commands/log.test.ts +26 -31
  38. package/src/commands/log.ts +97 -91
  39. package/src/commands/logs.test.ts +1 -1
  40. package/src/commands/logs.ts +101 -104
  41. package/src/commands/mail.test.ts +5 -5
  42. package/src/commands/mail.ts +157 -169
  43. package/src/commands/merge.test.ts +28 -66
  44. package/src/commands/merge.ts +21 -51
  45. package/src/commands/metrics.test.ts +8 -8
  46. package/src/commands/metrics.ts +34 -35
  47. package/src/commands/monitor.test.ts +3 -3
  48. package/src/commands/monitor.ts +57 -62
  49. package/src/commands/nudge.test.ts +1 -1
  50. package/src/commands/nudge.ts +41 -89
  51. package/src/commands/prime.test.ts +19 -51
  52. package/src/commands/prime.ts +13 -50
  53. package/src/commands/replay.test.ts +2 -2
  54. package/src/commands/replay.ts +79 -86
  55. package/src/commands/run.test.ts +1 -1
  56. package/src/commands/run.ts +97 -77
  57. package/src/commands/sling.test.ts +201 -5
  58. package/src/commands/sling.ts +37 -64
  59. package/src/commands/spec.test.ts +14 -40
  60. package/src/commands/spec.ts +32 -101
  61. package/src/commands/status.test.ts +97 -1
  62. package/src/commands/status.ts +63 -58
  63. package/src/commands/stop.test.ts +22 -40
  64. package/src/commands/stop.ts +18 -33
  65. package/src/commands/supervisor.test.ts +12 -14
  66. package/src/commands/supervisor.ts +144 -165
  67. package/src/commands/trace.test.ts +15 -15
  68. package/src/commands/trace.ts +59 -82
  69. package/src/commands/watch.test.ts +2 -2
  70. package/src/commands/watch.ts +38 -45
  71. package/src/commands/worktree.test.ts +213 -37
  72. package/src/commands/worktree.ts +110 -55
  73. package/src/config.test.ts +96 -0
  74. package/src/doctor/consistency.test.ts +14 -14
  75. package/src/doctor/databases.test.ts +22 -2
  76. package/src/doctor/databases.ts +16 -0
  77. package/src/doctor/dependencies.test.ts +55 -1
  78. package/src/doctor/dependencies.ts +113 -18
  79. package/src/doctor/merge-queue.test.ts +4 -4
  80. package/src/e2e/init-sling-lifecycle.test.ts +8 -8
  81. package/src/errors.ts +1 -1
  82. package/src/index.ts +223 -213
  83. package/src/logging/color.test.ts +74 -91
  84. package/src/logging/color.ts +52 -46
  85. package/src/logging/reporter.test.ts +10 -10
  86. package/src/logging/reporter.ts +6 -5
  87. package/src/mail/broadcast.test.ts +1 -1
  88. package/src/mail/client.test.ts +6 -6
  89. package/src/mail/store.test.ts +3 -3
  90. package/src/merge/queue.test.ts +73 -7
  91. package/src/merge/queue.ts +17 -2
  92. package/src/merge/resolver.test.ts +159 -7
  93. package/src/merge/resolver.ts +46 -2
  94. package/src/metrics/store.test.ts +44 -44
  95. package/src/metrics/store.ts +2 -2
  96. package/src/metrics/summary.test.ts +35 -35
  97. package/src/mulch/client.test.ts +1 -1
  98. package/src/schema-consistency.test.ts +239 -0
  99. package/src/sessions/compat.test.ts +3 -3
  100. package/src/sessions/compat.ts +2 -2
  101. package/src/sessions/store.test.ts +41 -4
  102. package/src/sessions/store.ts +13 -2
  103. package/src/types.ts +14 -14
  104. package/src/watchdog/daemon.test.ts +10 -10
  105. package/src/watchdog/daemon.ts +1 -1
  106. package/src/watchdog/health.test.ts +1 -1
  107. package/src/worktree/manager.test.ts +20 -20
  108. package/src/worktree/manager.ts +120 -4
  109. package/src/worktree/tmux.test.ts +98 -9
  110. package/src/worktree/tmux.ts +18 -0
@@ -1,10 +1,20 @@
1
1
  import { resolveBackend, trackerCliName } from "../tracker/factory.ts";
2
2
  import type { DoctorCheck, DoctorCheckFn } from "./types.ts";
3
3
 
4
+ interface ToolSpec {
5
+ name: string;
6
+ versionFlag: string;
7
+ required: boolean;
8
+ /** Short alias to check if the primary tool is available. */
9
+ alias?: string;
10
+ /** npm package name for install hint (e.g. "@os-eco/mulch-cli"). */
11
+ installHint?: string;
12
+ }
13
+
4
14
  /**
5
15
  * External dependency checks.
6
- * Validates that required CLI tools (git, bun, tmux, bd, mulch) are available
7
- * and that bd has functional CGO support for its Dolt database backend.
16
+ * Validates that required CLI tools (git, bun, tmux, tracker, mulch, overstory)
17
+ * and optional tools (cn) are available, including short alias availability.
8
18
  */
9
19
  export const checkDependencies: DoctorCheckFn = async (
10
20
  config,
@@ -12,30 +22,56 @@ export const checkDependencies: DoctorCheckFn = async (
12
22
  ): Promise<DoctorCheck[]> => {
13
23
  // Determine which tracker CLI to check based on config backend (resolve "auto")
14
24
  const resolvedBackend = await resolveBackend(config.taskTracker.backend, config.project.root);
15
- const trackerTool = {
16
- name: trackerCliName(resolvedBackend),
17
- versionFlag: "--version",
18
- required: true,
19
- };
25
+ const trackerName = trackerCliName(resolvedBackend);
20
26
 
21
- const requiredTools = [
27
+ const tools: ToolSpec[] = [
22
28
  { name: "git", versionFlag: "--version", required: true },
23
29
  { name: "bun", versionFlag: "--version", required: true },
24
30
  { name: "tmux", versionFlag: "-V", required: true },
25
- trackerTool,
26
- { name: "mulch", versionFlag: "--version", required: true },
31
+ {
32
+ name: trackerName,
33
+ versionFlag: "--version",
34
+ required: true,
35
+ installHint: trackerName === "sd" ? "@os-eco/seeds-cli" : undefined,
36
+ },
37
+ {
38
+ name: "mulch",
39
+ versionFlag: "--version",
40
+ required: true,
41
+ alias: "ml",
42
+ installHint: "@os-eco/mulch-cli",
43
+ },
44
+ {
45
+ name: "overstory",
46
+ versionFlag: "--version",
47
+ required: true,
48
+ alias: "ov",
49
+ installHint: "@os-eco/overstory-cli",
50
+ },
51
+ {
52
+ name: "cn",
53
+ versionFlag: "--version",
54
+ required: false,
55
+ installHint: "@os-eco/canopy-cli",
56
+ },
27
57
  ];
28
58
 
29
59
  const checks: DoctorCheck[] = [];
30
60
 
31
- for (const tool of requiredTools) {
32
- const check = await checkTool(tool.name, tool.versionFlag, tool.required);
61
+ for (const tool of tools) {
62
+ const check = await checkTool(tool.name, tool.versionFlag, tool.required, tool.installHint);
33
63
  checks.push(check);
64
+
65
+ // Check short alias availability if the main tool is available
66
+ if (tool.alias && check.status === "pass") {
67
+ const aliasCheck = await checkAlias(tool.name, tool.alias, tool.installHint);
68
+ checks.push(aliasCheck);
69
+ }
34
70
  }
35
71
 
36
72
  // If bd is available, probe for CGO/Dolt backend functionality.
37
73
  // Only run for beads backend (CGO check is beads-specific).
38
- if (trackerTool.name === "bd") {
74
+ if (trackerName === "bd") {
39
75
  const bdCheck = checks.find((c) => c.name === "bd availability");
40
76
  if (bdCheck?.status === "pass") {
41
77
  const cgoCheck = await checkBdCgoSupport();
@@ -119,6 +155,57 @@ async function checkBdCgoSupport(): Promise<DoctorCheck> {
119
155
  }
120
156
  }
121
157
 
158
+ /**
159
+ * Check if a short alias for a CLI tool is available.
160
+ */
161
+ async function checkAlias(
162
+ toolName: string,
163
+ alias: string,
164
+ installHint?: string,
165
+ ): Promise<DoctorCheck> {
166
+ try {
167
+ const proc = Bun.spawn([alias, "--version"], {
168
+ stdout: "pipe",
169
+ stderr: "pipe",
170
+ });
171
+ const exitCode = await proc.exited;
172
+
173
+ if (exitCode === 0) {
174
+ return {
175
+ name: `${alias} alias`,
176
+ category: "dependencies",
177
+ status: "pass",
178
+ message: `${alias} alias for ${toolName} is available`,
179
+ details: [`Short alias '${alias}' is configured`],
180
+ };
181
+ }
182
+
183
+ const hint = installHint
184
+ ? `Reinstall ${installHint} to get the '${alias}' alias.`
185
+ : `Ensure '${alias}' alias is in your PATH.`;
186
+ return {
187
+ name: `${alias} alias`,
188
+ category: "dependencies",
189
+ status: "warn",
190
+ message: `${alias} alias for ${toolName} not working`,
191
+ details: [hint],
192
+ fixable: true,
193
+ };
194
+ } catch {
195
+ const hint = installHint
196
+ ? `Reinstall ${installHint} to get the '${alias}' alias.`
197
+ : `Ensure '${alias}' alias is in your PATH.`;
198
+ return {
199
+ name: `${alias} alias`,
200
+ category: "dependencies",
201
+ status: "warn",
202
+ message: `${alias} alias for ${toolName} is not available`,
203
+ details: [`'${toolName}' works but short alias '${alias}' was not found.`, hint],
204
+ fixable: true,
205
+ };
206
+ }
207
+ }
208
+
122
209
  /**
123
210
  * Check if a CLI tool is available by attempting to run it with a version flag.
124
211
  */
@@ -126,6 +213,7 @@ async function checkTool(
126
213
  name: string,
127
214
  versionFlag: string,
128
215
  required: boolean,
216
+ installHint?: string,
129
217
  ): Promise<DoctorCheck> {
130
218
  try {
131
219
  const proc = Bun.spawn([name, versionFlag], {
@@ -150,25 +238,32 @@ async function checkTool(
150
238
 
151
239
  // Non-zero exit code
152
240
  const stderr = await new Response(proc.stderr).text();
241
+ const details: string[] = [];
242
+ if (stderr) details.push(stderr.trim());
243
+ if (installHint) details.push(`Install: npm install -g ${installHint}`);
153
244
  return {
154
245
  name: `${name} availability`,
155
246
  category: "dependencies",
156
247
  status: required ? "fail" : "warn",
157
248
  message: `${name} command failed (exit code ${exitCode})`,
158
- details: stderr ? [stderr.trim()] : undefined,
249
+ details: details.length > 0 ? details : undefined,
159
250
  fixable: true,
160
251
  };
161
252
  } catch (error) {
162
253
  // Command not found or spawn failed
254
+ const details: string[] = [];
255
+ if (installHint) {
256
+ details.push(`Install: npm install -g ${installHint}`);
257
+ } else {
258
+ details.push(`Install ${name} or ensure it is in your PATH`);
259
+ }
260
+ details.push(error instanceof Error ? error.message : String(error));
163
261
  return {
164
262
  name: `${name} availability`,
165
263
  category: "dependencies",
166
264
  status: required ? "fail" : "warn",
167
265
  message: `${name} is not installed or not in PATH`,
168
- details: [
169
- `Install ${name} or ensure it is in your PATH`,
170
- error instanceof Error ? error.message : String(error),
171
- ],
266
+ details,
172
267
  fixable: true,
173
268
  };
174
269
  }
@@ -77,13 +77,13 @@ describe("checkMergeQueue", () => {
77
77
  const queue = createMergeQueue(dbPath);
78
78
  queue.enqueue({
79
79
  branchName: "feature/test",
80
- beadId: "beads-abc",
80
+ taskId: "beads-abc",
81
81
  agentName: "test-agent",
82
82
  filesModified: ["src/test.ts"],
83
83
  });
84
84
  queue.enqueue({
85
85
  branchName: "feature/another",
86
- beadId: "beads-def",
86
+ taskId: "beads-def",
87
87
  agentName: "another-agent",
88
88
  filesModified: ["src/another.ts"],
89
89
  });
@@ -194,13 +194,13 @@ describe("checkMergeQueue", () => {
194
194
  const queue = createMergeQueue(dbPath);
195
195
  queue.enqueue({
196
196
  branchName: "feature/duplicate",
197
- beadId: "beads-abc",
197
+ taskId: "beads-abc",
198
198
  agentName: "test-agent",
199
199
  filesModified: ["src/test.ts"],
200
200
  });
201
201
  queue.enqueue({
202
202
  branchName: "feature/duplicate",
203
- beadId: "beads-def",
203
+ taskId: "beads-def",
204
204
  agentName: "another-agent",
205
205
  filesModified: ["src/another.ts"],
206
206
  });
@@ -52,7 +52,7 @@ describe("E2E: init→sling lifecycle on external project", () => {
52
52
  });
53
53
 
54
54
  test("init creates all expected artifacts", async () => {
55
- await initCommand([]);
55
+ await initCommand({});
56
56
 
57
57
  const overstoryDir = join(tempDir, ".overstory");
58
58
 
@@ -92,7 +92,7 @@ describe("E2E: init→sling lifecycle on external project", () => {
92
92
  });
93
93
 
94
94
  test("loadConfig returns valid config pointing to temp dir", async () => {
95
- await initCommand([]);
95
+ await initCommand({});
96
96
 
97
97
  const config = await loadConfig(tempDir);
98
98
 
@@ -110,7 +110,7 @@ describe("E2E: init→sling lifecycle on external project", () => {
110
110
  });
111
111
 
112
112
  test("manifest loads successfully with all 8 agents", async () => {
113
- await initCommand([]);
113
+ await initCommand({});
114
114
 
115
115
  const manifestPath = join(tempDir, ".overstory", "agent-manifest.json");
116
116
  const agentDefsDir = join(tempDir, ".overstory", "agent-defs");
@@ -145,7 +145,7 @@ describe("E2E: init→sling lifecycle on external project", () => {
145
145
  });
146
146
 
147
147
  test("manifest capability index is consistent", async () => {
148
- await initCommand([]);
148
+ await initCommand({});
149
149
 
150
150
  const manifestPath = join(tempDir, ".overstory", "agent-manifest.json");
151
151
  const agentDefsDir = join(tempDir, ".overstory", "agent-defs");
@@ -167,14 +167,14 @@ describe("E2E: init→sling lifecycle on external project", () => {
167
167
  });
168
168
 
169
169
  test("overlay generation works for external project", async () => {
170
- await initCommand([]);
170
+ await initCommand({});
171
171
 
172
172
  const agentDefsDir = join(tempDir, ".overstory", "agent-defs");
173
173
  const baseDefinition = await Bun.file(join(agentDefsDir, "builder.md")).text();
174
174
 
175
175
  const overlayConfig: OverlayConfig = {
176
176
  agentName: "test-agent",
177
- beadId: "test-bead-001",
177
+ taskId: "test-bead-001",
178
178
  specPath: null,
179
179
  branchName: "overstory/test-agent/test-bead-001",
180
180
  worktreePath: join(tempDir, ".overstory", "worktrees", "test-agent"),
@@ -215,7 +215,7 @@ describe("E2E: init→sling lifecycle on external project", () => {
215
215
  // init → load config → load manifest → generate overlay
216
216
 
217
217
  // Step 1: Init
218
- await initCommand([]);
218
+ await initCommand({});
219
219
 
220
220
  // Step 2: Load config
221
221
  const config = await loadConfig(tempDir);
@@ -241,7 +241,7 @@ describe("E2E: init→sling lifecycle on external project", () => {
241
241
  const builderDef = await Bun.file(join(agentDefsDir, "builder.md")).text();
242
242
  const overlayConfig: OverlayConfig = {
243
243
  agentName: "lifecycle-builder",
244
- beadId: "lifecycle-001",
244
+ taskId: "lifecycle-001",
245
245
  specPath: join(tempDir, ".overstory", "specs", "lifecycle-001.md"),
246
246
  branchName: "overstory/lifecycle-builder/lifecycle-001",
247
247
  worktreePath: join(tempDir, ".overstory", "worktrees", "lifecycle-builder"),
package/src/errors.ts CHANGED
@@ -152,7 +152,7 @@ export class MergeError extends OverstoryError {
152
152
 
153
153
  /**
154
154
  * Raised when input validation fails.
155
- * Examples: invalid agent names, malformed beadIds, bad CLI arguments.
155
+ * Examples: invalid agent names, malformed taskIds, bad CLI arguments.
156
156
  */
157
157
  export class ValidationError extends OverstoryError {
158
158
  readonly field: string | null;