gsd-pi 2.77.0-dev.58d3d4d6c → 2.77.0-dev.cfd69e714

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 (429) hide show
  1. package/README.md +1 -1
  2. package/dist/claude-cli-check.js +5 -1
  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 +5 -1
  13. package/dist/resources/extensions/claude-code-cli/stream-adapter.js +481 -17
  14. package/dist/resources/extensions/gsd/auto/loop.js +43 -0
  15. package/dist/resources/extensions/gsd/auto/phases.js +15 -21
  16. package/dist/resources/extensions/gsd/auto/session.js +0 -2
  17. package/dist/resources/extensions/gsd/auto-dispatch.js +102 -24
  18. package/dist/resources/extensions/gsd/auto-model-selection.js +124 -4
  19. package/dist/resources/extensions/gsd/auto-post-unit.js +71 -64
  20. package/dist/resources/extensions/gsd/auto-prompts.js +329 -102
  21. package/dist/resources/extensions/gsd/auto-recovery.js +195 -23
  22. package/dist/resources/extensions/gsd/auto-start.js +34 -24
  23. package/dist/resources/extensions/gsd/auto-tool-tracking.js +47 -7
  24. package/dist/resources/extensions/gsd/auto-worktree.js +122 -26
  25. package/dist/resources/extensions/gsd/auto.js +31 -20
  26. package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +9 -1
  27. package/dist/resources/extensions/gsd/bootstrap/db-tools.js +209 -0
  28. package/dist/resources/extensions/gsd/bootstrap/provider-error-resume.js +3 -6
  29. package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +7 -3
  30. package/dist/resources/extensions/gsd/bootstrap/write-gate.js +127 -9
  31. package/dist/resources/extensions/gsd/component-loader.js +447 -0
  32. package/dist/resources/extensions/gsd/component-types.js +69 -0
  33. package/dist/resources/extensions/gsd/detection.js +49 -1
  34. package/dist/resources/extensions/gsd/docs/preferences-reference.md +1 -1
  35. package/dist/resources/extensions/gsd/gate-registry.js +2 -2
  36. package/dist/resources/extensions/gsd/git-constants.js +28 -1
  37. package/dist/resources/extensions/gsd/git-self-heal.js +27 -0
  38. package/dist/resources/extensions/gsd/git-service.js +126 -2
  39. package/dist/resources/extensions/gsd/gsd-db.js +6 -3
  40. package/dist/resources/extensions/gsd/guided-flow.js +17 -5
  41. package/dist/resources/extensions/gsd/memory-extractor.js +7 -1
  42. package/dist/resources/extensions/gsd/milestone-scope-classifier.js +299 -0
  43. package/dist/resources/extensions/gsd/model-cost-table.js +3 -0
  44. package/dist/resources/extensions/gsd/model-router.js +6 -0
  45. package/dist/resources/extensions/gsd/native-git-bridge.js +34 -4
  46. package/dist/resources/extensions/gsd/prompts/complete-milestone.md +6 -2
  47. package/dist/resources/extensions/gsd/prompts/plan-slice.md +15 -2
  48. package/dist/resources/extensions/gsd/safety/git-checkpoint.js +11 -0
  49. package/dist/resources/extensions/gsd/service-tier.js +5 -2
  50. package/dist/resources/extensions/gsd/session-lock.js +19 -10
  51. package/dist/resources/extensions/gsd/skill-manifest.js +168 -0
  52. package/dist/resources/extensions/gsd/slice-parallel-orchestrator.js +278 -8
  53. package/dist/resources/extensions/gsd/state.js +44 -33
  54. package/dist/resources/extensions/gsd/sync-lock.js +98 -42
  55. package/dist/resources/extensions/gsd/unit-context-composer.js +147 -0
  56. package/dist/resources/extensions/gsd/unit-context-manifest.js +370 -0
  57. package/dist/resources/extensions/gsd/uok/gate-runner.js +53 -5
  58. package/dist/resources/extensions/gsd/workflow-mcp.js +6 -0
  59. package/dist/resources/extensions/gsd/worktree-manager.js +34 -8
  60. package/dist/resources/extensions/mcp-client/index.js +3 -1
  61. package/dist/resources/extensions/ollama/index.js +5 -1
  62. package/dist/resources/extensions/remote-questions/manager.js +11 -5
  63. package/dist/tsconfig.extensions.tsbuildinfo +1 -1
  64. package/dist/web/standalone/.next/BUILD_ID +1 -1
  65. package/dist/web/standalone/.next/app-path-routes-manifest.json +5 -5
  66. package/dist/web/standalone/.next/build-manifest.json +2 -2
  67. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  68. package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
  69. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  70. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  71. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  72. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  73. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  74. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  75. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  76. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  77. package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
  78. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
  79. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  80. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
  81. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  82. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  83. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  84. package/dist/web/standalone/.next/server/app/api/git/route.js +1 -1
  85. package/dist/web/standalone/.next/server/app/index.html +1 -1
  86. package/dist/web/standalone/.next/server/app/index.rsc +1 -1
  87. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
  88. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +1 -1
  89. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  90. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
  91. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  92. package/dist/web/standalone/.next/server/app-paths-manifest.json +5 -5
  93. package/dist/web/standalone/.next/server/chunks/1926.js +1 -1
  94. package/dist/web/standalone/.next/server/chunks/6897.js +1 -1
  95. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  96. package/dist/web/standalone/.next/server/middleware-manifest.json +5 -5
  97. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  98. package/dist/web/standalone/.next/server/pages/500.html +1 -1
  99. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  100. package/package.json +2 -3
  101. package/packages/daemon/src/logger.ts +4 -3
  102. package/packages/mcp-server/dist/server.d.ts +24 -0
  103. package/packages/mcp-server/dist/server.d.ts.map +1 -1
  104. package/packages/mcp-server/dist/server.js +88 -87
  105. package/packages/mcp-server/dist/server.js.map +1 -1
  106. package/packages/mcp-server/src/mcp-server.test.ts +25 -3
  107. package/packages/mcp-server/src/readers/graph.test.ts +87 -15
  108. package/packages/mcp-server/src/secure-env-collect.test.ts +232 -237
  109. package/packages/mcp-server/src/server.ts +131 -105
  110. package/packages/mcp-server/src/workflow-tools.test.ts +80 -39
  111. package/packages/mcp-server/tsconfig.tsbuildinfo +1 -1
  112. package/packages/native/package.json +1 -1
  113. package/packages/native/src/__tests__/_test-coverage-guard.test.mjs +98 -0
  114. package/packages/native/src/__tests__/module-compat.test.mjs +59 -27
  115. package/packages/native/src/__tests__/ps.test.mjs +14 -8
  116. package/packages/native/src/__tests__/stream-process.test.mjs +23 -2
  117. package/packages/native/src/__tests__/truncate.test.mjs +17 -2
  118. package/packages/pi-agent-core/src/agent-loop.test.ts +5 -15
  119. package/packages/pi-agent-core/src/agent.test.ts +96 -102
  120. package/packages/pi-agent-core/tsconfig.tsbuildinfo +1 -1
  121. package/packages/pi-ai/dist/models/capability-patches.d.ts.map +1 -1
  122. package/packages/pi-ai/dist/models/capability-patches.js +9 -2
  123. package/packages/pi-ai/dist/models/capability-patches.js.map +1 -1
  124. package/packages/pi-ai/dist/models/generated/index.d.ts +34 -0
  125. package/packages/pi-ai/dist/models/generated/index.d.ts.map +1 -1
  126. package/packages/pi-ai/dist/models/generated/openai-codex.d.ts +17 -0
  127. package/packages/pi-ai/dist/models/generated/openai-codex.d.ts.map +1 -1
  128. package/packages/pi-ai/dist/models/generated/openai-codex.js +17 -0
  129. package/packages/pi-ai/dist/models/generated/openai-codex.js.map +1 -1
  130. package/packages/pi-ai/dist/models/generated/openai.d.ts +17 -0
  131. package/packages/pi-ai/dist/models/generated/openai.d.ts.map +1 -1
  132. package/packages/pi-ai/dist/models/generated/openai.js +17 -0
  133. package/packages/pi-ai/dist/models/generated/openai.js.map +1 -1
  134. package/packages/pi-ai/dist/models.generated.test.js +43 -70
  135. package/packages/pi-ai/dist/models.generated.test.js.map +1 -1
  136. package/packages/pi-ai/dist/models.test.js +36 -11
  137. package/packages/pi-ai/dist/models.test.js.map +1 -1
  138. package/packages/pi-ai/scripts/generate-models.ts +44 -0
  139. package/packages/pi-ai/src/models/capability-patches.ts +10 -2
  140. package/packages/pi-ai/src/models/generated/openai-codex.ts +17 -0
  141. package/packages/pi-ai/src/models/generated/openai.ts +17 -0
  142. package/packages/pi-ai/src/models.generated.test.ts +46 -73
  143. package/packages/pi-ai/src/models.test.ts +48 -11
  144. package/packages/pi-ai/tsconfig.tsbuildinfo +1 -1
  145. package/packages/pi-coding-agent/dist/core/agent-session-abort-order.test.js +96 -32
  146. package/packages/pi-coding-agent/dist/core/agent-session-abort-order.test.js.map +1 -1
  147. package/packages/pi-coding-agent/dist/core/agent-session-model-switch.test.js +75 -12
  148. package/packages/pi-coding-agent/dist/core/agent-session-model-switch.test.js.map +1 -1
  149. package/packages/pi-coding-agent/dist/core/agent-session-tool-refresh.test.js +99 -31
  150. package/packages/pi-coding-agent/dist/core/agent-session-tool-refresh.test.js.map +1 -1
  151. package/packages/pi-coding-agent/dist/core/extensions/loader.d.ts +5 -0
  152. package/packages/pi-coding-agent/dist/core/extensions/loader.d.ts.map +1 -1
  153. package/packages/pi-coding-agent/dist/core/extensions/loader.js +61 -0
  154. package/packages/pi-coding-agent/dist/core/extensions/loader.js.map +1 -1
  155. package/packages/pi-coding-agent/dist/core/lsp/lsp-integration.test.js +30 -4
  156. package/packages/pi-coding-agent/dist/core/lsp/lsp-integration.test.js.map +1 -1
  157. package/packages/pi-coding-agent/dist/core/model-registry-auth-mode.test.js +17 -0
  158. package/packages/pi-coding-agent/dist/core/model-registry-auth-mode.test.js.map +1 -1
  159. package/packages/pi-coding-agent/dist/core/resource-loader-cache-reset.test.js +76 -18
  160. package/packages/pi-coding-agent/dist/core/resource-loader-cache-reset.test.js.map +1 -1
  161. package/packages/pi-coding-agent/dist/core/retry-handler.d.ts.map +1 -1
  162. package/packages/pi-coding-agent/dist/core/retry-handler.js +2 -6
  163. package/packages/pi-coding-agent/dist/core/retry-handler.js.map +1 -1
  164. package/packages/pi-coding-agent/dist/core/retry-handler.test.js +5 -1
  165. package/packages/pi-coding-agent/dist/core/retry-handler.test.js.map +1 -1
  166. package/packages/pi-coding-agent/dist/core/retryable-error-regex.d.ts +18 -0
  167. package/packages/pi-coding-agent/dist/core/retryable-error-regex.d.ts.map +1 -0
  168. package/packages/pi-coding-agent/dist/core/retryable-error-regex.js +18 -0
  169. package/packages/pi-coding-agent/dist/core/retryable-error-regex.js.map +1 -0
  170. package/packages/pi-coding-agent/dist/core/system-prompt.d.ts +20 -0
  171. package/packages/pi-coding-agent/dist/core/system-prompt.d.ts.map +1 -1
  172. package/packages/pi-coding-agent/dist/core/system-prompt.js +16 -2
  173. package/packages/pi-coding-agent/dist/core/system-prompt.js.map +1 -1
  174. package/packages/pi-coding-agent/dist/index.d.ts +1 -0
  175. package/packages/pi-coding-agent/dist/index.d.ts.map +1 -1
  176. package/packages/pi-coding-agent/dist/index.js +1 -0
  177. package/packages/pi-coding-agent/dist/index.js.map +1 -1
  178. package/packages/pi-coding-agent/dist/modes/interactive/components/dynamic-border.test.js +20 -13
  179. package/packages/pi-coding-agent/dist/modes/interactive/components/dynamic-border.test.js.map +1 -1
  180. package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.d.ts.map +1 -1
  181. package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.js +18 -3
  182. package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.js.map +1 -1
  183. package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.test.js +125 -0
  184. package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.test.js.map +1 -1
  185. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-state.d.ts +2 -0
  186. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-state.d.ts.map +1 -1
  187. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-state.js.map +1 -1
  188. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts +4 -0
  189. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  190. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js +105 -13
  191. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
  192. package/packages/pi-coding-agent/dist/tests/system-prompt-skill-filter.test.d.ts +2 -0
  193. package/packages/pi-coding-agent/dist/tests/system-prompt-skill-filter.test.d.ts.map +1 -0
  194. package/packages/pi-coding-agent/dist/tests/system-prompt-skill-filter.test.js +130 -0
  195. package/packages/pi-coding-agent/dist/tests/system-prompt-skill-filter.test.js.map +1 -0
  196. package/packages/pi-coding-agent/src/core/agent-session-abort-order.test.ts +113 -37
  197. package/packages/pi-coding-agent/src/core/agent-session-model-switch.test.ts +89 -17
  198. package/packages/pi-coding-agent/src/core/agent-session-tool-refresh.test.ts +112 -43
  199. package/packages/pi-coding-agent/src/core/extensions/loader.ts +58 -0
  200. package/packages/pi-coding-agent/src/core/lsp/lsp-integration.test.ts +35 -4
  201. package/packages/pi-coding-agent/src/core/model-registry-auth-mode.test.ts +20 -0
  202. package/packages/pi-coding-agent/src/core/resource-loader-cache-reset.test.ts +93 -28
  203. package/packages/pi-coding-agent/src/core/retry-handler.test.ts +5 -1
  204. package/packages/pi-coding-agent/src/core/retry-handler.ts +2 -8
  205. package/packages/pi-coding-agent/src/core/retryable-error-regex.ts +18 -0
  206. package/packages/pi-coding-agent/src/core/system-prompt.ts +35 -1
  207. package/packages/pi-coding-agent/src/index.ts +1 -0
  208. package/packages/pi-coding-agent/src/modes/interactive/components/dynamic-border.test.ts +26 -20
  209. package/packages/pi-coding-agent/src/modes/interactive/controllers/input-controller.test.ts +146 -1
  210. package/packages/pi-coding-agent/src/modes/interactive/controllers/input-controller.ts +20 -3
  211. package/packages/pi-coding-agent/src/modes/interactive/interactive-mode-state.ts +2 -0
  212. package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +119 -13
  213. package/packages/pi-coding-agent/src/tests/system-prompt-skill-filter.test.ts +157 -0
  214. package/packages/pi-coding-agent/tsconfig.tsbuildinfo +1 -1
  215. package/packages/pi-tui/dist/__tests__/autocomplete.test.js +18 -8
  216. package/packages/pi-tui/dist/__tests__/autocomplete.test.js.map +1 -1
  217. package/packages/pi-tui/dist/__tests__/overlay-layout.test.js +128 -17
  218. package/packages/pi-tui/dist/__tests__/overlay-layout.test.js.map +1 -1
  219. package/packages/pi-tui/dist/__tests__/stdin-buffer.test.js +36 -12
  220. package/packages/pi-tui/dist/__tests__/stdin-buffer.test.js.map +1 -1
  221. package/packages/pi-tui/dist/__tests__/tui.test.js +18 -30
  222. package/packages/pi-tui/dist/__tests__/tui.test.js.map +1 -1
  223. package/packages/pi-tui/dist/components/__tests__/input.test.js +10 -3
  224. package/packages/pi-tui/dist/components/__tests__/input.test.js.map +1 -1
  225. package/packages/pi-tui/dist/components/__tests__/loader.test.js +53 -9
  226. package/packages/pi-tui/dist/components/__tests__/loader.test.js.map +1 -1
  227. package/packages/pi-tui/dist/components/__tests__/markdown-maxlines.test.js +6 -2
  228. package/packages/pi-tui/dist/components/__tests__/markdown-maxlines.test.js.map +1 -1
  229. package/packages/pi-tui/dist/components/editor.d.ts +14 -0
  230. package/packages/pi-tui/dist/components/editor.d.ts.map +1 -1
  231. package/packages/pi-tui/dist/components/editor.js +19 -0
  232. package/packages/pi-tui/dist/components/editor.js.map +1 -1
  233. package/packages/pi-tui/dist/components/image.test.js +6 -5
  234. package/packages/pi-tui/dist/components/image.test.js.map +1 -1
  235. package/packages/pi-tui/dist/editor-component.d.ts +2 -0
  236. package/packages/pi-tui/dist/editor-component.d.ts.map +1 -1
  237. package/packages/pi-tui/dist/editor-component.js.map +1 -1
  238. package/packages/pi-tui/src/__tests__/autocomplete.test.ts +24 -8
  239. package/packages/pi-tui/src/__tests__/overlay-layout.test.ts +140 -17
  240. package/packages/pi-tui/src/__tests__/stdin-buffer.test.ts +41 -12
  241. package/packages/pi-tui/src/__tests__/tui.test.ts +18 -37
  242. package/packages/pi-tui/src/components/__tests__/input.test.ts +19 -3
  243. package/packages/pi-tui/src/components/__tests__/loader.test.ts +112 -35
  244. package/packages/pi-tui/src/components/__tests__/markdown-maxlines.test.ts +9 -2
  245. package/packages/pi-tui/src/components/editor.ts +22 -0
  246. package/packages/pi-tui/src/components/image.test.ts +10 -5
  247. package/packages/pi-tui/src/editor-component.ts +3 -0
  248. package/packages/pi-tui/tsconfig.tsbuildinfo +1 -1
  249. package/packages/rpc-client/dist/rpc-client.test.js +101 -51
  250. package/packages/rpc-client/dist/rpc-client.test.js.map +1 -1
  251. package/packages/rpc-client/src/rpc-client.test.ts +109 -52
  252. package/packages/rpc-client/tsconfig.tsbuildinfo +1 -1
  253. package/scripts/install.js +15 -1
  254. package/src/resources/extensions/browser-tools/capture.ts +12 -0
  255. package/src/resources/extensions/browser-tools/tests/browser-tools-integration.test.mjs +8 -59
  256. package/src/resources/extensions/browser-tools/tests/browser-tools-unit.test.cjs +36 -24
  257. package/src/resources/extensions/browser-tools/tests/capture-sharp-optional.test.cjs +69 -71
  258. package/src/resources/extensions/browser-tools/tools/forms.ts +5 -1
  259. package/src/resources/extensions/browser-tools/tools/intent.ts +5 -1
  260. package/src/resources/extensions/claude-code-cli/readiness.ts +5 -1
  261. package/src/resources/extensions/claude-code-cli/stream-adapter.ts +518 -19
  262. package/src/resources/extensions/claude-code-cli/tests/stream-adapter.test.ts +919 -75
  263. package/src/resources/extensions/github-sync/tests/cli.test.ts +76 -7
  264. package/src/resources/extensions/github-sync/tests/templates.test.ts +33 -1
  265. package/src/resources/extensions/gsd/auto/loop.ts +47 -0
  266. package/src/resources/extensions/gsd/auto/phases.ts +16 -20
  267. package/src/resources/extensions/gsd/auto/session.ts +0 -2
  268. package/src/resources/extensions/gsd/auto-dispatch.ts +113 -24
  269. package/src/resources/extensions/gsd/auto-model-selection.ts +131 -4
  270. package/src/resources/extensions/gsd/auto-post-unit.ts +82 -73
  271. package/src/resources/extensions/gsd/auto-prompts.ts +330 -90
  272. package/src/resources/extensions/gsd/auto-recovery.ts +225 -24
  273. package/src/resources/extensions/gsd/auto-start.ts +54 -6
  274. package/src/resources/extensions/gsd/auto-tool-tracking.ts +51 -7
  275. package/src/resources/extensions/gsd/auto-worktree.ts +130 -26
  276. package/src/resources/extensions/gsd/auto.ts +43 -22
  277. package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +9 -1
  278. package/src/resources/extensions/gsd/bootstrap/db-tools.ts +221 -0
  279. package/src/resources/extensions/gsd/bootstrap/provider-error-resume.ts +3 -7
  280. package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +7 -3
  281. package/src/resources/extensions/gsd/bootstrap/write-gate.ts +158 -9
  282. package/src/resources/extensions/gsd/component-loader.ts +598 -0
  283. package/src/resources/extensions/gsd/component-types.ts +362 -0
  284. package/src/resources/extensions/gsd/detection.ts +58 -1
  285. package/src/resources/extensions/gsd/docs/preferences-reference.md +1 -1
  286. package/src/resources/extensions/gsd/gate-registry.ts +2 -2
  287. package/src/resources/extensions/gsd/git-constants.ts +30 -1
  288. package/src/resources/extensions/gsd/git-self-heal.ts +31 -0
  289. package/src/resources/extensions/gsd/git-service.ts +133 -2
  290. package/src/resources/extensions/gsd/gsd-db.ts +6 -3
  291. package/src/resources/extensions/gsd/guided-flow.ts +20 -5
  292. package/src/resources/extensions/gsd/memory-extractor.ts +11 -3
  293. package/src/resources/extensions/gsd/milestone-scope-classifier.ts +366 -0
  294. package/src/resources/extensions/gsd/model-cost-table.ts +3 -0
  295. package/src/resources/extensions/gsd/model-router.ts +6 -0
  296. package/src/resources/extensions/gsd/native-git-bridge.ts +34 -4
  297. package/src/resources/extensions/gsd/prompts/complete-milestone.md +6 -2
  298. package/src/resources/extensions/gsd/prompts/plan-slice.md +15 -2
  299. package/src/resources/extensions/gsd/safety/git-checkpoint.ts +15 -0
  300. package/src/resources/extensions/gsd/service-tier.ts +5 -2
  301. package/src/resources/extensions/gsd/session-lock.ts +20 -10
  302. package/src/resources/extensions/gsd/skill-manifest.ts +175 -0
  303. package/src/resources/extensions/gsd/slice-parallel-orchestrator.ts +309 -8
  304. package/src/resources/extensions/gsd/state.ts +49 -44
  305. package/src/resources/extensions/gsd/sync-lock.ts +97 -39
  306. package/src/resources/extensions/gsd/tests/artifact-retry-cap.test.ts +270 -0
  307. package/src/resources/extensions/gsd/tests/auto-deterministic-error-classification-4973.test.ts +341 -0
  308. package/src/resources/extensions/gsd/tests/auto-discuss-milestone-deadlock-4973.test.ts +264 -0
  309. package/src/resources/extensions/gsd/tests/auto-loop.test.ts +94 -289
  310. package/src/resources/extensions/gsd/tests/auto-model-selection-tool-poisoning.test.ts +742 -0
  311. package/src/resources/extensions/gsd/tests/auto-model-selection.test.ts +78 -0
  312. package/src/resources/extensions/gsd/tests/auto-phases-lifecycle.test.ts +61 -0
  313. package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +93 -0
  314. package/src/resources/extensions/gsd/tests/auto-retry-mcp-churn-fixes.test.ts +8 -197
  315. package/src/resources/extensions/gsd/tests/auto-start-needs-discussion.test.ts +15 -58
  316. package/src/resources/extensions/gsd/tests/cache-staleness-regression.test.ts +17 -21
  317. package/src/resources/extensions/gsd/tests/complete-milestone-excerpt.test.ts +263 -0
  318. package/src/resources/extensions/gsd/tests/complete-milestone.test.ts +25 -0
  319. package/src/resources/extensions/gsd/tests/complete-slice-composer.test.ts +192 -0
  320. package/src/resources/extensions/gsd/tests/complete-task.test.ts +16 -8
  321. package/src/resources/extensions/gsd/tests/component-loader.test.ts +589 -0
  322. package/src/resources/extensions/gsd/tests/component-types.test.ts +127 -0
  323. package/src/resources/extensions/gsd/tests/crash-recovery.test.ts +50 -1
  324. package/src/resources/extensions/gsd/tests/derive-state-crossval.test.ts +3 -3
  325. package/src/resources/extensions/gsd/tests/derive-state-db-disk-reconcile.test.ts +40 -0
  326. package/src/resources/extensions/gsd/tests/derive-state-db.test.ts +91 -3
  327. package/src/resources/extensions/gsd/tests/derive-state.test.ts +4 -3
  328. package/src/resources/extensions/gsd/tests/dispatcher-stuck-planning.test.ts +3 -2
  329. package/src/resources/extensions/gsd/tests/extension-bootstrap-isolation.test.ts +139 -129
  330. package/src/resources/extensions/gsd/tests/finalize-timeout-guard.test.ts +9 -105
  331. package/src/resources/extensions/gsd/tests/gate-state-canonicalization.test.ts +102 -0
  332. package/src/resources/extensions/gsd/tests/gate-storage.test.ts +1 -1
  333. package/src/resources/extensions/gsd/tests/hook-key-parsing.test.ts +4 -55
  334. package/src/resources/extensions/gsd/tests/integration/all-milestones-complete-merge.test.ts +7 -57
  335. package/src/resources/extensions/gsd/tests/integration/auto-recovery.test.ts +20 -0
  336. package/src/resources/extensions/gsd/tests/integration/doctor-proactive.test.ts +18 -2
  337. package/src/resources/extensions/gsd/tests/integration/queue-completed-milestone-perf.test.ts +10 -4
  338. package/src/resources/extensions/gsd/tests/integration/state-machine-edge-cases.test.ts +144 -7
  339. package/src/resources/extensions/gsd/tests/integration/state-machine-live-validation.test.ts +4 -0
  340. package/src/resources/extensions/gsd/tests/integration/state-machine-runtime-failures.test.ts +2 -16
  341. package/src/resources/extensions/gsd/tests/interrupted-session-ui.test.ts +6 -9
  342. package/src/resources/extensions/gsd/tests/mcp-client-security.test.ts +8 -37
  343. package/src/resources/extensions/gsd/tests/memory-extractor.test.ts +5 -15
  344. package/src/resources/extensions/gsd/tests/merge-conflict-stops-loop.test.ts +227 -62
  345. package/src/resources/extensions/gsd/tests/milestone-scope-classifier.test.ts +187 -0
  346. package/src/resources/extensions/gsd/tests/model-cost-table.test.ts +9 -1
  347. package/src/resources/extensions/gsd/tests/model-router.test.ts +1 -1
  348. package/src/resources/extensions/gsd/tests/native-git-bridge-exec-fallback.test.ts +6 -49
  349. package/src/resources/extensions/gsd/tests/notification-widget.test.ts +6 -3
  350. package/src/resources/extensions/gsd/tests/parallel-research-dispatch.test.ts +273 -133
  351. package/src/resources/extensions/gsd/tests/pipeline-variant-dispatch.test.ts +301 -0
  352. package/src/resources/extensions/gsd/tests/pre-execution-pause-wiring.test.ts +32 -1
  353. package/src/resources/extensions/gsd/tests/provider-errors.test.ts +23 -24
  354. package/src/resources/extensions/gsd/tests/queue-auto-guard.test.ts +32 -0
  355. package/src/resources/extensions/gsd/tests/ready-phrase-no-files-4573.test.ts +75 -2
  356. package/src/resources/extensions/gsd/tests/reassess-default-optin.test.ts +132 -0
  357. package/src/resources/extensions/gsd/tests/recovery-attempts-reset.test.ts +8 -40
  358. package/src/resources/extensions/gsd/tests/regex-hardening.test.ts +136 -256
  359. package/src/resources/extensions/gsd/tests/research-milestone-composer.test.ts +114 -0
  360. package/src/resources/extensions/gsd/tests/run-uat-composer.test.ts +148 -0
  361. package/src/resources/extensions/gsd/tests/service-tier.test.ts +4 -0
  362. package/src/resources/extensions/gsd/tests/session-lock-regression.test.ts +29 -0
  363. package/src/resources/extensions/gsd/tests/silent-catch-diagnostics.test.ts +55 -95
  364. package/src/resources/extensions/gsd/tests/single-writer-v3-tool-surface.test.ts +158 -0
  365. package/src/resources/extensions/gsd/tests/skill-activation.test.ts +120 -1
  366. package/src/resources/extensions/gsd/tests/skill-manifest.test.ts +112 -0
  367. package/src/resources/extensions/gsd/tests/slice-parallel-orchestrator.test.ts +164 -1
  368. package/src/resources/extensions/gsd/tests/state-machine-full-walkthrough.test.ts +5 -5
  369. package/src/resources/extensions/gsd/tests/structured-data-formatter.test.ts +11 -92
  370. package/src/resources/extensions/gsd/tests/survivor-branch-complete.test.ts +102 -101
  371. package/src/resources/extensions/gsd/tests/sync-lock.test.ts +31 -0
  372. package/src/resources/extensions/gsd/tests/test-helpers.test.ts +12 -61
  373. package/src/resources/extensions/gsd/tests/test-helpers.ts +21 -8
  374. package/src/resources/extensions/gsd/tests/tool-invocation-error-loop-break.test.ts +61 -1
  375. package/src/resources/extensions/gsd/tests/tool-naming.test.ts +8 -1
  376. package/src/resources/extensions/gsd/tests/unit-context-composer.test.ts +355 -0
  377. package/src/resources/extensions/gsd/tests/unit-context-manifest.test.ts +258 -0
  378. package/src/resources/extensions/gsd/tests/uok-gate-runner.test.ts +75 -0
  379. package/src/resources/extensions/gsd/tests/uok-gitops-wiring.test.ts +49 -26
  380. package/src/resources/extensions/gsd/tests/validate-milestone.test.ts +1 -0
  381. package/src/resources/extensions/gsd/tests/verify-artifact-tightened.test.ts +144 -81
  382. package/src/resources/extensions/gsd/tests/visualizer-critical-path.test.ts +20 -54
  383. package/src/resources/extensions/gsd/tests/visualizer-overlay.test.ts +342 -277
  384. package/src/resources/extensions/gsd/tests/worker-model-override.test.ts +37 -29
  385. package/src/resources/extensions/gsd/tests/worktree-db.test.ts +226 -266
  386. package/src/resources/extensions/gsd/tests/worktree-health-monorepo.test.ts +103 -67
  387. package/src/resources/extensions/gsd/tests/worktree-nested-git-safety.test.ts +92 -90
  388. package/src/resources/extensions/gsd/tests/worktree-submodule-safety.test.ts +238 -59
  389. package/src/resources/extensions/gsd/tests/worktree-sync-overwrite-loop.test.ts +113 -161
  390. package/src/resources/extensions/gsd/tests/write-gate-planning-unit.test.ts +262 -0
  391. package/src/resources/extensions/gsd/tests/write-gate-predicates.test.ts +186 -0
  392. package/src/resources/extensions/gsd/tests/write-gate.test.ts +7 -5
  393. package/src/resources/extensions/gsd/tests/zombie-gsd-state.test.ts +80 -96
  394. package/src/resources/extensions/gsd/types.ts +3 -3
  395. package/src/resources/extensions/gsd/unit-context-composer.ts +218 -0
  396. package/src/resources/extensions/gsd/unit-context-manifest.ts +574 -0
  397. package/src/resources/extensions/gsd/uok/gate-runner.ts +65 -5
  398. package/src/resources/extensions/gsd/workflow-mcp.ts +6 -0
  399. package/src/resources/extensions/gsd/worktree-manager.ts +55 -7
  400. package/src/resources/extensions/mcp-client/index.ts +3 -1
  401. package/src/resources/extensions/mcp-client/tests/server-name-spaces.test.ts +70 -36
  402. package/src/resources/extensions/ollama/index.ts +5 -1
  403. package/src/resources/extensions/ollama/ollama-auth-mode.test.ts +123 -15
  404. package/src/resources/extensions/ollama/ollama-status-indicator.test.ts +206 -19
  405. package/src/resources/extensions/remote-questions/manager.ts +36 -4
  406. package/src/resources/extensions/remote-questions/tests/command-polling.test.ts +200 -190
  407. package/src/resources/extensions/shared/tests/interview-preview.test.ts +11 -3
  408. package/src/resources/extensions/voice/tests/linux-ready.test.ts +129 -113
  409. package/packages/pi-ai/dist/utils/oauth/oauth-providers.test.d.ts +0 -2
  410. package/packages/pi-ai/dist/utils/oauth/oauth-providers.test.d.ts.map +0 -1
  411. package/packages/pi-ai/dist/utils/oauth/oauth-providers.test.js +0 -289
  412. package/packages/pi-ai/dist/utils/oauth/oauth-providers.test.js.map +0 -1
  413. package/packages/pi-ai/src/utils/oauth/oauth-providers.test.ts +0 -363
  414. package/src/resources/extensions/gsd/tests/auto-start-model-capture.test.ts +0 -144
  415. package/src/resources/extensions/gsd/tests/complete-milestone-false-merge.test.ts +0 -157
  416. package/src/resources/extensions/gsd/tests/dashboard-model-label-ordering.test.ts +0 -107
  417. package/src/resources/extensions/gsd/tests/find-missing-summaries-closed.test.ts +0 -48
  418. package/src/resources/extensions/gsd/tests/forensics-context-persist.test.ts +0 -159
  419. package/src/resources/extensions/gsd/tests/forensics-db-completion.test.ts +0 -96
  420. package/src/resources/extensions/gsd/tests/forensics-dedup.test.ts +0 -79
  421. package/src/resources/extensions/gsd/tests/forensics-hook-key-parse.test.ts +0 -75
  422. package/src/resources/extensions/gsd/tests/forensics-journal.test.ts +0 -162
  423. package/src/resources/extensions/gsd/tests/forensics-worktree-telemetry.test.ts +0 -145
  424. package/src/resources/extensions/gsd/tests/gitignore-bg-shell.test.ts +0 -38
  425. package/src/resources/extensions/gsd/tests/gsd-no-project-error.test.ts +0 -73
  426. package/src/resources/extensions/gsd/tests/idle-watchdog-stall-override.test.ts +0 -130
  427. package/src/resources/extensions/gsd/tests/import-done-milestones.test.ts +0 -43
  428. /package/dist/web/standalone/.next/static/{Cev5xrAYA3ZGTRLyjR2fX → SvCJDZPQW104bR1KnBQg1}/_buildManifest.js +0 -0
  429. /package/dist/web/standalone/.next/static/{Cev5xrAYA3ZGTRLyjR2fX → SvCJDZPQW104bR1KnBQg1}/_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
  */
@@ -704,8 +787,14 @@ export function buildSkillActivationBlock(params: {
704
787
  extraContext?: string[];
705
788
  taskPlanContent?: string | null;
706
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;
707
796
  }): string {
708
- const prefs = params.preferences ?? loadEffectiveGSDPreferences()?.preferences;
797
+ const prefs = params.preferences ?? loadEffectiveGSDPreferences(params.base)?.preferences;
709
798
  const contextTokens = tokenizeSkillContext(
710
799
  params.milestoneId,
711
800
  params.milestoneTitle,
@@ -715,8 +804,22 @@ export function buildSkillActivationBlock(params: {
715
804
  params.taskTitle,
716
805
  );
717
806
 
718
- 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;
719
821
  const installedNames = new Set(visibleSkills.map(skill => normalizeSkillReference(skill.name)));
822
+ warnIfManifestHasMissingSkills(params.unitType, installedNames);
720
823
  const avoided = new Set(resolvePreferenceSkillNames(prefs?.avoid_skills ?? [], params.base));
721
824
  const matched = new Set<string>();
722
825
 
@@ -1126,30 +1229,64 @@ export async function buildDiscussMilestonePrompt(
1126
1229
  }
1127
1230
 
1128
1231
  export async function buildResearchMilestonePrompt(mid: string, midTitle: string, base: string): Promise<string> {
1129
- const contextPath = resolveMilestoneFile(base, mid, "CONTEXT");
1130
- 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
+ };
1131
1256
 
1132
- const inlined: string[] = [];
1133
- inlined.push(await inlineFile(contextPath, contextRel, "Milestone Context"));
1134
- const projectInline = await inlineProjectFromDb(base);
1135
- if (projectInline) inlined.push(projectInline);
1136
- const requirementsInline = await inlineRequirementsFromDb(base, mid);
1137
- if (requirementsInline) inlined.push(requirementsInline);
1138
- const decisionsInline = await inlineDecisionsFromDb(base, mid);
1139
- if (decisionsInline) inlined.push(decisionsInline);
1140
- // Scoped + budgeted — see issue #4719
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.
1141
1264
  const knowledgeInlineRM = await inlineKnowledgeBudgeted(base, extractKeywords(midTitle));
1142
- if (knowledgeInlineRM) inlined.push(knowledgeInlineRM);
1143
- inlined.push(inlineTemplate("research", "Research"));
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
+ }
1144
1281
 
1145
- 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")}`);
1146
1283
 
1147
1284
  const outputRelPath = relMilestoneFile(base, mid, "RESEARCH");
1148
1285
  return loadPrompt("research-milestone", {
1149
1286
  workingDirectory: base,
1150
1287
  milestoneId: mid, milestoneTitle: midTitle,
1151
1288
  milestonePath: relMilestonePath(base, mid),
1152
- contextPath: contextRel,
1289
+ contextPath: relMilestoneFile(base, mid, "CONTEXT"),
1153
1290
  outputPath: join(base, outputRelPath),
1154
1291
  inlinedContext,
1155
1292
  skillActivation: buildSkillActivationBlock({
@@ -1157,6 +1294,7 @@ export async function buildResearchMilestonePrompt(mid: string, midTitle: string
1157
1294
  milestoneId: mid,
1158
1295
  milestoneTitle: midTitle,
1159
1296
  extraContext: [inlinedContext],
1297
+ unitType: "research-milestone",
1160
1298
  }),
1161
1299
  ...buildSkillDiscoveryVars(),
1162
1300
  });
@@ -1235,6 +1373,7 @@ export async function buildPlanMilestonePrompt(mid: string, midTitle: string, ba
1235
1373
  milestoneId: mid,
1236
1374
  milestoneTitle: midTitle,
1237
1375
  extraContext: [inlinedContext],
1376
+ unitType: "plan-milestone",
1238
1377
  }),
1239
1378
  ...buildSkillDiscoveryVars(),
1240
1379
  });
@@ -1313,6 +1452,7 @@ export async function buildResearchSlicePrompt(
1313
1452
  sliceId: sid,
1314
1453
  sliceTitle: sTitle,
1315
1454
  extraContext: [inlinedContext, depContent],
1455
+ unitType: "research-slice",
1316
1456
  }),
1317
1457
  ...buildSkillDiscoveryVars(),
1318
1458
  });
@@ -1417,6 +1557,7 @@ async function renderSlicePrompt(options: {
1417
1557
  sliceId: sid,
1418
1558
  sliceTitle: sTitle,
1419
1559
  extraContext: [inlinedContext, depContent],
1560
+ unitType: promptTemplate,
1420
1561
  }),
1421
1562
  ...extraVars,
1422
1563
  });
@@ -1703,53 +1844,97 @@ export async function buildCompleteSlicePrompt(
1703
1844
  ): Promise<string> {
1704
1845
  const inlineLevel = level ?? resolveInlineLevel();
1705
1846
 
1706
- const roadmapPath = resolveMilestoneFile(base, mid, "ROADMAP");
1707
- const roadmapRel = relMilestoneFile(base, mid, "ROADMAP");
1708
- const slicePlanPath = resolveSliceFile(base, mid, sid, "PLAN");
1709
- const slicePlanRel = relSliceFile(base, mid, sid, "PLAN");
1710
- const sliceContextPath = resolveSliceFile(base, mid, sid, "CONTEXT");
1711
- 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
+ };
1712
1898
 
1713
- const inlined: string[] = [];
1714
- inlined.push(await inlineFile(roadmapPath, roadmapRel, "Milestone Roadmap"));
1715
- const sliceCtxInline = await inlineFileOptional(sliceContextPath, sliceContextRel, "Slice Context (from discussion)");
1716
- if (sliceCtxInline) inlined.push(sliceCtxInline);
1717
- inlined.push(await inlineFile(slicePlanPath, slicePlanRel, "Slice Plan"));
1718
- if (inlineLevel !== "minimal") {
1719
- const requirementsInline = await inlineRequirementsFromDb(base, mid, sid, inlineLevel);
1720
- if (requirementsInline) inlined.push(requirementsInline);
1721
- }
1722
- // Scoped + budgeted — see issue #4719. Slice context is richer than
1723
- // milestone context at complete-slice time, so combine both title sources.
1899
+ const composed = await composeInlinedContext("complete-slice", resolveArtifact);
1900
+
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.
1724
1904
  const knowledgeInlineCS = await inlineKnowledgeBudgeted(
1725
1905
  base,
1726
1906
  [...extractKeywords(midTitle), ...extractKeywords(sTitle)],
1727
1907
  );
1728
- if (knowledgeInlineCS) inlined.push(knowledgeInlineCS);
1729
1908
 
1730
- // Inline all task summaries for this slice
1731
- const tDir = resolveTasksDir(base, mid, sid);
1732
- if (tDir) {
1733
- const summaryFiles = resolveTaskFiles(tDir, "SUMMARY").sort();
1734
- for (const file of summaryFiles) {
1735
- const absPath = join(tDir, file);
1736
- const content = await loadFile(absPath);
1737
- const sRel = relSlicePath(base, mid, sid);
1738
- const relPath = `${sRel}/tasks/${file}`;
1739
- if (content) {
1740
- inlined.push(`### Task Summary: ${file.replace(/-SUMMARY\.md$/i, "")}\nSource: \`${relPath}\`\n\n${content.trim()}`);
1741
- }
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}`;
1742
1924
  }
1743
1925
  }
1744
- inlined.push(inlineTemplate("slice-summary", "Slice Summary"));
1745
- if (inlineLevel !== "minimal") {
1746
- inlined.push(inlineTemplate("uat", "UAT"));
1747
- }
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).
1748
1930
  const completeActiveOverrides = await loadActiveOverrides(base);
1749
1931
  const completeOverridesInline = formatOverridesSection(completeActiveOverrides);
1750
- if (completeOverridesInline) inlined.unshift(completeOverridesInline);
1932
+ const finalBody = completeOverridesInline
1933
+ ? `${completeOverridesInline}\n\n---\n\n${body}`
1934
+ : body;
1751
1935
 
1752
- 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");
1753
1938
 
1754
1939
  const sliceRel = relSlicePath(base, mid, sid);
1755
1940
  const sliceSummaryPath = join(base, `${sliceRel}/${sid}-SUMMARY.md`);
@@ -1810,12 +1995,22 @@ export async function buildCompleteMilestonePrompt(
1810
1995
  }
1811
1996
  }
1812
1997
  const seenSlices = new Set<string>();
1998
+ const summaryRelPaths: string[] = [];
1813
1999
  for (const sid of sliceIds) {
1814
2000
  if (seenSlices.has(sid)) continue;
1815
2001
  seenSlices.add(sid);
1816
2002
  const summaryPath = resolveSliceFile(base, mid, sid, "SUMMARY");
1817
2003
  const summaryRel = relSliceFile(base, mid, sid, "SUMMARY");
1818
- 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
+ );
1819
2014
  }
1820
2015
 
1821
2016
  // Inline root GSD files (skip for minimal — completion can read these if needed)
@@ -1862,6 +2057,7 @@ export async function buildCompleteMilestonePrompt(
1862
2057
  milestoneId: mid,
1863
2058
  milestoneTitle: midTitle,
1864
2059
  extraContext: [inlinedContext],
2060
+ unitType: "complete-milestone",
1865
2061
  }),
1866
2062
  });
1867
2063
  }
@@ -2002,6 +2198,7 @@ export async function buildValidateMilestonePrompt(
2002
2198
  milestoneId: mid,
2003
2199
  milestoneTitle: midTitle,
2004
2200
  extraContext: [inlinedContext],
2201
+ unitType: "validate-milestone",
2005
2202
  }),
2006
2203
  });
2007
2204
  }
@@ -2084,6 +2281,7 @@ export async function buildReplanSlicePrompt(
2084
2281
  sliceId: sid,
2085
2282
  sliceTitle: sTitle,
2086
2283
  extraContext: [inlinedContext, captureContext],
2284
+ unitType: "replan-slice",
2087
2285
  }),
2088
2286
  });
2089
2287
  }
@@ -2091,20 +2289,37 @@ export async function buildReplanSlicePrompt(
2091
2289
  export async function buildRunUatPrompt(
2092
2290
  mid: string, sliceId: string, uatPath: string, uatContent: string, base: string,
2093
2291
  ): Promise<string> {
2094
- const inlined: string[] = [];
2095
- inlined.push(await inlineFile(resolveSliceFile(base, mid, sliceId, "UAT"), uatPath, `${sliceId} UAT`));
2096
-
2097
- const summaryPath = resolveSliceFile(base, mid, sliceId, "SUMMARY");
2098
- const summaryRel = relSliceFile(base, mid, sliceId, "SUMMARY");
2099
- if (summaryPath) {
2100
- const summaryInline = await inlineFileOptional(summaryPath, summaryRel, `${sliceId} Summary`);
2101
- if (summaryInline) inlined.push(summaryInline);
2102
- }
2103
-
2104
- const projectInline = await inlineProjectFromDb(base);
2105
- 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
+ };
2106
2320
 
2107
- 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}`);
2108
2323
 
2109
2324
  const uatResultPath = join(base, relSliceFile(base, mid, sliceId, "ASSESSMENT"));
2110
2325
  const uatType = getUatType(uatContent);
@@ -2122,6 +2337,7 @@ export async function buildRunUatPrompt(
2122
2337
  milestoneId: mid,
2123
2338
  sliceId,
2124
2339
  extraContext: [inlinedContext],
2340
+ unitType: "run-uat",
2125
2341
  }),
2126
2342
  });
2127
2343
  }
@@ -2130,31 +2346,54 @@ export async function buildReassessRoadmapPrompt(
2130
2346
  mid: string, midTitle: string, completedSliceId: string, base: string, level?: InlineLevel,
2131
2347
  ): Promise<string> {
2132
2348
  const inlineLevel = level ?? resolveInlineLevel();
2133
- const roadmapPath = resolveMilestoneFile(base, mid, "ROADMAP");
2134
- const roadmapRel = relMilestoneFile(base, mid, "ROADMAP");
2135
- const summaryPath = resolveSliceFile(base, mid, completedSliceId, "SUMMARY");
2136
- const summaryRel = relSliceFile(base, mid, completedSliceId, "SUMMARY");
2137
- const sliceContextPath = resolveSliceFile(base, mid, completedSliceId, "CONTEXT");
2138
- const sliceContextRel = relSliceFile(base, mid, completedSliceId, "CONTEXT");
2139
2349
 
2140
- const inlined: string[] = [];
2141
- inlined.push(await inlineFile(roadmapPath, roadmapRel, "Current Roadmap"));
2142
- const sliceCtxInline = await inlineFileOptional(sliceContextPath, sliceContextRel, "Slice Context (from discussion)");
2143
- if (sliceCtxInline) inlined.push(sliceCtxInline);
2144
- inlined.push(await inlineFile(summaryPath, summaryRel, `${completedSliceId} Summary`));
2145
- if (inlineLevel !== "minimal") {
2146
- const projectInline = await inlineProjectFromDb(base);
2147
- if (projectInline) inlined.push(projectInline);
2148
- const requirementsInline = await inlineRequirementsFromDb(base, mid, undefined, inlineLevel);
2149
- if (requirementsInline) inlined.push(requirementsInline);
2150
- const decisionsInline = await inlineDecisionsFromDb(base, mid, undefined, inlineLevel);
2151
- if (decisionsInline) inlined.push(decisionsInline);
2152
- }
2153
- // Scoped + budgeted — see issue #4719
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
+ };
2387
+
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.
2154
2393
  const knowledgeInlineRA = await inlineKnowledgeBudgeted(base, extractKeywords(midTitle));
2155
- if (knowledgeInlineRA) inlined.push(knowledgeInlineRA);
2394
+ if (knowledgeInlineRA) parts.push(knowledgeInlineRA);
2156
2395
 
2157
- const inlinedContext = capPreamble(`## Inlined Context (preloaded — do not re-read these files)\n\n${inlined.join("\n\n---\n\n")}`);
2396
+ const inlinedContext = capPreamble(`## Inlined Context (preloaded — do not re-read these files)\n\n${parts.join("\n\n---\n\n")}`);
2158
2397
 
2159
2398
  const assessmentPath = join(base, relSliceFile(base, mid, completedSliceId, "ASSESSMENT"));
2160
2399
 
@@ -2179,7 +2418,7 @@ export async function buildReassessRoadmapPrompt(
2179
2418
  milestoneId: mid,
2180
2419
  milestoneTitle: midTitle,
2181
2420
  completedSliceId,
2182
- roadmapPath: roadmapRel,
2421
+ roadmapPath: relMilestoneFile(base, mid, "ROADMAP"),
2183
2422
  assessmentPath,
2184
2423
  inlinedContext,
2185
2424
  deferredCaptures,
@@ -2189,6 +2428,7 @@ export async function buildReassessRoadmapPrompt(
2189
2428
  milestoneId: mid,
2190
2429
  milestoneTitle: midTitle,
2191
2430
  extraContext: [inlinedContext, deferredCaptures],
2431
+ unitType: "reassess-roadmap",
2192
2432
  }),
2193
2433
  });
2194
2434
  }