@opengsd/gsd-pi 1.1.1-dev.a5a2de8 → 1.1.1-dev.b2556262

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 (325) hide show
  1. package/dist/headless-recover.js +56 -1
  2. package/dist/resources/.managed-resources-content-hash +1 -1
  3. package/dist/resources/extensions/browser-tools/engine/managed-gsd-browser.js +18 -2
  4. package/dist/resources/extensions/browser-tools/engine/selection.js +1 -1
  5. package/dist/resources/extensions/browser-tools/extension-manifest.json +1 -1
  6. package/dist/resources/extensions/browser-tools/index.js +68 -24
  7. package/dist/resources/extensions/browser-tools/state.js +12 -0
  8. package/dist/resources/extensions/browser-tools/tools/session.js +3 -2
  9. package/dist/resources/extensions/browser-tools/utils.js +3 -3
  10. package/dist/resources/extensions/browser-tools/web-app-detect.js +52 -0
  11. package/dist/resources/extensions/gsd/auto/loop.js +4 -2
  12. package/dist/resources/extensions/gsd/auto/phases.js +87 -12
  13. package/dist/resources/extensions/gsd/auto/session.js +22 -1
  14. package/dist/resources/extensions/gsd/auto/workflow-kernel.js +1 -0
  15. package/dist/resources/extensions/gsd/auto-dispatch.js +81 -13
  16. package/dist/resources/extensions/gsd/auto-model-selection.js +154 -9
  17. package/dist/resources/extensions/gsd/auto-post-unit.js +19 -2
  18. package/dist/resources/extensions/gsd/auto-prompts.js +26 -21
  19. package/dist/resources/extensions/gsd/auto-recovery.js +4 -2
  20. package/dist/resources/extensions/gsd/auto-runtime-state.js +3 -0
  21. package/dist/resources/extensions/gsd/auto-start.js +1 -1
  22. package/dist/resources/extensions/gsd/auto-timers.js +24 -10
  23. package/dist/resources/extensions/gsd/auto.js +40 -15
  24. package/dist/resources/extensions/gsd/bootstrap/db-tools.js +3 -3
  25. package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +192 -77
  26. package/dist/resources/extensions/gsd/bootstrap/system-context.js +1 -1
  27. package/dist/resources/extensions/gsd/closeout-wizard.js +32 -9
  28. package/dist/resources/extensions/gsd/commands/handlers/auto.js +10 -0
  29. package/dist/resources/extensions/gsd/commands/handlers/ops.js +2 -9
  30. package/dist/resources/extensions/gsd/commands-maintenance.js +93 -15
  31. package/dist/resources/extensions/gsd/commands-mcp-status.js +1 -1
  32. package/dist/resources/extensions/gsd/commands-prefs-wizard.js +2 -2
  33. package/dist/resources/extensions/gsd/config-overlay.js +1 -0
  34. package/dist/resources/extensions/gsd/context-masker.js +129 -5
  35. package/dist/resources/extensions/gsd/db-writer.js +35 -0
  36. package/dist/resources/extensions/gsd/docs/preferences-reference.md +50 -1
  37. package/dist/resources/extensions/gsd/gsd-db.js +480 -172
  38. package/dist/resources/extensions/gsd/guided-flow.js +4 -1
  39. package/dist/resources/extensions/gsd/markdown-renderer.js +37 -53
  40. package/dist/resources/extensions/gsd/md-importer.js +38 -3
  41. package/dist/resources/extensions/gsd/migration-auto-check.js +126 -31
  42. package/dist/resources/extensions/gsd/parsers-legacy.js +23 -0
  43. package/dist/resources/extensions/gsd/planner-handoff.js +98 -0
  44. package/dist/resources/extensions/gsd/planning-path-scope.js +22 -4
  45. package/dist/resources/extensions/gsd/pre-execution-checks.js +10 -2
  46. package/dist/resources/extensions/gsd/preferences-models.js +111 -43
  47. package/dist/resources/extensions/gsd/preferences-types.js +13 -0
  48. package/dist/resources/extensions/gsd/preferences-validation.js +68 -3
  49. package/dist/resources/extensions/gsd/preferences.js +4 -1
  50. package/dist/resources/extensions/gsd/prompts/gate-evaluate.md +1 -1
  51. package/dist/resources/extensions/gsd/prompts/plan-milestone.md +1 -1
  52. package/dist/resources/extensions/gsd/prompts/plan-slice.md +1 -1
  53. package/dist/resources/extensions/gsd/prompts/refine-slice.md +1 -1
  54. package/dist/resources/extensions/gsd/prompts/run-uat.md +2 -2
  55. package/dist/resources/extensions/gsd/prompts/system.md +1 -1
  56. package/dist/resources/extensions/gsd/roadmap-slices.js +5 -1
  57. package/dist/resources/extensions/gsd/safety/content-validator.js +6 -4
  58. package/dist/resources/extensions/gsd/skill-manifest.js +12 -0
  59. package/dist/resources/extensions/gsd/source-observations.js +306 -0
  60. package/dist/resources/extensions/gsd/state-reconciliation/drift/completion.js +15 -8
  61. package/dist/resources/extensions/gsd/state-reconciliation/drift/stale-render.js +33 -5
  62. package/dist/resources/extensions/gsd/state-reconciliation/drift/stale-worker.js +34 -13
  63. package/dist/resources/extensions/gsd/state-reconciliation/index.js +39 -14
  64. package/dist/resources/extensions/gsd/state-reconciliation/spawn-gate.js +4 -4
  65. package/dist/resources/extensions/gsd/state.js +7 -3
  66. package/dist/resources/extensions/gsd/tool-contract.js +15 -1
  67. package/dist/resources/extensions/gsd/tool-presentation-plan.js +24 -2
  68. package/dist/resources/extensions/gsd/tools/complete-slice.js +28 -0
  69. package/dist/resources/extensions/gsd/tools/plan-slice.js +42 -11
  70. package/dist/resources/extensions/gsd/tools/plan-task.js +7 -1
  71. package/dist/resources/extensions/gsd/tools/workflow-tool-executors.js +62 -406
  72. package/dist/resources/extensions/gsd/uat-policy.js +130 -0
  73. package/dist/resources/extensions/gsd/uat-run.js +414 -0
  74. package/dist/resources/extensions/gsd/unit-context-manifest.js +3 -4
  75. package/dist/resources/extensions/gsd/unit-tool-contracts.js +38 -14
  76. package/dist/resources/extensions/gsd/verdict-parser.js +3 -8
  77. package/dist/resources/extensions/gsd/workflow-manifest.js +132 -5
  78. package/dist/resources/extensions/gsd/workflow-mcp.js +2 -3
  79. package/dist/resources/extensions/gsd/workflow-projections.js +8 -0
  80. package/dist/resources/extensions/gsd/worktree-manager.js +26 -0
  81. package/dist/resources/extensions/gsd/worktree-reentry.js +96 -0
  82. package/dist/resources/extensions/gsd/worktree-state-projection.js +18 -17
  83. package/dist/resources/extensions/shared/gsd-browser-cli.js +6 -0
  84. package/dist/resources/extensions/subagent/agents.js +1 -0
  85. package/dist/resources/extensions/subagent/index.js +27 -12
  86. package/dist/resources/extensions/subagent/launch.js +7 -2
  87. package/dist/web/standalone/.next/BUILD_ID +1 -1
  88. package/dist/web/standalone/.next/app-path-routes-manifest.json +6 -6
  89. package/dist/web/standalone/.next/build-manifest.json +2 -2
  90. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  91. package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
  92. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  93. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  94. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  95. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  96. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  97. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  98. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  99. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  100. package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
  101. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
  102. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  103. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
  104. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  105. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  106. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  107. package/dist/web/standalone/.next/server/app/index.html +1 -1
  108. package/dist/web/standalone/.next/server/app/index.rsc +1 -1
  109. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
  110. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +1 -1
  111. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  112. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
  113. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  114. package/dist/web/standalone/.next/server/app-paths-manifest.json +6 -6
  115. package/dist/web/standalone/.next/server/chunks/8357.js +1 -1
  116. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  117. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  118. package/dist/web/standalone/.next/server/pages/500.html +1 -1
  119. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  120. package/dist/web/standalone/node_modules/@gsd/native/dist/native.js +22 -0
  121. package/dist/web/standalone/node_modules/node-pty/build/Makefile +1 -1
  122. package/package.json +4 -4
  123. package/packages/cloud-mcp-gateway/package.json +2 -2
  124. package/packages/contracts/package.json +1 -1
  125. package/packages/daemon/package.json +4 -4
  126. package/packages/gsd-agent-core/package.json +5 -5
  127. package/packages/gsd-agent-modes/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
  128. package/packages/gsd-agent-modes/dist/modes/interactive/components/assistant-message.js +21 -23
  129. package/packages/gsd-agent-modes/dist/modes/interactive/components/assistant-message.js.map +1 -1
  130. package/packages/gsd-agent-modes/dist/modes/interactive/components/tool-execution.d.ts +3 -0
  131. package/packages/gsd-agent-modes/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  132. package/packages/gsd-agent-modes/dist/modes/interactive/components/tool-execution.js +25 -0
  133. package/packages/gsd-agent-modes/dist/modes/interactive/components/tool-execution.js.map +1 -1
  134. package/packages/gsd-agent-modes/dist/modes/interactive/components/transcript-design.d.ts +1 -0
  135. package/packages/gsd-agent-modes/dist/modes/interactive/components/transcript-design.d.ts.map +1 -1
  136. package/packages/gsd-agent-modes/dist/modes/interactive/components/transcript-design.js +66 -12
  137. package/packages/gsd-agent-modes/dist/modes/interactive/components/transcript-design.js.map +1 -1
  138. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.d.ts.map +1 -1
  139. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.js +18 -11
  140. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.js.map +1 -1
  141. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-chat-render.d.ts.map +1 -1
  142. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-chat-render.js +16 -0
  143. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-chat-render.js.map +1 -1
  144. package/packages/gsd-agent-modes/package.json +7 -7
  145. package/packages/mcp-server/dist/workflow-tools.js +1 -1
  146. package/packages/mcp-server/dist/workflow-tools.js.map +1 -1
  147. package/packages/mcp-server/package.json +3 -3
  148. package/packages/native/dist/native.js +22 -0
  149. package/packages/native/package.json +1 -1
  150. package/packages/pi-agent-core/package.json +1 -1
  151. package/packages/pi-ai/dist/image-models.generated.d.ts +30 -0
  152. package/packages/pi-ai/dist/image-models.generated.d.ts.map +1 -1
  153. package/packages/pi-ai/dist/image-models.generated.js +30 -0
  154. package/packages/pi-ai/dist/image-models.generated.js.map +1 -1
  155. package/packages/pi-ai/dist/models.generated.d.ts +174 -29
  156. package/packages/pi-ai/dist/models.generated.d.ts.map +1 -1
  157. package/packages/pi-ai/dist/models.generated.js +178 -54
  158. package/packages/pi-ai/dist/models.generated.js.map +1 -1
  159. package/packages/pi-ai/dist/providers/transform-messages.d.ts.map +1 -1
  160. package/packages/pi-ai/dist/providers/transform-messages.js +8 -1
  161. package/packages/pi-ai/dist/providers/transform-messages.js.map +1 -1
  162. package/packages/pi-ai/package.json +1 -1
  163. package/packages/pi-coding-agent/dist/core/settings-manager.js +1 -1
  164. package/packages/pi-coding-agent/dist/core/settings-manager.js.map +1 -1
  165. package/packages/pi-coding-agent/dist/theme/themes.js +1 -1
  166. package/packages/pi-coding-agent/dist/theme/themes.js.map +1 -1
  167. package/packages/pi-coding-agent/package.json +7 -7
  168. package/packages/pi-tui/dist/utils.d.ts +11 -0
  169. package/packages/pi-tui/dist/utils.d.ts.map +1 -1
  170. package/packages/pi-tui/dist/utils.js +119 -6
  171. package/packages/pi-tui/dist/utils.js.map +1 -1
  172. package/packages/pi-tui/package.json +2 -1
  173. package/packages/rpc-client/package.json +2 -2
  174. package/pkg/dist/theme/themes.js +1 -1
  175. package/pkg/dist/theme/themes.js.map +1 -1
  176. package/pkg/package.json +1 -1
  177. package/scripts/install/handoff.js +16 -3
  178. package/src/resources/extensions/browser-tools/engine/managed-gsd-browser.ts +21 -2
  179. package/src/resources/extensions/browser-tools/engine/selection.ts +1 -1
  180. package/src/resources/extensions/browser-tools/extension-manifest.json +1 -1
  181. package/src/resources/extensions/browser-tools/index.ts +75 -27
  182. package/src/resources/extensions/browser-tools/state.ts +13 -0
  183. package/src/resources/extensions/browser-tools/tests/browser-engine-selection.test.mjs +2 -2
  184. package/src/resources/extensions/browser-tools/tests/browser-tools-unit.test.cjs +57 -0
  185. package/src/resources/extensions/browser-tools/tests/gsd-browser-launch-config.test.mjs +37 -0
  186. package/src/resources/extensions/browser-tools/tests/web-app-detect.test.mjs +68 -0
  187. package/src/resources/extensions/browser-tools/tools/session.ts +4 -2
  188. package/src/resources/extensions/browser-tools/utils.ts +3 -3
  189. package/src/resources/extensions/browser-tools/web-app-detect.ts +63 -0
  190. package/src/resources/extensions/gsd/auto/loop-deps.ts +1 -0
  191. package/src/resources/extensions/gsd/auto/loop.ts +4 -2
  192. package/src/resources/extensions/gsd/auto/phases.ts +89 -15
  193. package/src/resources/extensions/gsd/auto/session.ts +24 -1
  194. package/src/resources/extensions/gsd/auto/workflow-kernel.ts +1 -0
  195. package/src/resources/extensions/gsd/auto-dispatch.ts +117 -12
  196. package/src/resources/extensions/gsd/auto-model-selection.ts +190 -12
  197. package/src/resources/extensions/gsd/auto-post-unit.ts +20 -2
  198. package/src/resources/extensions/gsd/auto-prompts.ts +25 -22
  199. package/src/resources/extensions/gsd/auto-recovery.ts +22 -3
  200. package/src/resources/extensions/gsd/auto-runtime-state.ts +5 -0
  201. package/src/resources/extensions/gsd/auto-start.ts +1 -1
  202. package/src/resources/extensions/gsd/auto-timers.ts +25 -9
  203. package/src/resources/extensions/gsd/auto.ts +41 -14
  204. package/src/resources/extensions/gsd/bootstrap/db-tools.ts +3 -3
  205. package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +250 -78
  206. package/src/resources/extensions/gsd/bootstrap/system-context.ts +1 -1
  207. package/src/resources/extensions/gsd/closeout-wizard.ts +47 -13
  208. package/src/resources/extensions/gsd/commands/handlers/auto.ts +9 -0
  209. package/src/resources/extensions/gsd/commands/handlers/ops.ts +2 -17
  210. package/src/resources/extensions/gsd/commands-maintenance.ts +124 -13
  211. package/src/resources/extensions/gsd/commands-mcp-status.ts +1 -1
  212. package/src/resources/extensions/gsd/commands-prefs-wizard.ts +2 -2
  213. package/src/resources/extensions/gsd/config-overlay.ts +1 -0
  214. package/src/resources/extensions/gsd/context-masker.ts +152 -5
  215. package/src/resources/extensions/gsd/db-writer.ts +38 -0
  216. package/src/resources/extensions/gsd/docs/preferences-reference.md +50 -1
  217. package/src/resources/extensions/gsd/gsd-db.ts +564 -186
  218. package/src/resources/extensions/gsd/guided-flow.ts +4 -1
  219. package/src/resources/extensions/gsd/markdown-renderer.ts +44 -66
  220. package/src/resources/extensions/gsd/md-importer.ts +49 -2
  221. package/src/resources/extensions/gsd/migration-auto-check.ts +154 -34
  222. package/src/resources/extensions/gsd/parsers-legacy.ts +20 -0
  223. package/src/resources/extensions/gsd/planner-handoff.ts +149 -0
  224. package/src/resources/extensions/gsd/planning-path-scope.ts +22 -4
  225. package/src/resources/extensions/gsd/pre-execution-checks.ts +9 -2
  226. package/src/resources/extensions/gsd/preferences-models.ts +113 -43
  227. package/src/resources/extensions/gsd/preferences-types.ts +47 -0
  228. package/src/resources/extensions/gsd/preferences-validation.ts +76 -2
  229. package/src/resources/extensions/gsd/preferences.ts +5 -0
  230. package/src/resources/extensions/gsd/prompts/gate-evaluate.md +1 -1
  231. package/src/resources/extensions/gsd/prompts/plan-milestone.md +1 -1
  232. package/src/resources/extensions/gsd/prompts/plan-slice.md +1 -1
  233. package/src/resources/extensions/gsd/prompts/refine-slice.md +1 -1
  234. package/src/resources/extensions/gsd/prompts/run-uat.md +2 -2
  235. package/src/resources/extensions/gsd/prompts/system.md +1 -1
  236. package/src/resources/extensions/gsd/roadmap-slices.ts +6 -1
  237. package/src/resources/extensions/gsd/safety/content-validator.ts +8 -5
  238. package/src/resources/extensions/gsd/skill-manifest.ts +12 -0
  239. package/src/resources/extensions/gsd/source-observations.ts +402 -0
  240. package/src/resources/extensions/gsd/state-reconciliation/drift/completion.ts +20 -8
  241. package/src/resources/extensions/gsd/state-reconciliation/drift/stale-render.ts +44 -5
  242. package/src/resources/extensions/gsd/state-reconciliation/drift/stale-worker.ts +39 -11
  243. package/src/resources/extensions/gsd/state-reconciliation/index.ts +45 -15
  244. package/src/resources/extensions/gsd/state-reconciliation/spawn-gate.ts +4 -4
  245. package/src/resources/extensions/gsd/state.ts +7 -4
  246. package/src/resources/extensions/gsd/tests/auto-loop.test.ts +114 -0
  247. package/src/resources/extensions/gsd/tests/auto-model-selection-tool-poisoning.test.ts +66 -4
  248. package/src/resources/extensions/gsd/tests/auto-model-selection.test.ts +299 -1
  249. package/src/resources/extensions/gsd/tests/auto-paused-ui-cleanup.test.ts +32 -0
  250. package/src/resources/extensions/gsd/tests/auto-phases-lifecycle.test.ts +75 -3
  251. package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +22 -1
  252. package/src/resources/extensions/gsd/tests/auto-supervisor.test.mjs +4 -0
  253. package/src/resources/extensions/gsd/tests/before-provider-context-management.test.ts +145 -0
  254. package/src/resources/extensions/gsd/tests/bundled-skill-triggers.test.ts +9 -0
  255. package/src/resources/extensions/gsd/tests/closeout-wizard.test.ts +44 -0
  256. package/src/resources/extensions/gsd/tests/commands-dispatcher-unmerged-milestone.test.ts +26 -1
  257. package/src/resources/extensions/gsd/tests/complete-slice-verification-gate.test.ts +118 -0
  258. package/src/resources/extensions/gsd/tests/content-validator.test.ts +74 -0
  259. package/src/resources/extensions/gsd/tests/context-masker.test.ts +56 -1
  260. package/src/resources/extensions/gsd/tests/custom-engine-loop-integration.test.ts +17 -2
  261. package/src/resources/extensions/gsd/tests/dispatch-rule-coverage.test.ts +24 -0
  262. package/src/resources/extensions/gsd/tests/doctor-scope-db-unavailable.test.ts +1 -11
  263. package/src/resources/extensions/gsd/tests/gate-dispatch.test.ts +64 -0
  264. package/src/resources/extensions/gsd/tests/gate-storage.test.ts +15 -0
  265. package/src/resources/extensions/gsd/tests/gsd-recover.test.ts +62 -1
  266. package/src/resources/extensions/gsd/tests/integration/run-uat.test.ts +4 -1
  267. package/src/resources/extensions/gsd/tests/interrupted-session-auto.test.ts +27 -0
  268. package/src/resources/extensions/gsd/tests/journal-integration.test.ts +16 -0
  269. package/src/resources/extensions/gsd/tests/markdown-renderer.test.ts +42 -0
  270. package/src/resources/extensions/gsd/tests/mcp-project-config.test.ts +7 -1
  271. package/src/resources/extensions/gsd/tests/mcp-status.test.ts +1 -1
  272. package/src/resources/extensions/gsd/tests/migration-auto-check.test.ts +99 -0
  273. package/src/resources/extensions/gsd/tests/plan-slice.test.ts +99 -2
  274. package/src/resources/extensions/gsd/tests/plan-task.test.ts +19 -0
  275. package/src/resources/extensions/gsd/tests/planner-handoff.test.ts +100 -0
  276. package/src/resources/extensions/gsd/tests/preferences.test.ts +14 -0
  277. package/src/resources/extensions/gsd/tests/prefs-wizard-coverage.test.ts +1 -0
  278. package/src/resources/extensions/gsd/tests/prompt-contracts.test.ts +133 -0
  279. package/src/resources/extensions/gsd/tests/provider-switch-observer.test.ts +55 -0
  280. package/src/resources/extensions/gsd/tests/register-hooks-depth-verification.test.ts +101 -1
  281. package/src/resources/extensions/gsd/tests/repository-registry.test.ts +2 -2
  282. package/src/resources/extensions/gsd/tests/runtime-invariant-modules.test.ts +28 -0
  283. package/src/resources/extensions/gsd/tests/schema-v21-sequence.test.ts +5 -3
  284. package/src/resources/extensions/gsd/tests/schema-v27-v28-sequence.test.ts +162 -18
  285. package/src/resources/extensions/gsd/tests/skill-manifest.test.ts +4 -3
  286. package/src/resources/extensions/gsd/tests/skipped-validation-db-atomicity.test.ts +8 -0
  287. package/src/resources/extensions/gsd/tests/source-observations.test.ts +275 -0
  288. package/src/resources/extensions/gsd/tests/stale-queued-milestone.test.ts +43 -0
  289. package/src/resources/extensions/gsd/tests/state-reconciliation-drift.test.ts +76 -21
  290. package/src/resources/extensions/gsd/tests/thinking-level-resolution.test.ts +203 -0
  291. package/src/resources/extensions/gsd/tests/uat-policy.test.ts +170 -0
  292. package/src/resources/extensions/gsd/tests/unit-context-manifest.test.ts +7 -1
  293. package/src/resources/extensions/gsd/tests/workflow-kernel.test.ts +7 -0
  294. package/src/resources/extensions/gsd/tests/workflow-manifest.test.ts +306 -1
  295. package/src/resources/extensions/gsd/tests/workflow-mcp.test.ts +77 -10
  296. package/src/resources/extensions/gsd/tests/workflow-tool-executors.test.ts +260 -5
  297. package/src/resources/extensions/gsd/tests/worktree-db.test.ts +511 -1
  298. package/src/resources/extensions/gsd/tests/worktree-reentry.test.ts +102 -0
  299. package/src/resources/extensions/gsd/tests/worktree-state-projection.test.ts +44 -0
  300. package/src/resources/extensions/gsd/tool-contract.ts +29 -1
  301. package/src/resources/extensions/gsd/tool-presentation-plan.ts +41 -6
  302. package/src/resources/extensions/gsd/tools/complete-slice.ts +29 -0
  303. package/src/resources/extensions/gsd/tools/plan-slice.ts +54 -12
  304. package/src/resources/extensions/gsd/tools/plan-task.ts +8 -1
  305. package/src/resources/extensions/gsd/tools/workflow-tool-executors.ts +71 -489
  306. package/src/resources/extensions/gsd/types.ts +1 -0
  307. package/src/resources/extensions/gsd/uat-policy.ts +191 -0
  308. package/src/resources/extensions/gsd/uat-run.ts +550 -0
  309. package/src/resources/extensions/gsd/unit-context-manifest.ts +3 -4
  310. package/src/resources/extensions/gsd/unit-tool-contracts.ts +38 -14
  311. package/src/resources/extensions/gsd/verdict-parser.ts +3 -10
  312. package/src/resources/extensions/gsd/workflow-manifest.ts +193 -7
  313. package/src/resources/extensions/gsd/workflow-mcp.ts +2 -3
  314. package/src/resources/extensions/gsd/workflow-projections.ts +9 -0
  315. package/src/resources/extensions/gsd/worktree-manager.ts +32 -0
  316. package/src/resources/extensions/gsd/worktree-reentry.ts +103 -0
  317. package/src/resources/extensions/gsd/worktree-state-projection.ts +22 -22
  318. package/src/resources/extensions/shared/gsd-browser-cli.ts +6 -0
  319. package/src/resources/extensions/shared/tests/format-utils.test.ts +8 -3
  320. package/src/resources/extensions/subagent/agents.ts +4 -0
  321. package/src/resources/extensions/subagent/index.ts +28 -3
  322. package/src/resources/extensions/subagent/launch.ts +8 -0
  323. package/src/resources/extensions/subagent/tests/model-override.test.ts +31 -0
  324. /package/dist/web/standalone/.next/static/{9y3LeeR2uGr2yRj9RjY3D → tJOKQbQRO-9MiFDO8DIDS}/_buildManifest.js +0 -0
  325. /package/dist/web/standalone/.next/static/{9y3LeeR2uGr2yRj9RjY3D → tJOKQbQRO-9MiFDO8DIDS}/_ssgManifest.js +0 -0
@@ -2,8 +2,11 @@
2
2
  // File Purpose: State manifest snapshot and restore orchestration for GSD workflow data.
3
3
  import { _getAdapter, readTransaction, restoreManifest, } from "./gsd-db.js";
4
4
  import { atomicWriteSync } from "./atomic-write.js";
5
+ import { getAllDecisionsFromMemories } from "./context-store.js";
6
+ import { backfillDecisionsToMemories } from "./memory-backfill.js";
7
+ import { invalidateAllCaches } from "./cache.js";
5
8
  import { readFileSync, existsSync, mkdirSync } from "node:fs";
6
- import { join } from "node:path";
9
+ import { isAbsolute, join, relative, resolve } from "node:path";
7
10
  // ─── helpers ─────────────────────────────────────────────────────────────
8
11
  function requireDb() {
9
12
  const db = _getAdapter();
@@ -30,10 +33,24 @@ export function toNumeric(value, fallback = null) {
30
33
  }
31
34
  return fallback;
32
35
  }
36
+ function mergeDecisionSurfaces(legacyDecisions, memoryDecisions) {
37
+ const byId = new Map();
38
+ for (const decision of legacyDecisions) {
39
+ byId.set(decision.id, decision);
40
+ }
41
+ for (const decision of memoryDecisions) {
42
+ byId.set(decision.id, decision);
43
+ }
44
+ return Array.from(byId.values()).sort((a, b) => {
45
+ const seqDelta = (a.seq ?? 0) - (b.seq ?? 0);
46
+ return seqDelta === 0 ? a.id.localeCompare(b.id) : seqDelta;
47
+ });
48
+ }
33
49
  // ─── snapshotState ───────────────────────────────────────────────────────
34
50
  /**
35
- * Capture complete DB state as a StateManifest.
36
- * Reads all rows from milestones, slices, tasks, decisions, verification_evidence.
51
+ * Capture DB-backed workflow state as a StateManifest.
52
+ * Runtime soft state and append-only audit streams stay outside this recovery
53
+ * substrate; correctness records and persisted evidence are included.
37
54
  *
38
55
  * Note: rows returned from raw queries are plain objects with TEXT columns for
39
56
  * JSON arrays. We parse them into typed Row objects using the same logic as
@@ -44,6 +61,32 @@ export function snapshotState() {
44
61
  // Wrap all reads in a deferred transaction so the snapshot is consistent
45
62
  // (all SELECTs see the same DB state even if a concurrent write lands between them).
46
63
  return readTransaction(() => {
64
+ const rawRequirements = db.prepare("SELECT * FROM requirements ORDER BY id").all();
65
+ const requirements = rawRequirements.map((r) => ({
66
+ id: r["id"],
67
+ class: r["class"] ?? "",
68
+ status: r["status"] ?? "",
69
+ description: r["description"] ?? "",
70
+ why: r["why"] ?? "",
71
+ source: r["source"] ?? "",
72
+ primary_owner: r["primary_owner"] ?? "",
73
+ supporting_slices: r["supporting_slices"] ?? "",
74
+ validation: r["validation"] ?? "",
75
+ notes: r["notes"] ?? "",
76
+ full_content: r["full_content"] ?? "",
77
+ superseded_by: r["superseded_by"] ?? null,
78
+ }));
79
+ const rawArtifacts = db.prepare("SELECT * FROM artifacts ORDER BY path").all();
80
+ const artifacts = rawArtifacts.map((r) => ({
81
+ path: r["path"],
82
+ artifact_type: r["artifact_type"] ?? "",
83
+ milestone_id: r["milestone_id"] ?? null,
84
+ slice_id: r["slice_id"] ?? null,
85
+ task_id: r["task_id"] ?? null,
86
+ full_content: r["full_content"] ?? "",
87
+ imported_at: r["imported_at"] ?? "",
88
+ content_hash: r["content_hash"] ?? null,
89
+ }));
47
90
  const rawMilestones = db.prepare("SELECT * FROM milestones ORDER BY CASE WHEN sequence > 0 THEN 0 ELSE 1 END, sequence, id").all();
48
91
  const milestones = rawMilestones.map((r) => ({
49
92
  id: r["id"],
@@ -124,7 +167,7 @@ export function snapshotState() {
124
167
  escalation_override_applied_at: r["escalation_override_applied_at"] ?? null,
125
168
  }));
126
169
  const rawDecisions = db.prepare("SELECT * FROM decisions ORDER BY seq").all();
127
- const decisions = rawDecisions.map((r) => ({
170
+ const legacyDecisions = rawDecisions.map((r) => ({
128
171
  seq: toNumeric(r["seq"], 0),
129
172
  id: r["id"],
130
173
  when_context: r["when_context"] ?? "",
@@ -137,6 +180,42 @@ export function snapshotState() {
137
180
  source: r["source"] ?? "discussion",
138
181
  superseded_by: r["superseded_by"] ?? null,
139
182
  }));
183
+ const decisions = mergeDecisionSurfaces(legacyDecisions, getAllDecisionsFromMemories());
184
+ const rawReplanHistory = db.prepare("SELECT * FROM replan_history ORDER BY id").all();
185
+ const replan_history = rawReplanHistory.map((r) => ({
186
+ id: toNumeric(r["id"], 0),
187
+ milestone_id: r["milestone_id"] ?? "",
188
+ slice_id: r["slice_id"] ?? null,
189
+ task_id: r["task_id"] ?? null,
190
+ summary: r["summary"] ?? "",
191
+ previous_artifact_path: r["previous_artifact_path"] ?? null,
192
+ replacement_artifact_path: r["replacement_artifact_path"] ?? null,
193
+ created_at: r["created_at"] ?? "",
194
+ }));
195
+ const rawAssessments = db.prepare("SELECT * FROM assessments ORDER BY path").all();
196
+ const assessments = rawAssessments.map((r) => ({
197
+ path: r["path"],
198
+ milestone_id: r["milestone_id"] ?? "",
199
+ slice_id: r["slice_id"] ?? null,
200
+ task_id: r["task_id"] ?? null,
201
+ status: r["status"] ?? "",
202
+ scope: r["scope"] ?? "",
203
+ full_content: r["full_content"] ?? "",
204
+ created_at: r["created_at"] ?? "",
205
+ }));
206
+ const rawQualityGates = db.prepare("SELECT * FROM quality_gates ORDER BY milestone_id, slice_id, gate_id, task_id").all();
207
+ const quality_gates = rawQualityGates.map((r) => ({
208
+ milestone_id: r["milestone_id"],
209
+ slice_id: r["slice_id"],
210
+ gate_id: r["gate_id"],
211
+ scope: r["scope"],
212
+ task_id: r["task_id"] ?? "",
213
+ status: r["status"],
214
+ verdict: r["status"] === "pending" ? null : r["verdict"],
215
+ rationale: r["rationale"] ?? "",
216
+ findings: r["findings"] ?? "",
217
+ evaluated_at: r["evaluated_at"] ?? null,
218
+ }));
140
219
  const rawEvidence = db.prepare("SELECT * FROM verification_evidence ORDER BY id").all();
141
220
  const verification_evidence = rawEvidence.map((r) => ({
142
221
  id: r["id"],
@@ -149,14 +228,31 @@ export function snapshotState() {
149
228
  duration_ms: toNumeric(r["duration_ms"]),
150
229
  created_at: r["created_at"],
151
230
  }));
231
+ const rawCommitAttributions = db.prepare("SELECT * FROM milestone_commit_attributions ORDER BY milestone_id, commit_sha").all();
232
+ const milestone_commit_attributions = rawCommitAttributions.map((r) => ({
233
+ commit_sha: r["commit_sha"],
234
+ milestone_id: r["milestone_id"],
235
+ slice_id: r["slice_id"] ?? null,
236
+ task_id: r["task_id"] ?? null,
237
+ source: r["source"] ?? "recorded",
238
+ confidence: toNumeric(r["confidence"], 1),
239
+ files_json: r["files_json"] ?? "[]",
240
+ created_at: r["created_at"] ?? "",
241
+ }));
152
242
  const result = {
153
243
  version: 1,
154
244
  exported_at: new Date().toISOString(),
245
+ requirements,
246
+ artifacts,
155
247
  milestones,
156
248
  slices,
157
249
  tasks,
158
250
  decisions,
251
+ replan_history,
252
+ assessments,
253
+ quality_gates,
159
254
  verification_evidence,
255
+ milestone_commit_attributions,
160
256
  };
161
257
  return result;
162
258
  });
@@ -192,17 +288,45 @@ export function readManifest(basePath) {
192
288
  if (parsed.version !== 1) {
193
289
  throw new Error(`Unsupported manifest version: ${parsed.version}`);
194
290
  }
195
- // Validate required fields to avoid cryptic errors during restore
291
+ // Validate required fields to avoid cryptic errors during restore.
196
292
  if (!Array.isArray(parsed.milestones) || !Array.isArray(parsed.slices) ||
197
293
  !Array.isArray(parsed.tasks) || !Array.isArray(parsed.decisions) ||
198
294
  !Array.isArray(parsed.verification_evidence)) {
199
295
  throw new Error("Malformed manifest: missing or invalid required arrays");
200
296
  }
297
+ for (const key of ["requirements", "artifacts", "replan_history", "assessments", "quality_gates", "milestone_commit_attributions"]) {
298
+ if (parsed[key] !== undefined && !Array.isArray(parsed[key])) {
299
+ throw new Error(`Malformed manifest: ${key} must be an array when present`);
300
+ }
301
+ }
201
302
  return parsed;
202
303
  }
304
+ function stripGsdPrefix(path) {
305
+ return path.startsWith(".gsd/") ? path.slice(".gsd/".length) : path;
306
+ }
307
+ function artifactProjectionPath(basePath, artifactPath) {
308
+ const gsdDir = resolve(basePath, ".gsd");
309
+ const fullPath = resolve(gsdDir, stripGsdPrefix(artifactPath));
310
+ const rel = relative(gsdDir, fullPath);
311
+ if (rel.startsWith("..") || isAbsolute(rel)) {
312
+ throw new Error(`Malformed manifest: artifact path escapes .gsd: ${artifactPath}`);
313
+ }
314
+ return fullPath;
315
+ }
316
+ function restoreArtifactProjections(basePath, manifest) {
317
+ if (manifest.artifacts === undefined)
318
+ return;
319
+ for (const artifact of manifest.artifacts) {
320
+ atomicWriteSync(artifactProjectionPath(basePath, artifact.path), artifact.full_content ?? "");
321
+ }
322
+ }
203
323
  // ─── bootstrapFromManifest ──────────────────────────────────────────────
204
324
  /**
205
325
  * Read state-manifest.json and restore DB state from it.
326
+ * Rehydrates artifact projection files for restored artifacts so file-based
327
+ * fallback paths see the same evidence as the DB.
328
+ * Re-mirrors restored legacy decisions into memories so the ADR-013
329
+ * memory-backed decision readers see bootstrapped decisions immediately.
206
330
  * Returns true if bootstrap succeeded, false if manifest file doesn't exist.
207
331
  */
208
332
  export function bootstrapFromManifest(basePath) {
@@ -211,5 +335,8 @@ export function bootstrapFromManifest(basePath) {
211
335
  return false;
212
336
  }
213
337
  restoreManifest(manifest);
338
+ restoreArtifactProjections(basePath, manifest);
339
+ backfillDecisionsToMemories();
340
+ invalidateAllCaches();
214
341
  return true;
215
342
  }
@@ -409,10 +409,9 @@ export function getWorkflowTransportSupportError(provider, requiredTools, option
409
409
  return `Provider ${providerLabel} cannot run ${surface}${unitLabel}: the GSD workflow MCP server is not configured or discoverable. Detected Claude Code model but no workflow MCP. Please run /gsd mcp init . from your project root. You can also configure GSD_WORKFLOW_MCP_COMMAND, build packages/mcp-server/dist/cli.js, or install gsd-mcp-server on PATH.`;
410
410
  }
411
411
  const uniqueRequired = [...new Set(requiredTools)];
412
- const piRuntimeRequired = uniqueRequired.filter((tool) => !MCP_WORKFLOW_TOOL_SURFACE.has(tool));
413
412
  const missing = (options.activeTools && options.activeTools.length > 0)
414
- ? piRuntimeRequired.filter((tool) => !hasRequiredTool(tool, options.activeTools))
415
- : piRuntimeRequired;
413
+ ? uniqueRequired.filter((tool) => !hasRequiredTool(tool, options.activeTools))
414
+ : uniqueRequired.filter((tool) => !MCP_WORKFLOW_TOOL_SURFACE.has(tool));
416
415
  if (missing.length === 0)
417
416
  return null;
418
417
  if (options.activeTools && options.activeTools.length > 0) {
@@ -482,6 +482,14 @@ export async function regenerateIfMissing(basePath, milestoneId, sliceId, fileTy
482
482
  if (existsSync(filePath)) {
483
483
  return false;
484
484
  }
485
+ // A sketch slice (or any slice not yet planned into tasks) legitimately has
486
+ // no PLAN.md to project. renderPlanFromDb throws on a zero-task slice, so
487
+ // skip cleanly here rather than logging a spurious failure. The PLAN.md will
488
+ // be created once the slice is refined and its first task is written through
489
+ // the single writer.
490
+ if (fileType === "PLAN" && getSliceTasks(milestoneId, sliceId).length === 0) {
491
+ return false;
492
+ }
485
493
  // Regenerate the missing file. Each renderer may swallow its own errors
486
494
  // (e.g. renderStateProjection), so confirm the file actually exists on
487
495
  // disk before reporting success — true must mean "file is there now".
@@ -185,6 +185,32 @@ export function resolveCanonicalMilestoneRoot(basePath, milestoneId) {
185
185
  }
186
186
  return wtPath;
187
187
  }
188
+ /**
189
+ * Build human-facing guidance for manually validating a milestone's work.
190
+ *
191
+ * When a milestone runs in a git worktree, its checkout lives under the hidden
192
+ * `.gsd/worktrees/<MID>/` path that a human can't easily discover. The UAT
193
+ * pause/handoff and the saved assessment use this to tell the human exactly
194
+ * where to `cd` to run or inspect the app before signing off on NEEDS-HUMAN
195
+ * checks, rather than leaving them to hunt for a buried path.
196
+ *
197
+ * Returns null when no milestone id is available.
198
+ */
199
+ export function buildManualValidationGuidance(basePath, milestoneId, opts = {}) {
200
+ if (!milestoneId)
201
+ return null;
202
+ const validationRoot = resolveCanonicalMilestoneRoot(basePath, milestoneId);
203
+ const inWorktree = validationRoot.includes(`${sep}.gsd${sep}worktrees${sep}`);
204
+ const lines = [`Validate the work here: ${validationRoot}`];
205
+ if (inWorktree) {
206
+ lines.push("This milestone runs in a git worktree, so the code lives under the hidden " +
207
+ `\`.gsd/worktrees/\` path. Open it with: cd "${validationRoot}"`);
208
+ }
209
+ if (opts.uatPath) {
210
+ lines.push(`Follow the UAT checklist at: ${opts.uatPath}`);
211
+ }
212
+ return lines.join("\n");
213
+ }
188
214
  // ─── Core Operations ───────────────────────────────────────────────────────
189
215
  /**
190
216
  * Create a new git worktree under .gsd/worktrees/<name>/ with branch worktree/<name>.
@@ -0,0 +1,96 @@
1
+ // Project/App: gsd-pi
2
+ // File Purpose: Deterministically re-enter the active milestone's worktree on a
3
+ // cold start (after /quit + relaunch). Without this, Claude Code relaunches with
4
+ // cwd at the project root, and a bare /gsd leaves the agent there — forcing it to
5
+ // search the filesystem ("git worktree list", branch sniffing) to find its way
6
+ // back into the worktree. The worktree path is fully derivable from state, so we
7
+ // resolve and chdir into it directly instead.
8
+ import { readdirSync } from "node:fs";
9
+ import { enterAutoWorktree, getAutoWorktreePath } from "./auto-worktree.js";
10
+ import { getIsolationMode } from "./preferences.js";
11
+ import { worktreesDir } from "./worktree-manager.js";
12
+ import { isGsdWorktreePath, resolveWorktreeProjectRoot } from "./worktree-root.js";
13
+ /**
14
+ * Enumerate the live (valid git) auto-worktrees under <projectRoot>/.gsd/worktrees/.
15
+ * Reuses getAutoWorktreePath's validation so stray directories are ignored.
16
+ */
17
+ function liveMilestoneWorktrees(projectRoot) {
18
+ let names;
19
+ try {
20
+ names = readdirSync(worktreesDir(projectRoot));
21
+ }
22
+ catch {
23
+ return [];
24
+ }
25
+ const live = [];
26
+ for (const id of names) {
27
+ const path = getAutoWorktreePath(projectRoot, id);
28
+ if (path)
29
+ live.push({ id, path });
30
+ }
31
+ return live;
32
+ }
33
+ /**
34
+ * If we're sitting at the project root with worktree isolation enabled and the
35
+ * active milestone has a live worktree, chdir into it. No-op when already inside
36
+ * a worktree, when isolation is off, or when the target is ambiguous.
37
+ *
38
+ * Single live worktree → enter it (covers the common case without deriveState).
39
+ * Multiple live worktrees → disambiguate by the active milestone from state;
40
+ * if that can't be resolved unambiguously, do nothing.
41
+ *
42
+ * Best-effort: any failure resolves to a no-op so it can never block startup.
43
+ *
44
+ * @returns the worktree path entered, or null when nothing was done.
45
+ */
46
+ export async function reenterActiveWorktreeIfNeeded(basePath, opts = {}) {
47
+ let projectRoot;
48
+ try {
49
+ projectRoot = resolveWorktreeProjectRoot(basePath);
50
+ }
51
+ catch {
52
+ return null;
53
+ }
54
+ // Only worktree-isolation projects have worktrees to re-enter.
55
+ if (getIsolationMode(projectRoot) !== "worktree")
56
+ return null;
57
+ // Already inside a worktree (warm session, or auto-mode already entered) —
58
+ // nothing to do.
59
+ let cwd;
60
+ try {
61
+ cwd = process.cwd();
62
+ }
63
+ catch {
64
+ return null;
65
+ }
66
+ if (isGsdWorktreePath(cwd))
67
+ return null;
68
+ const live = liveMilestoneWorktrees(projectRoot);
69
+ if (live.length === 0)
70
+ return null;
71
+ let target = live.length === 1 ? live[0] : null;
72
+ if (!target) {
73
+ // Multiple live worktrees — disambiguate by the active milestone.
74
+ try {
75
+ const { deriveState } = await import("./state.js");
76
+ const state = await deriveState(projectRoot);
77
+ const activeId = state.activeMilestone?.id;
78
+ target = activeId ? live.find((w) => w.id === activeId) ?? null : null;
79
+ }
80
+ catch {
81
+ target = null;
82
+ }
83
+ }
84
+ if (!target)
85
+ return null;
86
+ try {
87
+ const entered = enterAutoWorktree(projectRoot, target.id);
88
+ opts.notify?.(`Resumed in worktree for ${target.id}.`);
89
+ return entered;
90
+ }
91
+ catch {
92
+ // Worktree vanished or chdir failed — leave cwd as-is, caller falls back to
93
+ // the project root.
94
+ return null;
95
+ }
96
+ }
@@ -100,28 +100,26 @@ function forceOverwriteAssessmentsWithVerdict(srcMilestoneDir, dstMilestoneDir)
100
100
  logWarning("worktree", `assessment sync failed: ${err instanceof Error ? err.message : String(err)}`);
101
101
  }
102
102
  }
103
- function syncTopLevelMilestoneArtifacts(srcMilestonesDir, dstMilestonesDir) {
103
+ function syncOtherMilestoneArtifacts(srcMilestonesDir, dstMilestonesDir, currentMilestoneId) {
104
104
  if (!existsSync(srcMilestonesDir))
105
105
  return;
106
106
  try {
107
107
  for (const milestoneEntry of readdirSync(srcMilestonesDir, { withFileTypes: true })) {
108
108
  if (!milestoneEntry.isDirectory())
109
109
  continue;
110
+ // The current milestone is already fully projected by the caller's
111
+ // additive safeCopyRecursive; skip it here to avoid redundant work.
112
+ if (milestoneEntry.name === currentMilestoneId)
113
+ continue;
110
114
  const srcMilestoneDir = join(srcMilestonesDir, milestoneEntry.name);
111
115
  const dstMilestoneDir = join(dstMilestonesDir, milestoneEntry.name);
112
- try {
113
- mkdirSync(dstMilestoneDir, { recursive: true });
114
- for (const fileEntry of readdirSync(srcMilestoneDir, { withFileTypes: true })) {
115
- if (!fileEntry.isFile())
116
- continue;
117
- if (!fileEntry.name.endsWith(".md") && !fileEntry.name.endsWith(".json"))
118
- continue;
119
- safeCopy(join(srcMilestoneDir, fileEntry.name), join(dstMilestoneDir, fileEntry.name), { force: false });
120
- }
121
- }
122
- catch (err) {
123
- logWarning("worktree", `milestone top-level artifact sync failed (${milestoneEntry.name}): ${err instanceof Error ? err.message : String(err)}`);
124
- }
116
+ // Additively project the entire milestone subtree (force:false), not just
117
+ // top-level files. Prior completed milestones keep their per-slice and
118
+ // per-task SUMMARY.md / UAT.md on disk so the worktree's stale-render
119
+ // detector doesn't flag them as missing (DB has summary, disk doesn't).
120
+ // force:false preserves any worktree-local files (#1886 invariant) and
121
+ // only fills in files absent from the worktree projection.
122
+ safeCopyRecursive(srcMilestoneDir, dstMilestoneDir, { force: false });
125
123
  }
126
124
  }
127
125
  catch (err) {
@@ -199,9 +197,12 @@ export function _projectRootToWorktreeImpl(projectRoot, worktreePath_, milestone
199
197
  // by validate-milestone) get clobbered by stale project root copies,
200
198
  // causing an infinite re-validation loop (#1886).
201
199
  safeCopyRecursive(join(prGsd, "milestones", milestoneId), join(wtGsd, "milestones", milestoneId), { force: false });
202
- // Additively project missing top-level milestone files for all milestones
203
- // so worktree-bound units can verify future-milestone context artifacts.
204
- syncTopLevelMilestoneArtifacts(join(prGsd, "milestones"), join(wtGsd, "milestones"));
200
+ // Additively project the full subtree of every OTHER milestone so
201
+ // worktree-bound units can read prior-milestone context artifacts and so
202
+ // completed milestones retain their per-slice/per-task SUMMARY.md and
203
+ // UAT.md on the worktree filesystem (otherwise the stale-render detector
204
+ // flags them as "complete in DB but missing on disk").
205
+ syncOtherMilestoneArtifacts(join(prGsd, "milestones"), join(wtGsd, "milestones"), milestoneId);
205
206
  // Force-sync ASSESSMENT files that have a verdict from project root (#2821).
206
207
  // The additive-only copy above preserves worktree-local files, but
207
208
  // ASSESSMENT files are special: after run-uat writes a verdict and post-unit
@@ -115,6 +115,10 @@ export function resolveGsdBrowserMcpLaunchConfig(projectRoot, env = process.env,
115
115
  ? resolveBundledGsdBrowserCliPath(env)
116
116
  : null;
117
117
  const sessionName = options.sessionName?.trim() || buildGsdBrowserSessionName(resolvedProjectRoot, options.sessionSuffix);
118
+ // Stable per-project identity key (no per-session suffix) so the browser
119
+ // profile/cookies persist across pi sessions for the same project. gsd-browser
120
+ // rejects --identity-scope unless --identity-key is also supplied.
121
+ const identityKey = env.GSD_BROWSER_IDENTITY_KEY?.trim() || buildGsdBrowserSessionName(resolvedProjectRoot);
118
122
  const command = explicitCommand
119
123
  || explicitCliPath
120
124
  || (preferPathCli ? "gsd-browser" : undefined)
@@ -129,6 +133,8 @@ export function resolveGsdBrowserMcpLaunchConfig(projectRoot, env = process.env,
129
133
  sessionName,
130
134
  "--identity-scope",
131
135
  "project",
136
+ "--identity-key",
137
+ identityKey,
132
138
  "--identity-project",
133
139
  resolvedProjectRoot,
134
140
  ];
@@ -64,6 +64,7 @@ function loadAgentsFromDir(dir, source) {
64
64
  description: frontmatter.description,
65
65
  tools: tools && tools.length > 0 ? tools : undefined,
66
66
  model: frontmatter.model,
67
+ thinking: typeof frontmatter.thinking === "string" ? frontmatter.thinking : undefined,
67
68
  conflictsWith,
68
69
  systemPrompt: body,
69
70
  source,
@@ -301,7 +301,10 @@ function formatRunRecord(record) {
301
301
  lines.push(`Failure: ${record.failure.message}`);
302
302
  return lines.join("\n");
303
303
  }
304
- async function runSingleAgent(defaultCwd, agents, agentName, task, cwd, step, signal, onUpdate, makeDetails, modelOverride, contextMode = "fresh", parentSessionManager, sessionOverride, trackingName) {
304
+ async function runSingleAgent(defaultCwd, agents, agentName, task, cwd, step, signal, onUpdate, makeDetails, modelOverride, contextMode = "fresh", parentSessionManager, sessionOverride, trackingName,
305
+ // Trailing param (kept after trackingName so existing positional call sites
306
+ // don't shift). Reasoning effort forwarded to the child (#508).
307
+ thinkingOverride) {
305
308
  const agent = agents.find((a) => a.name === agentName);
306
309
  if (!agent) {
307
310
  const available = agents.map((a) => `"${a.name}"`).join(", ") || "none";
@@ -368,6 +371,7 @@ async function runSingleAgent(defaultCwd, agents, agentName, task, cwd, step, si
368
371
  task,
369
372
  tmpPromptPath,
370
373
  modelOverride,
374
+ thinkingOverride,
371
375
  contextMode,
372
376
  parentSessionManager,
373
377
  session: sessionOverride,
@@ -441,10 +445,12 @@ async function runSingleAgent(defaultCwd, agents, agentName, task, cwd, step, si
441
445
  }
442
446
  }
443
447
  }
444
- async function runSingleAgentInCmuxSplit(cmuxClient, directionOrSurfaceId, defaultCwd, agents, agentName, task, cwd, step, signal, onUpdate, makeDetails, modelOverride, contextMode = "fresh", parentSessionManager, sessionOverride, trackingName) {
448
+ async function runSingleAgentInCmuxSplit(cmuxClient, directionOrSurfaceId, defaultCwd, agents, agentName, task, cwd, step, signal, onUpdate, makeDetails, modelOverride, contextMode = "fresh", parentSessionManager, sessionOverride, trackingName,
449
+ // Trailing param (see runSingleAgent). Reasoning effort forwarded to the child (#508).
450
+ thinkingOverride) {
445
451
  const agent = agents.find((a) => a.name === agentName);
446
452
  if (!agent) {
447
- return runSingleAgent(defaultCwd, agents, agentName, task, cwd, step, signal, onUpdate, makeDetails, modelOverride, contextMode, parentSessionManager, sessionOverride, trackingName);
453
+ return runSingleAgent(defaultCwd, agents, agentName, task, cwd, step, signal, onUpdate, makeDetails, modelOverride, contextMode, parentSessionManager, sessionOverride, trackingName, thinkingOverride);
448
454
  }
449
455
  let tmpPromptDir = null;
450
456
  let tmpPromptPath = null;
@@ -487,7 +493,7 @@ async function runSingleAgentInCmuxSplit(cmuxClient, directionOrSurfaceId, defau
487
493
  ? await cmuxClient.createSplit(directionOrSurfaceId)
488
494
  : directionOrSurfaceId;
489
495
  if (!cmuxSurfaceId) {
490
- return runSingleAgent(defaultCwd, agents, agentName, task, cwd, step, signal, onUpdate, makeDetails, modelOverride, contextMode, parentSessionManager, sessionOverride, trackingName);
496
+ return runSingleAgent(defaultCwd, agents, agentName, task, cwd, step, signal, onUpdate, makeDetails, modelOverride, contextMode, parentSessionManager, sessionOverride, trackingName, thinkingOverride);
491
497
  }
492
498
  const bundledPaths = (process.env.GSD_BUNDLED_EXTENSION_PATHS ?? "").split(path.delimiter).map((s) => s.trim()).filter(Boolean);
493
499
  const extensionArgs = bundledPaths.flatMap((p) => ["--extension", p]);
@@ -496,6 +502,7 @@ async function runSingleAgentInCmuxSplit(cmuxClient, directionOrSurfaceId, defau
496
502
  task,
497
503
  tmpPromptPath,
498
504
  modelOverride,
505
+ thinkingOverride,
499
506
  contextMode,
500
507
  parentSessionManager,
501
508
  session: sessionOverride,
@@ -520,7 +527,7 @@ async function runSingleAgentInCmuxSplit(cmuxClient, directionOrSurfaceId, defau
520
527
  ].join("; ");
521
528
  const sent = await cmuxClient.sendSurface(cmuxSurfaceId, `bash -lc ${shellEscape(innerScript)}`);
522
529
  if (!sent) {
523
- return runSingleAgent(defaultCwd, agents, agentName, task, cwd, step, signal, onUpdate, makeDetails, modelOverride, contextMode, parentSessionManager, sessionOverride, trackingName);
530
+ return runSingleAgent(defaultCwd, agents, agentName, task, cwd, step, signal, onUpdate, makeDetails, modelOverride, contextMode, parentSessionManager, sessionOverride, trackingName, thinkingOverride);
524
531
  }
525
532
  const finished = await waitForFile(exitPath, signal);
526
533
  if (!finished) {
@@ -583,11 +590,16 @@ async function runSingleAgentInCmuxSplit(cmuxClient, directionOrSurfaceId, defau
583
590
  }
584
591
  }
585
592
  }
593
+ const ThinkingLevelSchema = StringEnum(["off", "minimal", "low", "medium", "high", "xhigh"], {
594
+ description: "Reasoning effort override for the subagent (forwarded as --thinking). " +
595
+ "Independent of model choice; unsupported levels are clamped to the model at dispatch.",
596
+ });
586
597
  const TaskItem = Type.Object({
587
598
  agent: Type.String({ description: "Name of the agent to invoke" }),
588
599
  task: Type.String({ description: "Task to delegate to the agent" }),
589
600
  cwd: Type.Optional(Type.String({ description: "Working directory for the agent process" })),
590
601
  model: Type.Optional(Type.String({ description: "Model override for this task (e.g. 'claude-sonnet-4-6')" })),
602
+ thinking: Type.Optional(ThinkingLevelSchema),
591
603
  context: Type.Optional(StringEnum(["fresh", "fork"], {
592
604
  description: 'Context mode for this task (see context field on the top-level params).',
593
605
  default: "fresh",
@@ -598,6 +610,7 @@ const ChainItem = Type.Object({
598
610
  task: Type.String({ description: "Task with optional {previous} placeholder for prior step output" }),
599
611
  cwd: Type.Optional(Type.String({ description: "Working directory for the agent process" })),
600
612
  model: Type.Optional(Type.String({ description: "Model override for this step (e.g. 'claude-sonnet-4-6')" })),
613
+ thinking: Type.Optional(ThinkingLevelSchema),
601
614
  context: Type.Optional(StringEnum(["fresh", "fork"], {
602
615
  description: 'Context mode for this step (see context field on the top-level params).',
603
616
  default: "fresh",
@@ -629,6 +642,7 @@ const SubagentParams = Type.Object({
629
642
  confirmProjectAgents: Type.Optional(Type.Boolean({ description: "Prompt before running project-local agents. Default: false.", default: false })),
630
643
  cwd: Type.Optional(Type.String({ description: "Working directory for the agent process (single mode)" })),
631
644
  model: Type.Optional(Type.String({ description: "Model override for the subagent (e.g. 'claude-sonnet-4-6'). Takes precedence over the agent's frontmatter model." })),
645
+ thinking: Type.Optional(ThinkingLevelSchema),
632
646
  isolated: Type.Optional(Type.Boolean({
633
647
  description: "Run the subagent in an isolated filesystem (git worktree). " +
634
648
  "Changes are captured as patches and merged back. " +
@@ -749,7 +763,7 @@ export default function (pi) {
749
763
  isError: true,
750
764
  };
751
765
  }
752
- const result = await runSingleAgent(ctx.cwd, agents, selected.agent, followUp, selected.cwd, undefined, signal, onUpdate, makeDetails("single"), params.model, "fresh", ctx.sessionManager, { mode: "fork", sessionFile: selected.sessionFile, sessionDir: path.dirname(selected.sessionFile) }, selected.trackingName);
766
+ const result = await runSingleAgent(ctx.cwd, agents, selected.agent, followUp, selected.cwd, undefined, signal, onUpdate, makeDetails("single"), params.model, "fresh", ctx.sessionManager, { mode: "fork", sessionFile: selected.sessionFile, sessionDir: path.dirname(selected.sessionFile) }, selected.trackingName, params.thinking);
753
767
  return {
754
768
  content: [{ type: "text", text: getFinalOutput(result.messages) || result.errorMessage || result.stderr || "(no output)" }],
755
769
  details: makeDetails("single")([result]),
@@ -1017,7 +1031,7 @@ export default function (pi) {
1017
1031
  const result = await runSingleAgent(ctx.cwd, agents, params.agent, params.task, isolation ? isolation.workDir : params.cwd, undefined, undefined, (partial) => {
1018
1032
  if (partial.details?.results[0])
1019
1033
  persistRunResults([partial.details.results[0]]);
1020
- }, makeDetails("single"), params.model, contextMode, ctx.sessionManager, undefined, dispatchTrackingNames[0]);
1034
+ }, makeDetails("single"), params.model, contextMode, ctx.sessionManager, undefined, dispatchTrackingNames[0], params.thinking);
1021
1035
  if (isolation && result.exitCode === 0) {
1022
1036
  const patches = await isolation.captureDelta();
1023
1037
  if (patches.length > 0) {
@@ -1073,7 +1087,7 @@ export default function (pi) {
1073
1087
  }
1074
1088
  }
1075
1089
  };
1076
- const result = await runSingleAgent(ctx.cwd, agents, step.agent, taskWithContext, step.cwd, i + 1, signal, chainUpdate, makeDetails("chain"), step.model || params.model, step.context ?? contextMode, ctx.sessionManager, undefined, dispatchTrackingNames[i]);
1090
+ const result = await runSingleAgent(ctx.cwd, agents, step.agent, taskWithContext, step.cwd, i + 1, signal, chainUpdate, makeDetails("chain"), step.model || params.model, step.context ?? contextMode, ctx.sessionManager, undefined, dispatchTrackingNames[i], step.thinking || params.thinking);
1077
1091
  results.push(result);
1078
1092
  persistRunResults(results);
1079
1093
  const isError = result.exitCode !== 0 || result.stopReason === "error" || result.stopReason === "aborted";
@@ -1145,6 +1159,7 @@ export default function (pi) {
1145
1159
  const results = await mapWithConcurrencyLimit(taskParams, MAX_CONCURRENCY, async (t, index) => {
1146
1160
  const workerId = registerWorker(t.agent, t.task, index, batchSize, batchId);
1147
1161
  const taskModel = t.model || params.model;
1162
+ const taskThinking = t.thinking || params.thinking;
1148
1163
  const updateParallelResult = (partial) => {
1149
1164
  if (partial.details?.results[0]) {
1150
1165
  allResults[index] = partial.details.results[0];
@@ -1153,8 +1168,8 @@ export default function (pi) {
1153
1168
  }
1154
1169
  };
1155
1170
  const executeOnce = (runCwd) => cmuxSplitsEnabled
1156
- ? runSingleAgentInCmuxSplit(cmuxClient, gridSurfaces[index] ?? (index % 2 === 0 ? "right" : "down"), ctx.cwd, agents, t.agent, t.task, runCwd, undefined, signal, updateParallelResult, makeDetails("parallel"), taskModel, t.context ?? contextMode, ctx.sessionManager, undefined, dispatchTrackingNames[index])
1157
- : runSingleAgent(ctx.cwd, agents, t.agent, t.task, runCwd, undefined, signal, updateParallelResult, makeDetails("parallel"), taskModel, t.context ?? contextMode, ctx.sessionManager, undefined, dispatchTrackingNames[index]);
1171
+ ? runSingleAgentInCmuxSplit(cmuxClient, gridSurfaces[index] ?? (index % 2 === 0 ? "right" : "down"), ctx.cwd, agents, t.agent, t.task, runCwd, undefined, signal, updateParallelResult, makeDetails("parallel"), taskModel, t.context ?? contextMode, ctx.sessionManager, undefined, dispatchTrackingNames[index], taskThinking)
1172
+ : runSingleAgent(ctx.cwd, agents, t.agent, t.task, runCwd, undefined, signal, updateParallelResult, makeDetails("parallel"), taskModel, t.context ?? contextMode, ctx.sessionManager, undefined, dispatchTrackingNames[index], taskThinking);
1158
1173
  const runTask = async () => {
1159
1174
  let isolation = null;
1160
1175
  const effectiveCwd = t.cwd ?? ctx.cwd;
@@ -1232,8 +1247,8 @@ export default function (pi) {
1232
1247
  onUpdate(partial);
1233
1248
  };
1234
1249
  const result = cmuxSplitsEnabled
1235
- ? await runSingleAgentInCmuxSplit(cmuxClient, "right", ctx.cwd, agents, params.agent, params.task, isolation ? isolation.workDir : params.cwd, undefined, signal, singleUpdate, makeDetails("single"), params.model, contextMode, ctx.sessionManager, undefined, dispatchTrackingNames[0])
1236
- : await runSingleAgent(ctx.cwd, agents, params.agent, params.task, isolation ? isolation.workDir : params.cwd, undefined, signal, singleUpdate, makeDetails("single"), params.model, contextMode, ctx.sessionManager, undefined, dispatchTrackingNames[0]);
1250
+ ? await runSingleAgentInCmuxSplit(cmuxClient, "right", ctx.cwd, agents, params.agent, params.task, isolation ? isolation.workDir : params.cwd, undefined, signal, singleUpdate, makeDetails("single"), params.model, contextMode, ctx.sessionManager, undefined, dispatchTrackingNames[0], params.thinking)
1251
+ : await runSingleAgent(ctx.cwd, agents, params.agent, params.task, isolation ? isolation.workDir : params.cwd, undefined, signal, singleUpdate, makeDetails("single"), params.model, contextMode, ctx.sessionManager, undefined, dispatchTrackingNames[0], params.thinking);
1237
1252
  finalResults = [result];
1238
1253
  // Capture and merge delta if isolated
1239
1254
  if (isolation) {
@@ -17,7 +17,7 @@ export function buildShellEnvAssignments(env = process.env) {
17
17
  const value = env[SUBAGENT_CHILD_ENV_VAR];
18
18
  return value ? [`${SUBAGENT_CHILD_ENV_VAR}=${JSON.stringify(value)}`] : [];
19
19
  }
20
- export function buildSubagentProcessArgs(agent, task, tmpPromptPath, modelOverride, session = { mode: "fresh" }) {
20
+ export function buildSubagentProcessArgs(agent, task, tmpPromptPath, modelOverride, thinkingOverride, session = { mode: "fresh" }) {
21
21
  const args = ["--mode", "json", "-p"];
22
22
  if (session.mode === "fork") {
23
23
  args.push("--session", session.sessionFile);
@@ -30,6 +30,11 @@ export function buildSubagentProcessArgs(agent, task, tmpPromptPath, modelOverri
30
30
  const effectiveModel = modelOverride ?? agent.model;
31
31
  if (effectiveModel)
32
32
  args.push("--model", effectiveModel);
33
+ // Reasoning effort travels with the model (ADR-026 / #508). The child CLI
34
+ // validates `--thinking` and clamps to the resolved model at dispatch.
35
+ const effectiveThinking = thinkingOverride ?? agent.thinking;
36
+ if (effectiveThinking)
37
+ args.push("--thinking", effectiveThinking);
33
38
  if (agent.tools && agent.tools.length > 0)
34
39
  args.push("--tools", agent.tools.join(","));
35
40
  if (tmpPromptPath)
@@ -69,7 +74,7 @@ export function resolveSubagentSessionArgs(contextMode = "fresh", parentSessionM
69
74
  export function createSubagentLaunchPlan(input) {
70
75
  const session = input.session ?? resolveSubagentSessionArgs(input.contextMode ?? "fresh", input.parentSessionManager);
71
76
  return {
72
- args: buildSubagentProcessArgs(input.agent, input.task, input.tmpPromptPath, input.modelOverride, session),
77
+ args: buildSubagentProcessArgs(input.agent, input.task, input.tmpPromptPath, input.modelOverride, input.thinkingOverride, session),
73
78
  env: buildSubagentProcessEnv(),
74
79
  cwd: input.cwd ?? input.defaultCwd,
75
80
  session,
@@ -1 +1 @@
1
- 9y3LeeR2uGr2yRj9RjY3D
1
+ tJOKQbQRO-9MiFDO8DIDS