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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (368) hide show
  1. package/dist/headless.js +25 -4
  2. package/dist/resource-loader.d.ts +40 -0
  3. package/dist/resource-loader.js +32 -13
  4. package/dist/resources/extensions/browser-tools/capture.js +9 -0
  5. package/dist/resources/extensions/browser-tools/tests/browser-tools-integration.test.mjs +8 -59
  6. package/dist/resources/extensions/browser-tools/tests/browser-tools-unit.test.cjs +36 -24
  7. package/dist/resources/extensions/browser-tools/tests/capture-sharp-optional.test.cjs +69 -71
  8. package/dist/resources/extensions/browser-tools/tools/forms.js +5 -1
  9. package/dist/resources/extensions/browser-tools/tools/intent.js +5 -1
  10. package/dist/resources/extensions/gsd/auto/phases.js +5 -18
  11. package/dist/resources/extensions/gsd/auto/session.js +6 -0
  12. package/dist/resources/extensions/gsd/auto-dispatch.js +37 -8
  13. package/dist/resources/extensions/gsd/auto-post-unit.js +79 -0
  14. package/dist/resources/extensions/gsd/auto-prompts.js +372 -104
  15. package/dist/resources/extensions/gsd/auto-start.js +75 -24
  16. package/dist/resources/extensions/gsd/auto.js +34 -0
  17. package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +9 -1
  18. package/dist/resources/extensions/gsd/bootstrap/write-gate.js +7 -1
  19. package/dist/resources/extensions/gsd/component-loader.js +447 -0
  20. package/dist/resources/extensions/gsd/component-types.js +69 -0
  21. package/dist/resources/extensions/gsd/context-store.js +23 -7
  22. package/dist/resources/extensions/gsd/detection.js +49 -1
  23. package/dist/resources/extensions/gsd/docs/preferences-reference.md +1 -1
  24. package/dist/resources/extensions/gsd/forensics.js +106 -0
  25. package/dist/resources/extensions/gsd/gsd-db.js +1 -1
  26. package/dist/resources/extensions/gsd/guided-flow.js +2 -4
  27. package/dist/resources/extensions/gsd/memory-extractor.js +7 -1
  28. package/dist/resources/extensions/gsd/milestone-scope-classifier.js +299 -0
  29. package/dist/resources/extensions/gsd/model-cost-table.js +3 -0
  30. package/dist/resources/extensions/gsd/model-router.js +6 -0
  31. package/dist/resources/extensions/gsd/preferences-validation.js +23 -0
  32. package/dist/resources/extensions/gsd/prompt-cache-optimizer.js +4 -0
  33. package/dist/resources/extensions/gsd/prompts/complete-milestone.md +5 -1
  34. package/dist/resources/extensions/gsd/prompts/plan-slice.md +15 -2
  35. package/dist/resources/extensions/gsd/service-tier.js +5 -2
  36. package/dist/resources/extensions/gsd/skill-manifest.js +168 -0
  37. package/dist/resources/extensions/gsd/slice-cadence.js +238 -0
  38. package/dist/resources/extensions/gsd/tools/validate-milestone.js +7 -2
  39. package/dist/resources/extensions/gsd/unit-context-composer.js +147 -0
  40. package/dist/resources/extensions/gsd/unit-context-manifest.js +334 -0
  41. package/dist/resources/extensions/gsd/worktree-manager.js +51 -0
  42. package/dist/resources/extensions/gsd/worktree-resolver.js +86 -7
  43. package/dist/resources/extensions/gsd/worktree-telemetry.js +198 -0
  44. package/dist/resources/extensions/mcp-client/index.js +3 -1
  45. package/dist/resources/extensions/ollama/index.js +5 -1
  46. package/dist/resources/extensions/remote-questions/manager.js +11 -5
  47. package/dist/tsconfig.extensions.tsbuildinfo +1 -1
  48. package/dist/web/standalone/.next/BUILD_ID +1 -1
  49. package/dist/web/standalone/.next/app-path-routes-manifest.json +17 -17
  50. package/dist/web/standalone/.next/build-manifest.json +2 -2
  51. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  52. package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
  53. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  54. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  55. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  56. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  57. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  58. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  59. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  60. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  61. package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
  62. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
  63. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  64. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
  65. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  66. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  67. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  68. package/dist/web/standalone/.next/server/app/index.html +1 -1
  69. package/dist/web/standalone/.next/server/app/index.rsc +1 -1
  70. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
  71. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +1 -1
  72. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  73. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
  74. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  75. package/dist/web/standalone/.next/server/app-paths-manifest.json +17 -17
  76. package/dist/web/standalone/.next/server/chunks/6897.js +1 -1
  77. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  78. package/dist/web/standalone/.next/server/middleware-manifest.json +5 -5
  79. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  80. package/dist/web/standalone/.next/server/pages/500.html +1 -1
  81. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  82. package/package.json +1 -3
  83. package/packages/mcp-server/src/mcp-server.test.ts +25 -3
  84. package/packages/mcp-server/src/readers/graph.test.ts +87 -15
  85. package/packages/mcp-server/src/workflow-tools.test.ts +80 -39
  86. package/packages/native/package.json +1 -1
  87. package/packages/native/src/__tests__/_test-coverage-guard.test.mjs +98 -0
  88. package/packages/native/src/__tests__/module-compat.test.mjs +59 -27
  89. package/packages/native/src/__tests__/ps.test.mjs +14 -8
  90. package/packages/native/src/__tests__/stream-process.test.mjs +23 -2
  91. package/packages/native/src/__tests__/truncate.test.mjs +17 -2
  92. package/packages/pi-agent-core/src/agent-loop.test.ts +5 -15
  93. package/packages/pi-agent-core/src/agent.test.ts +96 -102
  94. package/packages/pi-agent-core/tsconfig.tsbuildinfo +1 -1
  95. package/packages/pi-ai/dist/models/generated/index.d.ts +34 -0
  96. package/packages/pi-ai/dist/models/generated/index.d.ts.map +1 -1
  97. package/packages/pi-ai/dist/models/generated/openai-codex.d.ts +17 -0
  98. package/packages/pi-ai/dist/models/generated/openai-codex.d.ts.map +1 -1
  99. package/packages/pi-ai/dist/models/generated/openai-codex.js +17 -0
  100. package/packages/pi-ai/dist/models/generated/openai-codex.js.map +1 -1
  101. package/packages/pi-ai/dist/models/generated/openai.d.ts +17 -0
  102. package/packages/pi-ai/dist/models/generated/openai.d.ts.map +1 -1
  103. package/packages/pi-ai/dist/models/generated/openai.js +17 -0
  104. package/packages/pi-ai/dist/models/generated/openai.js.map +1 -1
  105. package/packages/pi-ai/dist/models.generated.test.js +43 -70
  106. package/packages/pi-ai/dist/models.generated.test.js.map +1 -1
  107. package/packages/pi-ai/dist/models.test.js +29 -11
  108. package/packages/pi-ai/dist/models.test.js.map +1 -1
  109. package/packages/pi-ai/scripts/generate-models.ts +44 -0
  110. package/packages/pi-ai/src/models/generated/openai-codex.ts +17 -0
  111. package/packages/pi-ai/src/models/generated/openai.ts +17 -0
  112. package/packages/pi-ai/src/models.generated.test.ts +46 -73
  113. package/packages/pi-ai/src/models.test.ts +39 -11
  114. package/packages/pi-ai/tsconfig.tsbuildinfo +1 -1
  115. package/packages/pi-coding-agent/dist/core/agent-session-abort-order.test.js +96 -32
  116. package/packages/pi-coding-agent/dist/core/agent-session-abort-order.test.js.map +1 -1
  117. package/packages/pi-coding-agent/dist/core/agent-session-model-switch.test.js +75 -12
  118. package/packages/pi-coding-agent/dist/core/agent-session-model-switch.test.js.map +1 -1
  119. package/packages/pi-coding-agent/dist/core/agent-session-tool-refresh.test.js +99 -31
  120. package/packages/pi-coding-agent/dist/core/agent-session-tool-refresh.test.js.map +1 -1
  121. package/packages/pi-coding-agent/dist/core/extensions/loader.d.ts +5 -0
  122. package/packages/pi-coding-agent/dist/core/extensions/loader.d.ts.map +1 -1
  123. package/packages/pi-coding-agent/dist/core/extensions/loader.js +61 -0
  124. package/packages/pi-coding-agent/dist/core/extensions/loader.js.map +1 -1
  125. package/packages/pi-coding-agent/dist/core/lsp/lsp-integration.test.js +30 -4
  126. package/packages/pi-coding-agent/dist/core/lsp/lsp-integration.test.js.map +1 -1
  127. package/packages/pi-coding-agent/dist/core/model-registry-auth-mode.test.js +17 -0
  128. package/packages/pi-coding-agent/dist/core/model-registry-auth-mode.test.js.map +1 -1
  129. package/packages/pi-coding-agent/dist/core/resource-loader-cache-reset.test.js +76 -18
  130. package/packages/pi-coding-agent/dist/core/resource-loader-cache-reset.test.js.map +1 -1
  131. package/packages/pi-coding-agent/dist/core/retry-handler.d.ts.map +1 -1
  132. package/packages/pi-coding-agent/dist/core/retry-handler.js +2 -6
  133. package/packages/pi-coding-agent/dist/core/retry-handler.js.map +1 -1
  134. package/packages/pi-coding-agent/dist/core/retry-handler.test.js +5 -1
  135. package/packages/pi-coding-agent/dist/core/retry-handler.test.js.map +1 -1
  136. package/packages/pi-coding-agent/dist/core/retryable-error-regex.d.ts +18 -0
  137. package/packages/pi-coding-agent/dist/core/retryable-error-regex.d.ts.map +1 -0
  138. package/packages/pi-coding-agent/dist/core/retryable-error-regex.js +18 -0
  139. package/packages/pi-coding-agent/dist/core/retryable-error-regex.js.map +1 -0
  140. package/packages/pi-coding-agent/dist/core/system-prompt.d.ts +20 -0
  141. package/packages/pi-coding-agent/dist/core/system-prompt.d.ts.map +1 -1
  142. package/packages/pi-coding-agent/dist/core/system-prompt.js +16 -2
  143. package/packages/pi-coding-agent/dist/core/system-prompt.js.map +1 -1
  144. package/packages/pi-coding-agent/dist/index.d.ts +1 -0
  145. package/packages/pi-coding-agent/dist/index.d.ts.map +1 -1
  146. package/packages/pi-coding-agent/dist/index.js +1 -0
  147. package/packages/pi-coding-agent/dist/index.js.map +1 -1
  148. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/tool-execution.test.js +36 -5
  149. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/tool-execution.test.js.map +1 -1
  150. package/packages/pi-coding-agent/dist/modes/interactive/components/dynamic-border.test.js +20 -13
  151. package/packages/pi-coding-agent/dist/modes/interactive/components/dynamic-border.test.js.map +1 -1
  152. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  153. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js +30 -12
  154. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js.map +1 -1
  155. package/packages/pi-coding-agent/dist/tests/system-prompt-skill-filter.test.d.ts +2 -0
  156. package/packages/pi-coding-agent/dist/tests/system-prompt-skill-filter.test.d.ts.map +1 -0
  157. package/packages/pi-coding-agent/dist/tests/system-prompt-skill-filter.test.js +130 -0
  158. package/packages/pi-coding-agent/dist/tests/system-prompt-skill-filter.test.js.map +1 -0
  159. package/packages/pi-coding-agent/src/core/agent-session-abort-order.test.ts +113 -37
  160. package/packages/pi-coding-agent/src/core/agent-session-model-switch.test.ts +89 -17
  161. package/packages/pi-coding-agent/src/core/agent-session-tool-refresh.test.ts +112 -43
  162. package/packages/pi-coding-agent/src/core/extensions/loader.ts +58 -0
  163. package/packages/pi-coding-agent/src/core/lsp/lsp-integration.test.ts +35 -4
  164. package/packages/pi-coding-agent/src/core/model-registry-auth-mode.test.ts +20 -0
  165. package/packages/pi-coding-agent/src/core/resource-loader-cache-reset.test.ts +93 -28
  166. package/packages/pi-coding-agent/src/core/retry-handler.test.ts +5 -1
  167. package/packages/pi-coding-agent/src/core/retry-handler.ts +2 -8
  168. package/packages/pi-coding-agent/src/core/retryable-error-regex.ts +18 -0
  169. package/packages/pi-coding-agent/src/core/system-prompt.ts +35 -1
  170. package/packages/pi-coding-agent/src/index.ts +1 -0
  171. package/packages/pi-coding-agent/src/modes/interactive/components/__tests__/tool-execution.test.ts +49 -3
  172. package/packages/pi-coding-agent/src/modes/interactive/components/dynamic-border.test.ts +26 -20
  173. package/packages/pi-coding-agent/src/modes/interactive/components/tool-execution.ts +48 -9
  174. package/packages/pi-coding-agent/src/tests/system-prompt-skill-filter.test.ts +157 -0
  175. package/packages/pi-coding-agent/tsconfig.tsbuildinfo +1 -1
  176. package/packages/pi-tui/dist/__tests__/autocomplete.test.js +18 -8
  177. package/packages/pi-tui/dist/__tests__/autocomplete.test.js.map +1 -1
  178. package/packages/pi-tui/dist/__tests__/overlay-layout.test.js +128 -17
  179. package/packages/pi-tui/dist/__tests__/overlay-layout.test.js.map +1 -1
  180. package/packages/pi-tui/dist/__tests__/stdin-buffer.test.js +36 -12
  181. package/packages/pi-tui/dist/__tests__/stdin-buffer.test.js.map +1 -1
  182. package/packages/pi-tui/dist/__tests__/tui.test.js +18 -30
  183. package/packages/pi-tui/dist/__tests__/tui.test.js.map +1 -1
  184. package/packages/pi-tui/dist/components/__tests__/input.test.js +10 -3
  185. package/packages/pi-tui/dist/components/__tests__/input.test.js.map +1 -1
  186. package/packages/pi-tui/dist/components/__tests__/loader.test.js +53 -9
  187. package/packages/pi-tui/dist/components/__tests__/loader.test.js.map +1 -1
  188. package/packages/pi-tui/dist/components/__tests__/markdown-maxlines.test.js +6 -2
  189. package/packages/pi-tui/dist/components/__tests__/markdown-maxlines.test.js.map +1 -1
  190. package/packages/pi-tui/dist/components/image.test.js +6 -5
  191. package/packages/pi-tui/dist/components/image.test.js.map +1 -1
  192. package/packages/pi-tui/src/__tests__/autocomplete.test.ts +24 -8
  193. package/packages/pi-tui/src/__tests__/overlay-layout.test.ts +140 -17
  194. package/packages/pi-tui/src/__tests__/stdin-buffer.test.ts +41 -12
  195. package/packages/pi-tui/src/__tests__/tui.test.ts +18 -37
  196. package/packages/pi-tui/src/components/__tests__/input.test.ts +19 -3
  197. package/packages/pi-tui/src/components/__tests__/loader.test.ts +112 -35
  198. package/packages/pi-tui/src/components/__tests__/markdown-maxlines.test.ts +9 -2
  199. package/packages/pi-tui/src/components/image.test.ts +10 -5
  200. package/packages/pi-tui/tsconfig.tsbuildinfo +1 -1
  201. package/packages/rpc-client/dist/rpc-client.test.js +101 -51
  202. package/packages/rpc-client/dist/rpc-client.test.js.map +1 -1
  203. package/packages/rpc-client/src/rpc-client.test.ts +109 -52
  204. package/packages/rpc-client/tsconfig.tsbuildinfo +1 -1
  205. package/scripts/install.js +15 -1
  206. package/src/resources/extensions/browser-tools/capture.ts +12 -0
  207. package/src/resources/extensions/browser-tools/tests/browser-tools-integration.test.mjs +8 -59
  208. package/src/resources/extensions/browser-tools/tests/browser-tools-unit.test.cjs +36 -24
  209. package/src/resources/extensions/browser-tools/tests/capture-sharp-optional.test.cjs +69 -71
  210. package/src/resources/extensions/browser-tools/tools/forms.ts +5 -1
  211. package/src/resources/extensions/browser-tools/tools/intent.ts +5 -1
  212. package/src/resources/extensions/claude-code-cli/tests/stream-adapter.test.ts +80 -72
  213. package/src/resources/extensions/github-sync/tests/cli.test.ts +76 -7
  214. package/src/resources/extensions/github-sync/tests/templates.test.ts +33 -1
  215. package/src/resources/extensions/gsd/auto/phases.ts +6 -17
  216. package/src/resources/extensions/gsd/auto/session.ts +7 -0
  217. package/src/resources/extensions/gsd/auto-dispatch.ts +40 -8
  218. package/src/resources/extensions/gsd/auto-post-unit.ts +81 -0
  219. package/src/resources/extensions/gsd/auto-prompts.ts +385 -93
  220. package/src/resources/extensions/gsd/auto-start.ts +97 -4
  221. package/src/resources/extensions/gsd/auto.ts +37 -0
  222. package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +9 -1
  223. package/src/resources/extensions/gsd/bootstrap/write-gate.ts +7 -1
  224. package/src/resources/extensions/gsd/component-loader.ts +598 -0
  225. package/src/resources/extensions/gsd/component-types.ts +362 -0
  226. package/src/resources/extensions/gsd/context-store.ts +25 -8
  227. package/src/resources/extensions/gsd/detection.ts +58 -1
  228. package/src/resources/extensions/gsd/docs/preferences-reference.md +1 -1
  229. package/src/resources/extensions/gsd/forensics.ts +118 -1
  230. package/src/resources/extensions/gsd/git-service.ts +16 -0
  231. package/src/resources/extensions/gsd/gsd-db.ts +1 -1
  232. package/src/resources/extensions/gsd/guided-flow.ts +2 -4
  233. package/src/resources/extensions/gsd/journal.ts +11 -1
  234. package/src/resources/extensions/gsd/memory-extractor.ts +11 -3
  235. package/src/resources/extensions/gsd/milestone-scope-classifier.ts +366 -0
  236. package/src/resources/extensions/gsd/model-cost-table.ts +3 -0
  237. package/src/resources/extensions/gsd/model-router.ts +6 -0
  238. package/src/resources/extensions/gsd/preferences-validation.ts +21 -0
  239. package/src/resources/extensions/gsd/prompt-cache-optimizer.ts +4 -0
  240. package/src/resources/extensions/gsd/prompts/complete-milestone.md +5 -1
  241. package/src/resources/extensions/gsd/prompts/plan-slice.md +15 -2
  242. package/src/resources/extensions/gsd/service-tier.ts +5 -2
  243. package/src/resources/extensions/gsd/skill-manifest.ts +175 -0
  244. package/src/resources/extensions/gsd/slice-cadence.ts +299 -0
  245. package/src/resources/extensions/gsd/tests/artifacts-table-preserved-on-cache-invalidate.test.ts +2 -1
  246. package/src/resources/extensions/gsd/tests/auto-loop.test.ts +25 -292
  247. package/src/resources/extensions/gsd/tests/auto-remediate-slice-status.test.ts +4 -1
  248. package/src/resources/extensions/gsd/tests/auto-retry-mcp-churn-fixes.test.ts +8 -194
  249. package/src/resources/extensions/gsd/tests/auto-start-clean-runtime-db-gated.test.ts +3 -2
  250. package/src/resources/extensions/gsd/tests/auto-start-cold-db-bootstrap.test.ts +2 -2
  251. package/src/resources/extensions/gsd/tests/auto-start-needs-discussion.test.ts +15 -58
  252. package/src/resources/extensions/gsd/tests/auto-start-worktree-db-path.test.ts +2 -2
  253. package/src/resources/extensions/gsd/tests/auto-thinking-restore.test.ts +3 -2
  254. package/src/resources/extensions/gsd/tests/auto-warning-noise-regression.test.ts +3 -2
  255. package/src/resources/extensions/gsd/tests/bootstrap-derive-state-db-open.test.ts +2 -1
  256. package/src/resources/extensions/gsd/tests/cache-staleness-regression.test.ts +17 -21
  257. package/src/resources/extensions/gsd/tests/canonical-milestone-root.test.ts +108 -0
  258. package/src/resources/extensions/gsd/tests/complete-milestone-excerpt.test.ts +263 -0
  259. package/src/resources/extensions/gsd/tests/complete-slice-composer.test.ts +192 -0
  260. package/src/resources/extensions/gsd/tests/complete-slice-verification-gate.test.ts +2 -1
  261. package/src/resources/extensions/gsd/tests/complete-task.test.ts +8 -4
  262. package/src/resources/extensions/gsd/tests/component-loader.test.ts +589 -0
  263. package/src/resources/extensions/gsd/tests/component-types.test.ts +127 -0
  264. package/src/resources/extensions/gsd/tests/context-store.test.ts +79 -0
  265. package/src/resources/extensions/gsd/tests/copy-planning-artifacts-samepath.test.ts +2 -1
  266. package/src/resources/extensions/gsd/tests/discuss-slice-structured-questions.test.ts +2 -1
  267. package/src/resources/extensions/gsd/tests/discuss-tool-scope-leak.test.ts +2 -1
  268. package/src/resources/extensions/gsd/tests/double-merge-guard.test.ts +4 -3
  269. package/src/resources/extensions/gsd/tests/empty-content-abort-loop.test.ts +4 -3
  270. package/src/resources/extensions/gsd/tests/extension-bootstrap-isolation.test.ts +139 -129
  271. package/src/resources/extensions/gsd/tests/finalize-timeout-guard.test.ts +8 -104
  272. package/src/resources/extensions/gsd/tests/hook-key-parsing.test.ts +4 -55
  273. package/src/resources/extensions/gsd/tests/integration/all-milestones-complete-merge.test.ts +7 -56
  274. package/src/resources/extensions/gsd/tests/integration/doctor-proactive.test.ts +18 -2
  275. package/src/resources/extensions/gsd/tests/integration/queue-completed-milestone-perf.test.ts +10 -4
  276. package/src/resources/extensions/gsd/tests/integration/state-machine-edge-cases.test.ts +1 -1
  277. package/src/resources/extensions/gsd/tests/interactive-routing-bypass.test.ts +9 -3
  278. package/src/resources/extensions/gsd/tests/interrupted-session-ui.test.ts +6 -9
  279. package/src/resources/extensions/gsd/tests/knowledge.test.ts +93 -1
  280. package/src/resources/extensions/gsd/tests/mcp-client-security.test.ts +8 -37
  281. package/src/resources/extensions/gsd/tests/memory-extractor.test.ts +5 -15
  282. package/src/resources/extensions/gsd/tests/merge-conflict-stops-loop.test.ts +227 -55
  283. package/src/resources/extensions/gsd/tests/milestone-scope-classifier.test.ts +187 -0
  284. package/src/resources/extensions/gsd/tests/model-cost-table.test.ts +9 -1
  285. package/src/resources/extensions/gsd/tests/model-router.test.ts +1 -1
  286. package/src/resources/extensions/gsd/tests/native-git-bridge-exec-fallback.test.ts +6 -48
  287. package/src/resources/extensions/gsd/tests/notification-widget.test.ts +6 -3
  288. package/src/resources/extensions/gsd/tests/orphaned-worktree-audit.test.ts +59 -2
  289. package/src/resources/extensions/gsd/tests/parallel-research-dispatch.test.ts +273 -130
  290. package/src/resources/extensions/gsd/tests/pipeline-variant-dispatch.test.ts +301 -0
  291. package/src/resources/extensions/gsd/tests/preferences-worktree-sync.test.ts +2 -1
  292. package/src/resources/extensions/gsd/tests/prompt-cache-optimizer.test.ts +12 -0
  293. package/src/resources/extensions/gsd/tests/prompt-step-ordering.test.ts +15 -4
  294. package/src/resources/extensions/gsd/tests/provider-errors.test.ts +22 -16
  295. package/src/resources/extensions/gsd/tests/queue-draft-detection.test.ts +3 -2
  296. package/src/resources/extensions/gsd/tests/queued-discuss-fast-path.test.ts +4 -5
  297. package/src/resources/extensions/gsd/tests/reassess-default-optin.test.ts +132 -0
  298. package/src/resources/extensions/gsd/tests/recovery-attempts-reset.test.ts +8 -40
  299. package/src/resources/extensions/gsd/tests/regex-hardening.test.ts +136 -256
  300. package/src/resources/extensions/gsd/tests/research-milestone-composer.test.ts +114 -0
  301. package/src/resources/extensions/gsd/tests/restore-tools-after-discuss.test.ts +6 -3
  302. package/src/resources/extensions/gsd/tests/run-uat-composer.test.ts +148 -0
  303. package/src/resources/extensions/gsd/tests/service-tier.test.ts +4 -0
  304. package/src/resources/extensions/gsd/tests/sidecar-queue.test.ts +3 -2
  305. package/src/resources/extensions/gsd/tests/silent-catch-diagnostics.test.ts +55 -95
  306. package/src/resources/extensions/gsd/tests/skill-activation.test.ts +120 -1
  307. package/src/resources/extensions/gsd/tests/skill-manifest.test.ts +112 -0
  308. package/src/resources/extensions/gsd/tests/slice-cadence.test.ts +242 -0
  309. package/src/resources/extensions/gsd/tests/slice-context-injection.test.ts +3 -2
  310. package/src/resources/extensions/gsd/tests/smart-entry-draft.test.ts +2 -1
  311. package/src/resources/extensions/gsd/tests/stop-auto-race-null-unit.test.ts +3 -3
  312. package/src/resources/extensions/gsd/tests/structured-data-formatter.test.ts +11 -92
  313. package/src/resources/extensions/gsd/tests/subagent-model-dispatch.test.ts +7 -6
  314. package/src/resources/extensions/gsd/tests/survivor-branch-complete.test.ts +102 -101
  315. package/src/resources/extensions/gsd/tests/sync-worktree-skip-current.test.ts +4 -3
  316. package/src/resources/extensions/gsd/tests/test-helpers.test.ts +98 -0
  317. package/src/resources/extensions/gsd/tests/test-helpers.ts +153 -0
  318. package/src/resources/extensions/gsd/tests/token-profile.test.ts +8 -1
  319. package/src/resources/extensions/gsd/tests/unit-context-composer.test.ts +355 -0
  320. package/src/resources/extensions/gsd/tests/unit-context-manifest.test.ts +203 -0
  321. package/src/resources/extensions/gsd/tests/uok-gitops-wiring.test.ts +49 -26
  322. package/src/resources/extensions/gsd/tests/validate-milestone.test.ts +1 -0
  323. package/src/resources/extensions/gsd/tests/verify-artifact-tightened.test.ts +144 -80
  324. package/src/resources/extensions/gsd/tests/visualizer-critical-path.test.ts +20 -54
  325. package/src/resources/extensions/gsd/tests/visualizer-overlay.test.ts +342 -277
  326. package/src/resources/extensions/gsd/tests/worker-model-override.test.ts +37 -29
  327. package/src/resources/extensions/gsd/tests/worktree-db.test.ts +226 -266
  328. package/src/resources/extensions/gsd/tests/worktree-health-monorepo.test.ts +103 -67
  329. package/src/resources/extensions/gsd/tests/worktree-nested-git-safety.test.ts +92 -90
  330. package/src/resources/extensions/gsd/tests/worktree-submodule-safety.test.ts +238 -59
  331. package/src/resources/extensions/gsd/tests/worktree-sync-overwrite-loop.test.ts +113 -161
  332. package/src/resources/extensions/gsd/tests/worktree-telemetry.test.ts +210 -0
  333. package/src/resources/extensions/gsd/tests/zombie-gsd-state.test.ts +80 -96
  334. package/src/resources/extensions/gsd/tools/validate-milestone.ts +8 -2
  335. package/src/resources/extensions/gsd/unit-context-composer.ts +218 -0
  336. package/src/resources/extensions/gsd/unit-context-manifest.ts +492 -0
  337. package/src/resources/extensions/gsd/worktree-manager.ts +53 -0
  338. package/src/resources/extensions/gsd/worktree-resolver.ts +96 -9
  339. package/src/resources/extensions/gsd/worktree-telemetry.ts +322 -0
  340. package/src/resources/extensions/mcp-client/index.ts +3 -1
  341. package/src/resources/extensions/mcp-client/tests/server-name-spaces.test.ts +70 -36
  342. package/src/resources/extensions/ollama/index.ts +5 -1
  343. package/src/resources/extensions/ollama/ollama-auth-mode.test.ts +123 -15
  344. package/src/resources/extensions/ollama/ollama-status-indicator.test.ts +206 -19
  345. package/src/resources/extensions/remote-questions/manager.ts +36 -4
  346. package/src/resources/extensions/remote-questions/tests/command-polling.test.ts +200 -190
  347. package/src/resources/extensions/shared/tests/interview-preview.test.ts +11 -3
  348. package/src/resources/extensions/voice/tests/linux-ready.test.ts +129 -113
  349. package/packages/pi-ai/dist/utils/oauth/oauth-providers.test.d.ts +0 -2
  350. package/packages/pi-ai/dist/utils/oauth/oauth-providers.test.d.ts.map +0 -1
  351. package/packages/pi-ai/dist/utils/oauth/oauth-providers.test.js +0 -289
  352. package/packages/pi-ai/dist/utils/oauth/oauth-providers.test.js.map +0 -1
  353. package/packages/pi-ai/src/utils/oauth/oauth-providers.test.ts +0 -363
  354. package/src/resources/extensions/gsd/tests/auto-start-model-capture.test.ts +0 -143
  355. package/src/resources/extensions/gsd/tests/complete-milestone-false-merge.test.ts +0 -157
  356. package/src/resources/extensions/gsd/tests/dashboard-model-label-ordering.test.ts +0 -107
  357. package/src/resources/extensions/gsd/tests/find-missing-summaries-closed.test.ts +0 -48
  358. package/src/resources/extensions/gsd/tests/forensics-context-persist.test.ts +0 -159
  359. package/src/resources/extensions/gsd/tests/forensics-db-completion.test.ts +0 -96
  360. package/src/resources/extensions/gsd/tests/forensics-dedup.test.ts +0 -79
  361. package/src/resources/extensions/gsd/tests/forensics-hook-key-parse.test.ts +0 -74
  362. package/src/resources/extensions/gsd/tests/forensics-journal.test.ts +0 -162
  363. package/src/resources/extensions/gsd/tests/gitignore-bg-shell.test.ts +0 -38
  364. package/src/resources/extensions/gsd/tests/gsd-no-project-error.test.ts +0 -73
  365. package/src/resources/extensions/gsd/tests/idle-watchdog-stall-override.test.ts +0 -125
  366. package/src/resources/extensions/gsd/tests/import-done-milestones.test.ts +0 -42
  367. /package/dist/web/standalone/.next/static/{vidAVJkURvTJ0_V2-64ro → gYYky7yfxW8txb9vU2TrJ}/_buildManifest.js +0 -0
  368. /package/dist/web/standalone/.next/static/{vidAVJkURvTJ0_V2-64ro → gYYky7yfxW8txb9vU2TrJ}/_ssgManifest.js +0 -0
@@ -0,0 +1,299 @@
1
+ // GSD-2 — Milestone scope classifier (#4781 / ADR-003 companion).
2
+ //
3
+ // Pure heuristics over milestone planning fields. Produces a PipelineVariant
4
+ // that downstream dispatch logic can use to shape the auto-mode sequence.
5
+ // No LLM calls, no file I/O, sub-millisecond.
6
+ //
7
+ // Distinct from `complexity-classifier.ts`, which decides *model tier*
8
+ // (light/standard/heavy) for an individual unit. This module decides
9
+ // *pipeline topology* for an entire milestone at plan-milestone time.
10
+ //
11
+ // This file ships the classifier in isolation. Dispatch-side wiring
12
+ // lands in follow-up PRs so the classification contract can be reviewed
13
+ // and tested before any behavior change reaches users.
14
+ // ─── Keyword sets ─────────────────────────────────────────────────────────
15
+ /**
16
+ * Override keywords that force `standard` (at minimum) regardless of
17
+ * apparent triviality. Presence of any of these signals work that is
18
+ * either security-sensitive, irreversible, or requires runtime verification
19
+ * a "trivial" pipeline would skip.
20
+ *
21
+ * Matched as case-insensitive word-boundary substrings. Conservative — err
22
+ * on the side of including a keyword; over-classifying to `standard` costs
23
+ * units, under-classifying could ship broken auth/security/migration work.
24
+ */
25
+ const OVERRIDE_KEYWORDS = [
26
+ // Security-sensitive
27
+ "security", "auth", "authn", "authz", "authentication", "authorization",
28
+ "credential", "secret", "password", "token", "oauth", "encrypt", "decrypt",
29
+ "vulnerability", "exploit", "permission", "rbac", "acl",
30
+ // Data-migration / irreversible
31
+ "migration", "migrate", "schema change", "data migration",
32
+ "backfill", "drop column", "drop table",
33
+ // Compliance / regulatory
34
+ "compliance", "gdpr", "hipaa", "soc2", "pci",
35
+ // Infra / deploy — runtime verification needed
36
+ "deploy", "rollout", "canary", "production database",
37
+ ];
38
+ /**
39
+ * Keywords that contribute to `complex` classification on their own.
40
+ * Different from OVERRIDE_KEYWORDS in that a single match bumps to
41
+ * complex, not just to standard.
42
+ */
43
+ const COMPLEX_KEYWORDS = [
44
+ "multi-service", "distributed", "consensus", "saga", "eventual consistency",
45
+ "breaking change", "api contract change", "schema redesign",
46
+ "architect", "architecture", "refactor core",
47
+ ];
48
+ /**
49
+ * Trivial-signal keywords: presence strongly suggests a simple, contained
50
+ * deliverable. Only effective when combined with low file count / no tests
51
+ * / no override keywords.
52
+ */
53
+ const TRIVIAL_KEYWORDS = [
54
+ "single file", "one file", "static html", "static page",
55
+ "one-page", "landing page", "readme", "docs only", "typo", "rename",
56
+ "spelling", "comment", "changelog",
57
+ // Browser-only / no-build deliverable shapes (b23 forensic case).
58
+ "pure html", "browser-based", "no build step", "no build tooling",
59
+ "localstorage", "client-only", "no backend", "no server", "no backend.",
60
+ ];
61
+ // ─── Heuristics ───────────────────────────────────────────────────────────
62
+ /**
63
+ * Estimate how many distinct files the milestone will touch, based on
64
+ * explicit mentions in the input text. Returns `null` when no hint is
65
+ * discoverable — callers should treat that as "unknown, no signal."
66
+ */
67
+ function extractFileCountHint(text) {
68
+ // Explicit phrasing: "a single file", "two files", "3 files"
69
+ const singleFileMatch = /\b(a|one|single)\s+(file|page)\b/i.test(text);
70
+ if (singleFileMatch)
71
+ return 1;
72
+ const digitMatch = text.match(/\b(\d+)\s+files?\b/i);
73
+ if (digitMatch) {
74
+ const n = parseInt(digitMatch[1], 10);
75
+ if (!Number.isNaN(n))
76
+ return n;
77
+ }
78
+ const wordMatch = text.match(/\b(two|three|four|five|six|seven|eight|nine|ten)\s+files?\b/i);
79
+ if (wordMatch) {
80
+ const wordMap = {
81
+ two: 2, three: 3, four: 4, five: 5,
82
+ six: 6, seven: 7, eight: 8, nine: 9, ten: 10,
83
+ };
84
+ return wordMap[wordMatch[1].toLowerCase()] ?? null;
85
+ }
86
+ return null;
87
+ }
88
+ function escapeRegExp(value) {
89
+ return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
90
+ }
91
+ function containsAnyKeyword(haystack, keywords) {
92
+ const lower = haystack.toLowerCase();
93
+ const hits = [];
94
+ for (const kw of keywords) {
95
+ // Word-boundary match to prevent substring collisions (e.g. "auth"
96
+ // must not match "author", "api" must not match "capital"). Phrases
97
+ // containing non-word characters (hyphens, slashes) still work because
98
+ // `\b` sits at the word-char / non-word-char transition, so
99
+ // `\bbrowser-based\b` matches "browser-based" bounded by whitespace
100
+ // or punctuation on either side.
101
+ const pattern = new RegExp(String.raw `\b${escapeRegExp(kw)}\b`, "i");
102
+ if (pattern.test(lower))
103
+ hits.push(kw);
104
+ }
105
+ return hits;
106
+ }
107
+ /**
108
+ * True when `term` appears in the text without an immediately preceding
109
+ * negator (no / without / not / zero / skip) in the same clause. Used to
110
+ * keep phrases like "no backend" or "no tests" from flipping a trivial-
111
+ * class milestone to standard. Best-effort; imperfect English parsing,
112
+ * biased toward false negatives (if unsure, treats term as present —
113
+ * which routes to standard, the safe pipeline).
114
+ */
115
+ function mentionsWithoutNegation(text, term) {
116
+ const lower = text.toLowerCase();
117
+ const termPattern = new RegExp(String.raw `\b${term}\b`, "gi");
118
+ const matches = Array.from(lower.matchAll(termPattern));
119
+ for (const m of matches) {
120
+ const start = m.index ?? 0;
121
+ const windowStart = Math.max(0, start - 30);
122
+ const window = lower.slice(windowStart, start);
123
+ // Negator anywhere in the 30-char lookback window counts as negation —
124
+ // covers "no backend", "without a server", "not using api", "zero
125
+ // dependencies on an api". If a sentence break intervenes between the
126
+ // negator and the term, treat as a different clause (positive mention).
127
+ const hasNegator = /(^|[^a-z0-9])(no|without|not|zero|skip(s|ping)?|drops?)\b/i.test(window);
128
+ const hasSentenceBreak = /[.;!?]/.test(window);
129
+ if (hasNegator && !hasSentenceBreak)
130
+ continue;
131
+ return true;
132
+ }
133
+ return false;
134
+ }
135
+ function mentionsTests(haystack) {
136
+ return mentionsWithoutNegation(haystack, "test")
137
+ || mentionsWithoutNegation(haystack, "tests")
138
+ || mentionsWithoutNegation(haystack, "testing")
139
+ || mentionsWithoutNegation(haystack, "spec")
140
+ || mentionsWithoutNegation(haystack, "unit test")
141
+ || mentionsWithoutNegation(haystack, "integration test");
142
+ }
143
+ function mentionsBackend(haystack) {
144
+ return mentionsWithoutNegation(haystack, "api")
145
+ || mentionsWithoutNegation(haystack, "backend")
146
+ || mentionsWithoutNegation(haystack, "server")
147
+ || mentionsWithoutNegation(haystack, "database")
148
+ || mentionsWithoutNegation(haystack, "endpoint");
149
+ }
150
+ // ─── DB adapter ───────────────────────────────────────────────────────────
151
+ /**
152
+ * Shape adapter: convert a milestone DB row into the classifier input
153
+ * object. Keeps `milestone-scope-classifier.ts` free of DB types at the
154
+ * module boundary — callers can either use this helper or hand-build the
155
+ * input themselves (e.g. from plan-milestone tool params before insert).
156
+ */
157
+ export function milestoneRowToScopeInput(row) {
158
+ return {
159
+ title: row.title,
160
+ vision: row.vision,
161
+ successCriteria: row.success_criteria,
162
+ keyRisks: row.key_risks,
163
+ definitionOfDone: row.definition_of_done,
164
+ requirementCoverage: row.requirement_coverage,
165
+ verificationContract: row.verification_contract,
166
+ verificationIntegration: row.verification_integration,
167
+ verificationOperational: row.verification_operational,
168
+ verificationUat: row.verification_uat,
169
+ };
170
+ }
171
+ /**
172
+ * Compute the pipeline variant for a milestone by reading its planning
173
+ * fields from the DB and running the classifier. Returns `null` when
174
+ * classification is unavailable (DB closed, milestone missing, unexpected
175
+ * error) — callers MUST treat null as "run the full pipeline" so a
176
+ * classification failure never silently downshifts dispatch.
177
+ */
178
+ export async function getMilestonePipelineVariant(mid) {
179
+ try {
180
+ const { isDbAvailable, getMilestone } = await import("./gsd-db.js");
181
+ if (!isDbAvailable())
182
+ return null;
183
+ const row = getMilestone(mid);
184
+ if (!row)
185
+ return null;
186
+ return classifyMilestoneScope(milestoneRowToScopeInput(row)).variant;
187
+ }
188
+ catch {
189
+ return null;
190
+ }
191
+ }
192
+ // ─── Public API ───────────────────────────────────────────────────────────
193
+ /**
194
+ * Classify a milestone's pipeline variant based on its planning inputs.
195
+ *
196
+ * Precedence (matches implementation order — complex-first so that
197
+ * security-sensitive architecture refactors correctly route to complex
198
+ * rather than standard; the override hit is still recorded in
199
+ * `signals.triggeredOverride` for telemetry):
200
+ * 1. Complex-signal keyword OR ≥ 8 file hint OR architecture/refactor-core
201
+ * language → `complex`.
202
+ * 2. Override keyword → `standard` (at minimum). Prevents trivial
203
+ * misclassification of security / auth / migration work.
204
+ * 3. Trivial-signal keyword AND ≤ 2 file hint AND no tests mentioned AND
205
+ * no backend mentioned → `trivial`.
206
+ * 4. Otherwise → `standard`.
207
+ *
208
+ * Ambiguity → `standard` (today's default). Safe to run the full pipeline.
209
+ */
210
+ export function classifyMilestoneScope(input) {
211
+ const haystack = [
212
+ input.title ?? "",
213
+ input.vision ?? "",
214
+ (input.successCriteria ?? []).join("\n"),
215
+ (input.keyRisks ?? []).map(r => `${r.risk ?? ""} ${r.whyItMatters ?? ""}`).join("\n"),
216
+ (input.definitionOfDone ?? []).join("\n"),
217
+ input.requirementCoverage ?? "",
218
+ input.verificationContract ?? "",
219
+ input.verificationIntegration ?? "",
220
+ input.verificationOperational ?? "",
221
+ input.verificationUat ?? "",
222
+ ].join("\n");
223
+ const overrideHits = containsAnyKeyword(haystack, OVERRIDE_KEYWORDS);
224
+ const complexHits = containsAnyKeyword(haystack, COMPLEX_KEYWORDS);
225
+ const trivialHits = containsAnyKeyword(haystack, TRIVIAL_KEYWORDS);
226
+ const fileCountHint = extractFileCountHint(haystack);
227
+ const hasTests = mentionsTests(haystack);
228
+ const hasBackend = mentionsBackend(haystack);
229
+ const reasons = [];
230
+ // Rule 2: complex-class signals. Evaluated before override because a
231
+ // complex + override input should land in complex, not standard.
232
+ if (complexHits.length > 0) {
233
+ reasons.push(`complex keywords: ${complexHits.slice(0, 3).join(", ")}`);
234
+ }
235
+ if (fileCountHint !== null && fileCountHint >= 8) {
236
+ reasons.push(`file count hint: ${fileCountHint}`);
237
+ }
238
+ const isComplex = complexHits.length > 0 || (fileCountHint !== null && fileCountHint >= 8);
239
+ if (isComplex) {
240
+ return {
241
+ variant: "complex",
242
+ reasons,
243
+ signals: {
244
+ triggeredOverride: overrideHits.length > 0,
245
+ complexCount: complexHits.length,
246
+ trivialCount: trivialHits.length,
247
+ fileCountHint,
248
+ },
249
+ };
250
+ }
251
+ // Rule 1: override keywords force standard.
252
+ if (overrideHits.length > 0) {
253
+ return {
254
+ variant: "standard",
255
+ reasons: [`override keywords: ${overrideHits.slice(0, 3).join(", ")}`],
256
+ signals: {
257
+ triggeredOverride: true,
258
+ complexCount: complexHits.length,
259
+ trivialCount: trivialHits.length,
260
+ fileCountHint,
261
+ },
262
+ };
263
+ }
264
+ // Rule 3: trivial signals — require ALL of: trivial-keyword, low file
265
+ // hint (or nothing suggesting high count), no test mention, no backend
266
+ // mention.
267
+ const fileCountOk = fileCountHint === null || fileCountHint <= 2;
268
+ const trivial = trivialHits.length > 0 &&
269
+ fileCountOk &&
270
+ !hasTests &&
271
+ !hasBackend;
272
+ if (trivial) {
273
+ reasons.push(`trivial keywords: ${trivialHits.slice(0, 3).join(", ")}`);
274
+ if (fileCountHint !== null)
275
+ reasons.push(`file count hint: ${fileCountHint}`);
276
+ reasons.push("no tests mentioned", "no backend mentioned");
277
+ return {
278
+ variant: "trivial",
279
+ reasons,
280
+ signals: {
281
+ triggeredOverride: false,
282
+ complexCount: complexHits.length,
283
+ trivialCount: trivialHits.length,
284
+ fileCountHint,
285
+ },
286
+ };
287
+ }
288
+ // Rule 4: fallback.
289
+ return {
290
+ variant: "standard",
291
+ reasons: reasons.length > 0 ? reasons : ["no strong signals — default"],
292
+ signals: {
293
+ triggeredOverride: overrideHits.length > 0,
294
+ complexCount: complexHits.length,
295
+ trivialCount: trivialHits.length,
296
+ fileCountHint,
297
+ },
298
+ };
299
+ }
@@ -43,6 +43,9 @@ export const BUNDLED_COST_TABLE = [
43
43
  { id: "gpt-5.3-codex-spark", inputPer1k: 0.0003, outputPer1k: 0.0012, updatedAt: "2026-03-29" },
44
44
  { id: "gpt-5.4", inputPer1k: 0.005, outputPer1k: 0.02, updatedAt: "2026-03-29" },
45
45
  { id: "gpt-5.4-mini", inputPer1k: 0.00075, outputPer1k: 0.0045, updatedAt: "2026-04-18" },
46
+ // GPT-5.5 API list price, also used for live Codex OAuth routing.
47
+ // Source: https://openai.com/api/pricing/
48
+ { id: "gpt-5.5", inputPer1k: 0.005, outputPer1k: 0.03, updatedAt: "2026-04-23" },
46
49
  // Google
47
50
  { id: "gemini-2.0-flash", inputPer1k: 0.0001, outputPer1k: 0.0004, updatedAt: "2025-03-15" },
48
51
  { id: "gemini-flash-2.0", inputPer1k: 0.0001, outputPer1k: 0.0004, updatedAt: "2025-03-15" },
@@ -43,6 +43,7 @@ export const MODEL_CAPABILITY_TIER = {
43
43
  "gpt-5.2-codex": "heavy",
44
44
  "gpt-5.3-codex": "heavy",
45
45
  "gpt-5.4": "heavy",
46
+ "gpt-5.5": "heavy",
46
47
  "o1": "heavy",
47
48
  "o3": "heavy",
48
49
  "o4-mini": "heavy",
@@ -76,6 +77,7 @@ const MODEL_COST_PER_1K_INPUT = {
76
77
  "gpt-5.3-codex": 0.005,
77
78
  "gpt-5.3-codex-spark": 0.0003,
78
79
  "gpt-5.4": 0.005,
80
+ "gpt-5.5": 0.005,
79
81
  "o4-mini": 0.005,
80
82
  "o4-mini-deep-research": 0.005,
81
83
  "gemini-2.0-flash": 0.0001,
@@ -116,6 +118,10 @@ export const MODEL_CAPABILITY_PROFILES = {
116
118
  "gpt-5.3-codex": { coding: 94, debugging: 91, research: 74, reasoning: 89, speed: 50, longContext: 80, instruction: 89 },
117
119
  "gpt-5.3-codex-spark": { coding: 68, debugging: 58, research: 42, reasoning: 52, speed: 90, longContext: 50, instruction: 74 },
118
120
  "gpt-5.4": { coding: 95, debugging: 92, research: 88, reasoning: 94, speed: 42, longContext: 88, instruction: 92 },
121
+ // GPT-5.5 scores are relative to the existing gpt-5.4 profile and backed by
122
+ // OpenAI's 2026-04-23 published eval deltas across coding, tool use, and long context.
123
+ // Source: https://openai.com/index/introducing-gpt-5-5/
124
+ "gpt-5.5": { coding: 96, debugging: 93, research: 89, reasoning: 95, speed: 42, longContext: 90, instruction: 93 },
119
125
  // ── OpenAI o-series (reasoning-first) ──────────────────────────────────────
120
126
  "o1": { coding: 78, debugging: 82, research: 78, reasoning: 90, speed: 20, longContext: 65, instruction: 82 },
121
127
  "o3": { coding: 80, debugging: 85, research: 80, reasoning: 92, speed: 25, longContext: 70, instruction: 85 },
@@ -1031,6 +1031,29 @@ export function validatePreferences(preferences) {
1031
1031
  if (g.merge_to_main !== undefined) {
1032
1032
  warnings.push("git.merge_to_main is deprecated — milestone-level merge is now always used. Remove this setting.");
1033
1033
  }
1034
+ // #4765 — collapse cadence + milestone resquash
1035
+ if (g.collapse_cadence !== undefined) {
1036
+ const validCadence = new Set(["milestone", "slice"]);
1037
+ if (typeof g.collapse_cadence === "string" && validCadence.has(g.collapse_cadence)) {
1038
+ git.collapse_cadence = g.collapse_cadence;
1039
+ }
1040
+ else {
1041
+ errors.push("git.collapse_cadence must be one of: milestone, slice");
1042
+ }
1043
+ }
1044
+ if (g.milestone_resquash !== undefined) {
1045
+ if (typeof g.milestone_resquash === "boolean") {
1046
+ git.milestone_resquash = g.milestone_resquash;
1047
+ const cadence = git.collapse_cadence
1048
+ ?? (typeof g.collapse_cadence === "string" ? g.collapse_cadence : undefined);
1049
+ if (cadence !== "slice") {
1050
+ warnings.push('git.milestone_resquash is ignored unless git.collapse_cadence is "slice"');
1051
+ }
1052
+ }
1053
+ else {
1054
+ errors.push("git.milestone_resquash must be a boolean");
1055
+ }
1056
+ }
1034
1057
  if (Object.keys(git).length > 0) {
1035
1058
  validated.git = git;
1036
1059
  }
@@ -24,6 +24,10 @@ const SEMI_STATIC_LABELS = new Set([
24
24
  "prior-summaries",
25
25
  "project-context",
26
26
  "overrides",
27
+ // KNOWLEDGE is milestone-scoped (stable within a session), so it belongs
28
+ // in the cacheable prefix. See issue #4719.
29
+ "knowledge",
30
+ "project-knowledge",
27
31
  ]);
28
32
  /** Labels that change per-task */
29
33
  const DYNAMIC_LABELS = new Set([
@@ -10,7 +10,11 @@ Your working directory is `{{workingDirectory}}`. All file reads, writes, and sh
10
10
 
11
11
  All slices are done. You are closing out the milestone — verifying that the assembled work actually delivers the promised outcome, writing the milestone summary, and updating project state. The milestone summary is the final record. After you finish, the system merges the worktree back to the integration branch. If there are queued milestones, the next one starts its own research → plan → execute cycle from a clean slate — the milestone summary is how it learns what was already built.
12
12
 
13
- All relevant context has been preloaded below — the roadmap, all slice summaries, requirements, decisions, and project context are inlined. Start working immediately without re-reading these files.
13
+ Preloaded context below — the roadmap, compact slice-summary excerpts, requirements, decisions, and project context. **Slice summaries are excerpts, not full files.** They include frontmatter fields, section heads (deviations, known limitations, follow-ups), and short narrative only. When drafting LEARNINGS, the Decision Re-evaluation table, or cross-slice narrative, Read the full slice SUMMARY.md files listed under "On-demand Slice Summaries" — do that selectively as needed, not preemptively.
14
+
15
+ Start with what the excerpts give you. Read full files when the section heads signal richer context you need.
16
+
17
+ **On-demand Read ordering:** Complete all slice SUMMARY Reads you need for cross-slice synthesis, the Decision Re-evaluation table, and LEARNINGS **before** calling `gsd_complete_milestone` (step 10). Once that tool runs, the milestone is marked complete in the DB — running out of tool budget between step 10 and the LEARNINGS write (step 12) leaves the milestone committed without its LEARNINGS artifact.
14
18
 
15
19
  {{inlinedContext}}
16
20
 
@@ -20,9 +20,22 @@ Pay particular attention to **Forward Intelligence** sections — they contain h
20
20
 
21
21
  You have full tool access. Before decomposing, explore the relevant code to ground your plan in reality.
22
22
 
23
- ### Verify Roadmap Assumptions
23
+ ### Verify Roadmap Assumptions (JIT Reassessment — ADR-003 §4)
24
24
 
25
- Check prior slice summaries (inlined above as dependency summaries, if present). If prior slices discovered constraints, changed approaches, or flagged fragility, adjust your plan accordingly. The roadmap description may be stale — verify it against the current codebase state.
25
+ Before planning this slice, verify that the roadmap's assumptions still hold given prior slice summaries. Check inlined dependency summaries (below) for discovered constraints, changed approaches, or flagged fragility.
26
+
27
+ **If the remaining roadmap needs adjustment, modify it before proceeding:**
28
+
29
+ - If a downstream slice's title/demo/dependencies are now wrong, call `gsd_reassess_roadmap` with the corrected `sliceChanges.modified` entry.
30
+ - If new work surfaced that deserves its own slice, add it via `sliceChanges.added`.
31
+ - If a downstream slice is now redundant or out of scope, remove it via `sliceChanges.removed`.
32
+ - **Bias strongly toward "roadmap is fine."** Most slice completions produce no structural change. Only adjust when there is concrete evidence a downstream slice is wrong — not speculative concern. Over-reassessment is costlier than a later mid-slice replan.
33
+
34
+ Completed slices are immutable: never modify or remove a slice whose status is complete.
35
+
36
+ Then proceed with planning this slice against the (possibly updated) roadmap.
37
+
38
+ The roadmap description may be stale — verify it against the current codebase state.
26
39
 
27
40
  ### Explore Slice Scope
28
41
 
@@ -2,8 +2,8 @@
2
2
  * Service Tier — gating, status formatting, icon resolution, and
3
3
  * the /gsd fast command handler.
4
4
  *
5
- * Service tiers (priority/flex) are an OpenAI feature that only applies
6
- * to gpt-5.4 variants. This module centralizes the model-gating logic
5
+ * Service tiers (priority/flex) are an OpenAI feature that currently only
6
+ * applies to gpt-5.4 variants in GSD. This module centralizes the model-gating logic
7
7
  * so that icons, preferences, and the before_provider_request hook all
8
8
  * use a single source of truth.
9
9
  */
@@ -21,6 +21,9 @@ const SERVICE_TIER_SCOPE_NOTE = "Only affects gpt-5.4 models, regardless of prov
21
21
  * (set via CAPABILITY_PATCHES in packages/pi-ai/src/models.ts). When callers
22
22
  * have access to the full Model object, prefer reading capabilities directly.
23
23
  *
24
+ * GPT-5.5 is intentionally excluded until we verify its provider payload
25
+ * contract instead of assuming `service_tier` support.
26
+ *
24
27
  * See: https://github.com/gsd-build/gsd-2/issues/2546
25
28
  */
26
29
  const SERVICE_TIER_MODEL_PREFIXES = ["gpt-5.4"];
@@ -0,0 +1,168 @@
1
+ // GSD2 + skill-manifest — per-unit-type skill allowlist resolver (RFC #4779)
2
+ //
3
+ // Each auto-mode unit type can declare which skills are relevant to it. This
4
+ // trims the set of skills considered for activation in the per-unit prompt,
5
+ // reducing prompt token bloat and sharpening model focus.
6
+ //
7
+ // Contract:
8
+ // - Unknown unit types fall through to "all skills" (current behavior).
9
+ // - A manifest entry referencing a skill that is not installed is a silent
10
+ // no-op at filter time — the filter passes through installed skills only.
11
+ // - The allowlist is an inclusion list: only skills whose normalized name
12
+ // appears in the allowlist are retained. Order is not preserved.
13
+ //
14
+ // Phase 1 scope: seed manifests for a small number of unit types as proof.
15
+ // Additional unit types can be added incrementally; each addition is a pure
16
+ // data change with no wiring cost.
17
+ import { logWarning } from "./workflow-logger.js";
18
+ /** Normalize a skill reference the same way callers do (lowercase, trim). */
19
+ function normalize(name) {
20
+ return name.trim().toLowerCase();
21
+ }
22
+ /**
23
+ * Allowlist per unit type. Keys match unit type identifiers used by auto-mode
24
+ * dispatch. Values are normalized skill names.
25
+ *
26
+ * Wildcard semantics: a unit type absent from this map resolves to `null`
27
+ * (wildcard) — meaning "all installed skills are eligible". Prefer absence
28
+ * over an exhaustive list when uncertain.
29
+ */
30
+ const UNIT_TYPE_SKILL_MANIFEST = {
31
+ // Milestone-level planning / meta flows — predictable skill sets.
32
+ "research-milestone": [
33
+ "write-docs",
34
+ "write-milestone-brief",
35
+ "decompose-into-slices",
36
+ "grill-me",
37
+ "design-an-interface",
38
+ "api-design",
39
+ "observability",
40
+ ],
41
+ "plan-milestone": [
42
+ "write-milestone-brief",
43
+ "decompose-into-slices",
44
+ "design-an-interface",
45
+ "grill-me",
46
+ "write-docs",
47
+ "api-design",
48
+ "tdd",
49
+ "verify-before-complete",
50
+ ],
51
+ "complete-milestone": [
52
+ "verify-before-complete",
53
+ "write-docs",
54
+ "handoff",
55
+ "forensics",
56
+ "observability",
57
+ "security-review",
58
+ ],
59
+ "validate-milestone": [
60
+ "verify-before-complete",
61
+ "review",
62
+ "test",
63
+ "lint",
64
+ "security-review",
65
+ "accessibility",
66
+ "forensics",
67
+ "observability",
68
+ ],
69
+ "reassess-roadmap": [
70
+ "decompose-into-slices",
71
+ "grill-me",
72
+ "write-milestone-brief",
73
+ "write-docs",
74
+ "forensics",
75
+ ],
76
+ // Slice-level research / planning.
77
+ "research-slice": [
78
+ "write-docs",
79
+ "decompose-into-slices",
80
+ "design-an-interface",
81
+ "grill-me",
82
+ "api-design",
83
+ "observability",
84
+ ],
85
+ "plan-slice": [
86
+ "decompose-into-slices",
87
+ "design-an-interface",
88
+ "grill-me",
89
+ "write-docs",
90
+ "api-design",
91
+ "tdd",
92
+ "verify-before-complete",
93
+ ],
94
+ "refine-slice": [
95
+ "decompose-into-slices",
96
+ "design-an-interface",
97
+ "grill-me",
98
+ "write-docs",
99
+ "api-design",
100
+ "tdd",
101
+ "verify-before-complete",
102
+ ],
103
+ "replan-slice": [
104
+ "decompose-into-slices",
105
+ "grill-me",
106
+ "design-an-interface",
107
+ "write-docs",
108
+ "api-design",
109
+ ],
110
+ "run-uat": [
111
+ "verify-before-complete",
112
+ "test",
113
+ "review",
114
+ "accessibility",
115
+ ],
116
+ // `execute-task` intentionally omitted — implementation hot path covers a
117
+ // wide surface of technologies; wildcard fallback preserves today's
118
+ // behavior until per-task skill hints can be derived from task-plan
119
+ // frontmatter. See RFC #4779.
120
+ };
121
+ /**
122
+ * Resolve the skill allowlist for a unit type.
123
+ *
124
+ * @returns Array of normalized skill names when an entry exists, or `null`
125
+ * when the unit type is unknown (wildcard — caller should not filter).
126
+ */
127
+ export function resolveSkillManifest(unitType) {
128
+ if (!unitType)
129
+ return null;
130
+ const entry = UNIT_TYPE_SKILL_MANIFEST[unitType];
131
+ if (!entry)
132
+ return null;
133
+ return entry.map(normalize);
134
+ }
135
+ /**
136
+ * Filter a skill list by the manifest for `unitType`. Pass-through when the
137
+ * manifest is wildcard (unknown unit type) or `unitType` is undefined.
138
+ */
139
+ export function filterSkillsByManifest(skills, unitType) {
140
+ const allowlist = resolveSkillManifest(unitType);
141
+ if (allowlist === null)
142
+ return skills;
143
+ const allowed = new Set(allowlist);
144
+ return skills.filter(skill => allowed.has(normalize(skill.name)));
145
+ }
146
+ /**
147
+ * Dev-mode guard: warn once per process if a manifest entry references a name
148
+ * that is not currently installed. Silent in production.
149
+ */
150
+ const warnedMissing = new Set();
151
+ export function warnIfManifestHasMissingSkills(unitType, installedNames) {
152
+ // Strict mode is intentionally opt-in via exactly "1"; values like "0" or
153
+ // "false" must preserve the normal silent manifest behavior.
154
+ if (process.env.GSD_SKILL_MANIFEST_STRICT !== "1")
155
+ return;
156
+ const allowlist = resolveSkillManifest(unitType);
157
+ if (!allowlist)
158
+ return;
159
+ for (const name of allowlist) {
160
+ const key = `${unitType}:${name}`;
161
+ if (warnedMissing.has(key))
162
+ continue;
163
+ if (!installedNames.has(name)) {
164
+ warnedMissing.add(key);
165
+ logWarning("prompt", `skill-manifest: references uninstalled skill '${name}' for unit '${unitType}'`);
166
+ }
167
+ }
168
+ }