@opengsd/gsd-pi 1.2.0-dev.b1abb545 → 1.2.0-dev.fb12b103

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 (520) hide show
  1. package/dist/cli-style.d.ts +17 -0
  2. package/dist/cli-style.js +28 -0
  3. package/dist/cli.js +1 -1
  4. package/dist/headless-events.d.ts +4 -2
  5. package/dist/headless-events.js +7 -29
  6. package/dist/models-resolver.d.ts +3 -13
  7. package/dist/models-resolver.js +3 -22
  8. package/dist/resource-loader.js +2 -14
  9. package/dist/resources/.managed-resources-content-hash +1 -1
  10. package/dist/resources/extensions/async-jobs/async-bash-tool.js +30 -64
  11. package/dist/resources/extensions/async-jobs/await-tool.js +80 -12
  12. package/dist/resources/extensions/async-jobs/index.js +65 -0
  13. package/dist/resources/extensions/async-jobs/job-manager.js +12 -1
  14. package/dist/resources/extensions/bg-shell/bg-shell-command.js +6 -6
  15. package/dist/resources/extensions/bg-shell/bg-shell-tool.js +10 -7
  16. package/dist/resources/extensions/bg-shell/overlay.js +9 -6
  17. package/dist/resources/extensions/bg-shell/process-manager.js +54 -25
  18. package/dist/resources/extensions/bg-shell/readiness-detector.js +11 -0
  19. package/dist/resources/extensions/bg-shell/utilities.js +5 -2
  20. package/dist/resources/extensions/browser-tools/engine/managed-gsd-browser.js +209 -88
  21. package/dist/resources/extensions/browser-tools/engine/selection.js +73 -5
  22. package/dist/resources/extensions/browser-tools/index.js +69 -12
  23. package/dist/resources/extensions/claude-code-cli/models.js +9 -0
  24. package/dist/resources/extensions/claude-code-cli/stream-adapter.js +38 -6
  25. package/dist/resources/extensions/gsd/auto/orchestrator.js +40 -9
  26. package/dist/resources/extensions/gsd/auto/phases.js +6 -1
  27. package/dist/resources/extensions/gsd/auto-dispatch.js +12 -1
  28. package/dist/resources/extensions/gsd/auto-model-selection.js +25 -6
  29. package/dist/resources/extensions/gsd/auto-post-unit.js +19 -8
  30. package/dist/resources/extensions/gsd/auto-prompts.js +15 -10
  31. package/dist/resources/extensions/gsd/auto-start.js +21 -21
  32. package/dist/resources/extensions/gsd/auto-tool-tracking.js +18 -0
  33. package/dist/resources/extensions/gsd/auto-unit-tool-scope.js +7 -16
  34. package/dist/resources/extensions/gsd/auto-worktree-repair.js +10 -2
  35. package/dist/resources/extensions/gsd/auto-worktree.js +35 -352
  36. package/dist/resources/extensions/gsd/auto.js +8 -20
  37. package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +3 -2
  38. package/dist/resources/extensions/gsd/bootstrap/dynamic-tools.js +32 -12
  39. package/dist/resources/extensions/gsd/bootstrap/register-extension.js +19 -0
  40. package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +151 -20
  41. package/dist/resources/extensions/gsd/bootstrap/write-gate.js +30 -4
  42. package/dist/resources/extensions/gsd/branch-patterns.js +2 -0
  43. package/dist/resources/extensions/gsd/browser-daemon-auto-prep.js +83 -0
  44. package/dist/resources/extensions/gsd/browser-evidence.js +8 -2
  45. package/dist/resources/extensions/gsd/captures.js +5 -15
  46. package/dist/resources/extensions/gsd/closeout-recovery.js +3 -2
  47. package/dist/resources/extensions/gsd/commands/catalog.js +6 -62
  48. package/dist/resources/extensions/gsd/constants.js +0 -2
  49. package/dist/resources/extensions/gsd/crash-recovery.js +4 -12
  50. package/dist/resources/extensions/gsd/db/engine.js +755 -0
  51. package/dist/resources/extensions/gsd/db/queries.js +372 -0
  52. package/dist/resources/extensions/gsd/db/sql-constants.js +11 -0
  53. package/dist/resources/extensions/gsd/db/writers/cascades.js +194 -0
  54. package/dist/resources/extensions/gsd/db/writers/import-restore.js +182 -0
  55. package/dist/resources/extensions/gsd/db/writers/memory.js +149 -0
  56. package/dist/resources/extensions/gsd/db/writers/reconcile.js +458 -0
  57. package/dist/resources/extensions/gsd/db/writers/status.js +70 -0
  58. package/dist/resources/extensions/gsd/doctor-environment.js +5 -11
  59. package/dist/resources/extensions/gsd/doctor-format.js +9 -6
  60. package/dist/resources/extensions/gsd/doctor-git-checks.js +4 -3
  61. package/dist/resources/extensions/gsd/doctor-runtime-checks.js +21 -16
  62. package/dist/resources/extensions/gsd/error-classifier.js +9 -0
  63. package/dist/resources/extensions/gsd/exec-sandbox.js +30 -10
  64. package/dist/resources/extensions/gsd/git-service.js +1 -0
  65. package/dist/resources/extensions/gsd/gitignore.js +3 -0
  66. package/dist/resources/extensions/gsd/gsd-db.js +171 -2048
  67. package/dist/resources/extensions/gsd/guidance.js +98 -0
  68. package/dist/resources/extensions/gsd/guided-flow.js +51 -5
  69. package/dist/resources/extensions/gsd/mcp-filter.js +2 -19
  70. package/dist/resources/extensions/gsd/mcp-tool-name.js +5 -13
  71. package/dist/resources/extensions/gsd/memory-consolidation-scanner.js +1 -1
  72. package/dist/resources/extensions/gsd/migrate/safety.js +20 -9
  73. package/dist/resources/extensions/gsd/migration-auto-check.js +24 -3
  74. package/dist/resources/extensions/gsd/model-cost-table.js +1 -0
  75. package/dist/resources/extensions/gsd/model-router.js +3 -0
  76. package/dist/resources/extensions/gsd/notification-store.js +11 -4
  77. package/dist/resources/extensions/gsd/parallel-merge.js +14 -11
  78. package/dist/resources/extensions/gsd/parallel-monitor-overlay.js +11 -7
  79. package/dist/resources/extensions/gsd/paths.js +37 -24
  80. package/dist/resources/extensions/gsd/pre-execution-checks.js +91 -3
  81. package/dist/resources/extensions/gsd/preferences-models.js +14 -48
  82. package/dist/resources/extensions/gsd/preferences.js +14 -0
  83. package/dist/resources/extensions/gsd/prompts/complete-slice.md +1 -1
  84. package/dist/resources/extensions/gsd/prompts/plan-slice.md +1 -1
  85. package/dist/resources/extensions/gsd/prompts/refine-slice.md +1 -1
  86. package/dist/resources/extensions/gsd/prompts/replan-slice.md +1 -1
  87. package/dist/resources/extensions/gsd/prompts/run-uat.md +1 -1
  88. package/dist/resources/extensions/gsd/prompts/system.md +5 -2
  89. package/dist/resources/extensions/gsd/provider-error-guidance.js +1 -5
  90. package/dist/resources/extensions/gsd/provider-switch-observer.js +1 -1
  91. package/dist/resources/extensions/gsd/publication.js +87 -0
  92. package/dist/resources/extensions/gsd/recovery-classification.js +41 -87
  93. package/dist/resources/extensions/gsd/safety/destructive-confirmation.js +108 -0
  94. package/dist/resources/extensions/gsd/safety/evidence-collector.js +37 -4
  95. package/dist/resources/extensions/gsd/safety/evidence-cross-ref.js +7 -2
  96. package/dist/resources/extensions/gsd/safety/file-change-validator.js +10 -0
  97. package/dist/resources/extensions/gsd/state-transition-matrix.js +38 -0
  98. package/dist/resources/extensions/gsd/state.js +1 -20
  99. package/dist/resources/extensions/gsd/status-guards.js +56 -8
  100. package/dist/resources/extensions/gsd/stop-notice.js +57 -0
  101. package/dist/resources/extensions/gsd/tool-surface-readiness.js +56 -0
  102. package/dist/resources/extensions/gsd/tools/complete-slice.js +24 -43
  103. package/dist/resources/extensions/gsd/tools/exec-tool.js +10 -8
  104. package/dist/resources/extensions/gsd/tools/plan-slice.js +12 -6
  105. package/dist/resources/extensions/gsd/tools/reopen-milestone.js +11 -29
  106. package/dist/resources/extensions/gsd/tools/reopen-slice.js +14 -33
  107. package/dist/resources/extensions/gsd/tools/skip-slice.js +18 -36
  108. package/dist/resources/extensions/gsd/uat-policy.js +2 -1
  109. package/dist/resources/extensions/gsd/undo.js +8 -7
  110. package/dist/resources/extensions/gsd/unit-closeout.js +138 -0
  111. package/dist/resources/extensions/gsd/unit-context-composer.js +74 -1
  112. package/dist/resources/extensions/gsd/unit-context-manifest.js +4 -27
  113. package/dist/resources/extensions/gsd/unit-registry.js +337 -0
  114. package/dist/resources/extensions/gsd/unit-tool-contracts.js +9 -182
  115. package/dist/resources/extensions/gsd/web-app-uat.js +45 -8
  116. package/dist/resources/extensions/gsd/workflow-tool-surface.js +1 -1
  117. package/dist/resources/extensions/gsd/worktree-git-recovery.js +293 -0
  118. package/dist/resources/extensions/gsd/worktree-lifecycle.js +9 -1
  119. package/dist/resources/extensions/gsd/worktree-manager.js +45 -28
  120. package/dist/resources/extensions/gsd/worktree-placement.js +59 -0
  121. package/dist/resources/extensions/gsd/worktree-reentry.js +12 -8
  122. package/dist/resources/extensions/gsd/worktree-root.js +28 -6
  123. package/dist/resources/extensions/gsd/worktree-safety.js +8 -5
  124. package/dist/resources/extensions/gsd/worktree-session-state.js +12 -11
  125. package/dist/resources/extensions/search-the-web/native-search.js +5 -3
  126. package/dist/resources/extensions/shared/browser-contract.js +59 -0
  127. package/dist/resources/extensions/shared/gsd-browser-cli.js +96 -5
  128. package/dist/resources/shared/package.json +3 -0
  129. package/dist/resources/skills/create-skill/references/executable-code.md +1 -1
  130. package/dist/resources/skills/create-skill/workflows/add-reference.md +8 -3
  131. package/dist/resources/skills/create-skill/workflows/add-script.md +4 -2
  132. package/dist/resources/skills/create-skill/workflows/add-template.md +3 -1
  133. package/dist/resources/skills/create-skill/workflows/add-workflow.md +8 -3
  134. package/dist/resources/skills/create-skill/workflows/upgrade-to-router.md +10 -5
  135. package/dist/resources/skills/create-skill/workflows/verify-skill.md +9 -4
  136. package/dist/resources/skills/gsd-browser/SKILL.md +1 -1
  137. package/dist/resources/skills/spike-wrap-up/SKILL.md +9 -9
  138. package/dist/tsconfig.extensions.tsbuildinfo +1 -1
  139. package/dist/web/standalone/.next/BUILD_ID +1 -1
  140. package/dist/web/standalone/.next/app-path-routes-manifest.json +10 -10
  141. package/dist/web/standalone/.next/build-manifest.json +3 -3
  142. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  143. package/dist/web/standalone/.next/react-loadable-manifest.json +1 -1
  144. package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
  145. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  146. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  147. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  148. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  149. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  150. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  151. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  152. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  153. package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
  154. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
  155. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  156. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
  157. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  158. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  159. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  160. package/dist/web/standalone/.next/server/app/api/boot/route.js.nft.json +1 -1
  161. package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route.js.nft.json +1 -1
  162. package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route.js.nft.json +1 -1
  163. package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route.js.nft.json +1 -1
  164. package/dist/web/standalone/.next/server/app/api/captures/route.js.nft.json +1 -1
  165. package/dist/web/standalone/.next/server/app/api/cleanup/route.js.nft.json +1 -1
  166. package/dist/web/standalone/.next/server/app/api/doctor/route.js.nft.json +1 -1
  167. package/dist/web/standalone/.next/server/app/api/export-data/route.js.nft.json +1 -1
  168. package/dist/web/standalone/.next/server/app/api/files/route.js.nft.json +1 -1
  169. package/dist/web/standalone/.next/server/app/api/forensics/route.js.nft.json +1 -1
  170. package/dist/web/standalone/.next/server/app/api/git/route.js.nft.json +1 -1
  171. package/dist/web/standalone/.next/server/app/api/history/route.js.nft.json +1 -1
  172. package/dist/web/standalone/.next/server/app/api/hooks/route.js.nft.json +1 -1
  173. package/dist/web/standalone/.next/server/app/api/inspect/route.js.nft.json +1 -1
  174. package/dist/web/standalone/.next/server/app/api/knowledge/route.js.nft.json +1 -1
  175. package/dist/web/standalone/.next/server/app/api/live-state/route.js.nft.json +1 -1
  176. package/dist/web/standalone/.next/server/app/api/mcp-connections/route.js.nft.json +1 -1
  177. package/dist/web/standalone/.next/server/app/api/notifications/route.js.nft.json +1 -1
  178. package/dist/web/standalone/.next/server/app/api/onboarding/route.js.nft.json +1 -1
  179. package/dist/web/standalone/.next/server/app/api/projects/route.js.nft.json +1 -1
  180. package/dist/web/standalone/.next/server/app/api/recovery/route.js.nft.json +1 -1
  181. package/dist/web/standalone/.next/server/app/api/session/browser/route.js.nft.json +1 -1
  182. package/dist/web/standalone/.next/server/app/api/session/command/route.js.nft.json +1 -1
  183. package/dist/web/standalone/.next/server/app/api/session/events/route.js.nft.json +1 -1
  184. package/dist/web/standalone/.next/server/app/api/session/manage/route.js.nft.json +1 -1
  185. package/dist/web/standalone/.next/server/app/api/settings-data/route.js.nft.json +1 -1
  186. package/dist/web/standalone/.next/server/app/api/shutdown/route.js.nft.json +1 -1
  187. package/dist/web/standalone/.next/server/app/api/skill-health/route.js.nft.json +1 -1
  188. package/dist/web/standalone/.next/server/app/api/steer/route.js.nft.json +1 -1
  189. package/dist/web/standalone/.next/server/app/api/switch-root/route.js.nft.json +1 -1
  190. package/dist/web/standalone/.next/server/app/api/terminal/sessions/route.js.nft.json +1 -1
  191. package/dist/web/standalone/.next/server/app/api/terminal/stream/route.js.nft.json +1 -1
  192. package/dist/web/standalone/.next/server/app/api/undo/route.js.nft.json +1 -1
  193. package/dist/web/standalone/.next/server/app/api/update/route.js +1 -1
  194. package/dist/web/standalone/.next/server/app/api/update/route.js.nft.json +1 -1
  195. package/dist/web/standalone/.next/server/app/api/visualizer/route.js.nft.json +1 -1
  196. package/dist/web/standalone/.next/server/app/index.html +1 -1
  197. package/dist/web/standalone/.next/server/app/index.rsc +1 -1
  198. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
  199. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +1 -1
  200. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  201. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
  202. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  203. package/dist/web/standalone/.next/server/app-paths-manifest.json +10 -10
  204. package/dist/web/standalone/.next/server/chunks/5124.js +1 -1
  205. package/dist/web/standalone/.next/server/chunks/{5047.js → 5942.js} +2 -2
  206. package/dist/web/standalone/.next/server/chunks/8357.js +1 -1
  207. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  208. package/dist/web/standalone/.next/server/middleware-react-loadable-manifest.js +1 -1
  209. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  210. package/dist/web/standalone/.next/server/pages/500.html +1 -1
  211. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  212. package/dist/web/standalone/.next/static/chunks/{796.cf859a427a2cb2ac.js → 796.e0bdc932325d7e03.js} +1 -1
  213. package/dist/web/standalone/.next/static/chunks/{webpack-fbea77b5f9953368.js → webpack-f0285ce91d4ec9ef.js} +1 -1
  214. package/dist/web/standalone/node_modules/node-pty/build/Makefile +1 -1
  215. package/dist/web/standalone/node_modules/postcss/lib/container.js +18 -26
  216. package/dist/web/standalone/node_modules/postcss/lib/css-syntax-error.js +14 -47
  217. package/dist/web/standalone/node_modules/postcss/lib/declaration.js +4 -4
  218. package/dist/web/standalone/node_modules/postcss/lib/fromJSON.js +3 -3
  219. package/dist/web/standalone/node_modules/postcss/lib/input.js +29 -54
  220. package/dist/web/standalone/node_modules/postcss/lib/lazy-result.js +37 -47
  221. package/dist/web/standalone/node_modules/postcss/lib/map-generator.js +9 -26
  222. package/dist/web/standalone/node_modules/postcss/lib/no-work-result.js +55 -57
  223. package/dist/web/standalone/node_modules/postcss/lib/node.js +31 -99
  224. package/dist/web/standalone/node_modules/postcss/lib/parse.js +1 -1
  225. package/dist/web/standalone/node_modules/postcss/lib/parser.js +9 -10
  226. package/dist/web/standalone/node_modules/postcss/lib/postcss.js +12 -12
  227. package/dist/web/standalone/node_modules/postcss/lib/previous-map.js +11 -30
  228. package/dist/web/standalone/node_modules/postcss/lib/processor.js +7 -7
  229. package/dist/web/standalone/node_modules/postcss/lib/result.js +5 -5
  230. package/dist/web/standalone/node_modules/postcss/lib/rule.js +6 -6
  231. package/dist/web/standalone/node_modules/postcss/lib/stringifier.js +28 -69
  232. package/dist/web/standalone/node_modules/postcss/lib/tokenize.js +2 -6
  233. package/dist/web/standalone/node_modules/postcss/package.json +48 -48
  234. package/dist/web/standalone/package.json +1 -1
  235. package/dist/worktree-cli.js +3 -6
  236. package/dist/worktree-status-banner.js +7 -11
  237. package/package.json +1 -1
  238. package/packages/cloud-mcp-gateway/package.json +2 -2
  239. package/packages/contracts/dist/rpc.d.ts +1 -0
  240. package/packages/contracts/dist/rpc.d.ts.map +1 -1
  241. package/packages/contracts/dist/rpc.js.map +1 -1
  242. package/packages/contracts/dist/workflow.d.ts +4 -0
  243. package/packages/contracts/dist/workflow.d.ts.map +1 -1
  244. package/packages/contracts/dist/workflow.js.map +1 -1
  245. package/packages/contracts/package.json +1 -1
  246. package/packages/daemon/package.json +4 -4
  247. package/packages/gsd-agent-core/package.json +5 -5
  248. package/packages/gsd-agent-modes/dist/modes/interactive/components/tool-execution.d.ts +5 -0
  249. package/packages/gsd-agent-modes/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  250. package/packages/gsd-agent-modes/dist/modes/interactive/components/tool-execution.js +8 -0
  251. package/packages/gsd-agent-modes/dist/modes/interactive/components/tool-execution.js.map +1 -1
  252. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.d.ts.map +1 -1
  253. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.js +7 -0
  254. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.js.map +1 -1
  255. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/input-controller.d.ts.map +1 -1
  256. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/input-controller.js +8 -1
  257. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/input-controller.js.map +1 -1
  258. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-chat-render.d.ts.map +1 -1
  259. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-chat-render.js +11 -1
  260. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-chat-render.js.map +1 -1
  261. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-selectors-auth.d.ts.map +1 -1
  262. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-selectors-auth.js +4 -4
  263. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-selectors-auth.js.map +1 -1
  264. package/packages/gsd-agent-modes/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
  265. package/packages/gsd-agent-modes/dist/modes/rpc/rpc-mode.js +3 -1
  266. package/packages/gsd-agent-modes/dist/modes/rpc/rpc-mode.js.map +1 -1
  267. package/packages/gsd-agent-modes/package.json +7 -7
  268. package/packages/mcp-server/dist/cli.js +6 -3
  269. package/packages/mcp-server/dist/cli.js.map +1 -1
  270. package/packages/mcp-server/dist/workflow-tools.d.ts +8 -0
  271. package/packages/mcp-server/dist/workflow-tools.d.ts.map +1 -1
  272. package/packages/mcp-server/dist/workflow-tools.js +46 -21
  273. package/packages/mcp-server/dist/workflow-tools.js.map +1 -1
  274. package/packages/mcp-server/package.json +3 -3
  275. package/packages/native/package.json +1 -1
  276. package/packages/pi-agent-core/dist/harness/env/nodejs.d.ts +1 -0
  277. package/packages/pi-agent-core/dist/harness/env/nodejs.d.ts.map +1 -1
  278. package/packages/pi-agent-core/dist/harness/env/nodejs.js +34 -3
  279. package/packages/pi-agent-core/dist/harness/env/nodejs.js.map +1 -1
  280. package/packages/pi-agent-core/dist/index.d.ts +1 -0
  281. package/packages/pi-agent-core/dist/index.d.ts.map +1 -1
  282. package/packages/pi-agent-core/dist/index.js +3 -0
  283. package/packages/pi-agent-core/dist/index.js.map +1 -1
  284. package/packages/pi-agent-core/package.json +1 -1
  285. package/packages/pi-ai/dist/image-models.generated.d.ts +2 -2
  286. package/packages/pi-ai/dist/image-models.generated.js +6 -6
  287. package/packages/pi-ai/dist/image-models.generated.js.map +1 -1
  288. package/packages/pi-ai/dist/models.generated.d.ts +478 -484
  289. package/packages/pi-ai/dist/models.generated.d.ts.map +1 -1
  290. package/packages/pi-ai/dist/models.generated.js +500 -533
  291. package/packages/pi-ai/dist/models.generated.js.map +1 -1
  292. package/packages/pi-ai/package.json +1 -1
  293. package/packages/pi-coding-agent/dist/core/auth-storage.d.ts +2 -2
  294. package/packages/pi-coding-agent/dist/core/auth-storage.d.ts.map +1 -1
  295. package/packages/pi-coding-agent/dist/core/auth-storage.js +19 -13
  296. package/packages/pi-coding-agent/dist/core/auth-storage.js.map +1 -1
  297. package/packages/pi-coding-agent/dist/core/capability-patches.d.ts.map +1 -1
  298. package/packages/pi-coding-agent/dist/core/capability-patches.js +3 -1
  299. package/packages/pi-coding-agent/dist/core/capability-patches.js.map +1 -1
  300. package/packages/pi-coding-agent/dist/core/provider-readiness.d.ts.map +1 -1
  301. package/packages/pi-coding-agent/dist/core/provider-readiness.js +13 -6
  302. package/packages/pi-coding-agent/dist/core/provider-readiness.js.map +1 -1
  303. package/packages/pi-coding-agent/dist/core/tools/bash.d.ts +11 -0
  304. package/packages/pi-coding-agent/dist/core/tools/bash.d.ts.map +1 -1
  305. package/packages/pi-coding-agent/dist/core/tools/bash.js +53 -11
  306. package/packages/pi-coding-agent/dist/core/tools/bash.js.map +1 -1
  307. package/packages/pi-coding-agent/dist/index.d.ts +1 -1
  308. package/packages/pi-coding-agent/dist/index.d.ts.map +1 -1
  309. package/packages/pi-coding-agent/dist/index.js +1 -1
  310. package/packages/pi-coding-agent/dist/index.js.map +1 -1
  311. package/packages/pi-coding-agent/dist/utils/shell.d.ts +28 -2
  312. package/packages/pi-coding-agent/dist/utils/shell.d.ts.map +1 -1
  313. package/packages/pi-coding-agent/dist/utils/shell.js +56 -10
  314. package/packages/pi-coding-agent/dist/utils/shell.js.map +1 -1
  315. package/packages/pi-coding-agent/package.json +7 -7
  316. package/packages/pi-tui/dist/tui.d.ts.map +1 -1
  317. package/packages/pi-tui/dist/tui.js +9 -0
  318. package/packages/pi-tui/dist/tui.js.map +1 -1
  319. package/packages/pi-tui/package.json +2 -2
  320. package/packages/rpc-client/package.json +2 -2
  321. package/pkg/package.json +1 -1
  322. package/src/resources/extensions/async-jobs/async-bash-cancel.test.ts +360 -0
  323. package/src/resources/extensions/async-jobs/async-bash-tool.ts +33 -56
  324. package/src/resources/extensions/async-jobs/await-tool.test.ts +139 -0
  325. package/src/resources/extensions/async-jobs/await-tool.ts +82 -12
  326. package/src/resources/extensions/async-jobs/index.ts +79 -0
  327. package/src/resources/extensions/async-jobs/job-manager.ts +21 -1
  328. package/src/resources/extensions/bg-shell/bg-shell-command.ts +6 -6
  329. package/src/resources/extensions/bg-shell/bg-shell-tool.ts +10 -6
  330. package/src/resources/extensions/bg-shell/overlay.ts +9 -5
  331. package/src/resources/extensions/bg-shell/process-manager.ts +50 -25
  332. package/src/resources/extensions/bg-shell/readiness-detector.ts +12 -0
  333. package/src/resources/extensions/bg-shell/tests/lifecycle-and-utilities.test.ts +48 -1
  334. package/src/resources/extensions/bg-shell/utilities.ts +5 -2
  335. package/src/resources/extensions/browser-tools/engine/managed-gsd-browser.ts +265 -98
  336. package/src/resources/extensions/browser-tools/engine/selection.ts +90 -4
  337. package/src/resources/extensions/browser-tools/index.ts +71 -13
  338. package/src/resources/extensions/browser-tools/tests/browser-engine-selection.test.mjs +83 -13
  339. package/src/resources/extensions/browser-tools/tests/gsd-browser-launch-config.test.mjs +29 -1
  340. package/src/resources/extensions/browser-tools/tests/managed-gsd-browser-tools.test.mjs +136 -0
  341. package/src/resources/extensions/claude-code-cli/models.ts +9 -0
  342. package/src/resources/extensions/claude-code-cli/stream-adapter.ts +40 -4
  343. package/src/resources/extensions/claude-code-cli/tests/stream-adapter.test.ts +28 -0
  344. package/src/resources/extensions/gsd/auto/loop-deps.ts +1 -1
  345. package/src/resources/extensions/gsd/auto/orchestrator.ts +46 -10
  346. package/src/resources/extensions/gsd/auto/phases.ts +10 -1
  347. package/src/resources/extensions/gsd/auto-dispatch.ts +12 -0
  348. package/src/resources/extensions/gsd/auto-model-selection.ts +25 -5
  349. package/src/resources/extensions/gsd/auto-post-unit.ts +25 -7
  350. package/src/resources/extensions/gsd/auto-prompts.ts +40 -26
  351. package/src/resources/extensions/gsd/auto-start.ts +21 -22
  352. package/src/resources/extensions/gsd/auto-tool-tracking.ts +19 -0
  353. package/src/resources/extensions/gsd/auto-unit-tool-scope.ts +10 -17
  354. package/src/resources/extensions/gsd/auto-worktree-repair.ts +13 -2
  355. package/src/resources/extensions/gsd/auto-worktree.ts +41 -364
  356. package/src/resources/extensions/gsd/auto.ts +20 -24
  357. package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +3 -5
  358. package/src/resources/extensions/gsd/bootstrap/dynamic-tools.ts +33 -12
  359. package/src/resources/extensions/gsd/bootstrap/register-extension.ts +24 -0
  360. package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +180 -15
  361. package/src/resources/extensions/gsd/bootstrap/write-gate.ts +29 -3
  362. package/src/resources/extensions/gsd/branch-patterns.ts +3 -0
  363. package/src/resources/extensions/gsd/browser-daemon-auto-prep.ts +108 -0
  364. package/src/resources/extensions/gsd/browser-evidence.ts +18 -2
  365. package/src/resources/extensions/gsd/captures.ts +5 -16
  366. package/src/resources/extensions/gsd/closeout-recovery.ts +2 -1
  367. package/src/resources/extensions/gsd/commands/catalog.ts +6 -68
  368. package/src/resources/extensions/gsd/constants.ts +0 -3
  369. package/src/resources/extensions/gsd/crash-recovery.ts +3 -9
  370. package/src/resources/extensions/gsd/db/engine.ts +809 -0
  371. package/src/resources/extensions/gsd/db/queries.ts +453 -0
  372. package/src/resources/extensions/gsd/db/sql-constants.ts +12 -0
  373. package/src/resources/extensions/gsd/db/writers/cascades.ts +237 -0
  374. package/src/resources/extensions/gsd/db/writers/import-restore.ts +310 -0
  375. package/src/resources/extensions/gsd/db/writers/memory.ts +220 -0
  376. package/src/resources/extensions/gsd/db/writers/reconcile.ts +500 -0
  377. package/src/resources/extensions/gsd/db/writers/status.ts +88 -0
  378. package/src/resources/extensions/gsd/doctor-environment.ts +5 -13
  379. package/src/resources/extensions/gsd/doctor-format.ts +12 -7
  380. package/src/resources/extensions/gsd/doctor-git-checks.ts +3 -3
  381. package/src/resources/extensions/gsd/doctor-runtime-checks.ts +22 -17
  382. package/src/resources/extensions/gsd/error-classifier.ts +11 -0
  383. package/src/resources/extensions/gsd/exec-sandbox.ts +49 -9
  384. package/src/resources/extensions/gsd/git-service.ts +1 -0
  385. package/src/resources/extensions/gsd/gitignore.ts +3 -0
  386. package/src/resources/extensions/gsd/gsd-db.ts +173 -2373
  387. package/src/resources/extensions/gsd/guidance.ts +139 -0
  388. package/src/resources/extensions/gsd/guided-flow.ts +50 -5
  389. package/src/resources/extensions/gsd/mcp-filter.ts +2 -23
  390. package/src/resources/extensions/gsd/mcp-tool-name.ts +6 -11
  391. package/src/resources/extensions/gsd/memory-consolidation-scanner.ts +1 -1
  392. package/src/resources/extensions/gsd/migrate/safety.ts +18 -7
  393. package/src/resources/extensions/gsd/migration-auto-check.ts +28 -3
  394. package/src/resources/extensions/gsd/model-cost-table.ts +1 -0
  395. package/src/resources/extensions/gsd/model-router.ts +3 -0
  396. package/src/resources/extensions/gsd/notification-store.ts +26 -3
  397. package/src/resources/extensions/gsd/parallel-merge.ts +12 -9
  398. package/src/resources/extensions/gsd/parallel-monitor-overlay.ts +10 -7
  399. package/src/resources/extensions/gsd/paths.ts +42 -22
  400. package/src/resources/extensions/gsd/pre-execution-checks.ts +109 -3
  401. package/src/resources/extensions/gsd/preferences-models.ts +12 -47
  402. package/src/resources/extensions/gsd/preferences.ts +18 -0
  403. package/src/resources/extensions/gsd/prompts/complete-slice.md +1 -1
  404. package/src/resources/extensions/gsd/prompts/plan-slice.md +1 -1
  405. package/src/resources/extensions/gsd/prompts/refine-slice.md +1 -1
  406. package/src/resources/extensions/gsd/prompts/replan-slice.md +1 -1
  407. package/src/resources/extensions/gsd/prompts/run-uat.md +1 -1
  408. package/src/resources/extensions/gsd/prompts/system.md +5 -2
  409. package/src/resources/extensions/gsd/provider-error-guidance.ts +4 -9
  410. package/src/resources/extensions/gsd/provider-switch-observer.ts +1 -1
  411. package/src/resources/extensions/gsd/publication.ts +122 -0
  412. package/src/resources/extensions/gsd/recovery-classification.ts +47 -88
  413. package/src/resources/extensions/gsd/safety/destructive-confirmation.ts +134 -0
  414. package/src/resources/extensions/gsd/safety/evidence-collector.ts +36 -4
  415. package/src/resources/extensions/gsd/safety/evidence-cross-ref.ts +7 -2
  416. package/src/resources/extensions/gsd/safety/file-change-validator.ts +14 -0
  417. package/src/resources/extensions/gsd/state-transition-matrix.ts +42 -0
  418. package/src/resources/extensions/gsd/state.ts +4 -21
  419. package/src/resources/extensions/gsd/status-guards.ts +59 -8
  420. package/src/resources/extensions/gsd/stop-notice.ts +75 -0
  421. package/src/resources/extensions/gsd/tests/auto-loop.test.ts +123 -0
  422. package/src/resources/extensions/gsd/tests/auto-model-selection.test.ts +22 -0
  423. package/src/resources/extensions/gsd/tests/auto-orchestrator.test.ts +16 -19
  424. package/src/resources/extensions/gsd/tests/auto-paused-ui-cleanup.test.ts +3 -1
  425. package/src/resources/extensions/gsd/tests/auto-post-unit-evidence-crossref-4909.test.ts +46 -0
  426. package/src/resources/extensions/gsd/tests/auto-worktree-registry.test.ts +2 -2
  427. package/src/resources/extensions/gsd/tests/auto-worktree-repair.test.ts +4 -2
  428. package/src/resources/extensions/gsd/tests/browser-automation-contract-fixture.ts +39 -0
  429. package/src/resources/extensions/gsd/tests/browser-contract.test.ts +44 -0
  430. package/src/resources/extensions/gsd/tests/browser-daemon-auto-prep.test.ts +144 -0
  431. package/src/resources/extensions/gsd/tests/checkout-branch-stash-guard.test.ts +66 -1
  432. package/src/resources/extensions/gsd/tests/clear-stale-autostart.test.ts +44 -0
  433. package/src/resources/extensions/gsd/tests/commands-verdict.test.ts +8 -7
  434. package/src/resources/extensions/gsd/tests/destructive-confirmation.test.ts +303 -0
  435. package/src/resources/extensions/gsd/tests/dispatch-run-uat-browser-tools.test.ts +2 -1
  436. package/src/resources/extensions/gsd/tests/dynamic-bash-no-cap.test.ts +132 -0
  437. package/src/resources/extensions/gsd/tests/evidence-xref-gsd-exec.test.ts +157 -0
  438. package/src/resources/extensions/gsd/tests/exec-graceful-kill.test.ts +193 -0
  439. package/src/resources/extensions/gsd/tests/exec-tool.test.ts +29 -1
  440. package/src/resources/extensions/gsd/tests/extension-bootstrap-isolation.test.ts +35 -1
  441. package/src/resources/extensions/gsd/tests/file-change-validator.test.ts +33 -1
  442. package/src/resources/extensions/gsd/tests/guidance.test.ts +125 -0
  443. package/src/resources/extensions/gsd/tests/integration/auto-worktree-milestone-merge.test.ts +58 -15
  444. package/src/resources/extensions/gsd/tests/integration/auto-worktree.test.ts +74 -59
  445. package/src/resources/extensions/gsd/tests/integration/git-service.test.ts +3 -2
  446. package/src/resources/extensions/gsd/tests/integration/gsd-integration-fixture.ts +80 -0
  447. package/src/resources/extensions/gsd/tests/mcp-project-config.test.ts +3 -1
  448. package/src/resources/extensions/gsd/tests/migration-auto-check.test.ts +85 -1
  449. package/src/resources/extensions/gsd/tests/model-unittype-mapping.test.ts +32 -1
  450. package/src/resources/extensions/gsd/tests/notification-store.test.ts +32 -0
  451. package/src/resources/extensions/gsd/tests/oauth-api-model-routing.test.ts +167 -0
  452. package/src/resources/extensions/gsd/tests/pre-execution-checks.test.ts +193 -1
  453. package/src/resources/extensions/gsd/tests/provider-error-guidance.test.ts +3 -3
  454. package/src/resources/extensions/gsd/tests/publication.test.ts +120 -0
  455. package/src/resources/extensions/gsd/tests/recovery-classification-illegal-transition.test.ts +30 -0
  456. package/src/resources/extensions/gsd/tests/register-hooks-depth-verification.test.ts +248 -1
  457. package/src/resources/extensions/gsd/tests/runtime-invariant-modules.test.ts +1 -0
  458. package/src/resources/extensions/gsd/tests/safety-harness-false-positives.test.ts +38 -0
  459. package/src/resources/extensions/gsd/tests/session-switch-clears-pending-autostart.test.ts +108 -0
  460. package/src/resources/extensions/gsd/tests/single-writer-invariant.test.ts +43 -6
  461. package/src/resources/extensions/gsd/tests/state-transition-matrix.test.ts +36 -0
  462. package/src/resources/extensions/gsd/tests/status-guards.test.ts +38 -0
  463. package/src/resources/extensions/gsd/tests/stop-notice.test.ts +70 -0
  464. package/src/resources/extensions/gsd/tests/token-tool-gating.test.ts +76 -0
  465. package/src/resources/extensions/gsd/tests/tool-invocation-error-loop-break.test.ts +8 -0
  466. package/src/resources/extensions/gsd/tests/tool-surface-readiness.test.ts +155 -0
  467. package/src/resources/extensions/gsd/tests/uat-policy.test.ts +24 -29
  468. package/src/resources/extensions/gsd/tests/unit-closeout.test.ts +209 -0
  469. package/src/resources/extensions/gsd/tests/unit-context-composer.test.ts +67 -2
  470. package/src/resources/extensions/gsd/tests/unit-registry.test.ts +163 -0
  471. package/src/resources/extensions/gsd/tests/web-app-uat.test.ts +44 -1
  472. package/src/resources/extensions/gsd/tests/workflow-mcp.test.ts +2 -2
  473. package/src/resources/extensions/gsd/tests/workflow-tool-executors.test.ts +2 -2
  474. package/src/resources/extensions/gsd/tests/worktree-lifecycle.test.ts +41 -4
  475. package/src/resources/extensions/gsd/tests/worktree-manager.test.ts +22 -1
  476. package/src/resources/extensions/gsd/tests/worktree-placement.test.ts +113 -0
  477. package/src/resources/extensions/gsd/tests/worktree-reentry.test.ts +1 -1
  478. package/src/resources/extensions/gsd/tests/worktree-safety.test.ts +3 -1
  479. package/src/resources/extensions/gsd/tests/worktree-symlink-removal.test.ts +12 -6
  480. package/src/resources/extensions/gsd/tests/worktree-teardown-safety.test.ts +2 -2
  481. package/src/resources/extensions/gsd/tests/write-gate.test.ts +42 -0
  482. package/src/resources/extensions/gsd/tool-surface-readiness.ts +76 -0
  483. package/src/resources/extensions/gsd/tools/complete-slice.ts +23 -58
  484. package/src/resources/extensions/gsd/tools/exec-tool.ts +9 -8
  485. package/src/resources/extensions/gsd/tools/plan-slice.ts +12 -6
  486. package/src/resources/extensions/gsd/tools/reopen-milestone.ts +11 -38
  487. package/src/resources/extensions/gsd/tools/reopen-slice.ts +14 -42
  488. package/src/resources/extensions/gsd/tools/skip-slice.ts +18 -44
  489. package/src/resources/extensions/gsd/uat-policy.ts +2 -1
  490. package/src/resources/extensions/gsd/undo.ts +9 -8
  491. package/src/resources/extensions/gsd/unit-closeout.ts +201 -0
  492. package/src/resources/extensions/gsd/unit-context-composer.ts +111 -1
  493. package/src/resources/extensions/gsd/unit-context-manifest.ts +4 -28
  494. package/src/resources/extensions/gsd/unit-registry.ts +412 -0
  495. package/src/resources/extensions/gsd/unit-tool-contracts.ts +27 -192
  496. package/src/resources/extensions/gsd/web-app-uat.ts +51 -8
  497. package/src/resources/extensions/gsd/workflow-tool-surface.ts +4 -1
  498. package/src/resources/extensions/gsd/worktree-git-recovery.ts +314 -0
  499. package/src/resources/extensions/gsd/worktree-lifecycle.ts +10 -1
  500. package/src/resources/extensions/gsd/worktree-manager.ts +47 -28
  501. package/src/resources/extensions/gsd/worktree-placement.ts +63 -0
  502. package/src/resources/extensions/gsd/worktree-reentry.ts +10 -7
  503. package/src/resources/extensions/gsd/worktree-root.ts +29 -6
  504. package/src/resources/extensions/gsd/worktree-safety.ts +8 -5
  505. package/src/resources/extensions/gsd/worktree-session-state.ts +11 -11
  506. package/src/resources/extensions/search-the-web/native-search.ts +5 -3
  507. package/src/resources/extensions/shared/browser-contract.ts +66 -0
  508. package/src/resources/extensions/shared/gsd-browser-cli.ts +119 -5
  509. package/src/resources/shared/package.json +3 -0
  510. package/src/resources/skills/create-skill/references/executable-code.md +1 -1
  511. package/src/resources/skills/create-skill/workflows/add-reference.md +8 -3
  512. package/src/resources/skills/create-skill/workflows/add-script.md +4 -2
  513. package/src/resources/skills/create-skill/workflows/add-template.md +3 -1
  514. package/src/resources/skills/create-skill/workflows/add-workflow.md +8 -3
  515. package/src/resources/skills/create-skill/workflows/upgrade-to-router.md +10 -5
  516. package/src/resources/skills/create-skill/workflows/verify-skill.md +9 -4
  517. package/src/resources/skills/gsd-browser/SKILL.md +1 -1
  518. package/src/resources/skills/spike-wrap-up/SKILL.md +9 -9
  519. /package/dist/web/standalone/.next/static/{3PtrU9qGPEXwNLWkIyiqk → mU4QIDlpVHDdjDpeEKh5W}/_buildManifest.js +0 -0
  520. /package/dist/web/standalone/.next/static/{3PtrU9qGPEXwNLWkIyiqk → mU4QIDlpVHDdjDpeEKh5W}/_ssgManifest.js +0 -0
@@ -5517,6 +5517,129 @@ test("dispatch Worktree Safety wins before stuck detection for execute-task with
5517
5517
  );
5518
5518
  });
5519
5519
 
5520
+ test("dispatch Worktree Safety honors degraded branch fallback instead of demanding the canonical worktree root", async (t) => {
5521
+ _resetPendingResolve();
5522
+
5523
+ const ctx = makeMockCtx();
5524
+ const pi = makeMockPi();
5525
+ const notifications: string[] = [];
5526
+ ctx.ui.notify = (msg: string) => { notifications.push(msg); };
5527
+
5528
+ // Worktree creation failed and the lifecycle fell back to the milestone
5529
+ // branch in the project root. The safety gate must validate against that
5530
+ // effective branch mode, not the configured worktree mode.
5531
+ const projectRoot = mkdtempSync(join(tmpdir(), "gsd-wt-safety-degraded-"));
5532
+ t.after(() => rmSync(projectRoot, { recursive: true, force: true }));
5533
+
5534
+ const s = makeLoopSession({
5535
+ basePath: projectRoot,
5536
+ originalBasePath: projectRoot,
5537
+ canonicalProjectRoot: projectRoot,
5538
+ isolationDegraded: true,
5539
+ });
5540
+ const deps = makeMockDeps({
5541
+ getIsolationMode: () => "worktree",
5542
+ });
5543
+ const result = await runDispatch(
5544
+ {
5545
+ ctx,
5546
+ pi,
5547
+ s,
5548
+ deps,
5549
+ prefs: undefined,
5550
+ iteration: 1,
5551
+ flowId: "test-flow",
5552
+ nextSeq: () => 1,
5553
+ },
5554
+ {
5555
+ state: {
5556
+ phase: "executing",
5557
+ activeMilestone: { id: "M001", title: "Test", status: "active" },
5558
+ activeSlice: { id: "S01", title: "Slice 1" },
5559
+ activeTask: { id: "T01" },
5560
+ registry: [{ id: "M001", status: "active" }],
5561
+ blockers: [],
5562
+ } as any,
5563
+ mid: "M001",
5564
+ midTitle: "Test",
5565
+ },
5566
+ {
5567
+ recentUnits: [],
5568
+ stuckRecoveryAttempts: 0,
5569
+ consecutiveFinalizeTimeouts: 0,
5570
+ },
5571
+ );
5572
+
5573
+ assert.equal(result.action, "next", "dispatch must proceed under degraded branch isolation");
5574
+ assert.ok(
5575
+ !notifications.some((n) => n.includes("Worktree Safety failed")),
5576
+ "degraded branch fallback must not trip a false invalid-root",
5577
+ );
5578
+ assert.ok(!deps.callLog.includes("stopAuto"), "auto-mode must not stop on the degraded fallback");
5579
+ });
5580
+
5581
+ test("dispatch Worktree Safety honors stranded branch recovery instead of demanding the canonical worktree root", async (t) => {
5582
+ _resetPendingResolve();
5583
+
5584
+ const ctx = makeMockCtx();
5585
+ const pi = makeMockPi();
5586
+ const notifications: string[] = [];
5587
+ ctx.ui.notify = (msg: string) => { notifications.push(msg); };
5588
+
5589
+ // Bootstrap adopted stranded work by checking out the milestone branch in
5590
+ // the project root (strandedRecoveryIsolationMode = "branch"). Isolation is
5591
+ // NOT degraded — the adoption is intentional. The safety gate must validate
5592
+ // against the effective branch mode, not the configured worktree mode.
5593
+ const projectRoot = mkdtempSync(join(tmpdir(), "gsd-wt-safety-stranded-"));
5594
+ t.after(() => rmSync(projectRoot, { recursive: true, force: true }));
5595
+
5596
+ const s = makeLoopSession({
5597
+ basePath: projectRoot,
5598
+ originalBasePath: projectRoot,
5599
+ canonicalProjectRoot: projectRoot,
5600
+ strandedRecoveryIsolationMode: "branch",
5601
+ });
5602
+ const deps = makeMockDeps({
5603
+ getIsolationMode: () => "worktree",
5604
+ });
5605
+ const result = await runDispatch(
5606
+ {
5607
+ ctx,
5608
+ pi,
5609
+ s,
5610
+ deps,
5611
+ prefs: undefined,
5612
+ iteration: 1,
5613
+ flowId: "test-flow",
5614
+ nextSeq: () => 1,
5615
+ },
5616
+ {
5617
+ state: {
5618
+ phase: "executing",
5619
+ activeMilestone: { id: "M001", title: "Test", status: "active" },
5620
+ activeSlice: { id: "S01", title: "Slice 1" },
5621
+ activeTask: { id: "T01" },
5622
+ registry: [{ id: "M001", status: "active" }],
5623
+ blockers: [],
5624
+ } as any,
5625
+ mid: "M001",
5626
+ midTitle: "Test",
5627
+ },
5628
+ {
5629
+ recentUnits: [],
5630
+ stuckRecoveryAttempts: 0,
5631
+ consecutiveFinalizeTimeouts: 0,
5632
+ },
5633
+ );
5634
+
5635
+ assert.equal(result.action, "next", "dispatch must proceed under stranded branch recovery");
5636
+ assert.ok(
5637
+ !notifications.some((n) => n.includes("Worktree Safety failed")),
5638
+ "stranded branch recovery must not trip a false invalid-root",
5639
+ );
5640
+ assert.ok(!deps.callLog.includes("stopAuto"), "auto-mode must not stop on stranded branch recovery");
5641
+ });
5642
+
5520
5643
  test("runDispatch runs stuck detection while artifact verification retry is pending (#5719)", async (t) => {
5521
5644
  _resetPendingResolve();
5522
5645
 
@@ -857,3 +857,25 @@ test("resolveModelId: claude-code wins when session is claude-code regardless of
857
857
  assert.ok(result, "should resolve a model");
858
858
  assert.equal(result.provider, "claude-code", "claude-code must win when it is the session provider");
859
859
  });
860
+
861
+ test("resolveModelId: openai-codex wins over openai for bare GPT IDs when both are available", () => {
862
+ const availableModels = [
863
+ { id: "gpt-5.5", provider: "openai" },
864
+ { id: "gpt-5.5", provider: "openai-codex" },
865
+ ];
866
+
867
+ const result = resolveModelId("gpt-5.5", availableModels, undefined);
868
+ assert.ok(result, "should resolve a model");
869
+ assert.equal(result.provider, "openai-codex", "ChatGPT OAuth must win over platform API for bare IDs");
870
+ });
871
+
872
+ test("resolveModelId: github-copilot wins over openai when both offer the same GPT model", () => {
873
+ const availableModels = [
874
+ { id: "gpt-5.5", provider: "openai" },
875
+ { id: "gpt-5.5", provider: "github-copilot" },
876
+ ];
877
+
878
+ const result = resolveModelId("gpt-5.5", availableModels, undefined);
879
+ assert.ok(result);
880
+ assert.equal(result.provider, "github-copilot");
881
+ });
@@ -518,13 +518,12 @@ test("advance() is idempotent for the same active unit", async (t) => {
518
518
  if (first.kind === "advanced") {
519
519
  assert.deepEqual(first.unit, { unitType: "execute-task", unitId: "M001/S01/T01" });
520
520
  }
521
- assert.equal(second.kind, "blocked");
522
- if (second.kind !== "blocked") return;
521
+ assert.equal(second.kind, "skipped");
522
+ if (second.kind !== "skipped") return;
523
523
  assert.equal(second.reason, "idempotent advance: unit already active");
524
- assert.equal(second.action, "pause");
525
524
  });
526
525
 
527
- test("idempotency block fires with its own reason before saturation", async (t) => {
526
+ test("idempotency skip fires with its own reason before saturation", async (t) => {
528
527
  const f = makeFixture();
529
528
  t.after(() => f.cleanup());
530
529
 
@@ -532,10 +531,9 @@ test("idempotency block fires with its own reason before saturation", async (t)
532
531
  const second = await f.orchestrator.advance();
533
532
 
534
533
  assert.equal(first.kind, "advanced");
535
- assert.equal(second.kind, "blocked");
536
- if (second.kind !== "blocked") return;
534
+ assert.equal(second.kind, "skipped");
535
+ if (second.kind !== "skipped") return;
537
536
  assert.equal(second.reason, "idempotent advance: unit already active");
538
- assert.equal(second.action, "pause");
539
537
  });
540
538
 
541
539
  test("completeActiveUnit clears in-flight idempotency and stops stale same-unit advance", async (t) => {
@@ -671,12 +669,12 @@ test("resume() clears idempotent lock and allows re-advance", async (t) => {
671
669
  t.after(() => f.cleanup());
672
670
 
673
671
  const first = await f.orchestrator.advance();
674
- const blocked = await f.orchestrator.advance();
672
+ const idempotent = await f.orchestrator.advance();
675
673
  const resumed = await f.orchestrator.resume();
676
674
  const next = await f.orchestrator.advance();
677
675
 
678
676
  assert.equal(first.kind, "advanced");
679
- assert.equal(blocked.kind, "blocked");
677
+ assert.equal(idempotent.kind, "skipped");
680
678
  assert.equal(resumed.kind, "resumed");
681
679
  assert.equal(next.kind, "advanced");
682
680
  });
@@ -686,11 +684,11 @@ test("start() clears prior idempotent lock", async (t) => {
686
684
  t.after(() => f.cleanup());
687
685
 
688
686
  await f.orchestrator.advance();
689
- const blocked = await f.orchestrator.advance();
687
+ const idempotent = await f.orchestrator.advance();
690
688
  const restarted = await f.orchestrator.start(SESSION_CONTEXT);
691
689
  const next = await f.orchestrator.advance();
692
690
 
693
- assert.equal(blocked.kind, "blocked");
691
+ assert.equal(idempotent.kind, "skipped");
694
692
  assert.equal(restarted.kind, "started");
695
693
  assert.equal(next.kind, "advanced");
696
694
  });
@@ -700,24 +698,24 @@ test("stop() clears idempotent unit lock so advance can run again", async (t) =>
700
698
  t.after(() => f.cleanup());
701
699
 
702
700
  const first = await f.orchestrator.advance();
703
- const blocked = await f.orchestrator.advance();
701
+ const idempotent = await f.orchestrator.advance();
704
702
  const stopped = await f.orchestrator.stop("reset");
705
703
  const second = await f.orchestrator.advance();
706
704
 
707
705
  assert.equal(first.kind, "advanced");
708
- assert.equal(blocked.kind, "blocked");
706
+ assert.equal(idempotent.kind, "skipped");
709
707
  assert.equal(stopped.kind, "stopped");
710
708
  assert.equal(second.kind, "advanced");
711
709
  });
712
710
 
713
- test("blocked path journals advance-blocked and records a health snapshot", async (t) => {
711
+ test("idempotent path journals advance-skipped and records a health snapshot", async (t) => {
714
712
  const f = makeFixture();
715
713
  t.after(() => f.cleanup());
716
714
 
717
715
  await f.orchestrator.advance();
718
716
  await f.orchestrator.advance();
719
717
 
720
- assert.ok(f.journalNames().includes("advance-blocked"));
718
+ assert.ok(f.journalNames().includes("advance-skipped"));
721
719
  });
722
720
 
723
721
  // ─── Stuck-loop ring buffer (issue #5787) ──────────────────────────────────
@@ -761,13 +759,12 @@ test("stuck-loop: ring saturated with same unit blocks with action 'stop' and st
761
759
  // First call advances.
762
760
  assert.equal(results[0].kind, "advanced");
763
761
 
764
- // Intermediate calls are blocked by idempotency (not stuck-loop yet).
762
+ // Intermediate calls are skipped by idempotency (not stuck-loop yet).
765
763
  for (let i = 1; i < STUCK_WINDOW_SIZE - 1; i++) {
766
764
  const r = results[i];
767
- assert.equal(r.kind, "blocked", `round ${i} should be blocked`);
768
- if (r.kind !== "blocked") return;
765
+ assert.equal(r.kind, "skipped", `round ${i} should be skipped`);
766
+ if (r.kind !== "skipped") return;
769
767
  assert.equal(r.reason, "idempotent advance: unit already active");
770
- assert.equal(r.action, "pause");
771
768
  }
772
769
 
773
770
  // The final call (ring now holds STUCK_WINDOW_SIZE copies) returns stuck-loop.
@@ -306,7 +306,9 @@ test("pauseAuto records the expected worktree path when paused from project root
306
306
 
307
307
  const meta = readPausedSessionMetadata(base);
308
308
  assert.ok(meta);
309
- assert.equal(meta.worktreePath, join(base, ".gsd", "worktrees", "M001"));
309
+ // No worktree exists yet, so the recorded path is the canonical
310
+ // .gsd-worktrees/ creation location (worktree-placement seam).
311
+ assert.equal(meta.worktreePath, join(base, ".gsd-worktrees", "M001"));
310
312
  } finally {
311
313
  autoSession.reset();
312
314
  try {
@@ -88,3 +88,49 @@ test("detects session execution tools supported by the evidence collector", () =
88
88
 
89
89
  assert.equal(_hasExecutionToolCallsInSessionForTest(entries), true);
90
90
  });
91
+
92
+ test("detects execution tool calls in bare agent-end messages (no session-entry wrapper)", () => {
93
+ // The auto loop passes opts.agentEndMessages as bare {role, content}
94
+ // messages — not {type: "message", message} session-manager entries.
95
+ const entries = [
96
+ {
97
+ role: "assistant",
98
+ content: [
99
+ {
100
+ type: "toolCall",
101
+ name: "Bash",
102
+ arguments: { command: "test -s index.html && grep -q localStorage index.html" },
103
+ },
104
+ ],
105
+ },
106
+ ];
107
+
108
+ assert.equal(_hasExecutionToolCallsInSessionForTest(entries), true);
109
+ });
110
+
111
+ test("does not suppress for bare agent-end messages without execution tools", () => {
112
+ const entries = [
113
+ {
114
+ role: "assistant",
115
+ content: [
116
+ { type: "text", text: "Task complete." },
117
+ { type: "toolCall", name: "Write", arguments: { file_path: "index.html" } },
118
+ ],
119
+ },
120
+ ];
121
+
122
+ assert.equal(_hasExecutionToolCallsInSessionForTest(entries), false);
123
+ });
124
+
125
+ test("ignores bare user messages with toolCall-shaped content", () => {
126
+ const entries = [
127
+ {
128
+ role: "user",
129
+ content: [
130
+ { type: "toolCall", name: "bash", arguments: { command: "echo hi" } },
131
+ ],
132
+ },
133
+ ];
134
+
135
+ assert.equal(_hasExecutionToolCallsInSessionForTest(entries), false);
136
+ });
@@ -184,7 +184,7 @@ describe("auto-worktree workspace registry", () => {
184
184
  git(["commit", "-m", "add milestone"], tempDir);
185
185
 
186
186
  createAutoWorktree(tempDir, "M003");
187
- const wtDir = join(tempDir, ".gsd", "worktrees", "M003");
187
+ const wtDir = join(tempDir, ".gsd-worktrees", "M003");
188
188
  writeFileSync(join(wtDir, "feature.txt"), "implemented\n");
189
189
  git(["add", "feature.txt"], wtDir);
190
190
  git(["commit", "-m", "feat: implement M003"], wtDir);
@@ -216,7 +216,7 @@ describe("auto-worktree workspace registry", () => {
216
216
  git(["commit", "-m", "add milestone"], tempDir);
217
217
 
218
218
  createAutoWorktree(tempDir, "M004");
219
- const wtDir = join(tempDir, ".gsd", "worktrees", "M004");
219
+ const wtDir = join(tempDir, ".gsd-worktrees", "M004");
220
220
  writeFileSync(join(wtDir, "feature.txt"), "implemented\n");
221
221
  git(["add", "feature.txt"], wtDir);
222
222
  git(["commit", "-m", "feat: implement M004"], wtDir);
@@ -35,7 +35,8 @@ test("repair target accepts a missing expected milestone worktree", () => {
35
35
 
36
36
  assert.equal(result.ok, true);
37
37
  if (result.ok) {
38
- assert.equal(result.expectedPath, join(base, ".gsd", "worktrees", "M001"));
38
+ // No worktree exists yet, so the expected path is the canonical container.
39
+ assert.equal(result.expectedPath, join(base, ".gsd-worktrees", "M001"));
39
40
  }
40
41
  } finally {
41
42
  cleanup(base);
@@ -192,7 +193,8 @@ test("paused metadata path resolves to the expected worktree while paused at pro
192
193
  baseIsAutoWorktree: false,
193
194
  });
194
195
 
195
- assert.equal(result, join(base, ".gsd", "worktrees", "M001"));
196
+ // No worktree exists yet, so resolution lands at the canonical container.
197
+ assert.equal(result, join(base, ".gsd-worktrees", "M001"));
196
198
  } finally {
197
199
  cleanup(base);
198
200
  }
@@ -0,0 +1,39 @@
1
+ import assert from "node:assert/strict";
2
+
3
+ import {
4
+ getUatBrowserToolSupportError,
5
+ hasUatBrowserToolSurface,
6
+ type UatType,
7
+ } from "../uat-policy.ts";
8
+
9
+ export const BROWSER_AUTOMATION_CONTRACT_TOOLS = {
10
+ piProvider: ["read", "browser_navigate"],
11
+ externalMcpClient: ["read", "mcp__gsd-browser__browser_navigate"],
12
+ externalMcpWildcard: ["read", "mcp__gsd-browser__*"],
13
+ otherBrowserMcp: ["read", "mcp__browser-uat__*"],
14
+ workflowOnly: ["read", "mcp__gsd-workflow__*"],
15
+ withoutBrowser: ["read", "gsd_uat_exec"],
16
+ } as const;
17
+
18
+ export function assertBrowserAutomationContractAvailable(tools: readonly string[]): void {
19
+ assert.equal(hasUatBrowserToolSurface(tools), true, `${tools.join(", ")} should satisfy the Browser Automation Contract`);
20
+ }
21
+
22
+ export function assertBrowserAutomationContractMissing(tools: readonly string[] | undefined): void {
23
+ assert.equal(hasUatBrowserToolSurface(tools), false, `${tools?.join(", ") ?? "undefined"} should not satisfy the Browser Automation Contract`);
24
+ }
25
+
26
+ export function assertBrowserBackedUatCanDispatch(options: {
27
+ uatType: UatType;
28
+ activeTools: readonly string[] | undefined;
29
+ registeredTools?: readonly string[];
30
+ }): void {
31
+ assert.equal(
32
+ getUatBrowserToolSupportError({
33
+ ...options,
34
+ milestoneId: "M001",
35
+ sliceId: "S01",
36
+ }),
37
+ null,
38
+ );
39
+ }
@@ -0,0 +1,44 @@
1
+ import { describe, it } from "node:test";
2
+ import assert from "node:assert/strict";
3
+
4
+ import {
5
+ BROWSER_CONTRACT_TOOL_NAMES,
6
+ BROWSER_EVIDENCE_SIGNAL_TOOL_NAMES,
7
+ hasBrowserContractPrefix,
8
+ isBrowserContractToolName,
9
+ } from "../../shared/browser-contract.ts";
10
+ import { isUatBrowserToolName } from "../uat-policy.ts";
11
+ import { BROWSER_REQUIREMENT_RE, BROWSER_RUNTIME_RE } from "../browser-evidence.ts";
12
+
13
+ // Note: RUN_UAT_BROWSER_TOOL_NAMES and MANAGED_GSD_BROWSER_TOOL_NAMES are
14
+ // reference-equal aliases of BROWSER_CONTRACT_TOOL_NAMES, and the managed
15
+ // adapter's spec table is Record-keyed by BrowserContractToolName — both
16
+ // derivations are pinned by the type system, not by runtime assertions here.
17
+ describe("Browser Automation Contract parity", () => {
18
+ it("every contract name satisfies the UAT browser-tool predicate, bare and MCP-prefixed", () => {
19
+ for (const name of BROWSER_CONTRACT_TOOL_NAMES) {
20
+ assert.equal(isUatBrowserToolName(name), true, name);
21
+ assert.equal(isUatBrowserToolName(`mcp__gsd-browser__${name}`), true, `mcp__gsd-browser__${name}`);
22
+ }
23
+ });
24
+
25
+ it("contract names are canonical browser_* names with no duplicates", () => {
26
+ assert.equal(new Set(BROWSER_CONTRACT_TOOL_NAMES).size, BROWSER_CONTRACT_TOOL_NAMES.length);
27
+ for (const name of BROWSER_CONTRACT_TOOL_NAMES) {
28
+ assert.equal(hasBrowserContractPrefix(name), true, name);
29
+ assert.equal(isBrowserContractToolName(name), true, name);
30
+ }
31
+ assert.equal(isBrowserContractToolName("browser_not_a_real_tool"), false);
32
+ assert.equal(hasBrowserContractPrefix("gsd_uat_exec"), false);
33
+ });
34
+
35
+ it("evidence-signal names stay a subset of the contract and drive the detection regexes", () => {
36
+ for (const name of BROWSER_EVIDENCE_SIGNAL_TOOL_NAMES) {
37
+ assert.equal(isBrowserContractToolName(name), true, name);
38
+ // Identifier-shaped names keep the regex splice in browser-evidence.ts escape-free.
39
+ assert.match(name, /^browser_[a-z_]+$/);
40
+ assert.match(`Verified via ${name} call`, BROWSER_REQUIREMENT_RE);
41
+ assert.match(`Verified via ${name} call`, BROWSER_RUNTIME_RE);
42
+ }
43
+ });
44
+ });
@@ -0,0 +1,144 @@
1
+ import test from "node:test";
2
+ import assert from "node:assert/strict";
3
+
4
+ import {
5
+ prepareBrowserDaemonForUat,
6
+ shouldWarmBrowserDaemonForUat,
7
+ } from "../browser-daemon-auto-prep.ts";
8
+ import { commitBrowserEngineResolution } from "../../browser-tools/engine/selection.ts";
9
+ import { resolveGsdBrowserCliAvailability } from "../../shared/gsd-browser-cli.ts";
10
+
11
+ const GSD_BROWSER_ENGINE = { GSD_BROWSER_ENGINE: "gsd-browser" } as const;
12
+
13
+ test("shouldWarmBrowserDaemonForUat skips artifact-driven UAT", () => {
14
+ assert.equal(
15
+ shouldWarmBrowserDaemonForUat({
16
+ uatType: "artifact-driven",
17
+ sessionProvider: "claude-code",
18
+ projectRoot: "/tmp/project",
19
+ }),
20
+ false,
21
+ );
22
+ });
23
+
24
+ test("shouldWarmBrowserDaemonForUat enables Claude Code browser UAT when gsd-browser is available", (t) => {
25
+ const availability = resolveGsdBrowserCliAvailability();
26
+ if (!availability.available) {
27
+ t.skip("bundled gsd-browser CLI unavailable");
28
+ }
29
+
30
+ assert.equal(
31
+ shouldWarmBrowserDaemonForUat({
32
+ uatType: "browser-executable",
33
+ sessionProvider: "claude-code",
34
+ sessionAuthMode: "externalCli",
35
+ projectRoot: "/tmp/project",
36
+ env: GSD_BROWSER_ENGINE,
37
+ }),
38
+ true,
39
+ );
40
+ });
41
+
42
+ test("shouldWarmBrowserDaemonForUat enables warm-up for Claude Code oauth/apiKey when engine is gsd-browser", (t) => {
43
+ const availability = resolveGsdBrowserCliAvailability();
44
+ if (!availability.available) {
45
+ t.skip("bundled gsd-browser CLI unavailable");
46
+ }
47
+
48
+ for (const sessionAuthMode of ["oauth", "apiKey"] as const) {
49
+ assert.equal(
50
+ shouldWarmBrowserDaemonForUat({
51
+ uatType: "browser-executable",
52
+ sessionProvider: "claude-code",
53
+ sessionAuthMode,
54
+ sessionBaseUrl: "https://api.anthropic.com",
55
+ projectRoot: "/tmp/project",
56
+ env: GSD_BROWSER_ENGINE,
57
+ }),
58
+ true,
59
+ `expected warm-up for sessionAuthMode=${sessionAuthMode}`,
60
+ );
61
+ }
62
+ });
63
+
64
+ test("shouldWarmBrowserDaemonForUat skips legacy Playwright engine for Claude Code", () => {
65
+ assert.equal(
66
+ shouldWarmBrowserDaemonForUat({
67
+ uatType: "browser-executable",
68
+ sessionProvider: "claude-code",
69
+ sessionAuthMode: "oauth",
70
+ projectRoot: "/tmp/project",
71
+ env: { GSD_BROWSER_ENGINE: "legacy" },
72
+ }),
73
+ false,
74
+ );
75
+ });
76
+
77
+ test("shouldWarmBrowserDaemonForUat uses session-committed ambient engine for non-Claude providers", () => {
78
+ const projectRoot = "/tmp/ambient-engine-project";
79
+ commitBrowserEngineResolution(projectRoot, {
80
+ engine: "legacy",
81
+ source: "probe",
82
+ reason: "gsd-browser daemon connect failed (test); using legacy Playwright",
83
+ });
84
+
85
+ assert.equal(
86
+ shouldWarmBrowserDaemonForUat({
87
+ uatType: "browser-executable",
88
+ sessionProvider: "openai",
89
+ projectRoot,
90
+ }),
91
+ false,
92
+ );
93
+ });
94
+
95
+ test("shouldWarmBrowserDaemonForUat skips when browser MCP is disabled", () => {
96
+ assert.equal(
97
+ shouldWarmBrowserDaemonForUat({
98
+ uatType: "browser-executable",
99
+ sessionProvider: "claude-code",
100
+ projectRoot: "/tmp/project",
101
+ env: { GSD_BROWSER_MCP_ENABLED: "0" },
102
+ }),
103
+ false,
104
+ );
105
+ });
106
+
107
+ test("shouldWarmBrowserDaemonForUat skips when warm-up is disabled", () => {
108
+ assert.equal(
109
+ shouldWarmBrowserDaemonForUat({
110
+ uatType: "browser-executable",
111
+ sessionProvider: "claude-code",
112
+ projectRoot: "/tmp/project",
113
+ env: { GSD_BROWSER_WARMUP: "0" },
114
+ }),
115
+ false,
116
+ );
117
+ });
118
+
119
+ test("prepareBrowserDaemonForUat returns null when warm-up is not required", () => {
120
+ assert.equal(
121
+ prepareBrowserDaemonForUat({
122
+ uatType: "artifact-driven",
123
+ sessionProvider: "claude-code",
124
+ sessionAuthMode: "externalCli",
125
+ projectRoot: "/tmp/example-project",
126
+ }),
127
+ null,
128
+ );
129
+ });
130
+
131
+ test("prepareBrowserDaemonForUat returns actionable error when daemon start fails", () => {
132
+ const error = prepareBrowserDaemonForUat({
133
+ uatType: "browser-executable",
134
+ sessionProvider: "claude-code",
135
+ sessionAuthMode: "externalCli",
136
+ projectRoot: "/tmp/example-project",
137
+ env: {
138
+ ...GSD_BROWSER_ENGINE,
139
+ GSD_BROWSER_MCP_COMMAND: "/definitely/missing/gsd-browser",
140
+ },
141
+ });
142
+
143
+ assert.match(error ?? "", /gsd-browser daemon failed to start/i);
144
+ });
@@ -5,7 +5,7 @@ import { mkdirSync, mkdtempSync, readFileSync, realpathSync, rmSync, writeFileSy
5
5
  import { join } from "node:path";
6
6
  import { tmpdir } from "node:os";
7
7
 
8
- import { checkoutBranchWithStashGuard } from "../auto-worktree.ts";
8
+ import { checkoutBranchWithStashGuard } from "../worktree-git-recovery.ts";
9
9
 
10
10
  function git(args: string[], cwd: string): string {
11
11
  return execFileSync("git", args, {
@@ -159,4 +159,69 @@ describe("checkoutBranchWithStashGuard", () => {
159
159
  const stashList = git(["stash", "list"], repo).trim();
160
160
  assert.equal(stashList, "");
161
161
  });
162
+
163
+ test("auto-resolves combined non-.gsd untracked collision and .gsd index conflict", (t) => {
164
+ // Regression for: gate checked nonGsdUnmerged.length === 0 but ignored
165
+ // .gsd/ index conflicts, so a failed pop with both an untracked non-.gsd/
166
+ // collision AND a .gsd/ tracked conflict would drop the stash while leaving
167
+ // .gsd/ index unmerged entries unresolved.
168
+ const repo = createRepo(t);
169
+ // Add .gsd/DECISIONS.md to base so both branches diverge from it
170
+ writeFileSync(join(repo, ".gsd", "DECISIONS.md"), "base\n");
171
+ git(["add", ".gsd/DECISIONS.md"], repo);
172
+ git(["commit", "-m", "add decisions"], repo);
173
+
174
+ git(["checkout", "-b", "milestone/M003"], repo);
175
+ // Branch has its own version of DECISIONS.md (non-JSONL .gsd/ file)
176
+ writeFileSync(join(repo, ".gsd", "DECISIONS.md"), "target-version\n");
177
+ mkdirSync(join(repo, ".harness"), { recursive: true });
178
+ writeFileSync(join(repo, ".harness", "settings.json"), "{\"theme\":\"dark\"}\n");
179
+ git(["add", ".gsd/DECISIONS.md", ".harness/settings.json"], repo);
180
+ git(["commit", "-m", "branch state"], repo);
181
+ git(["checkout", "main"], repo);
182
+
183
+ // On main: tracked .gsd/ change (creates unmerged index entry on pop) +
184
+ // untracked harness file (triggers "already exists, no checkout").
185
+ writeFileSync(join(repo, ".gsd", "DECISIONS.md"), "local-version\n");
186
+ mkdirSync(join(repo, ".harness"), { recursive: true });
187
+ writeFileSync(join(repo, ".harness", "settings.json"), "{\"theme\":\"light\"}\n");
188
+
189
+ checkoutBranchWithStashGuard(repo, "milestone/M003", "test-combined-gsd-conflict");
190
+
191
+ const branch = git(["branch", "--show-current"], repo).trim();
192
+ assert.equal(branch, "milestone/M003");
193
+ const decisions = readFileSync(join(repo, ".gsd", "DECISIONS.md"), "utf8");
194
+ assert.equal(decisions, "target-version\n");
195
+ assert.doesNotMatch(decisions, /<<<<<<<|=======|>>>>>>>/);
196
+ const status = git(["status", "--porcelain"], repo).trim();
197
+ assert.equal(status, "");
198
+ const stashList = git(["stash", "list"], repo).trim();
199
+ assert.equal(stashList, "");
200
+ });
201
+
202
+ test("auto-resolves non-.gsd untracked restore collisions (e.g. harness config outside .gsd/)", (t) => {
203
+ const repo = createRepo(t);
204
+ // Target branch has a harness config file committed; source (main) has it untracked.
205
+ // Use a path not affected by global gitignore rules (unlike .claude/settings.local.json).
206
+ git(["checkout", "-b", "milestone/M001"], repo);
207
+ mkdirSync(join(repo, ".harness"), { recursive: true });
208
+ writeFileSync(join(repo, ".harness", "settings.json"), "{\"theme\":\"dark\"}\n");
209
+ git(["add", ".harness/settings.json"], repo);
210
+ git(["commit", "-m", "add harness settings"], repo);
211
+ git(["checkout", "main"], repo);
212
+
213
+ mkdirSync(join(repo, ".harness"), { recursive: true });
214
+ writeFileSync(join(repo, ".harness", "settings.json"), "{\"theme\":\"light\"}\n");
215
+
216
+ checkoutBranchWithStashGuard(repo, "milestone/M001", "test-non-gsd-untracked-collision");
217
+
218
+ const branch = git(["branch", "--show-current"], repo).trim();
219
+ assert.equal(branch, "milestone/M001");
220
+ const wtContent = readFileSync(join(repo, ".harness", "settings.json"), "utf8");
221
+ assert.equal(wtContent, "{\"theme\":\"dark\"}\n");
222
+ const status = git(["status", "--porcelain"], repo).trim();
223
+ assert.equal(status, "");
224
+ const stashList = git(["stash", "list"], repo).trim();
225
+ assert.equal(stashList, "");
226
+ });
162
227
  });