gsd-pi 2.77.0-dev.eaa4973bc → 2.78.0-dev.aeeb2ca00

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 (545) hide show
  1. package/README.md +53 -17
  2. package/dist/claude-cli-check.js +46 -10
  3. package/dist/headless.js +49 -4
  4. package/dist/resource-loader.d.ts +40 -0
  5. package/dist/resource-loader.js +32 -13
  6. package/dist/resources/extensions/browser-tools/capture.js +9 -0
  7. package/dist/resources/extensions/browser-tools/tests/browser-tools-integration.test.mjs +8 -59
  8. package/dist/resources/extensions/browser-tools/tests/browser-tools-unit.test.cjs +36 -24
  9. package/dist/resources/extensions/browser-tools/tests/capture-sharp-optional.test.cjs +69 -71
  10. package/dist/resources/extensions/browser-tools/tools/forms.js +5 -1
  11. package/dist/resources/extensions/browser-tools/tools/intent.js +5 -1
  12. package/dist/resources/extensions/claude-code-cli/readiness.js +72 -16
  13. package/dist/resources/extensions/claude-code-cli/stream-adapter.js +481 -17
  14. package/dist/resources/extensions/github-sync/templates.js +103 -0
  15. package/dist/resources/extensions/google-search/index.js +3 -2
  16. package/dist/resources/extensions/gsd/auto/loop.js +124 -2
  17. package/dist/resources/extensions/gsd/auto/phases.js +57 -39
  18. package/dist/resources/extensions/gsd/auto/session.js +6 -2
  19. package/dist/resources/extensions/gsd/auto-dispatch.js +142 -29
  20. package/dist/resources/extensions/gsd/auto-model-selection.js +124 -4
  21. package/dist/resources/extensions/gsd/auto-post-unit.js +150 -64
  22. package/dist/resources/extensions/gsd/auto-prompts.js +372 -104
  23. package/dist/resources/extensions/gsd/auto-recovery.js +197 -48
  24. package/dist/resources/extensions/gsd/auto-start.js +107 -29
  25. package/dist/resources/extensions/gsd/auto-tool-tracking.js +47 -7
  26. package/dist/resources/extensions/gsd/auto-worktree.js +122 -26
  27. package/dist/resources/extensions/gsd/auto.js +76 -21
  28. package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +19 -1
  29. package/dist/resources/extensions/gsd/bootstrap/db-tools.js +209 -0
  30. package/dist/resources/extensions/gsd/bootstrap/provider-error-resume.js +3 -6
  31. package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +7 -3
  32. package/dist/resources/extensions/gsd/bootstrap/write-gate.js +127 -9
  33. package/dist/resources/extensions/gsd/component-loader.js +447 -0
  34. package/dist/resources/extensions/gsd/component-types.js +69 -0
  35. package/dist/resources/extensions/gsd/context-store.js +23 -7
  36. package/dist/resources/extensions/gsd/detection.js +49 -1
  37. package/dist/resources/extensions/gsd/dispatch-guard.js +2 -17
  38. package/dist/resources/extensions/gsd/docs/preferences-reference.md +1 -1
  39. package/dist/resources/extensions/gsd/forensics.js +106 -0
  40. package/dist/resources/extensions/gsd/gate-registry.js +2 -2
  41. package/dist/resources/extensions/gsd/git-constants.js +28 -1
  42. package/dist/resources/extensions/gsd/git-self-heal.js +27 -0
  43. package/dist/resources/extensions/gsd/git-service.js +126 -2
  44. package/dist/resources/extensions/gsd/gsd-db.js +6 -3
  45. package/dist/resources/extensions/gsd/guided-flow.js +39 -13
  46. package/dist/resources/extensions/gsd/memory-extractor.js +7 -1
  47. package/dist/resources/extensions/gsd/milestone-scope-classifier.js +299 -0
  48. package/dist/resources/extensions/gsd/milestone-summary-classifier.js +37 -0
  49. package/dist/resources/extensions/gsd/model-cost-table.js +3 -0
  50. package/dist/resources/extensions/gsd/model-router.js +6 -0
  51. package/dist/resources/extensions/gsd/native-git-bridge.js +34 -4
  52. package/dist/resources/extensions/gsd/preferences-validation.js +23 -0
  53. package/dist/resources/extensions/gsd/prompt-cache-optimizer.js +4 -0
  54. package/dist/resources/extensions/gsd/prompts/complete-milestone.md +6 -2
  55. package/dist/resources/extensions/gsd/prompts/discuss-headless.md +23 -4
  56. package/dist/resources/extensions/gsd/prompts/doctor-heal.md +5 -4
  57. package/dist/resources/extensions/gsd/prompts/plan-slice.md +15 -2
  58. package/dist/resources/extensions/gsd/safety/git-checkpoint.js +11 -0
  59. package/dist/resources/extensions/gsd/service-tier.js +5 -2
  60. package/dist/resources/extensions/gsd/session-lock.js +19 -10
  61. package/dist/resources/extensions/gsd/skill-manifest.js +168 -0
  62. package/dist/resources/extensions/gsd/slice-cadence.js +238 -0
  63. package/dist/resources/extensions/gsd/slice-parallel-orchestrator.js +278 -8
  64. package/dist/resources/extensions/gsd/state-transition-matrix.js +118 -0
  65. package/dist/resources/extensions/gsd/state.js +69 -58
  66. package/dist/resources/extensions/gsd/sync-lock.js +98 -42
  67. package/dist/resources/extensions/gsd/tools/validate-milestone.js +7 -2
  68. package/dist/resources/extensions/gsd/unit-context-composer.js +147 -0
  69. package/dist/resources/extensions/gsd/unit-context-manifest.js +370 -0
  70. package/dist/resources/extensions/gsd/uok/dispatch-envelope.js +33 -0
  71. package/dist/resources/extensions/gsd/uok/execution-graph.js +10 -0
  72. package/dist/resources/extensions/gsd/uok/gate-runner.js +53 -5
  73. package/dist/resources/extensions/gsd/uok/gitops.js +2 -1
  74. package/dist/resources/extensions/gsd/uok/loop-adapter.js +37 -10
  75. package/dist/resources/extensions/gsd/uok/parity-report.js +58 -0
  76. package/dist/resources/extensions/gsd/uok/plan-v2.js +10 -4
  77. package/dist/resources/extensions/gsd/uok/writer.js +82 -0
  78. package/dist/resources/extensions/gsd/workflow-mcp.js +6 -0
  79. package/dist/resources/extensions/gsd/worktree-manager.js +85 -8
  80. package/dist/resources/extensions/gsd/worktree-resolver.js +86 -7
  81. package/dist/resources/extensions/gsd/worktree-telemetry.js +198 -0
  82. package/dist/resources/extensions/mcp-client/index.js +3 -1
  83. package/dist/resources/extensions/ollama/index.js +5 -1
  84. package/dist/resources/extensions/remote-questions/manager.js +11 -5
  85. package/dist/tsconfig.extensions.tsbuildinfo +1 -1
  86. package/dist/web/standalone/.next/BUILD_ID +1 -1
  87. package/dist/web/standalone/.next/app-path-routes-manifest.json +11 -11
  88. package/dist/web/standalone/.next/build-manifest.json +2 -2
  89. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  90. package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
  91. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  92. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  93. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  94. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  95. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  96. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  97. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  98. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  99. package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
  100. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
  101. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  102. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
  103. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  104. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  105. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  106. package/dist/web/standalone/.next/server/app/api/git/route.js +1 -1
  107. package/dist/web/standalone/.next/server/app/index.html +1 -1
  108. package/dist/web/standalone/.next/server/app/index.rsc +1 -1
  109. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
  110. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +1 -1
  111. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  112. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
  113. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  114. package/dist/web/standalone/.next/server/app-paths-manifest.json +11 -11
  115. package/dist/web/standalone/.next/server/chunks/1926.js +1 -1
  116. package/dist/web/standalone/.next/server/chunks/6897.js +1 -1
  117. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  118. package/dist/web/standalone/.next/server/middleware-manifest.json +5 -5
  119. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  120. package/dist/web/standalone/.next/server/pages/500.html +1 -1
  121. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  122. package/package.json +2 -3
  123. package/packages/daemon/package.json +2 -2
  124. package/packages/daemon/src/logger.ts +4 -3
  125. package/packages/mcp-server/dist/server.d.ts +24 -0
  126. package/packages/mcp-server/dist/server.d.ts.map +1 -1
  127. package/packages/mcp-server/dist/server.js +88 -87
  128. package/packages/mcp-server/dist/server.js.map +1 -1
  129. package/packages/mcp-server/dist/workflow-tools.d.ts.map +1 -1
  130. package/packages/mcp-server/dist/workflow-tools.js +15 -6
  131. package/packages/mcp-server/dist/workflow-tools.js.map +1 -1
  132. package/packages/mcp-server/package.json +2 -2
  133. package/packages/mcp-server/src/mcp-server.test.ts +25 -3
  134. package/packages/mcp-server/src/readers/graph.test.ts +87 -15
  135. package/packages/mcp-server/src/secure-env-collect.test.ts +232 -237
  136. package/packages/mcp-server/src/server.ts +131 -105
  137. package/packages/mcp-server/src/workflow-tools.test.ts +85 -0
  138. package/packages/mcp-server/src/workflow-tools.ts +19 -6
  139. package/packages/mcp-server/tsconfig.tsbuildinfo +1 -1
  140. package/packages/native/package.json +2 -2
  141. package/packages/native/src/__tests__/_test-coverage-guard.test.mjs +98 -0
  142. package/packages/native/src/__tests__/module-compat.test.mjs +59 -27
  143. package/packages/native/src/__tests__/ps.test.mjs +14 -8
  144. package/packages/native/src/__tests__/stream-process.test.mjs +23 -2
  145. package/packages/native/src/__tests__/truncate.test.mjs +17 -2
  146. package/packages/pi-agent-core/package.json +1 -1
  147. package/packages/pi-agent-core/src/agent-loop.test.ts +5 -15
  148. package/packages/pi-agent-core/src/agent.test.ts +96 -102
  149. package/packages/pi-agent-core/tsconfig.tsbuildinfo +1 -1
  150. package/packages/pi-ai/dist/models/capability-patches.d.ts.map +1 -1
  151. package/packages/pi-ai/dist/models/capability-patches.js +9 -2
  152. package/packages/pi-ai/dist/models/capability-patches.js.map +1 -1
  153. package/packages/pi-ai/dist/models/generated/index.d.ts +34 -0
  154. package/packages/pi-ai/dist/models/generated/index.d.ts.map +1 -1
  155. package/packages/pi-ai/dist/models/generated/openai-codex.d.ts +17 -0
  156. package/packages/pi-ai/dist/models/generated/openai-codex.d.ts.map +1 -1
  157. package/packages/pi-ai/dist/models/generated/openai-codex.js +17 -0
  158. package/packages/pi-ai/dist/models/generated/openai-codex.js.map +1 -1
  159. package/packages/pi-ai/dist/models/generated/openai.d.ts +17 -0
  160. package/packages/pi-ai/dist/models/generated/openai.d.ts.map +1 -1
  161. package/packages/pi-ai/dist/models/generated/openai.js +17 -0
  162. package/packages/pi-ai/dist/models/generated/openai.js.map +1 -1
  163. package/packages/pi-ai/dist/models.generated.test.js +43 -70
  164. package/packages/pi-ai/dist/models.generated.test.js.map +1 -1
  165. package/packages/pi-ai/dist/models.test.js +36 -11
  166. package/packages/pi-ai/dist/models.test.js.map +1 -1
  167. package/packages/pi-ai/package.json +1 -1
  168. package/packages/pi-ai/scripts/generate-models.ts +44 -0
  169. package/packages/pi-ai/src/models/capability-patches.ts +10 -2
  170. package/packages/pi-ai/src/models/generated/openai-codex.ts +17 -0
  171. package/packages/pi-ai/src/models/generated/openai.ts +17 -0
  172. package/packages/pi-ai/src/models.generated.test.ts +46 -73
  173. package/packages/pi-ai/src/models.test.ts +48 -11
  174. package/packages/pi-ai/tsconfig.tsbuildinfo +1 -1
  175. package/packages/pi-coding-agent/dist/core/agent-session-abort-order.test.js +96 -32
  176. package/packages/pi-coding-agent/dist/core/agent-session-abort-order.test.js.map +1 -1
  177. package/packages/pi-coding-agent/dist/core/agent-session-model-switch.test.js +75 -12
  178. package/packages/pi-coding-agent/dist/core/agent-session-model-switch.test.js.map +1 -1
  179. package/packages/pi-coding-agent/dist/core/agent-session-tool-refresh.test.js +99 -31
  180. package/packages/pi-coding-agent/dist/core/agent-session-tool-refresh.test.js.map +1 -1
  181. package/packages/pi-coding-agent/dist/core/extensions/loader.d.ts +5 -0
  182. package/packages/pi-coding-agent/dist/core/extensions/loader.d.ts.map +1 -1
  183. package/packages/pi-coding-agent/dist/core/extensions/loader.js +61 -0
  184. package/packages/pi-coding-agent/dist/core/extensions/loader.js.map +1 -1
  185. package/packages/pi-coding-agent/dist/core/lsp/lsp-integration.test.js +30 -4
  186. package/packages/pi-coding-agent/dist/core/lsp/lsp-integration.test.js.map +1 -1
  187. package/packages/pi-coding-agent/dist/core/model-registry-auth-mode.test.js +17 -0
  188. package/packages/pi-coding-agent/dist/core/model-registry-auth-mode.test.js.map +1 -1
  189. package/packages/pi-coding-agent/dist/core/resource-loader-cache-reset.test.js +76 -18
  190. package/packages/pi-coding-agent/dist/core/resource-loader-cache-reset.test.js.map +1 -1
  191. package/packages/pi-coding-agent/dist/core/retry-handler.d.ts.map +1 -1
  192. package/packages/pi-coding-agent/dist/core/retry-handler.js +2 -6
  193. package/packages/pi-coding-agent/dist/core/retry-handler.js.map +1 -1
  194. package/packages/pi-coding-agent/dist/core/retry-handler.test.js +5 -1
  195. package/packages/pi-coding-agent/dist/core/retry-handler.test.js.map +1 -1
  196. package/packages/pi-coding-agent/dist/core/retryable-error-regex.d.ts +18 -0
  197. package/packages/pi-coding-agent/dist/core/retryable-error-regex.d.ts.map +1 -0
  198. package/packages/pi-coding-agent/dist/core/retryable-error-regex.js +18 -0
  199. package/packages/pi-coding-agent/dist/core/retryable-error-regex.js.map +1 -0
  200. package/packages/pi-coding-agent/dist/core/system-prompt.d.ts +20 -0
  201. package/packages/pi-coding-agent/dist/core/system-prompt.d.ts.map +1 -1
  202. package/packages/pi-coding-agent/dist/core/system-prompt.js +16 -2
  203. package/packages/pi-coding-agent/dist/core/system-prompt.js.map +1 -1
  204. package/packages/pi-coding-agent/dist/index.d.ts +1 -0
  205. package/packages/pi-coding-agent/dist/index.d.ts.map +1 -1
  206. package/packages/pi-coding-agent/dist/index.js +1 -0
  207. package/packages/pi-coding-agent/dist/index.js.map +1 -1
  208. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/tool-execution.test.js +36 -5
  209. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/tool-execution.test.js.map +1 -1
  210. package/packages/pi-coding-agent/dist/modes/interactive/components/dynamic-border.test.js +20 -13
  211. package/packages/pi-coding-agent/dist/modes/interactive/components/dynamic-border.test.js.map +1 -1
  212. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  213. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js +30 -12
  214. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js.map +1 -1
  215. package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.d.ts.map +1 -1
  216. package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.js +18 -3
  217. package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.js.map +1 -1
  218. package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.test.js +125 -0
  219. package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.test.js.map +1 -1
  220. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-state.d.ts +2 -0
  221. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-state.d.ts.map +1 -1
  222. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-state.js.map +1 -1
  223. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts +4 -0
  224. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  225. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js +105 -13
  226. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
  227. package/packages/pi-coding-agent/dist/tests/system-prompt-skill-filter.test.d.ts +2 -0
  228. package/packages/pi-coding-agent/dist/tests/system-prompt-skill-filter.test.d.ts.map +1 -0
  229. package/packages/pi-coding-agent/dist/tests/system-prompt-skill-filter.test.js +130 -0
  230. package/packages/pi-coding-agent/dist/tests/system-prompt-skill-filter.test.js.map +1 -0
  231. package/packages/pi-coding-agent/package.json +1 -1
  232. package/packages/pi-coding-agent/src/core/agent-session-abort-order.test.ts +113 -37
  233. package/packages/pi-coding-agent/src/core/agent-session-model-switch.test.ts +89 -17
  234. package/packages/pi-coding-agent/src/core/agent-session-tool-refresh.test.ts +112 -43
  235. package/packages/pi-coding-agent/src/core/extensions/loader.ts +58 -0
  236. package/packages/pi-coding-agent/src/core/lsp/lsp-integration.test.ts +35 -4
  237. package/packages/pi-coding-agent/src/core/model-registry-auth-mode.test.ts +20 -0
  238. package/packages/pi-coding-agent/src/core/resource-loader-cache-reset.test.ts +93 -28
  239. package/packages/pi-coding-agent/src/core/retry-handler.test.ts +5 -1
  240. package/packages/pi-coding-agent/src/core/retry-handler.ts +2 -8
  241. package/packages/pi-coding-agent/src/core/retryable-error-regex.ts +18 -0
  242. package/packages/pi-coding-agent/src/core/system-prompt.ts +35 -1
  243. package/packages/pi-coding-agent/src/index.ts +1 -0
  244. package/packages/pi-coding-agent/src/modes/interactive/components/__tests__/tool-execution.test.ts +49 -3
  245. package/packages/pi-coding-agent/src/modes/interactive/components/dynamic-border.test.ts +26 -20
  246. package/packages/pi-coding-agent/src/modes/interactive/components/tool-execution.ts +48 -9
  247. package/packages/pi-coding-agent/src/modes/interactive/controllers/input-controller.test.ts +146 -1
  248. package/packages/pi-coding-agent/src/modes/interactive/controllers/input-controller.ts +20 -3
  249. package/packages/pi-coding-agent/src/modes/interactive/interactive-mode-state.ts +2 -0
  250. package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +119 -13
  251. package/packages/pi-coding-agent/src/tests/system-prompt-skill-filter.test.ts +157 -0
  252. package/packages/pi-coding-agent/tsconfig.tsbuildinfo +1 -1
  253. package/packages/pi-tui/dist/__tests__/autocomplete.test.js +18 -8
  254. package/packages/pi-tui/dist/__tests__/autocomplete.test.js.map +1 -1
  255. package/packages/pi-tui/dist/__tests__/overlay-layout.test.js +128 -17
  256. package/packages/pi-tui/dist/__tests__/overlay-layout.test.js.map +1 -1
  257. package/packages/pi-tui/dist/__tests__/stdin-buffer.test.js +37 -11
  258. package/packages/pi-tui/dist/__tests__/stdin-buffer.test.js.map +1 -1
  259. package/packages/pi-tui/dist/__tests__/tui.test.js +18 -30
  260. package/packages/pi-tui/dist/__tests__/tui.test.js.map +1 -1
  261. package/packages/pi-tui/dist/components/__tests__/input.test.js +10 -3
  262. package/packages/pi-tui/dist/components/__tests__/input.test.js.map +1 -1
  263. package/packages/pi-tui/dist/components/__tests__/loader.test.js +53 -9
  264. package/packages/pi-tui/dist/components/__tests__/loader.test.js.map +1 -1
  265. package/packages/pi-tui/dist/components/__tests__/markdown-maxlines.test.js +6 -2
  266. package/packages/pi-tui/dist/components/__tests__/markdown-maxlines.test.js.map +1 -1
  267. package/packages/pi-tui/dist/components/editor.d.ts +14 -0
  268. package/packages/pi-tui/dist/components/editor.d.ts.map +1 -1
  269. package/packages/pi-tui/dist/components/editor.js +19 -0
  270. package/packages/pi-tui/dist/components/editor.js.map +1 -1
  271. package/packages/pi-tui/dist/components/image.test.js +6 -5
  272. package/packages/pi-tui/dist/components/image.test.js.map +1 -1
  273. package/packages/pi-tui/dist/editor-component.d.ts +2 -0
  274. package/packages/pi-tui/dist/editor-component.d.ts.map +1 -1
  275. package/packages/pi-tui/dist/editor-component.js.map +1 -1
  276. package/packages/pi-tui/package.json +1 -1
  277. package/packages/pi-tui/src/__tests__/autocomplete.test.ts +24 -8
  278. package/packages/pi-tui/src/__tests__/overlay-layout.test.ts +140 -17
  279. package/packages/pi-tui/src/__tests__/stdin-buffer.test.ts +42 -11
  280. package/packages/pi-tui/src/__tests__/tui.test.ts +18 -37
  281. package/packages/pi-tui/src/components/__tests__/input.test.ts +19 -3
  282. package/packages/pi-tui/src/components/__tests__/loader.test.ts +112 -35
  283. package/packages/pi-tui/src/components/__tests__/markdown-maxlines.test.ts +9 -2
  284. package/packages/pi-tui/src/components/editor.ts +22 -0
  285. package/packages/pi-tui/src/components/image.test.ts +10 -5
  286. package/packages/pi-tui/src/editor-component.ts +3 -0
  287. package/packages/pi-tui/tsconfig.tsbuildinfo +1 -1
  288. package/packages/rpc-client/dist/rpc-client.test.js +101 -51
  289. package/packages/rpc-client/dist/rpc-client.test.js.map +1 -1
  290. package/packages/rpc-client/package.json +1 -1
  291. package/packages/rpc-client/src/rpc-client.test.ts +109 -52
  292. package/packages/rpc-client/tsconfig.tsbuildinfo +1 -1
  293. package/pkg/package.json +1 -1
  294. package/scripts/install.js +15 -1
  295. package/src/resources/extensions/browser-tools/capture.ts +12 -0
  296. package/src/resources/extensions/browser-tools/tests/browser-tools-integration.test.mjs +8 -59
  297. package/src/resources/extensions/browser-tools/tests/browser-tools-unit.test.cjs +36 -24
  298. package/src/resources/extensions/browser-tools/tests/capture-sharp-optional.test.cjs +69 -71
  299. package/src/resources/extensions/browser-tools/tools/forms.ts +5 -1
  300. package/src/resources/extensions/browser-tools/tools/intent.ts +5 -1
  301. package/src/resources/extensions/claude-code-cli/readiness.ts +75 -16
  302. package/src/resources/extensions/claude-code-cli/stream-adapter.ts +518 -19
  303. package/src/resources/extensions/claude-code-cli/tests/stream-adapter.test.ts +919 -75
  304. package/src/resources/extensions/github-sync/templates.ts +151 -0
  305. package/src/resources/extensions/github-sync/tests/cli.test.ts +76 -7
  306. package/src/resources/extensions/github-sync/tests/templates.test.ts +92 -1
  307. package/src/resources/extensions/google-search/index.ts +3 -2
  308. package/src/resources/extensions/gsd/auto/loop.ts +142 -2
  309. package/src/resources/extensions/gsd/auto/phases.ts +62 -38
  310. package/src/resources/extensions/gsd/auto/session.ts +7 -2
  311. package/src/resources/extensions/gsd/auto-dispatch.ts +156 -29
  312. package/src/resources/extensions/gsd/auto-model-selection.ts +131 -4
  313. package/src/resources/extensions/gsd/auto-post-unit.ts +163 -73
  314. package/src/resources/extensions/gsd/auto-prompts.ts +385 -93
  315. package/src/resources/extensions/gsd/auto-recovery.ts +230 -51
  316. package/src/resources/extensions/gsd/auto-start.ts +127 -9
  317. package/src/resources/extensions/gsd/auto-tool-tracking.ts +51 -7
  318. package/src/resources/extensions/gsd/auto-worktree.ts +130 -26
  319. package/src/resources/extensions/gsd/auto.ts +90 -23
  320. package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +20 -1
  321. package/src/resources/extensions/gsd/bootstrap/db-tools.ts +221 -0
  322. package/src/resources/extensions/gsd/bootstrap/provider-error-resume.ts +3 -7
  323. package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +7 -3
  324. package/src/resources/extensions/gsd/bootstrap/write-gate.ts +158 -9
  325. package/src/resources/extensions/gsd/component-loader.ts +598 -0
  326. package/src/resources/extensions/gsd/component-types.ts +362 -0
  327. package/src/resources/extensions/gsd/context-store.ts +25 -8
  328. package/src/resources/extensions/gsd/detection.ts +58 -1
  329. package/src/resources/extensions/gsd/dispatch-guard.ts +2 -20
  330. package/src/resources/extensions/gsd/docs/preferences-reference.md +1 -1
  331. package/src/resources/extensions/gsd/forensics.ts +118 -1
  332. package/src/resources/extensions/gsd/gate-registry.ts +2 -2
  333. package/src/resources/extensions/gsd/git-constants.ts +30 -1
  334. package/src/resources/extensions/gsd/git-self-heal.ts +31 -0
  335. package/src/resources/extensions/gsd/git-service.ts +149 -2
  336. package/src/resources/extensions/gsd/gsd-db.ts +6 -3
  337. package/src/resources/extensions/gsd/guided-flow.ts +57 -14
  338. package/src/resources/extensions/gsd/journal.ts +11 -1
  339. package/src/resources/extensions/gsd/memory-extractor.ts +11 -3
  340. package/src/resources/extensions/gsd/milestone-scope-classifier.ts +366 -0
  341. package/src/resources/extensions/gsd/milestone-summary-classifier.ts +42 -0
  342. package/src/resources/extensions/gsd/model-cost-table.ts +3 -0
  343. package/src/resources/extensions/gsd/model-router.ts +6 -0
  344. package/src/resources/extensions/gsd/native-git-bridge.ts +34 -4
  345. package/src/resources/extensions/gsd/preferences-validation.ts +21 -0
  346. package/src/resources/extensions/gsd/prompt-cache-optimizer.ts +4 -0
  347. package/src/resources/extensions/gsd/prompts/complete-milestone.md +6 -2
  348. package/src/resources/extensions/gsd/prompts/discuss-headless.md +23 -4
  349. package/src/resources/extensions/gsd/prompts/doctor-heal.md +5 -4
  350. package/src/resources/extensions/gsd/prompts/plan-slice.md +15 -2
  351. package/src/resources/extensions/gsd/safety/git-checkpoint.ts +15 -0
  352. package/src/resources/extensions/gsd/service-tier.ts +5 -2
  353. package/src/resources/extensions/gsd/session-lock.ts +20 -10
  354. package/src/resources/extensions/gsd/skill-manifest.ts +175 -0
  355. package/src/resources/extensions/gsd/slice-cadence.ts +299 -0
  356. package/src/resources/extensions/gsd/slice-parallel-orchestrator.ts +309 -8
  357. package/src/resources/extensions/gsd/state-transition-matrix.ts +152 -0
  358. package/src/resources/extensions/gsd/state.ts +76 -66
  359. package/src/resources/extensions/gsd/sync-lock.ts +97 -39
  360. package/src/resources/extensions/gsd/tests/artifact-retry-cap.test.ts +270 -0
  361. package/src/resources/extensions/gsd/tests/artifacts-table-preserved-on-cache-invalidate.test.ts +2 -1
  362. package/src/resources/extensions/gsd/tests/auto-deterministic-error-classification-4973.test.ts +341 -0
  363. package/src/resources/extensions/gsd/tests/auto-discuss-milestone-deadlock-4973.test.ts +264 -0
  364. package/src/resources/extensions/gsd/tests/auto-loop.test.ts +133 -292
  365. package/src/resources/extensions/gsd/tests/auto-model-selection-tool-poisoning.test.ts +742 -0
  366. package/src/resources/extensions/gsd/tests/auto-model-selection.test.ts +78 -0
  367. package/src/resources/extensions/gsd/tests/auto-phases-lifecycle.test.ts +61 -0
  368. package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +93 -0
  369. package/src/resources/extensions/gsd/tests/auto-remediate-slice-status.test.ts +4 -1
  370. package/src/resources/extensions/gsd/tests/auto-retry-mcp-churn-fixes.test.ts +8 -194
  371. package/src/resources/extensions/gsd/tests/auto-start-clean-runtime-db-gated.test.ts +3 -2
  372. package/src/resources/extensions/gsd/tests/auto-start-cold-db-bootstrap.test.ts +2 -2
  373. package/src/resources/extensions/gsd/tests/auto-start-needs-discussion.test.ts +15 -58
  374. package/src/resources/extensions/gsd/tests/auto-start-worktree-db-path.test.ts +2 -2
  375. package/src/resources/extensions/gsd/tests/auto-thinking-restore.test.ts +3 -2
  376. package/src/resources/extensions/gsd/tests/auto-warning-noise-regression.test.ts +3 -2
  377. package/src/resources/extensions/gsd/tests/bootstrap-derive-state-db-open.test.ts +2 -1
  378. package/src/resources/extensions/gsd/tests/cache-staleness-regression.test.ts +17 -21
  379. package/src/resources/extensions/gsd/tests/canonical-milestone-root.test.ts +108 -0
  380. package/src/resources/extensions/gsd/tests/complete-milestone-excerpt.test.ts +263 -0
  381. package/src/resources/extensions/gsd/tests/complete-milestone.test.ts +25 -0
  382. package/src/resources/extensions/gsd/tests/complete-slice-composer.test.ts +192 -0
  383. package/src/resources/extensions/gsd/tests/complete-slice-verification-gate.test.ts +2 -1
  384. package/src/resources/extensions/gsd/tests/complete-task.test.ts +16 -8
  385. package/src/resources/extensions/gsd/tests/component-loader.test.ts +589 -0
  386. package/src/resources/extensions/gsd/tests/component-types.test.ts +127 -0
  387. package/src/resources/extensions/gsd/tests/context-store.test.ts +79 -0
  388. package/src/resources/extensions/gsd/tests/copy-planning-artifacts-samepath.test.ts +2 -1
  389. package/src/resources/extensions/gsd/tests/crash-recovery.test.ts +50 -1
  390. package/src/resources/extensions/gsd/tests/custom-engine-loop-integration.test.ts +159 -0
  391. package/src/resources/extensions/gsd/tests/db-access-guardrails.test.ts +1 -0
  392. package/src/resources/extensions/gsd/tests/derive-state-crossval.test.ts +3 -3
  393. package/src/resources/extensions/gsd/tests/derive-state-db-disk-reconcile.test.ts +40 -0
  394. package/src/resources/extensions/gsd/tests/derive-state-db.test.ts +91 -3
  395. package/src/resources/extensions/gsd/tests/derive-state.test.ts +4 -4
  396. package/src/resources/extensions/gsd/tests/discuss-slice-structured-questions.test.ts +2 -1
  397. package/src/resources/extensions/gsd/tests/discuss-tool-scope-leak.test.ts +2 -1
  398. package/src/resources/extensions/gsd/tests/dispatch-complete-milestone-guard.test.ts +5 -0
  399. package/src/resources/extensions/gsd/tests/dispatch-guard.test.ts +25 -0
  400. package/src/resources/extensions/gsd/tests/dispatch-missing-task-plans.test.ts +14 -0
  401. package/src/resources/extensions/gsd/tests/dispatcher-stuck-planning.test.ts +3 -2
  402. package/src/resources/extensions/gsd/tests/double-merge-guard.test.ts +4 -3
  403. package/src/resources/extensions/gsd/tests/empty-content-abort-loop.test.ts +4 -3
  404. package/src/resources/extensions/gsd/tests/execution-entry-missing-context-4671.test.ts +173 -0
  405. package/src/resources/extensions/gsd/tests/extension-bootstrap-isolation.test.ts +139 -129
  406. package/src/resources/extensions/gsd/tests/finalize-timeout-guard.test.ts +8 -104
  407. package/src/resources/extensions/gsd/tests/gate-state-canonicalization.test.ts +102 -0
  408. package/src/resources/extensions/gsd/tests/gate-storage.test.ts +1 -1
  409. package/src/resources/extensions/gsd/tests/google-search-stub.test.ts +14 -4
  410. package/src/resources/extensions/gsd/tests/headless-milestone-parity.test.ts +117 -0
  411. package/src/resources/extensions/gsd/tests/hook-key-parsing.test.ts +4 -55
  412. package/src/resources/extensions/gsd/tests/integration/all-milestones-complete-merge.test.ts +7 -56
  413. package/src/resources/extensions/gsd/tests/integration/auto-recovery.test.ts +20 -0
  414. package/src/resources/extensions/gsd/tests/integration/doctor-proactive.test.ts +18 -2
  415. package/src/resources/extensions/gsd/tests/integration/queue-completed-milestone-perf.test.ts +10 -4
  416. package/src/resources/extensions/gsd/tests/integration/state-machine-edge-cases.test.ts +144 -7
  417. package/src/resources/extensions/gsd/tests/integration/state-machine-live-validation.test.ts +4 -0
  418. package/src/resources/extensions/gsd/tests/integration/state-machine-runtime-failures.test.ts +2 -16
  419. package/src/resources/extensions/gsd/tests/interactive-routing-bypass.test.ts +9 -3
  420. package/src/resources/extensions/gsd/tests/interrupted-session-ui.test.ts +6 -9
  421. package/src/resources/extensions/gsd/tests/journal-integration.test.ts +64 -0
  422. package/src/resources/extensions/gsd/tests/knowledge.test.ts +93 -1
  423. package/src/resources/extensions/gsd/tests/mcp-client-security.test.ts +8 -37
  424. package/src/resources/extensions/gsd/tests/memory-extractor.test.ts +5 -15
  425. package/src/resources/extensions/gsd/tests/merge-conflict-stops-loop.test.ts +227 -55
  426. package/src/resources/extensions/gsd/tests/milestone-scope-classifier.test.ts +187 -0
  427. package/src/resources/extensions/gsd/tests/milestone-summary-classifier.test.ts +30 -0
  428. package/src/resources/extensions/gsd/tests/model-cost-table.test.ts +9 -1
  429. package/src/resources/extensions/gsd/tests/model-router.test.ts +1 -1
  430. package/src/resources/extensions/gsd/tests/native-git-bridge-exec-fallback.test.ts +6 -48
  431. package/src/resources/extensions/gsd/tests/notification-widget.test.ts +6 -3
  432. package/src/resources/extensions/gsd/tests/orphaned-worktree-audit.test.ts +59 -2
  433. package/src/resources/extensions/gsd/tests/parallel-research-dispatch.test.ts +273 -130
  434. package/src/resources/extensions/gsd/tests/pipeline-variant-dispatch.test.ts +301 -0
  435. package/src/resources/extensions/gsd/tests/pre-execution-pause-wiring.test.ts +32 -1
  436. package/src/resources/extensions/gsd/tests/preferences-worktree-sync.test.ts +2 -1
  437. package/src/resources/extensions/gsd/tests/prompt-cache-optimizer.test.ts +12 -0
  438. package/src/resources/extensions/gsd/tests/prompt-step-ordering.test.ts +15 -4
  439. package/src/resources/extensions/gsd/tests/provider-errors.test.ts +23 -24
  440. package/src/resources/extensions/gsd/tests/queue-auto-guard.test.ts +32 -0
  441. package/src/resources/extensions/gsd/tests/queue-draft-detection.test.ts +3 -2
  442. package/src/resources/extensions/gsd/tests/queued-discuss-fast-path.test.ts +4 -5
  443. package/src/resources/extensions/gsd/tests/ready-phrase-no-files-4573.test.ts +75 -2
  444. package/src/resources/extensions/gsd/tests/reassess-default-optin.test.ts +132 -0
  445. package/src/resources/extensions/gsd/tests/recovery-attempts-reset.test.ts +8 -40
  446. package/src/resources/extensions/gsd/tests/regex-hardening.test.ts +136 -256
  447. package/src/resources/extensions/gsd/tests/research-milestone-composer.test.ts +114 -0
  448. package/src/resources/extensions/gsd/tests/restore-tools-after-discuss.test.ts +6 -3
  449. package/src/resources/extensions/gsd/tests/run-uat-composer.test.ts +148 -0
  450. package/src/resources/extensions/gsd/tests/service-tier.test.ts +4 -0
  451. package/src/resources/extensions/gsd/tests/session-lock-regression.test.ts +29 -0
  452. package/src/resources/extensions/gsd/tests/sidecar-queue.test.ts +3 -2
  453. package/src/resources/extensions/gsd/tests/silent-catch-diagnostics.test.ts +55 -95
  454. package/src/resources/extensions/gsd/tests/single-writer-v3-tool-surface.test.ts +158 -0
  455. package/src/resources/extensions/gsd/tests/skill-activation.test.ts +120 -1
  456. package/src/resources/extensions/gsd/tests/skill-manifest.test.ts +112 -0
  457. package/src/resources/extensions/gsd/tests/slice-cadence.test.ts +242 -0
  458. package/src/resources/extensions/gsd/tests/slice-context-injection.test.ts +3 -2
  459. package/src/resources/extensions/gsd/tests/slice-parallel-orchestrator.test.ts +164 -1
  460. package/src/resources/extensions/gsd/tests/smart-entry-draft.test.ts +2 -1
  461. package/src/resources/extensions/gsd/tests/stale-dirlistcache-4648.test.ts +112 -0
  462. package/src/resources/extensions/gsd/tests/state-machine-full-walkthrough.test.ts +29 -5
  463. package/src/resources/extensions/gsd/tests/state-transition-matrix.test.ts +44 -0
  464. package/src/resources/extensions/gsd/tests/stop-auto-race-null-unit.test.ts +3 -3
  465. package/src/resources/extensions/gsd/tests/structured-data-formatter.test.ts +11 -92
  466. package/src/resources/extensions/gsd/tests/subagent-model-dispatch.test.ts +7 -6
  467. package/src/resources/extensions/gsd/tests/survivor-branch-complete.test.ts +102 -101
  468. package/src/resources/extensions/gsd/tests/sync-lock.test.ts +31 -0
  469. package/src/resources/extensions/gsd/tests/sync-worktree-skip-current.test.ts +4 -3
  470. package/src/resources/extensions/gsd/tests/test-helpers.test.ts +98 -0
  471. package/src/resources/extensions/gsd/tests/test-helpers.ts +153 -0
  472. package/src/resources/extensions/gsd/tests/token-profile.test.ts +8 -1
  473. package/src/resources/extensions/gsd/tests/tool-invocation-error-loop-break.test.ts +61 -1
  474. package/src/resources/extensions/gsd/tests/tool-naming.test.ts +8 -1
  475. package/src/resources/extensions/gsd/tests/unit-context-composer.test.ts +355 -0
  476. package/src/resources/extensions/gsd/tests/unit-context-manifest.test.ts +258 -0
  477. package/src/resources/extensions/gsd/tests/uok-contracts.test.ts +51 -0
  478. package/src/resources/extensions/gsd/tests/uok-execution-graph.test.ts +16 -0
  479. package/src/resources/extensions/gsd/tests/uok-gate-runner.test.ts +75 -0
  480. package/src/resources/extensions/gsd/tests/uok-gitops-wiring.test.ts +49 -26
  481. package/src/resources/extensions/gsd/tests/uok-loop-adapter-writer.test.ts +65 -0
  482. package/src/resources/extensions/gsd/tests/uok-parity-report.test.ts +42 -0
  483. package/src/resources/extensions/gsd/tests/uok-plan-v2-wiring.test.ts +19 -2
  484. package/src/resources/extensions/gsd/tests/uok-writer.test.ts +75 -0
  485. package/src/resources/extensions/gsd/tests/validate-milestone.test.ts +12 -0
  486. package/src/resources/extensions/gsd/tests/verify-artifact-tightened.test.ts +144 -80
  487. package/src/resources/extensions/gsd/tests/visualizer-critical-path.test.ts +20 -54
  488. package/src/resources/extensions/gsd/tests/visualizer-overlay.test.ts +342 -277
  489. package/src/resources/extensions/gsd/tests/worker-model-override.test.ts +37 -29
  490. package/src/resources/extensions/gsd/tests/worktree-db.test.ts +226 -266
  491. package/src/resources/extensions/gsd/tests/worktree-health-monorepo.test.ts +103 -67
  492. package/src/resources/extensions/gsd/tests/worktree-nested-git-safety.test.ts +92 -90
  493. package/src/resources/extensions/gsd/tests/worktree-submodule-safety.test.ts +238 -59
  494. package/src/resources/extensions/gsd/tests/worktree-sync-overwrite-loop.test.ts +113 -161
  495. package/src/resources/extensions/gsd/tests/worktree-telemetry.test.ts +210 -0
  496. package/src/resources/extensions/gsd/tests/write-gate-planning-unit.test.ts +262 -0
  497. package/src/resources/extensions/gsd/tests/write-gate-predicates.test.ts +186 -0
  498. package/src/resources/extensions/gsd/tests/write-gate.test.ts +7 -5
  499. package/src/resources/extensions/gsd/tests/zombie-gsd-state.test.ts +80 -96
  500. package/src/resources/extensions/gsd/tools/validate-milestone.ts +8 -2
  501. package/src/resources/extensions/gsd/types.ts +3 -3
  502. package/src/resources/extensions/gsd/unit-context-composer.ts +218 -0
  503. package/src/resources/extensions/gsd/unit-context-manifest.ts +574 -0
  504. package/src/resources/extensions/gsd/uok/contracts.ts +65 -0
  505. package/src/resources/extensions/gsd/uok/dispatch-envelope.ts +56 -0
  506. package/src/resources/extensions/gsd/uok/execution-graph.ts +22 -0
  507. package/src/resources/extensions/gsd/uok/gate-runner.ts +65 -5
  508. package/src/resources/extensions/gsd/uok/gitops.ts +6 -1
  509. package/src/resources/extensions/gsd/uok/loop-adapter.ts +45 -10
  510. package/src/resources/extensions/gsd/uok/parity-report.ts +84 -0
  511. package/src/resources/extensions/gsd/uok/plan-v2.ts +13 -5
  512. package/src/resources/extensions/gsd/uok/writer.ts +113 -0
  513. package/src/resources/extensions/gsd/workflow-mcp.ts +6 -0
  514. package/src/resources/extensions/gsd/worktree-manager.ts +108 -7
  515. package/src/resources/extensions/gsd/worktree-resolver.ts +96 -9
  516. package/src/resources/extensions/gsd/worktree-telemetry.ts +322 -0
  517. package/src/resources/extensions/mcp-client/index.ts +3 -1
  518. package/src/resources/extensions/mcp-client/tests/server-name-spaces.test.ts +70 -36
  519. package/src/resources/extensions/ollama/index.ts +5 -1
  520. package/src/resources/extensions/ollama/ollama-auth-mode.test.ts +123 -15
  521. package/src/resources/extensions/ollama/ollama-status-indicator.test.ts +206 -19
  522. package/src/resources/extensions/remote-questions/manager.ts +36 -4
  523. package/src/resources/extensions/remote-questions/tests/command-polling.test.ts +200 -190
  524. package/src/resources/extensions/shared/tests/interview-preview.test.ts +11 -3
  525. package/src/resources/extensions/voice/tests/linux-ready.test.ts +129 -113
  526. package/packages/pi-ai/dist/utils/oauth/oauth-providers.test.d.ts +0 -2
  527. package/packages/pi-ai/dist/utils/oauth/oauth-providers.test.d.ts.map +0 -1
  528. package/packages/pi-ai/dist/utils/oauth/oauth-providers.test.js +0 -289
  529. package/packages/pi-ai/dist/utils/oauth/oauth-providers.test.js.map +0 -1
  530. package/packages/pi-ai/src/utils/oauth/oauth-providers.test.ts +0 -363
  531. package/src/resources/extensions/gsd/tests/auto-start-model-capture.test.ts +0 -143
  532. package/src/resources/extensions/gsd/tests/complete-milestone-false-merge.test.ts +0 -157
  533. package/src/resources/extensions/gsd/tests/dashboard-model-label-ordering.test.ts +0 -107
  534. package/src/resources/extensions/gsd/tests/find-missing-summaries-closed.test.ts +0 -48
  535. package/src/resources/extensions/gsd/tests/forensics-context-persist.test.ts +0 -159
  536. package/src/resources/extensions/gsd/tests/forensics-db-completion.test.ts +0 -96
  537. package/src/resources/extensions/gsd/tests/forensics-dedup.test.ts +0 -79
  538. package/src/resources/extensions/gsd/tests/forensics-hook-key-parse.test.ts +0 -74
  539. package/src/resources/extensions/gsd/tests/forensics-journal.test.ts +0 -162
  540. package/src/resources/extensions/gsd/tests/gitignore-bg-shell.test.ts +0 -38
  541. package/src/resources/extensions/gsd/tests/gsd-no-project-error.test.ts +0 -73
  542. package/src/resources/extensions/gsd/tests/idle-watchdog-stall-override.test.ts +0 -125
  543. package/src/resources/extensions/gsd/tests/import-done-milestones.test.ts +0 -42
  544. /package/dist/web/standalone/.next/static/{5wbu35_C2_MQ3Jj1lEVDx → cAJH99yNS1UPbeSEiNRrV}/_buildManifest.js +0 -0
  545. /package/dist/web/standalone/.next/static/{5wbu35_C2_MQ3Jj1lEVDx → cAJH99yNS1UPbeSEiNRrV}/_ssgManifest.js +0 -0
@@ -33,9 +33,11 @@ import {
33
33
  } from "./gate-registry.js";
34
34
  import { formatDecisionsCompact, formatRequirementsCompact } from "./structured-data-formatter.js";
35
35
  import { readPhaseAnchor, formatAnchorForPrompt } from "./phase-anchor.js";
36
+ import { composeInlinedContext, type ArtifactResolver } from "./unit-context-composer.js";
36
37
  import { logWarning } from "./workflow-logger.js";
37
38
  import { inlineGraphSubgraph } from "./graph-context.js";
38
39
  import { buildExtractionStepsBlock } from "./commands-extract-learnings.js";
40
+ import { warnIfManifestHasMissingSkills } from "./skill-manifest.js";
39
41
 
40
42
  // ─── Preamble Cap ─────────────────────────────────────────────────────────────
41
43
 
@@ -247,6 +249,87 @@ export async function inlineFileSmart(
247
249
  return `### ${label}\nSource: \`${relPath}\`\n\n${truncated}`;
248
250
  }
249
251
 
252
+ /**
253
+ * Compact slice-summary excerpt for milestone-level closers (#4780).
254
+ *
255
+ * Emits the frontmatter fields + short body section heads rather than the
256
+ * full SUMMARY.md body, and keeps the source path in the header so the
257
+ * closer agent can Read the full file on demand when drafting LEARNINGS.
258
+ *
259
+ * Scope: designed for `buildCompleteMilestonePrompt`, which previously
260
+ * inlined the full SUMMARY per slice and routinely paid ~300–500K tokens
261
+ * per close when the narrative was never synthesized. Not used by
262
+ * `buildValidateMilestonePrompt` yet — validate needs fuller verification
263
+ * evidence; follow-up PR can extend or parameterize.
264
+ *
265
+ * If parsing fails (unrecognizable frontmatter, missing id, etc.) the
266
+ * function falls back to `inlineFile` so the closer loses no information.
267
+ */
268
+ export async function buildSliceSummaryExcerpt(
269
+ absPath: string | null, relPath: string, sid: string,
270
+ ): Promise<string> {
271
+ const header = `### ${sid} Summary (excerpt)\nSource: \`${relPath}\``;
272
+ const content = absPath ? await loadFile(absPath) : null;
273
+ if (!content) {
274
+ return `${header}\n\n_(not found — file does not exist yet)_`;
275
+ }
276
+ try {
277
+ const s = parseSummary(content);
278
+ if (!s.frontmatter.id) {
279
+ // Unrecognizable — fall back to full file so no context is lost.
280
+ return `### ${sid} Summary\nSource: \`${relPath}\`\n\n${content.trim()}`;
281
+ }
282
+ const lines: string[] = [header, ""];
283
+ if (s.title) lines.push(`**Title:** ${s.title}`);
284
+ if (s.oneLiner) lines.push(`**One-liner:** ${s.oneLiner}`);
285
+ if (s.frontmatter.verification_result) {
286
+ lines.push(`**Verification:** \`${s.frontmatter.verification_result}\``);
287
+ }
288
+ lines.push(`**Blockers:** ${s.frontmatter.blocker_discovered ? "⚠️ blocker recorded — Read full summary" : "none"}`);
289
+ if (s.frontmatter.duration) lines.push(`**Duration:** ${s.frontmatter.duration}`);
290
+ if (s.frontmatter.provides.length > 0) lines.push(`**Provides:** ${s.frontmatter.provides.join("; ")}`);
291
+ if (s.frontmatter.affects.length > 0) lines.push(`**Affects:** ${s.frontmatter.affects.join("; ")}`);
292
+ if (s.frontmatter.key_decisions.length > 0) lines.push(`**Key decisions:** ${s.frontmatter.key_decisions.join("; ")}`);
293
+ if (s.frontmatter.patterns_established.length > 0) lines.push(`**Patterns established:** ${s.frontmatter.patterns_established.join("; ")}`);
294
+ if (s.frontmatter.key_files.length > 0) {
295
+ const files = s.frontmatter.key_files.slice(0, 8);
296
+ const more = s.frontmatter.key_files.length > files.length ? ` (+${s.frontmatter.key_files.length - files.length} more)` : "";
297
+ lines.push(`**Key files:** ${files.join(", ")}${more}`);
298
+ }
299
+
300
+ // Cap section bodies (coderabbit review on #4908): if any of these
301
+ // narrative sections balloon, excerpt mode still inflates and
302
+ // undermines the token-reduction goal. 800 chars (~200 tokens) is
303
+ // enough to carry intent; the closer agent Reads the full file when
304
+ // it needs richer context for LEARNINGS synthesis.
305
+ const SECTION_CAP_CHARS = 800;
306
+ const capSection = (body: string): string => {
307
+ const trimmed = body.trim();
308
+ if (trimmed.length <= SECTION_CAP_CHARS) return trimmed;
309
+ return `${trimmed.slice(0, SECTION_CAP_CHARS)}\n… (truncated — see full \`${relPath}\`)`;
310
+ };
311
+
312
+ if (s.deviations && s.deviations.trim()) {
313
+ lines.push("", "#### Deviations", capSection(s.deviations));
314
+ }
315
+ if (s.knownLimitations && s.knownLimitations.trim()) {
316
+ lines.push("", "#### Known limitations", capSection(s.knownLimitations));
317
+ }
318
+ if (s.followUps && s.followUps.trim()) {
319
+ lines.push("", "#### Follow-ups", capSection(s.followUps));
320
+ }
321
+
322
+ lines.push(
323
+ "",
324
+ `> **On-demand:** read \`${relPath}\` for the full "What Happened" narrative, integration notes, and detailed file-change list when drafting LEARNINGS, the Decision Re-evaluation table, or cross-slice synthesis.`,
325
+ );
326
+ return lines.join("\n");
327
+ } catch {
328
+ // Defensive — any parse failure falls back to full inline.
329
+ return `### ${sid} Summary\nSource: \`${relPath}\`\n\n${content.trim()}`;
330
+ }
331
+ }
332
+
250
333
  /**
251
334
  * Load and inline dependency slice summaries (full content, not just paths).
252
335
  */
@@ -514,6 +597,48 @@ export async function inlineKnowledgeScoped(
514
597
  return `### Project Knowledge (scoped)\nSource: \`${relGsdRootFile("KNOWLEDGE")}\`\n\n${scoped.trim()}`;
515
598
  }
516
599
 
600
+ /**
601
+ * Budget-capped knowledge inline for milestone-level prompt assembly.
602
+ *
603
+ * Addresses issue #4719: the six milestone-phase prompts (research-milestone,
604
+ * plan-milestone, complete-slice, complete-milestone, validate-milestone,
605
+ * reassess-roadmap) previously injected the full KNOWLEDGE.md (~226KB for a
606
+ * real project) on every invocation. This helper scopes by caller-supplied
607
+ * keywords and caps the payload at `maxChars` (default 30,000 chars).
608
+ *
609
+ * Returns null when no KNOWLEDGE.md exists or no entries match any keyword.
610
+ */
611
+ export async function inlineKnowledgeBudgeted(
612
+ base: string,
613
+ keywords: string[],
614
+ options?: { maxChars?: number },
615
+ ): Promise<string | null> {
616
+ const DEFAULT_MAX_CHARS = 30_000;
617
+ const HARD_MAX_CHARS = 100_000;
618
+ const raw = Number(options?.maxChars ?? DEFAULT_MAX_CHARS);
619
+ const maxChars = Number.isFinite(raw)
620
+ ? Math.max(0, Math.min(Math.floor(raw), HARD_MAX_CHARS))
621
+ : DEFAULT_MAX_CHARS;
622
+
623
+ const knowledgePath = resolveGsdRootFile(base, "KNOWLEDGE");
624
+ if (!existsSync(knowledgePath)) return null;
625
+
626
+ const content = await loadFile(knowledgePath);
627
+ if (!content) return null;
628
+
629
+ const { queryKnowledge } = await import("./context-store.js");
630
+ const scoped = await queryKnowledge(content, keywords);
631
+ if (!scoped) return null;
632
+
633
+ const trimmed = scoped.trim();
634
+ const truncated =
635
+ trimmed.length > maxChars
636
+ ? `${trimmed.slice(0, maxChars)}\n\n[...truncated ${trimmed.length - maxChars} chars; rerun with narrower scope if needed]`
637
+ : trimmed;
638
+
639
+ return `### Project Knowledge (scoped)\nSource: \`${relGsdRootFile("KNOWLEDGE")}\`\n\n${truncated}`;
640
+ }
641
+
517
642
  /**
518
643
  * Inline a roadmap excerpt for a specific slice.
519
644
  * Reads full roadmap, extracts minimal excerpt with header + predecessor + target row.
@@ -662,8 +787,14 @@ export function buildSkillActivationBlock(params: {
662
787
  extraContext?: string[];
663
788
  taskPlanContent?: string | null;
664
789
  preferences?: GSDPreferences;
790
+ /**
791
+ * Unit type dispatching this prompt. When provided, skills are filtered
792
+ * through the per-unit-type manifest (see `skill-manifest.ts`). Unknown
793
+ * or omitted values retain the pre-manifest behavior (all skills eligible).
794
+ */
795
+ unitType?: string;
665
796
  }): string {
666
- const prefs = params.preferences ?? loadEffectiveGSDPreferences()?.preferences;
797
+ const prefs = params.preferences ?? loadEffectiveGSDPreferences(params.base)?.preferences;
667
798
  const contextTokens = tokenizeSkillContext(
668
799
  params.milestoneId,
669
800
  params.milestoneTitle,
@@ -673,8 +804,22 @@ export function buildSkillActivationBlock(params: {
673
804
  params.taskTitle,
674
805
  );
675
806
 
676
- const visibleSkills = (typeof getLoadedSkills === 'function' ? getLoadedSkills() : []).filter(skill => !skill.disableModelInvocation);
807
+ const loaded = (typeof getLoadedSkills === 'function' ? getLoadedSkills() : []).filter(skill => !skill.disableModelInvocation);
808
+
809
+ // Skill activation here is driven entirely by explicit sources
810
+ // (always_use_skills, prefer_skills, skill_rules, task-plan skills_used).
811
+ // Every match is an explicit user/project intent and must not be dropped
812
+ // by the unit-type manifest — user intent is stronger signal than
813
+ // defaults. The manifest's real home is the skill catalog rendering
814
+ // layer (pi-coding-agent `formatSkillsForPrompt`); that wiring is tracked
815
+ // as the "load-time short-circuit" follow-up to RFC #4779.
816
+ //
817
+ // `unitType` stays plumbed so the strict-mode warning can surface
818
+ // manifest entries that reference uninstalled skills, and so the
819
+ // activation-block site is ready to opt in once PR B lands.
820
+ const visibleSkills = loaded;
677
821
  const installedNames = new Set(visibleSkills.map(skill => normalizeSkillReference(skill.name)));
822
+ warnIfManifestHasMissingSkills(params.unitType, installedNames);
678
823
  const avoided = new Set(resolvePreferenceSkillNames(prefs?.avoid_skills ?? [], params.base));
679
824
  const matched = new Set<string>();
680
825
 
@@ -1084,29 +1229,64 @@ export async function buildDiscussMilestonePrompt(
1084
1229
  }
1085
1230
 
1086
1231
  export async function buildResearchMilestonePrompt(mid: string, midTitle: string, base: string): Promise<string> {
1087
- const contextPath = resolveMilestoneFile(base, mid, "CONTEXT");
1088
- const contextRel = relMilestoneFile(base, mid, "CONTEXT");
1232
+ // #4782 phase 3: research-milestone migrated through the composer.
1233
+ // Declared inline order: milestone-context, project, requirements,
1234
+ // decisions, templates. Knowledge stays outside the composer
1235
+ // (budget-driven, scoped by keyword extraction — future phase folds
1236
+ // policy-driven blocks in).
1237
+ const resolveArtifact: ArtifactResolver = async (key) => {
1238
+ switch (key) {
1239
+ case "milestone-context": {
1240
+ const p = resolveMilestoneFile(base, mid, "CONTEXT");
1241
+ const r = relMilestoneFile(base, mid, "CONTEXT");
1242
+ return await inlineFile(p, r, "Milestone Context");
1243
+ }
1244
+ case "project":
1245
+ return await inlineProjectFromDb(base);
1246
+ case "requirements":
1247
+ return await inlineRequirementsFromDb(base, mid);
1248
+ case "decisions":
1249
+ return await inlineDecisionsFromDb(base, mid);
1250
+ case "templates":
1251
+ return inlineTemplate("research", "Research");
1252
+ default:
1253
+ return null;
1254
+ }
1255
+ };
1089
1256
 
1090
- const inlined: string[] = [];
1091
- inlined.push(await inlineFile(contextPath, contextRel, "Milestone Context"));
1092
- const projectInline = await inlineProjectFromDb(base);
1093
- if (projectInline) inlined.push(projectInline);
1094
- const requirementsInline = await inlineRequirementsFromDb(base, mid);
1095
- if (requirementsInline) inlined.push(requirementsInline);
1096
- const decisionsInline = await inlineDecisionsFromDb(base, mid);
1097
- if (decisionsInline) inlined.push(decisionsInline);
1098
- const knowledgeInlineRM = await inlineGsdRootFile(base, "knowledge.md", "Project Knowledge");
1099
- if (knowledgeInlineRM) inlined.push(knowledgeInlineRM);
1100
- inlined.push(inlineTemplate("research", "Research"));
1257
+ const composed = await composeInlinedContext("research-milestone", resolveArtifact);
1258
+
1259
+ // Knowledge block stays outside the composer — budgeted, scoped via
1260
+ // keyword extraction (#4719). Inserted between decisions and the
1261
+ // templates block to match the pre-migration output order. We split
1262
+ // the composer output around the templates section to preserve that
1263
+ // ordering.
1264
+ const knowledgeInlineRM = await inlineKnowledgeBudgeted(base, extractKeywords(midTitle));
1265
+ const parts: string[] = [];
1266
+ if (knowledgeInlineRM && composed) {
1267
+ // Insert knowledge before the template block so the overall order is:
1268
+ // milestone-context → project → requirements → decisions → KNOWLEDGE → research template
1269
+ const idx = composed.lastIndexOf("### Output Template:");
1270
+ if (idx > 0) {
1271
+ const before = composed.slice(0, idx).replace(/\n\n---\n\n$/, "");
1272
+ const after = composed.slice(idx);
1273
+ parts.push(before, knowledgeInlineRM, after);
1274
+ } else {
1275
+ parts.push(composed, knowledgeInlineRM);
1276
+ }
1277
+ } else if (composed) {
1278
+ parts.push(composed);
1279
+ if (knowledgeInlineRM) parts.push(knowledgeInlineRM);
1280
+ }
1101
1281
 
1102
- const inlinedContext = capPreamble(`## Inlined Context (preloaded — do not re-read these files)\n\n${inlined.join("\n\n---\n\n")}`);
1282
+ const inlinedContext = capPreamble(`## Inlined Context (preloaded — do not re-read these files)\n\n${parts.join("\n\n---\n\n")}`);
1103
1283
 
1104
1284
  const outputRelPath = relMilestoneFile(base, mid, "RESEARCH");
1105
1285
  return loadPrompt("research-milestone", {
1106
1286
  workingDirectory: base,
1107
1287
  milestoneId: mid, milestoneTitle: midTitle,
1108
1288
  milestonePath: relMilestonePath(base, mid),
1109
- contextPath: contextRel,
1289
+ contextPath: relMilestoneFile(base, mid, "CONTEXT"),
1110
1290
  outputPath: join(base, outputRelPath),
1111
1291
  inlinedContext,
1112
1292
  skillActivation: buildSkillActivationBlock({
@@ -1114,6 +1294,7 @@ export async function buildResearchMilestonePrompt(mid: string, midTitle: string
1114
1294
  milestoneId: mid,
1115
1295
  milestoneTitle: midTitle,
1116
1296
  extraContext: [inlinedContext],
1297
+ unitType: "research-milestone",
1117
1298
  }),
1118
1299
  ...buildSkillDiscoveryVars(),
1119
1300
  });
@@ -1156,7 +1337,8 @@ export async function buildPlanMilestonePrompt(mid: string, midTitle: string, ba
1156
1337
  );
1157
1338
  inlined.push(queueInline);
1158
1339
  }
1159
- const knowledgeInlinePM = await inlineGsdRootFile(base, "knowledge.md", "Project Knowledge");
1340
+ // Scoped + budgeted see issue #4719
1341
+ const knowledgeInlinePM = await inlineKnowledgeBudgeted(base, extractKeywords(midTitle));
1160
1342
  if (knowledgeInlinePM) inlined.push(knowledgeInlinePM);
1161
1343
  inlined.push(inlineTemplate("roadmap", "Roadmap"));
1162
1344
  if (inlineLevel === "full") {
@@ -1191,6 +1373,7 @@ export async function buildPlanMilestonePrompt(mid: string, midTitle: string, ba
1191
1373
  milestoneId: mid,
1192
1374
  milestoneTitle: midTitle,
1193
1375
  extraContext: [inlinedContext],
1376
+ unitType: "plan-milestone",
1194
1377
  }),
1195
1378
  ...buildSkillDiscoveryVars(),
1196
1379
  });
@@ -1269,6 +1452,7 @@ export async function buildResearchSlicePrompt(
1269
1452
  sliceId: sid,
1270
1453
  sliceTitle: sTitle,
1271
1454
  extraContext: [inlinedContext, depContent],
1455
+ unitType: "research-slice",
1272
1456
  }),
1273
1457
  ...buildSkillDiscoveryVars(),
1274
1458
  });
@@ -1373,6 +1557,7 @@ async function renderSlicePrompt(options: {
1373
1557
  sliceId: sid,
1374
1558
  sliceTitle: sTitle,
1375
1559
  extraContext: [inlinedContext, depContent],
1560
+ unitType: promptTemplate,
1376
1561
  }),
1377
1562
  ...extraVars,
1378
1563
  });
@@ -1655,52 +1840,101 @@ export async function buildExecuteTaskPrompt(
1655
1840
  }
1656
1841
 
1657
1842
  export async function buildCompleteSlicePrompt(
1658
- mid: string, _midTitle: string, sid: string, sTitle: string, base: string, level?: InlineLevel,
1843
+ mid: string, midTitle: string, sid: string, sTitle: string, base: string, level?: InlineLevel,
1659
1844
  ): Promise<string> {
1660
1845
  const inlineLevel = level ?? resolveInlineLevel();
1661
1846
 
1662
- const roadmapPath = resolveMilestoneFile(base, mid, "ROADMAP");
1663
- const roadmapRel = relMilestoneFile(base, mid, "ROADMAP");
1664
- const slicePlanPath = resolveSliceFile(base, mid, sid, "PLAN");
1665
- const slicePlanRel = relSliceFile(base, mid, sid, "PLAN");
1666
- const sliceContextPath = resolveSliceFile(base, mid, sid, "CONTEXT");
1667
- const sliceContextRel = relSliceFile(base, mid, sid, "CONTEXT");
1847
+ // #4782 phase 3: complete-slice migrated through composer. Manifest
1848
+ // declares [roadmap, slice-context, slice-plan, requirements,
1849
+ // prior-task-summaries, templates]. Overrides prepend and knowledge
1850
+ // splice stay imperative they need the composer v2 contract
1851
+ // (computed + prepend blocks; see RFC #4924).
1852
+ const resolveArtifact: ArtifactResolver = async (key) => {
1853
+ switch (key) {
1854
+ case "roadmap": {
1855
+ const p = resolveMilestoneFile(base, mid, "ROADMAP");
1856
+ const r = relMilestoneFile(base, mid, "ROADMAP");
1857
+ return await inlineFile(p, r, "Milestone Roadmap");
1858
+ }
1859
+ case "slice-context": {
1860
+ const p = resolveSliceFile(base, mid, sid, "CONTEXT");
1861
+ const r = relSliceFile(base, mid, sid, "CONTEXT");
1862
+ return await inlineFileOptional(p, r, "Slice Context (from discussion)");
1863
+ }
1864
+ case "slice-plan": {
1865
+ const p = resolveSliceFile(base, mid, sid, "PLAN");
1866
+ const r = relSliceFile(base, mid, sid, "PLAN");
1867
+ return await inlineFile(p, r, "Slice Plan");
1868
+ }
1869
+ case "requirements":
1870
+ if (inlineLevel === "minimal") return null;
1871
+ return await inlineRequirementsFromDb(base, mid, sid, inlineLevel);
1872
+ case "prior-task-summaries": {
1873
+ const tDir = resolveTasksDir(base, mid, sid);
1874
+ if (!tDir) return null;
1875
+ const summaryFiles = resolveTaskFiles(tDir, "SUMMARY").sort();
1876
+ const sRel = relSlicePath(base, mid, sid);
1877
+ const blocks: string[] = [];
1878
+ for (const file of summaryFiles) {
1879
+ const absPath = join(tDir, file);
1880
+ const content = await loadFile(absPath);
1881
+ if (!content) continue;
1882
+ const relPath = `${sRel}/tasks/${file}`;
1883
+ blocks.push(`### Task Summary: ${file.replace(/-SUMMARY\.md$/i, "")}\nSource: \`${relPath}\`\n\n${content.trim()}`);
1884
+ }
1885
+ return blocks.length > 0 ? blocks.join("\n\n---\n\n") : null;
1886
+ }
1887
+ case "templates": {
1888
+ const parts = [inlineTemplate("slice-summary", "Slice Summary")];
1889
+ if (inlineLevel !== "minimal") {
1890
+ parts.push(inlineTemplate("uat", "UAT"));
1891
+ }
1892
+ return parts.join("\n\n---\n\n");
1893
+ }
1894
+ default:
1895
+ return null;
1896
+ }
1897
+ };
1668
1898
 
1669
- const inlined: string[] = [];
1670
- inlined.push(await inlineFile(roadmapPath, roadmapRel, "Milestone Roadmap"));
1671
- const sliceCtxInline = await inlineFileOptional(sliceContextPath, sliceContextRel, "Slice Context (from discussion)");
1672
- if (sliceCtxInline) inlined.push(sliceCtxInline);
1673
- inlined.push(await inlineFile(slicePlanPath, slicePlanRel, "Slice Plan"));
1674
- if (inlineLevel !== "minimal") {
1675
- const requirementsInline = await inlineRequirementsFromDb(base, mid, sid, inlineLevel);
1676
- if (requirementsInline) inlined.push(requirementsInline);
1677
- }
1678
- const knowledgeInlineCS = await inlineGsdRootFile(base, "knowledge.md", "Project Knowledge");
1679
- if (knowledgeInlineCS) inlined.push(knowledgeInlineCS);
1899
+ const composed = await composeInlinedContext("complete-slice", resolveArtifact);
1680
1900
 
1681
- // Inline all task summaries for this slice
1682
- const tDir = resolveTasksDir(base, mid, sid);
1683
- if (tDir) {
1684
- const summaryFiles = resolveTaskFiles(tDir, "SUMMARY").sort();
1685
- for (const file of summaryFiles) {
1686
- const absPath = join(tDir, file);
1687
- const content = await loadFile(absPath);
1688
- const sRel = relSlicePath(base, mid, sid);
1689
- const relPath = `${sRel}/tasks/${file}`;
1690
- if (content) {
1691
- inlined.push(`### Task Summary: ${file.replace(/-SUMMARY\.md$/i, "")}\nSource: \`${relPath}\`\n\n${content.trim()}`);
1692
- }
1901
+ // Knowledge splices in between requirements and prior-task-summaries
1902
+ // so overall order matches pre-migration: roadmap → slice-context →
1903
+ // slice-plan → requirements → KNOWLEDGE → task summaries → templates.
1904
+ const knowledgeInlineCS = await inlineKnowledgeBudgeted(
1905
+ base,
1906
+ [...extractKeywords(midTitle), ...extractKeywords(sTitle)],
1907
+ );
1908
+
1909
+ let body = composed;
1910
+ if (knowledgeInlineCS && body) {
1911
+ // Splice knowledge right before the first "### Task Summary:" block
1912
+ // to preserve pre-migration ordering. If no task summaries exist,
1913
+ // splice before the templates block (which inlineTemplate emits as
1914
+ // "### Output Template: Slice Summary").
1915
+ const taskIdx = body.indexOf("### Task Summary:");
1916
+ const templatesIdx = body.lastIndexOf("### Output Template: Slice Summary");
1917
+ const spliceIdx = taskIdx > -1 ? taskIdx : templatesIdx;
1918
+ if (spliceIdx > 0) {
1919
+ const before = body.slice(0, spliceIdx).replace(/\n\n---\n\n$/, "");
1920
+ const after = body.slice(spliceIdx);
1921
+ body = [before, knowledgeInlineCS, after].join("\n\n---\n\n");
1922
+ } else {
1923
+ body = `${body}\n\n---\n\n${knowledgeInlineCS}`;
1693
1924
  }
1694
1925
  }
1695
- inlined.push(inlineTemplate("slice-summary", "Slice Summary"));
1696
- if (inlineLevel !== "minimal") {
1697
- inlined.push(inlineTemplate("uat", "UAT"));
1698
- }
1926
+
1927
+ // Overrides section prepends to the top of the inlined context —
1928
+ // standard pattern for slice-level builders (until composer v2 lands
1929
+ // the prepend contract).
1699
1930
  const completeActiveOverrides = await loadActiveOverrides(base);
1700
1931
  const completeOverridesInline = formatOverridesSection(completeActiveOverrides);
1701
- if (completeOverridesInline) inlined.unshift(completeOverridesInline);
1932
+ const finalBody = completeOverridesInline
1933
+ ? `${completeOverridesInline}\n\n---\n\n${body}`
1934
+ : body;
1702
1935
 
1703
- const inlinedContext = capPreamble(`## Inlined Context (preloaded — do not re-read these files)\n\n${inlined.join("\n\n---\n\n")}`);
1936
+ const inlinedContext = capPreamble(`## Inlined Context (preloaded — do not re-read these files)\n\n${finalBody}`);
1937
+ const roadmapRel = relMilestoneFile(base, mid, "ROADMAP");
1704
1938
 
1705
1939
  const sliceRel = relSlicePath(base, mid, sid);
1706
1940
  const sliceSummaryPath = join(base, `${sliceRel}/${sid}-SUMMARY.md`);
@@ -1761,12 +1995,22 @@ export async function buildCompleteMilestonePrompt(
1761
1995
  }
1762
1996
  }
1763
1997
  const seenSlices = new Set<string>();
1998
+ const summaryRelPaths: string[] = [];
1764
1999
  for (const sid of sliceIds) {
1765
2000
  if (seenSlices.has(sid)) continue;
1766
2001
  seenSlices.add(sid);
1767
2002
  const summaryPath = resolveSliceFile(base, mid, sid, "SUMMARY");
1768
2003
  const summaryRel = relSliceFile(base, mid, sid, "SUMMARY");
1769
- inlined.push(await inlineFile(summaryPath, summaryRel, `${sid} Summary`));
2004
+ summaryRelPaths.push(summaryRel);
2005
+ // Compact excerpt instead of full inline (#4780). Closer Reads the
2006
+ // full file on-demand when synthesizing LEARNINGS narrative.
2007
+ inlined.push(await buildSliceSummaryExcerpt(summaryPath, summaryRel, sid));
2008
+ }
2009
+ if (summaryRelPaths.length > 0) {
2010
+ const pathList = summaryRelPaths.map(p => `- \`${p}\``).join("\n");
2011
+ inlined.push(
2012
+ `### On-demand Slice Summaries\n\nExcerpted above. Read the full file for any slice when the excerpt's section heads don't carry enough narrative for the milestone summary you're drafting:\n\n${pathList}`,
2013
+ );
1770
2014
  }
1771
2015
 
1772
2016
  // Inline root GSD files (skip for minimal — completion can read these if needed)
@@ -1778,7 +2022,8 @@ export async function buildCompleteMilestonePrompt(
1778
2022
  const projectInline = await inlineProjectFromDb(base);
1779
2023
  if (projectInline) inlined.push(projectInline);
1780
2024
  }
1781
- const knowledgeInlineCM = await inlineGsdRootFile(base, "knowledge.md", "Project Knowledge");
2025
+ // Scoped + budgeted see issue #4719
2026
+ const knowledgeInlineCM = await inlineKnowledgeBudgeted(base, extractKeywords(midTitle));
1782
2027
  if (knowledgeInlineCM) inlined.push(knowledgeInlineCM);
1783
2028
  // Inline milestone context file (milestone-level, not GSD root)
1784
2029
  const contextPath = resolveMilestoneFile(base, mid, "CONTEXT");
@@ -1812,6 +2057,7 @@ export async function buildCompleteMilestonePrompt(
1812
2057
  milestoneId: mid,
1813
2058
  milestoneTitle: midTitle,
1814
2059
  extraContext: [inlinedContext],
2060
+ unitType: "complete-milestone",
1815
2061
  }),
1816
2062
  });
1817
2063
  }
@@ -1914,7 +2160,8 @@ export async function buildValidateMilestonePrompt(
1914
2160
  const projectInline = await inlineProjectFromDb(base);
1915
2161
  if (projectInline) inlined.push(projectInline);
1916
2162
  }
1917
- const knowledgeInline = await inlineGsdRootFile(base, "knowledge.md", "Project Knowledge");
2163
+ // Scoped + budgeted see issue #4719
2164
+ const knowledgeInline = await inlineKnowledgeBudgeted(base, extractKeywords(midTitle));
1918
2165
  if (knowledgeInline) inlined.push(knowledgeInline);
1919
2166
  // Inline milestone context file
1920
2167
  const contextPath = resolveMilestoneFile(base, mid, "CONTEXT");
@@ -1951,6 +2198,7 @@ export async function buildValidateMilestonePrompt(
1951
2198
  milestoneId: mid,
1952
2199
  milestoneTitle: midTitle,
1953
2200
  extraContext: [inlinedContext],
2201
+ unitType: "validate-milestone",
1954
2202
  }),
1955
2203
  });
1956
2204
  }
@@ -2033,6 +2281,7 @@ export async function buildReplanSlicePrompt(
2033
2281
  sliceId: sid,
2034
2282
  sliceTitle: sTitle,
2035
2283
  extraContext: [inlinedContext, captureContext],
2284
+ unitType: "replan-slice",
2036
2285
  }),
2037
2286
  });
2038
2287
  }
@@ -2040,20 +2289,37 @@ export async function buildReplanSlicePrompt(
2040
2289
  export async function buildRunUatPrompt(
2041
2290
  mid: string, sliceId: string, uatPath: string, uatContent: string, base: string,
2042
2291
  ): Promise<string> {
2043
- const inlined: string[] = [];
2044
- inlined.push(await inlineFile(resolveSliceFile(base, mid, sliceId, "UAT"), uatPath, `${sliceId} UAT`));
2045
-
2046
- const summaryPath = resolveSliceFile(base, mid, sliceId, "SUMMARY");
2047
- const summaryRel = relSliceFile(base, mid, sliceId, "SUMMARY");
2048
- if (summaryPath) {
2049
- const summaryInline = await inlineFileOptional(summaryPath, summaryRel, `${sliceId} Summary`);
2050
- if (summaryInline) inlined.push(summaryInline);
2051
- }
2052
-
2053
- const projectInline = await inlineProjectFromDb(base);
2054
- if (projectInline) inlined.push(projectInline);
2292
+ // #4782 phase 3: run-uat migrated to compose its inlined context via
2293
+ // the manifest. Behavior-equivalent resolver dispatches to the same
2294
+ // inline* helpers as the pre-migration builder.
2295
+ const resolveArtifact: ArtifactResolver = async (key) => {
2296
+ switch (key) {
2297
+ case "slice-uat": {
2298
+ // Use the in-memory snapshot the caller already loaded (#4925 review).
2299
+ // Re-reading from disk via inlineFile(p, uatPath, ...) would risk
2300
+ // drift between the inlined body and uatType (computed from
2301
+ // uatContent below) if the file changes mid-dispatch.
2302
+ const trimmed = uatContent.trim();
2303
+ if (!trimmed) {
2304
+ return `### ${sliceId} UAT\nSource: \`${uatPath}\`\n\n_(not found — file does not exist yet)_`;
2305
+ }
2306
+ return `### ${sliceId} UAT\nSource: \`${uatPath}\`\n\n${trimmed}`;
2307
+ }
2308
+ case "slice-summary": {
2309
+ const p = resolveSliceFile(base, mid, sliceId, "SUMMARY");
2310
+ if (!p) return null;
2311
+ const r = relSliceFile(base, mid, sliceId, "SUMMARY");
2312
+ return await inlineFileOptional(p, r, `${sliceId} Summary`);
2313
+ }
2314
+ case "project":
2315
+ return await inlineProjectFromDb(base);
2316
+ default:
2317
+ return null;
2318
+ }
2319
+ };
2055
2320
 
2056
- const inlinedContext = capPreamble(`## Inlined Context (preloaded — do not re-read these files)\n\n${inlined.join("\n\n---\n\n")}`);
2321
+ const composed = await composeInlinedContext("run-uat", resolveArtifact);
2322
+ const inlinedContext = capPreamble(`## Inlined Context (preloaded — do not re-read these files)\n\n${composed}`);
2057
2323
 
2058
2324
  const uatResultPath = join(base, relSliceFile(base, mid, sliceId, "ASSESSMENT"));
2059
2325
  const uatType = getUatType(uatContent);
@@ -2071,6 +2337,7 @@ export async function buildRunUatPrompt(
2071
2337
  milestoneId: mid,
2072
2338
  sliceId,
2073
2339
  extraContext: [inlinedContext],
2340
+ unitType: "run-uat",
2074
2341
  }),
2075
2342
  });
2076
2343
  }
@@ -2079,30 +2346,54 @@ export async function buildReassessRoadmapPrompt(
2079
2346
  mid: string, midTitle: string, completedSliceId: string, base: string, level?: InlineLevel,
2080
2347
  ): Promise<string> {
2081
2348
  const inlineLevel = level ?? resolveInlineLevel();
2082
- const roadmapPath = resolveMilestoneFile(base, mid, "ROADMAP");
2083
- const roadmapRel = relMilestoneFile(base, mid, "ROADMAP");
2084
- const summaryPath = resolveSliceFile(base, mid, completedSliceId, "SUMMARY");
2085
- const summaryRel = relSliceFile(base, mid, completedSliceId, "SUMMARY");
2086
- const sliceContextPath = resolveSliceFile(base, mid, completedSliceId, "CONTEXT");
2087
- const sliceContextRel = relSliceFile(base, mid, completedSliceId, "CONTEXT");
2088
2349
 
2089
- const inlined: string[] = [];
2090
- inlined.push(await inlineFile(roadmapPath, roadmapRel, "Current Roadmap"));
2091
- const sliceCtxInline = await inlineFileOptional(sliceContextPath, sliceContextRel, "Slice Context (from discussion)");
2092
- if (sliceCtxInline) inlined.push(sliceCtxInline);
2093
- inlined.push(await inlineFile(summaryPath, summaryRel, `${completedSliceId} Summary`));
2094
- if (inlineLevel !== "minimal") {
2095
- const projectInline = await inlineProjectFromDb(base);
2096
- if (projectInline) inlined.push(projectInline);
2097
- const requirementsInline = await inlineRequirementsFromDb(base, mid, undefined, inlineLevel);
2098
- if (requirementsInline) inlined.push(requirementsInline);
2099
- const decisionsInline = await inlineDecisionsFromDb(base, mid, undefined, inlineLevel);
2100
- if (decisionsInline) inlined.push(decisionsInline);
2101
- }
2102
- const knowledgeInlineRA = await inlineGsdRootFile(base, "knowledge.md", "Project Knowledge");
2103
- if (knowledgeInlineRA) inlined.push(knowledgeInlineRA);
2350
+ // #4782 phase 2 pilot: reassess-roadmap is the first unit type to
2351
+ // compose its inlined context through the manifest-driven composer.
2352
+ // The resolver below dispatches artifact keys to the existing inline*
2353
+ // helpers, preserving identical output so the migration is
2354
+ // observable-equivalent. Knowledge stays outside the composer (it's
2355
+ // budget-driven, not manifest-driven) until a later phase formalizes
2356
+ // knowledge/memory policies as composer inputs.
2357
+ const resolveArtifact: ArtifactResolver = async (key) => {
2358
+ switch (key) {
2359
+ case "roadmap": {
2360
+ const p = resolveMilestoneFile(base, mid, "ROADMAP");
2361
+ const r = relMilestoneFile(base, mid, "ROADMAP");
2362
+ return await inlineFile(p, r, "Current Roadmap");
2363
+ }
2364
+ case "slice-context": {
2365
+ const p = resolveSliceFile(base, mid, completedSliceId, "CONTEXT");
2366
+ const r = relSliceFile(base, mid, completedSliceId, "CONTEXT");
2367
+ return await inlineFileOptional(p, r, "Slice Context (from discussion)");
2368
+ }
2369
+ case "slice-summary": {
2370
+ const p = resolveSliceFile(base, mid, completedSliceId, "SUMMARY");
2371
+ const r = relSliceFile(base, mid, completedSliceId, "SUMMARY");
2372
+ return await inlineFile(p, r, `${completedSliceId} Summary`);
2373
+ }
2374
+ case "project":
2375
+ if (inlineLevel === "minimal") return null;
2376
+ return await inlineProjectFromDb(base);
2377
+ case "requirements":
2378
+ if (inlineLevel === "minimal") return null;
2379
+ return await inlineRequirementsFromDb(base, mid, undefined, inlineLevel);
2380
+ case "decisions":
2381
+ if (inlineLevel === "minimal") return null;
2382
+ return await inlineDecisionsFromDb(base, mid, undefined, inlineLevel);
2383
+ default:
2384
+ return null;
2385
+ }
2386
+ };
2104
2387
 
2105
- const inlinedContext = capPreamble(`## Inlined Context (preloaded — do not re-read these files)\n\n${inlined.join("\n\n---\n\n")}`);
2388
+ const composed = await composeInlinedContext("reassess-roadmap", resolveArtifact);
2389
+ const parts: string[] = [];
2390
+ if (composed) parts.push(composed);
2391
+ // Knowledge block stays outside the composer — budgeted, scoped via
2392
+ // keyword extraction (#4719). Future phase folds it in.
2393
+ const knowledgeInlineRA = await inlineKnowledgeBudgeted(base, extractKeywords(midTitle));
2394
+ if (knowledgeInlineRA) parts.push(knowledgeInlineRA);
2395
+
2396
+ const inlinedContext = capPreamble(`## Inlined Context (preloaded — do not re-read these files)\n\n${parts.join("\n\n---\n\n")}`);
2106
2397
 
2107
2398
  const assessmentPath = join(base, relSliceFile(base, mid, completedSliceId, "ASSESSMENT"));
2108
2399
 
@@ -2127,7 +2418,7 @@ export async function buildReassessRoadmapPrompt(
2127
2418
  milestoneId: mid,
2128
2419
  milestoneTitle: midTitle,
2129
2420
  completedSliceId,
2130
- roadmapPath: roadmapRel,
2421
+ roadmapPath: relMilestoneFile(base, mid, "ROADMAP"),
2131
2422
  assessmentPath,
2132
2423
  inlinedContext,
2133
2424
  deferredCaptures,
@@ -2137,6 +2428,7 @@ export async function buildReassessRoadmapPrompt(
2137
2428
  milestoneId: mid,
2138
2429
  milestoneTitle: midTitle,
2139
2430
  extraContext: [inlinedContext, deferredCaptures],
2431
+ unitType: "reassess-roadmap",
2140
2432
  }),
2141
2433
  });
2142
2434
  }