@os-eco/overstory-cli 0.6.5 → 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.
- package/README.md +60 -60
- package/agents/builder.md +16 -16
- package/agents/coordinator.md +57 -57
- package/agents/issue-reviews.md +71 -0
- package/agents/lead.md +43 -42
- package/agents/merger.md +15 -15
- package/agents/monitor.md +37 -37
- package/agents/pr-reviews.md +60 -0
- package/agents/prioritize.md +110 -0
- package/agents/release.md +56 -0
- package/agents/reviewer.md +15 -15
- package/agents/scout.md +18 -18
- package/agents/supervisor.md +78 -78
- package/package.json +1 -1
- package/src/agents/hooks-deployer.test.ts +23 -26
- package/src/agents/hooks-deployer.ts +9 -5
- package/src/agents/overlay.test.ts +5 -5
- package/src/agents/overlay.ts +11 -11
- package/src/commands/agents.ts +7 -6
- package/src/commands/clean.ts +5 -5
- package/src/commands/completions.test.ts +10 -10
- package/src/commands/completions.ts +26 -28
- package/src/commands/coordinator.test.ts +2 -2
- package/src/commands/coordinator.ts +12 -12
- package/src/commands/costs.ts +1 -1
- package/src/commands/dashboard.ts +8 -8
- package/src/commands/doctor.ts +4 -4
- package/src/commands/errors.ts +1 -1
- package/src/commands/feed.ts +1 -1
- package/src/commands/group.ts +3 -3
- package/src/commands/hooks.test.ts +7 -7
- package/src/commands/hooks.ts +7 -7
- package/src/commands/init.test.ts +6 -2
- package/src/commands/init.ts +19 -19
- package/src/commands/inspect.ts +19 -19
- package/src/commands/log.ts +3 -3
- package/src/commands/logs.ts +1 -1
- package/src/commands/mail.test.ts +2 -2
- package/src/commands/mail.ts +28 -11
- package/src/commands/merge.ts +7 -7
- package/src/commands/metrics.test.ts +1 -1
- package/src/commands/metrics.ts +2 -2
- package/src/commands/monitor.test.ts +5 -5
- package/src/commands/monitor.ts +4 -4
- package/src/commands/nudge.ts +1 -1
- package/src/commands/prime.test.ts +1 -1
- package/src/commands/prime.ts +2 -2
- package/src/commands/replay.ts +1 -1
- package/src/commands/run.ts +2 -2
- package/src/commands/sling.test.ts +84 -2
- package/src/commands/sling.ts +97 -9
- package/src/commands/spec.ts +8 -9
- package/src/commands/status.test.ts +2 -2
- package/src/commands/status.ts +2 -4
- package/src/commands/stop.ts +2 -2
- package/src/commands/supervisor.test.ts +1 -1
- package/src/commands/supervisor.ts +4 -4
- package/src/commands/trace.test.ts +2 -2
- package/src/commands/trace.ts +4 -4
- package/src/commands/watch.ts +5 -5
- package/src/commands/worktree.test.ts +3 -3
- package/src/commands/worktree.ts +11 -11
- package/src/doctor/dependencies.test.ts +5 -5
- package/src/doctor/dependencies.ts +2 -2
- package/src/doctor/logs.ts +1 -1
- package/src/doctor/structure.test.ts +1 -1
- package/src/doctor/structure.ts +1 -1
- package/src/doctor/version.test.ts +3 -3
- package/src/doctor/version.ts +1 -1
- package/src/e2e/init-sling-lifecycle.test.ts +6 -2
- package/src/index.ts +11 -9
- package/src/mail/client.test.ts +1 -1
- package/src/mail/client.ts +2 -2
- package/src/mulch/client.ts +1 -1
- package/src/worktree/tmux.test.ts +8 -3
- package/src/worktree/tmux.ts +19 -18
- package/templates/CLAUDE.md.tmpl +27 -27
- package/templates/hooks.json.tmpl +15 -11
- package/templates/overlay.md.tmpl +7 -7
|
@@ -134,7 +134,7 @@ describe("generateOverlay", () => {
|
|
|
134
134
|
const config = makeConfig({ mulchDomains: ["typescript", "testing"] });
|
|
135
135
|
const output = await generateOverlay(config);
|
|
136
136
|
|
|
137
|
-
expect(output).toContain("
|
|
137
|
+
expect(output).toContain("ml prime typescript testing");
|
|
138
138
|
});
|
|
139
139
|
|
|
140
140
|
test("empty mulch domains shows fallback text", async () => {
|
|
@@ -159,7 +159,7 @@ describe("generateOverlay", () => {
|
|
|
159
159
|
});
|
|
160
160
|
const output = await generateOverlay(config);
|
|
161
161
|
|
|
162
|
-
expect(output).toContain("
|
|
162
|
+
expect(output).toContain("ov sling");
|
|
163
163
|
expect(output).toContain("--parent lead-alpha");
|
|
164
164
|
expect(output).toContain("--depth 2");
|
|
165
165
|
});
|
|
@@ -267,7 +267,7 @@ describe("generateOverlay", () => {
|
|
|
267
267
|
const output = await generateOverlay(config);
|
|
268
268
|
|
|
269
269
|
expect(output).toContain("bd close overstory-task1");
|
|
270
|
-
expect(output).toContain("
|
|
270
|
+
expect(output).toContain("ov mail send --to lead-alpha");
|
|
271
271
|
});
|
|
272
272
|
|
|
273
273
|
test("reviewer completion section uses coordinator when no parent", async () => {
|
|
@@ -284,8 +284,8 @@ describe("generateOverlay", () => {
|
|
|
284
284
|
const config = makeConfig({ agentName: "worker-42" });
|
|
285
285
|
const output = await generateOverlay(config);
|
|
286
286
|
|
|
287
|
-
expect(output).toContain("
|
|
288
|
-
expect(output).toContain("
|
|
287
|
+
expect(output).toContain("ov mail check --agent worker-42");
|
|
288
|
+
expect(output).toContain("ov mail send --to");
|
|
289
289
|
});
|
|
290
290
|
|
|
291
291
|
test("output includes base agent definition content (Layer 1)", async () => {
|
package/src/agents/overlay.ts
CHANGED
|
@@ -24,14 +24,14 @@ function formatFileScope(fileScope: readonly string[]): string {
|
|
|
24
24
|
}
|
|
25
25
|
|
|
26
26
|
/**
|
|
27
|
-
* Format mulch domains as a `
|
|
27
|
+
* Format mulch domains as a `ml prime` command.
|
|
28
28
|
* Returns a human-readable fallback if no domains are configured.
|
|
29
29
|
*/
|
|
30
30
|
function formatMulchDomains(domains: readonly string[]): string {
|
|
31
31
|
if (domains.length === 0) {
|
|
32
32
|
return "No specific expertise domains configured";
|
|
33
33
|
}
|
|
34
|
-
return `\`\`\`bash\
|
|
34
|
+
return `\`\`\`bash\nml prime ${domains.join(" ")}\n\`\`\``;
|
|
35
35
|
}
|
|
36
36
|
|
|
37
37
|
/**
|
|
@@ -90,9 +90,9 @@ function formatQualityGates(config: OverlayConfig): string {
|
|
|
90
90
|
"",
|
|
91
91
|
"Before reporting completion:",
|
|
92
92
|
"",
|
|
93
|
-
`1. **Record mulch learnings:** \`
|
|
93
|
+
`1. **Record mulch learnings:** \`ml record <domain> --type <convention|pattern|reference> --description "..."\` — capture reusable knowledge from your work`,
|
|
94
94
|
`2. **Close issue:** \`${config.trackerCli ?? "bd"} close ${config.taskId} --reason "summary of findings"\``,
|
|
95
|
-
`3. **Send results:** \`
|
|
95
|
+
`3. **Send results:** \`ov mail send --to ${config.parentAgent ?? "coordinator"} --subject "done" --body "Summary" --type result --agent ${config.agentName}\``,
|
|
96
96
|
"",
|
|
97
97
|
"You are a read-only agent. Do NOT commit, modify files, or run quality gates.",
|
|
98
98
|
].join("\n");
|
|
@@ -112,12 +112,12 @@ function formatQualityGates(config: OverlayConfig): string {
|
|
|
112
112
|
"",
|
|
113
113
|
...gateLines,
|
|
114
114
|
`${gateLines.length + 1}. **Commit:** all changes committed to your branch (${config.branchName})`,
|
|
115
|
-
`${gateLines.length + 2}. **Record mulch learnings:** \`
|
|
116
|
-
`${gateLines.length + 3}. **Signal completion:** send \`worker_done\` mail to ${config.parentAgent ?? "coordinator"}: \`
|
|
115
|
+
`${gateLines.length + 2}. **Record mulch learnings:** \`ml record <domain> --type <convention|pattern|failure|decision> --description "..." --outcome-status success --outcome-agent ${config.agentName}\` — capture insights from your work`,
|
|
116
|
+
`${gateLines.length + 3}. **Signal completion:** send \`worker_done\` mail to ${config.parentAgent ?? "coordinator"}: \`ov mail send --to ${config.parentAgent ?? "coordinator"} --subject "Worker done: ${config.taskId}" --body "Quality gates passed." --type worker_done --agent ${config.agentName}\``,
|
|
117
117
|
`${gateLines.length + 4}. **Close issue:** \`${config.trackerCli ?? "bd"} close ${config.taskId} --reason "summary of changes"\``,
|
|
118
118
|
"",
|
|
119
119
|
"Do NOT push to the canonical branch. Your work will be merged by the",
|
|
120
|
-
"coordinator via `
|
|
120
|
+
"coordinator via `ov merge`.",
|
|
121
121
|
].join("\n");
|
|
122
122
|
}
|
|
123
123
|
|
|
@@ -132,7 +132,7 @@ function formatConstraints(config: OverlayConfig): string {
|
|
|
132
132
|
"",
|
|
133
133
|
"- You are **read-only**: do NOT modify, create, or delete any files",
|
|
134
134
|
"- Do NOT commit, push, or make any git state changes",
|
|
135
|
-
`- Report completion via \`${config.trackerCli ?? "bd"} close\` AND \`
|
|
135
|
+
`- Report completion via \`${config.trackerCli ?? "bd"} close\` AND \`ov mail send --type result\``,
|
|
136
136
|
"- If you encounter a blocking issue, send mail with `--priority urgent --type error`",
|
|
137
137
|
].join("\n");
|
|
138
138
|
}
|
|
@@ -145,7 +145,7 @@ function formatConstraints(config: OverlayConfig): string {
|
|
|
145
145
|
"- Only modify files in your File Scope",
|
|
146
146
|
`- Commit only to your branch: ${config.branchName}`,
|
|
147
147
|
"- Never push to the canonical branch",
|
|
148
|
-
`- Report completion via \`${config.trackerCli ?? "bd"} close\` AND \`
|
|
148
|
+
`- Report completion via \`${config.trackerCli ?? "bd"} close\` AND \`ov mail send --type result\``,
|
|
149
149
|
"- If you encounter a blocking issue, send mail with `--priority urgent --type error`",
|
|
150
150
|
].join("\n");
|
|
151
151
|
}
|
|
@@ -159,10 +159,10 @@ function formatCanSpawn(config: OverlayConfig): string {
|
|
|
159
159
|
return "You may NOT spawn sub-workers.";
|
|
160
160
|
}
|
|
161
161
|
return [
|
|
162
|
-
"You may spawn sub-workers using `
|
|
162
|
+
"You may spawn sub-workers using `ov sling`. Example:",
|
|
163
163
|
"",
|
|
164
164
|
"```bash",
|
|
165
|
-
"
|
|
165
|
+
"ov sling <task-id> --capability builder --name <worker-name> \\",
|
|
166
166
|
` --parent ${config.agentName} --depth ${config.depth + 1}`,
|
|
167
167
|
"```",
|
|
168
168
|
].join("\n");
|
package/src/commands/agents.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* CLI command:
|
|
2
|
+
* CLI command: ov agents <sub> [--json]
|
|
3
3
|
*
|
|
4
4
|
* Discover and query agents by capability.
|
|
5
5
|
*/
|
|
@@ -8,6 +8,7 @@ import { join } from "node:path";
|
|
|
8
8
|
import { Command } from "commander";
|
|
9
9
|
import { loadConfig } from "../config.ts";
|
|
10
10
|
import { ValidationError } from "../errors.ts";
|
|
11
|
+
import { color } from "../logging/color.ts";
|
|
11
12
|
import { openSessionStore } from "../sessions/compat.ts";
|
|
12
13
|
import { type AgentSession, SUPPORTED_CAPABILITIES } from "../types.ts";
|
|
13
14
|
|
|
@@ -140,11 +141,11 @@ export async function discoverAgents(
|
|
|
140
141
|
function getStateIcon(state: string): string {
|
|
141
142
|
switch (state) {
|
|
142
143
|
case "working":
|
|
143
|
-
return "
|
|
144
|
+
return color.cyan(">");
|
|
144
145
|
case "booting":
|
|
145
|
-
return "
|
|
146
|
+
return color.green("-");
|
|
146
147
|
case "stalled":
|
|
147
|
-
return "
|
|
148
|
+
return color.yellow("!");
|
|
148
149
|
default:
|
|
149
150
|
return " ";
|
|
150
151
|
}
|
|
@@ -181,7 +182,7 @@ function printAgents(agents: DiscoveredAgent[]): void {
|
|
|
181
182
|
}
|
|
182
183
|
|
|
183
184
|
/**
|
|
184
|
-
* Create the Commander command for `
|
|
185
|
+
* Create the Commander command for `ov agents`.
|
|
185
186
|
*/
|
|
186
187
|
export function createAgentsCommand(): Command {
|
|
187
188
|
const cmd = new Command("agents").description("Discover and query agents");
|
|
@@ -229,7 +230,7 @@ export function createAgentsCommand(): Command {
|
|
|
229
230
|
}
|
|
230
231
|
|
|
231
232
|
/**
|
|
232
|
-
* Entry point for `
|
|
233
|
+
* Entry point for `ov agents <subcommand>`.
|
|
233
234
|
*/
|
|
234
235
|
export async function agentsCommand(args: string[]): Promise<void> {
|
|
235
236
|
const cmd = createAgentsCommand();
|
package/src/commands/clean.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* CLI command:
|
|
2
|
+
* CLI command: ov clean [--all] [--mail] [--sessions] [--metrics]
|
|
3
3
|
* [--logs] [--worktrees] [--branches] [--agents] [--specs]
|
|
4
4
|
*
|
|
5
5
|
* Nuclear cleanup of overstory runtime state.
|
|
@@ -394,7 +394,7 @@ async function checkMulchHealth(repoRoot: string): Promise<{
|
|
|
394
394
|
}
|
|
395
395
|
|
|
396
396
|
/**
|
|
397
|
-
* Entry point for `
|
|
397
|
+
* Entry point for `ov clean [flags]`.
|
|
398
398
|
*
|
|
399
399
|
* @param opts - Command options
|
|
400
400
|
*/
|
|
@@ -556,7 +556,7 @@ export async function cleanCommand(opts: CleanOptions): Promise<void> {
|
|
|
556
556
|
const healthLines: string[] = [];
|
|
557
557
|
|
|
558
558
|
if (health.domainsNearLimit.length > 0) {
|
|
559
|
-
healthLines.push("\
|
|
559
|
+
healthLines.push("\nWarning: Mulch domains approaching governance limits:");
|
|
560
560
|
for (const d of health.domainsNearLimit) {
|
|
561
561
|
healthLines.push(
|
|
562
562
|
` ${d.domain}: ${d.recordCount} records (warn threshold: ${d.warnThreshold})`,
|
|
@@ -566,13 +566,13 @@ export async function cleanCommand(opts: CleanOptions): Promise<void> {
|
|
|
566
566
|
|
|
567
567
|
if (health.stalePruneCandidates > 0) {
|
|
568
568
|
healthLines.push(
|
|
569
|
-
`\
|
|
569
|
+
`\nStale records found: ${health.stalePruneCandidates} candidate${health.stalePruneCandidates === 1 ? "" : "s"} (run 'mulch prune' to remove)`,
|
|
570
570
|
);
|
|
571
571
|
}
|
|
572
572
|
|
|
573
573
|
if (health.doctorWarnings > 0 || health.doctorIssues > 0) {
|
|
574
574
|
healthLines.push(
|
|
575
|
-
`\
|
|
575
|
+
`\nMulch health check: ${health.doctorWarnings} warning${health.doctorWarnings === 1 ? "" : "s"}, ${health.doctorIssues} issue${health.doctorIssues === 1 ? "" : "s"} (run 'mulch doctor' for details)`,
|
|
576
576
|
);
|
|
577
577
|
}
|
|
578
578
|
|
|
@@ -54,8 +54,8 @@ describe("COMMANDS array", () => {
|
|
|
54
54
|
describe("generateBash", () => {
|
|
55
55
|
it("should return a bash completion script", () => {
|
|
56
56
|
const script = generateBash();
|
|
57
|
-
expect(script).toContain("
|
|
58
|
-
expect(script).toContain("complete -F
|
|
57
|
+
expect(script).toContain("_ov()");
|
|
58
|
+
expect(script).toContain("complete -F _ov ov");
|
|
59
59
|
expect(script).toContain("_init_completion");
|
|
60
60
|
});
|
|
61
61
|
|
|
@@ -87,8 +87,8 @@ describe("generateBash", () => {
|
|
|
87
87
|
describe("generateZsh", () => {
|
|
88
88
|
it("should return a zsh completion script", () => {
|
|
89
89
|
const script = generateZsh();
|
|
90
|
-
expect(script).toContain("#compdef
|
|
91
|
-
expect(script).toContain("
|
|
90
|
+
expect(script).toContain("#compdef ov");
|
|
91
|
+
expect(script).toContain("_ov()");
|
|
92
92
|
expect(script).toContain("_describe");
|
|
93
93
|
expect(script).toContain("_arguments");
|
|
94
94
|
});
|
|
@@ -119,7 +119,7 @@ describe("generateZsh", () => {
|
|
|
119
119
|
describe("generateFish", () => {
|
|
120
120
|
it("should return a fish completion script", () => {
|
|
121
121
|
const script = generateFish();
|
|
122
|
-
expect(script).toContain("complete -c
|
|
122
|
+
expect(script).toContain("complete -c ov");
|
|
123
123
|
expect(script).toContain("__fish_use_subcommand");
|
|
124
124
|
});
|
|
125
125
|
|
|
@@ -160,8 +160,8 @@ describe("completionsCommand", () => {
|
|
|
160
160
|
|
|
161
161
|
try {
|
|
162
162
|
completionsCommand(["bash"]);
|
|
163
|
-
expect(output).toContain("
|
|
164
|
-
expect(output).toContain("complete -F
|
|
163
|
+
expect(output).toContain("_ov()");
|
|
164
|
+
expect(output).toContain("complete -F _ov ov");
|
|
165
165
|
} finally {
|
|
166
166
|
process.stdout.write = originalWrite;
|
|
167
167
|
}
|
|
@@ -178,8 +178,8 @@ describe("completionsCommand", () => {
|
|
|
178
178
|
|
|
179
179
|
try {
|
|
180
180
|
completionsCommand(["zsh"]);
|
|
181
|
-
expect(output).toContain("#compdef
|
|
182
|
-
expect(output).toContain("
|
|
181
|
+
expect(output).toContain("#compdef ov");
|
|
182
|
+
expect(output).toContain("_ov()");
|
|
183
183
|
} finally {
|
|
184
184
|
process.stdout.write = originalWrite;
|
|
185
185
|
}
|
|
@@ -196,7 +196,7 @@ describe("completionsCommand", () => {
|
|
|
196
196
|
|
|
197
197
|
try {
|
|
198
198
|
completionsCommand(["fish"]);
|
|
199
|
-
expect(output).toContain("complete -c
|
|
199
|
+
expect(output).toContain("complete -c ov");
|
|
200
200
|
} finally {
|
|
201
201
|
process.stdout.write = originalWrite;
|
|
202
202
|
}
|
|
@@ -609,11 +609,11 @@ export const COMMANDS: readonly CommandDef[] = [
|
|
|
609
609
|
|
|
610
610
|
export function generateBash(): string {
|
|
611
611
|
const lines: string[] = [
|
|
612
|
-
"# Bash completion for
|
|
612
|
+
"# Bash completion for ov",
|
|
613
613
|
"# Source this file to enable completions:",
|
|
614
|
-
"# source <(
|
|
614
|
+
"# source <(ov --completions bash)",
|
|
615
615
|
"",
|
|
616
|
-
"
|
|
616
|
+
"_ov() {",
|
|
617
617
|
" local cur prev words cword",
|
|
618
618
|
" _init_completion || return",
|
|
619
619
|
"",
|
|
@@ -668,19 +668,19 @@ export function generateBash(): string {
|
|
|
668
668
|
lines.push(" return 0");
|
|
669
669
|
lines.push("}");
|
|
670
670
|
lines.push("");
|
|
671
|
-
lines.push("complete -F
|
|
671
|
+
lines.push("complete -F _ov ov");
|
|
672
672
|
|
|
673
673
|
return lines.join("\n");
|
|
674
674
|
}
|
|
675
675
|
|
|
676
676
|
export function generateZsh(): string {
|
|
677
677
|
const lines: string[] = [
|
|
678
|
-
"#compdef
|
|
679
|
-
"# Zsh completion for
|
|
678
|
+
"#compdef ov",
|
|
679
|
+
"# Zsh completion for ov",
|
|
680
680
|
"# Place this file in your fpath or source it:",
|
|
681
|
-
"# source <(
|
|
681
|
+
"# source <(ov --completions zsh)",
|
|
682
682
|
"",
|
|
683
|
-
"
|
|
683
|
+
"_ov() {",
|
|
684
684
|
" local -a commands",
|
|
685
685
|
" commands=(",
|
|
686
686
|
];
|
|
@@ -778,24 +778,24 @@ export function generateZsh(): string {
|
|
|
778
778
|
lines.push(" esac");
|
|
779
779
|
lines.push("}");
|
|
780
780
|
lines.push("");
|
|
781
|
-
lines.push('
|
|
781
|
+
lines.push('_ov "$@"');
|
|
782
782
|
|
|
783
783
|
return lines.join("\n");
|
|
784
784
|
}
|
|
785
785
|
|
|
786
786
|
export function generateFish(): string {
|
|
787
787
|
const lines: string[] = [
|
|
788
|
-
"# Fish completion for
|
|
789
|
-
"# Place this file in ~/.config/fish/completions/
|
|
790
|
-
"#
|
|
788
|
+
"# Fish completion for ov",
|
|
789
|
+
"# Place this file in ~/.config/fish/completions/ov.fish or source it:",
|
|
790
|
+
"# ov --completions fish | source",
|
|
791
791
|
"",
|
|
792
|
-
"# Remove all existing completions for
|
|
793
|
-
"complete -c
|
|
792
|
+
"# Remove all existing completions for ov",
|
|
793
|
+
"complete -c ov -e",
|
|
794
794
|
"",
|
|
795
795
|
"# Global options",
|
|
796
|
-
"complete -c
|
|
797
|
-
"complete -c
|
|
798
|
-
"complete -c
|
|
796
|
+
"complete -c ov -l help -d 'Show help'",
|
|
797
|
+
"complete -c ov -l version -d 'Show version'",
|
|
798
|
+
"complete -c ov -l completions -d 'Generate shell completions' -xa 'bash zsh fish'",
|
|
799
799
|
"",
|
|
800
800
|
];
|
|
801
801
|
|
|
@@ -803,15 +803,13 @@ export function generateFish(): string {
|
|
|
803
803
|
for (const cmd of COMMANDS) {
|
|
804
804
|
// Command name
|
|
805
805
|
lines.push(`# ${cmd.desc}`);
|
|
806
|
-
lines.push(
|
|
807
|
-
`complete -c overstory -f -n '__fish_use_subcommand' -a '${cmd.name}' -d '${cmd.desc}'`,
|
|
808
|
-
);
|
|
806
|
+
lines.push(`complete -c ov -f -n '__fish_use_subcommand' -a '${cmd.name}' -d '${cmd.desc}'`);
|
|
809
807
|
|
|
810
808
|
if (cmd.subcommands && cmd.subcommands.length > 0) {
|
|
811
809
|
// Subcommand names
|
|
812
810
|
for (const subcmd of cmd.subcommands) {
|
|
813
811
|
lines.push(
|
|
814
|
-
`complete -c
|
|
812
|
+
`complete -c ov -f -n '__fish_seen_subcommand_from ${cmd.name}; and not __fish_seen_subcommand_from ${cmd.subcommands.map((s) => s.name).join(" ")}' -a '${subcmd.name}' -d '${subcmd.desc}'`,
|
|
815
813
|
);
|
|
816
814
|
|
|
817
815
|
// Subcommand flags
|
|
@@ -822,12 +820,12 @@ export function generateFish(): string {
|
|
|
822
820
|
|
|
823
821
|
if (flag.values) {
|
|
824
822
|
lines.push(
|
|
825
|
-
`complete -c
|
|
823
|
+
`complete -c ov -f -n ${cond} -l '${flagName}' -d '${flag.desc}' -xa '${flag.values.join(" ")}'`,
|
|
826
824
|
);
|
|
827
825
|
} else if (flag.takesValue) {
|
|
828
|
-
lines.push(`complete -c
|
|
826
|
+
lines.push(`complete -c ov -n ${cond} -l '${flagName}' -d '${flag.desc}'`);
|
|
829
827
|
} else {
|
|
830
|
-
lines.push(`complete -c
|
|
828
|
+
lines.push(`complete -c ov -f -n ${cond} -l '${flagName}' -d '${flag.desc}'`);
|
|
831
829
|
}
|
|
832
830
|
}
|
|
833
831
|
}
|
|
@@ -842,12 +840,12 @@ export function generateFish(): string {
|
|
|
842
840
|
|
|
843
841
|
if (flag.values) {
|
|
844
842
|
lines.push(
|
|
845
|
-
`complete -c
|
|
843
|
+
`complete -c ov -f -n ${cond} -l '${flagName}' -d '${flag.desc}' -xa '${flag.values.join(" ")}'`,
|
|
846
844
|
);
|
|
847
845
|
} else if (flag.takesValue) {
|
|
848
|
-
lines.push(`complete -c
|
|
846
|
+
lines.push(`complete -c ov -n ${cond} -l '${flagName}' -d '${flag.desc}'`);
|
|
849
847
|
} else {
|
|
850
|
-
lines.push(`complete -c
|
|
848
|
+
lines.push(`complete -c ov -f -n ${cond} -l '${flagName}' -d '${flag.desc}'`);
|
|
851
849
|
}
|
|
852
850
|
}
|
|
853
851
|
}
|
|
@@ -875,7 +873,7 @@ export function completionsCommand(args: string[]): void {
|
|
|
875
873
|
|
|
876
874
|
if (!shell) {
|
|
877
875
|
process.stderr.write("Error: missing shell argument\n");
|
|
878
|
-
process.stderr.write("Usage:
|
|
876
|
+
process.stderr.write("Usage: ov --completions <bash|zsh|fish>\n");
|
|
879
877
|
process.exit(1);
|
|
880
878
|
}
|
|
881
879
|
|
|
@@ -1025,9 +1025,9 @@ describe("buildCoordinatorBeacon", () => {
|
|
|
1025
1025
|
test("includes startup instructions", () => {
|
|
1026
1026
|
const beacon = buildCoordinatorBeacon();
|
|
1027
1027
|
expect(beacon).toContain("mulch prime");
|
|
1028
|
-
expect(beacon).toContain("
|
|
1028
|
+
expect(beacon).toContain("ov mail check --agent coordinator");
|
|
1029
1029
|
expect(beacon).toContain("bd ready");
|
|
1030
|
-
expect(beacon).toContain("
|
|
1030
|
+
expect(beacon).toContain("ov group status");
|
|
1031
1031
|
});
|
|
1032
1032
|
|
|
1033
1033
|
test("defaults to bd ready when no cliName provided", () => {
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* CLI command:
|
|
2
|
+
* CLI command: ov coordinator start|stop|status
|
|
3
3
|
*
|
|
4
4
|
* Manages the persistent coordinator agent lifecycle. The coordinator runs
|
|
5
5
|
* at the project root (NOT in a worktree), receives work via mail and beads,
|
|
6
|
-
* and dispatches agents via
|
|
6
|
+
* and dispatches agents via ov sling.
|
|
7
7
|
*
|
|
8
8
|
* Unlike regular agents spawned by sling, the coordinator:
|
|
9
9
|
* - Has no worktree (operates on the main working tree)
|
|
@@ -115,7 +115,7 @@ async function removeWatchdogPid(projectRoot: string): Promise<void> {
|
|
|
115
115
|
|
|
116
116
|
/**
|
|
117
117
|
* Default watchdog implementation for production use.
|
|
118
|
-
* Starts/stops the watchdog daemon via `
|
|
118
|
+
* Starts/stops the watchdog daemon via `ov watch --background`.
|
|
119
119
|
*/
|
|
120
120
|
function createDefaultWatchdog(projectRoot: string): NonNullable<CoordinatorDeps["_watchdog"]> {
|
|
121
121
|
return {
|
|
@@ -132,7 +132,7 @@ function createDefaultWatchdog(projectRoot: string): NonNullable<CoordinatorDeps
|
|
|
132
132
|
}
|
|
133
133
|
|
|
134
134
|
// Start watchdog in background
|
|
135
|
-
const proc = Bun.spawn(["
|
|
135
|
+
const proc = Bun.spawn(["ov", "watch", "--background"], {
|
|
136
136
|
cwd: projectRoot,
|
|
137
137
|
stdout: "pipe",
|
|
138
138
|
stderr: "pipe",
|
|
@@ -189,12 +189,12 @@ function createDefaultWatchdog(projectRoot: string): NonNullable<CoordinatorDeps
|
|
|
189
189
|
|
|
190
190
|
/**
|
|
191
191
|
* Default monitor implementation for production use.
|
|
192
|
-
* Starts/stops the monitor agent via `
|
|
192
|
+
* Starts/stops the monitor agent via `ov monitor start/stop`.
|
|
193
193
|
*/
|
|
194
194
|
function createDefaultMonitor(projectRoot: string): NonNullable<CoordinatorDeps["_monitor"]> {
|
|
195
195
|
return {
|
|
196
196
|
async start(): Promise<{ pid: number } | null> {
|
|
197
|
-
const proc = Bun.spawn(["
|
|
197
|
+
const proc = Bun.spawn(["ov", "monitor", "start", "--no-attach", "--json"], {
|
|
198
198
|
cwd: projectRoot,
|
|
199
199
|
stdout: "pipe",
|
|
200
200
|
stderr: "pipe",
|
|
@@ -210,7 +210,7 @@ function createDefaultMonitor(projectRoot: string): NonNullable<CoordinatorDeps[
|
|
|
210
210
|
}
|
|
211
211
|
},
|
|
212
212
|
async stop(): Promise<boolean> {
|
|
213
|
-
const proc = Bun.spawn(["
|
|
213
|
+
const proc = Bun.spawn(["ov", "monitor", "stop", "--json"], {
|
|
214
214
|
cwd: projectRoot,
|
|
215
215
|
stdout: "pipe",
|
|
216
216
|
stderr: "pipe",
|
|
@@ -219,7 +219,7 @@ function createDefaultMonitor(projectRoot: string): NonNullable<CoordinatorDeps[
|
|
|
219
219
|
return exitCode === 0;
|
|
220
220
|
},
|
|
221
221
|
async isRunning(): Promise<boolean> {
|
|
222
|
-
const proc = Bun.spawn(["
|
|
222
|
+
const proc = Bun.spawn(["ov", "monitor", "status", "--json"], {
|
|
223
223
|
cwd: projectRoot,
|
|
224
224
|
stdout: "pipe",
|
|
225
225
|
stderr: "pipe",
|
|
@@ -248,9 +248,9 @@ export function buildCoordinatorBeacon(cliName = "bd"): string {
|
|
|
248
248
|
const parts = [
|
|
249
249
|
`[OVERSTORY] ${COORDINATOR_NAME} (coordinator) ${timestamp}`,
|
|
250
250
|
"Depth: 0 | Parent: none | Role: persistent orchestrator",
|
|
251
|
-
"HIERARCHY: You ONLY spawn leads (
|
|
251
|
+
"HIERARCHY: You ONLY spawn leads (ov sling --capability lead). Leads spawn scouts, builders, reviewers. NEVER spawn non-lead agents directly.",
|
|
252
252
|
"DELEGATION: For any exploration/scouting, spawn a lead who will spawn scouts. Do NOT explore the codebase yourself beyond initial planning.",
|
|
253
|
-
`Startup: run mulch prime, check mail (
|
|
253
|
+
`Startup: run mulch prime, check mail (ov mail check --agent ${COORDINATOR_NAME}), check ${cliName} ready, check ov group status, then begin work`,
|
|
254
254
|
];
|
|
255
255
|
return parts.join(" — ");
|
|
256
256
|
}
|
|
@@ -686,7 +686,7 @@ async function statusCoordinator(
|
|
|
686
686
|
}
|
|
687
687
|
|
|
688
688
|
/**
|
|
689
|
-
* Create the Commander command for `
|
|
689
|
+
* Create the Commander command for `ov coordinator`.
|
|
690
690
|
*/
|
|
691
691
|
export function createCoordinatorCommand(deps: CoordinatorDeps = {}): Command {
|
|
692
692
|
const cmd = new Command("coordinator").description("Manage the persistent coordinator agent");
|
|
@@ -735,7 +735,7 @@ export function createCoordinatorCommand(deps: CoordinatorDeps = {}): Command {
|
|
|
735
735
|
}
|
|
736
736
|
|
|
737
737
|
/**
|
|
738
|
-
* Entry point for `
|
|
738
|
+
* Entry point for `ov coordinator <subcommand>`.
|
|
739
739
|
*
|
|
740
740
|
* @param args - CLI arguments after "coordinator"
|
|
741
741
|
* @param deps - Optional dependency injection for testing (tmux)
|
package/src/commands/costs.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* CLI command:
|
|
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:
|
|
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(`
|
|
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
|
}
|
|
@@ -508,7 +508,7 @@ 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("
|
|
511
|
+
const tmuxDot = tmuxAlive ? color.green(">") : color.red("x");
|
|
512
512
|
|
|
513
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`;
|
package/src/commands/doctor.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* CLI command:
|
|
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
|
|
package/src/commands/errors.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* CLI command:
|
|
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.
|
package/src/commands/feed.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* CLI command:
|
|
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.
|
package/src/commands/group.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* CLI command:
|
|
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 `
|
|
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 `
|
|
475
|
+
* Entry point for `ov group <subcommand>`.
|
|
476
476
|
*/
|
|
477
477
|
export async function groupCommand(args: string[]): Promise<void> {
|
|
478
478
|
const cmd = createGroupCommand();
|