gsd-pi 2.24.0 → 2.26.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.
Files changed (206) hide show
  1. package/README.md +13 -3
  2. package/dist/headless.js +24 -4
  3. package/dist/models-resolver.d.ts +0 -11
  4. package/dist/models-resolver.js +0 -15
  5. package/dist/resource-loader.d.ts +0 -1
  6. package/dist/resource-loader.js +0 -9
  7. package/dist/resources/GSD-WORKFLOW.md +12 -9
  8. package/dist/resources/extensions/async-jobs/index.ts +9 -1
  9. package/dist/resources/extensions/bg-shell/index.ts +3 -2
  10. package/dist/resources/extensions/bg-shell/overlay.ts +18 -17
  11. package/dist/resources/extensions/get-secrets-from-user.ts +5 -23
  12. package/dist/resources/extensions/gsd/activity-log.ts +5 -3
  13. package/dist/resources/extensions/gsd/auto-prompts.ts +14 -0
  14. package/dist/resources/extensions/gsd/auto-recovery.ts +7 -4
  15. package/dist/resources/extensions/gsd/auto-worktree.ts +132 -3
  16. package/dist/resources/extensions/gsd/auto.ts +265 -48
  17. package/dist/resources/extensions/gsd/cache.ts +3 -1
  18. package/dist/resources/extensions/gsd/doctor-proactive.ts +7 -6
  19. package/dist/resources/extensions/gsd/doctor.ts +26 -1
  20. package/dist/resources/extensions/gsd/files.ts +13 -2
  21. package/dist/resources/extensions/gsd/git-service.ts +74 -14
  22. package/dist/resources/extensions/gsd/gsd-db.ts +78 -1
  23. package/dist/resources/extensions/gsd/guided-flow.ts +54 -22
  24. package/dist/resources/extensions/gsd/index.ts +62 -8
  25. package/dist/resources/extensions/gsd/memory-extractor.ts +352 -0
  26. package/dist/resources/extensions/gsd/memory-store.ts +441 -0
  27. package/dist/resources/extensions/gsd/migrate/command.ts +2 -2
  28. package/dist/resources/extensions/gsd/migrate/writer.ts +39 -0
  29. package/dist/resources/extensions/gsd/parallel-orchestrator.ts +122 -4
  30. package/dist/resources/extensions/gsd/preferences.ts +2 -1
  31. package/dist/resources/extensions/gsd/prompts/complete-slice.md +1 -1
  32. package/dist/resources/extensions/gsd/prompts/discuss-headless.md +4 -4
  33. package/dist/resources/extensions/gsd/prompts/discuss.md +5 -5
  34. package/dist/resources/extensions/gsd/prompts/execute-task.md +1 -1
  35. package/dist/resources/extensions/gsd/prompts/guided-discuss-milestone.md +1 -1
  36. package/dist/resources/extensions/gsd/prompts/guided-discuss-slice.md +1 -1
  37. package/dist/resources/extensions/gsd/prompts/plan-slice.md +1 -1
  38. package/dist/resources/extensions/gsd/prompts/queue.md +3 -3
  39. package/dist/resources/extensions/gsd/prompts/reassess-roadmap.md +1 -1
  40. package/dist/resources/extensions/gsd/roadmap-slices.ts +45 -1
  41. package/dist/resources/extensions/gsd/state.ts +17 -6
  42. package/dist/resources/extensions/gsd/tests/auto-recovery.test.ts +54 -0
  43. package/dist/resources/extensions/gsd/tests/auto-worktree.test.ts +58 -0
  44. package/dist/resources/extensions/gsd/tests/derive-state.test.ts +70 -0
  45. package/dist/resources/extensions/gsd/tests/doctor-proactive.test.ts +23 -3
  46. package/dist/resources/extensions/gsd/tests/git-service.test.ts +70 -4
  47. package/dist/resources/extensions/gsd/tests/gsd-db.test.ts +2 -2
  48. package/dist/resources/extensions/gsd/tests/md-importer.test.ts +2 -3
  49. package/dist/resources/extensions/gsd/tests/memory-extractor.test.ts +180 -0
  50. package/dist/resources/extensions/gsd/tests/memory-store.test.ts +345 -0
  51. package/dist/resources/extensions/gsd/tests/migrate-writer-integration.test.ts +13 -7
  52. package/dist/resources/extensions/gsd/tests/parallel-worker-monitoring.test.ts +171 -0
  53. package/dist/resources/extensions/gsd/tests/smart-entry-draft.test.ts +1 -1
  54. package/dist/resources/extensions/gsd/tests/validate-milestone.test.ts +8 -4
  55. package/dist/resources/extensions/gsd/tests/visualizer-data.test.ts +147 -2
  56. package/dist/resources/extensions/gsd/tests/visualizer-overlay.test.ts +88 -10
  57. package/dist/resources/extensions/gsd/tests/visualizer-views.test.ts +314 -87
  58. package/dist/resources/extensions/gsd/triage-ui.ts +1 -1
  59. package/dist/resources/extensions/gsd/types.ts +2 -0
  60. package/dist/resources/extensions/gsd/visualizer-data.ts +291 -10
  61. package/dist/resources/extensions/gsd/visualizer-overlay.ts +237 -28
  62. package/dist/resources/extensions/gsd/visualizer-views.ts +462 -48
  63. package/dist/resources/extensions/gsd/worktree.ts +9 -2
  64. package/dist/resources/extensions/search-the-web/native-search.ts +19 -5
  65. package/dist/resources/extensions/shared/path-display.ts +19 -0
  66. package/package.json +1 -6
  67. package/packages/pi-agent-core/dist/agent-loop.js +2 -0
  68. package/packages/pi-agent-core/dist/agent-loop.js.map +1 -1
  69. package/packages/pi-agent-core/src/agent-loop.ts +2 -0
  70. package/packages/pi-ai/dist/providers/anthropic.d.ts.map +1 -1
  71. package/packages/pi-ai/dist/providers/anthropic.js +64 -0
  72. package/packages/pi-ai/dist/providers/anthropic.js.map +1 -1
  73. package/packages/pi-ai/dist/providers/mistral.js +3 -0
  74. package/packages/pi-ai/dist/providers/mistral.js.map +1 -1
  75. package/packages/pi-ai/dist/types.d.ts +23 -1
  76. package/packages/pi-ai/dist/types.d.ts.map +1 -1
  77. package/packages/pi-ai/dist/types.js.map +1 -1
  78. package/packages/pi-ai/src/providers/anthropic.ts +65 -1
  79. package/packages/pi-ai/src/providers/mistral.ts +3 -0
  80. package/packages/pi-ai/src/types.ts +19 -1
  81. package/packages/pi-coding-agent/dist/core/agent-session.d.ts +7 -0
  82. package/packages/pi-coding-agent/dist/core/agent-session.d.ts.map +1 -1
  83. package/packages/pi-coding-agent/dist/core/agent-session.js +32 -0
  84. package/packages/pi-coding-agent/dist/core/agent-session.js.map +1 -1
  85. package/packages/pi-coding-agent/dist/core/keybindings.js +1 -1
  86. package/packages/pi-coding-agent/dist/core/keybindings.js.map +1 -1
  87. package/packages/pi-coding-agent/dist/core/lsp/client.d.ts.map +1 -1
  88. package/packages/pi-coding-agent/dist/core/lsp/client.js +12 -1
  89. package/packages/pi-coding-agent/dist/core/lsp/client.js.map +1 -1
  90. package/packages/pi-coding-agent/dist/core/lsp/index.d.ts.map +1 -1
  91. package/packages/pi-coding-agent/dist/core/lsp/index.js +7 -0
  92. package/packages/pi-coding-agent/dist/core/lsp/index.js.map +1 -1
  93. package/packages/pi-coding-agent/dist/core/sdk.d.ts +2 -2
  94. package/packages/pi-coding-agent/dist/core/sdk.d.ts.map +1 -1
  95. package/packages/pi-coding-agent/dist/core/sdk.js +8 -3
  96. package/packages/pi-coding-agent/dist/core/sdk.js.map +1 -1
  97. package/packages/pi-coding-agent/dist/core/settings-manager.d.ts +3 -0
  98. package/packages/pi-coding-agent/dist/core/settings-manager.d.ts.map +1 -1
  99. package/packages/pi-coding-agent/dist/core/settings-manager.js +8 -0
  100. package/packages/pi-coding-agent/dist/core/settings-manager.js.map +1 -1
  101. package/packages/pi-coding-agent/dist/core/slash-commands.d.ts.map +1 -1
  102. package/packages/pi-coding-agent/dist/core/slash-commands.js +1 -0
  103. package/packages/pi-coding-agent/dist/core/slash-commands.js.map +1 -1
  104. package/packages/pi-coding-agent/dist/core/system-prompt.d.ts.map +1 -1
  105. package/packages/pi-coding-agent/dist/core/system-prompt.js +2 -1
  106. package/packages/pi-coding-agent/dist/core/system-prompt.js.map +1 -1
  107. package/packages/pi-coding-agent/dist/index.d.ts +2 -1
  108. package/packages/pi-coding-agent/dist/index.d.ts.map +1 -1
  109. package/packages/pi-coding-agent/dist/index.js +5 -1
  110. package/packages/pi-coding-agent/dist/index.js.map +1 -1
  111. package/packages/pi-coding-agent/dist/modes/interactive/components/model-selector.d.ts +41 -3
  112. package/packages/pi-coding-agent/dist/modes/interactive/components/model-selector.d.ts.map +1 -1
  113. package/packages/pi-coding-agent/dist/modes/interactive/components/model-selector.js +301 -62
  114. package/packages/pi-coding-agent/dist/modes/interactive/components/model-selector.js.map +1 -1
  115. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  116. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js +17 -0
  117. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js.map +1 -1
  118. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts +5 -0
  119. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  120. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js +135 -30
  121. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
  122. package/packages/pi-coding-agent/dist/tests/path-display.test.d.ts +8 -0
  123. package/packages/pi-coding-agent/dist/tests/path-display.test.d.ts.map +1 -0
  124. package/packages/pi-coding-agent/dist/tests/path-display.test.js +60 -0
  125. package/packages/pi-coding-agent/dist/tests/path-display.test.js.map +1 -0
  126. package/packages/pi-coding-agent/dist/utils/clipboard-image.d.ts.map +1 -1
  127. package/packages/pi-coding-agent/dist/utils/clipboard-image.js +32 -6
  128. package/packages/pi-coding-agent/dist/utils/clipboard-image.js.map +1 -1
  129. package/packages/pi-coding-agent/dist/utils/path-display.d.ts +34 -0
  130. package/packages/pi-coding-agent/dist/utils/path-display.d.ts.map +1 -0
  131. package/packages/pi-coding-agent/dist/utils/path-display.js +36 -0
  132. package/packages/pi-coding-agent/dist/utils/path-display.js.map +1 -0
  133. package/packages/pi-coding-agent/src/core/agent-session.ts +36 -0
  134. package/packages/pi-coding-agent/src/core/keybindings.ts +1 -1
  135. package/packages/pi-coding-agent/src/core/lsp/client.ts +11 -1
  136. package/packages/pi-coding-agent/src/core/lsp/index.ts +7 -0
  137. package/packages/pi-coding-agent/src/core/sdk.ts +17 -1
  138. package/packages/pi-coding-agent/src/core/settings-manager.ts +11 -0
  139. package/packages/pi-coding-agent/src/core/slash-commands.ts +1 -0
  140. package/packages/pi-coding-agent/src/core/system-prompt.ts +2 -1
  141. package/packages/pi-coding-agent/src/index.ts +15 -0
  142. package/packages/pi-coding-agent/src/modes/interactive/components/model-selector.ts +347 -62
  143. package/packages/pi-coding-agent/src/modes/interactive/components/tool-execution.ts +18 -0
  144. package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +124 -4
  145. package/packages/pi-coding-agent/src/tests/path-display.test.ts +85 -0
  146. package/packages/pi-coding-agent/src/utils/clipboard-image.ts +33 -6
  147. package/packages/pi-coding-agent/src/utils/path-display.ts +36 -0
  148. package/src/resources/GSD-WORKFLOW.md +12 -9
  149. package/src/resources/extensions/async-jobs/index.ts +9 -1
  150. package/src/resources/extensions/bg-shell/index.ts +3 -2
  151. package/src/resources/extensions/bg-shell/overlay.ts +18 -17
  152. package/src/resources/extensions/get-secrets-from-user.ts +5 -23
  153. package/src/resources/extensions/gsd/activity-log.ts +5 -3
  154. package/src/resources/extensions/gsd/auto-prompts.ts +14 -0
  155. package/src/resources/extensions/gsd/auto-recovery.ts +7 -4
  156. package/src/resources/extensions/gsd/auto-worktree.ts +132 -3
  157. package/src/resources/extensions/gsd/auto.ts +265 -48
  158. package/src/resources/extensions/gsd/cache.ts +3 -1
  159. package/src/resources/extensions/gsd/doctor-proactive.ts +7 -6
  160. package/src/resources/extensions/gsd/doctor.ts +26 -1
  161. package/src/resources/extensions/gsd/files.ts +13 -2
  162. package/src/resources/extensions/gsd/git-service.ts +74 -14
  163. package/src/resources/extensions/gsd/gsd-db.ts +78 -1
  164. package/src/resources/extensions/gsd/guided-flow.ts +54 -22
  165. package/src/resources/extensions/gsd/index.ts +62 -8
  166. package/src/resources/extensions/gsd/memory-extractor.ts +352 -0
  167. package/src/resources/extensions/gsd/memory-store.ts +441 -0
  168. package/src/resources/extensions/gsd/migrate/command.ts +2 -2
  169. package/src/resources/extensions/gsd/migrate/writer.ts +39 -0
  170. package/src/resources/extensions/gsd/parallel-orchestrator.ts +122 -4
  171. package/src/resources/extensions/gsd/preferences.ts +2 -1
  172. package/src/resources/extensions/gsd/prompts/complete-slice.md +1 -1
  173. package/src/resources/extensions/gsd/prompts/discuss-headless.md +4 -4
  174. package/src/resources/extensions/gsd/prompts/discuss.md +5 -5
  175. package/src/resources/extensions/gsd/prompts/execute-task.md +1 -1
  176. package/src/resources/extensions/gsd/prompts/guided-discuss-milestone.md +1 -1
  177. package/src/resources/extensions/gsd/prompts/guided-discuss-slice.md +1 -1
  178. package/src/resources/extensions/gsd/prompts/plan-slice.md +1 -1
  179. package/src/resources/extensions/gsd/prompts/queue.md +3 -3
  180. package/src/resources/extensions/gsd/prompts/reassess-roadmap.md +1 -1
  181. package/src/resources/extensions/gsd/roadmap-slices.ts +45 -1
  182. package/src/resources/extensions/gsd/state.ts +17 -6
  183. package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +54 -0
  184. package/src/resources/extensions/gsd/tests/auto-worktree.test.ts +58 -0
  185. package/src/resources/extensions/gsd/tests/derive-state.test.ts +70 -0
  186. package/src/resources/extensions/gsd/tests/doctor-proactive.test.ts +23 -3
  187. package/src/resources/extensions/gsd/tests/git-service.test.ts +70 -4
  188. package/src/resources/extensions/gsd/tests/gsd-db.test.ts +2 -2
  189. package/src/resources/extensions/gsd/tests/md-importer.test.ts +2 -3
  190. package/src/resources/extensions/gsd/tests/memory-extractor.test.ts +180 -0
  191. package/src/resources/extensions/gsd/tests/memory-store.test.ts +345 -0
  192. package/src/resources/extensions/gsd/tests/migrate-writer-integration.test.ts +13 -7
  193. package/src/resources/extensions/gsd/tests/parallel-worker-monitoring.test.ts +171 -0
  194. package/src/resources/extensions/gsd/tests/smart-entry-draft.test.ts +1 -1
  195. package/src/resources/extensions/gsd/tests/validate-milestone.test.ts +8 -4
  196. package/src/resources/extensions/gsd/tests/visualizer-data.test.ts +147 -2
  197. package/src/resources/extensions/gsd/tests/visualizer-overlay.test.ts +88 -10
  198. package/src/resources/extensions/gsd/tests/visualizer-views.test.ts +314 -87
  199. package/src/resources/extensions/gsd/triage-ui.ts +1 -1
  200. package/src/resources/extensions/gsd/types.ts +2 -0
  201. package/src/resources/extensions/gsd/visualizer-data.ts +291 -10
  202. package/src/resources/extensions/gsd/visualizer-overlay.ts +237 -28
  203. package/src/resources/extensions/gsd/visualizer-views.ts +462 -48
  204. package/src/resources/extensions/gsd/worktree.ts +9 -2
  205. package/src/resources/extensions/search-the-web/native-search.ts +19 -5
  206. package/src/resources/extensions/shared/path-display.ts +19 -0
@@ -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
- async function loadChangelog(basePath: string, milestones: VisualizerMilestone[]): Promise<ChangelogInfo> {
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
- changelogCache.set(cacheKey, { mtime, entry });
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 loadChangelog(basePath, milestones);
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
  }