gsd-pi 2.38.0-dev.96dc7fb → 2.38.0-dev.98b44dc

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 (217) hide show
  1. package/README.md +15 -11
  2. package/dist/app-paths.js +1 -1
  3. package/dist/extension-registry.js +2 -2
  4. package/dist/remote-questions-config.js +2 -2
  5. package/dist/resource-loader.js +34 -1
  6. package/dist/resources/extensions/browser-tools/index.js +3 -1
  7. package/dist/resources/extensions/browser-tools/tools/verify.js +97 -0
  8. package/dist/resources/extensions/env-utils.js +29 -0
  9. package/dist/resources/extensions/get-secrets-from-user.js +5 -24
  10. package/dist/resources/extensions/github-sync/cli.js +284 -0
  11. package/dist/resources/extensions/github-sync/index.js +73 -0
  12. package/dist/resources/extensions/github-sync/mapping.js +67 -0
  13. package/dist/resources/extensions/github-sync/sync.js +424 -0
  14. package/dist/resources/extensions/github-sync/templates.js +118 -0
  15. package/dist/resources/extensions/github-sync/types.js +7 -0
  16. package/dist/resources/extensions/gsd/auto/session.js +6 -23
  17. package/dist/resources/extensions/gsd/auto-dispatch.js +8 -9
  18. package/dist/resources/extensions/gsd/auto-loop.js +636 -594
  19. package/dist/resources/extensions/gsd/auto-post-unit.js +99 -70
  20. package/dist/resources/extensions/gsd/auto-prompts.js +202 -48
  21. package/dist/resources/extensions/gsd/auto-start.js +7 -1
  22. package/dist/resources/extensions/gsd/auto-worktree-sync.js +2 -1
  23. package/dist/resources/extensions/gsd/auto-worktree.js +3 -3
  24. package/dist/resources/extensions/gsd/auto.js +143 -96
  25. package/dist/resources/extensions/gsd/commands-extensions.js +3 -2
  26. package/dist/resources/extensions/gsd/commands-prefs-wizard.js +1 -1
  27. package/dist/resources/extensions/gsd/commands.js +4 -2
  28. package/dist/resources/extensions/gsd/context-budget.js +2 -10
  29. package/dist/resources/extensions/gsd/detection.js +1 -2
  30. package/dist/resources/extensions/gsd/docs/preferences-reference.md +0 -2
  31. package/dist/resources/extensions/gsd/doctor-providers.js +30 -11
  32. package/dist/resources/extensions/gsd/doctor.js +20 -1
  33. package/dist/resources/extensions/gsd/exit-command.js +2 -1
  34. package/dist/resources/extensions/gsd/export.js +1 -1
  35. package/dist/resources/extensions/gsd/files.js +48 -9
  36. package/dist/resources/extensions/gsd/forensics.js +1 -1
  37. package/dist/resources/extensions/gsd/git-service.js +30 -12
  38. package/dist/resources/extensions/gsd/gitignore.js +16 -3
  39. package/dist/resources/extensions/gsd/guided-flow.js +149 -38
  40. package/dist/resources/extensions/gsd/health-widget-core.js +32 -70
  41. package/dist/resources/extensions/gsd/health-widget.js +3 -86
  42. package/dist/resources/extensions/gsd/index.js +24 -20
  43. package/dist/resources/extensions/gsd/migrate/parsers.js +1 -1
  44. package/dist/resources/extensions/gsd/migrate-external.js +18 -1
  45. package/dist/resources/extensions/gsd/native-git-bridge.js +37 -0
  46. package/dist/resources/extensions/gsd/paths.js +3 -0
  47. package/dist/resources/extensions/gsd/preferences-models.js +0 -12
  48. package/dist/resources/extensions/gsd/preferences-types.js +1 -1
  49. package/dist/resources/extensions/gsd/preferences-validation.js +59 -11
  50. package/dist/resources/extensions/gsd/preferences.js +22 -11
  51. package/dist/resources/extensions/gsd/prompt-loader.js +6 -2
  52. package/dist/resources/extensions/gsd/prompts/complete-milestone.md +1 -1
  53. package/dist/resources/extensions/gsd/prompts/complete-slice.md +1 -1
  54. package/dist/resources/extensions/gsd/prompts/discuss.md +11 -14
  55. package/dist/resources/extensions/gsd/prompts/execute-task.md +5 -3
  56. package/dist/resources/extensions/gsd/prompts/guided-complete-slice.md +1 -1
  57. package/dist/resources/extensions/gsd/prompts/guided-discuss-milestone.md +11 -12
  58. package/dist/resources/extensions/gsd/prompts/guided-discuss-slice.md +8 -10
  59. package/dist/resources/extensions/gsd/prompts/guided-execute-task.md +1 -1
  60. package/dist/resources/extensions/gsd/prompts/guided-plan-milestone.md +1 -1
  61. package/dist/resources/extensions/gsd/prompts/guided-plan-slice.md +1 -1
  62. package/dist/resources/extensions/gsd/prompts/guided-research-slice.md +1 -1
  63. package/dist/resources/extensions/gsd/prompts/guided-resume-task.md +1 -1
  64. package/dist/resources/extensions/gsd/prompts/plan-milestone.md +1 -1
  65. package/dist/resources/extensions/gsd/prompts/plan-slice.md +1 -1
  66. package/dist/resources/extensions/gsd/prompts/queue.md +4 -8
  67. package/dist/resources/extensions/gsd/prompts/reactive-execute.md +11 -8
  68. package/dist/resources/extensions/gsd/prompts/reassess-roadmap.md +1 -1
  69. package/dist/resources/extensions/gsd/prompts/research-milestone.md +1 -1
  70. package/dist/resources/extensions/gsd/prompts/research-slice.md +1 -1
  71. package/dist/resources/extensions/gsd/prompts/run-uat.md +28 -11
  72. package/dist/resources/extensions/gsd/prompts/workflow-start.md +2 -2
  73. package/dist/resources/extensions/gsd/repo-identity.js +21 -4
  74. package/dist/resources/extensions/gsd/resource-version.js +2 -1
  75. package/dist/resources/extensions/gsd/roadmap-mutations.js +24 -0
  76. package/dist/resources/extensions/gsd/state.js +42 -23
  77. package/dist/resources/extensions/gsd/templates/runtime.md +21 -0
  78. package/dist/resources/extensions/gsd/templates/task-plan.md +3 -0
  79. package/dist/resources/extensions/gsd/visualizer-data.js +1 -1
  80. package/dist/resources/extensions/mcp-client/index.js +14 -1
  81. package/dist/resources/extensions/remote-questions/status.js +4 -1
  82. package/dist/resources/extensions/remote-questions/store.js +4 -1
  83. package/dist/resources/extensions/search-the-web/provider.js +2 -1
  84. package/dist/resources/extensions/shared/frontmatter.js +1 -1
  85. package/dist/resources/extensions/subagent/isolation.js +2 -1
  86. package/dist/resources/extensions/ttsr/rule-loader.js +2 -1
  87. package/package.json +1 -1
  88. package/packages/pi-ai/dist/utils/oauth/anthropic.js +2 -2
  89. package/packages/pi-ai/dist/utils/oauth/anthropic.js.map +1 -1
  90. package/packages/pi-ai/src/utils/oauth/anthropic.ts +2 -2
  91. package/packages/pi-coding-agent/dist/core/extensions/loader.d.ts.map +1 -1
  92. package/packages/pi-coding-agent/dist/core/extensions/loader.js +205 -7
  93. package/packages/pi-coding-agent/dist/core/extensions/loader.js.map +1 -1
  94. package/packages/pi-coding-agent/dist/core/skills.d.ts +1 -0
  95. package/packages/pi-coding-agent/dist/core/skills.d.ts.map +1 -1
  96. package/packages/pi-coding-agent/dist/core/skills.js +6 -1
  97. package/packages/pi-coding-agent/dist/core/skills.js.map +1 -1
  98. package/packages/pi-coding-agent/dist/index.d.ts +1 -1
  99. package/packages/pi-coding-agent/dist/index.d.ts.map +1 -1
  100. package/packages/pi-coding-agent/dist/index.js +1 -1
  101. package/packages/pi-coding-agent/dist/index.js.map +1 -1
  102. package/packages/pi-coding-agent/src/core/extensions/loader.ts +223 -7
  103. package/packages/pi-coding-agent/src/core/skills.ts +9 -1
  104. package/packages/pi-coding-agent/src/index.ts +1 -0
  105. package/src/resources/extensions/browser-tools/index.ts +3 -0
  106. package/src/resources/extensions/browser-tools/tools/verify.ts +117 -0
  107. package/src/resources/extensions/env-utils.ts +31 -0
  108. package/src/resources/extensions/get-secrets-from-user.ts +5 -24
  109. package/src/resources/extensions/github-sync/cli.ts +364 -0
  110. package/src/resources/extensions/github-sync/index.ts +93 -0
  111. package/src/resources/extensions/github-sync/mapping.ts +81 -0
  112. package/src/resources/extensions/github-sync/sync.ts +556 -0
  113. package/src/resources/extensions/github-sync/templates.ts +183 -0
  114. package/src/resources/extensions/github-sync/tests/cli.test.ts +20 -0
  115. package/src/resources/extensions/github-sync/tests/commit-linking.test.ts +39 -0
  116. package/src/resources/extensions/github-sync/tests/mapping.test.ts +104 -0
  117. package/src/resources/extensions/github-sync/tests/templates.test.ts +110 -0
  118. package/src/resources/extensions/github-sync/types.ts +47 -0
  119. package/src/resources/extensions/gsd/auto/session.ts +7 -25
  120. package/src/resources/extensions/gsd/auto-dispatch.ts +7 -9
  121. package/src/resources/extensions/gsd/auto-loop.ts +526 -545
  122. package/src/resources/extensions/gsd/auto-post-unit.ts +80 -44
  123. package/src/resources/extensions/gsd/auto-prompts.ts +247 -50
  124. package/src/resources/extensions/gsd/auto-start.ts +11 -1
  125. package/src/resources/extensions/gsd/auto-worktree-sync.ts +3 -1
  126. package/src/resources/extensions/gsd/auto-worktree.ts +3 -3
  127. package/src/resources/extensions/gsd/auto.ts +139 -101
  128. package/src/resources/extensions/gsd/commands-extensions.ts +4 -2
  129. package/src/resources/extensions/gsd/commands-prefs-wizard.ts +1 -1
  130. package/src/resources/extensions/gsd/commands.ts +5 -3
  131. package/src/resources/extensions/gsd/context-budget.ts +2 -12
  132. package/src/resources/extensions/gsd/detection.ts +2 -2
  133. package/src/resources/extensions/gsd/docs/preferences-reference.md +0 -2
  134. package/src/resources/extensions/gsd/doctor-providers.ts +30 -9
  135. package/src/resources/extensions/gsd/doctor.ts +22 -1
  136. package/src/resources/extensions/gsd/exit-command.ts +2 -2
  137. package/src/resources/extensions/gsd/export.ts +1 -1
  138. package/src/resources/extensions/gsd/files.ts +51 -11
  139. package/src/resources/extensions/gsd/forensics.ts +1 -1
  140. package/src/resources/extensions/gsd/git-service.ts +44 -10
  141. package/src/resources/extensions/gsd/gitignore.ts +17 -3
  142. package/src/resources/extensions/gsd/guided-flow.ts +177 -44
  143. package/src/resources/extensions/gsd/health-widget-core.ts +28 -80
  144. package/src/resources/extensions/gsd/health-widget.ts +3 -89
  145. package/src/resources/extensions/gsd/index.ts +24 -17
  146. package/src/resources/extensions/gsd/migrate/parsers.ts +1 -1
  147. package/src/resources/extensions/gsd/migrate-external.ts +18 -1
  148. package/src/resources/extensions/gsd/native-git-bridge.ts +37 -0
  149. package/src/resources/extensions/gsd/paths.ts +4 -0
  150. package/src/resources/extensions/gsd/preferences-models.ts +0 -12
  151. package/src/resources/extensions/gsd/preferences-types.ts +4 -4
  152. package/src/resources/extensions/gsd/preferences-validation.ts +51 -11
  153. package/src/resources/extensions/gsd/preferences.ts +25 -11
  154. package/src/resources/extensions/gsd/prompt-loader.ts +7 -2
  155. package/src/resources/extensions/gsd/prompts/complete-milestone.md +1 -1
  156. package/src/resources/extensions/gsd/prompts/complete-slice.md +1 -1
  157. package/src/resources/extensions/gsd/prompts/discuss.md +11 -14
  158. package/src/resources/extensions/gsd/prompts/execute-task.md +5 -3
  159. package/src/resources/extensions/gsd/prompts/guided-complete-slice.md +1 -1
  160. package/src/resources/extensions/gsd/prompts/guided-discuss-milestone.md +11 -12
  161. package/src/resources/extensions/gsd/prompts/guided-discuss-slice.md +8 -10
  162. package/src/resources/extensions/gsd/prompts/guided-execute-task.md +1 -1
  163. package/src/resources/extensions/gsd/prompts/guided-plan-milestone.md +1 -1
  164. package/src/resources/extensions/gsd/prompts/guided-plan-slice.md +1 -1
  165. package/src/resources/extensions/gsd/prompts/guided-research-slice.md +1 -1
  166. package/src/resources/extensions/gsd/prompts/guided-resume-task.md +1 -1
  167. package/src/resources/extensions/gsd/prompts/plan-milestone.md +1 -1
  168. package/src/resources/extensions/gsd/prompts/plan-slice.md +1 -1
  169. package/src/resources/extensions/gsd/prompts/queue.md +4 -8
  170. package/src/resources/extensions/gsd/prompts/reactive-execute.md +11 -8
  171. package/src/resources/extensions/gsd/prompts/reassess-roadmap.md +1 -1
  172. package/src/resources/extensions/gsd/prompts/research-milestone.md +1 -1
  173. package/src/resources/extensions/gsd/prompts/research-slice.md +1 -1
  174. package/src/resources/extensions/gsd/prompts/run-uat.md +28 -11
  175. package/src/resources/extensions/gsd/prompts/workflow-start.md +2 -2
  176. package/src/resources/extensions/gsd/repo-identity.ts +23 -4
  177. package/src/resources/extensions/gsd/resource-version.ts +3 -1
  178. package/src/resources/extensions/gsd/roadmap-mutations.ts +29 -0
  179. package/src/resources/extensions/gsd/state.ts +39 -21
  180. package/src/resources/extensions/gsd/templates/runtime.md +21 -0
  181. package/src/resources/extensions/gsd/templates/task-plan.md +3 -0
  182. package/src/resources/extensions/gsd/tests/agent-end-retry.test.ts +21 -18
  183. package/src/resources/extensions/gsd/tests/auto-loop.test.ts +122 -68
  184. package/src/resources/extensions/gsd/tests/auto-worktree-milestone-merge.test.ts +4 -3
  185. package/src/resources/extensions/gsd/tests/derive-state.test.ts +43 -0
  186. package/src/resources/extensions/gsd/tests/doctor-providers.test.ts +86 -3
  187. package/src/resources/extensions/gsd/tests/gitignore-tracked-gsd.test.ts +50 -0
  188. package/src/resources/extensions/gsd/tests/health-widget.test.ts +16 -54
  189. package/src/resources/extensions/gsd/tests/parsers.test.ts +131 -14
  190. package/src/resources/extensions/gsd/tests/plan-slice-prompt.test.ts +209 -0
  191. package/src/resources/extensions/gsd/tests/preferences.test.ts +2 -7
  192. package/src/resources/extensions/gsd/tests/prompt-contracts.test.ts +59 -0
  193. package/src/resources/extensions/gsd/tests/repo-identity-worktree.test.ts +21 -1
  194. package/src/resources/extensions/gsd/tests/run-uat.test.ts +16 -4
  195. package/src/resources/extensions/gsd/tests/skill-activation.test.ts +140 -0
  196. package/src/resources/extensions/gsd/types.ts +18 -1
  197. package/src/resources/extensions/gsd/verification-evidence.ts +16 -0
  198. package/src/resources/extensions/gsd/visualizer-data.ts +1 -1
  199. package/src/resources/extensions/mcp-client/index.ts +17 -1
  200. package/src/resources/extensions/remote-questions/status.ts +5 -1
  201. package/src/resources/extensions/remote-questions/store.ts +5 -1
  202. package/src/resources/extensions/search-the-web/provider.ts +2 -1
  203. package/src/resources/extensions/shared/frontmatter.ts +1 -1
  204. package/src/resources/extensions/subagent/isolation.ts +3 -1
  205. package/src/resources/extensions/ttsr/rule-loader.ts +3 -1
  206. package/dist/resources/extensions/gsd/prompt-compressor.js +0 -393
  207. package/dist/resources/extensions/gsd/semantic-chunker.js +0 -254
  208. package/dist/resources/extensions/gsd/summary-distiller.js +0 -212
  209. package/src/resources/extensions/gsd/prompt-compressor.ts +0 -508
  210. package/src/resources/extensions/gsd/semantic-chunker.ts +0 -336
  211. package/src/resources/extensions/gsd/summary-distiller.ts +0 -258
  212. package/src/resources/extensions/gsd/tests/context-compression.test.ts +0 -193
  213. package/src/resources/extensions/gsd/tests/prompt-compressor.test.ts +0 -529
  214. package/src/resources/extensions/gsd/tests/semantic-chunker.test.ts +0 -426
  215. package/src/resources/extensions/gsd/tests/summary-distiller.test.ts +0 -323
  216. package/src/resources/extensions/gsd/tests/token-optimization-benchmark.test.ts +0 -1272
  217. package/src/resources/extensions/gsd/tests/token-optimization-prefs.test.ts +0 -164
@@ -1,323 +0,0 @@
1
- /**
2
- * Tests for summary-distiller.ts — the summary distillation module.
3
- * Verifies frontmatter extraction, compact formatting, budget enforcement,
4
- * and progressive field dropping.
5
- */
6
-
7
- import { describe, it } from "node:test";
8
- import assert from "node:assert/strict";
9
-
10
- import { distillSingle, distillSummaries } from "../summary-distiller.js";
11
-
12
- // ─── Fixtures ────────────────────────────────────────────────────────────────
13
-
14
- const REALISTIC_SUMMARY = `---
15
- id: S01
16
- parent: M001
17
- milestone: M001
18
- provides:
19
- - Core type definitions
20
- - File I/O utilities
21
- requires: []
22
- affects:
23
- - All downstream slices
24
- key_files:
25
- - src/types.ts
26
- - src/files.ts
27
- - src/paths.ts
28
- key_decisions:
29
- - D001
30
- - D003
31
- patterns_established:
32
- - Pure function modules
33
- - Dependency injection via parameters
34
- drill_down_paths:
35
- - src/types.ts for interface contracts
36
- observability_surfaces:
37
- - Unit test coverage > 90%
38
- duration: 45m
39
- verification_result: pass
40
- completed_at: 2025-03-15T10:00:00Z
41
- blocker_discovered: false
42
- ---
43
-
44
- # S01: Core Type Definitions and File I/O
45
-
46
- Foundation types and file operations for the GSD extension.
47
-
48
- ## What Happened
49
-
50
- Implemented 12 core interfaces spanning roadmap parsing, slice plans, summaries,
51
- and continuation state. Added file I/O utilities for reading, parsing, and writing
52
- GSD artifact files. Established the path resolution module for computing absolute
53
- and relative paths to milestone, slice, and task artifacts.
54
-
55
- ## Deviations
56
-
57
- Minor deviation from plan: added \`filesModified\` field to Summary interface that
58
- was not in the original design, based on the realization that tracking modified
59
- files in summaries enables better diff-context prioritization.
60
-
61
- ## Files Modified
62
-
63
- - \`src/types.ts\` — 12 interfaces, 4 type aliases
64
- - \`src/files.ts\` — 8 parser functions, 3 writer functions
65
- - \`src/paths.ts\` — 14 path resolver functions
66
- `;
67
-
68
- const SECOND_SUMMARY = `---
69
- id: S02
70
- parent: M001
71
- milestone: M001
72
- provides:
73
- - Roadmap parser
74
- - Slice dependency resolver
75
- requires:
76
- - Core type definitions
77
- key_files:
78
- - src/roadmap.ts
79
- - src/deps.ts
80
- key_decisions:
81
- - D004
82
- patterns_established:
83
- - DAG-based ordering
84
- drill_down_paths:
85
- - src/deps.ts for topological sort
86
- duration: 30m
87
- verification_result: pass
88
- completed_at: 2025-03-15T11:00:00Z
89
- ---
90
-
91
- # S02: Roadmap Parser and Dependency Resolution
92
-
93
- Built the roadmap parser and DAG-based dependency resolver.
94
-
95
- ## What Happened
96
-
97
- Created a Markdown-based roadmap parser that extracts slice metadata from
98
- structured headings and bullet lists. Implemented a topological sort for
99
- resolving slice execution order based on declared dependencies.
100
-
101
- ## Files Modified
102
-
103
- - \`src/roadmap.ts\` — parser with regex-based extraction
104
- - \`src/deps.ts\` — DAG builder and topological sort
105
- `;
106
-
107
- const NO_FRONTMATTER = `# S99: Quick Fix
108
-
109
- A quick patch with no frontmatter at all.
110
-
111
- ## What Happened
112
-
113
- Fixed a typo.
114
- `;
115
-
116
- const EMPTY_ARRAYS_SUMMARY = `---
117
- id: S03
118
- provides: []
119
- requires: []
120
- key_files: []
121
- key_decisions: []
122
- patterns_established: []
123
- ---
124
-
125
- # S03: Empty Slice
126
-
127
- Nothing to provide or require.
128
- `;
129
-
130
- // ─── distillSingle ──────────────────────────────────────────────────────────
131
-
132
- describe("summary-distiller: distillSingle", () => {
133
- it("extracts frontmatter fields from a realistic summary", () => {
134
- const result = distillSingle(REALISTIC_SUMMARY);
135
- assert.ok(result.includes("## S01:"), "should include the id header");
136
- assert.ok(result.includes("provides: Core type definitions, File I/O utilities"),
137
- "should list provides");
138
- assert.ok(result.includes("key_files: src/types.ts, src/files.ts, src/paths.ts"),
139
- "should list key_files");
140
- assert.ok(result.includes("key_decisions: D001, D003"),
141
- "should list key_decisions");
142
- assert.ok(result.includes("patterns: Pure function modules, Dependency injection via parameters"),
143
- "should list patterns");
144
- });
145
-
146
- it("extracts the one-liner from the title line", () => {
147
- const result = distillSingle(REALISTIC_SUMMARY);
148
- // The title line "# S01: Core Type Definitions and File I/O" provides the one-liner
149
- assert.ok(
150
- result.includes("Core Type Definitions and File I/O"),
151
- "should include one-liner from title",
152
- );
153
- });
154
-
155
- it("falls back to first paragraph when title has no inline text", () => {
156
- const summary = `---
157
- id: S10
158
- provides:
159
- - Widget API
160
- ---
161
-
162
- # S10:
163
-
164
- Widget API for rendering dashboard components.
165
-
166
- ## What Happened
167
-
168
- Built the widget system.
169
- `;
170
- const result = distillSingle(summary);
171
- assert.ok(
172
- result.includes("Widget API for rendering"),
173
- "should use first paragraph as one-liner when title text is empty",
174
- );
175
- });
176
-
177
- it("drops verbose prose sections", () => {
178
- const result = distillSingle(REALISTIC_SUMMARY);
179
- assert.ok(!result.includes("What Happened"), "should not include What Happened heading");
180
- assert.ok(!result.includes("Implemented 12 core"), "should not include prose body");
181
- assert.ok(!result.includes("Deviations"), "should not include Deviations");
182
- assert.ok(!result.includes("filesModified"), "should not include deviation details");
183
- assert.ok(!result.includes("drill_down_paths"), "should not include drill_down_paths label");
184
- assert.ok(!result.includes("duration"), "should not include duration");
185
- assert.ok(!result.includes("verification_result"), "should not include verification_result");
186
- assert.ok(!result.includes("completed_at"), "should not include completed_at");
187
- });
188
-
189
- it("handles array fields in provides/requires", () => {
190
- const result = distillSingle(SECOND_SUMMARY);
191
- assert.ok(result.includes("provides: Roadmap parser, Slice dependency resolver"),
192
- "should join provides array");
193
- assert.ok(result.includes("requires: Core type definitions"),
194
- "should join requires array");
195
- });
196
-
197
- it("omits empty requires when none declared", () => {
198
- const result = distillSingle(REALISTIC_SUMMARY);
199
- assert.ok(!result.includes("requires:"), "should omit requires when empty");
200
- });
201
-
202
- it("handles missing frontmatter gracefully", () => {
203
- const result = distillSingle(NO_FRONTMATTER);
204
- assert.ok(result.includes("## S99:"), "should extract id from title");
205
- assert.ok(result.includes("Quick Fix"), "should include title text");
206
- });
207
-
208
- it("handles empty array frontmatter fields", () => {
209
- const result = distillSingle(EMPTY_ARRAYS_SUMMARY);
210
- assert.ok(result.includes("## S03:"), "should have the id");
211
- assert.ok(!result.includes("provides:"), "should omit empty provides");
212
- assert.ok(!result.includes("requires:"), "should omit empty requires");
213
- assert.ok(!result.includes("key_files:"), "should omit empty key_files");
214
- assert.ok(!result.includes("key_decisions:"), "should omit empty key_decisions");
215
- assert.ok(!result.includes("patterns:"), "should omit empty patterns");
216
- });
217
-
218
- it("produces significantly shorter output than input", () => {
219
- const result = distillSingle(REALISTIC_SUMMARY);
220
- assert.ok(
221
- result.length < REALISTIC_SUMMARY.length * 0.5,
222
- `distilled (${result.length}) should be <50% of original (${REALISTIC_SUMMARY.length})`,
223
- );
224
- });
225
- });
226
-
227
- // ─── distillSummaries ────────────────────────────────────────────────────────
228
-
229
- describe("summary-distiller: distillSummaries", () => {
230
- it("combines multiple summaries into structured blocks", () => {
231
- const result = distillSummaries([REALISTIC_SUMMARY, SECOND_SUMMARY], 10_000);
232
- assert.equal(result.summaryCount, 2);
233
- assert.ok(result.content.includes("## S01:"), "should include first summary");
234
- assert.ok(result.content.includes("## S02:"), "should include second summary");
235
- });
236
-
237
- it("reports positive savings percentage", () => {
238
- const result = distillSummaries([REALISTIC_SUMMARY, SECOND_SUMMARY], 10_000);
239
- assert.ok(result.savingsPercent > 0, `savings should be positive, got ${result.savingsPercent}%`);
240
- assert.ok(result.distilledChars < result.originalChars,
241
- "distilled chars should be less than original");
242
- });
243
-
244
- it("fits content within budgetChars when budget is generous", () => {
245
- const result = distillSummaries([REALISTIC_SUMMARY, SECOND_SUMMARY], 10_000);
246
- assert.ok(
247
- result.content.length <= 10_000,
248
- `content length ${result.content.length} should be within budget 10000`,
249
- );
250
- assert.ok(!result.content.includes("[...truncated]"), "should not truncate with generous budget");
251
- });
252
-
253
- it("enforces budget with truncation when needed", () => {
254
- const result = distillSummaries([REALISTIC_SUMMARY, SECOND_SUMMARY], 200);
255
- assert.ok(
256
- result.content.length <= 215, // allow some slack for truncation marker
257
- `content length ${result.content.length} should be near budget 200`,
258
- );
259
- assert.ok(result.content.includes("[...truncated]"), "should include truncation marker");
260
- });
261
-
262
- it("progressively drops fields when budget is tight", () => {
263
- // With a budget that can fit the header lines but not all fields,
264
- // patterns should be dropped first, then key_decisions, then key_files
265
- const full = distillSummaries([REALISTIC_SUMMARY], 100_000);
266
- assert.ok(full.content.includes("patterns:"), "full output should have patterns");
267
-
268
- // Find a budget that forces dropping patterns but keeps key_decisions
269
- const withoutPatterns = full.content.replace(/patterns:.*$/m, "").length;
270
- const withPatterns = full.content.length;
271
-
272
- if (withPatterns > withoutPatterns) {
273
- const tightBudget = withoutPatterns + 5;
274
- const tight = distillSummaries([REALISTIC_SUMMARY], tightBudget);
275
- assert.ok(!tight.content.includes("patterns:"),
276
- "tight budget should drop patterns first");
277
- assert.ok(tight.content.includes("key_decisions:"),
278
- "tight budget should still have key_decisions");
279
- }
280
- });
281
-
282
- it("handles a single summary", () => {
283
- const result = distillSummaries([REALISTIC_SUMMARY], 10_000);
284
- assert.equal(result.summaryCount, 1);
285
- assert.ok(result.content.includes("## S01:"), "should include the single summary");
286
- });
287
-
288
- it("handles empty input array", () => {
289
- const result = distillSummaries([], 10_000);
290
- assert.equal(result.summaryCount, 0);
291
- assert.equal(result.content, "");
292
- assert.equal(result.savingsPercent, 0);
293
- assert.equal(result.originalChars, 0);
294
- assert.equal(result.distilledChars, 0);
295
- });
296
-
297
- it("handles malformed content gracefully", () => {
298
- const malformed = "this is not a valid summary at all\nno frontmatter\nno headings";
299
- const result = distillSummaries([malformed], 10_000);
300
- assert.equal(result.summaryCount, 1);
301
- // Should not throw, should produce some output
302
- assert.ok(result.content.length > 0, "should produce output even for malformed input");
303
- });
304
-
305
- it("handles very tight budget (100 chars) with truncation", () => {
306
- const result = distillSummaries([REALISTIC_SUMMARY, SECOND_SUMMARY], 100);
307
- assert.ok(
308
- result.content.length <= 115, // small slack for marker
309
- `content (${result.content.length}) should be near budget 100`,
310
- );
311
- assert.ok(result.content.includes("[...truncated]"), "should truncate at very tight budget");
312
- assert.ok(result.savingsPercent > 80, `savings should be very high, got ${result.savingsPercent}%`);
313
- });
314
-
315
- it("tracks original and distilled character counts accurately", () => {
316
- const summaries = [REALISTIC_SUMMARY, SECOND_SUMMARY];
317
- const totalOriginal = summaries.reduce((s, c) => s + c.length, 0);
318
- const result = distillSummaries(summaries, 10_000);
319
- assert.equal(result.originalChars, totalOriginal, "originalChars should match input total");
320
- assert.equal(result.distilledChars, result.content.length,
321
- "distilledChars should match content length");
322
- });
323
- });