@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.
- package/README.md +61 -61
- 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/checkpoint.test.ts +2 -2
- package/src/agents/hooks-deployer.test.ts +59 -25
- package/src/agents/hooks-deployer.ts +24 -6
- 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/overlay.test.ts +14 -14
- package/src/agents/overlay.ts +14 -14
- package/src/commands/agents.test.ts +5 -5
- package/src/commands/agents.ts +10 -9
- package/src/commands/clean.test.ts +5 -5
- 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 +4 -4
- package/src/commands/coordinator.ts +13 -13
- package/src/commands/costs.test.ts +45 -45
- package/src/commands/costs.ts +1 -1
- package/src/commands/dashboard.ts +11 -11
- 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.test.ts +16 -16
- package/src/commands/inspect.ts +19 -19
- package/src/commands/log.test.ts +21 -21
- package/src/commands/log.ts +10 -10
- package/src/commands/logs.ts +1 -1
- package/src/commands/mail.test.ts +7 -7
- package/src/commands/mail.ts +28 -11
- package/src/commands/merge.test.ts +8 -8
- package/src/commands/merge.ts +15 -15
- package/src/commands/metrics.test.ts +7 -7
- package/src/commands/metrics.ts +3 -3
- package/src/commands/monitor.test.ts +5 -5
- package/src/commands/monitor.ts +5 -5
- package/src/commands/nudge.test.ts +1 -1
- package/src/commands/nudge.ts +1 -1
- package/src/commands/prime.test.ts +5 -5
- package/src/commands/prime.ts +8 -8
- package/src/commands/replay.ts +1 -1
- package/src/commands/run.test.ts +1 -1
- package/src/commands/run.ts +2 -2
- package/src/commands/sling.test.ts +89 -7
- package/src/commands/sling.ts +109 -18
- package/src/commands/spec.test.ts +2 -2
- package/src/commands/spec.ts +13 -14
- package/src/commands/status.test.ts +99 -3
- package/src/commands/status.ts +19 -20
- package/src/commands/stop.test.ts +1 -1
- package/src/commands/stop.ts +2 -2
- package/src/commands/supervisor.test.ts +10 -10
- package/src/commands/supervisor.ts +14 -14
- package/src/commands/trace.test.ts +7 -7
- package/src/commands/trace.ts +10 -10
- package/src/commands/watch.ts +5 -5
- package/src/commands/worktree.test.ts +208 -32
- package/src/commands/worktree.ts +56 -18
- package/src/doctor/consistency.test.ts +14 -14
- 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/merge-queue.test.ts +4 -4
- 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 +8 -4
- package/src/errors.ts +1 -1
- package/src/index.ts +13 -11
- package/src/mail/broadcast.test.ts +1 -1
- package/src/mail/client.test.ts +7 -7
- package/src/mail/client.ts +2 -2
- package/src/mail/store.test.ts +3 -3
- package/src/merge/queue.test.ts +12 -12
- package/src/merge/queue.ts +2 -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/mulch/client.ts +1 -1
- package/src/sessions/compat.test.ts +3 -3
- package/src/sessions/compat.ts +1 -1
- package/src/sessions/store.test.ts +4 -4
- package/src/sessions/store.ts +2 -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 +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
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
|
|
|
@@ -18,7 +19,7 @@ export interface DiscoveredAgent {
|
|
|
18
19
|
agentName: string;
|
|
19
20
|
capability: string;
|
|
20
21
|
state: string;
|
|
21
|
-
|
|
22
|
+
taskId: string;
|
|
22
23
|
branchName: string;
|
|
23
24
|
parentAgent: string | null;
|
|
24
25
|
depth: number;
|
|
@@ -117,7 +118,7 @@ export async function discoverAgents(
|
|
|
117
118
|
agentName: session.agentName,
|
|
118
119
|
capability: session.capability,
|
|
119
120
|
state: session.state,
|
|
120
|
-
|
|
121
|
+
taskId: session.taskId,
|
|
121
122
|
branchName: session.branchName,
|
|
122
123
|
parentAgent: session.parentAgent,
|
|
123
124
|
depth: session.depth,
|
|
@@ -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
|
}
|
|
@@ -166,7 +167,7 @@ function printAgents(agents: DiscoveredAgent[]): void {
|
|
|
166
167
|
for (const agent of agents) {
|
|
167
168
|
const icon = getStateIcon(agent.state);
|
|
168
169
|
w(` ${icon} ${agent.agentName} [${agent.capability}]\n`);
|
|
169
|
-
w(` State: ${agent.state} | Task: ${agent.
|
|
170
|
+
w(` State: ${agent.state} | Task: ${agent.taskId}\n`);
|
|
170
171
|
w(` Branch: ${agent.branchName}\n`);
|
|
171
172
|
w(` Parent: ${agent.parentAgent ?? "none"} | Depth: ${agent.depth}\n`);
|
|
172
173
|
|
|
@@ -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();
|
|
@@ -113,7 +113,7 @@ describe("--all", () => {
|
|
|
113
113
|
const store = createMetricsStore(metricsDbPath);
|
|
114
114
|
store.recordSession({
|
|
115
115
|
agentName: "test-agent",
|
|
116
|
-
|
|
116
|
+
taskId: "task-1",
|
|
117
117
|
capability: "builder",
|
|
118
118
|
startedAt: new Date().toISOString(),
|
|
119
119
|
completedAt: null,
|
|
@@ -148,7 +148,7 @@ describe("--all", () => {
|
|
|
148
148
|
capability: "builder",
|
|
149
149
|
worktreePath: "/tmp/wt",
|
|
150
150
|
branchName: "overstory/test/task",
|
|
151
|
-
|
|
151
|
+
taskId: "task-1",
|
|
152
152
|
tmuxSession: "overstory-test-agent",
|
|
153
153
|
state: "completed",
|
|
154
154
|
pid: 12345,
|
|
@@ -177,7 +177,7 @@ describe("--all", () => {
|
|
|
177
177
|
const queue = createMergeQueue(queuePath);
|
|
178
178
|
queue.enqueue({
|
|
179
179
|
branchName: "test-branch",
|
|
180
|
-
|
|
180
|
+
taskId: "beads-test",
|
|
181
181
|
agentName: "test",
|
|
182
182
|
filesModified: ["src/test.ts"],
|
|
183
183
|
});
|
|
@@ -292,7 +292,7 @@ describe("individual flags", () => {
|
|
|
292
292
|
capability: "builder",
|
|
293
293
|
worktreePath: "/tmp/wt",
|
|
294
294
|
branchName: "overstory/test/task",
|
|
295
|
-
|
|
295
|
+
taskId: "task-1",
|
|
296
296
|
tmuxSession: "overstory-test-agent",
|
|
297
297
|
state: "completed",
|
|
298
298
|
pid: 12345,
|
|
@@ -413,7 +413,7 @@ describe("synthetic session-end events", () => {
|
|
|
413
413
|
capability: "builder",
|
|
414
414
|
worktreePath: "/tmp/wt",
|
|
415
415
|
branchName: "overstory/test-builder/task-1",
|
|
416
|
-
|
|
416
|
+
taskId: "task-1",
|
|
417
417
|
tmuxSession: "overstory-test-builder",
|
|
418
418
|
state: "working",
|
|
419
419
|
pid: 12345,
|
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
|
|
|
@@ -286,7 +286,7 @@ function makeCoordinatorSession(overrides: Partial<AgentSession> = {}): AgentSes
|
|
|
286
286
|
capability: "coordinator",
|
|
287
287
|
worktreePath: tempDir,
|
|
288
288
|
branchName: "main",
|
|
289
|
-
|
|
289
|
+
taskId: "",
|
|
290
290
|
tmuxSession: "overstory-test-project-coordinator",
|
|
291
291
|
state: "working",
|
|
292
292
|
pid: 99999,
|
|
@@ -437,7 +437,7 @@ describe("startCoordinator", () => {
|
|
|
437
437
|
expect(session?.pid).toBe(99999);
|
|
438
438
|
expect(session?.parentAgent).toBeNull();
|
|
439
439
|
expect(session?.depth).toBe(0);
|
|
440
|
-
expect(session?.
|
|
440
|
+
expect(session?.taskId).toBe("");
|
|
441
441
|
expect(session?.branchName).toBe("main");
|
|
442
442
|
expect(session?.worktreePath).toBe(tempDir);
|
|
443
443
|
expect(session?.id).toMatch(/^session-\d+-coordinator$/);
|
|
@@ -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
|
}
|
|
@@ -379,7 +379,7 @@ async function startCoordinator(
|
|
|
379
379
|
capability: "coordinator",
|
|
380
380
|
worktreePath: projectRoot, // Coordinator uses project root, not a worktree
|
|
381
381
|
branchName: config.project.canonicalBranch, // Operates on canonical branch
|
|
382
|
-
|
|
382
|
+
taskId: "", // No specific bead assignment
|
|
383
383
|
tmuxSession,
|
|
384
384
|
state: "booting",
|
|
385
385
|
pid,
|
|
@@ -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)
|