gsd-pi 2.80.0-dev.3065f7bfa → 2.80.0-dev.488219eb6

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 (376) hide show
  1. package/dist/claude-cli-check.d.ts +30 -0
  2. package/dist/claude-cli-check.js +18 -7
  3. package/dist/cli.js +0 -19
  4. package/dist/headless-query.d.ts +10 -0
  5. package/dist/headless-query.js +6 -4
  6. package/dist/loader-entrypoint.d.ts +8 -0
  7. package/dist/loader-entrypoint.js +27 -0
  8. package/dist/loader.js +2 -11
  9. package/dist/mcp-server.d.ts +1 -0
  10. package/dist/mcp-server.js +6 -3
  11. package/dist/resources/.managed-resources-content-hash +1 -1
  12. package/dist/resources/extensions/claude-code-cli/readiness.js +18 -7
  13. package/dist/resources/extensions/claude-code-cli/stream-adapter.js +29 -0
  14. package/dist/resources/extensions/github-sync/sync.js +4 -1
  15. package/dist/resources/extensions/gsd/auto/loop.js +71 -8
  16. package/dist/resources/extensions/gsd/auto/phases.js +32 -8
  17. package/dist/resources/extensions/gsd/auto/resolve.js +12 -0
  18. package/dist/resources/extensions/gsd/auto/run-unit.js +3 -1
  19. package/dist/resources/extensions/gsd/auto/workflow-dispatch-claim.js +33 -1
  20. package/dist/resources/extensions/gsd/auto/workflow-worker-heartbeat.js +9 -1
  21. package/dist/resources/extensions/gsd/auto-post-unit.js +81 -76
  22. package/dist/resources/extensions/gsd/auto-start.js +41 -6
  23. package/dist/resources/extensions/gsd/auto-worktree.js +98 -80
  24. package/dist/resources/extensions/gsd/auto.js +84 -29
  25. package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +62 -13
  26. package/dist/resources/extensions/gsd/bootstrap/db-tools.js +20 -26
  27. package/dist/resources/extensions/gsd/bootstrap/dynamic-tools.js +29 -12
  28. package/dist/resources/extensions/gsd/bootstrap/exec-tools.js +6 -9
  29. package/dist/resources/extensions/gsd/bootstrap/journal-tools.js +4 -7
  30. package/dist/resources/extensions/gsd/bootstrap/memory-tools.js +6 -10
  31. package/dist/resources/extensions/gsd/bootstrap/query-tools.js +5 -9
  32. package/dist/resources/extensions/gsd/bootstrap/register-extension.js +1 -1
  33. package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +60 -26
  34. package/dist/resources/extensions/gsd/bootstrap/sanitize-complete-milestone.js +4 -0
  35. package/dist/resources/extensions/gsd/commands/handlers/ops.js +2 -2
  36. package/dist/resources/extensions/gsd/commands-config.js +1 -1
  37. package/dist/resources/extensions/gsd/commands-eval-review.js +2 -2
  38. package/dist/resources/extensions/gsd/dashboard-overlay.js +1 -1
  39. package/dist/resources/extensions/gsd/db/unit-dispatches.js +53 -0
  40. package/dist/resources/extensions/gsd/git-service.js +37 -1
  41. package/dist/resources/extensions/gsd/guided-flow.js +14 -4
  42. package/dist/resources/extensions/gsd/init-wizard.js +4 -1
  43. package/dist/resources/extensions/gsd/prompts/complete-milestone.md +6 -4
  44. package/dist/resources/extensions/gsd/slice-cadence.js +45 -2
  45. package/dist/resources/extensions/gsd/slice-parallel-orchestrator.js +15 -9
  46. package/dist/resources/extensions/gsd/tools/complete-milestone.js +6 -7
  47. package/dist/resources/extensions/gsd/tools/complete-task.js +1 -1
  48. package/dist/resources/extensions/gsd/worktree-resolver.js +22 -1
  49. package/dist/resources/skills/web-quality-audit/scripts/analyze.sh +0 -0
  50. package/dist/tsconfig.extensions.tsbuildinfo +1 -1
  51. package/dist/web/standalone/.next/BUILD_ID +1 -1
  52. package/dist/web/standalone/.next/app-path-routes-manifest.json +17 -17
  53. package/dist/web/standalone/.next/build-manifest.json +3 -3
  54. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  55. package/dist/web/standalone/.next/react-loadable-manifest.json +2 -2
  56. package/dist/web/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
  57. package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
  58. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  59. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  60. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  61. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  62. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  63. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  64. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  65. package/dist/web/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  66. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  67. package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
  68. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
  69. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  70. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
  71. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  72. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  73. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  74. package/dist/web/standalone/.next/server/app/index.html +1 -1
  75. package/dist/web/standalone/.next/server/app/index.rsc +2 -2
  76. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
  77. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +2 -2
  78. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  79. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
  80. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  81. package/dist/web/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
  82. package/dist/web/standalone/.next/server/app-paths-manifest.json +17 -17
  83. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  84. package/dist/web/standalone/.next/server/middleware-react-loadable-manifest.js +1 -1
  85. package/dist/web/standalone/.next/server/middleware.js +3 -3
  86. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  87. package/dist/web/standalone/.next/server/pages/500.html +1 -1
  88. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  89. package/dist/web/standalone/.next/static/chunks/8359.e059d86b255fce1c.js +10 -0
  90. package/dist/web/standalone/.next/static/chunks/app/{page-fab3ebb85b006001.js → page-752f1e2ebdaa3e45.js} +1 -1
  91. package/dist/web/standalone/.next/static/chunks/{webpack-0481f1221120a7c6.js → webpack-de742b64187e13fe.js} +1 -1
  92. package/dist/welcome-screen.d.ts +2 -0
  93. package/dist/welcome-screen.js +9 -7
  94. package/package.json +1 -1
  95. package/packages/pi-ai/dist/providers/anthropic-auth.test.js +35 -13
  96. package/packages/pi-ai/dist/providers/anthropic-auth.test.js.map +1 -1
  97. package/packages/pi-ai/dist/providers/anthropic-bearer-auth.test.js +21 -11
  98. package/packages/pi-ai/dist/providers/anthropic-bearer-auth.test.js.map +1 -1
  99. package/packages/pi-ai/dist/providers/anthropic.d.ts +7 -0
  100. package/packages/pi-ai/dist/providers/anthropic.d.ts.map +1 -1
  101. package/packages/pi-ai/dist/providers/anthropic.js +9 -7
  102. package/packages/pi-ai/dist/providers/anthropic.js.map +1 -1
  103. package/packages/pi-ai/dist/providers/minimax-tool-name.test.js +23 -14
  104. package/packages/pi-ai/dist/providers/minimax-tool-name.test.js.map +1 -1
  105. package/packages/pi-ai/dist/utils/oauth/github-copilot.test.js +48 -21
  106. package/packages/pi-ai/dist/utils/oauth/github-copilot.test.js.map +1 -1
  107. package/packages/pi-ai/dist/utils/oauth/google-antigravity.test.js +22 -21
  108. package/packages/pi-ai/dist/utils/oauth/google-antigravity.test.js.map +1 -1
  109. package/packages/pi-ai/dist/utils/oauth/google-gemini-cli.test.js +22 -21
  110. package/packages/pi-ai/dist/utils/oauth/google-gemini-cli.test.js.map +1 -1
  111. package/packages/pi-ai/src/providers/anthropic-auth.test.ts +39 -25
  112. package/packages/pi-ai/src/providers/anthropic-bearer-auth.test.ts +26 -22
  113. package/packages/pi-ai/src/providers/anthropic.ts +22 -9
  114. package/packages/pi-ai/src/providers/minimax-tool-name.test.ts +34 -21
  115. package/packages/pi-ai/src/utils/oauth/github-copilot.test.ts +56 -22
  116. package/packages/pi-ai/src/utils/oauth/google-antigravity.test.ts +24 -28
  117. package/packages/pi-ai/src/utils/oauth/google-gemini-cli.test.ts +24 -28
  118. package/packages/pi-ai/tsconfig.tsbuildinfo +1 -1
  119. package/packages/pi-coding-agent/dist/core/chat-controller-ordering.test.js +3 -1
  120. package/packages/pi-coding-agent/dist/core/chat-controller-ordering.test.js.map +1 -1
  121. package/packages/pi-coding-agent/dist/core/extensions/types.d.ts +2 -2
  122. package/packages/pi-coding-agent/dist/core/extensions/types.d.ts.map +1 -1
  123. package/packages/pi-coding-agent/dist/core/extensions/types.js.map +1 -1
  124. package/packages/pi-coding-agent/dist/core/tools/bash-spawn-windows.test.js +22 -56
  125. package/packages/pi-coding-agent/dist/core/tools/bash-spawn-windows.test.js.map +1 -1
  126. package/packages/pi-coding-agent/dist/core/tools/bash.d.ts +1 -0
  127. package/packages/pi-coding-agent/dist/core/tools/bash.d.ts.map +1 -1
  128. package/packages/pi-coding-agent/dist/core/tools/bash.js +3 -1
  129. package/packages/pi-coding-agent/dist/core/tools/bash.js.map +1 -1
  130. package/packages/pi-coding-agent/dist/core/tools/edit.d.ts +2 -0
  131. package/packages/pi-coding-agent/dist/core/tools/edit.d.ts.map +1 -1
  132. package/packages/pi-coding-agent/dist/core/tools/edit.js +12 -1
  133. package/packages/pi-coding-agent/dist/core/tools/edit.js.map +1 -1
  134. package/packages/pi-coding-agent/dist/core/tools/find.d.ts +2 -0
  135. package/packages/pi-coding-agent/dist/core/tools/find.d.ts.map +1 -1
  136. package/packages/pi-coding-agent/dist/core/tools/find.js +14 -6
  137. package/packages/pi-coding-agent/dist/core/tools/find.js.map +1 -1
  138. package/packages/pi-coding-agent/dist/core/tools/grep.d.ts +2 -0
  139. package/packages/pi-coding-agent/dist/core/tools/grep.d.ts.map +1 -1
  140. package/packages/pi-coding-agent/dist/core/tools/grep.js +12 -3
  141. package/packages/pi-coding-agent/dist/core/tools/grep.js.map +1 -1
  142. package/packages/pi-coding-agent/dist/core/tools/hashline-read.d.ts +2 -0
  143. package/packages/pi-coding-agent/dist/core/tools/hashline-read.d.ts.map +1 -1
  144. package/packages/pi-coding-agent/dist/core/tools/hashline-read.js +3 -1
  145. package/packages/pi-coding-agent/dist/core/tools/hashline-read.js.map +1 -1
  146. package/packages/pi-coding-agent/dist/core/tools/index.d.ts +2 -1
  147. package/packages/pi-coding-agent/dist/core/tools/index.d.ts.map +1 -1
  148. package/packages/pi-coding-agent/dist/core/tools/index.js +1 -0
  149. package/packages/pi-coding-agent/dist/core/tools/index.js.map +1 -1
  150. package/packages/pi-coding-agent/dist/core/tools/ls.d.ts +2 -0
  151. package/packages/pi-coding-agent/dist/core/tools/ls.d.ts.map +1 -1
  152. package/packages/pi-coding-agent/dist/core/tools/ls.js +10 -3
  153. package/packages/pi-coding-agent/dist/core/tools/ls.js.map +1 -1
  154. package/packages/pi-coding-agent/dist/core/tools/read.d.ts +2 -0
  155. package/packages/pi-coding-agent/dist/core/tools/read.d.ts.map +1 -1
  156. package/packages/pi-coding-agent/dist/core/tools/read.js +3 -1
  157. package/packages/pi-coding-agent/dist/core/tools/read.js.map +1 -1
  158. package/packages/pi-coding-agent/dist/core/tools/spawn-shell-windows.test.js +7 -62
  159. package/packages/pi-coding-agent/dist/core/tools/spawn-shell-windows.test.js.map +1 -1
  160. package/packages/pi-coding-agent/dist/core/tools/tool-target-metadata.test.d.ts +2 -0
  161. package/packages/pi-coding-agent/dist/core/tools/tool-target-metadata.test.d.ts.map +1 -0
  162. package/packages/pi-coding-agent/dist/core/tools/tool-target-metadata.test.js +115 -0
  163. package/packages/pi-coding-agent/dist/core/tools/tool-target-metadata.test.js.map +1 -0
  164. package/packages/pi-coding-agent/dist/core/tools/tool-target.d.ts +19 -0
  165. package/packages/pi-coding-agent/dist/core/tools/tool-target.d.ts.map +1 -0
  166. package/packages/pi-coding-agent/dist/core/tools/tool-target.js +20 -0
  167. package/packages/pi-coding-agent/dist/core/tools/tool-target.js.map +1 -0
  168. package/packages/pi-coding-agent/dist/core/tools/write.d.ts +4 -0
  169. package/packages/pi-coding-agent/dist/core/tools/write.d.ts.map +1 -1
  170. package/packages/pi-coding-agent/dist/core/tools/write.js +9 -1
  171. package/packages/pi-coding-agent/dist/core/tools/write.js.map +1 -1
  172. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/tool-execution.test.js +89 -2
  173. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/tool-execution.test.js.map +1 -1
  174. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-card-cleanup-and-success-runtime.test.js +25 -1
  175. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-card-cleanup-and-success-runtime.test.js.map +1 -1
  176. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.d.ts +5 -0
  177. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  178. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js +153 -8
  179. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js.map +1 -1
  180. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.d.ts.map +1 -1
  181. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js +18 -1
  182. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js.map +1 -1
  183. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.test.js +23 -5
  184. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.test.js.map +1 -1
  185. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts +2 -0
  186. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  187. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js +19 -0
  188. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
  189. package/packages/pi-coding-agent/dist/resources/extensions/memory/storage-safety-guard.test.js +23 -5
  190. package/packages/pi-coding-agent/dist/resources/extensions/memory/storage-safety-guard.test.js.map +1 -1
  191. package/packages/pi-coding-agent/src/core/chat-controller-ordering.test.ts +3 -1
  192. package/packages/pi-coding-agent/src/core/extensions/types.ts +2 -1
  193. package/packages/pi-coding-agent/src/core/tools/bash-spawn-windows.test.ts +22 -66
  194. package/packages/pi-coding-agent/src/core/tools/bash.ts +4 -1
  195. package/packages/pi-coding-agent/src/core/tools/edit.ts +13 -1
  196. package/packages/pi-coding-agent/src/core/tools/find.ts +15 -6
  197. package/packages/pi-coding-agent/src/core/tools/grep.ts +13 -3
  198. package/packages/pi-coding-agent/src/core/tools/hashline-read.ts +4 -1
  199. package/packages/pi-coding-agent/src/core/tools/index.ts +8 -0
  200. package/packages/pi-coding-agent/src/core/tools/ls.ts +11 -3
  201. package/packages/pi-coding-agent/src/core/tools/read.ts +4 -1
  202. package/packages/pi-coding-agent/src/core/tools/spawn-shell-windows.test.ts +11 -72
  203. package/packages/pi-coding-agent/src/core/tools/tool-target-metadata.test.ts +127 -0
  204. package/packages/pi-coding-agent/src/core/tools/tool-target.ts +48 -0
  205. package/packages/pi-coding-agent/src/core/tools/write.ts +14 -2
  206. package/packages/pi-coding-agent/src/modes/interactive/components/__tests__/tool-execution.test.ts +119 -2
  207. package/packages/pi-coding-agent/src/modes/interactive/components/tool-card-cleanup-and-success-runtime.test.ts +31 -1
  208. package/packages/pi-coding-agent/src/modes/interactive/components/tool-execution.ts +177 -8
  209. package/packages/pi-coding-agent/src/modes/interactive/controllers/chat-controller.test.ts +24 -5
  210. package/packages/pi-coding-agent/src/modes/interactive/controllers/chat-controller.ts +17 -1
  211. package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +21 -0
  212. package/packages/pi-coding-agent/src/resources/extensions/memory/storage-safety-guard.test.ts +25 -8
  213. package/packages/pi-coding-agent/tsconfig.tsbuildinfo +1 -1
  214. package/src/resources/extensions/claude-code-cli/readiness.ts +25 -7
  215. package/src/resources/extensions/claude-code-cli/stream-adapter.ts +30 -0
  216. package/src/resources/extensions/claude-code-cli/tests/stream-adapter.test.ts +26 -0
  217. package/src/resources/extensions/github-sync/sync.ts +8 -1
  218. package/src/resources/extensions/github-sync/tests/sync-source.test.ts +6 -18
  219. package/src/resources/extensions/gsd/auto/loop.ts +84 -8
  220. package/src/resources/extensions/gsd/auto/phases.ts +43 -8
  221. package/src/resources/extensions/gsd/auto/resolve.ts +19 -0
  222. package/src/resources/extensions/gsd/auto/run-unit.ts +3 -0
  223. package/src/resources/extensions/gsd/auto/workflow-dispatch-claim.ts +63 -1
  224. package/src/resources/extensions/gsd/auto/workflow-worker-heartbeat.ts +14 -1
  225. package/src/resources/extensions/gsd/auto-post-unit.ts +93 -78
  226. package/src/resources/extensions/gsd/auto-start.ts +56 -6
  227. package/src/resources/extensions/gsd/auto-worktree.ts +118 -72
  228. package/src/resources/extensions/gsd/auto.ts +121 -29
  229. package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +76 -12
  230. package/src/resources/extensions/gsd/bootstrap/db-tools.ts +20 -26
  231. package/src/resources/extensions/gsd/bootstrap/dynamic-tools.ts +27 -12
  232. package/src/resources/extensions/gsd/bootstrap/exec-tools.ts +7 -9
  233. package/src/resources/extensions/gsd/bootstrap/journal-tools.ts +4 -7
  234. package/src/resources/extensions/gsd/bootstrap/memory-tools.ts +6 -10
  235. package/src/resources/extensions/gsd/bootstrap/query-tools.ts +5 -9
  236. package/src/resources/extensions/gsd/bootstrap/register-extension.ts +1 -1
  237. package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +64 -26
  238. package/src/resources/extensions/gsd/bootstrap/sanitize-complete-milestone.ts +4 -0
  239. package/src/resources/extensions/gsd/commands/handlers/ops.ts +4 -2
  240. package/src/resources/extensions/gsd/commands-config.ts +1 -1
  241. package/src/resources/extensions/gsd/commands-eval-review.ts +2 -2
  242. package/src/resources/extensions/gsd/dashboard-overlay.ts +1 -1
  243. package/src/resources/extensions/gsd/db/unit-dispatches.ts +66 -0
  244. package/src/resources/extensions/gsd/git-service.ts +41 -2
  245. package/src/resources/extensions/gsd/guided-flow.ts +19 -4
  246. package/src/resources/extensions/gsd/init-wizard.ts +5 -1
  247. package/src/resources/extensions/gsd/prompts/complete-milestone.md +6 -4
  248. package/src/resources/extensions/gsd/slice-cadence.ts +49 -2
  249. package/src/resources/extensions/gsd/slice-parallel-orchestrator.ts +23 -9
  250. package/src/resources/extensions/gsd/tests/agent-end-retry.test.ts +59 -89
  251. package/src/resources/extensions/gsd/tests/artifact-retry-cap.test.ts +47 -172
  252. package/src/resources/extensions/gsd/tests/artifacts-table-preserved-on-cache-invalidate.test.ts +0 -35
  253. package/src/resources/extensions/gsd/tests/auto-dashboard.test.ts +35 -9
  254. package/src/resources/extensions/gsd/tests/auto-loop.test.ts +15 -0
  255. package/src/resources/extensions/gsd/tests/auto-model-selection.test.ts +80 -59
  256. package/src/resources/extensions/gsd/tests/auto-paused-session-validation.test.ts +3 -47
  257. package/src/resources/extensions/gsd/tests/auto-paused-ui-cleanup.test.ts +76 -18
  258. package/src/resources/extensions/gsd/tests/auto-phases-lifecycle.test.ts +106 -0
  259. package/src/resources/extensions/gsd/tests/auto-pr-bugs.test.ts +54 -95
  260. package/src/resources/extensions/gsd/tests/auto-project-root-env.test.ts +67 -26
  261. package/src/resources/extensions/gsd/tests/auto-remediate-slice-status.test.ts +32 -30
  262. package/src/resources/extensions/gsd/tests/auto-start-bootstrap-await-3420.test.ts +32 -128
  263. package/src/resources/extensions/gsd/tests/auto-start-clean-runtime-db-gated.test.ts +20 -54
  264. package/src/resources/extensions/gsd/tests/auto-start-cold-db-bootstrap.test.ts +20 -30
  265. package/src/resources/extensions/gsd/tests/auto-start-index-lock.test.ts +17 -29
  266. package/src/resources/extensions/gsd/tests/auto-start-orphan-bootstrap.test.ts +138 -0
  267. package/src/resources/extensions/gsd/tests/auto-start-time-persistence.test.ts +21 -39
  268. package/src/resources/extensions/gsd/tests/auto-start-worktree-db-path.test.ts +15 -24
  269. package/src/resources/extensions/gsd/tests/auto-thinking-restore.test.ts +44 -29
  270. package/src/resources/extensions/gsd/tests/auto-warning-noise-regression.test.ts +39 -51
  271. package/src/resources/extensions/gsd/tests/auto-wrapup-inflight-guard.test.ts +1 -217
  272. package/src/resources/extensions/gsd/tests/bootstrap-derive-state-db-open.test.ts +15 -32
  273. package/src/resources/extensions/gsd/tests/browser-teardown.test.ts +0 -41
  274. package/src/resources/extensions/gsd/tests/clear-stale-autostart.test.ts +34 -27
  275. package/src/resources/extensions/gsd/tests/cmux.test.ts +51 -53
  276. package/src/resources/extensions/gsd/tests/cold-resume-db-reopen.test.ts +39 -61
  277. package/src/resources/extensions/gsd/tests/commands-config.test.ts +26 -19
  278. package/src/resources/extensions/gsd/tests/complete-milestone.test.ts +140 -0
  279. package/src/resources/extensions/gsd/tests/complete-task-normalize-lists.test.ts +29 -33
  280. package/src/resources/extensions/gsd/tests/completed-units-metrics-sync.test.ts +45 -108
  281. package/src/resources/extensions/gsd/tests/crash-handler-secondary.test.ts +35 -31
  282. package/src/resources/extensions/gsd/tests/cwd-fallback-hardening.test.ts +138 -0
  283. package/src/resources/extensions/gsd/tests/dashboard-custom-engine.test.ts +4 -68
  284. package/src/resources/extensions/gsd/tests/deep-project-auto-loop.test.ts +4 -9
  285. package/src/resources/extensions/gsd/tests/deferred-milestone-dir-4996.test.ts +14 -65
  286. package/src/resources/extensions/gsd/tests/discuss-tool-scoping.test.ts +44 -37
  287. package/src/resources/extensions/gsd/tests/dispatch-complete-milestone-guard.test.ts +58 -40
  288. package/src/resources/extensions/gsd/tests/dispatch-guard-closed-status.test.ts +25 -15
  289. package/src/resources/extensions/gsd/tests/dispatcher-stuck-planning.test.ts +35 -17
  290. package/src/resources/extensions/gsd/tests/error-success-mask.test.ts +16 -21
  291. package/src/resources/extensions/gsd/tests/est-annotation-timeout.test.ts +15 -82
  292. package/src/resources/extensions/gsd/tests/flat-rate-routing-guard.test.ts +2 -20
  293. package/src/resources/extensions/gsd/tests/frontmatter-parse-noise.test.ts +18 -26
  294. package/src/resources/extensions/gsd/tests/init-skip-git.test.ts +9 -12
  295. package/src/resources/extensions/gsd/tests/integration/auto-worktree-milestone-merge.test.ts +40 -0
  296. package/src/resources/extensions/gsd/tests/integration/commands-eval-review.integration.test.ts +4 -2
  297. package/src/resources/extensions/gsd/tests/integration/git-locale.test.ts +31 -20
  298. package/src/resources/extensions/gsd/tests/integration/git-service.test.ts +12 -0
  299. package/src/resources/extensions/gsd/tests/integration/milestone-transition-worktree.test.ts +0 -47
  300. package/src/resources/extensions/gsd/tests/interactive-routing-bypass.test.ts +60 -202
  301. package/src/resources/extensions/gsd/tests/isolation-none-branch-guard.test.ts +13 -59
  302. package/src/resources/extensions/gsd/tests/lazy-pi-tui-import.test.ts +44 -6
  303. package/src/resources/extensions/gsd/tests/memory-pressure-stuck-state.test.ts +21 -35
  304. package/src/resources/extensions/gsd/tests/milestone-transition-state-rebuild.test.ts +79 -98
  305. package/src/resources/extensions/gsd/tests/model-unittype-mapping.test.ts +70 -278
  306. package/src/resources/extensions/gsd/tests/needs-remediation-revalidation.test.ts +37 -30
  307. package/src/resources/extensions/gsd/tests/note-captures-executed.test.ts +32 -28
  308. package/src/resources/extensions/gsd/tests/phantom-ghost-detection.test.ts +24 -37
  309. package/src/resources/extensions/gsd/tests/phantom-milestone-default-queued.test.ts +9 -24
  310. package/src/resources/extensions/gsd/tests/phases-merge-error-stops-auto.test.ts +113 -0
  311. package/src/resources/extensions/gsd/tests/post-unit-state-rebuild.test.ts +36 -22
  312. package/src/resources/extensions/gsd/tests/pre-exec-backtick-strip.test.ts +36 -30
  313. package/src/resources/extensions/gsd/tests/pre-execution-pause-wiring.test.ts +74 -4
  314. package/src/resources/extensions/gsd/tests/preferences-worktree-sync.test.ts +20 -22
  315. package/src/resources/extensions/gsd/tests/prefs-wizard-coverage.test.ts +130 -32
  316. package/src/resources/extensions/gsd/tests/project-root-cwd-crash.test.ts +18 -36
  317. package/src/resources/extensions/gsd/tests/projection-no-plan-overwrite.test.ts +35 -73
  318. package/src/resources/extensions/gsd/tests/prompt-budget-enforcement.test.ts +76 -138
  319. package/src/resources/extensions/gsd/tests/prompt-step-ordering.test.ts +70 -125
  320. package/src/resources/extensions/gsd/tests/provider-errors.test.ts +59 -161
  321. package/src/resources/extensions/gsd/tests/query-tools-db-open.test.ts +33 -29
  322. package/src/resources/extensions/gsd/tests/queue-auto-guard.test.ts +22 -196
  323. package/src/resources/extensions/gsd/tests/quick-auto-guard.test.ts +23 -93
  324. package/src/resources/extensions/gsd/tests/quick-turn-end-cleanup.test.ts +50 -79
  325. package/src/resources/extensions/gsd/tests/reassess-default-optin.test.ts +27 -13
  326. package/src/resources/extensions/gsd/tests/remote-questions.test.ts +151 -251
  327. package/src/resources/extensions/gsd/tests/resource-loader-import-path.test.ts +41 -29
  328. package/src/resources/extensions/gsd/tests/restore-tools-after-discuss.test.ts +58 -90
  329. package/src/resources/extensions/gsd/tests/resume-dispatch-worktree.test.ts +32 -164
  330. package/src/resources/extensions/gsd/tests/run-uat-replay-cap.test.ts +57 -41
  331. package/src/resources/extensions/gsd/tests/session-model-override.test.ts +14 -9
  332. package/src/resources/extensions/gsd/tests/session-start-footer.test.ts +77 -0
  333. package/src/resources/extensions/gsd/tests/session-switch-abort-misclassification.test.ts +61 -1
  334. package/src/resources/extensions/gsd/tests/show-config-command.test.ts +44 -42
  335. package/src/resources/extensions/gsd/tests/skip-slice-state-rebuild.test.ts +56 -24
  336. package/src/resources/extensions/gsd/tests/skipped-validation-db-atomicity.test.ts +51 -11
  337. package/src/resources/extensions/gsd/tests/slice-cadence.test.ts +23 -0
  338. package/src/resources/extensions/gsd/tests/slice-context-injection.test.ts +66 -50
  339. package/src/resources/extensions/gsd/tests/slice-parallel-orchestrator.test.ts +68 -107
  340. package/src/resources/extensions/gsd/tests/slice-sequence-insert.test.ts +115 -42
  341. package/src/resources/extensions/gsd/tests/smart-entry-complete.test.ts +21 -97
  342. package/src/resources/extensions/gsd/tests/smart-entry-draft.test.ts +25 -116
  343. package/src/resources/extensions/gsd/tests/sqlite-unavailable-gate.test.ts +21 -57
  344. package/src/resources/extensions/gsd/tests/stale-dirlistcache-4648.test.ts +29 -76
  345. package/src/resources/extensions/gsd/tests/stale-lockfile-recovery.test.ts +33 -24
  346. package/src/resources/extensions/gsd/tests/stale-slice-rows.test.ts +39 -30
  347. package/src/resources/extensions/gsd/tests/status-db-open.test.ts +33 -47
  348. package/src/resources/extensions/gsd/tests/stop-auto-merge-back.test.ts +48 -46
  349. package/src/resources/extensions/gsd/tests/stop-auto-race-null-unit.test.ts +14 -102
  350. package/src/resources/extensions/gsd/tests/subagent-model-dispatch.test.ts +78 -232
  351. package/src/resources/extensions/gsd/tests/sync-worktree-skip-current.test.ts +32 -35
  352. package/src/resources/extensions/gsd/tests/token-profile.test.ts +84 -309
  353. package/src/resources/extensions/gsd/tests/triage-dispatch.test.ts +134 -341
  354. package/src/resources/extensions/gsd/tests/unit-context-manifest.test.ts +8 -25
  355. package/src/resources/extensions/gsd/tests/unit-dispatches.test.ts +50 -1
  356. package/src/resources/extensions/gsd/tests/unstructured-continue-context-injection.test.ts +6 -101
  357. package/src/resources/extensions/gsd/tests/uok-plan-v2-wiring.test.ts +43 -36
  358. package/src/resources/extensions/gsd/tests/visualizer-data.test.ts +84 -444
  359. package/src/resources/extensions/gsd/tests/workflow-dispatch-claim.test.ts +142 -0
  360. package/src/resources/extensions/gsd/tests/workflow-logger-wiring.test.ts +44 -189
  361. package/src/resources/extensions/gsd/tests/workflow-mcp.test.ts +2 -57
  362. package/src/resources/extensions/gsd/tests/workflow-worker-heartbeat.test.ts +32 -1
  363. package/src/resources/extensions/gsd/tests/worktree-db-same-file.test.ts +21 -44
  364. package/src/resources/extensions/gsd/tests/worktree-expected-warnings.test.ts +27 -26
  365. package/src/resources/extensions/gsd/tests/worktree-health-dispatch.test.ts +14 -13
  366. package/src/resources/extensions/gsd/tests/worktree-main-branch.test.ts +20 -18
  367. package/src/resources/extensions/gsd/tests/worktree-resolver.test.ts +36 -0
  368. package/src/resources/extensions/gsd/tests/zero-slice-roadmap-guided.test.ts +19 -13
  369. package/src/resources/extensions/gsd/tools/complete-milestone.ts +14 -15
  370. package/src/resources/extensions/gsd/tools/complete-task.ts +1 -1
  371. package/src/resources/extensions/gsd/worktree-resolver.ts +34 -1
  372. package/src/resources/skills/create-gsd-extension/templates/templates.test.ts +86 -40
  373. package/src/resources/skills/web-quality-audit/scripts/analyze.sh +0 -0
  374. package/dist/web/standalone/.next/static/chunks/8336.631939fb583761fa.js +0 -10
  375. /package/dist/web/standalone/.next/static/{O2WvnXROue6l7nAp_4dhC → G68KoLv5claox_Dyd4pZn}/_buildManifest.js +0 -0
  376. /package/dist/web/standalone/.next/static/{O2WvnXROue6l7nAp_4dhC → G68KoLv5claox_Dyd4pZn}/_ssgManifest.js +0 -0
@@ -1,45 +1,143 @@
1
- // Guard test every key in KNOWN_PREFERENCE_KEYS must be reachable from the
2
- // /gsd prefs wizard. Without this guard, a new preference can be added to the
3
- // schema without anyone wiring it into the TUI, silently re-creating the gap
4
- // this test exists to prevent.
1
+ // GSD-2 + prefs-wizard-coverage.test.ts - Behavioral coverage for preferences wizard persistence.
5
2
 
6
3
  import test from "node:test";
7
4
  import assert from "node:assert/strict";
8
- import { readFileSync } from "node:fs";
5
+ import { mkdtempSync, readFileSync, rmSync } from "node:fs";
6
+ import { join } from "node:path";
7
+ import { tmpdir } from "node:os";
9
8
 
9
+ import { buildCategorySummaries, handlePrefsWizard } from "../commands-prefs-wizard.ts";
10
10
  import { KNOWN_PREFERENCE_KEYS } from "../preferences-types.ts";
11
11
 
12
- // Keys exposed via a dedicated command rather than the wizard. They're still
13
- // reachable by the user, just not inside the category menu flow. If you add a
14
- // new key here, add a comment explaining where it lives.
15
- const EXPOSED_OUTSIDE_WIZARD = new Set<string>([
16
- "version", // auto-managed by writePreferencesFile
17
- "modelOverrides", // advanced routing — edit PREFERENCES.md directly (not in KNOWN_PREFERENCE_KEYS)
18
- "context_mode", // advanced sandbox config (gsd_exec + compaction) — enabled by default; edit PREFERENCES.md directly to tune timeouts/caps. Wizard coverage tracked separately.
19
- "planning_depth", // exposed through /gsd new-project --deep and /gsd new-milestone --deep
20
- ]);
12
+ const PREF_SAMPLE_VALUES: Record<string, unknown> = {
13
+ version: 1,
14
+ mode: "team",
15
+ always_use_skills: ["debug-like-expert"],
16
+ prefer_skills: ["typescript-expert"],
17
+ avoid_skills: ["slow-skill"],
18
+ skill_rules: [{ when: "unit:execute-task", use: ["test-writer-fixer"] }],
19
+ custom_instructions: ["Keep changes focused."],
20
+ models: { execution: "openai/gpt-5" },
21
+ skill_discovery: "auto",
22
+ skill_staleness_days: 7,
23
+ auto_supervisor: { soft_timeout_minutes: 20, idle_timeout_minutes: 10, hard_timeout_minutes: 30 },
24
+ uat_dispatch: true,
25
+ unique_milestone_ids: true,
26
+ budget_ceiling: 12.5,
27
+ budget_enforcement: "warn",
28
+ context_pause_threshold: 0.8,
29
+ notifications: {
30
+ enabled: true,
31
+ on_complete: true,
32
+ on_error: true,
33
+ on_budget: true,
34
+ on_milestone: true,
35
+ on_attention: true,
36
+ },
37
+ cmux: { enabled: true },
38
+ remote_questions: { provider: "slack", channel: "C123" },
39
+ git: {
40
+ auto_push: false,
41
+ push_branches: true,
42
+ pre_merge_check: true,
43
+ merge_strategy: "squash",
44
+ isolation: "worktree",
45
+ main_branch: "main",
46
+ absorb_snapshot_commits: true,
47
+ },
48
+ post_unit_hooks: [{ command: "npm test" }],
49
+ pre_dispatch_hooks: [{ command: "npm run lint" }],
50
+ dynamic_routing: { enabled: true },
51
+ disabled_model_providers: ["slow-provider"],
52
+ uok: { enabled: true },
53
+ token_profile: "standard",
54
+ phases: { progressive_planning: true },
55
+ auto_visualize: true,
56
+ auto_report: true,
57
+ parallel: { enabled: true, max_workers: 2 },
58
+ verification_commands: ["npm test"],
59
+ verification_auto_fix: true,
60
+ verification_max_retries: 1,
61
+ search_provider: "web",
62
+ context_selection: "auto",
63
+ widget_mode: "small",
64
+ reactive_execution: { enabled: true },
65
+ gate_evaluation: { enabled: true },
66
+ github: { enabled: true },
67
+ service_tier: "default",
68
+ forensics_dedup: true,
69
+ show_token_cost: true,
70
+ min_request_interval_ms: 250,
71
+ stale_commit_threshold_minutes: 15,
72
+ context_management: { enabled: true },
73
+ experimental: { rtk: true },
74
+ codebase: { indexing: "auto" },
75
+ slice_parallel: { enabled: true, max_workers: 2 },
76
+ safety_harness: { enabled: true },
77
+ enhanced_verification: true,
78
+ enhanced_verification_pre: true,
79
+ enhanced_verification_post: true,
80
+ enhanced_verification_strict: false,
81
+ discuss_preparation: true,
82
+ discuss_web_research: true,
83
+ discuss_depth: "standard",
84
+ flat_rate_providers: ["openai"],
85
+ language: "en",
86
+ context_window_override: 128000,
87
+ context_mode: { enabled: true },
88
+ planning_depth: "deep",
89
+ };
21
90
 
22
- test("every KNOWN_PREFERENCE_KEYS entry is reachable from the wizard source", () => {
23
- const src = readFileSync(
24
- new URL("../commands-prefs-wizard.ts", import.meta.url),
25
- "utf-8",
26
- );
91
+ test("prefs wizard save path preserves every known preference key", async () => {
92
+ const missingSamples = [...KNOWN_PREFERENCE_KEYS].filter((key) => !(key in PREF_SAMPLE_VALUES));
93
+ assert.deepEqual(missingSamples, [], "test fixture must cover every known preference key");
94
+
95
+ const dir = mkdtempSync(join(tmpdir(), "gsd-prefs-wizard-"));
96
+ const prefsPath = join(dir, "PREFERENCES.md");
97
+ const choices = ["── Save & Exit ──"];
98
+ const ctx = {
99
+ ui: {
100
+ notify() {},
101
+ select: async () => choices.shift(),
102
+ },
103
+ waitForIdle: async () => {},
104
+ reload: async () => {},
105
+ } as any;
27
106
 
28
- const missing: string[] = [];
29
- for (const key of KNOWN_PREFERENCE_KEYS) {
30
- if (EXPOSED_OUTSIDE_WIZARD.has(key)) continue;
31
- // The key must appear somewhere in the wizard — either as a direct
32
- // prefs[...] / pref reference, or in the orderedKeys serialization list.
33
- // A plain substring match is enough because all prefs-wizard references
34
- // use the exact key name.
35
- if (!src.includes(`"${key}"`) && !src.includes(`.${key}`)) {
36
- missing.push(key);
37
- }
107
+ try {
108
+ await handlePrefsWizard(ctx, "project", PREF_SAMPLE_VALUES, { pathOverride: prefsPath });
109
+ const saved = readFileSync(prefsPath, "utf-8");
110
+ const missingPersisted = [...KNOWN_PREFERENCE_KEYS].filter((key) => !saved.includes(`${key}:`));
111
+ assert.deepEqual(missingPersisted, []);
112
+ } finally {
113
+ rmSync(dir, { recursive: true, force: true });
38
114
  }
115
+ });
39
116
 
117
+ test("category summaries expose the wizard menu surface for configured prefs", () => {
118
+ const summaries = buildCategorySummaries(PREF_SAMPLE_VALUES);
40
119
  assert.deepEqual(
41
- missing,
42
- [],
43
- `These preference keys are in KNOWN_PREFERENCE_KEYS but are not referenced anywhere in the /gsd prefs wizard — they cannot be configured through the UI. Either add wizard coverage or add them to EXPOSED_OUTSIDE_WIZARD with an explanatory comment:\n${missing.join("\n")}`,
120
+ Object.keys(summaries).sort(),
121
+ [
122
+ "advanced",
123
+ "budget",
124
+ "context",
125
+ "discuss",
126
+ "git",
127
+ "hooks",
128
+ "integrations",
129
+ "mode",
130
+ "models",
131
+ "notifications",
132
+ "parallelism",
133
+ "phases",
134
+ "skills",
135
+ "timeouts",
136
+ "uok",
137
+ "verification",
138
+ ],
44
139
  );
140
+ assert.match(summaries.models, /phase/);
141
+ assert.match(summaries.integrations, /remote: C123/);
142
+ assert.match(summaries.verification, /1 cmd/);
45
143
  });
@@ -8,46 +8,28 @@
8
8
  * Also verifies #3589 — nativeBranchExists validation for prefs.main_branch
9
9
  * in auto-worktree.ts to prevent merge failures with stale preferences.
10
10
  *
11
- * Structural verification test — reads source to confirm the guards exist.
11
+ * Behavior verification test — exercises the exported projectRoot helper
12
+ * without reading command source.
12
13
  */
13
14
 
14
- import { describe, test } from 'node:test';
15
+ import { describe, test, mock } from 'node:test';
15
16
  import assert from 'node:assert/strict';
16
- import { readFileSync } from 'node:fs';
17
- import { fileURLToPath } from 'node:url';
18
- import { dirname, join } from 'node:path';
19
-
20
- const __filename = fileURLToPath(import.meta.url);
21
- const __dirname = dirname(__filename);
22
-
23
- const contextSource = readFileSync(join(__dirname, '..', 'commands', 'context.ts'), 'utf-8');
24
- const worktreeSource = readFileSync(join(__dirname, '..', 'auto-worktree.ts'), 'utf-8');
17
+ import { GSDNoProjectError, projectRoot } from '../commands/context.ts';
25
18
 
26
19
  describe('projectRoot cwd crash guard (#3598)', () => {
27
- test('projectRoot wraps process.cwd() in try/catch', () => {
28
- assert.match(contextSource, /try\s*\{[\s\S]*?process\.cwd\(\)/,
29
- 'process.cwd() should be inside a try block');
30
- });
31
-
32
- test('catch block falls back to homedir()', () => {
33
- assert.match(contextSource, /catch[\s\S]*?homedir\(\)/,
34
- 'catch block should fall back to homedir()');
35
- });
36
-
37
- test('projectRoot function is exported', () => {
38
- assert.match(contextSource, /export function projectRoot\(\)/,
39
- 'projectRoot should be an exported function');
40
- });
41
- });
42
-
43
- describe('main_branch nativeBranchExists validation (#3589)', () => {
44
- test('prefs.main_branch is validated with nativeBranchExists', () => {
45
- assert.match(worktreeSource, /nativeBranchExists\(.*prefs\.main_branch\)/,
46
- 'nativeBranchExists should validate prefs.main_branch');
47
- });
48
-
49
- test('validatedPrefBranch falls back to undefined when branch missing', () => {
50
- assert.match(worktreeSource, /validatedPrefBranch[\s\S]*?:\s*undefined/,
51
- 'validatedPrefBranch should fall back to undefined');
20
+ test('reports the home-directory guard instead of leaking cwd ENOENT', () => {
21
+ const cwd = mock.method(process, 'cwd', () => {
22
+ const err = new Error('ENOENT: current working directory was removed') as NodeJS.ErrnoException;
23
+ err.code = 'ENOENT';
24
+ throw err;
25
+ });
26
+ try {
27
+ assert.throws(
28
+ () => projectRoot(),
29
+ (err) => err instanceof GSDNoProjectError && !String(err.message).includes('ENOENT'),
30
+ );
31
+ } finally {
32
+ cwd.mock.restore();
33
+ }
52
34
  });
53
35
  });
@@ -13,80 +13,42 @@
13
13
 
14
14
  import { describe, it } from 'node:test'
15
15
  import assert from 'node:assert/strict'
16
- import { readFileSync } from 'node:fs'
17
- import { resolve } from 'node:path'
18
-
19
- // Use process.cwd() based resolution instead of import.meta.url
20
- // to avoid tsx test runner path resolution issues
21
- const src = readFileSync(
22
- resolve(process.cwd(), 'src', 'resources', 'extensions', 'gsd', 'workflow-projections.ts'),
23
- 'utf-8',
24
- )
16
+ import { mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs'
17
+ import { join } from 'node:path'
18
+ import { tmpdir } from 'node:os'
19
+ import { closeDatabase, insertMilestone, insertSlice, openDatabase } from '../gsd-db.ts'
20
+ import { renderAllProjections } from '../workflow-projections.ts'
25
21
 
26
22
  describe('renderAllProjections must not overwrite PLAN.md (#3651)', () => {
27
- it('renderAllProjections function body does NOT invoke renderPlanProjection', () => {
28
- // Extract the renderAllProjections function body
29
- const fnStart = src.indexOf('export async function renderAllProjections(')
30
- assert.ok(fnStart !== -1, 'renderAllProjections function must exist')
31
-
32
- // Find the for-loop over sliceRows inside renderAllProjections
33
- const loopStart = src.indexOf('for (const slice of sliceRows)', fnStart)
34
- assert.ok(loopStart !== -1, 'slice loop must exist in renderAllProjections')
35
-
36
- // Find the closing of renderAllProjections (next section marker)
37
- const fnEnd = src.indexOf('\n// ─── ', fnStart + 1)
38
- assert.ok(fnEnd !== -1, 'section delimiter after renderAllProjections must exist')
39
-
40
- const fnBody = src.slice(loopStart, fnEnd)
41
-
42
- // The fix: renderPlanProjection must NOT appear as a function call.
43
- // Strip comment lines before checking (comments may mention the function name).
44
- const codeOnly = fnBody
45
- .split('\n')
46
- .filter(line => !line.trim().startsWith('//'))
47
- .join('\n')
48
-
49
- const hasPlanCall = /renderPlanProjection\s*\(/.test(codeOnly)
50
- assert.equal(
51
- hasPlanCall,
52
- false,
53
- 'renderPlanProjection must not be called inside the renderAllProjections slice loop — ' +
54
- 'authoritative PLAN.md is rendered only by plan-slice/replan-slice tools',
55
- )
56
- })
57
-
58
- it('renderPlanProjection is still defined (available for regenerateIfMissing)', () => {
59
- assert.ok(
60
- src.includes('function renderPlanProjection('),
61
- 'renderPlanProjection function definition must still exist for on-demand recovery',
62
- )
63
- })
64
-
65
- it('renderAllProjections still renders ROADMAP, SUMMARY, and STATE projections', () => {
66
- const fnStart = src.indexOf('export async function renderAllProjections(')
67
- const fnEnd = src.indexOf('\n// ─── ', fnStart + 1)
68
- const fnBody = src.slice(fnStart, fnEnd)
69
-
70
- // #4402: ROADMAP.md is now rendered by the authoritative renderer
71
- // (renderRoadmapFromDb) to preserve ## Boundary Map and other sections
72
- // that the reduced renderRoadmapProjection would strip.
73
- assert.ok(
74
- fnBody.includes('renderRoadmapFromDb('),
75
- 'renderRoadmapFromDb must be called (authoritative roadmap renderer)',
76
- )
77
- assert.ok(
78
- !/renderRoadmapProjection\s*\(/.test(
79
- fnBody.split('\n').filter(l => !l.trim().startsWith('//')).join('\n'),
80
- ),
81
- 'renderRoadmapProjection must NOT be called — it clobbers Boundary Map (#4402)',
82
- )
83
- assert.ok(
84
- fnBody.includes('renderSummaryProjection('),
85
- 'renderSummaryProjection must still be called',
86
- )
87
- assert.ok(
88
- fnBody.includes('renderStateProjection('),
89
- 'renderStateProjection must still be called',
90
- )
23
+ it('preserves authoritative PLAN.md while rendering other projections', async () => {
24
+ const base = mkdtempSync(join(tmpdir(), 'gsd-projection-plan-'))
25
+ const msDir = join(base, '.gsd', 'milestones', 'M001')
26
+ const sliceDir = join(msDir, 'slices', 'S01')
27
+ const planPath = join(sliceDir, 'S01-PLAN.md')
28
+ const planContent = [
29
+ '# S01 Plan',
30
+ '',
31
+ '## Must-Haves',
32
+ '',
33
+ '- preserve this authoritative section',
34
+ '',
35
+ ].join('\n')
36
+
37
+ try {
38
+ mkdirSync(sliceDir, { recursive: true })
39
+ writeFileSync(join(msDir, 'M001-ROADMAP.md'), '# Roadmap\n\n## Slices\n\n- [ ] **S01: Slice** `risk:low` `depends:[]`\n')
40
+ writeFileSync(planPath, planContent)
41
+ openDatabase(join(base, '.gsd', 'gsd.db'))
42
+ insertMilestone({ id: 'M001', title: 'Milestone', status: 'active' })
43
+ insertSlice({ id: 'S01', milestoneId: 'M001', title: 'Slice', status: 'pending' })
44
+
45
+ await renderAllProjections(base, 'M001')
46
+
47
+ assert.equal(readFileSync(planPath, 'utf-8'), planContent)
48
+ assert.ok(readFileSync(join(base, '.gsd', 'STATE.md'), 'utf-8').includes('M001'))
49
+ } finally {
50
+ closeDatabase()
51
+ rmSync(base, { recursive: true, force: true })
52
+ }
91
53
  })
92
54
  })
@@ -7,12 +7,12 @@
7
7
 
8
8
  import { describe, it, beforeEach, afterEach } from "node:test";
9
9
  import assert from "node:assert/strict";
10
- import { mkdtempSync, mkdirSync, rmSync, writeFileSync, readFileSync } from "node:fs";
10
+ import { mkdtempSync, mkdirSync, rmSync, writeFileSync } from "node:fs";
11
11
  import { join, dirname } from "node:path";
12
12
  import { tmpdir } from "node:os";
13
13
  import { fileURLToPath } from "node:url";
14
14
 
15
- import { inlineDependencySummaries } from "../auto-prompts.js";
15
+ import { buildExecuteTaskPrompt, buildPlanSlicePrompt, inlineDependencySummaries } from "../auto-prompts.js";
16
16
  import { computeBudgets, truncateAtSectionBoundary } from "../context-budget.js";
17
17
 
18
18
  const __dirname = dirname(fileURLToPath(import.meta.url));
@@ -191,13 +191,18 @@ describe("prompt-budget: inlineDependencySummaries truncation", () => {
191
191
  // ─── plan-slice template includes executor constraints placeholder ────────────
192
192
 
193
193
  describe("prompt-budget: plan-slice template", () => {
194
- it("contains {{executorContextConstraints}} placeholder", () => {
195
- const templatePath = join(__dirname, "..", "prompts", "plan-slice.md");
196
- const template = readFileSync(templatePath, "utf-8");
197
- assert.ok(
198
- template.includes("{{executorContextConstraints}}"),
199
- "plan-slice.md should contain {{executorContextConstraints}} placeholder",
200
- );
194
+ it("rendered plan-slice prompt includes executor context constraints", async () => {
195
+ const base = createFixtureBase();
196
+ try {
197
+ setupDependencyFixture(base, "M001", "S01", ["S00"], { S00: "### Results\n\nDone." });
198
+ const prompt = await buildPlanSlicePrompt("M001", "Milestone", "S01", "Current slice", base, "minimal", {
199
+ sessionContextWindow: 128_000,
200
+ });
201
+ assert.match(prompt, /Executor Context Constraints/);
202
+ assert.match(prompt, /128K token/);
203
+ } finally {
204
+ cleanup(base);
205
+ }
201
206
  });
202
207
  });
203
208
 
@@ -323,13 +328,25 @@ describe("prompt-budget: different context windows produce different outputs", (
323
328
  // ─── execute-task template includes verificationBudget placeholder ─────────
324
329
 
325
330
  describe("prompt-budget: execute-task template", () => {
326
- it("contains {{verificationBudget}} placeholder", () => {
327
- const templatePath = join(__dirname, "..", "prompts", "execute-task.md");
328
- const template = readFileSync(templatePath, "utf-8");
329
- assert.ok(
330
- template.includes("{{verificationBudget}}"),
331
- "execute-task.md should contain {{verificationBudget}} placeholder",
332
- );
331
+ it("rendered execute-task prompt includes verification budget", async () => {
332
+ const base = createFixtureBase();
333
+ try {
334
+ const sliceDir = join(base, ".gsd", "milestones", "M001", "slices", "S01");
335
+ const taskDir = join(sliceDir, "tasks");
336
+ mkdirSync(taskDir, { recursive: true });
337
+ writeFileSync(join(base, ".gsd", "milestones", "M001", "M001-ROADMAP.md"), "# Roadmap\n");
338
+ writeFileSync(join(sliceDir, "S01-PLAN.md"), "# Slice Plan\n");
339
+ writeFileSync(join(taskDir, "T01-PLAN.md"), "# Task Plan\n");
340
+
341
+ const prompt = await buildExecuteTaskPrompt("M001", "S01", "Slice", "T01", "Task", base, {
342
+ level: "minimal",
343
+ sessionContextWindow: 128_000,
344
+ });
345
+ assert.match(prompt, /verification/i);
346
+ assert.match(prompt, /~51K chars/);
347
+ } finally {
348
+ cleanup(base);
349
+ }
333
350
  });
334
351
 
335
352
  it("verificationBudget format varies with context window size", () => {
@@ -486,130 +503,51 @@ describe("prompt-budget: execute-task builder truncation pattern", () => {
486
503
  });
487
504
 
488
505
  // ─── Regression: prompt builders must thread modelRegistry + sessionContextWindow (issue #4142) ───
489
- //
490
- // `resolveExecutorContextWindow()` resolves the executor context window in 3
491
- // steps: (1) look up the configured executor model in `modelRegistry`, (2) fall
492
- // back to `sessionContextWindow`, (3) fall back to `DEFAULT_CONTEXT_WINDOW`
493
- // (200K). Before this fix, prompt-builder call sites passed `undefined` for
494
- // both knobs and always landed on Step 3 — even on 1M-token models. These
495
- // source-level assertions pin the wiring so future refactors cannot regress it.
496
-
497
- describe("prompt-budget: modelRegistry + sessionContextWindow wiring", () => {
498
- const autoPromptsSrc = readFileSync(join(__dirname, "..", "auto-prompts.ts"), "utf-8");
499
- const autoDispatchSrc = readFileSync(join(__dirname, "..", "auto-dispatch.ts"), "utf-8");
500
- const autoDirectDispatchSrc = readFileSync(join(__dirname, "..", "auto-direct-dispatch.ts"), "utf-8");
501
- const phasesSrc = readFileSync(join(__dirname, "..", "auto", "phases.ts"), "utf-8");
502
-
503
- it("formatExecutorConstraints accepts and forwards both knobs", () => {
504
- assert.match(
505
- autoPromptsSrc,
506
- /function formatExecutorConstraints\([^)]*sessionContextWindow[^)]*modelRegistry[^)]*\)/s,
507
- "formatExecutorConstraints must accept sessionContextWindow and modelRegistry",
508
- );
509
- assert.match(
510
- autoPromptsSrc,
511
- /resolveExecutorContextWindow\(\s*modelRegistry\s*,\s*prefs\?\.preferences\s*,\s*sessionContextWindow/,
512
- "formatExecutorConstraints must forward both to resolveExecutorContextWindow",
513
- );
514
- });
515
-
516
- it("renderSlicePrompt options declare both knobs and forward to formatExecutorConstraints", () => {
517
- assert.match(
518
- autoPromptsSrc,
519
- /async function renderSlicePrompt\(options:\s*\{[^}]*sessionContextWindow\?[^}]*modelRegistry\?/s,
520
- "renderSlicePrompt options must declare both fields",
521
- );
522
- assert.match(
523
- autoPromptsSrc,
524
- /formatExecutorConstraints\(sessionContextWindow,\s*modelRegistry(?:,\s*sessionProvider)?\)/,
525
- "renderSlicePrompt must forward both to formatExecutorConstraints",
526
- );
527
- });
528
-
529
- it("buildPlanSlicePrompt options declare both knobs and thread them into renderSlicePrompt", () => {
530
- assert.match(
531
- autoPromptsSrc,
532
- /export async function buildPlanSlicePrompt\([\s\S]*?options\?:\s*\{[^}]*sessionContextWindow\?[^}]*modelRegistry\?/,
533
- "buildPlanSlicePrompt options must declare both fields",
534
- );
535
- assert.match(
536
- autoPromptsSrc,
537
- /sessionContextWindow:\s*options\?\.sessionContextWindow,\s*modelRegistry:\s*options\?\.modelRegistry/,
538
- "buildPlanSlicePrompt must forward both into renderSlicePrompt",
539
- );
540
- });
541
506
 
542
- it("ExecuteTaskPromptOptions declares both knobs", () => {
543
- assert.match(
544
- autoPromptsSrc,
545
- /interface ExecuteTaskPromptOptions\s*\{[^}]*sessionContextWindow\?[^}]*modelRegistry\?/s,
546
- "ExecuteTaskPromptOptions must declare both fields",
547
- );
548
- });
549
-
550
- it("buildExecuteTaskPrompt forwards opts.modelRegistry + opts.sessionContextWindow to resolveExecutorContextWindow", () => {
551
- assert.match(
552
- autoPromptsSrc,
553
- /resolveExecutorContextWindow\(\s*opts\.modelRegistry\s*,\s*prefs\?\.preferences\s*,\s*opts\.sessionContextWindow/,
554
- "buildExecuteTaskPrompt must forward both into resolveExecutorContextWindow",
555
- );
556
- });
557
-
558
- it("buildReactiveExecutePrompt accepts opts and forwards to embedded buildExecuteTaskPrompt", () => {
559
- assert.match(
560
- autoPromptsSrc,
561
- /export async function buildReactiveExecutePrompt\([\s\S]*?opts\?:\s*\{[^}]*sessionContextWindow\?[^}]*modelRegistry\?/,
562
- "buildReactiveExecutePrompt must accept sessionContextWindow + modelRegistry",
563
- );
564
- assert.match(
565
- autoPromptsSrc,
566
- /sessionContextWindow:\s*opts\?\.sessionContextWindow,\s*modelRegistry:\s*opts\?\.modelRegistry/,
567
- "buildReactiveExecutePrompt must forward both into the embedded buildExecuteTaskPrompt call",
568
- );
569
- });
570
-
571
- it("DispatchContext declares both knobs", () => {
572
- assert.match(
573
- autoDispatchSrc,
574
- /interface DispatchContext\s*\{[^}]*sessionContextWindow\?[^}]*modelRegistry\?/s,
575
- "DispatchContext must declare both fields so dispatch rules can thread them",
576
- );
577
- });
578
-
579
- it("DISPATCH_RULES destructure and forward both knobs at every prompt-builder call site", () => {
580
- // Every plan-slice / execute-task / reactive-execute rule must destructure
581
- // both names from its match context so new call sites can't silently drop them.
582
- const matchLines = autoDispatchSrc.match(/match:\s*async\s*\(\{[^}]*sessionContextWindow[^}]*modelRegistry[^}]*\}/g) ?? [];
583
- assert.ok(
584
- matchLines.length >= 5,
585
- `expected ≥5 dispatch rules destructuring both knobs, got ${matchLines.length}`,
586
- );
587
-
588
- const forwardCount = (autoDispatchSrc.match(/sessionContextWindow,\s*modelRegistry/g) ?? []).length;
589
- assert.ok(
590
- forwardCount >= 5,
591
- `expected ≥5 forward sites of { sessionContextWindow, modelRegistry }, got ${forwardCount}`,
592
- );
593
- });
594
-
595
- it("runDispatch populates both knobs from ctx.model / ctx.modelRegistry", () => {
596
- assert.match(
597
- phasesSrc,
598
- /sessionContextWindow:\s*ctx\.model\?\.contextWindow/,
599
- "runDispatch must populate sessionContextWindow from ctx.model?.contextWindow",
600
- );
601
- assert.match(
602
- phasesSrc,
603
- /modelRegistry:\s*ctx\.modelRegistry/,
604
- "runDispatch must populate modelRegistry from ctx.modelRegistry",
605
- );
507
+ describe("prompt-budget: modelRegistry + sessionContextWindow behavior", () => {
508
+ it("buildPlanSlicePrompt output changes when sessionContextWindow changes", async () => {
509
+ const base = createFixtureBase();
510
+ try {
511
+ setupDependencyFixture(base, "M001", "S01", ["S00"], { S00: "### Results\n\nDone." });
512
+ const small = await buildPlanSlicePrompt("M001", "Milestone", "S01", "Current slice", base, "minimal", {
513
+ sessionContextWindow: 128_000,
514
+ });
515
+ const large = await buildPlanSlicePrompt("M001", "Milestone", "S01", "Current slice", base, "minimal", {
516
+ sessionContextWindow: 1_000_000,
517
+ });
518
+
519
+ assert.match(small, /128K token/);
520
+ assert.match(large, /1000K token/);
521
+ assert.notEqual(small, large);
522
+ } finally {
523
+ cleanup(base);
524
+ }
606
525
  });
607
526
 
608
- it("dispatchDirectPhase forwards both knobs to buildPlanSlicePrompt and buildExecuteTaskPrompt", () => {
609
- const passes = (autoDirectDispatchSrc.match(/sessionContextWindow:\s*ctx\.model\?\.contextWindow[\s\S]*?modelRegistry:\s*ctx\.modelRegistry/g) ?? []).length;
610
- assert.ok(
611
- passes >= 2,
612
- `dispatchDirectPhase must forward the pair at both prompt-builder call sites (≥2), got ${passes}`,
613
- );
527
+ it("buildExecuteTaskPrompt output changes when sessionContextWindow changes", async () => {
528
+ const base = createFixtureBase();
529
+ try {
530
+ const sliceDir = join(base, ".gsd", "milestones", "M001", "slices", "S01");
531
+ const taskDir = join(sliceDir, "tasks");
532
+ mkdirSync(taskDir, { recursive: true });
533
+ writeFileSync(join(base, ".gsd", "milestones", "M001", "M001-ROADMAP.md"), "# Roadmap\n");
534
+ writeFileSync(join(sliceDir, "S01-PLAN.md"), "# Slice Plan\n");
535
+ writeFileSync(join(taskDir, "T01-PLAN.md"), "# Task Plan\n");
536
+
537
+ const small = await buildExecuteTaskPrompt("M001", "S01", "Slice", "T01", "Task", base, {
538
+ level: "minimal",
539
+ sessionContextWindow: 128_000,
540
+ });
541
+ const large = await buildExecuteTaskPrompt("M001", "S01", "Slice", "T01", "Task", base, {
542
+ level: "minimal",
543
+ sessionContextWindow: 1_000_000,
544
+ });
545
+
546
+ assert.match(small, /~51K chars/);
547
+ assert.match(large, /~400K chars/);
548
+ assert.notEqual(small, large);
549
+ } finally {
550
+ cleanup(base);
551
+ }
614
552
  });
615
553
  });