@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.
- package/README.md +8 -7
- package/package.json +12 -4
- package/src/agents/checkpoint.test.ts +2 -2
- package/src/agents/hooks-deployer.test.ts +131 -16
- package/src/agents/hooks-deployer.ts +33 -1
- package/src/agents/identity.test.ts +27 -27
- package/src/agents/identity.ts +10 -10
- package/src/agents/lifecycle.test.ts +6 -6
- package/src/agents/lifecycle.ts +2 -2
- package/src/agents/manifest.test.ts +86 -0
- package/src/agents/overlay.test.ts +9 -9
- package/src/agents/overlay.ts +4 -4
- package/src/commands/agents.test.ts +8 -8
- package/src/commands/agents.ts +62 -91
- package/src/commands/clean.test.ts +36 -51
- package/src/commands/clean.ts +28 -49
- package/src/commands/completions.ts +14 -0
- package/src/commands/coordinator.test.ts +133 -26
- package/src/commands/coordinator.ts +101 -64
- package/src/commands/costs.test.ts +47 -47
- package/src/commands/costs.ts +96 -75
- package/src/commands/dashboard.test.ts +2 -2
- package/src/commands/dashboard.ts +75 -95
- package/src/commands/doctor.test.ts +2 -2
- package/src/commands/doctor.ts +92 -79
- package/src/commands/errors.test.ts +2 -2
- package/src/commands/errors.ts +56 -50
- package/src/commands/feed.test.ts +2 -2
- package/src/commands/feed.ts +86 -83
- package/src/commands/group.ts +167 -177
- package/src/commands/hooks.test.ts +2 -2
- package/src/commands/hooks.ts +52 -42
- package/src/commands/init.test.ts +19 -19
- package/src/commands/init.ts +7 -16
- package/src/commands/inspect.test.ts +18 -18
- package/src/commands/inspect.ts +55 -58
- package/src/commands/log.test.ts +26 -31
- package/src/commands/log.ts +97 -91
- package/src/commands/logs.test.ts +1 -1
- package/src/commands/logs.ts +101 -104
- package/src/commands/mail.test.ts +5 -5
- package/src/commands/mail.ts +157 -169
- package/src/commands/merge.test.ts +28 -66
- package/src/commands/merge.ts +21 -51
- package/src/commands/metrics.test.ts +8 -8
- package/src/commands/metrics.ts +34 -35
- package/src/commands/monitor.test.ts +3 -3
- package/src/commands/monitor.ts +57 -62
- package/src/commands/nudge.test.ts +1 -1
- package/src/commands/nudge.ts +41 -89
- package/src/commands/prime.test.ts +19 -51
- package/src/commands/prime.ts +13 -50
- package/src/commands/replay.test.ts +2 -2
- package/src/commands/replay.ts +79 -86
- package/src/commands/run.test.ts +1 -1
- package/src/commands/run.ts +97 -77
- package/src/commands/sling.test.ts +201 -5
- package/src/commands/sling.ts +37 -64
- package/src/commands/spec.test.ts +14 -40
- package/src/commands/spec.ts +32 -101
- package/src/commands/status.test.ts +97 -1
- package/src/commands/status.ts +63 -58
- package/src/commands/stop.test.ts +22 -40
- package/src/commands/stop.ts +18 -33
- package/src/commands/supervisor.test.ts +12 -14
- package/src/commands/supervisor.ts +144 -165
- package/src/commands/trace.test.ts +15 -15
- package/src/commands/trace.ts +59 -82
- package/src/commands/watch.test.ts +2 -2
- package/src/commands/watch.ts +38 -45
- package/src/commands/worktree.test.ts +213 -37
- package/src/commands/worktree.ts +110 -55
- package/src/config.test.ts +96 -0
- package/src/doctor/consistency.test.ts +14 -14
- package/src/doctor/databases.test.ts +22 -2
- package/src/doctor/databases.ts +16 -0
- package/src/doctor/dependencies.test.ts +55 -1
- package/src/doctor/dependencies.ts +113 -18
- package/src/doctor/merge-queue.test.ts +4 -4
- package/src/e2e/init-sling-lifecycle.test.ts +8 -8
- package/src/errors.ts +1 -1
- package/src/index.ts +223 -213
- package/src/logging/color.test.ts +74 -91
- package/src/logging/color.ts +52 -46
- package/src/logging/reporter.test.ts +10 -10
- package/src/logging/reporter.ts +6 -5
- package/src/mail/broadcast.test.ts +1 -1
- package/src/mail/client.test.ts +6 -6
- package/src/mail/store.test.ts +3 -3
- package/src/merge/queue.test.ts +73 -7
- package/src/merge/queue.ts +17 -2
- package/src/merge/resolver.test.ts +159 -7
- package/src/merge/resolver.ts +46 -2
- package/src/metrics/store.test.ts +44 -44
- package/src/metrics/store.ts +2 -2
- package/src/metrics/summary.test.ts +35 -35
- package/src/mulch/client.test.ts +1 -1
- package/src/schema-consistency.test.ts +239 -0
- package/src/sessions/compat.test.ts +3 -3
- package/src/sessions/compat.ts +2 -2
- package/src/sessions/store.test.ts +41 -4
- package/src/sessions/store.ts +13 -2
- package/src/types.ts +14 -14
- package/src/watchdog/daemon.test.ts +10 -10
- package/src/watchdog/daemon.ts +1 -1
- package/src/watchdog/health.test.ts +1 -1
- package/src/worktree/manager.test.ts +20 -20
- package/src/worktree/manager.ts +120 -4
- package/src/worktree/tmux.test.ts +98 -9
- 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,
|
|
7
|
-
* and
|
|
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
|
|
16
|
-
name: trackerCliName(resolvedBackend),
|
|
17
|
-
versionFlag: "--version",
|
|
18
|
-
required: true,
|
|
19
|
-
};
|
|
25
|
+
const trackerName = trackerCliName(resolvedBackend);
|
|
20
26
|
|
|
21
|
-
const
|
|
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
|
-
|
|
26
|
-
|
|
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
|
|
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 (
|
|
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:
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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;
|