gsd-pi 2.77.0-dev.1d17f366c → 2.77.0-dev.2daa994b6

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 (368) hide show
  1. package/dist/headless.js +25 -4
  2. package/dist/resource-loader.d.ts +40 -0
  3. package/dist/resource-loader.js +32 -13
  4. package/dist/resources/extensions/browser-tools/capture.js +9 -0
  5. package/dist/resources/extensions/browser-tools/tests/browser-tools-integration.test.mjs +8 -59
  6. package/dist/resources/extensions/browser-tools/tests/browser-tools-unit.test.cjs +36 -24
  7. package/dist/resources/extensions/browser-tools/tests/capture-sharp-optional.test.cjs +69 -71
  8. package/dist/resources/extensions/browser-tools/tools/forms.js +5 -1
  9. package/dist/resources/extensions/browser-tools/tools/intent.js +5 -1
  10. package/dist/resources/extensions/gsd/auto/phases.js +5 -18
  11. package/dist/resources/extensions/gsd/auto/session.js +6 -0
  12. package/dist/resources/extensions/gsd/auto-dispatch.js +37 -8
  13. package/dist/resources/extensions/gsd/auto-post-unit.js +79 -0
  14. package/dist/resources/extensions/gsd/auto-prompts.js +372 -104
  15. package/dist/resources/extensions/gsd/auto-start.js +75 -24
  16. package/dist/resources/extensions/gsd/auto.js +34 -0
  17. package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +9 -1
  18. package/dist/resources/extensions/gsd/bootstrap/write-gate.js +7 -1
  19. package/dist/resources/extensions/gsd/component-loader.js +447 -0
  20. package/dist/resources/extensions/gsd/component-types.js +69 -0
  21. package/dist/resources/extensions/gsd/context-store.js +23 -7
  22. package/dist/resources/extensions/gsd/detection.js +49 -1
  23. package/dist/resources/extensions/gsd/docs/preferences-reference.md +1 -1
  24. package/dist/resources/extensions/gsd/forensics.js +106 -0
  25. package/dist/resources/extensions/gsd/gsd-db.js +1 -1
  26. package/dist/resources/extensions/gsd/guided-flow.js +2 -4
  27. package/dist/resources/extensions/gsd/memory-extractor.js +7 -1
  28. package/dist/resources/extensions/gsd/milestone-scope-classifier.js +299 -0
  29. package/dist/resources/extensions/gsd/model-cost-table.js +3 -0
  30. package/dist/resources/extensions/gsd/model-router.js +6 -0
  31. package/dist/resources/extensions/gsd/preferences-validation.js +23 -0
  32. package/dist/resources/extensions/gsd/prompt-cache-optimizer.js +4 -0
  33. package/dist/resources/extensions/gsd/prompts/complete-milestone.md +5 -1
  34. package/dist/resources/extensions/gsd/prompts/plan-slice.md +15 -2
  35. package/dist/resources/extensions/gsd/service-tier.js +5 -2
  36. package/dist/resources/extensions/gsd/skill-manifest.js +168 -0
  37. package/dist/resources/extensions/gsd/slice-cadence.js +238 -0
  38. package/dist/resources/extensions/gsd/tools/validate-milestone.js +7 -2
  39. package/dist/resources/extensions/gsd/unit-context-composer.js +147 -0
  40. package/dist/resources/extensions/gsd/unit-context-manifest.js +334 -0
  41. package/dist/resources/extensions/gsd/worktree-manager.js +51 -0
  42. package/dist/resources/extensions/gsd/worktree-resolver.js +86 -7
  43. package/dist/resources/extensions/gsd/worktree-telemetry.js +198 -0
  44. package/dist/resources/extensions/mcp-client/index.js +3 -1
  45. package/dist/resources/extensions/ollama/index.js +5 -1
  46. package/dist/resources/extensions/remote-questions/manager.js +11 -5
  47. package/dist/tsconfig.extensions.tsbuildinfo +1 -1
  48. package/dist/web/standalone/.next/BUILD_ID +1 -1
  49. package/dist/web/standalone/.next/app-path-routes-manifest.json +17 -17
  50. package/dist/web/standalone/.next/build-manifest.json +2 -2
  51. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  52. package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
  53. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  54. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  55. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  56. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  57. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  58. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  59. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  60. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  61. package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
  62. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
  63. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  64. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
  65. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  66. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  67. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  68. package/dist/web/standalone/.next/server/app/index.html +1 -1
  69. package/dist/web/standalone/.next/server/app/index.rsc +1 -1
  70. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
  71. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +1 -1
  72. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  73. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
  74. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  75. package/dist/web/standalone/.next/server/app-paths-manifest.json +17 -17
  76. package/dist/web/standalone/.next/server/chunks/6897.js +1 -1
  77. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  78. package/dist/web/standalone/.next/server/middleware-manifest.json +5 -5
  79. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  80. package/dist/web/standalone/.next/server/pages/500.html +1 -1
  81. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  82. package/package.json +1 -3
  83. package/packages/mcp-server/src/mcp-server.test.ts +25 -3
  84. package/packages/mcp-server/src/readers/graph.test.ts +87 -15
  85. package/packages/mcp-server/src/workflow-tools.test.ts +80 -39
  86. package/packages/native/package.json +1 -1
  87. package/packages/native/src/__tests__/_test-coverage-guard.test.mjs +98 -0
  88. package/packages/native/src/__tests__/module-compat.test.mjs +59 -27
  89. package/packages/native/src/__tests__/ps.test.mjs +14 -8
  90. package/packages/native/src/__tests__/stream-process.test.mjs +23 -2
  91. package/packages/native/src/__tests__/truncate.test.mjs +17 -2
  92. package/packages/pi-agent-core/src/agent-loop.test.ts +5 -15
  93. package/packages/pi-agent-core/src/agent.test.ts +96 -102
  94. package/packages/pi-agent-core/tsconfig.tsbuildinfo +1 -1
  95. package/packages/pi-ai/dist/models/generated/index.d.ts +34 -0
  96. package/packages/pi-ai/dist/models/generated/index.d.ts.map +1 -1
  97. package/packages/pi-ai/dist/models/generated/openai-codex.d.ts +17 -0
  98. package/packages/pi-ai/dist/models/generated/openai-codex.d.ts.map +1 -1
  99. package/packages/pi-ai/dist/models/generated/openai-codex.js +17 -0
  100. package/packages/pi-ai/dist/models/generated/openai-codex.js.map +1 -1
  101. package/packages/pi-ai/dist/models/generated/openai.d.ts +17 -0
  102. package/packages/pi-ai/dist/models/generated/openai.d.ts.map +1 -1
  103. package/packages/pi-ai/dist/models/generated/openai.js +17 -0
  104. package/packages/pi-ai/dist/models/generated/openai.js.map +1 -1
  105. package/packages/pi-ai/dist/models.generated.test.js +43 -70
  106. package/packages/pi-ai/dist/models.generated.test.js.map +1 -1
  107. package/packages/pi-ai/dist/models.test.js +29 -11
  108. package/packages/pi-ai/dist/models.test.js.map +1 -1
  109. package/packages/pi-ai/scripts/generate-models.ts +44 -0
  110. package/packages/pi-ai/src/models/generated/openai-codex.ts +17 -0
  111. package/packages/pi-ai/src/models/generated/openai.ts +17 -0
  112. package/packages/pi-ai/src/models.generated.test.ts +46 -73
  113. package/packages/pi-ai/src/models.test.ts +39 -11
  114. package/packages/pi-ai/tsconfig.tsbuildinfo +1 -1
  115. package/packages/pi-coding-agent/dist/core/agent-session-abort-order.test.js +96 -32
  116. package/packages/pi-coding-agent/dist/core/agent-session-abort-order.test.js.map +1 -1
  117. package/packages/pi-coding-agent/dist/core/agent-session-model-switch.test.js +75 -12
  118. package/packages/pi-coding-agent/dist/core/agent-session-model-switch.test.js.map +1 -1
  119. package/packages/pi-coding-agent/dist/core/agent-session-tool-refresh.test.js +99 -31
  120. package/packages/pi-coding-agent/dist/core/agent-session-tool-refresh.test.js.map +1 -1
  121. package/packages/pi-coding-agent/dist/core/extensions/loader.d.ts +5 -0
  122. package/packages/pi-coding-agent/dist/core/extensions/loader.d.ts.map +1 -1
  123. package/packages/pi-coding-agent/dist/core/extensions/loader.js +61 -0
  124. package/packages/pi-coding-agent/dist/core/extensions/loader.js.map +1 -1
  125. package/packages/pi-coding-agent/dist/core/lsp/lsp-integration.test.js +30 -4
  126. package/packages/pi-coding-agent/dist/core/lsp/lsp-integration.test.js.map +1 -1
  127. package/packages/pi-coding-agent/dist/core/model-registry-auth-mode.test.js +17 -0
  128. package/packages/pi-coding-agent/dist/core/model-registry-auth-mode.test.js.map +1 -1
  129. package/packages/pi-coding-agent/dist/core/resource-loader-cache-reset.test.js +76 -18
  130. package/packages/pi-coding-agent/dist/core/resource-loader-cache-reset.test.js.map +1 -1
  131. package/packages/pi-coding-agent/dist/core/retry-handler.d.ts.map +1 -1
  132. package/packages/pi-coding-agent/dist/core/retry-handler.js +2 -6
  133. package/packages/pi-coding-agent/dist/core/retry-handler.js.map +1 -1
  134. package/packages/pi-coding-agent/dist/core/retry-handler.test.js +5 -1
  135. package/packages/pi-coding-agent/dist/core/retry-handler.test.js.map +1 -1
  136. package/packages/pi-coding-agent/dist/core/retryable-error-regex.d.ts +18 -0
  137. package/packages/pi-coding-agent/dist/core/retryable-error-regex.d.ts.map +1 -0
  138. package/packages/pi-coding-agent/dist/core/retryable-error-regex.js +18 -0
  139. package/packages/pi-coding-agent/dist/core/retryable-error-regex.js.map +1 -0
  140. package/packages/pi-coding-agent/dist/core/system-prompt.d.ts +20 -0
  141. package/packages/pi-coding-agent/dist/core/system-prompt.d.ts.map +1 -1
  142. package/packages/pi-coding-agent/dist/core/system-prompt.js +16 -2
  143. package/packages/pi-coding-agent/dist/core/system-prompt.js.map +1 -1
  144. package/packages/pi-coding-agent/dist/index.d.ts +1 -0
  145. package/packages/pi-coding-agent/dist/index.d.ts.map +1 -1
  146. package/packages/pi-coding-agent/dist/index.js +1 -0
  147. package/packages/pi-coding-agent/dist/index.js.map +1 -1
  148. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/tool-execution.test.js +36 -5
  149. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/tool-execution.test.js.map +1 -1
  150. package/packages/pi-coding-agent/dist/modes/interactive/components/dynamic-border.test.js +20 -13
  151. package/packages/pi-coding-agent/dist/modes/interactive/components/dynamic-border.test.js.map +1 -1
  152. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  153. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js +30 -12
  154. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js.map +1 -1
  155. package/packages/pi-coding-agent/dist/tests/system-prompt-skill-filter.test.d.ts +2 -0
  156. package/packages/pi-coding-agent/dist/tests/system-prompt-skill-filter.test.d.ts.map +1 -0
  157. package/packages/pi-coding-agent/dist/tests/system-prompt-skill-filter.test.js +130 -0
  158. package/packages/pi-coding-agent/dist/tests/system-prompt-skill-filter.test.js.map +1 -0
  159. package/packages/pi-coding-agent/src/core/agent-session-abort-order.test.ts +113 -37
  160. package/packages/pi-coding-agent/src/core/agent-session-model-switch.test.ts +89 -17
  161. package/packages/pi-coding-agent/src/core/agent-session-tool-refresh.test.ts +112 -43
  162. package/packages/pi-coding-agent/src/core/extensions/loader.ts +58 -0
  163. package/packages/pi-coding-agent/src/core/lsp/lsp-integration.test.ts +35 -4
  164. package/packages/pi-coding-agent/src/core/model-registry-auth-mode.test.ts +20 -0
  165. package/packages/pi-coding-agent/src/core/resource-loader-cache-reset.test.ts +93 -28
  166. package/packages/pi-coding-agent/src/core/retry-handler.test.ts +5 -1
  167. package/packages/pi-coding-agent/src/core/retry-handler.ts +2 -8
  168. package/packages/pi-coding-agent/src/core/retryable-error-regex.ts +18 -0
  169. package/packages/pi-coding-agent/src/core/system-prompt.ts +35 -1
  170. package/packages/pi-coding-agent/src/index.ts +1 -0
  171. package/packages/pi-coding-agent/src/modes/interactive/components/__tests__/tool-execution.test.ts +49 -3
  172. package/packages/pi-coding-agent/src/modes/interactive/components/dynamic-border.test.ts +26 -20
  173. package/packages/pi-coding-agent/src/modes/interactive/components/tool-execution.ts +48 -9
  174. package/packages/pi-coding-agent/src/tests/system-prompt-skill-filter.test.ts +157 -0
  175. package/packages/pi-coding-agent/tsconfig.tsbuildinfo +1 -1
  176. package/packages/pi-tui/dist/__tests__/autocomplete.test.js +18 -8
  177. package/packages/pi-tui/dist/__tests__/autocomplete.test.js.map +1 -1
  178. package/packages/pi-tui/dist/__tests__/overlay-layout.test.js +128 -17
  179. package/packages/pi-tui/dist/__tests__/overlay-layout.test.js.map +1 -1
  180. package/packages/pi-tui/dist/__tests__/stdin-buffer.test.js +36 -12
  181. package/packages/pi-tui/dist/__tests__/stdin-buffer.test.js.map +1 -1
  182. package/packages/pi-tui/dist/__tests__/tui.test.js +18 -30
  183. package/packages/pi-tui/dist/__tests__/tui.test.js.map +1 -1
  184. package/packages/pi-tui/dist/components/__tests__/input.test.js +10 -3
  185. package/packages/pi-tui/dist/components/__tests__/input.test.js.map +1 -1
  186. package/packages/pi-tui/dist/components/__tests__/loader.test.js +53 -9
  187. package/packages/pi-tui/dist/components/__tests__/loader.test.js.map +1 -1
  188. package/packages/pi-tui/dist/components/__tests__/markdown-maxlines.test.js +6 -2
  189. package/packages/pi-tui/dist/components/__tests__/markdown-maxlines.test.js.map +1 -1
  190. package/packages/pi-tui/dist/components/image.test.js +6 -5
  191. package/packages/pi-tui/dist/components/image.test.js.map +1 -1
  192. package/packages/pi-tui/src/__tests__/autocomplete.test.ts +24 -8
  193. package/packages/pi-tui/src/__tests__/overlay-layout.test.ts +140 -17
  194. package/packages/pi-tui/src/__tests__/stdin-buffer.test.ts +41 -12
  195. package/packages/pi-tui/src/__tests__/tui.test.ts +18 -37
  196. package/packages/pi-tui/src/components/__tests__/input.test.ts +19 -3
  197. package/packages/pi-tui/src/components/__tests__/loader.test.ts +112 -35
  198. package/packages/pi-tui/src/components/__tests__/markdown-maxlines.test.ts +9 -2
  199. package/packages/pi-tui/src/components/image.test.ts +10 -5
  200. package/packages/pi-tui/tsconfig.tsbuildinfo +1 -1
  201. package/packages/rpc-client/dist/rpc-client.test.js +101 -51
  202. package/packages/rpc-client/dist/rpc-client.test.js.map +1 -1
  203. package/packages/rpc-client/src/rpc-client.test.ts +109 -52
  204. package/packages/rpc-client/tsconfig.tsbuildinfo +1 -1
  205. package/scripts/install.js +15 -1
  206. package/src/resources/extensions/browser-tools/capture.ts +12 -0
  207. package/src/resources/extensions/browser-tools/tests/browser-tools-integration.test.mjs +8 -59
  208. package/src/resources/extensions/browser-tools/tests/browser-tools-unit.test.cjs +36 -24
  209. package/src/resources/extensions/browser-tools/tests/capture-sharp-optional.test.cjs +69 -71
  210. package/src/resources/extensions/browser-tools/tools/forms.ts +5 -1
  211. package/src/resources/extensions/browser-tools/tools/intent.ts +5 -1
  212. package/src/resources/extensions/claude-code-cli/tests/stream-adapter.test.ts +80 -72
  213. package/src/resources/extensions/github-sync/tests/cli.test.ts +76 -7
  214. package/src/resources/extensions/github-sync/tests/templates.test.ts +33 -1
  215. package/src/resources/extensions/gsd/auto/phases.ts +6 -17
  216. package/src/resources/extensions/gsd/auto/session.ts +7 -0
  217. package/src/resources/extensions/gsd/auto-dispatch.ts +40 -8
  218. package/src/resources/extensions/gsd/auto-post-unit.ts +81 -0
  219. package/src/resources/extensions/gsd/auto-prompts.ts +385 -93
  220. package/src/resources/extensions/gsd/auto-start.ts +97 -4
  221. package/src/resources/extensions/gsd/auto.ts +37 -0
  222. package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +9 -1
  223. package/src/resources/extensions/gsd/bootstrap/write-gate.ts +7 -1
  224. package/src/resources/extensions/gsd/component-loader.ts +598 -0
  225. package/src/resources/extensions/gsd/component-types.ts +362 -0
  226. package/src/resources/extensions/gsd/context-store.ts +25 -8
  227. package/src/resources/extensions/gsd/detection.ts +58 -1
  228. package/src/resources/extensions/gsd/docs/preferences-reference.md +1 -1
  229. package/src/resources/extensions/gsd/forensics.ts +118 -1
  230. package/src/resources/extensions/gsd/git-service.ts +16 -0
  231. package/src/resources/extensions/gsd/gsd-db.ts +1 -1
  232. package/src/resources/extensions/gsd/guided-flow.ts +2 -4
  233. package/src/resources/extensions/gsd/journal.ts +11 -1
  234. package/src/resources/extensions/gsd/memory-extractor.ts +11 -3
  235. package/src/resources/extensions/gsd/milestone-scope-classifier.ts +366 -0
  236. package/src/resources/extensions/gsd/model-cost-table.ts +3 -0
  237. package/src/resources/extensions/gsd/model-router.ts +6 -0
  238. package/src/resources/extensions/gsd/preferences-validation.ts +21 -0
  239. package/src/resources/extensions/gsd/prompt-cache-optimizer.ts +4 -0
  240. package/src/resources/extensions/gsd/prompts/complete-milestone.md +5 -1
  241. package/src/resources/extensions/gsd/prompts/plan-slice.md +15 -2
  242. package/src/resources/extensions/gsd/service-tier.ts +5 -2
  243. package/src/resources/extensions/gsd/skill-manifest.ts +175 -0
  244. package/src/resources/extensions/gsd/slice-cadence.ts +299 -0
  245. package/src/resources/extensions/gsd/tests/artifacts-table-preserved-on-cache-invalidate.test.ts +2 -1
  246. package/src/resources/extensions/gsd/tests/auto-loop.test.ts +25 -292
  247. package/src/resources/extensions/gsd/tests/auto-remediate-slice-status.test.ts +4 -1
  248. package/src/resources/extensions/gsd/tests/auto-retry-mcp-churn-fixes.test.ts +8 -194
  249. package/src/resources/extensions/gsd/tests/auto-start-clean-runtime-db-gated.test.ts +3 -2
  250. package/src/resources/extensions/gsd/tests/auto-start-cold-db-bootstrap.test.ts +2 -2
  251. package/src/resources/extensions/gsd/tests/auto-start-needs-discussion.test.ts +15 -58
  252. package/src/resources/extensions/gsd/tests/auto-start-worktree-db-path.test.ts +2 -2
  253. package/src/resources/extensions/gsd/tests/auto-thinking-restore.test.ts +3 -2
  254. package/src/resources/extensions/gsd/tests/auto-warning-noise-regression.test.ts +3 -2
  255. package/src/resources/extensions/gsd/tests/bootstrap-derive-state-db-open.test.ts +2 -1
  256. package/src/resources/extensions/gsd/tests/cache-staleness-regression.test.ts +17 -21
  257. package/src/resources/extensions/gsd/tests/canonical-milestone-root.test.ts +108 -0
  258. package/src/resources/extensions/gsd/tests/complete-milestone-excerpt.test.ts +263 -0
  259. package/src/resources/extensions/gsd/tests/complete-slice-composer.test.ts +192 -0
  260. package/src/resources/extensions/gsd/tests/complete-slice-verification-gate.test.ts +2 -1
  261. package/src/resources/extensions/gsd/tests/complete-task.test.ts +8 -4
  262. package/src/resources/extensions/gsd/tests/component-loader.test.ts +589 -0
  263. package/src/resources/extensions/gsd/tests/component-types.test.ts +127 -0
  264. package/src/resources/extensions/gsd/tests/context-store.test.ts +79 -0
  265. package/src/resources/extensions/gsd/tests/copy-planning-artifacts-samepath.test.ts +2 -1
  266. package/src/resources/extensions/gsd/tests/discuss-slice-structured-questions.test.ts +2 -1
  267. package/src/resources/extensions/gsd/tests/discuss-tool-scope-leak.test.ts +2 -1
  268. package/src/resources/extensions/gsd/tests/double-merge-guard.test.ts +4 -3
  269. package/src/resources/extensions/gsd/tests/empty-content-abort-loop.test.ts +4 -3
  270. package/src/resources/extensions/gsd/tests/extension-bootstrap-isolation.test.ts +139 -129
  271. package/src/resources/extensions/gsd/tests/finalize-timeout-guard.test.ts +8 -104
  272. package/src/resources/extensions/gsd/tests/hook-key-parsing.test.ts +4 -55
  273. package/src/resources/extensions/gsd/tests/integration/all-milestones-complete-merge.test.ts +7 -56
  274. package/src/resources/extensions/gsd/tests/integration/doctor-proactive.test.ts +18 -2
  275. package/src/resources/extensions/gsd/tests/integration/queue-completed-milestone-perf.test.ts +10 -4
  276. package/src/resources/extensions/gsd/tests/integration/state-machine-edge-cases.test.ts +1 -1
  277. package/src/resources/extensions/gsd/tests/interactive-routing-bypass.test.ts +9 -3
  278. package/src/resources/extensions/gsd/tests/interrupted-session-ui.test.ts +6 -9
  279. package/src/resources/extensions/gsd/tests/knowledge.test.ts +93 -1
  280. package/src/resources/extensions/gsd/tests/mcp-client-security.test.ts +8 -37
  281. package/src/resources/extensions/gsd/tests/memory-extractor.test.ts +5 -15
  282. package/src/resources/extensions/gsd/tests/merge-conflict-stops-loop.test.ts +227 -55
  283. package/src/resources/extensions/gsd/tests/milestone-scope-classifier.test.ts +187 -0
  284. package/src/resources/extensions/gsd/tests/model-cost-table.test.ts +9 -1
  285. package/src/resources/extensions/gsd/tests/model-router.test.ts +1 -1
  286. package/src/resources/extensions/gsd/tests/native-git-bridge-exec-fallback.test.ts +6 -48
  287. package/src/resources/extensions/gsd/tests/notification-widget.test.ts +6 -3
  288. package/src/resources/extensions/gsd/tests/orphaned-worktree-audit.test.ts +59 -2
  289. package/src/resources/extensions/gsd/tests/parallel-research-dispatch.test.ts +273 -130
  290. package/src/resources/extensions/gsd/tests/pipeline-variant-dispatch.test.ts +301 -0
  291. package/src/resources/extensions/gsd/tests/preferences-worktree-sync.test.ts +2 -1
  292. package/src/resources/extensions/gsd/tests/prompt-cache-optimizer.test.ts +12 -0
  293. package/src/resources/extensions/gsd/tests/prompt-step-ordering.test.ts +15 -4
  294. package/src/resources/extensions/gsd/tests/provider-errors.test.ts +22 -16
  295. package/src/resources/extensions/gsd/tests/queue-draft-detection.test.ts +3 -2
  296. package/src/resources/extensions/gsd/tests/queued-discuss-fast-path.test.ts +4 -5
  297. package/src/resources/extensions/gsd/tests/reassess-default-optin.test.ts +132 -0
  298. package/src/resources/extensions/gsd/tests/recovery-attempts-reset.test.ts +8 -40
  299. package/src/resources/extensions/gsd/tests/regex-hardening.test.ts +136 -256
  300. package/src/resources/extensions/gsd/tests/research-milestone-composer.test.ts +114 -0
  301. package/src/resources/extensions/gsd/tests/restore-tools-after-discuss.test.ts +6 -3
  302. package/src/resources/extensions/gsd/tests/run-uat-composer.test.ts +148 -0
  303. package/src/resources/extensions/gsd/tests/service-tier.test.ts +4 -0
  304. package/src/resources/extensions/gsd/tests/sidecar-queue.test.ts +3 -2
  305. package/src/resources/extensions/gsd/tests/silent-catch-diagnostics.test.ts +55 -95
  306. package/src/resources/extensions/gsd/tests/skill-activation.test.ts +120 -1
  307. package/src/resources/extensions/gsd/tests/skill-manifest.test.ts +112 -0
  308. package/src/resources/extensions/gsd/tests/slice-cadence.test.ts +242 -0
  309. package/src/resources/extensions/gsd/tests/slice-context-injection.test.ts +3 -2
  310. package/src/resources/extensions/gsd/tests/smart-entry-draft.test.ts +2 -1
  311. package/src/resources/extensions/gsd/tests/stop-auto-race-null-unit.test.ts +3 -3
  312. package/src/resources/extensions/gsd/tests/structured-data-formatter.test.ts +11 -92
  313. package/src/resources/extensions/gsd/tests/subagent-model-dispatch.test.ts +7 -6
  314. package/src/resources/extensions/gsd/tests/survivor-branch-complete.test.ts +102 -101
  315. package/src/resources/extensions/gsd/tests/sync-worktree-skip-current.test.ts +4 -3
  316. package/src/resources/extensions/gsd/tests/test-helpers.test.ts +98 -0
  317. package/src/resources/extensions/gsd/tests/test-helpers.ts +153 -0
  318. package/src/resources/extensions/gsd/tests/token-profile.test.ts +8 -1
  319. package/src/resources/extensions/gsd/tests/unit-context-composer.test.ts +355 -0
  320. package/src/resources/extensions/gsd/tests/unit-context-manifest.test.ts +203 -0
  321. package/src/resources/extensions/gsd/tests/uok-gitops-wiring.test.ts +49 -26
  322. package/src/resources/extensions/gsd/tests/validate-milestone.test.ts +1 -0
  323. package/src/resources/extensions/gsd/tests/verify-artifact-tightened.test.ts +144 -80
  324. package/src/resources/extensions/gsd/tests/visualizer-critical-path.test.ts +20 -54
  325. package/src/resources/extensions/gsd/tests/visualizer-overlay.test.ts +342 -277
  326. package/src/resources/extensions/gsd/tests/worker-model-override.test.ts +37 -29
  327. package/src/resources/extensions/gsd/tests/worktree-db.test.ts +226 -266
  328. package/src/resources/extensions/gsd/tests/worktree-health-monorepo.test.ts +103 -67
  329. package/src/resources/extensions/gsd/tests/worktree-nested-git-safety.test.ts +92 -90
  330. package/src/resources/extensions/gsd/tests/worktree-submodule-safety.test.ts +238 -59
  331. package/src/resources/extensions/gsd/tests/worktree-sync-overwrite-loop.test.ts +113 -161
  332. package/src/resources/extensions/gsd/tests/worktree-telemetry.test.ts +210 -0
  333. package/src/resources/extensions/gsd/tests/zombie-gsd-state.test.ts +80 -96
  334. package/src/resources/extensions/gsd/tools/validate-milestone.ts +8 -2
  335. package/src/resources/extensions/gsd/unit-context-composer.ts +218 -0
  336. package/src/resources/extensions/gsd/unit-context-manifest.ts +492 -0
  337. package/src/resources/extensions/gsd/worktree-manager.ts +53 -0
  338. package/src/resources/extensions/gsd/worktree-resolver.ts +96 -9
  339. package/src/resources/extensions/gsd/worktree-telemetry.ts +322 -0
  340. package/src/resources/extensions/mcp-client/index.ts +3 -1
  341. package/src/resources/extensions/mcp-client/tests/server-name-spaces.test.ts +70 -36
  342. package/src/resources/extensions/ollama/index.ts +5 -1
  343. package/src/resources/extensions/ollama/ollama-auth-mode.test.ts +123 -15
  344. package/src/resources/extensions/ollama/ollama-status-indicator.test.ts +206 -19
  345. package/src/resources/extensions/remote-questions/manager.ts +36 -4
  346. package/src/resources/extensions/remote-questions/tests/command-polling.test.ts +200 -190
  347. package/src/resources/extensions/shared/tests/interview-preview.test.ts +11 -3
  348. package/src/resources/extensions/voice/tests/linux-ready.test.ts +129 -113
  349. package/packages/pi-ai/dist/utils/oauth/oauth-providers.test.d.ts +0 -2
  350. package/packages/pi-ai/dist/utils/oauth/oauth-providers.test.d.ts.map +0 -1
  351. package/packages/pi-ai/dist/utils/oauth/oauth-providers.test.js +0 -289
  352. package/packages/pi-ai/dist/utils/oauth/oauth-providers.test.js.map +0 -1
  353. package/packages/pi-ai/src/utils/oauth/oauth-providers.test.ts +0 -363
  354. package/src/resources/extensions/gsd/tests/auto-start-model-capture.test.ts +0 -143
  355. package/src/resources/extensions/gsd/tests/complete-milestone-false-merge.test.ts +0 -157
  356. package/src/resources/extensions/gsd/tests/dashboard-model-label-ordering.test.ts +0 -107
  357. package/src/resources/extensions/gsd/tests/find-missing-summaries-closed.test.ts +0 -48
  358. package/src/resources/extensions/gsd/tests/forensics-context-persist.test.ts +0 -159
  359. package/src/resources/extensions/gsd/tests/forensics-db-completion.test.ts +0 -96
  360. package/src/resources/extensions/gsd/tests/forensics-dedup.test.ts +0 -79
  361. package/src/resources/extensions/gsd/tests/forensics-hook-key-parse.test.ts +0 -74
  362. package/src/resources/extensions/gsd/tests/forensics-journal.test.ts +0 -162
  363. package/src/resources/extensions/gsd/tests/gitignore-bg-shell.test.ts +0 -38
  364. package/src/resources/extensions/gsd/tests/gsd-no-project-error.test.ts +0 -73
  365. package/src/resources/extensions/gsd/tests/idle-watchdog-stall-override.test.ts +0 -125
  366. package/src/resources/extensions/gsd/tests/import-done-milestones.test.ts +0 -42
  367. /package/dist/web/standalone/.next/static/{vidAVJkURvTJ0_V2-64ro → gYYky7yfxW8txb9vU2TrJ}/_buildManifest.js +0 -0
  368. /package/dist/web/standalone/.next/static/{vidAVJkURvTJ0_V2-64ro → gYYky7yfxW8txb9vU2TrJ}/_ssgManifest.js +0 -0
@@ -0,0 +1,242 @@
1
+ /**
2
+ * Tests for slice-cadence collapse — #4765.
3
+ *
4
+ * Covers mergeSliceToMain (squash + advance), resquashMilestoneOnMain,
5
+ * and the preference accessors.
6
+ */
7
+
8
+ import { describe, test, beforeEach, afterEach } from "node:test";
9
+ import assert from "node:assert/strict";
10
+ import { mkdtempSync, mkdirSync, writeFileSync, rmSync, realpathSync, readFileSync, existsSync } from "node:fs";
11
+ import { join } from "node:path";
12
+ import { tmpdir } from "node:os";
13
+ import { execFileSync } from "node:child_process";
14
+
15
+ import {
16
+ mergeSliceToMain,
17
+ resquashMilestoneOnMain,
18
+ getCollapseCadence,
19
+ getMilestoneResquash,
20
+ } from "../slice-cadence.ts";
21
+ import { MergeConflictError } from "../git-service.ts";
22
+ import { summarizeWorktreeTelemetry } from "../worktree-telemetry.ts";
23
+
24
+ function git(args: string[], cwd: string): string {
25
+ return execFileSync("git", args, { cwd, stdio: ["ignore", "pipe", "pipe"], encoding: "utf-8" }).trim();
26
+ }
27
+
28
+ /** Create a temp git repo with an initial commit on main. */
29
+ function createRepo(): string {
30
+ const dir = realpathSync(mkdtempSync(join(tmpdir(), "slice-cad-test-")));
31
+ git(["init"], dir);
32
+ git(["config", "user.email", "test@test.com"], dir);
33
+ git(["config", "user.name", "Test"], dir);
34
+ writeFileSync(join(dir, "README.md"), "# test\n");
35
+ git(["add", "."], dir);
36
+ git(["commit", "-m", "init"], dir);
37
+ git(["branch", "-M", "main"], dir);
38
+ mkdirSync(join(dir, ".gsd"), { recursive: true });
39
+ return dir;
40
+ }
41
+
42
+ function enterMilestoneBranch(dir: string, milestoneId: string): void {
43
+ git(["checkout", "-b", `milestone/${milestoneId}`], dir);
44
+ }
45
+
46
+ function commitFile(dir: string, file: string, content: string, msg: string): string {
47
+ writeFileSync(join(dir, file), content);
48
+ git(["add", "."], dir);
49
+ git(["commit", "-m", msg], dir);
50
+ return git(["rev-parse", "HEAD"], dir);
51
+ }
52
+
53
+ describe("getCollapseCadence / getMilestoneResquash", () => {
54
+ test("defaults to milestone cadence", () => {
55
+ assert.equal(getCollapseCadence(undefined), "milestone");
56
+ assert.equal(getCollapseCadence(null), "milestone");
57
+ assert.equal(getCollapseCadence({}), "milestone");
58
+ assert.equal(getCollapseCadence({ git: {} }), "milestone");
59
+ });
60
+ test("reads slice cadence when set", () => {
61
+ assert.equal(getCollapseCadence({ git: { collapse_cadence: "slice" } }), "slice");
62
+ });
63
+ test("milestone_resquash defaults to true when not set", () => {
64
+ assert.equal(getMilestoneResquash(undefined), true);
65
+ assert.equal(getMilestoneResquash({ git: {} }), true);
66
+ assert.equal(getMilestoneResquash({ git: { milestone_resquash: true } }), true);
67
+ });
68
+ test("milestone_resquash can be disabled explicitly", () => {
69
+ assert.equal(getMilestoneResquash({ git: { milestone_resquash: false } }), false);
70
+ });
71
+ });
72
+
73
+ describe("mergeSliceToMain", () => {
74
+ let dir: string;
75
+ let originalCwd: string;
76
+
77
+ beforeEach(() => {
78
+ dir = createRepo();
79
+ originalCwd = process.cwd();
80
+ });
81
+
82
+ afterEach(() => {
83
+ try { process.chdir(originalCwd); } catch { /* */ }
84
+ rmSync(dir, { recursive: true, force: true });
85
+ });
86
+
87
+ test("squashes one slice's commits onto main and advances the milestone branch", () => {
88
+ enterMilestoneBranch(dir, "M001");
89
+ commitFile(dir, "feature.txt", "slice 1 work\n", "feat: S01 work");
90
+
91
+ process.chdir(dir);
92
+ const result = mergeSliceToMain(dir, "M001", "S01");
93
+
94
+ assert.equal(result.skipped, false);
95
+ assert.ok(result.commitSha, "expected a commit SHA");
96
+ assert.equal(result.milestoneBranch, "milestone/M001");
97
+ assert.equal(result.mainBranch, "main");
98
+
99
+ const mainLog = git(["log", "main", "--oneline"], dir);
100
+ assert.ok(mainLog.includes("S01 of M001 (slice-cadence)"), `main log: ${mainLog}`);
101
+ assert.equal(readFileSync(join(dir, "feature.txt"), "utf-8"), "slice 1 work\n");
102
+
103
+ const mainSha = git(["rev-parse", "main"], dir);
104
+ const milestoneSha = git(["rev-parse", "milestone/M001"], dir);
105
+ assert.equal(milestoneSha, mainSha, "milestone branch must be advanced to main");
106
+
107
+ const summary = summarizeWorktreeTelemetry(dir);
108
+ assert.equal(summary.slicesMerged, 1);
109
+ assert.equal(summary.sliceMergeConflicts, 0);
110
+ });
111
+
112
+ test("handles sequential slice merges cleanly", () => {
113
+ enterMilestoneBranch(dir, "M001");
114
+ commitFile(dir, "a.txt", "slice 1\n", "feat: S01");
115
+
116
+ process.chdir(dir);
117
+ mergeSliceToMain(dir, "M001", "S01");
118
+
119
+ git(["checkout", "milestone/M001"], dir);
120
+ commitFile(dir, "b.txt", "slice 2\n", "feat: S02");
121
+
122
+ const result = mergeSliceToMain(dir, "M001", "S02");
123
+ assert.equal(result.skipped, false);
124
+
125
+ const mainLog = git(["log", "main", "--oneline"], dir);
126
+ assert.ok(mainLog.includes("S01 of M001"));
127
+ assert.ok(mainLog.includes("S02 of M001"));
128
+
129
+ assert.equal(readFileSync(join(dir, "a.txt"), "utf-8"), "slice 1\n");
130
+ assert.equal(readFileSync(join(dir, "b.txt"), "utf-8"), "slice 2\n");
131
+
132
+ const summary = summarizeWorktreeTelemetry(dir);
133
+ assert.equal(summary.slicesMerged, 2);
134
+ });
135
+
136
+ test("returns skipped when milestone branch has no commits ahead of main", () => {
137
+ enterMilestoneBranch(dir, "M001");
138
+
139
+ process.chdir(dir);
140
+ const result = mergeSliceToMain(dir, "M001", "S01");
141
+
142
+ assert.equal(result.skipped, true);
143
+ assert.equal(result.skippedReason, "no-commits-ahead");
144
+ assert.equal(result.commitSha, null);
145
+ });
146
+
147
+ test("throws MergeConflictError on a real conflict and leaves no merge artifacts", () => {
148
+ writeFileSync(join(dir, "shared.txt"), "main version\n");
149
+ git(["add", "."], dir);
150
+ git(["commit", "-m", "main-seed"], dir);
151
+
152
+ enterMilestoneBranch(dir, "M001");
153
+ commitFile(dir, "shared.txt", "slice version\n", "feat: S01 conflicting");
154
+
155
+ git(["checkout", "main"], dir);
156
+ commitFile(dir, "shared.txt", "main evolved\n", "main evolved");
157
+ git(["checkout", "milestone/M001"], dir);
158
+
159
+ process.chdir(dir);
160
+ assert.throws(
161
+ () => mergeSliceToMain(dir, "M001", "S01"),
162
+ (err: unknown) => err instanceof MergeConflictError,
163
+ );
164
+
165
+ const gitDir = join(dir, ".git");
166
+ for (const f of ["SQUASH_MSG", "MERGE_MSG", "MERGE_HEAD"]) {
167
+ assert.ok(!existsSync(join(gitDir, f)), `${f} should be cleaned up`);
168
+ }
169
+
170
+ const summary = summarizeWorktreeTelemetry(dir);
171
+ assert.equal(summary.sliceMergeConflicts, 1);
172
+ });
173
+
174
+ test("restores cwd even when merge fails (dirty working tree)", () => {
175
+ enterMilestoneBranch(dir, "M001");
176
+ commitFile(dir, "feature.txt", "slice 1\n", "feat: S01");
177
+ // Introduce an untracked file AFTER the slice commit so it's still
178
+ // present when mergeSliceToMain runs its status check.
179
+ writeFileSync(join(dir, "dirty.txt"), "uncommitted\n");
180
+
181
+ process.chdir(dir);
182
+ const cwdBefore = process.cwd();
183
+ assert.throws(() => mergeSliceToMain(dir, "M001", "S01"));
184
+ assert.equal(process.cwd(), cwdBefore, "cwd must be restored on failure");
185
+ });
186
+ });
187
+
188
+ describe("resquashMilestoneOnMain", () => {
189
+ let dir: string;
190
+ let originalCwd: string;
191
+
192
+ beforeEach(() => {
193
+ dir = createRepo();
194
+ originalCwd = process.cwd();
195
+ });
196
+
197
+ afterEach(() => {
198
+ try { process.chdir(originalCwd); } catch { /* */ }
199
+ rmSync(dir, { recursive: true, force: true });
200
+ });
201
+
202
+ test("collapses N slice commits on main into one milestone commit", () => {
203
+ const startSha = git(["rev-parse", "main"], dir);
204
+
205
+ enterMilestoneBranch(dir, "M001");
206
+ commitFile(dir, "a.txt", "slice 1\n", "feat: S01");
207
+ process.chdir(dir);
208
+ mergeSliceToMain(dir, "M001", "S01");
209
+
210
+ git(["checkout", "milestone/M001"], dir);
211
+ commitFile(dir, "b.txt", "slice 2\n", "feat: S02");
212
+ mergeSliceToMain(dir, "M001", "S02");
213
+
214
+ const beforeCount = parseInt(git(["rev-list", "--count", `${startSha}..main`], dir), 10);
215
+ assert.equal(beforeCount, 2);
216
+
217
+ const result = resquashMilestoneOnMain(dir, "M001", startSha);
218
+ assert.equal(result.resquashed, true);
219
+ assert.ok(result.newSha);
220
+
221
+ git(["checkout", "main"], dir);
222
+ const afterCount = parseInt(git(["rev-list", "--count", `${startSha}..main`], dir), 10);
223
+ assert.equal(afterCount, 1, "slice commits collapsed into one milestone commit");
224
+
225
+ const msg = git(["log", "-1", "--format=%s", "main"], dir);
226
+ assert.ok(msg.includes("M001") && msg.includes("2 slices"), `commit message should describe the resquash; got: ${msg}`);
227
+
228
+ assert.equal(readFileSync(join(dir, "a.txt"), "utf-8"), "slice 1\n");
229
+ assert.equal(readFileSync(join(dir, "b.txt"), "utf-8"), "slice 2\n");
230
+
231
+ const summary = summarizeWorktreeTelemetry(dir);
232
+ assert.equal(summary.milestoneResquashes, 1);
233
+ });
234
+
235
+ test("no-op when startSha equals HEAD", () => {
236
+ const startSha = git(["rev-parse", "main"], dir);
237
+ process.chdir(dir);
238
+ const result = resquashMilestoneOnMain(dir, "M001", startSha);
239
+ assert.equal(result.resquashed, false);
240
+ assert.equal(result.newSha, null);
241
+ });
242
+ });
@@ -11,6 +11,7 @@ import assert from "node:assert/strict";
11
11
  import { readFileSync } from "node:fs";
12
12
  import { join, dirname } from "node:path";
13
13
  import { fileURLToPath } from "node:url";
14
+ import { extractSourceRegion } from "./test-helpers.ts";
14
15
 
15
16
  const __dirname = dirname(fileURLToPath(import.meta.url));
16
17
  const autoPromptsPath = join(__dirname, "..", "auto-prompts.ts");
@@ -32,7 +33,7 @@ describe("slice CONTEXT.md injection into prompt builders (#3452)", () => {
32
33
  assert.ok(fnStart !== -1, `${builder} should exist in auto-prompts.ts`);
33
34
 
34
35
  // Get a reasonable chunk after the function start
35
- const chunk = source.slice(fnStart, fnStart + 3000);
36
+ const chunk = extractSourceRegion(source, `export async function ${builder}`);
36
37
 
37
38
  // ADR-011: buildPlanSlicePrompt / buildRefineSlicePrompt now delegate to
38
39
  // a shared helper (renderSlicePrompt) that performs the slice CONTEXT
@@ -42,7 +43,7 @@ describe("slice CONTEXT.md injection into prompt builders (#3452)", () => {
42
43
  ? (() => {
43
44
  const helperStart = source.indexOf("async function renderSlicePrompt");
44
45
  assert.ok(helperStart !== -1, "renderSlicePrompt helper must exist");
45
- return source.slice(helperStart, helperStart + 3000);
46
+ return extractSourceRegion(source, "async function renderSlicePrompt");
46
47
  })()
47
48
  : chunk;
48
49
 
@@ -4,6 +4,7 @@ import { tmpdir } from "node:os";
4
4
 
5
5
  import { deriveState } from "../state.js";
6
6
  import { resolveMilestoneFile } from "../paths.js";
7
+ import { extractSourceRegion } from "./test-helpers.ts";
7
8
 
8
9
  let passed = 0;
9
10
  let failed = 0;
@@ -81,7 +82,7 @@ assert(
81
82
 
82
83
  // Check the branch has draft-aware menu options
83
84
  const branchIdx = guidedFlowSource.indexOf('state.phase === "needs-discussion"');
84
- const branchChunk = guidedFlowSource.slice(branchIdx, branchIdx + 4000);
85
+ const branchChunk = extractSourceRegion(guidedFlowSource, 'state.phase === "needs-discussion"');
85
86
 
86
87
  assert(
87
88
  branchChunk.includes("discuss_draft"),
@@ -13,7 +13,7 @@
13
13
 
14
14
  import { readFileSync } from "node:fs";
15
15
  import { join } from "node:path";
16
- import { createTestContext } from "./test-helpers.ts";
16
+ import { createTestContext, extractSourceRegion } from "./test-helpers.ts";
17
17
 
18
18
  const { assertTrue, report } = createTestContext();
19
19
 
@@ -35,7 +35,7 @@ assertTrue(
35
35
  );
36
36
 
37
37
  // Extract the region from the closeout comment to the next section comment
38
- const closeoutRegion = phasesSrc.slice(closeoutIdx, closeoutIdx + 500);
38
+ const closeoutRegion = extractSourceRegion(phasesSrc, closeoutComment);
39
39
  assertTrue(
40
40
  closeoutRegion.includes("if (s.currentUnit)"),
41
41
  "closeoutUnit call is guarded by `if (s.currentUnit)` check (#2939)",
@@ -52,7 +52,7 @@ assertTrue(
52
52
  "phases.ts contains the 'Zero tool-call guard' comment block",
53
53
  );
54
54
 
55
- const zeroToolRegion = phasesSrc.slice(zeroToolIdx, zeroToolIdx + 600);
55
+ const zeroToolRegion = extractSourceRegion(phasesSrc, zeroToolComment);
56
56
 
57
57
  // The non-null assertion `s.currentUnit!.startedAt` must be replaced with
58
58
  // optional chaining `s.currentUnit?.startedAt`
@@ -271,96 +271,15 @@ describe("structured-data-formatter: measureSavings", () => {
271
271
  });
272
272
 
273
273
  // ---------------------------------------------------------------------------
274
- // Realistic token savings measurement
274
+ // Dropped (#4836): the previous "realistic savings" suite asserted that the
275
+ // compact formatter beat hand-authored "typical markdown" baselines by 30%+.
276
+ // Those baselines were written by the test author to make the assertion pass
277
+ // — they are not the format GSD actually emits anywhere else, so shifting
278
+ // the compact output by any amount could be absorbed by padding the baseline.
279
+ // There was no regression signal.
280
+ //
281
+ // The unit tests above already pin the compact format's structure byte for
282
+ // byte; a genuine regression changes one of those exact-string assertions.
283
+ // If a size-budget guarantee is needed later, capture a real production
284
+ // baseline into a fixture file and assert against a checked-in byte count.
275
285
  // ---------------------------------------------------------------------------
276
-
277
- describe("structured-data-formatter: realistic savings", () => {
278
- it("decisions compact format saves 30%+ vs markdown table", () => {
279
- const decisions = [sampleDecision, sampleDecision2];
280
-
281
- // Simulate a typical markdown table
282
- const markdownTable = [
283
- "| ID | When | Scope | Decision | Choice | Rationale | Revisable |",
284
- "|------|------------|--------------|-------------------------|------------------------|--------------------------|-----------|",
285
- "| D001 | M001/S01 | architecture | Use SQLite for storage | WAL mode, single-writer | Built-in, no external deps | yes |",
286
- "| D002 | M001/S02 | testing | Unit test all parsers | node:test framework | Fast, zero-dependency | no |",
287
- ].join("\n");
288
-
289
- const compactOutput = formatDecisionsCompact(decisions);
290
- const savings = measureSavings(compactOutput, markdownTable);
291
- assert.ok(
292
- savings >= 30,
293
- `expected >=30% savings, got ${savings.toFixed(1)}%`,
294
- );
295
- });
296
-
297
- it("requirements compact format saves 30%+ vs markdown sections", () => {
298
- const requirements = [sampleRequirement, sampleRequirement2];
299
-
300
- // Simulate verbose markdown format with all fields
301
- const markdownSections = [
302
- "## R001",
303
- "",
304
- "- **Class:** functional",
305
- "- **Status:** active",
306
- "- **Description:** Response latency < 200ms for API endpoints",
307
- "- **Why:** Critical for user experience",
308
- "- **Source:** architecture review",
309
- "- **Primary Owner:** S01",
310
- "- **Supporting Slices:** S02, S03",
311
- "- **Validation:** Load test confirms P99 < 200ms",
312
- "- **Notes:** Monitor in production",
313
- "",
314
- "## R002",
315
- "",
316
- "- **Class:** non-functional",
317
- "- **Status:** active",
318
- "- **Description:** Data consistency across writes",
319
- "- **Why:** Prevents data loss",
320
- "- **Source:** data team review",
321
- "- **Primary Owner:** S02",
322
- "- **Supporting Slices:** S01",
323
- "- **Validation:** Integration test suite",
324
- "- **Notes:** Requires WAL mode",
325
- ].join("\n");
326
-
327
- const compactOutput = formatRequirementsCompact(requirements);
328
- const savings = measureSavings(compactOutput, markdownSections);
329
- assert.ok(
330
- savings >= 30,
331
- `expected >=30% savings, got ${savings.toFixed(1)}%`,
332
- );
333
- });
334
-
335
- it("task plan compact format saves 30%+ vs markdown sections", () => {
336
- const tasks = [sampleTaskDone, sampleTaskPending];
337
-
338
- // Simulate verbose markdown task format
339
- const markdownTasks = [
340
- "## T01 - Database schema",
341
- "",
342
- "- **Status:** Done",
343
- "- **Estimate:** 30m",
344
- "- **Description:** Create tables for decisions and requirements",
345
- "- **Files:**",
346
- " - src/db.ts",
347
- " - src/schema.ts",
348
- "",
349
- "## T02 - API endpoints",
350
- "",
351
- "- **Status:** Pending",
352
- "- **Estimate:** 1h",
353
- "- **Description:** REST endpoints for CRUD operations",
354
- "- **Files:**",
355
- " - src/api.ts",
356
- "- **Verify:** npm test",
357
- ].join("\n");
358
-
359
- const compactOutput = formatTaskPlanCompact(tasks);
360
- const savings = measureSavings(compactOutput, markdownTasks);
361
- assert.ok(
362
- savings >= 30,
363
- `expected >=30% savings, got ${savings.toFixed(1)}%`,
364
- );
365
- });
366
- });
@@ -15,6 +15,7 @@ import { join, dirname } from "node:path";
15
15
  import { tmpdir } from "node:os";
16
16
  import { fileURLToPath } from "node:url";
17
17
  import { validatePreferences } from "../preferences-validation.ts";
18
+ import { extractSourceRegion } from "./test-helpers.ts";
18
19
 
19
20
  const __dirname = dirname(fileURLToPath(import.meta.url));
20
21
  const promptsSrc = readFileSync(join(__dirname, "..", "auto-prompts.ts"), "utf-8");
@@ -59,7 +60,7 @@ test("reactive_execution: subagent_model rejects empty string", () => {
59
60
  test("buildReactiveExecutePrompt: accepts subagentModel parameter", () => {
60
61
  const fnStart = promptsSrc.indexOf("export async function buildReactiveExecutePrompt");
61
62
  assert.ok(fnStart !== -1, "buildReactiveExecutePrompt should be exported");
62
- const signature = promptsSrc.slice(fnStart, fnStart + 300);
63
+ const signature = extractSourceRegion(promptsSrc, "export async function buildReactiveExecutePrompt", { fromIdx: fnStart });
63
64
  assert.ok(
64
65
  signature.includes("subagentModel"),
65
66
  "buildReactiveExecutePrompt should accept a subagentModel parameter",
@@ -69,7 +70,7 @@ test("buildReactiveExecutePrompt: accepts subagentModel parameter", () => {
69
70
  test("buildParallelResearchSlicesPrompt: accepts subagentModel parameter", () => {
70
71
  const fnStart = promptsSrc.indexOf("export async function buildParallelResearchSlicesPrompt");
71
72
  assert.ok(fnStart !== -1, "buildParallelResearchSlicesPrompt should be exported");
72
- const signature = promptsSrc.slice(fnStart, fnStart + 300);
73
+ const signature = extractSourceRegion(promptsSrc, "export async function buildParallelResearchSlicesPrompt", { fromIdx: fnStart });
73
74
  assert.ok(
74
75
  signature.includes("subagentModel"),
75
76
  "buildParallelResearchSlicesPrompt should accept a subagentModel parameter",
@@ -79,7 +80,7 @@ test("buildParallelResearchSlicesPrompt: accepts subagentModel parameter", () =>
79
80
  test("buildGateEvaluatePrompt: accepts subagentModel parameter", () => {
80
81
  const fnStart = promptsSrc.indexOf("export async function buildGateEvaluatePrompt");
81
82
  assert.ok(fnStart !== -1, "buildGateEvaluatePrompt should be exported");
82
- const signature = promptsSrc.slice(fnStart, fnStart + 300);
83
+ const signature = extractSourceRegion(promptsSrc, "export async function buildGateEvaluatePrompt", { fromIdx: fnStart });
83
84
  assert.ok(
84
85
  signature.includes("subagentModel"),
85
86
  "buildGateEvaluatePrompt should accept a subagentModel parameter",
@@ -129,7 +130,7 @@ test("auto-dispatch: passes model to buildReactiveExecutePrompt", () => {
129
130
  // Find the reactive-execute dispatch rule
130
131
  const ruleStart = dispatchSrc.indexOf("reactive-execute (parallel dispatch)");
131
132
  assert.ok(ruleStart !== -1, "reactive-execute dispatch rule should exist");
132
- const ruleBlock = dispatchSrc.slice(ruleStart, ruleStart + 1000);
133
+ const ruleBlock = extractSourceRegion(dispatchSrc, "reactive-execute (parallel dispatch)", { fromIdx: ruleStart });
133
134
  assert.ok(
134
135
  ruleBlock.includes("subagent_model") || ruleBlock.includes("subagentModel"),
135
136
  "reactive-execute rule should resolve and pass the subagent model",
@@ -140,7 +141,7 @@ test("auto-dispatch: passes model to buildParallelResearchSlicesPrompt", () => {
140
141
  const callIdx = dispatchSrc.indexOf("buildParallelResearchSlicesPrompt(");
141
142
  assert.ok(callIdx !== -1, "buildParallelResearchSlicesPrompt call should exist");
142
143
  // The call site should pass a model argument (not just 4 args)
143
- const callSite = dispatchSrc.slice(callIdx, callIdx + 300);
144
+ const callSite = extractSourceRegion(dispatchSrc, "buildParallelResearchSlicesPrompt(", { fromIdx: callIdx });
144
145
  assert.ok(
145
146
  callSite.includes("subagentModel") || callSite.includes("resolveModelWithFallbacksForUnit"),
146
147
  "buildParallelResearchSlicesPrompt call should include model argument",
@@ -150,7 +151,7 @@ test("auto-dispatch: passes model to buildParallelResearchSlicesPrompt", () => {
150
151
  test("auto-dispatch: passes model to buildGateEvaluatePrompt", () => {
151
152
  const callIdx = dispatchSrc.indexOf("buildGateEvaluatePrompt(");
152
153
  assert.ok(callIdx !== -1, "buildGateEvaluatePrompt call should exist");
153
- const callSite = dispatchSrc.slice(callIdx, callIdx + 300);
154
+ const callSite = extractSourceRegion(dispatchSrc, "buildGateEvaluatePrompt(", { fromIdx: callIdx });
154
155
  assert.ok(
155
156
  callSite.includes("subagentModel") || callSite.includes("resolveModelWithFallbacksForUnit"),
156
157
  "buildGateEvaluatePrompt call should include model argument",