@os-eco/overstory-cli 0.6.4 → 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 +4 -4
- package/package.json +1 -1
- package/src/agents/checkpoint.test.ts +2 -2
- package/src/agents/hooks-deployer.test.ts +37 -0
- package/src/agents/hooks-deployer.ts +15 -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/overlay.test.ts +9 -9
- package/src/agents/overlay.ts +4 -4
- package/src/commands/agents.test.ts +5 -5
- package/src/commands/agents.ts +3 -3
- package/src/commands/clean.test.ts +5 -5
- package/src/commands/coordinator.test.ts +2 -2
- package/src/commands/coordinator.ts +1 -1
- package/src/commands/costs.test.ts +45 -45
- package/src/commands/dashboard.ts +3 -3
- package/src/commands/inspect.test.ts +16 -16
- package/src/commands/inspect.ts +1 -1
- package/src/commands/log.test.ts +21 -21
- package/src/commands/log.ts +7 -7
- package/src/commands/mail.test.ts +5 -5
- package/src/commands/merge.test.ts +8 -8
- package/src/commands/merge.ts +8 -8
- package/src/commands/metrics.test.ts +6 -6
- package/src/commands/metrics.ts +1 -1
- package/src/commands/monitor.ts +1 -1
- package/src/commands/nudge.test.ts +1 -1
- package/src/commands/prime.test.ts +4 -4
- package/src/commands/prime.ts +6 -6
- package/src/commands/run.test.ts +1 -1
- package/src/commands/sling.test.ts +5 -5
- package/src/commands/sling.ts +13 -10
- package/src/commands/spec.test.ts +2 -2
- package/src/commands/spec.ts +8 -8
- package/src/commands/status.test.ts +97 -1
- package/src/commands/status.ts +17 -16
- package/src/commands/stop.test.ts +1 -1
- package/src/commands/supervisor.test.ts +9 -9
- package/src/commands/supervisor.ts +11 -11
- package/src/commands/trace.test.ts +6 -6
- package/src/commands/trace.ts +6 -6
- package/src/commands/worktree.test.ts +205 -29
- package/src/commands/worktree.ts +47 -9
- package/src/doctor/consistency.test.ts +14 -14
- package/src/doctor/merge-queue.test.ts +4 -4
- package/src/e2e/init-sling-lifecycle.test.ts +2 -2
- package/src/errors.ts +1 -1
- package/src/index.ts +3 -3
- 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 +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/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
|
@@ -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,
|
|
@@ -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$/);
|
|
@@ -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,
|
|
@@ -22,7 +22,7 @@ import { costsCommand } from "./costs.ts";
|
|
|
22
22
|
function makeMetrics(overrides: Partial<SessionMetrics> = {}): SessionMetrics {
|
|
23
23
|
return {
|
|
24
24
|
agentName: "builder-1",
|
|
25
|
-
|
|
25
|
+
taskId: "task-001",
|
|
26
26
|
capability: "builder",
|
|
27
27
|
startedAt: new Date().toISOString(),
|
|
28
28
|
completedAt: new Date().toISOString(),
|
|
@@ -142,8 +142,8 @@ describe("costsCommand", () => {
|
|
|
142
142
|
test("outputs valid JSON array with sessions", async () => {
|
|
143
143
|
const dbPath = join(tempDir, ".overstory", "metrics.db");
|
|
144
144
|
const store = createMetricsStore(dbPath);
|
|
145
|
-
store.recordSession(makeMetrics({ agentName: "builder-1",
|
|
146
|
-
store.recordSession(makeMetrics({ agentName: "scout-1",
|
|
145
|
+
store.recordSession(makeMetrics({ agentName: "builder-1", taskId: "t1" }));
|
|
146
|
+
store.recordSession(makeMetrics({ agentName: "scout-1", taskId: "t2", capability: "scout" }));
|
|
147
147
|
store.close();
|
|
148
148
|
|
|
149
149
|
await costsCommand(["--json"]);
|
|
@@ -160,7 +160,7 @@ describe("costsCommand", () => {
|
|
|
160
160
|
store.recordSession(
|
|
161
161
|
makeMetrics({
|
|
162
162
|
agentName: "builder-1",
|
|
163
|
-
|
|
163
|
+
taskId: "t1",
|
|
164
164
|
inputTokens: 100,
|
|
165
165
|
outputTokens: 50,
|
|
166
166
|
cacheReadTokens: 30,
|
|
@@ -187,7 +187,7 @@ describe("costsCommand", () => {
|
|
|
187
187
|
test("JSON output returns empty array when no sessions match", async () => {
|
|
188
188
|
const dbPath = join(tempDir, ".overstory", "metrics.db");
|
|
189
189
|
const store = createMetricsStore(dbPath);
|
|
190
|
-
store.recordSession(makeMetrics({ agentName: "builder-1",
|
|
190
|
+
store.recordSession(makeMetrics({ agentName: "builder-1", taskId: "t1" }));
|
|
191
191
|
store.close();
|
|
192
192
|
|
|
193
193
|
await costsCommand(["--json", "--agent", "nonexistent"]);
|
|
@@ -203,7 +203,7 @@ describe("costsCommand", () => {
|
|
|
203
203
|
store.recordSession(
|
|
204
204
|
makeMetrics({
|
|
205
205
|
agentName: "builder-1",
|
|
206
|
-
|
|
206
|
+
taskId: "t1",
|
|
207
207
|
capability: "builder",
|
|
208
208
|
inputTokens: 100,
|
|
209
209
|
}),
|
|
@@ -211,7 +211,7 @@ describe("costsCommand", () => {
|
|
|
211
211
|
store.recordSession(
|
|
212
212
|
makeMetrics({
|
|
213
213
|
agentName: "scout-1",
|
|
214
|
-
|
|
214
|
+
taskId: "t2",
|
|
215
215
|
capability: "scout",
|
|
216
216
|
inputTokens: 50,
|
|
217
217
|
}),
|
|
@@ -238,7 +238,7 @@ describe("costsCommand", () => {
|
|
|
238
238
|
test("shows Cost Summary header", async () => {
|
|
239
239
|
const dbPath = join(tempDir, ".overstory", "metrics.db");
|
|
240
240
|
const store = createMetricsStore(dbPath);
|
|
241
|
-
store.recordSession(makeMetrics({ agentName: "builder-1",
|
|
241
|
+
store.recordSession(makeMetrics({ agentName: "builder-1", taskId: "t1" }));
|
|
242
242
|
store.close();
|
|
243
243
|
|
|
244
244
|
await costsCommand([]);
|
|
@@ -250,7 +250,7 @@ describe("costsCommand", () => {
|
|
|
250
250
|
test("shows column headers", async () => {
|
|
251
251
|
const dbPath = join(tempDir, ".overstory", "metrics.db");
|
|
252
252
|
const store = createMetricsStore(dbPath);
|
|
253
|
-
store.recordSession(makeMetrics({ agentName: "builder-1",
|
|
253
|
+
store.recordSession(makeMetrics({ agentName: "builder-1", taskId: "t1" }));
|
|
254
254
|
store.close();
|
|
255
255
|
|
|
256
256
|
await costsCommand([]);
|
|
@@ -270,7 +270,7 @@ describe("costsCommand", () => {
|
|
|
270
270
|
store.recordSession(
|
|
271
271
|
makeMetrics({
|
|
272
272
|
agentName: "builder-1",
|
|
273
|
-
|
|
273
|
+
taskId: "t1",
|
|
274
274
|
capability: "builder",
|
|
275
275
|
}),
|
|
276
276
|
);
|
|
@@ -286,7 +286,7 @@ describe("costsCommand", () => {
|
|
|
286
286
|
test("shows separator line", async () => {
|
|
287
287
|
const dbPath = join(tempDir, ".overstory", "metrics.db");
|
|
288
288
|
const store = createMetricsStore(dbPath);
|
|
289
|
-
store.recordSession(makeMetrics({ agentName: "builder-1",
|
|
289
|
+
store.recordSession(makeMetrics({ agentName: "builder-1", taskId: "t1" }));
|
|
290
290
|
store.close();
|
|
291
291
|
|
|
292
292
|
await costsCommand([]);
|
|
@@ -298,7 +298,7 @@ describe("costsCommand", () => {
|
|
|
298
298
|
test("shows Total row", async () => {
|
|
299
299
|
const dbPath = join(tempDir, ".overstory", "metrics.db");
|
|
300
300
|
const store = createMetricsStore(dbPath);
|
|
301
|
-
store.recordSession(makeMetrics({ agentName: "builder-1",
|
|
301
|
+
store.recordSession(makeMetrics({ agentName: "builder-1", taskId: "t1" }));
|
|
302
302
|
store.close();
|
|
303
303
|
|
|
304
304
|
await costsCommand([]);
|
|
@@ -329,7 +329,7 @@ describe("costsCommand", () => {
|
|
|
329
329
|
store.recordSession(
|
|
330
330
|
makeMetrics({
|
|
331
331
|
agentName: "builder-1",
|
|
332
|
-
|
|
332
|
+
taskId: "t1",
|
|
333
333
|
inputTokens: 12345,
|
|
334
334
|
outputTokens: 5678,
|
|
335
335
|
}),
|
|
@@ -349,7 +349,7 @@ describe("costsCommand", () => {
|
|
|
349
349
|
store.recordSession(
|
|
350
350
|
makeMetrics({
|
|
351
351
|
agentName: "builder-1",
|
|
352
|
-
|
|
352
|
+
taskId: "t1",
|
|
353
353
|
estimatedCostUsd: 0.42,
|
|
354
354
|
}),
|
|
355
355
|
);
|
|
@@ -367,7 +367,7 @@ describe("costsCommand", () => {
|
|
|
367
367
|
store.recordSession(
|
|
368
368
|
makeMetrics({
|
|
369
369
|
agentName: "builder-1",
|
|
370
|
-
|
|
370
|
+
taskId: "t1",
|
|
371
371
|
inputTokens: 0,
|
|
372
372
|
outputTokens: 0,
|
|
373
373
|
cacheReadTokens: 0,
|
|
@@ -389,7 +389,7 @@ describe("costsCommand", () => {
|
|
|
389
389
|
store.recordSession(
|
|
390
390
|
makeMetrics({
|
|
391
391
|
agentName: "builder-1",
|
|
392
|
-
|
|
392
|
+
taskId: "t1",
|
|
393
393
|
estimatedCostUsd: null,
|
|
394
394
|
}),
|
|
395
395
|
);
|
|
@@ -408,8 +408,8 @@ describe("costsCommand", () => {
|
|
|
408
408
|
test("filters sessions by agent name", async () => {
|
|
409
409
|
const dbPath = join(tempDir, ".overstory", "metrics.db");
|
|
410
410
|
const store = createMetricsStore(dbPath);
|
|
411
|
-
store.recordSession(makeMetrics({ agentName: "builder-1",
|
|
412
|
-
store.recordSession(makeMetrics({ agentName: "scout-1",
|
|
411
|
+
store.recordSession(makeMetrics({ agentName: "builder-1", taskId: "t1", inputTokens: 100 }));
|
|
412
|
+
store.recordSession(makeMetrics({ agentName: "scout-1", taskId: "t2", inputTokens: 200 }));
|
|
413
413
|
store.close();
|
|
414
414
|
|
|
415
415
|
await costsCommand(["--json", "--agent", "builder-1"]);
|
|
@@ -423,7 +423,7 @@ describe("costsCommand", () => {
|
|
|
423
423
|
test("returns empty for non-existent agent", async () => {
|
|
424
424
|
const dbPath = join(tempDir, ".overstory", "metrics.db");
|
|
425
425
|
const store = createMetricsStore(dbPath);
|
|
426
|
-
store.recordSession(makeMetrics({ agentName: "builder-1",
|
|
426
|
+
store.recordSession(makeMetrics({ agentName: "builder-1", taskId: "t1" }));
|
|
427
427
|
store.close();
|
|
428
428
|
|
|
429
429
|
await costsCommand(["--json", "--agent", "nonexistent"]);
|
|
@@ -441,12 +441,12 @@ describe("costsCommand", () => {
|
|
|
441
441
|
const dbPath = join(tempDir, ".overstory", "metrics.db");
|
|
442
442
|
const store = createMetricsStore(dbPath);
|
|
443
443
|
store.recordSession(
|
|
444
|
-
makeMetrics({ agentName: "builder-1",
|
|
444
|
+
makeMetrics({ agentName: "builder-1", taskId: "task-001", runId: "run-2026-01-01" }),
|
|
445
445
|
);
|
|
446
446
|
store.recordSession(
|
|
447
447
|
makeMetrics({
|
|
448
448
|
agentName: "scout-1",
|
|
449
|
-
|
|
449
|
+
taskId: "task-002",
|
|
450
450
|
capability: "scout",
|
|
451
451
|
runId: "run-other",
|
|
452
452
|
}),
|
|
@@ -465,7 +465,7 @@ describe("costsCommand", () => {
|
|
|
465
465
|
const dbPath = join(tempDir, ".overstory", "metrics.db");
|
|
466
466
|
const store = createMetricsStore(dbPath);
|
|
467
467
|
store.recordSession(
|
|
468
|
-
makeMetrics({ agentName: "builder-1",
|
|
468
|
+
makeMetrics({ agentName: "builder-1", taskId: "t1", runId: "run-2026-01-01" }),
|
|
469
469
|
);
|
|
470
470
|
store.close();
|
|
471
471
|
|
|
@@ -484,7 +484,7 @@ describe("costsCommand", () => {
|
|
|
484
484
|
const dbPath = join(tempDir, ".overstory", "metrics.db");
|
|
485
485
|
const store = createMetricsStore(dbPath);
|
|
486
486
|
store.recordSession(
|
|
487
|
-
makeMetrics({ agentName: "builder-1",
|
|
487
|
+
makeMetrics({ agentName: "builder-1", taskId: "t1", capability: "builder" }),
|
|
488
488
|
);
|
|
489
489
|
store.close();
|
|
490
490
|
|
|
@@ -498,7 +498,7 @@ describe("costsCommand", () => {
|
|
|
498
498
|
const dbPath = join(tempDir, ".overstory", "metrics.db");
|
|
499
499
|
const store = createMetricsStore(dbPath);
|
|
500
500
|
store.recordSession(
|
|
501
|
-
makeMetrics({ agentName: "builder-1",
|
|
501
|
+
makeMetrics({ agentName: "builder-1", taskId: "t1", capability: "builder" }),
|
|
502
502
|
);
|
|
503
503
|
store.close();
|
|
504
504
|
|
|
@@ -514,7 +514,7 @@ describe("costsCommand", () => {
|
|
|
514
514
|
store.recordSession(
|
|
515
515
|
makeMetrics({
|
|
516
516
|
agentName: "builder-1",
|
|
517
|
-
|
|
517
|
+
taskId: "t1",
|
|
518
518
|
capability: "builder",
|
|
519
519
|
inputTokens: 1000,
|
|
520
520
|
}),
|
|
@@ -522,7 +522,7 @@ describe("costsCommand", () => {
|
|
|
522
522
|
store.recordSession(
|
|
523
523
|
makeMetrics({
|
|
524
524
|
agentName: "builder-2",
|
|
525
|
-
|
|
525
|
+
taskId: "t2",
|
|
526
526
|
capability: "builder",
|
|
527
527
|
inputTokens: 2000,
|
|
528
528
|
}),
|
|
@@ -530,7 +530,7 @@ describe("costsCommand", () => {
|
|
|
530
530
|
store.recordSession(
|
|
531
531
|
makeMetrics({
|
|
532
532
|
agentName: "scout-1",
|
|
533
|
-
|
|
533
|
+
taskId: "t3",
|
|
534
534
|
capability: "scout",
|
|
535
535
|
inputTokens: 500,
|
|
536
536
|
}),
|
|
@@ -548,10 +548,10 @@ describe("costsCommand", () => {
|
|
|
548
548
|
test("shows correct session count per capability", async () => {
|
|
549
549
|
const dbPath = join(tempDir, ".overstory", "metrics.db");
|
|
550
550
|
const store = createMetricsStore(dbPath);
|
|
551
|
-
store.recordSession(makeMetrics({ agentName: "b1",
|
|
552
|
-
store.recordSession(makeMetrics({ agentName: "b2",
|
|
553
|
-
store.recordSession(makeMetrics({ agentName: "b3",
|
|
554
|
-
store.recordSession(makeMetrics({ agentName: "s1",
|
|
551
|
+
store.recordSession(makeMetrics({ agentName: "b1", taskId: "t1", capability: "builder" }));
|
|
552
|
+
store.recordSession(makeMetrics({ agentName: "b2", taskId: "t2", capability: "builder" }));
|
|
553
|
+
store.recordSession(makeMetrics({ agentName: "b3", taskId: "t3", capability: "builder" }));
|
|
554
|
+
store.recordSession(makeMetrics({ agentName: "s1", taskId: "t4", capability: "scout" }));
|
|
555
555
|
store.close();
|
|
556
556
|
|
|
557
557
|
await costsCommand(["--json", "--by-capability"]);
|
|
@@ -584,7 +584,7 @@ describe("costsCommand", () => {
|
|
|
584
584
|
const dbPath = join(tempDir, ".overstory", "metrics.db");
|
|
585
585
|
const store = createMetricsStore(dbPath);
|
|
586
586
|
for (let i = 0; i < 10; i++) {
|
|
587
|
-
store.recordSession(makeMetrics({ agentName: `agent-${i}`,
|
|
587
|
+
store.recordSession(makeMetrics({ agentName: `agent-${i}`, taskId: `t-${i}` }));
|
|
588
588
|
}
|
|
589
589
|
store.close();
|
|
590
590
|
|
|
@@ -599,7 +599,7 @@ describe("costsCommand", () => {
|
|
|
599
599
|
const dbPath = join(tempDir, ".overstory", "metrics.db");
|
|
600
600
|
const store = createMetricsStore(dbPath);
|
|
601
601
|
for (let i = 0; i < 25; i++) {
|
|
602
|
-
store.recordSession(makeMetrics({ agentName: `agent-${i}`,
|
|
602
|
+
store.recordSession(makeMetrics({ agentName: `agent-${i}`, taskId: `t-${i}` }));
|
|
603
603
|
}
|
|
604
604
|
store.close();
|
|
605
605
|
|
|
@@ -620,7 +620,7 @@ describe("costsCommand", () => {
|
|
|
620
620
|
store.recordSession(
|
|
621
621
|
makeMetrics({
|
|
622
622
|
agentName: "builder-1",
|
|
623
|
-
|
|
623
|
+
taskId: "t1",
|
|
624
624
|
inputTokens: 0,
|
|
625
625
|
outputTokens: 0,
|
|
626
626
|
cacheReadTokens: 0,
|
|
@@ -644,7 +644,7 @@ describe("costsCommand", () => {
|
|
|
644
644
|
store.recordSession(
|
|
645
645
|
makeMetrics({
|
|
646
646
|
agentName: "builder-1",
|
|
647
|
-
|
|
647
|
+
taskId: "t1",
|
|
648
648
|
estimatedCostUsd: null,
|
|
649
649
|
}),
|
|
650
650
|
);
|
|
@@ -664,7 +664,7 @@ describe("costsCommand", () => {
|
|
|
664
664
|
store.recordSession(
|
|
665
665
|
makeMetrics({
|
|
666
666
|
agentName: "builder-1",
|
|
667
|
-
|
|
667
|
+
taskId: "t1",
|
|
668
668
|
cacheReadTokens: 8000,
|
|
669
669
|
cacheCreationTokens: 901,
|
|
670
670
|
}),
|
|
@@ -684,7 +684,7 @@ describe("costsCommand", () => {
|
|
|
684
684
|
store.recordSession(
|
|
685
685
|
makeMetrics({
|
|
686
686
|
agentName: "builder-1",
|
|
687
|
-
|
|
687
|
+
taskId: "t1",
|
|
688
688
|
inputTokens: 100,
|
|
689
689
|
outputTokens: 50,
|
|
690
690
|
estimatedCostUsd: 0.1,
|
|
@@ -693,7 +693,7 @@ describe("costsCommand", () => {
|
|
|
693
693
|
store.recordSession(
|
|
694
694
|
makeMetrics({
|
|
695
695
|
agentName: "scout-1",
|
|
696
|
-
|
|
696
|
+
taskId: "t2",
|
|
697
697
|
capability: "scout",
|
|
698
698
|
inputTokens: 200,
|
|
699
699
|
outputTokens: 100,
|
|
@@ -716,10 +716,10 @@ describe("costsCommand", () => {
|
|
|
716
716
|
const dbPath = join(tempDir, ".overstory", "metrics.db");
|
|
717
717
|
const store = createMetricsStore(dbPath);
|
|
718
718
|
store.recordSession(
|
|
719
|
-
makeMetrics({ agentName: "builder-1",
|
|
719
|
+
makeMetrics({ agentName: "builder-1", taskId: "t1", capability: "builder" }),
|
|
720
720
|
);
|
|
721
721
|
store.recordSession(
|
|
722
|
-
makeMetrics({ agentName: "builder-2",
|
|
722
|
+
makeMetrics({ agentName: "builder-2", taskId: "t2", capability: "builder" }),
|
|
723
723
|
);
|
|
724
724
|
store.close();
|
|
725
725
|
|
|
@@ -759,7 +759,7 @@ describe("costsCommand", () => {
|
|
|
759
759
|
capability: "builder",
|
|
760
760
|
worktreePath: "/tmp/wt1",
|
|
761
761
|
branchName: "feat/task1",
|
|
762
|
-
|
|
762
|
+
taskId: "task-001",
|
|
763
763
|
tmuxSession: "tmux-001",
|
|
764
764
|
state: "working",
|
|
765
765
|
pid: 12345,
|
|
@@ -815,7 +815,7 @@ describe("costsCommand", () => {
|
|
|
815
815
|
capability: "builder",
|
|
816
816
|
worktreePath: "/tmp/wt1",
|
|
817
817
|
branchName: "feat/task1",
|
|
818
|
-
|
|
818
|
+
taskId: "task-001",
|
|
819
819
|
tmuxSession: "tmux-001",
|
|
820
820
|
state: "working",
|
|
821
821
|
pid: 12345,
|
|
@@ -879,7 +879,7 @@ describe("costsCommand", () => {
|
|
|
879
879
|
capability: "builder",
|
|
880
880
|
worktreePath: "/tmp/wt1",
|
|
881
881
|
branchName: "feat/task1",
|
|
882
|
-
|
|
882
|
+
taskId: "task-001",
|
|
883
883
|
tmuxSession: "tmux-001",
|
|
884
884
|
state: "working",
|
|
885
885
|
pid: 12345,
|
|
@@ -897,7 +897,7 @@ describe("costsCommand", () => {
|
|
|
897
897
|
capability: "scout",
|
|
898
898
|
worktreePath: "/tmp/wt2",
|
|
899
899
|
branchName: "feat/task2",
|
|
900
|
-
|
|
900
|
+
taskId: "task-002",
|
|
901
901
|
tmuxSession: "tmux-002",
|
|
902
902
|
state: "working",
|
|
903
903
|
pid: 12346,
|
|
@@ -956,7 +956,7 @@ describe("costsCommand", () => {
|
|
|
956
956
|
capability: "builder",
|
|
957
957
|
worktreePath: "/tmp/wt1",
|
|
958
958
|
branchName: "feat/task1",
|
|
959
|
-
|
|
959
|
+
taskId: "task-001",
|
|
960
960
|
tmuxSession: "tmux-001",
|
|
961
961
|
state: "working",
|
|
962
962
|
pid: 12345,
|
|
@@ -470,7 +470,7 @@ function renderAgentPanel(
|
|
|
470
470
|
output += `${CURSOR.cursorTo(startRow, 1)}${headerLine}${headerPadding}${BOX.vertical}\n`;
|
|
471
471
|
|
|
472
472
|
// Column headers
|
|
473
|
-
const colHeaders = `${BOX.vertical} St Name Capability State
|
|
473
|
+
const colHeaders = `${BOX.vertical} St Name Capability State Task ID Duration Tmux ${BOX.vertical}`;
|
|
474
474
|
output += `${CURSOR.cursorTo(startRow + 1, 1)}${colHeaders}\n`;
|
|
475
475
|
|
|
476
476
|
// Separator
|
|
@@ -500,7 +500,7 @@ function renderAgentPanel(
|
|
|
500
500
|
const name = pad(truncate(agent.agentName, 15), 15);
|
|
501
501
|
const capability = pad(truncate(agent.capability, 12), 12);
|
|
502
502
|
const state = pad(agent.state, 10);
|
|
503
|
-
const
|
|
503
|
+
const taskId = pad(truncate(agent.taskId, 16), 16);
|
|
504
504
|
const endTime =
|
|
505
505
|
agent.state === "completed" || agent.state === "zombie"
|
|
506
506
|
? new Date(agent.lastActivity).getTime()
|
|
@@ -510,7 +510,7 @@ function renderAgentPanel(
|
|
|
510
510
|
const tmuxAlive = data.status.tmuxSessions.some((s) => s.name === agent.tmuxSession);
|
|
511
511
|
const tmuxDot = tmuxAlive ? color.green("●") : color.red("○");
|
|
512
512
|
|
|
513
|
-
const line = `${BOX.vertical} ${stateColor(icon)} ${name} ${capability} ${stateColor(state)} ${
|
|
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`;
|
|
515
515
|
}
|
|
516
516
|
|
|
@@ -39,7 +39,7 @@ function makeEvent(overrides: Partial<InsertEvent> = {}): InsertEvent {
|
|
|
39
39
|
function makeMetrics(overrides: Partial<SessionMetrics> = {}): SessionMetrics {
|
|
40
40
|
return {
|
|
41
41
|
agentName: "builder-1",
|
|
42
|
-
|
|
42
|
+
taskId: "overstory-001",
|
|
43
43
|
capability: "builder",
|
|
44
44
|
startedAt: new Date().toISOString(),
|
|
45
45
|
completedAt: null,
|
|
@@ -142,7 +142,7 @@ describe("inspectCommand", () => {
|
|
|
142
142
|
capability: "builder",
|
|
143
143
|
worktreePath: "/tmp/wt",
|
|
144
144
|
branchName: "overstory/builder-1/test",
|
|
145
|
-
|
|
145
|
+
taskId: "overstory-001",
|
|
146
146
|
tmuxSession: "overstory-test-builder-1",
|
|
147
147
|
state: "working",
|
|
148
148
|
pid: 12345,
|
|
@@ -174,7 +174,7 @@ describe("inspectCommand", () => {
|
|
|
174
174
|
capability: "builder",
|
|
175
175
|
worktreePath: "/tmp/wt",
|
|
176
176
|
branchName: "overstory/builder-1/test",
|
|
177
|
-
|
|
177
|
+
taskId: "overstory-001",
|
|
178
178
|
tmuxSession: "overstory-test-builder-1",
|
|
179
179
|
state: "working",
|
|
180
180
|
pid: 12345,
|
|
@@ -210,7 +210,7 @@ describe("inspectCommand", () => {
|
|
|
210
210
|
capability: "builder",
|
|
211
211
|
worktreePath: "/tmp/wt",
|
|
212
212
|
branchName: "overstory/builder-1/test",
|
|
213
|
-
|
|
213
|
+
taskId: "overstory-001",
|
|
214
214
|
tmuxSession: "overstory-test-builder-1",
|
|
215
215
|
state: "working",
|
|
216
216
|
pid: 12345,
|
|
@@ -229,7 +229,7 @@ describe("inspectCommand", () => {
|
|
|
229
229
|
expect(data.session.agentName).toBe("builder-1");
|
|
230
230
|
expect(data.session.capability).toBe("builder");
|
|
231
231
|
expect(data.session.state).toBe("working");
|
|
232
|
-
expect(data.session.
|
|
232
|
+
expect(data.session.taskId).toBe("overstory-001");
|
|
233
233
|
expect(data.timeSinceLastActivity).toBeGreaterThan(4000);
|
|
234
234
|
expect(data.timeSinceLastActivity).toBeLessThan(10000);
|
|
235
235
|
});
|
|
@@ -246,7 +246,7 @@ describe("inspectCommand", () => {
|
|
|
246
246
|
capability: "builder",
|
|
247
247
|
worktreePath: "/tmp/wt",
|
|
248
248
|
branchName: "overstory/builder-1/test",
|
|
249
|
-
|
|
249
|
+
taskId: "overstory-001",
|
|
250
250
|
tmuxSession: "overstory-test-builder-1",
|
|
251
251
|
state: "working",
|
|
252
252
|
pid: 12345,
|
|
@@ -285,7 +285,7 @@ describe("inspectCommand", () => {
|
|
|
285
285
|
capability: "builder",
|
|
286
286
|
worktreePath: "/tmp/wt",
|
|
287
287
|
branchName: "overstory/builder-1/test",
|
|
288
|
-
|
|
288
|
+
taskId: "overstory-001",
|
|
289
289
|
tmuxSession: "overstory-test-builder-1",
|
|
290
290
|
state: "working",
|
|
291
291
|
pid: 12345,
|
|
@@ -320,7 +320,7 @@ describe("inspectCommand", () => {
|
|
|
320
320
|
capability: "builder",
|
|
321
321
|
worktreePath: "/tmp/wt",
|
|
322
322
|
branchName: "overstory/builder-1/test",
|
|
323
|
-
|
|
323
|
+
taskId: "overstory-001",
|
|
324
324
|
tmuxSession: "overstory-test-builder-1",
|
|
325
325
|
state: "working",
|
|
326
326
|
pid: 12345,
|
|
@@ -355,7 +355,7 @@ describe("inspectCommand", () => {
|
|
|
355
355
|
capability: "builder",
|
|
356
356
|
worktreePath: "/tmp/wt",
|
|
357
357
|
branchName: "overstory/builder-1/test",
|
|
358
|
-
|
|
358
|
+
taskId: "overstory-001",
|
|
359
359
|
tmuxSession: "overstory-test-builder-1",
|
|
360
360
|
state: "working",
|
|
361
361
|
pid: 12345,
|
|
@@ -399,7 +399,7 @@ describe("inspectCommand", () => {
|
|
|
399
399
|
capability: "builder",
|
|
400
400
|
worktreePath: "/tmp/wt",
|
|
401
401
|
branchName: "overstory/builder-1/test",
|
|
402
|
-
|
|
402
|
+
taskId: "overstory-001",
|
|
403
403
|
tmuxSession: "overstory-test-builder-1",
|
|
404
404
|
state: "working",
|
|
405
405
|
pid: 12345,
|
|
@@ -442,7 +442,7 @@ describe("inspectCommand", () => {
|
|
|
442
442
|
capability: "builder",
|
|
443
443
|
worktreePath: "/tmp/wt",
|
|
444
444
|
branchName: "overstory/builder-1/test",
|
|
445
|
-
|
|
445
|
+
taskId: "overstory-001",
|
|
446
446
|
tmuxSession: "overstory-test-builder-1",
|
|
447
447
|
state: "working",
|
|
448
448
|
pid: 12345,
|
|
@@ -491,7 +491,7 @@ describe("inspectCommand", () => {
|
|
|
491
491
|
capability: "builder",
|
|
492
492
|
worktreePath: "/tmp/wt",
|
|
493
493
|
branchName: "overstory/builder-1/test",
|
|
494
|
-
|
|
494
|
+
taskId: "overstory-001",
|
|
495
495
|
tmuxSession: "overstory-test-builder-1",
|
|
496
496
|
state: "working",
|
|
497
497
|
pid: 12345,
|
|
@@ -528,7 +528,7 @@ describe("inspectCommand", () => {
|
|
|
528
528
|
capability: "builder",
|
|
529
529
|
worktreePath: "/tmp/wt",
|
|
530
530
|
branchName: "overstory/builder-1/test",
|
|
531
|
-
|
|
531
|
+
taskId: "overstory-001",
|
|
532
532
|
tmuxSession: "overstory-test-builder-1",
|
|
533
533
|
state: "working",
|
|
534
534
|
pid: 12345,
|
|
@@ -564,7 +564,7 @@ describe("inspectCommand", () => {
|
|
|
564
564
|
capability: "builder",
|
|
565
565
|
worktreePath: "/tmp/wt",
|
|
566
566
|
branchName: "overstory/builder-1/test",
|
|
567
|
-
|
|
567
|
+
taskId: "overstory-001",
|
|
568
568
|
tmuxSession: "overstory-test-builder-1",
|
|
569
569
|
state: "working",
|
|
570
570
|
pid: 12345,
|
|
@@ -601,7 +601,7 @@ describe("inspectCommand", () => {
|
|
|
601
601
|
capability: "builder",
|
|
602
602
|
worktreePath: "/tmp/wt",
|
|
603
603
|
branchName: "overstory/builder-1/test",
|
|
604
|
-
|
|
604
|
+
taskId: "overstory-001",
|
|
605
605
|
tmuxSession: "overstory-test-builder-1",
|
|
606
606
|
state: "working",
|
|
607
607
|
pid: 12345,
|
|
@@ -639,7 +639,7 @@ describe("inspectCommand", () => {
|
|
|
639
639
|
capability: "builder",
|
|
640
640
|
worktreePath: "/tmp/wt",
|
|
641
641
|
branchName: "overstory/builder-1/test",
|
|
642
|
-
|
|
642
|
+
taskId: "overstory-001",
|
|
643
643
|
tmuxSession: "overstory-test-builder-1",
|
|
644
644
|
state: "working",
|
|
645
645
|
pid: 12345,
|
package/src/commands/inspect.ts
CHANGED
|
@@ -259,7 +259,7 @@ export function printInspectData(data: InspectData): void {
|
|
|
259
259
|
const stateIcon = getStateIcon(session.state);
|
|
260
260
|
w(`${stateIcon} State: ${session.state}\n`);
|
|
261
261
|
w(`⏱ Last activity: ${formatDuration(data.timeSinceLastActivity)} ago\n`);
|
|
262
|
-
w(`🎯 Task: ${session.
|
|
262
|
+
w(`🎯 Task: ${session.taskId}\n`);
|
|
263
263
|
w(`🔧 Capability: ${session.capability}\n`);
|
|
264
264
|
w(`🌿 Branch: ${session.branchName}\n`);
|
|
265
265
|
if (session.parentAgent) {
|