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
@@ -19,9 +19,11 @@ import { getPendingGatesForTurn } from "./gsd-db.js";
19
19
  import { assertGateCoverage, getGatesForTurn, } from "./gate-registry.js";
20
20
  import { formatDecisionsCompact, formatRequirementsCompact } from "./structured-data-formatter.js";
21
21
  import { readPhaseAnchor, formatAnchorForPrompt } from "./phase-anchor.js";
22
+ import { composeInlinedContext } from "./unit-context-composer.js";
22
23
  import { logWarning } from "./workflow-logger.js";
23
24
  import { inlineGraphSubgraph } from "./graph-context.js";
24
25
  import { buildExtractionStepsBlock } from "./commands-extract-learnings.js";
26
+ import { warnIfManifestHasMissingSkills } from "./skill-manifest.js";
25
27
  // ─── Preamble Cap ─────────────────────────────────────────────────────────────
26
28
  /**
27
29
  * Historical static ceiling for the preamble cap. Kept as an upper bound even
@@ -201,6 +203,87 @@ export async function inlineFileSmart(absPath, relPath, label, query, threshold
201
203
  const truncated = truncateAtSectionBoundary(content, threshold).content;
202
204
  return `### ${label}\nSource: \`${relPath}\`\n\n${truncated}`;
203
205
  }
206
+ /**
207
+ * Compact slice-summary excerpt for milestone-level closers (#4780).
208
+ *
209
+ * Emits the frontmatter fields + short body section heads rather than the
210
+ * full SUMMARY.md body, and keeps the source path in the header so the
211
+ * closer agent can Read the full file on demand when drafting LEARNINGS.
212
+ *
213
+ * Scope: designed for `buildCompleteMilestonePrompt`, which previously
214
+ * inlined the full SUMMARY per slice and routinely paid ~300–500K tokens
215
+ * per close when the narrative was never synthesized. Not used by
216
+ * `buildValidateMilestonePrompt` yet — validate needs fuller verification
217
+ * evidence; follow-up PR can extend or parameterize.
218
+ *
219
+ * If parsing fails (unrecognizable frontmatter, missing id, etc.) the
220
+ * function falls back to `inlineFile` so the closer loses no information.
221
+ */
222
+ export async function buildSliceSummaryExcerpt(absPath, relPath, sid) {
223
+ const header = `### ${sid} Summary (excerpt)\nSource: \`${relPath}\``;
224
+ const content = absPath ? await loadFile(absPath) : null;
225
+ if (!content) {
226
+ return `${header}\n\n_(not found — file does not exist yet)_`;
227
+ }
228
+ try {
229
+ const s = parseSummary(content);
230
+ if (!s.frontmatter.id) {
231
+ // Unrecognizable — fall back to full file so no context is lost.
232
+ return `### ${sid} Summary\nSource: \`${relPath}\`\n\n${content.trim()}`;
233
+ }
234
+ const lines = [header, ""];
235
+ if (s.title)
236
+ lines.push(`**Title:** ${s.title}`);
237
+ if (s.oneLiner)
238
+ lines.push(`**One-liner:** ${s.oneLiner}`);
239
+ if (s.frontmatter.verification_result) {
240
+ lines.push(`**Verification:** \`${s.frontmatter.verification_result}\``);
241
+ }
242
+ lines.push(`**Blockers:** ${s.frontmatter.blocker_discovered ? "⚠️ blocker recorded — Read full summary" : "none"}`);
243
+ if (s.frontmatter.duration)
244
+ lines.push(`**Duration:** ${s.frontmatter.duration}`);
245
+ if (s.frontmatter.provides.length > 0)
246
+ lines.push(`**Provides:** ${s.frontmatter.provides.join("; ")}`);
247
+ if (s.frontmatter.affects.length > 0)
248
+ lines.push(`**Affects:** ${s.frontmatter.affects.join("; ")}`);
249
+ if (s.frontmatter.key_decisions.length > 0)
250
+ lines.push(`**Key decisions:** ${s.frontmatter.key_decisions.join("; ")}`);
251
+ if (s.frontmatter.patterns_established.length > 0)
252
+ lines.push(`**Patterns established:** ${s.frontmatter.patterns_established.join("; ")}`);
253
+ if (s.frontmatter.key_files.length > 0) {
254
+ const files = s.frontmatter.key_files.slice(0, 8);
255
+ const more = s.frontmatter.key_files.length > files.length ? ` (+${s.frontmatter.key_files.length - files.length} more)` : "";
256
+ lines.push(`**Key files:** ${files.join(", ")}${more}`);
257
+ }
258
+ // Cap section bodies (coderabbit review on #4908): if any of these
259
+ // narrative sections balloon, excerpt mode still inflates and
260
+ // undermines the token-reduction goal. 800 chars (~200 tokens) is
261
+ // enough to carry intent; the closer agent Reads the full file when
262
+ // it needs richer context for LEARNINGS synthesis.
263
+ const SECTION_CAP_CHARS = 800;
264
+ const capSection = (body) => {
265
+ const trimmed = body.trim();
266
+ if (trimmed.length <= SECTION_CAP_CHARS)
267
+ return trimmed;
268
+ return `${trimmed.slice(0, SECTION_CAP_CHARS)}\n… (truncated — see full \`${relPath}\`)`;
269
+ };
270
+ if (s.deviations && s.deviations.trim()) {
271
+ lines.push("", "#### Deviations", capSection(s.deviations));
272
+ }
273
+ if (s.knownLimitations && s.knownLimitations.trim()) {
274
+ lines.push("", "#### Known limitations", capSection(s.knownLimitations));
275
+ }
276
+ if (s.followUps && s.followUps.trim()) {
277
+ lines.push("", "#### Follow-ups", capSection(s.followUps));
278
+ }
279
+ lines.push("", `> **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.`);
280
+ return lines.join("\n");
281
+ }
282
+ catch {
283
+ // Defensive — any parse failure falls back to full inline.
284
+ return `### ${sid} Summary\nSource: \`${relPath}\`\n\n${content.trim()}`;
285
+ }
286
+ }
204
287
  /**
205
288
  * Load and inline dependency slice summaries (full content, not just paths).
206
289
  */
@@ -593,10 +676,23 @@ function formatSkillActivationBlock(skillNames) {
593
676
  return `<skill_activation>${calls}.</skill_activation>`;
594
677
  }
595
678
  export function buildSkillActivationBlock(params) {
596
- const prefs = params.preferences ?? loadEffectiveGSDPreferences()?.preferences;
679
+ const prefs = params.preferences ?? loadEffectiveGSDPreferences(params.base)?.preferences;
597
680
  const contextTokens = tokenizeSkillContext(params.milestoneId, params.milestoneTitle, params.sliceId, params.sliceTitle, params.taskId, params.taskTitle);
598
- const visibleSkills = (typeof getLoadedSkills === 'function' ? getLoadedSkills() : []).filter(skill => !skill.disableModelInvocation);
681
+ const loaded = (typeof getLoadedSkills === 'function' ? getLoadedSkills() : []).filter(skill => !skill.disableModelInvocation);
682
+ // Skill activation here is driven entirely by explicit sources
683
+ // (always_use_skills, prefer_skills, skill_rules, task-plan skills_used).
684
+ // Every match is an explicit user/project intent and must not be dropped
685
+ // by the unit-type manifest — user intent is stronger signal than
686
+ // defaults. The manifest's real home is the skill catalog rendering
687
+ // layer (pi-coding-agent `formatSkillsForPrompt`); that wiring is tracked
688
+ // as the "load-time short-circuit" follow-up to RFC #4779.
689
+ //
690
+ // `unitType` stays plumbed so the strict-mode warning can surface
691
+ // manifest entries that reference uninstalled skills, and so the
692
+ // activation-block site is ready to opt in once PR B lands.
693
+ const visibleSkills = loaded;
599
694
  const installedNames = new Set(visibleSkills.map(skill => normalizeSkillReference(skill.name)));
695
+ warnIfManifestHasMissingSkills(params.unitType, installedNames);
600
696
  const avoided = new Set(resolvePreferenceSkillNames(prefs?.avoid_skills ?? [], params.base));
601
697
  const matched = new Set();
602
698
  for (const name of resolvePreferenceSkillNames(prefs?.always_use_skills ?? [], params.base)) {
@@ -979,31 +1075,63 @@ export async function buildDiscussMilestonePrompt(mid, midTitle, base, structure
979
1075
  return basePrompt;
980
1076
  }
981
1077
  export async function buildResearchMilestonePrompt(mid, midTitle, base) {
982
- const contextPath = resolveMilestoneFile(base, mid, "CONTEXT");
983
- const contextRel = relMilestoneFile(base, mid, "CONTEXT");
984
- const inlined = [];
985
- inlined.push(await inlineFile(contextPath, contextRel, "Milestone Context"));
986
- const projectInline = await inlineProjectFromDb(base);
987
- if (projectInline)
988
- inlined.push(projectInline);
989
- const requirementsInline = await inlineRequirementsFromDb(base, mid);
990
- if (requirementsInline)
991
- inlined.push(requirementsInline);
992
- const decisionsInline = await inlineDecisionsFromDb(base, mid);
993
- if (decisionsInline)
994
- inlined.push(decisionsInline);
995
- // Scoped + budgeted — see issue #4719
1078
+ // #4782 phase 3: research-milestone migrated through the composer.
1079
+ // Declared inline order: milestone-context, project, requirements,
1080
+ // decisions, templates. Knowledge stays outside the composer
1081
+ // (budget-driven, scoped by keyword extraction — future phase folds
1082
+ // policy-driven blocks in).
1083
+ const resolveArtifact = async (key) => {
1084
+ switch (key) {
1085
+ case "milestone-context": {
1086
+ const p = resolveMilestoneFile(base, mid, "CONTEXT");
1087
+ const r = relMilestoneFile(base, mid, "CONTEXT");
1088
+ return await inlineFile(p, r, "Milestone Context");
1089
+ }
1090
+ case "project":
1091
+ return await inlineProjectFromDb(base);
1092
+ case "requirements":
1093
+ return await inlineRequirementsFromDb(base, mid);
1094
+ case "decisions":
1095
+ return await inlineDecisionsFromDb(base, mid);
1096
+ case "templates":
1097
+ return inlineTemplate("research", "Research");
1098
+ default:
1099
+ return null;
1100
+ }
1101
+ };
1102
+ const composed = await composeInlinedContext("research-milestone", resolveArtifact);
1103
+ // Knowledge block stays outside the composer — budgeted, scoped via
1104
+ // keyword extraction (#4719). Inserted between decisions and the
1105
+ // templates block to match the pre-migration output order. We split
1106
+ // the composer output around the templates section to preserve that
1107
+ // ordering.
996
1108
  const knowledgeInlineRM = await inlineKnowledgeBudgeted(base, extractKeywords(midTitle));
997
- if (knowledgeInlineRM)
998
- inlined.push(knowledgeInlineRM);
999
- inlined.push(inlineTemplate("research", "Research"));
1000
- const inlinedContext = capPreamble(`## Inlined Context (preloaded do not re-read these files)\n\n${inlined.join("\n\n---\n\n")}`);
1109
+ const parts = [];
1110
+ if (knowledgeInlineRM && composed) {
1111
+ // Insert knowledge before the template block so the overall order is:
1112
+ // milestone-context project requirements decisions KNOWLEDGE research template
1113
+ const idx = composed.lastIndexOf("### Output Template:");
1114
+ if (idx > 0) {
1115
+ const before = composed.slice(0, idx).replace(/\n\n---\n\n$/, "");
1116
+ const after = composed.slice(idx);
1117
+ parts.push(before, knowledgeInlineRM, after);
1118
+ }
1119
+ else {
1120
+ parts.push(composed, knowledgeInlineRM);
1121
+ }
1122
+ }
1123
+ else if (composed) {
1124
+ parts.push(composed);
1125
+ if (knowledgeInlineRM)
1126
+ parts.push(knowledgeInlineRM);
1127
+ }
1128
+ const inlinedContext = capPreamble(`## Inlined Context (preloaded — do not re-read these files)\n\n${parts.join("\n\n---\n\n")}`);
1001
1129
  const outputRelPath = relMilestoneFile(base, mid, "RESEARCH");
1002
1130
  return loadPrompt("research-milestone", {
1003
1131
  workingDirectory: base,
1004
1132
  milestoneId: mid, milestoneTitle: midTitle,
1005
1133
  milestonePath: relMilestonePath(base, mid),
1006
- contextPath: contextRel,
1134
+ contextPath: relMilestoneFile(base, mid, "CONTEXT"),
1007
1135
  outputPath: join(base, outputRelPath),
1008
1136
  inlinedContext,
1009
1137
  skillActivation: buildSkillActivationBlock({
@@ -1011,6 +1139,7 @@ export async function buildResearchMilestonePrompt(mid, midTitle, base) {
1011
1139
  milestoneId: mid,
1012
1140
  milestoneTitle: midTitle,
1013
1141
  extraContext: [inlinedContext],
1142
+ unitType: "research-milestone",
1014
1143
  }),
1015
1144
  ...buildSkillDiscoveryVars(),
1016
1145
  });
@@ -1086,6 +1215,7 @@ export async function buildPlanMilestonePrompt(mid, midTitle, base, level) {
1086
1215
  milestoneId: mid,
1087
1216
  milestoneTitle: midTitle,
1088
1217
  extraContext: [inlinedContext],
1218
+ unitType: "plan-milestone",
1089
1219
  }),
1090
1220
  ...buildSkillDiscoveryVars(),
1091
1221
  });
@@ -1159,6 +1289,7 @@ export async function buildResearchSlicePrompt(mid, _midTitle, sid, sTitle, base
1159
1289
  sliceId: sid,
1160
1290
  sliceTitle: sTitle,
1161
1291
  extraContext: [inlinedContext, depContent],
1292
+ unitType: "research-slice",
1162
1293
  }),
1163
1294
  ...buildSkillDiscoveryVars(),
1164
1295
  });
@@ -1245,6 +1376,7 @@ async function renderSlicePrompt(options) {
1245
1376
  sliceId: sid,
1246
1377
  sliceTitle: sTitle,
1247
1378
  extraContext: [inlinedContext, depContent],
1379
+ unitType: promptTemplate,
1248
1380
  }),
1249
1381
  ...extraVars,
1250
1382
  });
@@ -1455,51 +1587,93 @@ export async function buildExecuteTaskPrompt(mid, sid, sTitle, tid, tTitle, base
1455
1587
  }
1456
1588
  export async function buildCompleteSlicePrompt(mid, midTitle, sid, sTitle, base, level) {
1457
1589
  const inlineLevel = level ?? resolveInlineLevel();
1458
- const roadmapPath = resolveMilestoneFile(base, mid, "ROADMAP");
1459
- const roadmapRel = relMilestoneFile(base, mid, "ROADMAP");
1460
- const slicePlanPath = resolveSliceFile(base, mid, sid, "PLAN");
1461
- const slicePlanRel = relSliceFile(base, mid, sid, "PLAN");
1462
- const sliceContextPath = resolveSliceFile(base, mid, sid, "CONTEXT");
1463
- const sliceContextRel = relSliceFile(base, mid, sid, "CONTEXT");
1464
- const inlined = [];
1465
- inlined.push(await inlineFile(roadmapPath, roadmapRel, "Milestone Roadmap"));
1466
- const sliceCtxInline = await inlineFileOptional(sliceContextPath, sliceContextRel, "Slice Context (from discussion)");
1467
- if (sliceCtxInline)
1468
- inlined.push(sliceCtxInline);
1469
- inlined.push(await inlineFile(slicePlanPath, slicePlanRel, "Slice Plan"));
1470
- if (inlineLevel !== "minimal") {
1471
- const requirementsInline = await inlineRequirementsFromDb(base, mid, sid, inlineLevel);
1472
- if (requirementsInline)
1473
- inlined.push(requirementsInline);
1474
- }
1475
- // Scoped + budgeted — see issue #4719. Slice context is richer than
1476
- // milestone context at complete-slice time, so combine both title sources.
1477
- const knowledgeInlineCS = await inlineKnowledgeBudgeted(base, [...extractKeywords(midTitle), ...extractKeywords(sTitle)]);
1478
- if (knowledgeInlineCS)
1479
- inlined.push(knowledgeInlineCS);
1480
- // Inline all task summaries for this slice
1481
- const tDir = resolveTasksDir(base, mid, sid);
1482
- if (tDir) {
1483
- const summaryFiles = resolveTaskFiles(tDir, "SUMMARY").sort();
1484
- for (const file of summaryFiles) {
1485
- const absPath = join(tDir, file);
1486
- const content = await loadFile(absPath);
1487
- const sRel = relSlicePath(base, mid, sid);
1488
- const relPath = `${sRel}/tasks/${file}`;
1489
- if (content) {
1490
- inlined.push(`### Task Summary: ${file.replace(/-SUMMARY\.md$/i, "")}\nSource: \`${relPath}\`\n\n${content.trim()}`);
1590
+ // #4782 phase 3: complete-slice migrated through composer. Manifest
1591
+ // declares [roadmap, slice-context, slice-plan, requirements,
1592
+ // prior-task-summaries, templates]. Overrides prepend and knowledge
1593
+ // splice stay imperative they need the composer v2 contract
1594
+ // (computed + prepend blocks; see RFC #4924).
1595
+ const resolveArtifact = async (key) => {
1596
+ switch (key) {
1597
+ case "roadmap": {
1598
+ const p = resolveMilestoneFile(base, mid, "ROADMAP");
1599
+ const r = relMilestoneFile(base, mid, "ROADMAP");
1600
+ return await inlineFile(p, r, "Milestone Roadmap");
1601
+ }
1602
+ case "slice-context": {
1603
+ const p = resolveSliceFile(base, mid, sid, "CONTEXT");
1604
+ const r = relSliceFile(base, mid, sid, "CONTEXT");
1605
+ return await inlineFileOptional(p, r, "Slice Context (from discussion)");
1491
1606
  }
1607
+ case "slice-plan": {
1608
+ const p = resolveSliceFile(base, mid, sid, "PLAN");
1609
+ const r = relSliceFile(base, mid, sid, "PLAN");
1610
+ return await inlineFile(p, r, "Slice Plan");
1611
+ }
1612
+ case "requirements":
1613
+ if (inlineLevel === "minimal")
1614
+ return null;
1615
+ return await inlineRequirementsFromDb(base, mid, sid, inlineLevel);
1616
+ case "prior-task-summaries": {
1617
+ const tDir = resolveTasksDir(base, mid, sid);
1618
+ if (!tDir)
1619
+ return null;
1620
+ const summaryFiles = resolveTaskFiles(tDir, "SUMMARY").sort();
1621
+ const sRel = relSlicePath(base, mid, sid);
1622
+ const blocks = [];
1623
+ for (const file of summaryFiles) {
1624
+ const absPath = join(tDir, file);
1625
+ const content = await loadFile(absPath);
1626
+ if (!content)
1627
+ continue;
1628
+ const relPath = `${sRel}/tasks/${file}`;
1629
+ blocks.push(`### Task Summary: ${file.replace(/-SUMMARY\.md$/i, "")}\nSource: \`${relPath}\`\n\n${content.trim()}`);
1630
+ }
1631
+ return blocks.length > 0 ? blocks.join("\n\n---\n\n") : null;
1632
+ }
1633
+ case "templates": {
1634
+ const parts = [inlineTemplate("slice-summary", "Slice Summary")];
1635
+ if (inlineLevel !== "minimal") {
1636
+ parts.push(inlineTemplate("uat", "UAT"));
1637
+ }
1638
+ return parts.join("\n\n---\n\n");
1639
+ }
1640
+ default:
1641
+ return null;
1642
+ }
1643
+ };
1644
+ const composed = await composeInlinedContext("complete-slice", resolveArtifact);
1645
+ // Knowledge splices in between requirements and prior-task-summaries
1646
+ // so overall order matches pre-migration: roadmap → slice-context →
1647
+ // slice-plan → requirements → KNOWLEDGE → task summaries → templates.
1648
+ const knowledgeInlineCS = await inlineKnowledgeBudgeted(base, [...extractKeywords(midTitle), ...extractKeywords(sTitle)]);
1649
+ let body = composed;
1650
+ if (knowledgeInlineCS && body) {
1651
+ // Splice knowledge right before the first "### Task Summary:" block
1652
+ // to preserve pre-migration ordering. If no task summaries exist,
1653
+ // splice before the templates block (which inlineTemplate emits as
1654
+ // "### Output Template: Slice Summary").
1655
+ const taskIdx = body.indexOf("### Task Summary:");
1656
+ const templatesIdx = body.lastIndexOf("### Output Template: Slice Summary");
1657
+ const spliceIdx = taskIdx > -1 ? taskIdx : templatesIdx;
1658
+ if (spliceIdx > 0) {
1659
+ const before = body.slice(0, spliceIdx).replace(/\n\n---\n\n$/, "");
1660
+ const after = body.slice(spliceIdx);
1661
+ body = [before, knowledgeInlineCS, after].join("\n\n---\n\n");
1662
+ }
1663
+ else {
1664
+ body = `${body}\n\n---\n\n${knowledgeInlineCS}`;
1492
1665
  }
1493
1666
  }
1494
- inlined.push(inlineTemplate("slice-summary", "Slice Summary"));
1495
- if (inlineLevel !== "minimal") {
1496
- inlined.push(inlineTemplate("uat", "UAT"));
1497
- }
1667
+ // Overrides section prepends to the top of the inlined context
1668
+ // standard pattern for slice-level builders (until composer v2 lands
1669
+ // the prepend contract).
1498
1670
  const completeActiveOverrides = await loadActiveOverrides(base);
1499
1671
  const completeOverridesInline = formatOverridesSection(completeActiveOverrides);
1500
- if (completeOverridesInline)
1501
- inlined.unshift(completeOverridesInline);
1502
- const inlinedContext = capPreamble(`## Inlined Context (preloaded — do not re-read these files)\n\n${inlined.join("\n\n---\n\n")}`);
1672
+ const finalBody = completeOverridesInline
1673
+ ? `${completeOverridesInline}\n\n---\n\n${body}`
1674
+ : body;
1675
+ const inlinedContext = capPreamble(`## Inlined Context (preloaded — do not re-read these files)\n\n${finalBody}`);
1676
+ const roadmapRel = relMilestoneFile(base, mid, "ROADMAP");
1503
1677
  const sliceRel = relSlicePath(base, mid, sid);
1504
1678
  const sliceSummaryPath = join(base, `${sliceRel}/${sid}-SUMMARY.md`);
1505
1679
  const sliceUatPath = join(base, `${sliceRel}/${sid}-UAT.md`);
@@ -1550,13 +1724,21 @@ export async function buildCompleteMilestonePrompt(mid, midTitle, base, level) {
1550
1724
  }
1551
1725
  }
1552
1726
  const seenSlices = new Set();
1727
+ const summaryRelPaths = [];
1553
1728
  for (const sid of sliceIds) {
1554
1729
  if (seenSlices.has(sid))
1555
1730
  continue;
1556
1731
  seenSlices.add(sid);
1557
1732
  const summaryPath = resolveSliceFile(base, mid, sid, "SUMMARY");
1558
1733
  const summaryRel = relSliceFile(base, mid, sid, "SUMMARY");
1559
- inlined.push(await inlineFile(summaryPath, summaryRel, `${sid} Summary`));
1734
+ summaryRelPaths.push(summaryRel);
1735
+ // Compact excerpt instead of full inline (#4780). Closer Reads the
1736
+ // full file on-demand when synthesizing LEARNINGS narrative.
1737
+ inlined.push(await buildSliceSummaryExcerpt(summaryPath, summaryRel, sid));
1738
+ }
1739
+ if (summaryRelPaths.length > 0) {
1740
+ const pathList = summaryRelPaths.map(p => `- \`${p}\``).join("\n");
1741
+ inlined.push(`### 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}`);
1560
1742
  }
1561
1743
  // Inline root GSD files (skip for minimal — completion can read these if needed)
1562
1744
  if (inlineLevel !== "minimal") {
@@ -1603,6 +1785,7 @@ export async function buildCompleteMilestonePrompt(mid, midTitle, base, level) {
1603
1785
  milestoneId: mid,
1604
1786
  milestoneTitle: midTitle,
1605
1787
  extraContext: [inlinedContext],
1788
+ unitType: "complete-milestone",
1606
1789
  }),
1607
1790
  });
1608
1791
  }
@@ -1746,6 +1929,7 @@ export async function buildValidateMilestonePrompt(mid, midTitle, base, level) {
1746
1929
  milestoneId: mid,
1747
1930
  milestoneTitle: midTitle,
1748
1931
  extraContext: [inlinedContext],
1932
+ unitType: "validate-milestone",
1749
1933
  }),
1750
1934
  });
1751
1935
  }
@@ -1821,23 +2005,42 @@ export async function buildReplanSlicePrompt(mid, midTitle, sid, sTitle, base) {
1821
2005
  sliceId: sid,
1822
2006
  sliceTitle: sTitle,
1823
2007
  extraContext: [inlinedContext, captureContext],
2008
+ unitType: "replan-slice",
1824
2009
  }),
1825
2010
  });
1826
2011
  }
1827
2012
  export async function buildRunUatPrompt(mid, sliceId, uatPath, uatContent, base) {
1828
- const inlined = [];
1829
- inlined.push(await inlineFile(resolveSliceFile(base, mid, sliceId, "UAT"), uatPath, `${sliceId} UAT`));
1830
- const summaryPath = resolveSliceFile(base, mid, sliceId, "SUMMARY");
1831
- const summaryRel = relSliceFile(base, mid, sliceId, "SUMMARY");
1832
- if (summaryPath) {
1833
- const summaryInline = await inlineFileOptional(summaryPath, summaryRel, `${sliceId} Summary`);
1834
- if (summaryInline)
1835
- inlined.push(summaryInline);
1836
- }
1837
- const projectInline = await inlineProjectFromDb(base);
1838
- if (projectInline)
1839
- inlined.push(projectInline);
1840
- const inlinedContext = capPreamble(`## Inlined Context (preloaded do not re-read these files)\n\n${inlined.join("\n\n---\n\n")}`);
2013
+ // #4782 phase 3: run-uat migrated to compose its inlined context via
2014
+ // the manifest. Behavior-equivalent resolver dispatches to the same
2015
+ // inline* helpers as the pre-migration builder.
2016
+ const resolveArtifact = async (key) => {
2017
+ switch (key) {
2018
+ case "slice-uat": {
2019
+ // Use the in-memory snapshot the caller already loaded (#4925 review).
2020
+ // Re-reading from disk via inlineFile(p, uatPath, ...) would risk
2021
+ // drift between the inlined body and uatType (computed from
2022
+ // uatContent below) if the file changes mid-dispatch.
2023
+ const trimmed = uatContent.trim();
2024
+ if (!trimmed) {
2025
+ return `### ${sliceId} UAT\nSource: \`${uatPath}\`\n\n_(not found file does not exist yet)_`;
2026
+ }
2027
+ return `### ${sliceId} UAT\nSource: \`${uatPath}\`\n\n${trimmed}`;
2028
+ }
2029
+ case "slice-summary": {
2030
+ const p = resolveSliceFile(base, mid, sliceId, "SUMMARY");
2031
+ if (!p)
2032
+ return null;
2033
+ const r = relSliceFile(base, mid, sliceId, "SUMMARY");
2034
+ return await inlineFileOptional(p, r, `${sliceId} Summary`);
2035
+ }
2036
+ case "project":
2037
+ return await inlineProjectFromDb(base);
2038
+ default:
2039
+ return null;
2040
+ }
2041
+ };
2042
+ const composed = await composeInlinedContext("run-uat", resolveArtifact);
2043
+ const inlinedContext = capPreamble(`## Inlined Context (preloaded — do not re-read these files)\n\n${composed}`);
1841
2044
  const uatResultPath = join(base, relSliceFile(base, mid, sliceId, "ASSESSMENT"));
1842
2045
  const uatType = getUatType(uatContent);
1843
2046
  return loadPrompt("run-uat", {
@@ -1853,39 +2056,62 @@ export async function buildRunUatPrompt(mid, sliceId, uatPath, uatContent, base)
1853
2056
  milestoneId: mid,
1854
2057
  sliceId,
1855
2058
  extraContext: [inlinedContext],
2059
+ unitType: "run-uat",
1856
2060
  }),
1857
2061
  });
1858
2062
  }
1859
2063
  export async function buildReassessRoadmapPrompt(mid, midTitle, completedSliceId, base, level) {
1860
2064
  const inlineLevel = level ?? resolveInlineLevel();
1861
- const roadmapPath = resolveMilestoneFile(base, mid, "ROADMAP");
1862
- const roadmapRel = relMilestoneFile(base, mid, "ROADMAP");
1863
- const summaryPath = resolveSliceFile(base, mid, completedSliceId, "SUMMARY");
1864
- const summaryRel = relSliceFile(base, mid, completedSliceId, "SUMMARY");
1865
- const sliceContextPath = resolveSliceFile(base, mid, completedSliceId, "CONTEXT");
1866
- const sliceContextRel = relSliceFile(base, mid, completedSliceId, "CONTEXT");
1867
- const inlined = [];
1868
- inlined.push(await inlineFile(roadmapPath, roadmapRel, "Current Roadmap"));
1869
- const sliceCtxInline = await inlineFileOptional(sliceContextPath, sliceContextRel, "Slice Context (from discussion)");
1870
- if (sliceCtxInline)
1871
- inlined.push(sliceCtxInline);
1872
- inlined.push(await inlineFile(summaryPath, summaryRel, `${completedSliceId} Summary`));
1873
- if (inlineLevel !== "minimal") {
1874
- const projectInline = await inlineProjectFromDb(base);
1875
- if (projectInline)
1876
- inlined.push(projectInline);
1877
- const requirementsInline = await inlineRequirementsFromDb(base, mid, undefined, inlineLevel);
1878
- if (requirementsInline)
1879
- inlined.push(requirementsInline);
1880
- const decisionsInline = await inlineDecisionsFromDb(base, mid, undefined, inlineLevel);
1881
- if (decisionsInline)
1882
- inlined.push(decisionsInline);
1883
- }
1884
- // Scoped + budgeted — see issue #4719
2065
+ // #4782 phase 2 pilot: reassess-roadmap is the first unit type to
2066
+ // compose its inlined context through the manifest-driven composer.
2067
+ // The resolver below dispatches artifact keys to the existing inline*
2068
+ // helpers, preserving identical output so the migration is
2069
+ // observable-equivalent. Knowledge stays outside the composer (it's
2070
+ // budget-driven, not manifest-driven) until a later phase formalizes
2071
+ // knowledge/memory policies as composer inputs.
2072
+ const resolveArtifact = async (key) => {
2073
+ switch (key) {
2074
+ case "roadmap": {
2075
+ const p = resolveMilestoneFile(base, mid, "ROADMAP");
2076
+ const r = relMilestoneFile(base, mid, "ROADMAP");
2077
+ return await inlineFile(p, r, "Current Roadmap");
2078
+ }
2079
+ case "slice-context": {
2080
+ const p = resolveSliceFile(base, mid, completedSliceId, "CONTEXT");
2081
+ const r = relSliceFile(base, mid, completedSliceId, "CONTEXT");
2082
+ return await inlineFileOptional(p, r, "Slice Context (from discussion)");
2083
+ }
2084
+ case "slice-summary": {
2085
+ const p = resolveSliceFile(base, mid, completedSliceId, "SUMMARY");
2086
+ const r = relSliceFile(base, mid, completedSliceId, "SUMMARY");
2087
+ return await inlineFile(p, r, `${completedSliceId} Summary`);
2088
+ }
2089
+ case "project":
2090
+ if (inlineLevel === "minimal")
2091
+ return null;
2092
+ return await inlineProjectFromDb(base);
2093
+ case "requirements":
2094
+ if (inlineLevel === "minimal")
2095
+ return null;
2096
+ return await inlineRequirementsFromDb(base, mid, undefined, inlineLevel);
2097
+ case "decisions":
2098
+ if (inlineLevel === "minimal")
2099
+ return null;
2100
+ return await inlineDecisionsFromDb(base, mid, undefined, inlineLevel);
2101
+ default:
2102
+ return null;
2103
+ }
2104
+ };
2105
+ const composed = await composeInlinedContext("reassess-roadmap", resolveArtifact);
2106
+ const parts = [];
2107
+ if (composed)
2108
+ parts.push(composed);
2109
+ // Knowledge block stays outside the composer — budgeted, scoped via
2110
+ // keyword extraction (#4719). Future phase folds it in.
1885
2111
  const knowledgeInlineRA = await inlineKnowledgeBudgeted(base, extractKeywords(midTitle));
1886
2112
  if (knowledgeInlineRA)
1887
- inlined.push(knowledgeInlineRA);
1888
- const inlinedContext = capPreamble(`## Inlined Context (preloaded — do not re-read these files)\n\n${inlined.join("\n\n---\n\n")}`);
2113
+ parts.push(knowledgeInlineRA);
2114
+ const inlinedContext = capPreamble(`## Inlined Context (preloaded — do not re-read these files)\n\n${parts.join("\n\n---\n\n")}`);
1889
2115
  const assessmentPath = join(base, relSliceFile(base, mid, completedSliceId, "ASSESSMENT"));
1890
2116
  // Build deferred captures context for reassess prompt
1891
2117
  let deferredCaptures = "(none)";
@@ -1905,7 +2131,7 @@ export async function buildReassessRoadmapPrompt(mid, midTitle, completedSliceId
1905
2131
  milestoneId: mid,
1906
2132
  milestoneTitle: midTitle,
1907
2133
  completedSliceId,
1908
- roadmapPath: roadmapRel,
2134
+ roadmapPath: relMilestoneFile(base, mid, "ROADMAP"),
1909
2135
  assessmentPath,
1910
2136
  inlinedContext,
1911
2137
  deferredCaptures,
@@ -1915,6 +2141,7 @@ export async function buildReassessRoadmapPrompt(mid, midTitle, completedSliceId
1915
2141
  milestoneId: mid,
1916
2142
  milestoneTitle: midTitle,
1917
2143
  extraContext: [inlinedContext, deferredCaptures],
2144
+ unitType: "reassess-roadmap",
1918
2145
  }),
1919
2146
  });
1920
2147
  }