@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
package/src/commands/nudge.ts
CHANGED
|
@@ -10,7 +10,8 @@
|
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
12
|
import { join } from "node:path";
|
|
13
|
-
import {
|
|
13
|
+
import { Command } from "commander";
|
|
14
|
+
import { AgentError } from "../errors.ts";
|
|
14
15
|
import { createEventStore } from "../events/store.ts";
|
|
15
16
|
import { openSessionStore } from "../sessions/compat.ts";
|
|
16
17
|
import type { EventStore } from "../types.ts";
|
|
@@ -21,44 +22,6 @@ const MAX_RETRIES = 3;
|
|
|
21
22
|
const RETRY_DELAY_MS = 500;
|
|
22
23
|
const DEBOUNCE_MS = 500;
|
|
23
24
|
|
|
24
|
-
/**
|
|
25
|
-
* Parse a named flag value from args.
|
|
26
|
-
*/
|
|
27
|
-
function getFlag(args: string[], flag: string): string | undefined {
|
|
28
|
-
const idx = args.indexOf(flag);
|
|
29
|
-
if (idx === -1 || idx + 1 >= args.length) {
|
|
30
|
-
return undefined;
|
|
31
|
-
}
|
|
32
|
-
return args[idx + 1];
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
/** Boolean flags that do NOT consume the next arg. */
|
|
36
|
-
const BOOLEAN_FLAGS = new Set(["--json", "--force", "--help", "-h"]);
|
|
37
|
-
|
|
38
|
-
/**
|
|
39
|
-
* Extract positional arguments, skipping flag-value pairs.
|
|
40
|
-
*/
|
|
41
|
-
function getPositionalArgs(args: string[]): string[] {
|
|
42
|
-
const positional: string[] = [];
|
|
43
|
-
let i = 0;
|
|
44
|
-
while (i < args.length) {
|
|
45
|
-
const arg = args[i];
|
|
46
|
-
if (arg?.startsWith("-")) {
|
|
47
|
-
if (BOOLEAN_FLAGS.has(arg)) {
|
|
48
|
-
i += 1;
|
|
49
|
-
} else {
|
|
50
|
-
i += 2;
|
|
51
|
-
}
|
|
52
|
-
} else {
|
|
53
|
-
if (arg !== undefined) {
|
|
54
|
-
positional.push(arg);
|
|
55
|
-
}
|
|
56
|
-
i += 1;
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
return positional;
|
|
60
|
-
}
|
|
61
|
-
|
|
62
25
|
/**
|
|
63
26
|
* Load the orchestrator's registered tmux session name.
|
|
64
27
|
*
|
|
@@ -317,56 +280,45 @@ export async function nudgeAgent(
|
|
|
317
280
|
/**
|
|
318
281
|
* Entry point for `overstory nudge <agent-name> [message]`.
|
|
319
282
|
*/
|
|
320
|
-
const NUDGE_HELP = `overstory nudge — Send a text nudge to an agent
|
|
321
|
-
|
|
322
|
-
Usage: overstory nudge <agent-name> [message]
|
|
323
|
-
|
|
324
|
-
Arguments:
|
|
325
|
-
<agent-name> Name of the agent to nudge
|
|
326
|
-
[message] Text to send (default: "${DEFAULT_MESSAGE}")
|
|
327
|
-
|
|
328
|
-
Options:
|
|
329
|
-
--from <name> Sender name for the nudge prefix (default: orchestrator)
|
|
330
|
-
--force Skip debounce check
|
|
331
|
-
--json Output result as JSON
|
|
332
|
-
--help, -h Show this help`;
|
|
333
|
-
|
|
334
283
|
export async function nudgeCommand(args: string[]): Promise<void> {
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
284
|
+
const program = new Command();
|
|
285
|
+
program
|
|
286
|
+
.name("overstory nudge")
|
|
287
|
+
.description("Send a text nudge to an agent")
|
|
288
|
+
.argument("<agent-name>", "Name of the agent to nudge")
|
|
289
|
+
.argument("[message...]", "Text to send (default: check mail prompt)")
|
|
290
|
+
.option("--from <name>", "Sender name", "orchestrator")
|
|
291
|
+
.option("--force", "Skip debounce check")
|
|
292
|
+
.option("--json", "Output result as JSON")
|
|
293
|
+
.exitOverride()
|
|
294
|
+
.action(
|
|
295
|
+
async (
|
|
296
|
+
agentName: string,
|
|
297
|
+
messageParts: string[],
|
|
298
|
+
opts: { from: string; force?: boolean; json?: boolean },
|
|
299
|
+
) => {
|
|
300
|
+
// Build the nudge message: prefix with sender, use custom or default text
|
|
301
|
+
const customMessage = messageParts.join(" ");
|
|
302
|
+
const rawMessage = customMessage.length > 0 ? customMessage : DEFAULT_MESSAGE;
|
|
303
|
+
const message = `[NUDGE from ${opts.from}] ${rawMessage}`;
|
|
304
|
+
|
|
305
|
+
// Resolve project root
|
|
306
|
+
const { resolveProjectRoot } = await import("../config.ts");
|
|
307
|
+
const projectRoot = await resolveProjectRoot(process.cwd());
|
|
308
|
+
|
|
309
|
+
const result = await nudgeAgent(projectRoot, agentName, message, opts.force ?? false);
|
|
310
|
+
|
|
311
|
+
if (opts.json) {
|
|
312
|
+
process.stdout.write(
|
|
313
|
+
`${JSON.stringify({ agentName, delivered: result.delivered, reason: result.reason })}\n`,
|
|
314
|
+
);
|
|
315
|
+
} else if (result.delivered) {
|
|
316
|
+
process.stdout.write(`📢 Nudged "${agentName}"\n`);
|
|
317
|
+
} else {
|
|
318
|
+
throw new AgentError(`Nudge failed: ${result.reason}`, { agentName });
|
|
319
|
+
}
|
|
320
|
+
},
|
|
366
321
|
);
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
} else {
|
|
370
|
-
throw new AgentError(`Nudge failed: ${result.reason}`, { agentName });
|
|
371
|
-
}
|
|
322
|
+
|
|
323
|
+
await program.parseAsync(["node", "overstory-nudge", ...args]);
|
|
372
324
|
}
|
|
@@ -66,41 +66,9 @@ describe("primeCommand", () => {
|
|
|
66
66
|
return stderrChunks.join("");
|
|
67
67
|
}
|
|
68
68
|
|
|
69
|
-
describe("Help", () => {
|
|
70
|
-
test("--help shows help text", async () => {
|
|
71
|
-
await primeCommand(["--help"]);
|
|
72
|
-
const out = output();
|
|
73
|
-
|
|
74
|
-
expect(out).toContain("overstory prime");
|
|
75
|
-
expect(out).toContain("--agent");
|
|
76
|
-
expect(out).toContain("--compact");
|
|
77
|
-
});
|
|
78
|
-
|
|
79
|
-
test("-h shows help text", async () => {
|
|
80
|
-
await primeCommand(["-h"]);
|
|
81
|
-
const out = output();
|
|
82
|
-
|
|
83
|
-
expect(out).toContain("overstory prime");
|
|
84
|
-
expect(out).toContain("--agent");
|
|
85
|
-
expect(out).toContain("--compact");
|
|
86
|
-
});
|
|
87
|
-
});
|
|
88
|
-
|
|
89
|
-
describe("parseArgs validation", () => {
|
|
90
|
-
test("--agent without a name throws AgentError", async () => {
|
|
91
|
-
await expect(primeCommand(["--agent"])).rejects.toThrow("--agent requires a name argument");
|
|
92
|
-
});
|
|
93
|
-
|
|
94
|
-
test("--agent followed by another flag throws AgentError", async () => {
|
|
95
|
-
await expect(primeCommand(["--agent", "--compact"])).rejects.toThrow(
|
|
96
|
-
"--agent requires a name argument",
|
|
97
|
-
);
|
|
98
|
-
});
|
|
99
|
-
});
|
|
100
|
-
|
|
101
69
|
describe("Orchestrator priming (no --agent flag)", () => {
|
|
102
70
|
test("default prime outputs project context", async () => {
|
|
103
|
-
await primeCommand(
|
|
71
|
+
await primeCommand({});
|
|
104
72
|
const out = output();
|
|
105
73
|
|
|
106
74
|
expect(out).toContain("# Overstory Context");
|
|
@@ -111,7 +79,7 @@ describe("primeCommand", () => {
|
|
|
111
79
|
});
|
|
112
80
|
|
|
113
81
|
test("includes agent manifest section", async () => {
|
|
114
|
-
await primeCommand(
|
|
82
|
+
await primeCommand({});
|
|
115
83
|
const out = output();
|
|
116
84
|
|
|
117
85
|
expect(out).toContain("## Agent Manifest");
|
|
@@ -120,7 +88,7 @@ describe("primeCommand", () => {
|
|
|
120
88
|
});
|
|
121
89
|
|
|
122
90
|
test("without metrics.db shows no recent sessions message", async () => {
|
|
123
|
-
await primeCommand(
|
|
91
|
+
await primeCommand({});
|
|
124
92
|
const out = output();
|
|
125
93
|
|
|
126
94
|
expect(out).toContain("## Recent Activity");
|
|
@@ -128,7 +96,7 @@ describe("primeCommand", () => {
|
|
|
128
96
|
});
|
|
129
97
|
|
|
130
98
|
test("--compact skips Recent Activity and Expertise sections", async () => {
|
|
131
|
-
await primeCommand(
|
|
99
|
+
await primeCommand({ compact: true });
|
|
132
100
|
const out = output();
|
|
133
101
|
|
|
134
102
|
// Should still have project basics
|
|
@@ -143,7 +111,7 @@ describe("primeCommand", () => {
|
|
|
143
111
|
|
|
144
112
|
describe("Agent priming (--agent <name>)", () => {
|
|
145
113
|
test("unknown agent outputs basic context and warns", async () => {
|
|
146
|
-
await primeCommand(
|
|
114
|
+
await primeCommand({ agent: "unknown-agent" });
|
|
147
115
|
const out = output();
|
|
148
116
|
const err = stderr();
|
|
149
117
|
|
|
@@ -166,13 +134,13 @@ expertiseDomains:
|
|
|
166
134
|
- typescript
|
|
167
135
|
- testing
|
|
168
136
|
recentTasks:
|
|
169
|
-
-
|
|
137
|
+
- taskId: task-001
|
|
170
138
|
summary: "Implemented feature X"
|
|
171
139
|
completedAt: "2026-01-10T12:00:00Z"
|
|
172
140
|
`,
|
|
173
141
|
);
|
|
174
142
|
|
|
175
|
-
await primeCommand(
|
|
143
|
+
await primeCommand({ agent: "my-builder" });
|
|
176
144
|
const out = output();
|
|
177
145
|
|
|
178
146
|
expect(out).toContain("# Agent Context: my-builder");
|
|
@@ -193,7 +161,7 @@ recentTasks:
|
|
|
193
161
|
capability: "builder",
|
|
194
162
|
worktreePath: join(tempDir, ".overstory", "worktrees", "active-builder"),
|
|
195
163
|
branchName: "overstory/active-builder/task-001",
|
|
196
|
-
|
|
164
|
+
taskId: "task-001",
|
|
197
165
|
tmuxSession: "overstory-active-builder",
|
|
198
166
|
state: "working",
|
|
199
167
|
pid: 12345,
|
|
@@ -212,7 +180,7 @@ recentTasks:
|
|
|
212
180
|
`${JSON.stringify(sessions, null, 2)}\n`,
|
|
213
181
|
);
|
|
214
182
|
|
|
215
|
-
await primeCommand(
|
|
183
|
+
await primeCommand({ agent: "active-builder" });
|
|
216
184
|
const out = output();
|
|
217
185
|
|
|
218
186
|
expect(out).toContain("# Agent Context: active-builder");
|
|
@@ -230,7 +198,7 @@ recentTasks:
|
|
|
230
198
|
capability: "builder",
|
|
231
199
|
worktreePath: join(tempDir, ".overstory", "worktrees", "completed-builder"),
|
|
232
200
|
branchName: "overstory/completed-builder/task-002",
|
|
233
|
-
|
|
201
|
+
taskId: "task-002",
|
|
234
202
|
tmuxSession: "overstory-completed-builder",
|
|
235
203
|
state: "completed",
|
|
236
204
|
pid: null,
|
|
@@ -249,7 +217,7 @@ recentTasks:
|
|
|
249
217
|
`${JSON.stringify(sessions, null, 2)}\n`,
|
|
250
218
|
);
|
|
251
219
|
|
|
252
|
-
await primeCommand(
|
|
220
|
+
await primeCommand({ agent: "completed-builder" });
|
|
253
221
|
const out = output();
|
|
254
222
|
|
|
255
223
|
expect(out).toContain("# Agent Context: completed-builder");
|
|
@@ -265,7 +233,7 @@ recentTasks:
|
|
|
265
233
|
`${JSON.stringify(
|
|
266
234
|
{
|
|
267
235
|
agentName: "recovery-agent",
|
|
268
|
-
|
|
236
|
+
taskId: "task-003",
|
|
269
237
|
sessionId: "session-003",
|
|
270
238
|
timestamp: new Date().toISOString(),
|
|
271
239
|
progressSummary: "Implemented initial tests for prime command",
|
|
@@ -291,7 +259,7 @@ recentTasks: []
|
|
|
291
259
|
`,
|
|
292
260
|
);
|
|
293
261
|
|
|
294
|
-
await primeCommand(
|
|
262
|
+
await primeCommand({ agent: "recovery-agent", compact: true });
|
|
295
263
|
const out = output();
|
|
296
264
|
|
|
297
265
|
expect(out).toContain("# Agent Context: recovery-agent");
|
|
@@ -317,7 +285,7 @@ recentTasks: []
|
|
|
317
285
|
`,
|
|
318
286
|
);
|
|
319
287
|
|
|
320
|
-
await primeCommand(
|
|
288
|
+
await primeCommand({ agent: "compact-agent", compact: true });
|
|
321
289
|
const out = output();
|
|
322
290
|
|
|
323
291
|
expect(out).toContain("# Agent Context: compact-agent");
|
|
@@ -340,7 +308,7 @@ recentTasks: []
|
|
|
340
308
|
// Save and change cwd to the git repo
|
|
341
309
|
process.chdir(gitRepoDir);
|
|
342
310
|
|
|
343
|
-
await primeCommand(
|
|
311
|
+
await primeCommand({});
|
|
344
312
|
const out = output();
|
|
345
313
|
|
|
346
314
|
expect(out).toContain("# Overstory Context");
|
|
@@ -375,7 +343,7 @@ recentTasks: []
|
|
|
375
343
|
|
|
376
344
|
process.chdir(gitRepoDir);
|
|
377
345
|
|
|
378
|
-
await primeCommand(
|
|
346
|
+
await primeCommand({});
|
|
379
347
|
const out = output();
|
|
380
348
|
|
|
381
349
|
expect(out).toContain("Session branch: feature/my-work (merge target)");
|
|
@@ -412,7 +380,7 @@ recentTasks: []
|
|
|
412
380
|
expect(existsBefore).toBe(false);
|
|
413
381
|
|
|
414
382
|
// Run primeCommand
|
|
415
|
-
await primeCommand(
|
|
383
|
+
await primeCommand({});
|
|
416
384
|
|
|
417
385
|
// Verify .gitignore was created with correct content
|
|
418
386
|
const content = await Bun.file(gitignorePath).text();
|
|
@@ -435,7 +403,7 @@ sessions.db
|
|
|
435
403
|
expect(contentBefore).toBe(staleContent);
|
|
436
404
|
|
|
437
405
|
// Run primeCommand
|
|
438
|
-
await primeCommand(
|
|
406
|
+
await primeCommand({});
|
|
439
407
|
|
|
440
408
|
// Verify .gitignore now has the wildcard+whitelist content
|
|
441
409
|
const contentAfter = await Bun.file(gitignorePath).text();
|
|
@@ -455,7 +423,7 @@ sessions.db
|
|
|
455
423
|
await new Promise((resolve) => setTimeout(resolve, 10));
|
|
456
424
|
|
|
457
425
|
// Run primeCommand
|
|
458
|
-
await primeCommand(
|
|
426
|
+
await primeCommand({});
|
|
459
427
|
|
|
460
428
|
// Verify content is still correct
|
|
461
429
|
const contentAfter = await Bun.file(gitignorePath).text();
|
package/src/commands/prime.ts
CHANGED
|
@@ -12,7 +12,6 @@ import { loadCheckpoint } from "../agents/checkpoint.ts";
|
|
|
12
12
|
import { loadIdentity } from "../agents/identity.ts";
|
|
13
13
|
import { createManifestLoader } from "../agents/manifest.ts";
|
|
14
14
|
import { loadConfig } from "../config.ts";
|
|
15
|
-
import { AgentError } from "../errors.ts";
|
|
16
15
|
import { createMetricsStore } from "../metrics/store.ts";
|
|
17
16
|
import { createMulchClient } from "../mulch/client.ts";
|
|
18
17
|
import { openSessionStore } from "../sessions/compat.ts";
|
|
@@ -35,32 +34,9 @@ const OVERSTORY_GITIGNORE = `# Wildcard+whitelist: ignore everything, whitelist
|
|
|
35
34
|
!agent-defs/
|
|
36
35
|
`;
|
|
37
36
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
* Supports:
|
|
42
|
-
* - `--agent <name>` — Prime for a specific agent
|
|
43
|
-
* - `--compact` — Output reduced context
|
|
44
|
-
*/
|
|
45
|
-
function parseArgs(args: string[]): { agentName: string | null; compact: boolean } {
|
|
46
|
-
let agentName: string | null = null;
|
|
47
|
-
let compact = false;
|
|
48
|
-
|
|
49
|
-
for (let i = 0; i < args.length; i++) {
|
|
50
|
-
const arg = args[i];
|
|
51
|
-
if (arg === "--agent") {
|
|
52
|
-
const next = args[i + 1];
|
|
53
|
-
if (next === undefined || next.startsWith("--")) {
|
|
54
|
-
throw new AgentError("--agent requires a name argument");
|
|
55
|
-
}
|
|
56
|
-
agentName = next;
|
|
57
|
-
i++; // Skip the value
|
|
58
|
-
} else if (arg === "--compact") {
|
|
59
|
-
compact = true;
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
return { agentName, compact };
|
|
37
|
+
export interface PrimeOptions {
|
|
38
|
+
agent?: string;
|
|
39
|
+
compact?: boolean;
|
|
64
40
|
}
|
|
65
41
|
|
|
66
42
|
/**
|
|
@@ -89,7 +65,7 @@ function formatMetrics(sessions: SessionMetrics[]): string {
|
|
|
89
65
|
const status = s.completedAt !== null ? "completed" : "in-progress";
|
|
90
66
|
const duration = s.durationMs > 0 ? ` (${Math.round(s.durationMs / 1000)}s)` : "";
|
|
91
67
|
const merge = s.mergeResult !== null ? ` [${s.mergeResult}]` : "";
|
|
92
|
-
lines.push(`- ${s.agentName} (${s.capability}): ${s.
|
|
68
|
+
lines.push(`- ${s.agentName} (${s.capability}): ${s.taskId} — ${status}${duration}${merge}`);
|
|
93
69
|
}
|
|
94
70
|
return lines.join("\n");
|
|
95
71
|
}
|
|
@@ -110,7 +86,7 @@ function formatIdentity(identity: AgentIdentity): string {
|
|
|
110
86
|
if (identity.recentTasks.length > 0) {
|
|
111
87
|
lines.push("Recent tasks:");
|
|
112
88
|
for (const task of identity.recentTasks) {
|
|
113
|
-
lines.push(` - ${task.
|
|
89
|
+
lines.push(` - ${task.taskId}: ${task.summary} (${task.completedAt})`);
|
|
114
90
|
}
|
|
115
91
|
}
|
|
116
92
|
|
|
@@ -156,24 +132,11 @@ async function healGitignore(overstoryDir: string): Promise<void> {
|
|
|
156
132
|
* Gathers project state and outputs context to stdout for injection
|
|
157
133
|
* into Claude Code's context.
|
|
158
134
|
*
|
|
159
|
-
* @param
|
|
135
|
+
* @param opts - Command options
|
|
160
136
|
*/
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
Options:
|
|
166
|
-
--agent <name> Prime for a specific agent (default: orchestrator)
|
|
167
|
-
--compact Output reduced context (for PreCompact hook)
|
|
168
|
-
--help, -h Show this help`;
|
|
169
|
-
|
|
170
|
-
export async function primeCommand(args: string[]): Promise<void> {
|
|
171
|
-
if (args.includes("--help") || args.includes("-h")) {
|
|
172
|
-
process.stdout.write(`${PRIME_HELP}\n`);
|
|
173
|
-
return;
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
const { agentName, compact } = parseArgs(args);
|
|
137
|
+
export async function primeCommand(opts: PrimeOptions): Promise<void> {
|
|
138
|
+
const agentName = opts.agent ?? null;
|
|
139
|
+
const compact = opts.compact ?? false;
|
|
177
140
|
|
|
178
141
|
// 1. Load config
|
|
179
142
|
const config = await loadConfig(process.cwd());
|
|
@@ -221,7 +184,7 @@ async function outputAgentContext(
|
|
|
221
184
|
const overstoryDir = join(config.project.root, ".overstory");
|
|
222
185
|
const { store } = openSessionStore(overstoryDir);
|
|
223
186
|
let sessionExists = false;
|
|
224
|
-
let boundSession: {
|
|
187
|
+
let boundSession: { taskId: string } | null = null;
|
|
225
188
|
try {
|
|
226
189
|
const agentSession = store.getByName(agentName);
|
|
227
190
|
sessionExists = agentSession !== null;
|
|
@@ -229,9 +192,9 @@ async function outputAgentContext(
|
|
|
229
192
|
agentSession &&
|
|
230
193
|
agentSession.state !== "completed" &&
|
|
231
194
|
agentSession.state !== "zombie" &&
|
|
232
|
-
agentSession.
|
|
195
|
+
agentSession.taskId
|
|
233
196
|
) {
|
|
234
|
-
boundSession = {
|
|
197
|
+
boundSession = { taskId: agentSession.taskId };
|
|
235
198
|
}
|
|
236
199
|
} finally {
|
|
237
200
|
store.close();
|
|
@@ -263,7 +226,7 @@ async function outputAgentContext(
|
|
|
263
226
|
// Activation context: if agent has a bound task, inject it
|
|
264
227
|
if (boundSession) {
|
|
265
228
|
sections.push("\n## Activation");
|
|
266
|
-
sections.push(`You have a bound task: **${boundSession.
|
|
229
|
+
sections.push(`You have a bound task: **${boundSession.taskId}**`);
|
|
267
230
|
sections.push("Read your overlay at `.claude/CLAUDE.md` and begin working immediately.");
|
|
268
231
|
sections.push("Do not wait for dispatch mail. Your assignment was bound at spawn time.");
|
|
269
232
|
}
|
|
@@ -78,7 +78,7 @@ describe("replayCommand", () => {
|
|
|
78
78
|
await replayCommand(["--help"]);
|
|
79
79
|
const out = output();
|
|
80
80
|
|
|
81
|
-
expect(out).toContain("
|
|
81
|
+
expect(out).toContain("replay");
|
|
82
82
|
expect(out).toContain("--run");
|
|
83
83
|
expect(out).toContain("--agent");
|
|
84
84
|
expect(out).toContain("--json");
|
|
@@ -91,7 +91,7 @@ describe("replayCommand", () => {
|
|
|
91
91
|
await replayCommand(["-h"]);
|
|
92
92
|
const out = output();
|
|
93
93
|
|
|
94
|
-
expect(out).toContain("
|
|
94
|
+
expect(out).toContain("replay");
|
|
95
95
|
});
|
|
96
96
|
});
|
|
97
97
|
|