@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
|
@@ -71,26 +71,11 @@ afterEach(async () => {
|
|
|
71
71
|
await cleanupTempDir(tempDir);
|
|
72
72
|
});
|
|
73
73
|
|
|
74
|
-
// === help ===
|
|
75
|
-
|
|
76
|
-
describe("help", () => {
|
|
77
|
-
test("--help shows usage", async () => {
|
|
78
|
-
await cleanCommand(["--help"]);
|
|
79
|
-
expect(stdoutOutput).toContain("overstory clean");
|
|
80
|
-
expect(stdoutOutput).toContain("--all");
|
|
81
|
-
});
|
|
82
|
-
|
|
83
|
-
test("-h shows usage", async () => {
|
|
84
|
-
await cleanCommand(["-h"]);
|
|
85
|
-
expect(stdoutOutput).toContain("overstory clean");
|
|
86
|
-
});
|
|
87
|
-
});
|
|
88
|
-
|
|
89
74
|
// === validation ===
|
|
90
75
|
|
|
91
76
|
describe("validation", () => {
|
|
92
77
|
test("no flags throws ValidationError", async () => {
|
|
93
|
-
await expect(cleanCommand(
|
|
78
|
+
await expect(cleanCommand({})).rejects.toThrow("No cleanup targets specified");
|
|
94
79
|
});
|
|
95
80
|
});
|
|
96
81
|
|
|
@@ -116,7 +101,7 @@ describe("--all", () => {
|
|
|
116
101
|
// Verify DB exists
|
|
117
102
|
expect(await Bun.file(mailDbPath).exists()).toBe(true);
|
|
118
103
|
|
|
119
|
-
await cleanCommand(
|
|
104
|
+
await cleanCommand({ all: true });
|
|
120
105
|
|
|
121
106
|
// DB should be gone
|
|
122
107
|
expect(await Bun.file(mailDbPath).exists()).toBe(false);
|
|
@@ -128,7 +113,7 @@ describe("--all", () => {
|
|
|
128
113
|
const store = createMetricsStore(metricsDbPath);
|
|
129
114
|
store.recordSession({
|
|
130
115
|
agentName: "test-agent",
|
|
131
|
-
|
|
116
|
+
taskId: "task-1",
|
|
132
117
|
capability: "builder",
|
|
133
118
|
startedAt: new Date().toISOString(),
|
|
134
119
|
completedAt: null,
|
|
@@ -148,7 +133,7 @@ describe("--all", () => {
|
|
|
148
133
|
|
|
149
134
|
expect(await Bun.file(metricsDbPath).exists()).toBe(true);
|
|
150
135
|
|
|
151
|
-
await cleanCommand(
|
|
136
|
+
await cleanCommand({ all: true });
|
|
152
137
|
|
|
153
138
|
expect(await Bun.file(metricsDbPath).exists()).toBe(false);
|
|
154
139
|
expect(stdoutOutput).toContain("Wiped metrics.db");
|
|
@@ -163,7 +148,7 @@ describe("--all", () => {
|
|
|
163
148
|
capability: "builder",
|
|
164
149
|
worktreePath: "/tmp/wt",
|
|
165
150
|
branchName: "overstory/test/task",
|
|
166
|
-
|
|
151
|
+
taskId: "task-1",
|
|
167
152
|
tmuxSession: "overstory-test-agent",
|
|
168
153
|
state: "completed",
|
|
169
154
|
pid: 12345,
|
|
@@ -180,7 +165,7 @@ describe("--all", () => {
|
|
|
180
165
|
const sessionsDbPath = join(overstoryDir, "sessions.db");
|
|
181
166
|
expect(await Bun.file(sessionsDbPath).exists()).toBe(true);
|
|
182
167
|
|
|
183
|
-
await cleanCommand(
|
|
168
|
+
await cleanCommand({ all: true });
|
|
184
169
|
|
|
185
170
|
expect(await Bun.file(sessionsDbPath).exists()).toBe(false);
|
|
186
171
|
expect(stdoutOutput).toContain("Wiped sessions.db");
|
|
@@ -192,13 +177,13 @@ describe("--all", () => {
|
|
|
192
177
|
const queue = createMergeQueue(queuePath);
|
|
193
178
|
queue.enqueue({
|
|
194
179
|
branchName: "test-branch",
|
|
195
|
-
|
|
180
|
+
taskId: "beads-test",
|
|
196
181
|
agentName: "test",
|
|
197
182
|
filesModified: ["src/test.ts"],
|
|
198
183
|
});
|
|
199
184
|
queue.close();
|
|
200
185
|
|
|
201
|
-
await cleanCommand(
|
|
186
|
+
await cleanCommand({ all: true });
|
|
202
187
|
|
|
203
188
|
expect(await Bun.file(queuePath).exists()).toBe(false);
|
|
204
189
|
expect(stdoutOutput).toContain("Wiped merge-queue.db");
|
|
@@ -209,7 +194,7 @@ describe("--all", () => {
|
|
|
209
194
|
await mkdir(join(logsDir, "agent-a", "2026-01-01"), { recursive: true });
|
|
210
195
|
await writeFile(join(logsDir, "agent-a", "2026-01-01", "session.log"), "log data");
|
|
211
196
|
|
|
212
|
-
await cleanCommand(
|
|
197
|
+
await cleanCommand({ all: true });
|
|
213
198
|
|
|
214
199
|
const entries = await readdir(logsDir);
|
|
215
200
|
expect(entries).toHaveLength(0);
|
|
@@ -221,7 +206,7 @@ describe("--all", () => {
|
|
|
221
206
|
await mkdir(join(agentsDir, "test-agent"), { recursive: true });
|
|
222
207
|
await writeFile(join(agentsDir, "test-agent", "identity.yaml"), "name: test-agent");
|
|
223
208
|
|
|
224
|
-
await cleanCommand(
|
|
209
|
+
await cleanCommand({ all: true });
|
|
225
210
|
|
|
226
211
|
const entries = await readdir(agentsDir);
|
|
227
212
|
expect(entries).toHaveLength(0);
|
|
@@ -232,7 +217,7 @@ describe("--all", () => {
|
|
|
232
217
|
const specsDir = join(overstoryDir, "specs");
|
|
233
218
|
await writeFile(join(specsDir, "task-123.md"), "# Spec");
|
|
234
219
|
|
|
235
|
-
await cleanCommand(
|
|
220
|
+
await cleanCommand({ all: true });
|
|
236
221
|
|
|
237
222
|
const entries = await readdir(specsDir);
|
|
238
223
|
expect(entries).toHaveLength(0);
|
|
@@ -243,7 +228,7 @@ describe("--all", () => {
|
|
|
243
228
|
const nudgePath = join(overstoryDir, "nudge-state.json");
|
|
244
229
|
await Bun.write(nudgePath, "{}");
|
|
245
230
|
|
|
246
|
-
await cleanCommand(
|
|
231
|
+
await cleanCommand({ all: true });
|
|
247
232
|
|
|
248
233
|
expect(await Bun.file(nudgePath).exists()).toBe(false);
|
|
249
234
|
expect(stdoutOutput).toContain("Cleared nudge-state.json");
|
|
@@ -253,7 +238,7 @@ describe("--all", () => {
|
|
|
253
238
|
const currentRunPath = join(overstoryDir, "current-run.txt");
|
|
254
239
|
await Bun.write(currentRunPath, "run-2026-02-13T10-00-00-000Z");
|
|
255
240
|
|
|
256
|
-
await cleanCommand(
|
|
241
|
+
await cleanCommand({ all: true });
|
|
257
242
|
|
|
258
243
|
expect(await Bun.file(currentRunPath).exists()).toBe(false);
|
|
259
244
|
expect(stdoutOutput).toContain("Cleared current-run.txt");
|
|
@@ -261,7 +246,7 @@ describe("--all", () => {
|
|
|
261
246
|
|
|
262
247
|
test("handles missing current-run.txt gracefully", async () => {
|
|
263
248
|
// current-run.txt does not exist — should not error
|
|
264
|
-
await cleanCommand(
|
|
249
|
+
await cleanCommand({ all: true });
|
|
265
250
|
expect(stdoutOutput).not.toContain("Cleared current-run.txt");
|
|
266
251
|
});
|
|
267
252
|
});
|
|
@@ -288,7 +273,7 @@ describe("individual flags", () => {
|
|
|
288
273
|
const sessionsPath = join(overstoryDir, "sessions.json");
|
|
289
274
|
await Bun.write(sessionsPath, '[{"id":"s1"}]\n');
|
|
290
275
|
|
|
291
|
-
await cleanCommand(
|
|
276
|
+
await cleanCommand({ mail: true });
|
|
292
277
|
|
|
293
278
|
// Mail gone
|
|
294
279
|
expect(await Bun.file(mailDbPath).exists()).toBe(false);
|
|
@@ -307,7 +292,7 @@ describe("individual flags", () => {
|
|
|
307
292
|
capability: "builder",
|
|
308
293
|
worktreePath: "/tmp/wt",
|
|
309
294
|
branchName: "overstory/test/task",
|
|
310
|
-
|
|
295
|
+
taskId: "task-1",
|
|
311
296
|
tmuxSession: "overstory-test-agent",
|
|
312
297
|
state: "completed",
|
|
313
298
|
pid: 12345,
|
|
@@ -324,7 +309,7 @@ describe("individual flags", () => {
|
|
|
324
309
|
// Create a spec file that should survive
|
|
325
310
|
await writeFile(join(overstoryDir, "specs", "task.md"), "spec");
|
|
326
311
|
|
|
327
|
-
await cleanCommand(
|
|
312
|
+
await cleanCommand({ sessions: true });
|
|
328
313
|
|
|
329
314
|
// sessions.db should be gone
|
|
330
315
|
expect(await Bun.file(sessionsDbPath).exists()).toBe(false);
|
|
@@ -341,7 +326,7 @@ describe("individual flags", () => {
|
|
|
341
326
|
|
|
342
327
|
await writeFile(join(overstoryDir, "specs", "task.md"), "spec");
|
|
343
328
|
|
|
344
|
-
await cleanCommand(
|
|
329
|
+
await cleanCommand({ logs: true });
|
|
345
330
|
|
|
346
331
|
const logEntries = await readdir(logsDir);
|
|
347
332
|
expect(logEntries).toHaveLength(0);
|
|
@@ -356,7 +341,7 @@ describe("individual flags", () => {
|
|
|
356
341
|
|
|
357
342
|
describe("idempotent", () => {
|
|
358
343
|
test("running --all when nothing exists does not error", async () => {
|
|
359
|
-
await cleanCommand(
|
|
344
|
+
await cleanCommand({ all: true });
|
|
360
345
|
expect(stdoutOutput).toContain("Nothing to clean");
|
|
361
346
|
});
|
|
362
347
|
|
|
@@ -366,9 +351,9 @@ describe("idempotent", () => {
|
|
|
366
351
|
const store = createMailStore(mailDbPath);
|
|
367
352
|
store.close();
|
|
368
353
|
|
|
369
|
-
await cleanCommand(
|
|
354
|
+
await cleanCommand({ all: true });
|
|
370
355
|
stdoutOutput = "";
|
|
371
|
-
await cleanCommand(
|
|
356
|
+
await cleanCommand({ all: true });
|
|
372
357
|
expect(stdoutOutput).toContain("Nothing to clean");
|
|
373
358
|
});
|
|
374
359
|
});
|
|
@@ -391,7 +376,7 @@ describe("JSON output", () => {
|
|
|
391
376
|
});
|
|
392
377
|
store.close();
|
|
393
378
|
|
|
394
|
-
await cleanCommand(
|
|
379
|
+
await cleanCommand({ all: true, json: true });
|
|
395
380
|
|
|
396
381
|
const result = JSON.parse(stdoutOutput);
|
|
397
382
|
expect(result).toHaveProperty("tmuxKilled");
|
|
@@ -402,7 +387,7 @@ describe("JSON output", () => {
|
|
|
402
387
|
});
|
|
403
388
|
|
|
404
389
|
test("--json includes sessionEndEventsLogged field", async () => {
|
|
405
|
-
await cleanCommand(
|
|
390
|
+
await cleanCommand({ all: true, json: true });
|
|
406
391
|
const result = JSON.parse(stdoutOutput);
|
|
407
392
|
expect(result).toHaveProperty("sessionEndEventsLogged");
|
|
408
393
|
});
|
|
@@ -411,7 +396,7 @@ describe("JSON output", () => {
|
|
|
411
396
|
const currentRunPath = join(overstoryDir, "current-run.txt");
|
|
412
397
|
await Bun.write(currentRunPath, "run-2026-02-13T10-00-00-000Z");
|
|
413
398
|
|
|
414
|
-
await cleanCommand(
|
|
399
|
+
await cleanCommand({ all: true, json: true });
|
|
415
400
|
const result = JSON.parse(stdoutOutput);
|
|
416
401
|
expect(result).toHaveProperty("currentRunCleared");
|
|
417
402
|
expect(result.currentRunCleared).toBe(true);
|
|
@@ -428,7 +413,7 @@ describe("synthetic session-end events", () => {
|
|
|
428
413
|
capability: "builder",
|
|
429
414
|
worktreePath: "/tmp/wt",
|
|
430
415
|
branchName: "overstory/test-builder/task-1",
|
|
431
|
-
|
|
416
|
+
taskId: "task-1",
|
|
432
417
|
tmuxSession: "overstory-test-builder",
|
|
433
418
|
state: "working",
|
|
434
419
|
pid: 12345,
|
|
@@ -449,7 +434,7 @@ describe("synthetic session-end events", () => {
|
|
|
449
434
|
const sessions = [makeSession({ agentName: "builder-a", state: "working" })];
|
|
450
435
|
await Bun.write(sessionsPath, JSON.stringify(sessions));
|
|
451
436
|
|
|
452
|
-
await cleanCommand(
|
|
437
|
+
await cleanCommand({ all: true });
|
|
453
438
|
|
|
454
439
|
// Verify event was written to events.db
|
|
455
440
|
const eventsDbPath = join(overstoryDir, "events.db");
|
|
@@ -478,7 +463,7 @@ describe("synthetic session-end events", () => {
|
|
|
478
463
|
];
|
|
479
464
|
await Bun.write(sessionsPath, JSON.stringify(sessions));
|
|
480
465
|
|
|
481
|
-
await cleanCommand(
|
|
466
|
+
await cleanCommand({ all: true });
|
|
482
467
|
|
|
483
468
|
const eventsDbPath = join(overstoryDir, "events.db");
|
|
484
469
|
const eventStore = createEventStore(eventsDbPath);
|
|
@@ -501,7 +486,7 @@ describe("synthetic session-end events", () => {
|
|
|
501
486
|
];
|
|
502
487
|
await Bun.write(sessionsPath, JSON.stringify(sessions));
|
|
503
488
|
|
|
504
|
-
await cleanCommand(
|
|
489
|
+
await cleanCommand({ all: true });
|
|
505
490
|
|
|
506
491
|
// events.db may not even be created if there are no events to log
|
|
507
492
|
const eventsDbPath = join(overstoryDir, "events.db");
|
|
@@ -520,7 +505,7 @@ describe("synthetic session-end events", () => {
|
|
|
520
505
|
const sessions = [makeSession({ agentName: "wt-agent", state: "working" })];
|
|
521
506
|
await Bun.write(sessionsPath, JSON.stringify(sessions));
|
|
522
507
|
|
|
523
|
-
await cleanCommand(
|
|
508
|
+
await cleanCommand({ worktrees: true });
|
|
524
509
|
|
|
525
510
|
const eventsDbPath = join(overstoryDir, "events.db");
|
|
526
511
|
const eventStore = createEventStore(eventsDbPath);
|
|
@@ -543,7 +528,7 @@ describe("synthetic session-end events", () => {
|
|
|
543
528
|
];
|
|
544
529
|
await Bun.write(sessionsPath, JSON.stringify(sessions));
|
|
545
530
|
|
|
546
|
-
await cleanCommand(
|
|
531
|
+
await cleanCommand({ all: true });
|
|
547
532
|
|
|
548
533
|
const eventsDbPath = join(overstoryDir, "events.db");
|
|
549
534
|
const eventStore = createEventStore(eventsDbPath);
|
|
@@ -558,7 +543,7 @@ describe("synthetic session-end events", () => {
|
|
|
558
543
|
|
|
559
544
|
test("handles missing sessions.json gracefully", async () => {
|
|
560
545
|
// No sessions.json file — should not error
|
|
561
|
-
await cleanCommand(
|
|
546
|
+
await cleanCommand({ all: true });
|
|
562
547
|
// Just verify it didn't crash
|
|
563
548
|
expect(stdoutOutput).toBeDefined();
|
|
564
549
|
});
|
|
@@ -580,7 +565,7 @@ describe("mulch health checks", () => {
|
|
|
580
565
|
`{"id":"mx-1","type":"convention","description":"Test record 1","recorded_at":"2026-01-01T00:00:00Z"}\n`,
|
|
581
566
|
);
|
|
582
567
|
|
|
583
|
-
await cleanCommand(
|
|
568
|
+
await cleanCommand({ all: true });
|
|
584
569
|
|
|
585
570
|
// Mulch health checks should have run (might show warnings or might be clean)
|
|
586
571
|
// The output should not error, and if there are no issues, it's fine
|
|
@@ -589,7 +574,7 @@ describe("mulch health checks", () => {
|
|
|
589
574
|
|
|
590
575
|
test("handles missing .mulch directory gracefully", async () => {
|
|
591
576
|
// No .mulch directory — should not error
|
|
592
|
-
await cleanCommand(
|
|
577
|
+
await cleanCommand({ all: true });
|
|
593
578
|
expect(stdoutOutput).toBeDefined();
|
|
594
579
|
});
|
|
595
580
|
|
|
@@ -606,7 +591,7 @@ describe("mulch health checks", () => {
|
|
|
606
591
|
`{"id":"mx-1","type":"convention","description":"Test","recorded_at":"2026-01-01T00:00:00Z"}\n`,
|
|
607
592
|
);
|
|
608
593
|
|
|
609
|
-
await cleanCommand(
|
|
594
|
+
await cleanCommand({ all: true, json: true });
|
|
610
595
|
|
|
611
596
|
const result = JSON.parse(stdoutOutput);
|
|
612
597
|
expect(result).toHaveProperty("mulchHealth");
|
|
@@ -632,7 +617,7 @@ describe("mulch health checks", () => {
|
|
|
632
617
|
const store = createMailStore(mailDbPath);
|
|
633
618
|
store.close();
|
|
634
619
|
|
|
635
|
-
await cleanCommand(
|
|
620
|
+
await cleanCommand({ mail: true, json: true });
|
|
636
621
|
|
|
637
622
|
const result = JSON.parse(stdoutOutput);
|
|
638
623
|
// mulchHealth should be null because we didn't use --all
|
|
@@ -661,7 +646,7 @@ describe("mulch health checks", () => {
|
|
|
661
646
|
return; // Skip this test if mulch setup failed
|
|
662
647
|
}
|
|
663
648
|
|
|
664
|
-
await cleanCommand(
|
|
649
|
+
await cleanCommand({ all: true });
|
|
665
650
|
|
|
666
651
|
// Should show warning about domain near limit (if mulch status worked)
|
|
667
652
|
// The exact output depends on whether mulch CLI is available in the test environment
|
package/src/commands/clean.ts
CHANGED
|
@@ -31,8 +31,17 @@ import type { AgentSession, MulchDoctorResult, MulchPruneResult, MulchStatus } f
|
|
|
31
31
|
import { listWorktrees, removeWorktree } from "../worktree/manager.ts";
|
|
32
32
|
import { killSession, listSessions } from "../worktree/tmux.ts";
|
|
33
33
|
|
|
34
|
-
|
|
35
|
-
|
|
34
|
+
export interface CleanOptions {
|
|
35
|
+
all?: boolean;
|
|
36
|
+
mail?: boolean;
|
|
37
|
+
sessions?: boolean;
|
|
38
|
+
metrics?: boolean;
|
|
39
|
+
logs?: boolean;
|
|
40
|
+
worktrees?: boolean;
|
|
41
|
+
branches?: boolean;
|
|
42
|
+
agents?: boolean;
|
|
43
|
+
specs?: boolean;
|
|
44
|
+
json?: boolean;
|
|
36
45
|
}
|
|
37
46
|
|
|
38
47
|
/**
|
|
@@ -384,53 +393,23 @@ async function checkMulchHealth(repoRoot: string): Promise<{
|
|
|
384
393
|
}
|
|
385
394
|
}
|
|
386
395
|
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
--help, -h Show this help
|
|
405
|
-
|
|
406
|
-
When --all is passed, ALL of the above are executed in safe order:
|
|
407
|
-
0. Run mulch health checks (informational, non-destructive):
|
|
408
|
-
- Check domains approaching governance limits (warn threshold: 400 records)
|
|
409
|
-
- Run mulch prune --dry-run (report stale record counts)
|
|
410
|
-
- Run mulch doctor (report health issues)
|
|
411
|
-
1. Kill all overstory tmux sessions (processes first)
|
|
412
|
-
2. Remove all worktrees
|
|
413
|
-
3. Delete orphaned branch refs
|
|
414
|
-
4. Wipe mail.db, metrics.db, sessions.db, merge-queue.db
|
|
415
|
-
5. Clear logs, agents, specs, nudge state`;
|
|
416
|
-
|
|
417
|
-
export async function cleanCommand(args: string[]): Promise<void> {
|
|
418
|
-
if (hasFlag(args, "--help") || hasFlag(args, "-h")) {
|
|
419
|
-
process.stdout.write(`${CLEAN_HELP}\n`);
|
|
420
|
-
return;
|
|
421
|
-
}
|
|
422
|
-
|
|
423
|
-
const json = hasFlag(args, "--json");
|
|
424
|
-
const all = hasFlag(args, "--all");
|
|
425
|
-
|
|
426
|
-
const doWorktrees = all || hasFlag(args, "--worktrees");
|
|
427
|
-
const doBranches = all || hasFlag(args, "--branches");
|
|
428
|
-
const doMail = all || hasFlag(args, "--mail");
|
|
429
|
-
const doSessions = all || hasFlag(args, "--sessions");
|
|
430
|
-
const doMetrics = all || hasFlag(args, "--metrics");
|
|
431
|
-
const doLogs = all || hasFlag(args, "--logs");
|
|
432
|
-
const doAgents = all || hasFlag(args, "--agents");
|
|
433
|
-
const doSpecs = all || hasFlag(args, "--specs");
|
|
396
|
+
/**
|
|
397
|
+
* Entry point for `overstory clean [flags]`.
|
|
398
|
+
*
|
|
399
|
+
* @param opts - Command options
|
|
400
|
+
*/
|
|
401
|
+
export async function cleanCommand(opts: CleanOptions): Promise<void> {
|
|
402
|
+
const json = opts.json ?? false;
|
|
403
|
+
const all = opts.all ?? false;
|
|
404
|
+
|
|
405
|
+
const doWorktrees = all || (opts.worktrees ?? false);
|
|
406
|
+
const doBranches = all || (opts.branches ?? false);
|
|
407
|
+
const doMail = all || (opts.mail ?? false);
|
|
408
|
+
const doSessions = all || (opts.sessions ?? false);
|
|
409
|
+
const doMetrics = all || (opts.metrics ?? false);
|
|
410
|
+
const doLogs = all || (opts.logs ?? false);
|
|
411
|
+
const doAgents = all || (opts.agents ?? false);
|
|
412
|
+
const doSpecs = all || (opts.specs ?? false);
|
|
434
413
|
|
|
435
414
|
const anySelected =
|
|
436
415
|
doWorktrees || doBranches || doMail || doSessions || doMetrics || doLogs || doAgents || doSpecs;
|
|
@@ -4,6 +4,8 @@
|
|
|
4
4
|
* Generates completion scripts for bash, zsh, and fish shells.
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
+
import { Command } from "commander";
|
|
8
|
+
|
|
7
9
|
interface FlagDef {
|
|
8
10
|
name: string;
|
|
9
11
|
desc: string;
|
|
@@ -856,6 +858,18 @@ export function generateFish(): string {
|
|
|
856
858
|
return lines.join("\n");
|
|
857
859
|
}
|
|
858
860
|
|
|
861
|
+
/**
|
|
862
|
+
* Create the Commander command for `overstory completions`.
|
|
863
|
+
*/
|
|
864
|
+
export function createCompletionsCommand(): Command {
|
|
865
|
+
return new Command("completions")
|
|
866
|
+
.description("Generate shell completions")
|
|
867
|
+
.argument("<shell>", "Shell to generate completions for (bash, zsh, fish)")
|
|
868
|
+
.action((shell: string) => {
|
|
869
|
+
completionsCommand([shell]);
|
|
870
|
+
});
|
|
871
|
+
}
|
|
872
|
+
|
|
859
873
|
export function completionsCommand(args: string[]): void {
|
|
860
874
|
const shell = args[0];
|
|
861
875
|
|