@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
@@ -107,7 +107,7 @@ import {
107
107
  } from "./auto-tool-tracking.js";
108
108
  import { closeoutUnit } from "./auto-unit-closeout.js";
109
109
  import { recoverTimedOutUnit } from "./auto-timeout-recovery.js";
110
- import { selectAndApplyModel, resolveModelId, clearToolBaseline } from "./auto-model-selection.js";
110
+ import { selectAndApplyModel, resolveModelId, clearToolBaseline, getToolBaselineSnapshot } from "./auto-model-selection.js";
111
111
  import { resetRoutingHistory, recordOutcome } from "./routing-history.js";
112
112
  import {
113
113
  checkPostUnitHooks,
@@ -542,8 +542,26 @@ function handlePausedSessionResumeRecovery(
542
542
  ): { skippedReplay: boolean } {
543
543
  if (!state.pausedSessionFile) return { skippedReplay: false };
544
544
 
545
- const pausedRecoveryUnitType = state.currentUnit?.type ?? state.pausedUnitType ?? "unknown";
546
- const pausedRecoveryUnitId = state.currentUnit?.id ?? state.pausedUnitId ?? "unknown";
545
+ const pausedRecoveryUnitType = state.currentUnit?.type ?? state.pausedUnitType ?? null;
546
+ const pausedRecoveryUnitId = state.currentUnit?.id ?? state.pausedUnitId ?? null;
547
+
548
+ // When the paused-session metadata never captured the unit identity (the
549
+ // pause happened between units, or the worker died before currentUnit was
550
+ // set), we have nothing to verify against and nothing correct to target. A
551
+ // replay synthesized with an "unknown" unit re-injects an unbounded,
552
+ // mis-identified tool-call blob into the fresh resume context — exactly the
553
+ // thrash that turns one stuck unit into several. Disk state has already been
554
+ // rebuilt (rebuildState + doctor) before this runs, so skip the replay and
555
+ // let the normal dispatcher recompute the next unit from disk.
556
+ if (!pausedRecoveryUnitType || !pausedRecoveryUnitId) {
557
+ state.pausedSessionFile = null;
558
+ state.pausedUnitType = null;
559
+ state.pausedUnitId = null;
560
+ state.pendingCrashRecovery = null;
561
+ notify("Paused session had no recorded unit identity. Skipping tool-call replay and resuming from disk state.");
562
+ return { skippedReplay: true };
563
+ }
564
+
547
565
  const completedPausedUnit = verifyExpectedArtifact(
548
566
  pausedRecoveryUnitType,
549
567
  pausedRecoveryUnitId,
@@ -1228,7 +1246,7 @@ export async function cleanupAfterLoopExit(ctx: ExtensionContext): Promise<void>
1228
1246
  const preserveStepSurface = s.preserveStepSurfaceAfterLoopExit;
1229
1247
  const preserveCompletionSurface = s.completionStopInProgress;
1230
1248
  const preservePausedSurface = s.paused;
1231
- s.currentUnit = null;
1249
+ s.clearCurrentUnit();
1232
1250
  s.active = false;
1233
1251
  deactivateGSD();
1234
1252
  clearUnitTimeout();
@@ -1251,11 +1269,14 @@ export async function cleanupAfterLoopExit(ctx: ExtensionContext): Promise<void>
1251
1269
  // A transient provider-error pause intentionally leaves the paused badge
1252
1270
  // visible so the user still has a resumable auto-mode signal on screen.
1253
1271
  if (!s.paused) {
1254
- if (preserveStepSurface) {
1255
- s.preserveStepSurfaceAfterLoopExit = false;
1256
- } else if (preserveCompletionSurface) {
1272
+ if (preserveCompletionSurface) {
1257
1273
  ctx.ui.setStatus("gsd-auto", undefined);
1258
1274
  s.completionStopInProgress = false;
1275
+ if (preserveStepSurface) {
1276
+ s.preserveStepSurfaceAfterLoopExit = false;
1277
+ }
1278
+ } else if (preserveStepSurface) {
1279
+ s.preserveStepSurfaceAfterLoopExit = false;
1259
1280
  } else {
1260
1281
  ctx.ui.setStatus("gsd-auto", undefined);
1261
1282
  ctx.ui.setWidget("gsd-progress", undefined);
@@ -1969,7 +1990,7 @@ export async function pauseAuto(
1969
1990
  // Non-fatal — best-effort closeout on pause
1970
1991
  logWarning("engine", `unit closeout on pause failed: ${err instanceof Error ? err.message : String(err)}`, { file: "auto.ts" });
1971
1992
  }
1972
- s.currentUnit = null;
1993
+ s.clearCurrentUnit();
1973
1994
  }
1974
1995
 
1975
1996
  // Keep STATE.md aligned with the DB-backed state before releasing pause state.
@@ -2154,7 +2175,10 @@ export function createWiredDispatchAdapter(
2154
2175
  sessionProvider && typeof ctx.modelRegistry?.getProviderAuthMode === "function"
2155
2176
  ? ctx.modelRegistry.getProviderAuthMode(sessionProvider)
2156
2177
  : undefined;
2157
- const activeTools = typeof pi.getActiveTools === "function" ? pi.getActiveTools() : [];
2178
+ // Use baseline snapshot same reason as phases.ts:runDispatch: the live
2179
+ // active set may be narrowed by the prior unit before selectAndApplyModel
2180
+ // restores it, causing false transport-preflight failures (#477 follow-up).
2181
+ const activeTools = getToolBaselineSnapshot(pi);
2158
2182
  // Mirrors runDispatch: deep-planning keeps approval gates in plain chat
2159
2183
  // because structured questions can be cancelled outside the chat turn on
2160
2184
  // some transports.
@@ -2201,6 +2225,9 @@ export function createWiredDispatchAdapter(
2201
2225
  sessionContextWindow,
2202
2226
  sessionProvider,
2203
2227
  modelRegistry,
2228
+ activeTools,
2229
+ sessionAuthMode: authMode,
2230
+ sessionBaseUrl: ctx.model?.baseUrl,
2204
2231
  });
2205
2232
 
2206
2233
  if (action.action === "stop") {
@@ -3284,7 +3311,7 @@ export async function dispatchHookUnit(
3284
3311
  s.stepMode = true;
3285
3312
  s.cmdCtx = ctx as ExtensionCommandContext;
3286
3313
  s.autoStartTime = Date.now();
3287
- s.currentUnit = null;
3314
+ s.clearCurrentUnit();
3288
3315
  s.pendingQuickTasks = [];
3289
3316
  }
3290
3317
 
@@ -3301,12 +3328,12 @@ export async function dispatchHookUnit(
3301
3328
  const hookUnitType = `hook/${hookName}`;
3302
3329
  const hookStartedAt = Date.now();
3303
3330
 
3304
- s.currentUnit = {
3331
+ s.setCurrentUnit({
3305
3332
  type: triggerUnitType,
3306
3333
  id: triggerUnitId,
3307
3334
  startedAt: hookStartedAt,
3308
3335
  workspaceRoot: s.basePath,
3309
- };
3336
+ });
3310
3337
 
3311
3338
  const result = await s.cmdCtx!.newSession({ workspaceRoot: s.basePath });
3312
3339
  if (result.cancelled) {
@@ -3314,12 +3341,12 @@ export async function dispatchHookUnit(
3314
3341
  return false;
3315
3342
  }
3316
3343
 
3317
- s.currentUnit = {
3344
+ s.setCurrentUnit({
3318
3345
  type: hookUnitType,
3319
3346
  id: triggerUnitId,
3320
3347
  startedAt: hookStartedAt,
3321
3348
  workspaceRoot: s.basePath,
3322
- };
3349
+ });
3323
3350
 
3324
3351
  if (hookModel) {
3325
3352
  const availableModels = ctx.modelRegistry.getAvailable();
@@ -699,7 +699,7 @@ export function registerDbTools(pi: ExtensionAPI): void {
699
699
  files: Type.Array(Type.String(), { description: "Array<string> of files likely touched; pass [\"path\"] or [], never a single string" }),
700
700
  verify: Type.String({ description: "Verification command or block" }),
701
701
  inputs: Type.Array(Type.String(), { description: "Array<string> of input files or references; pass [\"path\"] or [], never a single string" }),
702
- expectedOutput: Type.Array(Type.String(), { description: "Array<string> of expected output files or artifacts; pass [\"path\"] or [], never a single string" }),
702
+ expectedOutput: Type.Array(Type.String(), { description: "Array<string> of files this task creates or overwrites; pass [\"path\"] or [], never prose or a single string" }),
703
703
  observabilityImpact: Type.Optional(Type.String({ description: "Task observability impact" })),
704
704
  }), { description: "Planned tasks for the slice" }),
705
705
  // ── Enrichment metadata (optional — defaults to empty) ────────────
@@ -779,7 +779,7 @@ export function registerDbTools(pi: ExtensionAPI): void {
779
779
  files: Type.Array(Type.String(), { description: "Array<string> of files likely touched; pass [\"path\"] or [], never a single string" }),
780
780
  verify: Type.String({ description: "Verification command or block" }),
781
781
  inputs: Type.Array(Type.String(), { description: "Array<string> of input files or references; pass [\"path\"] or [], never a single string" }),
782
- expectedOutput: Type.Array(Type.String(), { description: "Array<string> of expected output files or artifacts; pass [\"path\"] or [], never a single string" }),
782
+ expectedOutput: Type.Array(Type.String(), { description: "Array<string> of files this task creates or overwrites; pass [\"path\"] or [], never prose or a single string" }),
783
783
  observabilityImpact: Type.Optional(Type.String({ description: "Task observability impact" })),
784
784
  // Single-writer v3 audit trail (Stream 2): caller-provided actor identity + causation.
785
785
  actorName: Type.Optional(Type.String({ description: "Caller-provided actor identity for the audit trail (e.g. 'executor-01', 'gsd-orchestrator')" })),
@@ -1160,7 +1160,7 @@ export function registerDbTools(pi: ExtensionAPI): void {
1160
1160
  files: Type.Array(Type.String(), { description: "Files likely touched" }),
1161
1161
  verify: Type.String({ description: "Verification command or block" }),
1162
1162
  inputs: Type.Array(Type.String(), { description: "Input files or references" }),
1163
- expectedOutput: Type.Array(Type.String(), { description: "Expected output files or artifacts" }),
1163
+ expectedOutput: Type.Array(Type.String(), { description: "Files this task creates or overwrites" }),
1164
1164
  }),
1165
1165
  { description: "Tasks to upsert (update existing or insert new)" },
1166
1166
  ),
@@ -1,7 +1,7 @@
1
1
  // Project/App: gsd-pi
2
2
  // File Purpose: Registers GSD extension runtime hooks and token-saving tool policies.
3
3
 
4
- import { existsSync } from "node:fs";
4
+ import { existsSync, mkdirSync } from "node:fs";
5
5
  import { dirname, join } from "node:path";
6
6
  import { pathToFileURL } from "node:url";
7
7
 
@@ -12,12 +12,22 @@ import { ALWAYS_PRESERVED_SHIM_TOOL_NAMES } from "@gsd/pi-ai";
12
12
  import type { GSDEcosystemBeforeAgentStartHandler } from "../ecosystem/gsd-extension-api.js";
13
13
  import { updateSnapshot } from "../ecosystem/gsd-extension-api.js";
14
14
 
15
- import { buildMilestoneFileName, resolveMilestonePath, resolveSliceFile, resolveSlicePath } from "../paths.js";
15
+ import { buildMilestoneFileName, clearPathCache, milestonesDir, resolveMilestonePath, resolveSliceFile, resolveSlicePath } from "../paths.js";
16
16
  import { canonicalToolName, clearDiscussionFlowState, isDepthConfirmationAnswer, isMilestoneDepthVerified, isQueuePhaseActive, markApprovalGateVerified, markDepthVerified, resetWriteGateState, shouldBlockContextWrite, shouldBlockPlanningUnit, shouldBlockQueueExecution, shouldBlockWorktreeWrite, isGateQuestionId, setPendingGate, clearPendingGate, getPendingGate, shouldBlockPendingGate, shouldBlockPendingGateBash, extractDepthVerificationMilestoneId } from "./write-gate.js";
17
17
  import { resolveManifest } from "../unit-context-manifest.js";
18
18
  import { isBlockedStateFile, isBashWriteToStateFile, BLOCKED_WRITE_ERROR } from "../write-intercept.js";
19
19
  import { loadFile, saveFile, formatContinue } from "../files.js";
20
- import { clearToolInvocationError, getAutoRuntimeSnapshot, isAutoActive, isAutoCompletionStopInProgress, isAutoPaused, markToolEnd, markToolStart, recordToolInvocationError } from "../auto-runtime-state.js";
20
+ import {
21
+ clearToolInvocationError,
22
+ getAutoRuntimeSnapshot,
23
+ getSourceObservationStore,
24
+ isAutoActive,
25
+ isAutoCompletionStopInProgress,
26
+ isAutoPaused,
27
+ markToolEnd,
28
+ markToolStart,
29
+ recordToolInvocationError,
30
+ } from "../auto-runtime-state.js";
21
31
 
22
32
  import { checkToolCallLoop, resetToolCallLoopGuard } from "./tool-call-loop-guard.js";
23
33
  import { maybePauseAutoForApprovalGate, resetPendingGatePauseGuard } from "./pending-gate-pause.js";
@@ -39,6 +49,7 @@ import { registerPlanMilestoneSchemaRecovery } from "./plan-milestone-schema-rec
39
49
  import { AUTO_UNIT_SCOPED_TOOLS, RUN_UAT_BROWSER_TOOL_NAMES, isWorkflowAliasTool } from "../auto-unit-tool-scope.js";
40
50
  import { filterToolsForProvider } from "../model-router.js";
41
51
  import { RUN_UAT_READ_ONLY_TOOL_NAMES, RUN_UAT_WORKFLOW_TOOL_NAMES } from "../tool-presentation-plan.js";
52
+ import { injectSourceContextBlockIntoPayload, supportsSourceObservationsForUnit } from "../source-observations.js";
42
53
 
43
54
  let approvalQuestionAbortInFlight = false;
44
55
 
@@ -259,7 +270,19 @@ export function buildRunUatGsdToolSet(
259
270
  ...RUN_UAT_BROWSER_TOOL_NAMES,
260
271
  ],
261
272
  );
262
- return [...new Set(scoped)];
273
+ const resolved = [...new Set(scoped)];
274
+
275
+ const unresolved = RUN_UAT_WORKFLOW_TOOL_NAMES.filter(
276
+ (tool) => !resolved.some((name) => name === tool || (name.startsWith("mcp__") && name.endsWith(`__${tool}`))),
277
+ );
278
+ if (unresolved.length > 0) {
279
+ safetyLogWarning(
280
+ "bootstrap",
281
+ `buildRunUatGsdToolSet: required run-uat workflow tool(s) not found in active/registered surface: ${unresolved.join(", ")}. Session may lack gsd-workflow MCP connection.`,
282
+ );
283
+ }
284
+
285
+ return resolved;
263
286
  }
264
287
 
265
288
  export function buildMinimalGsdWorkflowToolSet(
@@ -462,6 +485,55 @@ function contextBasePath(ctx?: { cwd?: string }): string {
462
485
  return typeof ctx?.cwd === "string" ? ctx.cwd : process.cwd();
463
486
  }
464
487
 
488
+ function beginSourceObservationStoreForCurrentUnit(
489
+ ctx?: { cwd?: string },
490
+ ): ReturnType<typeof getSourceObservationStore> | null {
491
+ if (!isAutoActive()) return null;
492
+ const dash = getAutoRuntimeSnapshot();
493
+ if (!dash.currentUnit) return null;
494
+ if (!supportsSourceObservationsForUnit(dash.currentUnit.type)) return null;
495
+
496
+ const store = getSourceObservationStore();
497
+ store.beginUnit({
498
+ unitType: dash.currentUnit.type,
499
+ unitId: dash.currentUnit.id,
500
+ startedAt: dash.currentUnit.startedAt,
501
+ basePath: dash.currentUnit.workspaceRoot ?? (dash.basePath || contextBasePath(ctx)),
502
+ });
503
+ return store;
504
+ }
505
+
506
+ function refreshSourceObservationAfterMutation(
507
+ canonicalName: string,
508
+ input: unknown,
509
+ ctx?: { cwd?: string },
510
+ ): void {
511
+ if (canonicalName !== "edit" && canonicalName !== "write") return;
512
+ if (!input || typeof input !== "object") return;
513
+
514
+ const store = beginSourceObservationStoreForCurrentUnit(ctx);
515
+ if (!store) return;
516
+ store.observeMutation(input as { path?: unknown; file_path?: unknown });
517
+ }
518
+
519
+ function clearSourceObservationsAfterShell(
520
+ canonicalName: string,
521
+ ): void {
522
+ if (!isAutoActive()) return;
523
+ if (!isShellExecutionTool(canonicalName)) return;
524
+ const dash = getAutoRuntimeSnapshot();
525
+ if (!dash.currentUnit || !supportsSourceObservationsForUnit(dash.currentUnit.type)) return;
526
+ getSourceObservationStore().clear();
527
+ }
528
+
529
+ function isShellExecutionTool(canonicalName: string): boolean {
530
+ return canonicalName === "bash" ||
531
+ canonicalName === "bg_shell" ||
532
+ canonicalName === "async_bash" ||
533
+ canonicalName === "shell" ||
534
+ canonicalName === "powershell";
535
+ }
536
+
465
537
  function activateDeferredApprovalGate(basePath: string): void {
466
538
  if (deferredApprovalGate?.basePath !== basePath) return;
467
539
  setPendingGate(deferredApprovalGate.gateId, basePath);
@@ -485,6 +557,109 @@ function isContextDraftSummarySave(toolName: string, input: unknown): boolean {
485
557
  return (input as { artifact_type?: unknown }).artifact_type === "CONTEXT-DRAFT";
486
558
  }
487
559
 
560
+ type StructuredQuestion = {
561
+ id?: string;
562
+ header?: string;
563
+ question?: string;
564
+ options?: Array<{ label?: string; description?: string }>;
565
+ };
566
+
567
+ type StructuredAnswer = {
568
+ selected?: unknown;
569
+ notes?: unknown;
570
+ };
571
+
572
+ function selectedAnswerLabel(selected: unknown): string {
573
+ if (Array.isArray(selected)) return selected.map(String).join(", ");
574
+ if (selected == null) return "";
575
+ return String(selected);
576
+ }
577
+
578
+ function formatQuestionExchange(
579
+ questions: StructuredQuestion[],
580
+ answers: Record<string, StructuredAnswer> | undefined,
581
+ ): string {
582
+ const lines: string[] = [];
583
+ for (const question of questions) {
584
+ lines.push(`### ${question.header ?? "Question"}`, "", question.question ?? "");
585
+ if (Array.isArray(question.options)) {
586
+ lines.push("");
587
+ for (const opt of question.options) {
588
+ lines.push(`- **${opt.label ?? ""}** — ${opt.description ?? ""}`);
589
+ }
590
+ }
591
+
592
+ const answer = question.id ? answers?.[question.id] : undefined;
593
+ if (answer) {
594
+ lines.push("");
595
+ const selected = selectedAnswerLabel(answer.selected);
596
+ if (selected) lines.push(`**Selected:** ${selected}`);
597
+ if (answer.notes) lines.push(`**Notes:** ${String(answer.notes)}`);
598
+ }
599
+ lines.push("");
600
+ }
601
+ return lines.join("\n");
602
+ }
603
+
604
+ async function ensureMilestoneShell(basePath: string, milestoneId: string): Promise<string> {
605
+ const milestoneDir = resolveMilestonePath(basePath, milestoneId)
606
+ ?? join(milestonesDir(basePath), milestoneId);
607
+ mkdirSync(milestoneDir, { recursive: true });
608
+ clearPathCache();
609
+
610
+ try {
611
+ const { ensureDbOpen } = await import("./dynamic-tools.js");
612
+ if (await ensureDbOpen(basePath)) {
613
+ const { getMilestone, insertMilestone } = await import("../gsd-db.js");
614
+ if (!getMilestone(milestoneId)) {
615
+ insertMilestone({
616
+ id: milestoneId,
617
+ title: `New milestone ${milestoneId}`,
618
+ status: "queued",
619
+ });
620
+ }
621
+ }
622
+ } catch (err) {
623
+ safetyLogWarning("guided", `failed to persist milestone shell for ${milestoneId}: ${(err as Error).message}`);
624
+ }
625
+
626
+ return milestoneDir;
627
+ }
628
+
629
+ async function saveDiscussionQuestionRound(
630
+ basePath: string,
631
+ milestoneId: string,
632
+ questions: StructuredQuestion[],
633
+ details: any,
634
+ ): Promise<void> {
635
+ const milestoneDir = await ensureMilestoneShell(basePath, milestoneId);
636
+ const answers = details?.response?.answers;
637
+ const timestamp = new Date().toISOString();
638
+ const exchange = formatQuestionExchange(questions, answers);
639
+
640
+ const discussionPath = join(milestoneDir, buildMilestoneFileName(milestoneId, "DISCUSSION"));
641
+ const existingDiscussion = await loadFile(discussionPath) ?? `# ${milestoneId} Discussion Log\n\n`;
642
+ await saveFile(
643
+ discussionPath,
644
+ `${existingDiscussion}## Exchange — ${timestamp}\n\n${exchange}---\n\n`,
645
+ );
646
+
647
+ const draftPath = join(milestoneDir, buildMilestoneFileName(milestoneId, "CONTEXT-DRAFT"));
648
+ const existingDraft = await loadFile(draftPath);
649
+ const draftHeader = existingDraft
650
+ ?? [
651
+ `# ${milestoneId}: New milestone ${milestoneId}`,
652
+ "",
653
+ "This draft was captured automatically from structured question responses.",
654
+ "Use it so `/gsd` can resume the in-flight milestone discussion.",
655
+ "",
656
+ ].join("\n");
657
+ await saveFile(
658
+ draftPath,
659
+ `${draftHeader.trimEnd()}\n\n## Captured Question Round — ${timestamp}\n\n${exchange}`,
660
+ );
661
+ }
662
+
488
663
  function withDepthGateDisplayReason<T extends { block: boolean; reason?: string }>(
489
664
  result: T,
490
665
  displayReason = "Depth confirmation is waiting for your answer.",
@@ -577,6 +752,17 @@ export function registerHooks(
577
752
  if (isAutoActive() || preserveCloseoutSurface) {
578
753
  ctx.ui.setWidget("gsd-health", undefined);
579
754
  }
755
+ // Cold start after /quit relaunches with cwd at the project root. When
756
+ // auto-mode is neither active nor paused (its own resume path re-enters the
757
+ // worktree with a lease check — auto.ts:3032), proactively chdir back into
758
+ // the active milestone's worktree so subsequent work isn't stranded at the
759
+ // root. Best-effort and a no-op when already inside a worktree.
760
+ if (!isAutoActive() && !isAutoPaused() && !preserveCloseoutSurface) {
761
+ try {
762
+ const { reenterActiveWorktreeIfNeeded } = await import("../worktree-reentry.js");
763
+ await reenterActiveWorktreeIfNeeded(basePath);
764
+ } catch { /* non-fatal */ }
765
+ }
580
766
  });
581
767
 
582
768
  pi.on("session_switch", async (_event, ctx) => {
@@ -1106,6 +1292,17 @@ export function registerHooks(
1106
1292
  if (isAutoActive() && typeof event.toolCallId === "string") {
1107
1293
  markToolEnd(event.toolCallId);
1108
1294
  }
1295
+ const toolName = canonicalToolName(event.toolName);
1296
+ if (isAutoActive() && toolName === "read" && !event.isError) {
1297
+ const store = beginSourceObservationStoreForCurrentUnit(ctx);
1298
+ if (store) {
1299
+ store.observeRead(event.input);
1300
+ }
1301
+ }
1302
+ if (!event.isError) {
1303
+ refreshSourceObservationAfterMutation(toolName, event.input, ctx);
1304
+ clearSourceObservationsAfterShell(toolName);
1305
+ }
1109
1306
  if (isAutoActive() && event.isError) {
1110
1307
  const resultPayload = ("result" in event ? event.result : undefined) as any;
1111
1308
  const errorText = typeof resultPayload === "string"
@@ -1121,11 +1318,9 @@ export function registerHooks(
1121
1318
  } else if (isAutoActive()) {
1122
1319
  clearToolInvocationError();
1123
1320
  }
1124
- const toolName = canonicalToolName(event.toolName);
1125
1321
  if (toolName !== "ask_user_questions") return;
1126
1322
  const basePath = contextBasePath(ctx);
1127
1323
  const milestoneId = await getDiscussionMilestoneIdFor(basePath);
1128
- const queueActive = isQueuePhaseActive(basePath);
1129
1324
 
1130
1325
  const details = event.details as any;
1131
1326
 
@@ -1204,36 +1399,8 @@ export function registerHooks(
1204
1399
  }
1205
1400
  }
1206
1401
 
1207
- if (!milestoneId && !queueActive) return;
1208
1402
  if (!milestoneId) return;
1209
- const milestoneDir = resolveMilestonePath(basePath, milestoneId);
1210
- if (!milestoneDir) return;
1211
-
1212
- const discussionPath = join(milestoneDir, buildMilestoneFileName(milestoneId, "DISCUSSION"));
1213
- const timestamp = new Date().toISOString();
1214
- const lines: string[] = [`## Exchange — ${timestamp}`, ""];
1215
- for (const question of questions) {
1216
- lines.push(`### ${question.header ?? "Question"}`, "", question.question ?? "");
1217
- if (Array.isArray(question.options)) {
1218
- lines.push("");
1219
- for (const opt of question.options) {
1220
- lines.push(`- **${opt.label}** — ${opt.description ?? ""}`);
1221
- }
1222
- }
1223
- const answer = details.response?.answers?.[question.id];
1224
- if (answer) {
1225
- lines.push("");
1226
- const selected = Array.isArray(answer.selected) ? answer.selected.join(", ") : answer.selected;
1227
- lines.push(`**Selected:** ${selected}`);
1228
- if (answer.notes) {
1229
- lines.push(`**Notes:** ${answer.notes}`);
1230
- }
1231
- }
1232
- lines.push("");
1233
- }
1234
- lines.push("---", "");
1235
- const existing = await loadFile(discussionPath) ?? `# ${milestoneId} Discussion Log\n\n`;
1236
- await saveFile(discussionPath, existing + lines.join("\n"));
1403
+ await saveDiscussionQuestionRound(basePath, milestoneId, questions, details);
1237
1404
  });
1238
1405
 
1239
1406
  pi.on("tool_execution_start", async (event, ctx) => {
@@ -1287,52 +1454,57 @@ export function registerHooks(
1287
1454
  const payload = event.payload as Record<string, unknown> | null;
1288
1455
  if (!payload || typeof payload !== "object") return;
1289
1456
 
1290
- // ── Observation Masking ─────────────────────────────────────────────
1291
- // Replace old tool results with placeholders to reduce context bloat.
1292
- // Only active during auto-mode when context_management.observation_masking is enabled.
1293
- if (isAutoActive()) {
1294
- try {
1295
- const { loadEffectiveGSDPreferences } = await import("../preferences.js");
1296
- const prefs = loadEffectiveGSDPreferences();
1297
- const cmConfig = prefs?.preferences.context_management;
1298
-
1299
- // Observation masking: replace old tool results with placeholders
1300
- if (cmConfig?.observation_masking !== false) {
1301
- const keepTurns = cmConfig?.observation_mask_turns ?? 8;
1302
- const { createObservationMask } = await import("../context-masker.js");
1303
- const mask = createObservationMask(keepTurns);
1304
- const messages = payload.messages;
1305
- if (Array.isArray(messages)) {
1306
- payload.messages = mask(messages);
1307
- }
1457
+ // ── Context Management ──────────────────────────────────────────────
1458
+ // Load preferences once for both masking and truncation.
1459
+ try {
1460
+ const { loadEffectiveGSDPreferences } = await import("../preferences.js");
1461
+ const {
1462
+ createObservationMask,
1463
+ createResponsesInputObservationMask,
1464
+ truncateContextResultMessages,
1465
+ truncateResponsesInputResultItems,
1466
+ } = await import("../context-masker.js");
1467
+ const prefs = loadEffectiveGSDPreferences();
1468
+ const cmConfig = prefs?.preferences.context_management;
1469
+
1470
+ // Observation masking: replace old tool results with placeholders.
1471
+ // Only active during auto-mode when context_management.observation_masking is enabled.
1472
+ if (isAutoActive() && cmConfig?.observation_masking !== false) {
1473
+ const keepTurns = cmConfig?.observation_mask_turns ?? 8;
1474
+ const messages = payload.messages;
1475
+ if (Array.isArray(messages)) {
1476
+ payload.messages = createObservationMask(keepTurns)(messages);
1308
1477
  }
1478
+ const input = payload.input;
1479
+ if (Array.isArray(input)) {
1480
+ payload.input = createResponsesInputObservationMask(keepTurns)(input);
1481
+ }
1482
+ }
1309
1483
 
1310
- // Tool result truncation: cap individual tool result content length.
1311
- // In pi-ai format, toolResult messages have role: "toolResult" and content: TextContent[].
1312
- // Creates new objects to avoid mutating shared conversation state.
1313
- const maxChars = cmConfig?.tool_result_max_chars ?? 800;
1314
- const msgs = payload.messages;
1315
- if (Array.isArray(msgs)) {
1316
- payload.messages = msgs.map((msg: Record<string, unknown>) => {
1317
- // Match toolResult messages (role: "toolResult", content is array of content blocks)
1318
- if (msg?.role === "toolResult" && Array.isArray(msg.content)) {
1319
- const blocks = msg.content as Array<Record<string, unknown>>;
1320
- const totalLen = blocks.reduce((sum: number, b) => sum + (typeof b.text === "string" ? b.text.length : 0), 0);
1321
- if (totalLen > maxChars) {
1322
- const truncated = blocks.map(b => {
1323
- if (typeof b.text === "string" && b.text.length > maxChars) {
1324
- return { ...b, text: b.text.slice(0, maxChars) + "\n…[truncated]" };
1325
- }
1326
- return b;
1327
- });
1328
- return { ...msg, content: truncated };
1329
- }
1330
- }
1331
- return msg;
1332
- });
1484
+ // Tool result truncation: cap individual tool result content length.
1485
+ // Applies in ALL modes (auto + interactive) to prevent context bloat.
1486
+ // In pi-ai format, toolResult messages have role: "toolResult" and content: TextContent[].
1487
+ // Creates new objects to avoid mutating shared conversation state.
1488
+ const maxChars = cmConfig?.tool_result_max_chars ?? 800;
1489
+ const msgs = payload.messages;
1490
+ if (Array.isArray(msgs)) {
1491
+ payload.messages = truncateContextResultMessages(msgs as any, maxChars);
1492
+ }
1493
+ const input = payload.input;
1494
+ if (Array.isArray(input)) {
1495
+ payload.input = truncateResponsesInputResultItems(input as any, maxChars);
1496
+ }
1497
+ } catch { /* non-fatal */ }
1498
+
1499
+ try {
1500
+ if (isAutoActive()) {
1501
+ const sourceContextBlock = getSourceObservationStore().renderActiveBlock();
1502
+ if (sourceContextBlock) {
1503
+ const nextPayload = injectSourceContextBlockIntoPayload(payload, sourceContextBlock);
1504
+ Object.assign(payload, nextPayload);
1333
1505
  }
1334
- } catch { /* non-fatal */ }
1335
- }
1506
+ }
1507
+ } catch { /* non-fatal */ }
1336
1508
 
1337
1509
  // ── Service Tier ────────────────────────────────────────────────────
1338
1510
  const modelId = event.model?.id;
@@ -61,7 +61,7 @@ export const BUNDLED_SKILL_TRIGGERS: Array<{ trigger: string; skill: string }> =
61
61
  { trigger: "Core Web Vitals — fix LCP, CLS, INP; layout shifts; page experience optimization", skill: "core-web-vitals" },
62
62
  { trigger: "GitHub Actions CI/CD — write, run, and debug workflow files; live syntax and run monitoring", skill: "github-workflows" },
63
63
  { trigger: "Comprehensive web quality audit — performance, accessibility, SEO, and best-practices (Lighthouse-style)", skill: "web-quality-audit" },
64
- { trigger: "gsd-browser UAT default browser MCP/CLI for real UI verification, screenshots, assertions, console/network diagnostics", skill: "gsd-browser" },
64
+ { trigger: "gsd-browser opt-in and External MCP UAT screenshots, assertions, console/network diagnostics", skill: "gsd-browser" },
65
65
  { trigger: "Browser automation — open sites, fill forms, click, screenshot, scrape, or test web apps programmatically", skill: "agent-browser" },
66
66
  { trigger: "Review UI code for Web Interface Guidelines compliance — UX, design, and accessibility patterns", skill: "web-design-guidelines" },
67
67
  { trigger: "UI/UX patterns reference — animations, CSS, typography, prefetching, icons (file:line findings)", skill: "userinterface-wiki" },