gsd-pi 2.23.0 → 2.25.0
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 +2 -1
- package/dist/cli.js +12 -3
- package/dist/headless.d.ts +4 -0
- package/dist/headless.js +118 -10
- package/dist/help-text.js +22 -7
- package/dist/models-resolver.d.ts +0 -11
- package/dist/models-resolver.js +0 -15
- package/dist/resource-loader.d.ts +0 -1
- package/dist/resource-loader.js +64 -18
- package/dist/resources/GSD-WORKFLOW.md +12 -9
- package/dist/resources/extensions/bg-shell/overlay.ts +18 -17
- package/dist/resources/extensions/get-secrets-from-user.ts +5 -23
- package/dist/resources/extensions/gsd/activity-log.ts +5 -3
- package/dist/resources/extensions/gsd/auto-dispatch.ts +51 -2
- package/dist/resources/extensions/gsd/auto-prompts.ts +87 -0
- package/dist/resources/extensions/gsd/auto-recovery.ts +41 -2
- package/dist/resources/extensions/gsd/auto-worktree.ts +134 -4
- package/dist/resources/extensions/gsd/auto.ts +307 -77
- package/dist/resources/extensions/gsd/cache.ts +3 -1
- package/dist/resources/extensions/gsd/commands.ts +176 -10
- package/dist/resources/extensions/gsd/complexity.ts +1 -0
- package/dist/resources/extensions/gsd/dashboard-overlay.ts +38 -0
- package/dist/resources/extensions/gsd/doctor.ts +58 -11
- package/dist/resources/extensions/gsd/exit-command.ts +2 -2
- package/dist/resources/extensions/gsd/git-service.ts +74 -14
- package/dist/resources/extensions/gsd/gitignore.ts +1 -0
- package/dist/resources/extensions/gsd/gsd-db.ts +78 -1
- package/dist/resources/extensions/gsd/guided-flow.ts +109 -12
- package/dist/resources/extensions/gsd/index.ts +48 -2
- package/dist/resources/extensions/gsd/memory-extractor.ts +352 -0
- package/dist/resources/extensions/gsd/memory-store.ts +441 -0
- package/dist/resources/extensions/gsd/migrate/command.ts +2 -2
- package/dist/resources/extensions/gsd/parallel-eligibility.ts +233 -0
- package/dist/resources/extensions/gsd/parallel-merge.ts +156 -0
- package/dist/resources/extensions/gsd/parallel-orchestrator.ts +496 -0
- package/dist/resources/extensions/gsd/preferences.ts +65 -1
- package/dist/resources/extensions/gsd/prompts/complete-slice.md +1 -1
- package/dist/resources/extensions/gsd/prompts/discuss-headless.md +86 -0
- package/dist/resources/extensions/gsd/prompts/discuss.md +4 -4
- package/dist/resources/extensions/gsd/prompts/execute-task.md +1 -1
- package/dist/resources/extensions/gsd/prompts/guided-discuss-milestone.md +1 -1
- package/dist/resources/extensions/gsd/prompts/guided-discuss-slice.md +1 -1
- package/dist/resources/extensions/gsd/prompts/plan-slice.md +1 -1
- package/dist/resources/extensions/gsd/prompts/queue.md +1 -1
- package/dist/resources/extensions/gsd/prompts/reassess-roadmap.md +1 -1
- package/dist/resources/extensions/gsd/prompts/research-slice.md +1 -1
- package/dist/resources/extensions/gsd/prompts/validate-milestone.md +40 -61
- package/dist/resources/extensions/gsd/provider-error-pause.ts +29 -2
- package/dist/resources/extensions/gsd/session-status-io.ts +197 -0
- package/dist/resources/extensions/gsd/state.ts +72 -30
- package/dist/resources/extensions/gsd/tests/agent-end-provider-error.test.ts +81 -0
- package/dist/resources/extensions/gsd/tests/auto-budget-alerts.test.ts +20 -3
- package/dist/resources/extensions/gsd/tests/auto-preflight.test.ts +1 -0
- package/dist/resources/extensions/gsd/tests/auto-recovery.test.ts +256 -2
- package/dist/resources/extensions/gsd/tests/auto-worktree-milestone-merge.test.ts +34 -0
- package/dist/resources/extensions/gsd/tests/auto-worktree.test.ts +58 -0
- package/dist/resources/extensions/gsd/tests/complete-milestone.test.ts +8 -1
- package/dist/resources/extensions/gsd/tests/derive-state-db.test.ts +9 -15
- package/dist/resources/extensions/gsd/tests/derive-state-deps.test.ts +9 -0
- package/dist/resources/extensions/gsd/tests/derive-state-draft.test.ts +8 -0
- package/dist/resources/extensions/gsd/tests/derive-state.test.ts +14 -0
- package/dist/resources/extensions/gsd/tests/git-service.test.ts +70 -4
- package/dist/resources/extensions/gsd/tests/gsd-db.test.ts +2 -2
- package/dist/resources/extensions/gsd/tests/integration-mixed-milestones.test.ts +8 -0
- package/dist/resources/extensions/gsd/tests/md-importer.test.ts +2 -3
- package/dist/resources/extensions/gsd/tests/memory-extractor.test.ts +180 -0
- package/dist/resources/extensions/gsd/tests/memory-store.test.ts +345 -0
- package/dist/resources/extensions/gsd/tests/migrate-writer-integration.test.ts +5 -5
- package/dist/resources/extensions/gsd/tests/parallel-orchestration.test.ts +656 -0
- package/dist/resources/extensions/gsd/tests/parallel-workers-multi-milestone-e2e.test.ts +354 -0
- package/dist/resources/extensions/gsd/tests/queue-reorder-e2e.test.ts +1 -0
- package/dist/resources/extensions/gsd/tests/smart-entry-draft.test.ts +1 -1
- package/dist/resources/extensions/gsd/tests/validate-milestone.test.ts +316 -0
- package/dist/resources/extensions/gsd/tests/visualizer-data.test.ts +147 -2
- package/dist/resources/extensions/gsd/tests/visualizer-overlay.test.ts +88 -10
- package/dist/resources/extensions/gsd/tests/visualizer-views.test.ts +314 -87
- package/dist/resources/extensions/gsd/tests/worker-registry.test.ts +148 -0
- package/dist/resources/extensions/gsd/triage-ui.ts +1 -1
- package/dist/resources/extensions/gsd/types.ts +15 -1
- package/dist/resources/extensions/gsd/visualizer-data.ts +291 -10
- package/dist/resources/extensions/gsd/visualizer-overlay.ts +237 -28
- package/dist/resources/extensions/gsd/visualizer-views.ts +462 -48
- package/dist/resources/extensions/gsd/worktree.ts +9 -2
- package/dist/resources/extensions/search-the-web/native-search.ts +15 -5
- package/dist/resources/extensions/subagent/index.ts +5 -0
- package/dist/resources/extensions/subagent/worker-registry.ts +99 -0
- package/dist/update-check.d.ts +9 -0
- package/dist/update-check.js +97 -0
- package/package.json +6 -1
- package/packages/pi-agent-core/dist/agent-loop.js +2 -0
- package/packages/pi-agent-core/dist/agent-loop.js.map +1 -1
- package/packages/pi-agent-core/src/agent-loop.ts +2 -0
- package/packages/pi-ai/dist/providers/anthropic.d.ts.map +1 -1
- package/packages/pi-ai/dist/providers/anthropic.js +55 -7
- package/packages/pi-ai/dist/providers/anthropic.js.map +1 -1
- package/packages/pi-ai/dist/providers/azure-openai-responses.d.ts.map +1 -1
- package/packages/pi-ai/dist/providers/azure-openai-responses.js +12 -4
- package/packages/pi-ai/dist/providers/azure-openai-responses.js.map +1 -1
- package/packages/pi-ai/dist/providers/google-vertex.d.ts.map +1 -1
- package/packages/pi-ai/dist/providers/google-vertex.js +21 -9
- package/packages/pi-ai/dist/providers/google-vertex.js.map +1 -1
- package/packages/pi-ai/dist/providers/mistral.js +3 -0
- package/packages/pi-ai/dist/providers/mistral.js.map +1 -1
- package/packages/pi-ai/dist/providers/openai-completions.d.ts.map +1 -1
- package/packages/pi-ai/dist/providers/openai-completions.js +12 -4
- package/packages/pi-ai/dist/providers/openai-completions.js.map +1 -1
- package/packages/pi-ai/dist/providers/openai-responses.d.ts.map +1 -1
- package/packages/pi-ai/dist/providers/openai-responses.js +12 -4
- package/packages/pi-ai/dist/providers/openai-responses.js.map +1 -1
- package/packages/pi-ai/dist/types.d.ts +23 -1
- package/packages/pi-ai/dist/types.d.ts.map +1 -1
- package/packages/pi-ai/dist/types.js.map +1 -1
- package/packages/pi-ai/src/providers/anthropic.ts +59 -9
- package/packages/pi-ai/src/providers/azure-openai-responses.ts +16 -4
- package/packages/pi-ai/src/providers/google-vertex.ts +32 -17
- package/packages/pi-ai/src/providers/mistral.ts +3 -0
- package/packages/pi-ai/src/providers/openai-completions.ts +16 -4
- package/packages/pi-ai/src/providers/openai-responses.ts +16 -4
- package/packages/pi-ai/src/types.ts +19 -1
- package/packages/pi-coding-agent/dist/core/agent-session.js +1 -1
- package/packages/pi-coding-agent/dist/core/agent-session.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/settings-manager.js +1 -1
- package/packages/pi-coding-agent/dist/core/settings-manager.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js +17 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts +4 -0
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js +72 -0
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/packages/pi-coding-agent/src/core/agent-session.ts +1 -1
- package/packages/pi-coding-agent/src/core/settings-manager.ts +2 -2
- package/packages/pi-coding-agent/src/modes/interactive/components/tool-execution.ts +18 -0
- package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +84 -0
- package/scripts/postinstall.js +7 -109
- package/src/resources/GSD-WORKFLOW.md +12 -9
- package/src/resources/extensions/bg-shell/overlay.ts +18 -17
- package/src/resources/extensions/get-secrets-from-user.ts +5 -23
- package/src/resources/extensions/gsd/activity-log.ts +5 -3
- package/src/resources/extensions/gsd/auto-dispatch.ts +51 -2
- package/src/resources/extensions/gsd/auto-prompts.ts +87 -0
- package/src/resources/extensions/gsd/auto-recovery.ts +41 -2
- package/src/resources/extensions/gsd/auto-worktree.ts +134 -4
- package/src/resources/extensions/gsd/auto.ts +307 -77
- package/src/resources/extensions/gsd/cache.ts +3 -1
- package/src/resources/extensions/gsd/commands.ts +176 -10
- package/src/resources/extensions/gsd/complexity.ts +1 -0
- package/src/resources/extensions/gsd/dashboard-overlay.ts +38 -0
- package/src/resources/extensions/gsd/doctor.ts +58 -11
- package/src/resources/extensions/gsd/exit-command.ts +2 -2
- package/src/resources/extensions/gsd/git-service.ts +74 -14
- package/src/resources/extensions/gsd/gitignore.ts +1 -0
- package/src/resources/extensions/gsd/gsd-db.ts +78 -1
- package/src/resources/extensions/gsd/guided-flow.ts +109 -12
- package/src/resources/extensions/gsd/index.ts +48 -2
- package/src/resources/extensions/gsd/memory-extractor.ts +352 -0
- package/src/resources/extensions/gsd/memory-store.ts +441 -0
- package/src/resources/extensions/gsd/migrate/command.ts +2 -2
- package/src/resources/extensions/gsd/parallel-eligibility.ts +233 -0
- package/src/resources/extensions/gsd/parallel-merge.ts +156 -0
- package/src/resources/extensions/gsd/parallel-orchestrator.ts +496 -0
- package/src/resources/extensions/gsd/preferences.ts +65 -1
- package/src/resources/extensions/gsd/prompts/complete-slice.md +1 -1
- package/src/resources/extensions/gsd/prompts/discuss-headless.md +86 -0
- package/src/resources/extensions/gsd/prompts/discuss.md +4 -4
- package/src/resources/extensions/gsd/prompts/execute-task.md +1 -1
- package/src/resources/extensions/gsd/prompts/guided-discuss-milestone.md +1 -1
- package/src/resources/extensions/gsd/prompts/guided-discuss-slice.md +1 -1
- package/src/resources/extensions/gsd/prompts/plan-slice.md +1 -1
- package/src/resources/extensions/gsd/prompts/queue.md +1 -1
- package/src/resources/extensions/gsd/prompts/reassess-roadmap.md +1 -1
- package/src/resources/extensions/gsd/prompts/research-slice.md +1 -1
- package/src/resources/extensions/gsd/prompts/validate-milestone.md +40 -61
- package/src/resources/extensions/gsd/provider-error-pause.ts +29 -2
- package/src/resources/extensions/gsd/session-status-io.ts +197 -0
- package/src/resources/extensions/gsd/state.ts +72 -30
- package/src/resources/extensions/gsd/tests/agent-end-provider-error.test.ts +81 -0
- package/src/resources/extensions/gsd/tests/auto-budget-alerts.test.ts +20 -3
- package/src/resources/extensions/gsd/tests/auto-preflight.test.ts +1 -0
- package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +256 -2
- package/src/resources/extensions/gsd/tests/auto-worktree-milestone-merge.test.ts +34 -0
- package/src/resources/extensions/gsd/tests/auto-worktree.test.ts +58 -0
- package/src/resources/extensions/gsd/tests/complete-milestone.test.ts +8 -1
- package/src/resources/extensions/gsd/tests/derive-state-db.test.ts +9 -15
- package/src/resources/extensions/gsd/tests/derive-state-deps.test.ts +9 -0
- package/src/resources/extensions/gsd/tests/derive-state-draft.test.ts +8 -0
- package/src/resources/extensions/gsd/tests/derive-state.test.ts +14 -0
- package/src/resources/extensions/gsd/tests/git-service.test.ts +70 -4
- package/src/resources/extensions/gsd/tests/gsd-db.test.ts +2 -2
- package/src/resources/extensions/gsd/tests/integration-mixed-milestones.test.ts +8 -0
- package/src/resources/extensions/gsd/tests/md-importer.test.ts +2 -3
- package/src/resources/extensions/gsd/tests/memory-extractor.test.ts +180 -0
- package/src/resources/extensions/gsd/tests/memory-store.test.ts +345 -0
- package/src/resources/extensions/gsd/tests/migrate-writer-integration.test.ts +5 -5
- package/src/resources/extensions/gsd/tests/parallel-orchestration.test.ts +656 -0
- package/src/resources/extensions/gsd/tests/parallel-workers-multi-milestone-e2e.test.ts +354 -0
- package/src/resources/extensions/gsd/tests/queue-reorder-e2e.test.ts +1 -0
- package/src/resources/extensions/gsd/tests/smart-entry-draft.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/validate-milestone.test.ts +316 -0
- package/src/resources/extensions/gsd/tests/visualizer-data.test.ts +147 -2
- package/src/resources/extensions/gsd/tests/visualizer-overlay.test.ts +88 -10
- package/src/resources/extensions/gsd/tests/visualizer-views.test.ts +314 -87
- package/src/resources/extensions/gsd/tests/worker-registry.test.ts +148 -0
- package/src/resources/extensions/gsd/triage-ui.ts +1 -1
- package/src/resources/extensions/gsd/types.ts +15 -1
- package/src/resources/extensions/gsd/visualizer-data.ts +291 -10
- package/src/resources/extensions/gsd/visualizer-overlay.ts +237 -28
- package/src/resources/extensions/gsd/visualizer-views.ts +462 -48
- package/src/resources/extensions/gsd/worktree.ts +9 -2
- package/src/resources/extensions/search-the-web/native-search.ts +15 -5
- package/src/resources/extensions/subagent/index.ts +5 -0
- package/src/resources/extensions/subagent/worker-registry.ts +99 -0
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests for the parallel worker registry used by the dashboard overlay.
|
|
3
|
+
*
|
|
4
|
+
* Verifies worker lifecycle (register → update → cleanup), batch grouping,
|
|
5
|
+
* and the hasActiveWorkers() status check.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { createTestContext } from './test-helpers.ts';
|
|
9
|
+
import {
|
|
10
|
+
registerWorker,
|
|
11
|
+
updateWorker,
|
|
12
|
+
getActiveWorkers,
|
|
13
|
+
getWorkerBatches,
|
|
14
|
+
hasActiveWorkers,
|
|
15
|
+
resetWorkerRegistry,
|
|
16
|
+
} from '../../subagent/worker-registry.ts';
|
|
17
|
+
|
|
18
|
+
const { assertEq, assertTrue, report } = createTestContext();
|
|
19
|
+
|
|
20
|
+
// ─── Setup ────────────────────────────────────────────────────────────────────
|
|
21
|
+
|
|
22
|
+
resetWorkerRegistry();
|
|
23
|
+
|
|
24
|
+
// ─── Registration ─────────────────────────────────────────────────────────────
|
|
25
|
+
|
|
26
|
+
console.log("\n=== Worker Registration ===");
|
|
27
|
+
|
|
28
|
+
{
|
|
29
|
+
resetWorkerRegistry();
|
|
30
|
+
const id = registerWorker("scout", "Explore codebase", 0, 3, "batch-1");
|
|
31
|
+
assertTrue(id.startsWith("worker-"), "worker ID has correct prefix");
|
|
32
|
+
const workers = getActiveWorkers();
|
|
33
|
+
assertEq(workers.length, 1, "one worker registered");
|
|
34
|
+
assertEq(workers[0].agent, "scout", "worker agent name correct");
|
|
35
|
+
assertEq(workers[0].task, "Explore codebase", "worker task correct");
|
|
36
|
+
assertEq(workers[0].status, "running", "worker starts as running");
|
|
37
|
+
assertEq(workers[0].index, 0, "worker index correct");
|
|
38
|
+
assertEq(workers[0].batchSize, 3, "worker batch size correct");
|
|
39
|
+
assertEq(workers[0].batchId, "batch-1", "worker batch ID correct");
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// ─── Multiple workers in a batch ──────────────────────────────────────────────
|
|
43
|
+
|
|
44
|
+
console.log("\n=== Multiple Workers in a Batch ===");
|
|
45
|
+
|
|
46
|
+
{
|
|
47
|
+
resetWorkerRegistry();
|
|
48
|
+
const id1 = registerWorker("scout", "Task A", 0, 3, "batch-2");
|
|
49
|
+
const id2 = registerWorker("researcher", "Task B", 1, 3, "batch-2");
|
|
50
|
+
const id3 = registerWorker("worker", "Task C", 2, 3, "batch-2");
|
|
51
|
+
|
|
52
|
+
const workers = getActiveWorkers();
|
|
53
|
+
assertEq(workers.length, 3, "three workers registered");
|
|
54
|
+
assertTrue(hasActiveWorkers(), "has active workers");
|
|
55
|
+
|
|
56
|
+
const batches = getWorkerBatches();
|
|
57
|
+
assertEq(batches.size, 1, "one batch");
|
|
58
|
+
const batch = batches.get("batch-2");
|
|
59
|
+
assertTrue(batch !== undefined, "batch-2 exists");
|
|
60
|
+
assertEq(batch!.length, 3, "batch has 3 workers");
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// ─── Worker status updates ────────────────────────────────────────────────────
|
|
64
|
+
|
|
65
|
+
console.log("\n=== Worker Status Updates ===");
|
|
66
|
+
|
|
67
|
+
{
|
|
68
|
+
resetWorkerRegistry();
|
|
69
|
+
const id1 = registerWorker("scout", "Task A", 0, 2, "batch-3");
|
|
70
|
+
const id2 = registerWorker("worker", "Task B", 1, 2, "batch-3");
|
|
71
|
+
|
|
72
|
+
updateWorker(id1, "completed");
|
|
73
|
+
const workers = getActiveWorkers();
|
|
74
|
+
const w1 = workers.find(w => w.id === id1);
|
|
75
|
+
assertEq(w1?.status, "completed", "worker 1 marked completed");
|
|
76
|
+
|
|
77
|
+
const w2 = workers.find(w => w.id === id2);
|
|
78
|
+
assertEq(w2?.status, "running", "worker 2 still running");
|
|
79
|
+
assertTrue(hasActiveWorkers(), "still has active workers (worker 2 running)");
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// ─── Failed worker ────────────────────────────────────────────────────────────
|
|
83
|
+
|
|
84
|
+
console.log("\n=== Failed Worker ===");
|
|
85
|
+
|
|
86
|
+
{
|
|
87
|
+
resetWorkerRegistry();
|
|
88
|
+
const id = registerWorker("scout", "Task A", 0, 1, "batch-4");
|
|
89
|
+
updateWorker(id, "failed");
|
|
90
|
+
const workers = getActiveWorkers();
|
|
91
|
+
assertEq(workers[0].status, "failed", "worker marked failed");
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// ─── Multiple batches ─────────────────────────────────────────────────────────
|
|
95
|
+
|
|
96
|
+
console.log("\n=== Multiple Batches ===");
|
|
97
|
+
|
|
98
|
+
{
|
|
99
|
+
resetWorkerRegistry();
|
|
100
|
+
registerWorker("scout", "Task A", 0, 2, "batch-5");
|
|
101
|
+
registerWorker("worker", "Task B", 1, 2, "batch-5");
|
|
102
|
+
registerWorker("researcher", "Task C", 0, 1, "batch-6");
|
|
103
|
+
|
|
104
|
+
const batches = getWorkerBatches();
|
|
105
|
+
assertEq(batches.size, 2, "two batches");
|
|
106
|
+
assertEq(batches.get("batch-5")!.length, 2, "batch-5 has 2 workers");
|
|
107
|
+
assertEq(batches.get("batch-6")!.length, 1, "batch-6 has 1 worker");
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// ─── hasActiveWorkers with all completed ──────────────────────────────────────
|
|
111
|
+
|
|
112
|
+
console.log("\n=== hasActiveWorkers — all completed ===");
|
|
113
|
+
|
|
114
|
+
{
|
|
115
|
+
resetWorkerRegistry();
|
|
116
|
+
const id1 = registerWorker("scout", "Task A", 0, 2, "batch-7");
|
|
117
|
+
const id2 = registerWorker("worker", "Task B", 1, 2, "batch-7");
|
|
118
|
+
updateWorker(id1, "completed");
|
|
119
|
+
updateWorker(id2, "completed");
|
|
120
|
+
assertTrue(!hasActiveWorkers(), "no active workers when all completed");
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// ─── Reset clears everything ─────────────────────────────────────────────────
|
|
124
|
+
|
|
125
|
+
console.log("\n=== Reset ===");
|
|
126
|
+
|
|
127
|
+
{
|
|
128
|
+
registerWorker("scout", "Task", 0, 1, "batch-8");
|
|
129
|
+
assertTrue(getActiveWorkers().length > 0, "workers exist before reset");
|
|
130
|
+
resetWorkerRegistry();
|
|
131
|
+
assertEq(getActiveWorkers().length, 0, "no workers after reset");
|
|
132
|
+
assertTrue(!hasActiveWorkers(), "hasActiveWorkers false after reset");
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// ─── Update non-existent worker is no-op ──────────────────────────────────────
|
|
136
|
+
|
|
137
|
+
console.log("\n=== Update non-existent worker ===");
|
|
138
|
+
|
|
139
|
+
{
|
|
140
|
+
resetWorkerRegistry();
|
|
141
|
+
// Should not throw
|
|
142
|
+
updateWorker("nonexistent-id", "completed");
|
|
143
|
+
assertEq(getActiveWorkers().length, 0, "no workers created by updating nonexistent");
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// ─── Summary ──────────────────────────────────────────────────────────────────
|
|
147
|
+
|
|
148
|
+
report();
|
|
@@ -135,7 +135,7 @@ export async function showTriageConfirmation(
|
|
|
135
135
|
recommended: cls === proposed,
|
|
136
136
|
}));
|
|
137
137
|
|
|
138
|
-
const choice = await showNextAction(ctx
|
|
138
|
+
const choice = await showNextAction(ctx, {
|
|
139
139
|
title: `Triage: ${result.captureId}`,
|
|
140
140
|
summary,
|
|
141
141
|
actions,
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
// ─── Enums & Literal Unions ────────────────────────────────────────────────
|
|
6
6
|
|
|
7
7
|
export type RiskLevel = 'low' | 'medium' | 'high';
|
|
8
|
-
export type Phase = 'pre-planning' | 'needs-discussion' | 'discussing' | 'researching' | 'planning' | 'executing' | 'verifying' | 'summarizing' | 'advancing' | 'completing-milestone' | 'replanning-slice' | 'complete' | 'paused' | 'blocked';
|
|
8
|
+
export type Phase = 'pre-planning' | 'needs-discussion' | 'discussing' | 'researching' | 'planning' | 'executing' | 'verifying' | 'summarizing' | 'advancing' | 'validating-milestone' | 'completing-milestone' | 'replanning-slice' | 'complete' | 'paused' | 'blocked';
|
|
9
9
|
export type ContinueStatus = 'in_progress' | 'interrupted' | 'compacted';
|
|
10
10
|
|
|
11
11
|
// ─── Roadmap (Milestone-level) ─────────────────────────────────────────────
|
|
@@ -264,6 +264,7 @@ export interface PhaseSkipPreferences {
|
|
|
264
264
|
skip_research?: boolean;
|
|
265
265
|
skip_reassess?: boolean;
|
|
266
266
|
skip_slice_research?: boolean;
|
|
267
|
+
skip_milestone_validation?: boolean;
|
|
267
268
|
}
|
|
268
269
|
|
|
269
270
|
export interface NotificationPreferences {
|
|
@@ -363,3 +364,16 @@ export interface Requirement {
|
|
|
363
364
|
full_content: string; // full requirement text
|
|
364
365
|
superseded_by: string | null; // ID of superseding requirement, or null
|
|
365
366
|
}
|
|
367
|
+
|
|
368
|
+
// ─── Parallel Orchestration Types ────────────────────────────────────────
|
|
369
|
+
|
|
370
|
+
export type MergeStrategy = "per-slice" | "per-milestone";
|
|
371
|
+
export type AutoMergeMode = "auto" | "confirm" | "manual";
|
|
372
|
+
|
|
373
|
+
export interface ParallelConfig {
|
|
374
|
+
enabled: boolean;
|
|
375
|
+
max_workers: number;
|
|
376
|
+
budget_ceiling?: number;
|
|
377
|
+
merge_strategy: MergeStrategy;
|
|
378
|
+
auto_merge: AutoMergeMode;
|
|
379
|
+
}
|
|
@@ -1,25 +1,32 @@
|
|
|
1
1
|
// Data loader for workflow visualizer overlay — aggregates state + metrics.
|
|
2
2
|
|
|
3
|
+
import { existsSync, readFileSync, statSync } from 'node:fs';
|
|
3
4
|
import { deriveState } from './state.js';
|
|
4
5
|
import { parseRoadmap, parsePlan, parseSummary, loadFile } from './files.js';
|
|
5
6
|
import { findMilestoneIds } from './guided-flow.js';
|
|
6
|
-
import { resolveMilestoneFile, resolveSliceFile } from './paths.js';
|
|
7
|
+
import { resolveMilestoneFile, resolveSliceFile, resolveGsdRootFile } from './paths.js';
|
|
7
8
|
import {
|
|
8
9
|
getLedger,
|
|
9
10
|
getProjectTotals,
|
|
10
11
|
aggregateByPhase,
|
|
11
12
|
aggregateBySlice,
|
|
12
13
|
aggregateByModel,
|
|
14
|
+
aggregateByTier,
|
|
15
|
+
formatTierSavings,
|
|
13
16
|
loadLedgerFromDisk,
|
|
14
17
|
classifyUnitPhase,
|
|
15
18
|
} from './metrics.js';
|
|
19
|
+
import { loadAllCaptures, countPendingCaptures } from './captures.js';
|
|
20
|
+
import { loadEffectiveGSDPreferences } from './preferences.js';
|
|
16
21
|
|
|
17
22
|
import type { Phase } from './types.js';
|
|
23
|
+
import type { CaptureEntry } from './captures.js';
|
|
18
24
|
import type {
|
|
19
25
|
ProjectTotals,
|
|
20
26
|
PhaseAggregate,
|
|
21
27
|
SliceAggregate,
|
|
22
28
|
ModelAggregate,
|
|
29
|
+
TierAggregate,
|
|
23
30
|
UnitMetrics,
|
|
24
31
|
} from './metrics.js';
|
|
25
32
|
|
|
@@ -48,6 +55,7 @@ export interface VisualizerTask {
|
|
|
48
55
|
title: string;
|
|
49
56
|
done: boolean;
|
|
50
57
|
active: boolean;
|
|
58
|
+
estimate?: string;
|
|
51
59
|
}
|
|
52
60
|
|
|
53
61
|
export interface CriticalPathInfo {
|
|
@@ -81,6 +89,71 @@ export interface ChangelogInfo {
|
|
|
81
89
|
entries: ChangelogEntry[];
|
|
82
90
|
}
|
|
83
91
|
|
|
92
|
+
export interface VisualizerSliceRef {
|
|
93
|
+
milestoneId: string;
|
|
94
|
+
sliceId: string;
|
|
95
|
+
title: string;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
export interface VisualizerSliceActivity extends VisualizerSliceRef {
|
|
99
|
+
completedAt: string;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
export interface VisualizerStats {
|
|
103
|
+
missingCount: number;
|
|
104
|
+
missingSlices: VisualizerSliceRef[];
|
|
105
|
+
updatedCount: number;
|
|
106
|
+
updatedSlices: VisualizerSliceActivity[];
|
|
107
|
+
recentEntries: ChangelogEntry[];
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
export type DiscussionState = 'undiscussed' | 'draft' | 'discussed';
|
|
111
|
+
|
|
112
|
+
export interface VisualizerDiscussionState {
|
|
113
|
+
milestoneId: string;
|
|
114
|
+
title: string;
|
|
115
|
+
state: DiscussionState;
|
|
116
|
+
hasContext: boolean;
|
|
117
|
+
hasDraft: boolean;
|
|
118
|
+
lastUpdated: string | null;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
export interface SliceVerification {
|
|
122
|
+
milestoneId: string;
|
|
123
|
+
sliceId: string;
|
|
124
|
+
verificationResult: string;
|
|
125
|
+
blockerDiscovered: boolean;
|
|
126
|
+
keyDecisions: string[];
|
|
127
|
+
patternsEstablished: string[];
|
|
128
|
+
provides: string[];
|
|
129
|
+
requires: { slice: string; provides: string }[];
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
export interface KnowledgeInfo {
|
|
133
|
+
rules: { id: string; scope: string; content: string }[];
|
|
134
|
+
patterns: { id: string; content: string }[];
|
|
135
|
+
lessons: { id: string; content: string }[];
|
|
136
|
+
exists: boolean;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
export interface CapturesInfo {
|
|
140
|
+
entries: CaptureEntry[];
|
|
141
|
+
pendingCount: number;
|
|
142
|
+
totalCount: number;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
export interface HealthInfo {
|
|
146
|
+
budgetCeiling: number | undefined;
|
|
147
|
+
tokenProfile: string;
|
|
148
|
+
truncationRate: number;
|
|
149
|
+
continueHereRate: number;
|
|
150
|
+
tierBreakdown: TierAggregate[];
|
|
151
|
+
tierSavingsLine: string;
|
|
152
|
+
toolCalls: number;
|
|
153
|
+
assistantMessages: number;
|
|
154
|
+
userMessages: number;
|
|
155
|
+
}
|
|
156
|
+
|
|
84
157
|
export interface VisualizerData {
|
|
85
158
|
milestones: VisualizerMilestone[];
|
|
86
159
|
phase: Phase;
|
|
@@ -88,11 +161,19 @@ export interface VisualizerData {
|
|
|
88
161
|
byPhase: PhaseAggregate[];
|
|
89
162
|
bySlice: SliceAggregate[];
|
|
90
163
|
byModel: ModelAggregate[];
|
|
164
|
+
byTier: TierAggregate[];
|
|
165
|
+
tierSavingsLine: string;
|
|
91
166
|
units: UnitMetrics[];
|
|
92
167
|
criticalPath: CriticalPathInfo;
|
|
93
168
|
remainingSliceCount: number;
|
|
94
169
|
agentActivity: AgentActivityInfo | null;
|
|
95
170
|
changelog: ChangelogInfo;
|
|
171
|
+
sliceVerifications: SliceVerification[];
|
|
172
|
+
knowledge: KnowledgeInfo;
|
|
173
|
+
captures: CapturesInfo;
|
|
174
|
+
health: HealthInfo;
|
|
175
|
+
discussion: VisualizerDiscussionState[];
|
|
176
|
+
stats: VisualizerStats;
|
|
96
177
|
}
|
|
97
178
|
|
|
98
179
|
// ─── Critical Path ────────────────────────────────────────────────────────────
|
|
@@ -334,12 +415,18 @@ function loadAgentActivity(units: UnitMetrics[], milestones: VisualizerMilestone
|
|
|
334
415
|
};
|
|
335
416
|
}
|
|
336
417
|
|
|
337
|
-
// ─── Changelog
|
|
418
|
+
// ─── Changelog & Verifications ────────────────────────────────────────────────
|
|
338
419
|
|
|
339
|
-
const changelogCache = new Map<string, { mtime: number; entry: ChangelogEntry }>();
|
|
420
|
+
const changelogCache = new Map<string, { mtime: number; entry: ChangelogEntry; verification: SliceVerification }>();
|
|
340
421
|
|
|
341
|
-
|
|
422
|
+
interface ChangelogAndVerifications {
|
|
423
|
+
changelog: ChangelogInfo;
|
|
424
|
+
verifications: SliceVerification[];
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
async function loadChangelogAndVerifications(basePath: string, milestones: VisualizerMilestone[]): Promise<ChangelogAndVerifications> {
|
|
342
428
|
const entries: ChangelogEntry[] = [];
|
|
429
|
+
const verifications: SliceVerification[] = [];
|
|
343
430
|
|
|
344
431
|
for (const ms of milestones) {
|
|
345
432
|
for (const sl of ms.slices) {
|
|
@@ -348,11 +435,9 @@ async function loadChangelog(basePath: string, milestones: VisualizerMilestone[]
|
|
|
348
435
|
const summaryFile = resolveSliceFile(basePath, ms.id, sl.id, 'SUMMARY');
|
|
349
436
|
if (!summaryFile) continue;
|
|
350
437
|
|
|
351
|
-
// Check cache by file path
|
|
352
438
|
const cacheKey = `${ms.id}/${sl.id}`;
|
|
353
439
|
const cached = changelogCache.get(cacheKey);
|
|
354
440
|
|
|
355
|
-
// Check mtime for cache invalidation
|
|
356
441
|
let mtime = 0;
|
|
357
442
|
try {
|
|
358
443
|
const { statSync } = await import('node:fs');
|
|
@@ -363,6 +448,7 @@ async function loadChangelog(basePath: string, milestones: VisualizerMilestone[]
|
|
|
363
448
|
|
|
364
449
|
if (cached && cached.mtime === mtime) {
|
|
365
450
|
entries.push(cached.entry);
|
|
451
|
+
verifications.push(cached.verification);
|
|
366
452
|
continue;
|
|
367
453
|
}
|
|
368
454
|
|
|
@@ -382,15 +468,184 @@ async function loadChangelog(basePath: string, milestones: VisualizerMilestone[]
|
|
|
382
468
|
completedAt: String(summary.frontmatter.completed_at ?? ''),
|
|
383
469
|
};
|
|
384
470
|
|
|
385
|
-
|
|
471
|
+
const verification: SliceVerification = {
|
|
472
|
+
milestoneId: ms.id,
|
|
473
|
+
sliceId: sl.id,
|
|
474
|
+
verificationResult: summary.frontmatter.verification_result || '',
|
|
475
|
+
blockerDiscovered: summary.frontmatter.blocker_discovered,
|
|
476
|
+
keyDecisions: summary.frontmatter.key_decisions || [],
|
|
477
|
+
patternsEstablished: summary.frontmatter.patterns_established || [],
|
|
478
|
+
provides: summary.frontmatter.provides || [],
|
|
479
|
+
requires: (summary.frontmatter.requires || []).map(r => ({
|
|
480
|
+
slice: r.slice,
|
|
481
|
+
provides: r.provides,
|
|
482
|
+
})),
|
|
483
|
+
};
|
|
484
|
+
|
|
485
|
+
changelogCache.set(cacheKey, { mtime, entry, verification });
|
|
386
486
|
entries.push(entry);
|
|
487
|
+
verifications.push(verification);
|
|
387
488
|
}
|
|
388
489
|
}
|
|
389
490
|
|
|
390
|
-
// Sort by completedAt descending
|
|
391
491
|
entries.sort((a, b) => String(b.completedAt || '').localeCompare(String(a.completedAt || '')));
|
|
392
492
|
|
|
393
|
-
return { entries };
|
|
493
|
+
return { changelog: { entries }, verifications };
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
// ─── Knowledge Loader ─────────────────────────────────────────────────────────
|
|
497
|
+
|
|
498
|
+
function loadKnowledge(basePath: string): KnowledgeInfo {
|
|
499
|
+
const knowledgePath = resolveGsdRootFile(basePath, 'KNOWLEDGE');
|
|
500
|
+
if (!existsSync(knowledgePath)) {
|
|
501
|
+
return { rules: [], patterns: [], lessons: [], exists: false };
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
let content: string;
|
|
505
|
+
try {
|
|
506
|
+
content = readFileSync(knowledgePath, 'utf-8');
|
|
507
|
+
} catch {
|
|
508
|
+
return { rules: [], patterns: [], lessons: [], exists: false };
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
const rules: { id: string; scope: string; content: string }[] = [];
|
|
512
|
+
const patterns: { id: string; content: string }[] = [];
|
|
513
|
+
const lessons: { id: string; content: string }[] = [];
|
|
514
|
+
|
|
515
|
+
const lines = content.split('\n');
|
|
516
|
+
let currentSection = '';
|
|
517
|
+
|
|
518
|
+
for (const line of lines) {
|
|
519
|
+
if (line.startsWith('## Rules')) { currentSection = 'rules'; continue; }
|
|
520
|
+
if (line.startsWith('## Patterns')) { currentSection = 'patterns'; continue; }
|
|
521
|
+
if (line.startsWith('## Lessons')) { currentSection = 'lessons'; continue; }
|
|
522
|
+
if (line.startsWith('## ')) { currentSection = ''; continue; }
|
|
523
|
+
|
|
524
|
+
if (!line.startsWith('| ') || line.startsWith('| ---') || line.startsWith('| ID')) continue;
|
|
525
|
+
const cols = line.split('|').map(c => c.trim()).filter(c => c.length > 0);
|
|
526
|
+
if (cols.length < 2) continue;
|
|
527
|
+
|
|
528
|
+
if (currentSection === 'rules' && cols.length >= 3) {
|
|
529
|
+
rules.push({ id: cols[0], scope: cols[1], content: cols[2] });
|
|
530
|
+
} else if (currentSection === 'patterns' && cols.length >= 2) {
|
|
531
|
+
patterns.push({ id: cols[0], content: cols[1] });
|
|
532
|
+
} else if (currentSection === 'lessons' && cols.length >= 2) {
|
|
533
|
+
lessons.push({ id: cols[0], content: cols[1] });
|
|
534
|
+
}
|
|
535
|
+
}
|
|
536
|
+
|
|
537
|
+
return { rules, patterns, lessons, exists: true };
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
// ─── Health Loader ────────────────────────────────────────────────────────────
|
|
541
|
+
|
|
542
|
+
function loadHealth(units: UnitMetrics[], totals: ProjectTotals | null): HealthInfo {
|
|
543
|
+
const prefs = loadEffectiveGSDPreferences();
|
|
544
|
+
const budgetCeiling = prefs?.preferences?.budget_ceiling;
|
|
545
|
+
const tokenProfile = prefs?.preferences?.token_profile ?? 'standard';
|
|
546
|
+
|
|
547
|
+
let truncationRate = 0;
|
|
548
|
+
let continueHereRate = 0;
|
|
549
|
+
if (totals && totals.units > 0) {
|
|
550
|
+
truncationRate = (totals.totalTruncationSections / totals.units) * 100;
|
|
551
|
+
continueHereRate = (totals.continueHereFiredCount / totals.units) * 100;
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
const tierBreakdown = aggregateByTier(units);
|
|
555
|
+
const tierSavingsLine = formatTierSavings(units);
|
|
556
|
+
|
|
557
|
+
return {
|
|
558
|
+
budgetCeiling,
|
|
559
|
+
tokenProfile,
|
|
560
|
+
truncationRate,
|
|
561
|
+
continueHereRate,
|
|
562
|
+
tierBreakdown,
|
|
563
|
+
tierSavingsLine,
|
|
564
|
+
toolCalls: totals?.toolCalls ?? 0,
|
|
565
|
+
assistantMessages: totals?.assistantMessages ?? 0,
|
|
566
|
+
userMessages: totals?.userMessages ?? 0,
|
|
567
|
+
};
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
const RECENT_ENTRY_LIMIT = 3;
|
|
571
|
+
const FEATURE_PREVIEW_LIMIT = 5;
|
|
572
|
+
const UPDATED_WINDOW_MS = 7 * 24 * 60 * 60 * 1000;
|
|
573
|
+
|
|
574
|
+
function buildVisualizerStats(
|
|
575
|
+
milestones: VisualizerMilestone[],
|
|
576
|
+
entries: ChangelogEntry[],
|
|
577
|
+
): VisualizerStats {
|
|
578
|
+
const missing: VisualizerSliceRef[] = [];
|
|
579
|
+
for (const ms of milestones) {
|
|
580
|
+
for (const sl of ms.slices) {
|
|
581
|
+
if (!sl.done) missing.push({ milestoneId: ms.id, sliceId: sl.id, title: sl.title });
|
|
582
|
+
}
|
|
583
|
+
}
|
|
584
|
+
|
|
585
|
+
const missingCount = missing.length;
|
|
586
|
+
const missingSlices = missing.slice(0, FEATURE_PREVIEW_LIMIT);
|
|
587
|
+
|
|
588
|
+
const now = Date.now();
|
|
589
|
+
const updatedEntries = entries.filter(entry => {
|
|
590
|
+
if (!entry.completedAt) return false;
|
|
591
|
+
const parsed = Date.parse(entry.completedAt);
|
|
592
|
+
return !Number.isNaN(parsed) && now - parsed <= UPDATED_WINDOW_MS;
|
|
593
|
+
});
|
|
594
|
+
const updatedCount = updatedEntries.length;
|
|
595
|
+
const updatedSlices = updatedEntries.slice(0, FEATURE_PREVIEW_LIMIT).map(entry => ({
|
|
596
|
+
milestoneId: entry.milestoneId,
|
|
597
|
+
sliceId: entry.sliceId,
|
|
598
|
+
title: entry.title,
|
|
599
|
+
completedAt: entry.completedAt,
|
|
600
|
+
}));
|
|
601
|
+
|
|
602
|
+
const recentEntries = entries.slice(0, RECENT_ENTRY_LIMIT);
|
|
603
|
+
|
|
604
|
+
return {
|
|
605
|
+
missingCount,
|
|
606
|
+
missingSlices,
|
|
607
|
+
updatedCount,
|
|
608
|
+
updatedSlices,
|
|
609
|
+
recentEntries,
|
|
610
|
+
};
|
|
611
|
+
}
|
|
612
|
+
|
|
613
|
+
function loadDiscussionState(
|
|
614
|
+
basePath: string,
|
|
615
|
+
milestones: VisualizerMilestone[],
|
|
616
|
+
): VisualizerDiscussionState[] {
|
|
617
|
+
const states: VisualizerDiscussionState[] = [];
|
|
618
|
+
|
|
619
|
+
for (const ms of milestones) {
|
|
620
|
+
const contextPath = resolveMilestoneFile(basePath, ms.id, "CONTEXT");
|
|
621
|
+
const draftPath = resolveMilestoneFile(basePath, ms.id, "CONTEXT-DRAFT");
|
|
622
|
+
const state: DiscussionState = contextPath
|
|
623
|
+
? "discussed"
|
|
624
|
+
: draftPath
|
|
625
|
+
? "draft"
|
|
626
|
+
: "undiscussed";
|
|
627
|
+
|
|
628
|
+
let lastUpdated: string | null = null;
|
|
629
|
+
const target = contextPath ?? draftPath;
|
|
630
|
+
if (target) {
|
|
631
|
+
try {
|
|
632
|
+
lastUpdated = new Date(statSync(target).mtimeMs).toISOString();
|
|
633
|
+
} catch {
|
|
634
|
+
lastUpdated = null;
|
|
635
|
+
}
|
|
636
|
+
}
|
|
637
|
+
|
|
638
|
+
states.push({
|
|
639
|
+
milestoneId: ms.id,
|
|
640
|
+
title: ms.title,
|
|
641
|
+
state,
|
|
642
|
+
hasContext: !!contextPath,
|
|
643
|
+
hasDraft: !!draftPath,
|
|
644
|
+
lastUpdated,
|
|
645
|
+
});
|
|
646
|
+
}
|
|
647
|
+
|
|
648
|
+
return states;
|
|
394
649
|
}
|
|
395
650
|
|
|
396
651
|
// ─── Loader ───────────────────────────────────────────────────────────────────
|
|
@@ -433,6 +688,7 @@ export async function loadVisualizerData(basePath: string): Promise<VisualizerDa
|
|
|
433
688
|
title: t.title,
|
|
434
689
|
done: t.done,
|
|
435
690
|
active: state.activeTask?.id === t.id,
|
|
691
|
+
estimate: t.estimate || undefined,
|
|
436
692
|
});
|
|
437
693
|
}
|
|
438
694
|
}
|
|
@@ -464,6 +720,8 @@ export async function loadVisualizerData(basePath: string): Promise<VisualizerDa
|
|
|
464
720
|
let byPhase: PhaseAggregate[] = [];
|
|
465
721
|
let bySlice: SliceAggregate[] = [];
|
|
466
722
|
let byModel: ModelAggregate[] = [];
|
|
723
|
+
let byTier: TierAggregate[] = [];
|
|
724
|
+
let tierSavingsLine = '';
|
|
467
725
|
let units: UnitMetrics[] = [];
|
|
468
726
|
|
|
469
727
|
const ledger = getLedger() ?? loadLedgerFromDisk(basePath);
|
|
@@ -474,6 +732,8 @@ export async function loadVisualizerData(basePath: string): Promise<VisualizerDa
|
|
|
474
732
|
byPhase = aggregateByPhase(units);
|
|
475
733
|
bySlice = aggregateBySlice(units);
|
|
476
734
|
byModel = aggregateByModel(units);
|
|
735
|
+
byTier = aggregateByTier(units);
|
|
736
|
+
tierSavingsLine = formatTierSavings(units);
|
|
477
737
|
}
|
|
478
738
|
|
|
479
739
|
// Compute new fields
|
|
@@ -487,7 +747,20 @@ export async function loadVisualizerData(basePath: string): Promise<VisualizerDa
|
|
|
487
747
|
}
|
|
488
748
|
|
|
489
749
|
const agentActivity = loadAgentActivity(units, milestones);
|
|
490
|
-
const changelog = await
|
|
750
|
+
const { changelog, verifications: sliceVerifications } = await loadChangelogAndVerifications(basePath, milestones);
|
|
751
|
+
|
|
752
|
+
const knowledge = loadKnowledge(basePath);
|
|
753
|
+
const allCaptures = loadAllCaptures(basePath);
|
|
754
|
+
const pendingCount = countPendingCaptures(basePath);
|
|
755
|
+
const captures: CapturesInfo = {
|
|
756
|
+
entries: allCaptures,
|
|
757
|
+
pendingCount,
|
|
758
|
+
totalCount: allCaptures.length,
|
|
759
|
+
};
|
|
760
|
+
|
|
761
|
+
const health = loadHealth(units, totals);
|
|
762
|
+
const stats = buildVisualizerStats(milestones, changelog.entries);
|
|
763
|
+
const discussion = loadDiscussionState(basePath, milestones);
|
|
491
764
|
|
|
492
765
|
return {
|
|
493
766
|
milestones,
|
|
@@ -496,10 +769,18 @@ export async function loadVisualizerData(basePath: string): Promise<VisualizerDa
|
|
|
496
769
|
byPhase,
|
|
497
770
|
bySlice,
|
|
498
771
|
byModel,
|
|
772
|
+
byTier,
|
|
773
|
+
tierSavingsLine,
|
|
499
774
|
units,
|
|
500
775
|
criticalPath,
|
|
501
776
|
remainingSliceCount,
|
|
502
777
|
agentActivity,
|
|
503
778
|
changelog,
|
|
779
|
+
sliceVerifications,
|
|
780
|
+
knowledge,
|
|
781
|
+
captures,
|
|
782
|
+
health,
|
|
783
|
+
discussion,
|
|
784
|
+
stats,
|
|
504
785
|
};
|
|
505
786
|
}
|