@opengsd/gsd-pi 1.4.0 → 1.5.0-dev.553dc518

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 (606) hide show
  1. package/README.md +11 -11
  2. package/dist/onboarding.js +11 -0
  3. package/dist/resources/.managed-resources-content-hash +1 -1
  4. package/dist/resources/GSD-WORKFLOW.md +20 -25
  5. package/dist/resources/extensions/claude-code-cli/stream-adapter.js +118 -53
  6. package/dist/resources/extensions/cursor-cli/index.js +16 -0
  7. package/dist/resources/extensions/cursor-cli/models.js +63 -0
  8. package/dist/resources/extensions/cursor-cli/package.json +11 -0
  9. package/dist/resources/extensions/cursor-cli/readiness.js +128 -0
  10. package/dist/resources/extensions/cursor-cli/stream-adapter.js +353 -0
  11. package/dist/resources/extensions/gsd/activity-log.js +4 -1
  12. package/dist/resources/extensions/gsd/artifact-verification.js +25 -9
  13. package/dist/resources/extensions/gsd/auto/closeout.js +137 -42
  14. package/dist/resources/extensions/gsd/auto/finalize.js +9 -0
  15. package/dist/resources/extensions/gsd/auto/orchestrator.js +4 -3
  16. package/dist/resources/extensions/gsd/auto/pre-dispatch.js +6 -3
  17. package/dist/resources/extensions/gsd/auto/run-unit.js +5 -2
  18. package/dist/resources/extensions/gsd/auto/schedule-wakeup.js +3 -0
  19. package/dist/resources/extensions/gsd/auto/unit-phase.js +5 -9
  20. package/dist/resources/extensions/gsd/auto-direct-dispatch.js +4 -5
  21. package/dist/resources/extensions/gsd/auto-dispatch.js +15 -5
  22. package/dist/resources/extensions/gsd/auto-model-selection.js +36 -18
  23. package/dist/resources/extensions/gsd/auto-prompts.js +76 -2
  24. package/dist/resources/extensions/gsd/auto-start.js +7 -5
  25. package/dist/resources/extensions/gsd/auto-timeout-recovery.js +4 -0
  26. package/dist/resources/extensions/gsd/auto-worktree-branch-lifecycle.js +189 -0
  27. package/dist/resources/extensions/gsd/auto-worktree-cleanup.js +133 -0
  28. package/dist/resources/extensions/gsd/auto-worktree-conflict-auto-resolve.js +35 -0
  29. package/dist/resources/extensions/gsd/auto-worktree-creation.js +130 -0
  30. package/dist/resources/extensions/gsd/auto-worktree-entry.js +118 -0
  31. package/dist/resources/extensions/gsd/auto-worktree-merge-already-merged.js +98 -0
  32. package/dist/resources/extensions/gsd/auto-worktree-merge-branch-head.js +52 -0
  33. package/dist/resources/extensions/gsd/auto-worktree-merge-cleanup.js +87 -0
  34. package/dist/resources/extensions/gsd/auto-worktree-merge-code-changes.js +46 -0
  35. package/dist/resources/extensions/gsd/auto-worktree-merge-db-ready.js +68 -0
  36. package/dist/resources/extensions/gsd/auto-worktree-merge-integration-branch.js +51 -0
  37. package/dist/resources/extensions/gsd/auto-worktree-merge-message.js +106 -0
  38. package/dist/resources/extensions/gsd/auto-worktree-merge-pre-teardown.js +64 -0
  39. package/dist/resources/extensions/gsd/auto-worktree-merge-stash.js +168 -0
  40. package/dist/resources/extensions/gsd/auto-worktree-merge.js +302 -0
  41. package/dist/resources/extensions/gsd/auto-worktree-milestone-shelter.js +119 -0
  42. package/dist/resources/extensions/gsd/auto-worktree-path-resolution.js +5 -0
  43. package/dist/resources/extensions/gsd/auto-worktree-path-utils.js +5 -0
  44. package/dist/resources/extensions/gsd/auto-worktree-resource-version.js +41 -0
  45. package/dist/resources/extensions/gsd/auto-worktree-runtime-cleanup.js +99 -0
  46. package/dist/resources/extensions/gsd/auto-worktree-session-registry.js +57 -0
  47. package/dist/resources/extensions/gsd/auto-worktree-sync.js +249 -0
  48. package/dist/resources/extensions/gsd/auto-worktree-teardown.js +120 -0
  49. package/dist/resources/extensions/gsd/auto-worktree.js +20 -2046
  50. package/dist/resources/extensions/gsd/auto.js +31 -5
  51. package/dist/resources/extensions/gsd/bootstrap/db-tools.js +3 -0
  52. package/dist/resources/extensions/gsd/bootstrap/dynamic-tools.js +1 -1
  53. package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +133 -6
  54. package/dist/resources/extensions/gsd/bootstrap/schedule-wakeup-tool.js +58 -9
  55. package/dist/resources/extensions/gsd/bootstrap/system-context.js +1 -1
  56. package/dist/resources/extensions/gsd/bootstrap/tool-call-loop-guard.js +127 -22
  57. package/dist/resources/extensions/gsd/bootstrap/write-gate.js +14 -1
  58. package/dist/resources/extensions/gsd/codebase-generator.js +157 -19
  59. package/dist/resources/extensions/gsd/commands/handlers/core.js +40 -4
  60. package/dist/resources/extensions/gsd/commands-handlers.js +1 -1
  61. package/dist/resources/extensions/gsd/commands-prefs-wizard.js +153 -1
  62. package/dist/resources/extensions/gsd/commands-workflow-templates.js +3 -3
  63. package/dist/resources/extensions/gsd/commands-worktree.js +11 -2
  64. package/dist/resources/extensions/gsd/db/queries.js +48 -9
  65. package/dist/resources/extensions/gsd/discussion-handoff.js +8 -3
  66. package/dist/resources/extensions/gsd/docs/preferences-reference.md +8 -2
  67. package/dist/resources/extensions/gsd/doctor-engine-checks.js +292 -18
  68. package/dist/resources/extensions/gsd/doctor-providers.js +38 -10
  69. package/dist/resources/extensions/gsd/doctor.js +93 -3
  70. package/dist/resources/extensions/gsd/exec-sandbox.js +6 -2
  71. package/dist/resources/extensions/gsd/flat-phase-migration.js +88 -26
  72. package/dist/resources/extensions/gsd/forensics.js +1 -1
  73. package/dist/resources/extensions/gsd/git-conflict-resolve.js +2 -2
  74. package/dist/resources/extensions/gsd/git-service.js +59 -18
  75. package/dist/resources/extensions/gsd/gsd-db.js +63 -0
  76. package/dist/resources/extensions/gsd/guidance.js +1 -0
  77. package/dist/resources/extensions/gsd/guided-flow.js +46 -12
  78. package/dist/resources/extensions/gsd/key-manager.js +1 -0
  79. package/dist/resources/extensions/gsd/markdown-renderer.js +40 -11
  80. package/dist/resources/extensions/gsd/migrate-external.js +24 -7
  81. package/dist/resources/extensions/gsd/milestone-merge-transaction.js +14 -3
  82. package/dist/resources/extensions/gsd/milestone-settlement.js +1 -1
  83. package/dist/resources/extensions/gsd/parallel-merge.js +1 -1
  84. package/dist/resources/extensions/gsd/parallel-orchestrator.js +3 -1
  85. package/dist/resources/extensions/gsd/preferences-diagnostics.js +24 -1
  86. package/dist/resources/extensions/gsd/preferences-models.js +6 -4
  87. package/dist/resources/extensions/gsd/preferences-types.js +1 -0
  88. package/dist/resources/extensions/gsd/preferences-validation.js +107 -2
  89. package/dist/resources/extensions/gsd/preferences.js +29 -2
  90. package/dist/resources/extensions/gsd/prompts/plan-slice.md +4 -2
  91. package/dist/resources/extensions/gsd/prompts/system.md +6 -6
  92. package/dist/resources/extensions/gsd/quick.js +12 -3
  93. package/dist/resources/extensions/gsd/redact-secrets.js +37 -0
  94. package/dist/resources/extensions/gsd/repo-identity.js +16 -0
  95. package/dist/resources/extensions/gsd/repository-registry.js +6 -1
  96. package/dist/resources/extensions/gsd/root-write-leak-guard.js +4 -2
  97. package/dist/resources/extensions/gsd/safe-fs.js +23 -2
  98. package/dist/resources/extensions/gsd/skills/gsd-headless/SKILL.md +7 -9
  99. package/dist/resources/extensions/gsd/skills/gsd-headless/references/commands.md +1 -0
  100. package/dist/resources/extensions/gsd/slice-parallel-orchestrator.js +2 -1
  101. package/dist/resources/extensions/gsd/state/derive/from-db.js +88 -153
  102. package/dist/resources/extensions/gsd/tool-contract.js +14 -0
  103. package/dist/resources/extensions/gsd/tools/plan-task.js +76 -8
  104. package/dist/resources/extensions/gsd/tools/workflow-tool-executors.js +40 -0
  105. package/dist/resources/extensions/gsd/unit-context-manifest.js +5 -4
  106. package/dist/resources/extensions/gsd/unit-registry.js +37 -2
  107. package/dist/resources/extensions/gsd/unit-runtime.js +21 -0
  108. package/dist/resources/extensions/gsd/unmerged-milestone-guard.js +1 -1
  109. package/dist/resources/extensions/gsd/validation-block-guard.js +2 -1
  110. package/dist/resources/extensions/gsd/workspace-git-preflight.js +2 -2
  111. package/dist/resources/extensions/gsd/workspace.js +26 -8
  112. package/dist/resources/extensions/gsd/worktree-command.js +1 -1
  113. package/dist/resources/extensions/gsd/worktree-lifecycle.js +81 -14
  114. package/dist/resources/extensions/gsd/worktree-manager.js +97 -4
  115. package/dist/resources/extensions/gsd/worktree-reentry.js +2 -1
  116. package/dist/tsconfig.extensions.tsbuildinfo +1 -1
  117. package/dist/web/standalone/.next/BUILD_ID +1 -1
  118. package/dist/web/standalone/.next/app-path-routes-manifest.json +10 -10
  119. package/dist/web/standalone/.next/build-manifest.json +3 -3
  120. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  121. package/dist/web/standalone/.next/required-server-files.json +3 -3
  122. package/dist/web/standalone/.next/server/app/_global-error/page.js +3 -3
  123. package/dist/web/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
  124. package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
  125. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  126. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  127. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  128. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  129. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  130. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  131. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  132. package/dist/web/standalone/.next/server/app/_not-found/page.js +2 -2
  133. package/dist/web/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  134. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  135. package/dist/web/standalone/.next/server/app/_not-found.rsc +3 -3
  136. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +3 -3
  137. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  138. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +3 -3
  139. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  140. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  141. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  142. package/dist/web/standalone/.next/server/app/api/boot/route.js +1 -1
  143. package/dist/web/standalone/.next/server/app/api/boot/route_client-reference-manifest.js +1 -1
  144. package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route.js +1 -1
  145. package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route_client-reference-manifest.js +1 -1
  146. package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route.js +1 -1
  147. package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route_client-reference-manifest.js +1 -1
  148. package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route.js +2 -2
  149. package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route_client-reference-manifest.js +1 -1
  150. package/dist/web/standalone/.next/server/app/api/browse-directories/route.js +1 -1
  151. package/dist/web/standalone/.next/server/app/api/browse-directories/route_client-reference-manifest.js +1 -1
  152. package/dist/web/standalone/.next/server/app/api/captures/route.js +1 -1
  153. package/dist/web/standalone/.next/server/app/api/captures/route_client-reference-manifest.js +1 -1
  154. package/dist/web/standalone/.next/server/app/api/cleanup/route.js +1 -1
  155. package/dist/web/standalone/.next/server/app/api/cleanup/route_client-reference-manifest.js +1 -1
  156. package/dist/web/standalone/.next/server/app/api/dev-mode/route.js +1 -1
  157. package/dist/web/standalone/.next/server/app/api/dev-mode/route_client-reference-manifest.js +1 -1
  158. package/dist/web/standalone/.next/server/app/api/doctor/route.js +1 -1
  159. package/dist/web/standalone/.next/server/app/api/doctor/route_client-reference-manifest.js +1 -1
  160. package/dist/web/standalone/.next/server/app/api/experimental/route.js +2 -2
  161. package/dist/web/standalone/.next/server/app/api/experimental/route_client-reference-manifest.js +1 -1
  162. package/dist/web/standalone/.next/server/app/api/export-data/route.js +1 -1
  163. package/dist/web/standalone/.next/server/app/api/export-data/route_client-reference-manifest.js +1 -1
  164. package/dist/web/standalone/.next/server/app/api/files/route.js +1 -1
  165. package/dist/web/standalone/.next/server/app/api/files/route_client-reference-manifest.js +1 -1
  166. package/dist/web/standalone/.next/server/app/api/forensics/route.js +1 -1
  167. package/dist/web/standalone/.next/server/app/api/forensics/route_client-reference-manifest.js +1 -1
  168. package/dist/web/standalone/.next/server/app/api/git/route.js +1 -1
  169. package/dist/web/standalone/.next/server/app/api/git/route_client-reference-manifest.js +1 -1
  170. package/dist/web/standalone/.next/server/app/api/history/route.js +1 -1
  171. package/dist/web/standalone/.next/server/app/api/history/route_client-reference-manifest.js +1 -1
  172. package/dist/web/standalone/.next/server/app/api/hooks/route.js +1 -1
  173. package/dist/web/standalone/.next/server/app/api/hooks/route_client-reference-manifest.js +1 -1
  174. package/dist/web/standalone/.next/server/app/api/inspect/route.js +1 -1
  175. package/dist/web/standalone/.next/server/app/api/inspect/route_client-reference-manifest.js +1 -1
  176. package/dist/web/standalone/.next/server/app/api/knowledge/route.js +1 -1
  177. package/dist/web/standalone/.next/server/app/api/knowledge/route_client-reference-manifest.js +1 -1
  178. package/dist/web/standalone/.next/server/app/api/live-state/route.js +1 -1
  179. package/dist/web/standalone/.next/server/app/api/live-state/route_client-reference-manifest.js +1 -1
  180. package/dist/web/standalone/.next/server/app/api/mcp-connections/route.js +1 -1
  181. package/dist/web/standalone/.next/server/app/api/mcp-connections/route_client-reference-manifest.js +1 -1
  182. package/dist/web/standalone/.next/server/app/api/notifications/route.js +2 -2
  183. package/dist/web/standalone/.next/server/app/api/notifications/route_client-reference-manifest.js +1 -1
  184. package/dist/web/standalone/.next/server/app/api/onboarding/route.js +1 -1
  185. package/dist/web/standalone/.next/server/app/api/onboarding/route_client-reference-manifest.js +1 -1
  186. package/dist/web/standalone/.next/server/app/api/preferences/route.js +1 -1
  187. package/dist/web/standalone/.next/server/app/api/preferences/route_client-reference-manifest.js +1 -1
  188. package/dist/web/standalone/.next/server/app/api/projects/route.js +1 -1
  189. package/dist/web/standalone/.next/server/app/api/projects/route_client-reference-manifest.js +1 -1
  190. package/dist/web/standalone/.next/server/app/api/recovery/route.js +1 -1
  191. package/dist/web/standalone/.next/server/app/api/recovery/route_client-reference-manifest.js +1 -1
  192. package/dist/web/standalone/.next/server/app/api/remote-questions/route.js +2 -2
  193. package/dist/web/standalone/.next/server/app/api/remote-questions/route_client-reference-manifest.js +1 -1
  194. package/dist/web/standalone/.next/server/app/api/session/browser/route.js +1 -1
  195. package/dist/web/standalone/.next/server/app/api/session/browser/route_client-reference-manifest.js +1 -1
  196. package/dist/web/standalone/.next/server/app/api/session/command/route.js +1 -1
  197. package/dist/web/standalone/.next/server/app/api/session/command/route_client-reference-manifest.js +1 -1
  198. package/dist/web/standalone/.next/server/app/api/session/events/route.js +2 -2
  199. package/dist/web/standalone/.next/server/app/api/session/events/route_client-reference-manifest.js +1 -1
  200. package/dist/web/standalone/.next/server/app/api/session/manage/route.js +1 -1
  201. package/dist/web/standalone/.next/server/app/api/session/manage/route_client-reference-manifest.js +1 -1
  202. package/dist/web/standalone/.next/server/app/api/settings-data/route.js +1 -1
  203. package/dist/web/standalone/.next/server/app/api/settings-data/route_client-reference-manifest.js +1 -1
  204. package/dist/web/standalone/.next/server/app/api/shutdown/route.js +1 -1
  205. package/dist/web/standalone/.next/server/app/api/shutdown/route_client-reference-manifest.js +1 -1
  206. package/dist/web/standalone/.next/server/app/api/skill-health/route.js +1 -1
  207. package/dist/web/standalone/.next/server/app/api/skill-health/route_client-reference-manifest.js +1 -1
  208. package/dist/web/standalone/.next/server/app/api/steer/route.js +1 -1
  209. package/dist/web/standalone/.next/server/app/api/steer/route_client-reference-manifest.js +1 -1
  210. package/dist/web/standalone/.next/server/app/api/switch-root/route.js +1 -1
  211. package/dist/web/standalone/.next/server/app/api/switch-root/route_client-reference-manifest.js +1 -1
  212. package/dist/web/standalone/.next/server/app/api/terminal/input/route.js +1 -1
  213. package/dist/web/standalone/.next/server/app/api/terminal/input/route_client-reference-manifest.js +1 -1
  214. package/dist/web/standalone/.next/server/app/api/terminal/resize/route.js +2 -2
  215. package/dist/web/standalone/.next/server/app/api/terminal/resize/route_client-reference-manifest.js +1 -1
  216. package/dist/web/standalone/.next/server/app/api/terminal/sessions/route.js +1 -1
  217. package/dist/web/standalone/.next/server/app/api/terminal/sessions/route_client-reference-manifest.js +1 -1
  218. package/dist/web/standalone/.next/server/app/api/terminal/stream/route.js +4 -4
  219. package/dist/web/standalone/.next/server/app/api/terminal/stream/route_client-reference-manifest.js +1 -1
  220. package/dist/web/standalone/.next/server/app/api/terminal/upload/route.js +1 -1
  221. package/dist/web/standalone/.next/server/app/api/terminal/upload/route_client-reference-manifest.js +1 -1
  222. package/dist/web/standalone/.next/server/app/api/undo/route.js +1 -1
  223. package/dist/web/standalone/.next/server/app/api/undo/route_client-reference-manifest.js +1 -1
  224. package/dist/web/standalone/.next/server/app/api/update/route.js +1 -1
  225. package/dist/web/standalone/.next/server/app/api/update/route_client-reference-manifest.js +1 -1
  226. package/dist/web/standalone/.next/server/app/api/visualizer/route.js +1 -1
  227. package/dist/web/standalone/.next/server/app/api/visualizer/route_client-reference-manifest.js +1 -1
  228. package/dist/web/standalone/.next/server/app/index.html +1 -1
  229. package/dist/web/standalone/.next/server/app/index.rsc +4 -4
  230. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
  231. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +4 -4
  232. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  233. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +3 -3
  234. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  235. package/dist/web/standalone/.next/server/app/page.js +2 -2
  236. package/dist/web/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
  237. package/dist/web/standalone/.next/server/app-paths-manifest.json +10 -10
  238. package/dist/web/standalone/.next/server/chunks/2842.js +4 -4
  239. package/dist/web/standalone/.next/server/chunks/8357.js +2 -2
  240. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  241. package/dist/web/standalone/.next/server/middleware.js +3 -3
  242. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  243. package/dist/web/standalone/.next/server/pages/500.html +1 -1
  244. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  245. package/dist/web/standalone/.next/static/chunks/app/_not-found/page-a6fb1847f67f167c.js +1 -0
  246. package/dist/web/standalone/.next/static/chunks/app/{layout-b35cbfff38aaf4cf.js → layout-4ae2d68984392bbf.js} +1 -1
  247. package/dist/web/standalone/.next/static/chunks/app/page-72a856634ad14c10.js +1 -0
  248. package/dist/web/standalone/.next/static/chunks/{main-app-590a74400e35f685.js → main-app-90d1d8d5e5d2dc6b.js} +1 -1
  249. package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/global-error-1115d46ac61b9823.js +1 -0
  250. package/dist/web/standalone/node_modules/@gsd/native/package.json +1 -1
  251. package/dist/web/standalone/node_modules/node-pty/build/Makefile +2 -2
  252. package/dist/web/standalone/node_modules/node-pty/build/Release/pty.node +0 -0
  253. package/dist/web/standalone/node_modules/node-pty/build/pty.target.mk +14 -14
  254. package/dist/web/standalone/server.js +1 -1
  255. package/dist/wizard.d.ts +8 -0
  256. package/dist/wizard.js +8 -1
  257. package/integrations/hermes/CONTEXT.md +47 -0
  258. package/integrations/hermes/README.md +21 -0
  259. package/integrations/hermes/__init__.py +31 -0
  260. package/integrations/hermes/docs/issue-1162-grilling.md +197 -0
  261. package/integrations/hermes/docs/setup.md +4 -0
  262. package/integrations/hermes/open_gsd_hermes/commands.py +141 -0
  263. package/integrations/hermes/open_gsd_hermes/config.py +2 -0
  264. package/integrations/hermes/open_gsd_hermes/gsd_client.py +591 -39
  265. package/integrations/hermes/open_gsd_hermes/notifications.py +10 -1
  266. package/integrations/hermes/plugin.yaml +4 -0
  267. package/integrations/hermes/tests/test_config.py +6 -0
  268. package/integrations/hermes/tests/test_directory_loader.py +37 -0
  269. package/integrations/hermes/tests/test_gsd_client_cache.py +3 -0
  270. package/integrations/hermes/tests/test_gsd_client_execute.py +35 -0
  271. package/integrations/hermes/tests/test_gsd_client_process_cwd.py +22 -0
  272. package/integrations/hermes/tests/test_gsd_client_timeout.py +98 -0
  273. package/integrations/hermes/tests/test_milestone_client.py +447 -0
  274. package/integrations/hermes/tests/test_new_milestone_command.py +313 -0
  275. package/integrations/hermes/tests/test_supervisor_fsm.py +40 -0
  276. package/package.json +8 -8
  277. package/packages/cloud-mcp-gateway/dist/auth-store.d.ts +1 -0
  278. package/packages/cloud-mcp-gateway/dist/auth-store.d.ts.map +1 -1
  279. package/packages/cloud-mcp-gateway/dist/auth-store.js +21 -1
  280. package/packages/cloud-mcp-gateway/dist/auth-store.js.map +1 -1
  281. package/packages/cloud-mcp-gateway/dist/auth-store.test.js +34 -0
  282. package/packages/cloud-mcp-gateway/dist/auth-store.test.js.map +1 -1
  283. package/packages/cloud-mcp-gateway/package.json +2 -2
  284. package/packages/contracts/package.json +1 -1
  285. package/packages/daemon/dist/cloud-runtime.d.ts +2 -0
  286. package/packages/daemon/dist/cloud-runtime.d.ts.map +1 -1
  287. package/packages/daemon/dist/cloud-runtime.js +25 -1
  288. package/packages/daemon/dist/cloud-runtime.js.map +1 -1
  289. package/packages/daemon/dist/cloud-runtime.test.js +51 -0
  290. package/packages/daemon/dist/cloud-runtime.test.js.map +1 -1
  291. package/packages/daemon/dist/message-batcher.d.ts +7 -0
  292. package/packages/daemon/dist/message-batcher.d.ts.map +1 -1
  293. package/packages/daemon/dist/message-batcher.js +13 -0
  294. package/packages/daemon/dist/message-batcher.js.map +1 -1
  295. package/packages/daemon/dist/message-batcher.test.js +48 -0
  296. package/packages/daemon/dist/message-batcher.test.js.map +1 -1
  297. package/packages/daemon/dist/session-manager.js +1 -1
  298. package/packages/daemon/dist/session-manager.js.map +1 -1
  299. package/packages/daemon/package.json +5 -5
  300. package/packages/gsd-agent-core/dist/compaction/compaction.d.ts +13 -1
  301. package/packages/gsd-agent-core/dist/compaction/compaction.d.ts.map +1 -1
  302. package/packages/gsd-agent-core/dist/compaction/compaction.js +15 -1
  303. package/packages/gsd-agent-core/dist/compaction/compaction.js.map +1 -1
  304. package/packages/gsd-agent-core/dist/export-html/template.js +53 -4
  305. package/packages/gsd-agent-core/dist/session/agent-session-navigation.d.ts.map +1 -1
  306. package/packages/gsd-agent-core/dist/session/agent-session-navigation.js +4 -1
  307. package/packages/gsd-agent-core/dist/session/agent-session-navigation.js.map +1 -1
  308. package/packages/gsd-agent-core/package.json +5 -5
  309. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.d.ts.map +1 -1
  310. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.js +3 -2
  311. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.js.map +1 -1
  312. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-segment-walker.d.ts.map +1 -1
  313. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-segment-walker.js +1 -0
  314. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-segment-walker.js.map +1 -1
  315. package/packages/gsd-agent-modes/dist/modes/rpc/rpc-client.js +1 -1
  316. package/packages/gsd-agent-modes/dist/modes/rpc/rpc-client.js.map +1 -1
  317. package/packages/gsd-agent-modes/package.json +7 -7
  318. package/packages/mcp-server/dist/server.d.ts +18 -5
  319. package/packages/mcp-server/dist/server.d.ts.map +1 -1
  320. package/packages/mcp-server/dist/server.js +46 -5
  321. package/packages/mcp-server/dist/server.js.map +1 -1
  322. package/packages/mcp-server/dist/session-manager.js +1 -1
  323. package/packages/mcp-server/dist/session-manager.js.map +1 -1
  324. package/packages/mcp-server/package.json +4 -4
  325. package/packages/native/package.json +1 -1
  326. package/packages/pi-agent-core/dist/agent-loop.d.ts.map +1 -1
  327. package/packages/pi-agent-core/dist/agent-loop.js +14 -9
  328. package/packages/pi-agent-core/dist/agent-loop.js.map +1 -1
  329. package/packages/pi-agent-core/package.json +1 -1
  330. package/packages/pi-ai/dist/env-api-keys.d.ts.map +1 -1
  331. package/packages/pi-ai/dist/env-api-keys.js +3 -0
  332. package/packages/pi-ai/dist/env-api-keys.js.map +1 -1
  333. package/packages/pi-ai/dist/index.d.ts +1 -0
  334. package/packages/pi-ai/dist/index.d.ts.map +1 -1
  335. package/packages/pi-ai/dist/index.js +1 -0
  336. package/packages/pi-ai/dist/index.js.map +1 -1
  337. package/packages/pi-ai/dist/providers/transform-messages.d.ts.map +1 -1
  338. package/packages/pi-ai/dist/providers/transform-messages.js +7 -3
  339. package/packages/pi-ai/dist/providers/transform-messages.js.map +1 -1
  340. package/packages/pi-ai/dist/tool-result-content.d.ts +3 -0
  341. package/packages/pi-ai/dist/tool-result-content.d.ts.map +1 -0
  342. package/packages/pi-ai/dist/tool-result-content.js +62 -0
  343. package/packages/pi-ai/dist/tool-result-content.js.map +1 -0
  344. package/packages/pi-ai/dist/types.d.ts +10 -22
  345. package/packages/pi-ai/dist/types.d.ts.map +1 -1
  346. package/packages/pi-ai/dist/types.js.map +1 -1
  347. package/packages/pi-ai/package.json +1 -1
  348. package/packages/pi-coding-agent/dist/core/model-resolver.d.ts.map +1 -1
  349. package/packages/pi-coding-agent/dist/core/model-resolver.js +1 -0
  350. package/packages/pi-coding-agent/dist/core/model-resolver.js.map +1 -1
  351. package/packages/pi-coding-agent/dist/core/session-manager-types.d.ts +1 -0
  352. package/packages/pi-coding-agent/dist/core/session-manager-types.d.ts.map +1 -1
  353. package/packages/pi-coding-agent/dist/core/session-manager-types.js.map +1 -1
  354. package/packages/pi-coding-agent/dist/core/session-manager.d.ts.map +1 -1
  355. package/packages/pi-coding-agent/dist/core/session-manager.js +3 -0
  356. package/packages/pi-coding-agent/dist/core/session-manager.js.map +1 -1
  357. package/packages/pi-coding-agent/package.json +7 -7
  358. package/packages/pi-tui/package.json +2 -2
  359. package/packages/rpc-client/dist/rpc-client.js +1 -1
  360. package/packages/rpc-client/dist/rpc-client.js.map +1 -1
  361. package/packages/rpc-client/package.json +2 -2
  362. package/pkg/dist/core/export-html/template.js +53 -4
  363. package/pkg/package.json +1 -1
  364. package/scripts/link-workspace-packages.cjs +14 -4
  365. package/src/resources/GSD-WORKFLOW.md +20 -25
  366. package/src/resources/extensions/claude-code-cli/stream-adapter.ts +130 -51
  367. package/src/resources/extensions/claude-code-cli/tests/stream-adapter.test.ts +371 -39
  368. package/src/resources/extensions/cursor-cli/index.ts +18 -0
  369. package/src/resources/extensions/cursor-cli/models.ts +65 -0
  370. package/src/resources/extensions/cursor-cli/package.json +11 -0
  371. package/src/resources/extensions/cursor-cli/readiness.ts +143 -0
  372. package/src/resources/extensions/cursor-cli/stream-adapter.ts +440 -0
  373. package/src/resources/extensions/cursor-cli/tests/index.test.ts +54 -0
  374. package/src/resources/extensions/cursor-cli/tests/readiness.test.ts +29 -0
  375. package/src/resources/extensions/cursor-cli/tests/stream-adapter.test.ts +166 -0
  376. package/src/resources/extensions/gsd/activity-log.ts +4 -1
  377. package/src/resources/extensions/gsd/artifact-verification.ts +25 -9
  378. package/src/resources/extensions/gsd/auto/closeout.ts +163 -58
  379. package/src/resources/extensions/gsd/auto/finalize.ts +8 -0
  380. package/src/resources/extensions/gsd/auto/loop-deps.ts +1 -0
  381. package/src/resources/extensions/gsd/auto/orchestrator.ts +4 -3
  382. package/src/resources/extensions/gsd/auto/pre-dispatch.ts +6 -3
  383. package/src/resources/extensions/gsd/auto/run-unit.ts +5 -2
  384. package/src/resources/extensions/gsd/auto/schedule-wakeup.ts +8 -0
  385. package/src/resources/extensions/gsd/auto/unit-phase.ts +5 -9
  386. package/src/resources/extensions/gsd/auto-direct-dispatch.ts +4 -5
  387. package/src/resources/extensions/gsd/auto-dispatch.ts +17 -5
  388. package/src/resources/extensions/gsd/auto-model-selection.ts +49 -18
  389. package/src/resources/extensions/gsd/auto-prompts.ts +73 -2
  390. package/src/resources/extensions/gsd/auto-start.ts +8 -5
  391. package/src/resources/extensions/gsd/auto-timeout-recovery.ts +4 -0
  392. package/src/resources/extensions/gsd/auto-worktree-branch-lifecycle.ts +237 -0
  393. package/src/resources/extensions/gsd/auto-worktree-cleanup.ts +166 -0
  394. package/src/resources/extensions/gsd/auto-worktree-conflict-auto-resolve.ts +37 -0
  395. package/src/resources/extensions/gsd/auto-worktree-creation.ts +171 -0
  396. package/src/resources/extensions/gsd/auto-worktree-entry.ts +154 -0
  397. package/src/resources/extensions/gsd/auto-worktree-merge-already-merged.ts +161 -0
  398. package/src/resources/extensions/gsd/auto-worktree-merge-branch-head.ts +83 -0
  399. package/src/resources/extensions/gsd/auto-worktree-merge-cleanup.ts +132 -0
  400. package/src/resources/extensions/gsd/auto-worktree-merge-code-changes.ts +71 -0
  401. package/src/resources/extensions/gsd/auto-worktree-merge-db-ready.ts +112 -0
  402. package/src/resources/extensions/gsd/auto-worktree-merge-integration-branch.ts +99 -0
  403. package/src/resources/extensions/gsd/auto-worktree-merge-message.ts +166 -0
  404. package/src/resources/extensions/gsd/auto-worktree-merge-pre-teardown.ts +93 -0
  405. package/src/resources/extensions/gsd/auto-worktree-merge-stash.ts +213 -0
  406. package/src/resources/extensions/gsd/auto-worktree-merge.ts +391 -0
  407. package/src/resources/extensions/gsd/auto-worktree-milestone-shelter.ts +159 -0
  408. package/src/resources/extensions/gsd/auto-worktree-path-resolution.ts +6 -0
  409. package/src/resources/extensions/gsd/auto-worktree-path-utils.ts +10 -0
  410. package/src/resources/extensions/gsd/auto-worktree-resource-version.ts +44 -0
  411. package/src/resources/extensions/gsd/auto-worktree-runtime-cleanup.ts +119 -0
  412. package/src/resources/extensions/gsd/auto-worktree-session-registry.ts +71 -0
  413. package/src/resources/extensions/gsd/auto-worktree-sync.ts +370 -0
  414. package/src/resources/extensions/gsd/auto-worktree-teardown.ts +161 -0
  415. package/src/resources/extensions/gsd/auto-worktree.ts +69 -2390
  416. package/src/resources/extensions/gsd/auto.ts +32 -19
  417. package/src/resources/extensions/gsd/bootstrap/db-tools.ts +3 -0
  418. package/src/resources/extensions/gsd/bootstrap/dynamic-tools.ts +1 -1
  419. package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +147 -6
  420. package/src/resources/extensions/gsd/bootstrap/schedule-wakeup-tool.ts +80 -12
  421. package/src/resources/extensions/gsd/bootstrap/system-context.ts +1 -1
  422. package/src/resources/extensions/gsd/bootstrap/tool-call-loop-guard.ts +163 -22
  423. package/src/resources/extensions/gsd/bootstrap/write-gate.ts +23 -1
  424. package/src/resources/extensions/gsd/codebase-generator.ts +179 -18
  425. package/src/resources/extensions/gsd/commands/handlers/core.ts +39 -3
  426. package/src/resources/extensions/gsd/commands-handlers.ts +1 -1
  427. package/src/resources/extensions/gsd/commands-prefs-wizard.ts +135 -1
  428. package/src/resources/extensions/gsd/commands-workflow-templates.ts +3 -3
  429. package/src/resources/extensions/gsd/commands-worktree.ts +13 -2
  430. package/src/resources/extensions/gsd/db/queries.ts +49 -9
  431. package/src/resources/extensions/gsd/discussion-handoff.ts +10 -2
  432. package/src/resources/extensions/gsd/docs/preferences-reference.md +8 -2
  433. package/src/resources/extensions/gsd/doctor-engine-checks.ts +372 -22
  434. package/src/resources/extensions/gsd/doctor-providers.ts +39 -10
  435. package/src/resources/extensions/gsd/doctor-types.ts +5 -1
  436. package/src/resources/extensions/gsd/doctor.ts +95 -3
  437. package/src/resources/extensions/gsd/exec-sandbox.ts +6 -2
  438. package/src/resources/extensions/gsd/flat-phase-migration.ts +112 -25
  439. package/src/resources/extensions/gsd/forensics.ts +1 -1
  440. package/src/resources/extensions/gsd/git-conflict-resolve.ts +2 -2
  441. package/src/resources/extensions/gsd/git-service.ts +67 -17
  442. package/src/resources/extensions/gsd/gsd-db.ts +85 -0
  443. package/src/resources/extensions/gsd/guidance.ts +2 -0
  444. package/src/resources/extensions/gsd/guided-flow.ts +52 -13
  445. package/src/resources/extensions/gsd/key-manager.ts +1 -0
  446. package/src/resources/extensions/gsd/markdown-renderer.ts +40 -10
  447. package/src/resources/extensions/gsd/migrate-external.ts +23 -6
  448. package/src/resources/extensions/gsd/milestone-merge-transaction.ts +19 -4
  449. package/src/resources/extensions/gsd/milestone-settlement.ts +1 -1
  450. package/src/resources/extensions/gsd/model-router.ts +4 -5
  451. package/src/resources/extensions/gsd/parallel-merge.ts +1 -1
  452. package/src/resources/extensions/gsd/parallel-orchestrator.ts +3 -1
  453. package/src/resources/extensions/gsd/preferences-diagnostics.ts +24 -0
  454. package/src/resources/extensions/gsd/preferences-models.ts +6 -3
  455. package/src/resources/extensions/gsd/preferences-types.ts +30 -0
  456. package/src/resources/extensions/gsd/preferences-validation.ts +97 -2
  457. package/src/resources/extensions/gsd/preferences.ts +38 -4
  458. package/src/resources/extensions/gsd/prompts/plan-slice.md +4 -2
  459. package/src/resources/extensions/gsd/prompts/system.md +6 -6
  460. package/src/resources/extensions/gsd/quick.ts +11 -3
  461. package/src/resources/extensions/gsd/redact-secrets.ts +40 -0
  462. package/src/resources/extensions/gsd/repo-identity.ts +17 -0
  463. package/src/resources/extensions/gsd/repository-registry.ts +7 -1
  464. package/src/resources/extensions/gsd/root-write-leak-guard.ts +3 -2
  465. package/src/resources/extensions/gsd/safe-fs.ts +22 -2
  466. package/src/resources/extensions/gsd/skills/gsd-headless/SKILL.md +7 -9
  467. package/src/resources/extensions/gsd/skills/gsd-headless/references/commands.md +1 -0
  468. package/src/resources/extensions/gsd/slice-parallel-orchestrator.ts +3 -1
  469. package/src/resources/extensions/gsd/state/derive/from-db.ts +201 -157
  470. package/src/resources/extensions/gsd/tests/auto-loop-no-copy-artifacts.test.ts +2 -1
  471. package/src/resources/extensions/gsd/tests/auto-loop.test.ts +131 -5
  472. package/src/resources/extensions/gsd/tests/auto-migrating-recovery.test.ts +18 -0
  473. package/src/resources/extensions/gsd/tests/auto-model-selection.test.ts +178 -0
  474. package/src/resources/extensions/gsd/tests/auto-phases-lifecycle.test.ts +43 -1
  475. package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +54 -0
  476. package/src/resources/extensions/gsd/tests/auto-remote-session-lock-cleanup.test.ts +41 -0
  477. package/src/resources/extensions/gsd/tests/auto-runtime-state.test.ts +41 -0
  478. package/src/resources/extensions/gsd/tests/auto-session-scope.test.ts +4 -4
  479. package/src/resources/extensions/gsd/tests/auto-start-bootstrap-await-3420.test.ts +3 -0
  480. package/src/resources/extensions/gsd/tests/auto-start-clean-runtime-db-gated.test.ts +1 -1
  481. package/src/resources/extensions/gsd/tests/auto-timeout-recovery-harness-abort.test.ts +55 -0
  482. package/src/resources/extensions/gsd/tests/auto-warning-noise-regression.test.ts +10 -1
  483. package/src/resources/extensions/gsd/tests/auto-worktree-auto-resolve.test.ts +1 -1
  484. package/src/resources/extensions/gsd/tests/auto-worktree-merge-already-merged.test.ts +177 -0
  485. package/src/resources/extensions/gsd/tests/auto-worktree-merge-branch-head.test.ts +118 -0
  486. package/src/resources/extensions/gsd/tests/auto-worktree-merge-cleanup.test.ts +115 -0
  487. package/src/resources/extensions/gsd/tests/auto-worktree-merge-code-changes.test.ts +76 -0
  488. package/src/resources/extensions/gsd/tests/auto-worktree-merge-db-ready.test.ts +140 -0
  489. package/src/resources/extensions/gsd/tests/auto-worktree-merge-integration-branch.test.ts +123 -0
  490. package/src/resources/extensions/gsd/tests/auto-worktree-merge-message.test.ts +114 -0
  491. package/src/resources/extensions/gsd/tests/auto-worktree-merge-pre-teardown.test.ts +84 -0
  492. package/src/resources/extensions/gsd/tests/auto-worktree-merge-stash.test.ts +70 -0
  493. package/src/resources/extensions/gsd/tests/auto-worktree-milestone-shelter.test.ts +52 -0
  494. package/src/resources/extensions/gsd/tests/auto-worktree-registry.test.ts +6 -6
  495. package/src/resources/extensions/gsd/tests/auto-worktree-resource-version.test.ts +59 -0
  496. package/src/resources/extensions/gsd/tests/auto-worktree-untracked-content.test.ts +3 -1
  497. package/src/resources/extensions/gsd/tests/batch-task-query.test.ts +85 -0
  498. package/src/resources/extensions/gsd/tests/check-auto-start-ready-guard.test.ts +29 -0
  499. package/src/resources/extensions/gsd/tests/codebase-generator.test.ts +365 -0
  500. package/src/resources/extensions/gsd/tests/complete-milestone-excerpt.test.ts +62 -1
  501. package/src/resources/extensions/gsd/tests/completed-units-metrics-sync.test.ts +1 -1
  502. package/src/resources/extensions/gsd/tests/derive-state-db.test.ts +4 -0
  503. package/src/resources/extensions/gsd/tests/doctor-providers.test.ts +138 -1
  504. package/src/resources/extensions/gsd/tests/doctor-scope-db-unavailable.test.ts +571 -5
  505. package/src/resources/extensions/gsd/tests/doctor-workspace.test.ts +207 -0
  506. package/src/resources/extensions/gsd/tests/fast-forward-reused-milestone-branch.test.ts +1 -1
  507. package/src/resources/extensions/gsd/tests/flat-phase-migration.test.ts +82 -2
  508. package/src/resources/extensions/gsd/tests/flat-phase-renderer.test.ts +25 -1
  509. package/src/resources/extensions/gsd/tests/flat-rate-routing-guard.test.ts +87 -19
  510. package/src/resources/extensions/gsd/tests/gate-1b-orphan-discrimination.test.ts +89 -0
  511. package/src/resources/extensions/gsd/tests/gsd-db.test.ts +40 -0
  512. package/src/resources/extensions/gsd/tests/guided-flow-session-isolation.test.ts +9 -0
  513. package/src/resources/extensions/gsd/tests/integration/all-milestones-complete-merge.test.ts +4 -6
  514. package/src/resources/extensions/gsd/tests/integration/auto-stash-merge.test.ts +2 -1
  515. package/src/resources/extensions/gsd/tests/integration/auto-worktree-milestone-merge.test.ts +3 -3
  516. package/src/resources/extensions/gsd/tests/integration/auto-worktree.test.ts +7 -8
  517. package/src/resources/extensions/gsd/tests/integration/feature-branch-lifecycle-integration.test.ts +2 -5
  518. package/src/resources/extensions/gsd/tests/integration/git-service.test.ts +76 -0
  519. package/src/resources/extensions/gsd/tests/integration/merge-cwd-restore.test.ts +1 -1
  520. package/src/resources/extensions/gsd/tests/integration/merge-preserve-worktree-on-preteardown-error.test.ts +1 -1
  521. package/src/resources/extensions/gsd/tests/integration/merge-strategy-regular.test.ts +2 -1
  522. package/src/resources/extensions/gsd/tests/integration/milestone-transition-worktree.test.ts +5 -7
  523. package/src/resources/extensions/gsd/tests/integration/state-machine-edge-cases.test.ts +4 -2
  524. package/src/resources/extensions/gsd/tests/integration/workspace-collapse-integration.test.ts +2 -4
  525. package/src/resources/extensions/gsd/tests/markdown-renderer.test.ts +122 -0
  526. package/src/resources/extensions/gsd/tests/merge-closeout-consistency-gate.test.ts +1 -1
  527. package/src/resources/extensions/gsd/tests/merge-conflict-stops-loop.test.ts +4 -4
  528. package/src/resources/extensions/gsd/tests/merge-db-cycle.test.ts +1 -1
  529. package/src/resources/extensions/gsd/tests/merge-self-branch-guard.test.ts +1 -1
  530. package/src/resources/extensions/gsd/tests/migrate-external-worktree.test.ts +116 -0
  531. package/src/resources/extensions/gsd/tests/milestone-merge-stash-restore.test.ts +592 -23
  532. package/src/resources/extensions/gsd/tests/milestone-merge-transaction.test.ts +25 -1
  533. package/src/resources/extensions/gsd/tests/none-mode-gates.test.ts +1 -1
  534. package/src/resources/extensions/gsd/tests/originalbase-path-comparison.test.ts +3 -3
  535. package/src/resources/extensions/gsd/tests/parallel-worker-lock-contention.test.ts +1 -1
  536. package/src/resources/extensions/gsd/tests/pending-autostart-scope.test.ts +2 -2
  537. package/src/resources/extensions/gsd/tests/phases-merge-error-stops-auto.test.ts +50 -6
  538. package/src/resources/extensions/gsd/tests/plan-slice-prompt.test.ts +17 -0
  539. package/src/resources/extensions/gsd/tests/plan-task.test.ts +264 -1
  540. package/src/resources/extensions/gsd/tests/preferences-worktree-sync.test.ts +1 -4
  541. package/src/resources/extensions/gsd/tests/preferences.test.ts +150 -0
  542. package/src/resources/extensions/gsd/tests/prefs-wizard-coverage.test.ts +147 -0
  543. package/src/resources/extensions/gsd/tests/recovery-verify-logs.test.ts +4 -4
  544. package/src/resources/extensions/gsd/tests/redact-secrets.test.ts +56 -0
  545. package/src/resources/extensions/gsd/tests/register-hooks-flat-phase-migration.test.ts +73 -0
  546. package/src/resources/extensions/gsd/tests/register-hooks-loop-guard-auto.test.ts +275 -0
  547. package/src/resources/extensions/gsd/tests/repository-registry.test.ts +41 -2
  548. package/src/resources/extensions/gsd/tests/require-slice-discussion-dispatch.test.ts +55 -0
  549. package/src/resources/extensions/gsd/tests/root-write-leak-guard.test.ts +31 -9
  550. package/src/resources/extensions/gsd/tests/runtime-invariant-modules.test.ts +20 -0
  551. package/src/resources/extensions/gsd/tests/schedule-wakeup-tool.test.ts +167 -0
  552. package/src/resources/extensions/gsd/tests/stale-worktree-cwd.test.ts +3 -5
  553. package/src/resources/extensions/gsd/tests/stalled-tool-recovery.test.ts +49 -0
  554. package/src/resources/extensions/gsd/tests/stash-pop-gsd-conflict.test.ts +2 -1
  555. package/src/resources/extensions/gsd/tests/stash-queued-context-files.test.ts +2 -1
  556. package/src/resources/extensions/gsd/tests/state-corruption-2945.test.ts +1 -1
  557. package/src/resources/extensions/gsd/tests/status-per-repo.test.ts +94 -0
  558. package/src/resources/extensions/gsd/tests/steer-worktree-path.test.ts +1 -1
  559. package/src/resources/extensions/gsd/tests/sync-worktree-skip-current.test.ts +1 -1
  560. package/src/resources/extensions/gsd/tests/system-flat-phase-layout.test.ts +33 -0
  561. package/src/resources/extensions/gsd/tests/teardown-chdir-failure-clears-registry.test.ts +4 -4
  562. package/src/resources/extensions/gsd/tests/teardown-cleanup-parity.test.ts +2 -1
  563. package/src/resources/extensions/gsd/tests/teardown-failure-clears-registry.test.ts +4 -4
  564. package/src/resources/extensions/gsd/tests/token-tool-gating.test.ts +35 -0
  565. package/src/resources/extensions/gsd/tests/tool-call-loop-guard.test.ts +166 -0
  566. package/src/resources/extensions/gsd/tests/uat-stuck-loop-orphaned-worktree.test.ts +1 -1
  567. package/src/resources/extensions/gsd/tests/unit-context-manifest.test.ts +66 -18
  568. package/src/resources/extensions/gsd/tests/unit-registry.test.ts +81 -0
  569. package/src/resources/extensions/gsd/tests/unit-runtime.test.ts +30 -0
  570. package/src/resources/extensions/gsd/tests/uok-gitops-turn-action.test.ts +52 -0
  571. package/src/resources/extensions/gsd/tests/validator-scope-parity.test.ts +53 -1
  572. package/src/resources/extensions/gsd/tests/workflow-tool-executors.test.ts +208 -1
  573. package/src/resources/extensions/gsd/tests/workspace.test.ts +18 -4
  574. package/src/resources/extensions/gsd/tests/worktree-db-integration.test.ts +1 -1
  575. package/src/resources/extensions/gsd/tests/worktree-db-respawn-truncation.test.ts +1 -1
  576. package/src/resources/extensions/gsd/tests/worktree-db-same-file.test.ts +1 -3
  577. package/src/resources/extensions/gsd/tests/worktree-expected-warnings.test.ts +1 -1
  578. package/src/resources/extensions/gsd/tests/worktree-git-pathspec.test.ts +1 -1
  579. package/src/resources/extensions/gsd/tests/worktree-journal-events.test.ts +4 -4
  580. package/src/resources/extensions/gsd/tests/worktree-lifecycle.test.ts +2 -2
  581. package/src/resources/extensions/gsd/tests/worktree-main-branch.test.ts +1 -1
  582. package/src/resources/extensions/gsd/tests/worktree-preferences-sync.test.ts +1 -1
  583. package/src/resources/extensions/gsd/tests/worktree-reentry.test.ts +2 -1
  584. package/src/resources/extensions/gsd/tests/worktree-sync-milestones.test.ts +36 -3
  585. package/src/resources/extensions/gsd/tests/worktree-sync-overwrite-loop.test.ts +1 -1
  586. package/src/resources/extensions/gsd/tests/worktree-sync-tasks.test.ts +1 -1
  587. package/src/resources/extensions/gsd/tests/worktree-teardown-safety.test.ts +32 -0
  588. package/src/resources/extensions/gsd/tool-contract.ts +29 -0
  589. package/src/resources/extensions/gsd/tools/plan-task.ts +107 -9
  590. package/src/resources/extensions/gsd/tools/workflow-tool-executors.ts +58 -0
  591. package/src/resources/extensions/gsd/unit-context-manifest.ts +11 -5
  592. package/src/resources/extensions/gsd/unit-registry.ts +48 -2
  593. package/src/resources/extensions/gsd/unit-runtime.ts +42 -0
  594. package/src/resources/extensions/gsd/unmerged-milestone-guard.ts +1 -1
  595. package/src/resources/extensions/gsd/validation-block-guard.ts +2 -1
  596. package/src/resources/extensions/gsd/workspace-git-preflight.ts +2 -2
  597. package/src/resources/extensions/gsd/workspace.ts +42 -8
  598. package/src/resources/extensions/gsd/worktree-command.ts +1 -1
  599. package/src/resources/extensions/gsd/worktree-lifecycle.ts +154 -26
  600. package/src/resources/extensions/gsd/worktree-manager.ts +143 -5
  601. package/src/resources/extensions/gsd/worktree-reentry.ts +2 -1
  602. package/dist/web/standalone/.next/static/chunks/app/_not-found/page-49f565245e1e4afe.js +0 -1
  603. package/dist/web/standalone/.next/static/chunks/app/page-bc4c723c6a19c6f0.js +0 -1
  604. package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/global-error-ec3eaffc9785ba48.js +0 -1
  605. /package/dist/web/standalone/.next/static/{zQLcXm0Za8lexoXtgDpMG → ZpFDazP-38PXBPiI_LdZf}/_buildManifest.js +0 -0
  606. /package/dist/web/standalone/.next/static/{zQLcXm0Za8lexoXtgDpMG → ZpFDazP-38PXBPiI_LdZf}/_ssgManifest.js +0 -0
@@ -0,0 +1,207 @@
1
+ /**
2
+ * doctor-workspace.test.ts — Parent-workspace declared-repository probe (#818).
3
+ *
4
+ * Covers:
5
+ * - declared child repo path missing on disk → workspace_repo_path_missing
6
+ * - declared child repo path exists but is not a git repo → workspace_repo_not_a_repo
7
+ * - valid child repos → no workspace issues
8
+ * - single-repo (project-mode) project → probe is a no-op
9
+ * - non-git parent root is handled gracefully (the common layout)
10
+ */
11
+
12
+ import test from "node:test";
13
+ import assert from "node:assert/strict";
14
+ import { chmodSync, mkdtempSync, mkdirSync, rmSync, symlinkSync, writeFileSync } from "node:fs";
15
+ import { delimiter, join } from "node:path";
16
+ import { tmpdir } from "node:os";
17
+ import { execFileSync } from "node:child_process";
18
+
19
+ import { runGSDDoctor } from "../doctor.ts";
20
+ import { GIT_NO_PROMPT_ENV } from "../git-constants.ts";
21
+
22
+ function gitInit(cwd: string): void {
23
+ execFileSync("git", ["init"], { cwd, stdio: "ignore" });
24
+ }
25
+
26
+ function writeParentPrefs(base: string, repos: Record<string, { path: string }>): void {
27
+ const repoLines = Object.entries(repos)
28
+ .map(([id, cfg]) => ` ${id}:\n path: ${cfg.path}`)
29
+ .join("\n");
30
+ writeFileSync(
31
+ join(base, ".gsd", "PREFERENCES.md"),
32
+ `---\nversion: 1\nworkspace:\n mode: parent\n repositories:\n${repoLines}\n---\n`,
33
+ "utf-8",
34
+ );
35
+ }
36
+
37
+ test("doctor flags a declared child repo whose path is missing on disk", async () => {
38
+ const base = mkdtempSync(join(tmpdir(), "gsd-doctor-ws-missing-"));
39
+ try {
40
+ mkdirSync(join(base, ".gsd"), { recursive: true });
41
+ gitInit(base);
42
+ // `frontend` is declared but never created on disk.
43
+ writeParentPrefs(base, { frontend: { path: "frontend" } });
44
+
45
+ const report = await runGSDDoctor(base);
46
+ const issue = report.issues.find((i) => i.code === "workspace_repo_path_missing");
47
+ assert.ok(issue, "expected a workspace_repo_path_missing issue");
48
+ assert.equal(issue?.unitId, "workspace.repositories.frontend");
49
+ assert.match(issue?.message ?? "", /does not exist on disk/);
50
+ } finally {
51
+ rmSync(base, { recursive: true, force: true });
52
+ }
53
+ });
54
+
55
+ test("doctor flags a declared child repo path that is not a git repository", async () => {
56
+ const base = mkdtempSync(join(tmpdir(), "gsd-doctor-ws-notrepo-"));
57
+ try {
58
+ mkdirSync(join(base, ".gsd"), { recursive: true });
59
+ gitInit(base);
60
+ // `backend` exists as a plain directory but is not a git repo.
61
+ mkdirSync(join(base, "backend"), { recursive: true });
62
+ writeParentPrefs(base, { backend: { path: "backend" } });
63
+
64
+ const report = await runGSDDoctor(base);
65
+ const issue = report.issues.find((i) => i.code === "workspace_repo_not_a_repo");
66
+ assert.ok(issue, "expected a workspace_repo_not_a_repo issue");
67
+ assert.equal(issue?.unitId, "workspace.repositories.backend");
68
+ assert.match(issue?.message ?? "", /not a git repository/);
69
+ } finally {
70
+ rmSync(base, { recursive: true, force: true });
71
+ }
72
+ });
73
+
74
+ test("doctor reports no workspace issues when declared child repos are valid", async () => {
75
+ const base = mkdtempSync(join(tmpdir(), "gsd-doctor-ws-valid-"));
76
+ try {
77
+ mkdirSync(join(base, ".gsd"), { recursive: true });
78
+ gitInit(base);
79
+ mkdirSync(join(base, "frontend"), { recursive: true });
80
+ gitInit(join(base, "frontend"));
81
+ writeParentPrefs(base, { frontend: { path: "frontend" } });
82
+
83
+ const report = await runGSDDoctor(base);
84
+ const wsIssues = report.issues.filter(
85
+ (i) => i.code === "workspace_repo_path_missing" || i.code === "workspace_repo_not_a_repo",
86
+ );
87
+ assert.deepEqual(wsIssues, []);
88
+ } finally {
89
+ rmSync(base, { recursive: true, force: true });
90
+ }
91
+ });
92
+
93
+ test("doctor workspace git probe uses safe env and canonical toplevel comparison", async (t) => {
94
+ if (process.platform === "win32") {
95
+ t.skip("POSIX-only git shim regression");
96
+ return;
97
+ }
98
+
99
+ const originalProcessGitDir = process.env.GIT_DIR;
100
+ const originalProcessGitWorkTree = process.env.GIT_WORK_TREE;
101
+ const originalGitEnvPath = GIT_NO_PROMPT_ENV.PATH;
102
+ const originalGitEnvRealGit = GIT_NO_PROMPT_ENV.GSD_REAL_GIT;
103
+ const originalGitEnvFakeCwd = GIT_NO_PROMPT_ENV.GSD_FAKE_TOPLEVEL_CWD;
104
+ const originalGitEnvFakeToplevel = GIT_NO_PROMPT_ENV.GSD_FAKE_TOPLEVEL;
105
+ const base = mkdtempSync(join(tmpdir(), "gsd-doctor-ws-safeenv-"));
106
+
107
+ t.after(() => {
108
+ if (originalProcessGitDir === undefined) delete process.env.GIT_DIR;
109
+ else process.env.GIT_DIR = originalProcessGitDir;
110
+ if (originalProcessGitWorkTree === undefined) delete process.env.GIT_WORK_TREE;
111
+ else process.env.GIT_WORK_TREE = originalProcessGitWorkTree;
112
+ if (originalGitEnvPath === undefined) delete GIT_NO_PROMPT_ENV.PATH;
113
+ else GIT_NO_PROMPT_ENV.PATH = originalGitEnvPath;
114
+ if (originalGitEnvRealGit === undefined) delete GIT_NO_PROMPT_ENV.GSD_REAL_GIT;
115
+ else GIT_NO_PROMPT_ENV.GSD_REAL_GIT = originalGitEnvRealGit;
116
+ if (originalGitEnvFakeCwd === undefined) delete GIT_NO_PROMPT_ENV.GSD_FAKE_TOPLEVEL_CWD;
117
+ else GIT_NO_PROMPT_ENV.GSD_FAKE_TOPLEVEL_CWD = originalGitEnvFakeCwd;
118
+ if (originalGitEnvFakeToplevel === undefined) delete GIT_NO_PROMPT_ENV.GSD_FAKE_TOPLEVEL;
119
+ else GIT_NO_PROMPT_ENV.GSD_FAKE_TOPLEVEL = originalGitEnvFakeToplevel;
120
+ rmSync(base, { recursive: true, force: true });
121
+ });
122
+
123
+ mkdirSync(join(base, ".gsd"), { recursive: true });
124
+ const realChild = join(base, "frontend-real");
125
+ const linkedChild = join(base, "frontend");
126
+ mkdirSync(realChild, { recursive: true });
127
+ gitInit(realChild);
128
+ symlinkSync(realChild, linkedChild, "dir");
129
+ writeParentPrefs(base, { frontend: { path: "frontend" } });
130
+
131
+ const shimDir = join(base, "bin");
132
+ mkdirSync(shimDir, { recursive: true });
133
+ const realGit = execFileSync("which", ["git"], { encoding: "utf-8" }).trim();
134
+ const shim = join(shimDir, "git");
135
+ writeFileSync(
136
+ shim,
137
+ [
138
+ "#!/usr/bin/env bash",
139
+ "set -euo pipefail",
140
+ "if [ -n \"${GIT_DIR:-}\" ] || [ -n \"${GIT_WORK_TREE:-}\" ]; then",
141
+ " echo \"leaked git env\" >&2",
142
+ " exit 97",
143
+ "fi",
144
+ "if [ \"${1:-}\" = \"rev-parse\" ] && [ \"${2:-}\" = \"--show-toplevel\" ] && [ \"$(pwd -P)\" = \"$GSD_FAKE_TOPLEVEL_CWD\" ]; then",
145
+ " printf '%s\\n' \"$GSD_FAKE_TOPLEVEL\"",
146
+ " exit 0",
147
+ "fi",
148
+ "exec \"$GSD_REAL_GIT\" \"$@\"",
149
+ "",
150
+ ].join("\n"),
151
+ "utf-8",
152
+ );
153
+ chmodSync(shim, 0o755);
154
+
155
+ process.env.GIT_DIR = join(base, ".git");
156
+ process.env.GIT_WORK_TREE = base;
157
+ GIT_NO_PROMPT_ENV.PATH = `${shimDir}${delimiter}${process.env.PATH ?? ""}`;
158
+ GIT_NO_PROMPT_ENV.GSD_REAL_GIT = realGit;
159
+ GIT_NO_PROMPT_ENV.GSD_FAKE_TOPLEVEL_CWD = realChild;
160
+ GIT_NO_PROMPT_ENV.GSD_FAKE_TOPLEVEL = linkedChild;
161
+
162
+ const report = await runGSDDoctor(base);
163
+ const wsIssues = report.issues.filter(
164
+ (i) => i.code === "workspace_repo_path_missing" || i.code === "workspace_repo_not_a_repo",
165
+ );
166
+ assert.deepEqual(wsIssues, []);
167
+ });
168
+
169
+ test("doctor workspace probe is a no-op for single-repo (project-mode) projects", async () => {
170
+ const base = mkdtempSync(join(tmpdir(), "gsd-doctor-ws-noproj-"));
171
+ try {
172
+ mkdirSync(join(base, ".gsd"), { recursive: true });
173
+ gitInit(base);
174
+ // No workspace config → project mode (default).
175
+ const report = await runGSDDoctor(base);
176
+ const wsIssues = report.issues.filter(
177
+ (i) => i.code === "workspace_repo_path_missing" || i.code === "workspace_repo_not_a_repo",
178
+ );
179
+ assert.deepEqual(wsIssues, []);
180
+ } finally {
181
+ rmSync(base, { recursive: true, force: true });
182
+ }
183
+ });
184
+
185
+ test("doctor runs cleanly when the parent root is itself not a git repo (common layout)", async () => {
186
+ // Regression guard (#818 cross-cutting): a parent folder holding child git
187
+ // repos need not be a git repo itself. Doctor must not crash and must not
188
+ // treat the parent as a missing/non-repo child.
189
+ const base = mkdtempSync(join(tmpdir(), "gsd-doctor-ws-nongitparent-"));
190
+ try {
191
+ mkdirSync(join(base, ".gsd"), { recursive: true });
192
+ // NOTE: no gitInit(base) — parent is a plain folder.
193
+ mkdirSync(join(base, "frontend"), { recursive: true });
194
+ gitInit(join(base, "frontend"));
195
+ writeParentPrefs(base, { frontend: { path: "frontend" } });
196
+
197
+ const report = await runGSDDoctor(base);
198
+ // The declared child repo is valid; the non-git parent must not produce a
199
+ // child-repo issue or crash the run.
200
+ const wsIssues = report.issues.filter(
201
+ (i) => i.code === "workspace_repo_path_missing" || i.code === "workspace_repo_not_a_repo",
202
+ );
203
+ assert.deepEqual(wsIssues, []);
204
+ } finally {
205
+ rmSync(base, { recursive: true, force: true });
206
+ }
207
+ });
@@ -13,7 +13,7 @@ import { basename, join } from "node:path";
13
13
  import {
14
14
  fastForwardReusedMilestoneBranchIfSafe,
15
15
  _isBranchCheckedOutElsewhere,
16
- } from "../auto-worktree.js";
16
+ } from "../auto-worktree-branch-lifecycle.js";
17
17
 
18
18
  const NO_PROMPT_ENV = {
19
19
  ...process.env,
@@ -2,17 +2,18 @@
2
2
  // File Purpose: Tests the one-time migration from nested to flat-phase layout.
3
3
  import test, { afterEach } from "node:test";
4
4
  import assert from "node:assert/strict";
5
- import { mkdtempSync, mkdirSync, rmSync, writeFileSync, existsSync, readdirSync, readFileSync, utimesSync } from "node:fs";
5
+ import { mkdtempSync, mkdirSync, renameSync, rmSync, writeFileSync, existsSync, readdirSync, readFileSync, utimesSync } from "node:fs";
6
6
  import { join } from "node:path";
7
7
  import { tmpdir } from "node:os";
8
8
  import { randomUUID } from "node:crypto";
9
9
 
10
10
  import {
11
+ _setFlatPhaseMigrationFsOpsForTest,
11
12
  migrateToFlatPhase,
12
13
  needsFlatPhaseMigration,
13
14
  pruneStaleFlatPhaseBackups,
14
15
  } from "../flat-phase-migration.ts";
15
- import { openDatabase, closeDatabase, insertMilestone, insertSlice, insertTask, getAllMilestones, getMilestoneSlices, getSliceTasks } from "../gsd-db.ts";
16
+ import { openDatabase, closeDatabase, insertArtifact, insertMilestone, insertSlice, insertTask, getAllMilestones, getMilestoneSlices, getSliceTasks, _getAdapter } from "../gsd-db.ts";
16
17
 
17
18
  const tmpDirs: string[] = [];
18
19
  function makeTmp(options: { withTask?: boolean } = {}): string {
@@ -64,6 +65,42 @@ test("migrateToFlatPhase moves content from milestones/ to phases/", async () =>
64
65
  assert.ok(!existsSync(join(base, ".gsd", "milestones")), "milestones/ should be removed");
65
66
  });
66
67
 
68
+ test("migrateToFlatPhase ignores and removes stale phase dirs from prior aborted runs", async () => {
69
+ const base = makeTmp();
70
+ const stalePhaseDir = join(base, ".gsd", "phases", "99-stale-aborted-run");
71
+ mkdirSync(stalePhaseDir, { recursive: true });
72
+
73
+ await migrateToFlatPhase(base);
74
+
75
+ assert.ok(existsSync(join(base, ".gsd", "phases", "01-foundation")), "current DB phase should render");
76
+ assert.equal(existsSync(stalePhaseDir), false, "stale pre-existing phase dir should be removed");
77
+ });
78
+
79
+ test("migrateToFlatPhase falls back to copy-delete when legacy rename is blocked", async (t) => {
80
+ const base = makeTmp();
81
+ const milestonesPath = join(base, ".gsd", "milestones");
82
+ const migratingPath = join(base, ".gsd", "milestones.migrating");
83
+ let blockedRenameAttempts = 0;
84
+
85
+ const restoreFsOps = _setFlatPhaseMigrationFsOpsForTest({
86
+ renameSync(src, dst) {
87
+ if (src === milestonesPath && dst === migratingPath) {
88
+ blockedRenameAttempts++;
89
+ throw Object.assign(new Error("simulated busy handle"), { code: "EPERM" });
90
+ }
91
+ return renameSync(src, dst);
92
+ },
93
+ });
94
+ t.after(restoreFsOps);
95
+
96
+ await migrateToFlatPhase(base);
97
+
98
+ assert.equal(blockedRenameAttempts, 1, "test should exercise the rename fallback path");
99
+ assert.ok(existsSync(join(base, ".gsd", "phases", "01-foundation")), "flat phase should render");
100
+ assert.equal(existsSync(milestonesPath), false, "legacy milestones dir should be removed");
101
+ assert.equal(existsSync(migratingPath), false, "staging dir should be removed after success");
102
+ });
103
+
67
104
  test("migrateToFlatPhase creates a backup", async () => {
68
105
  const base = makeTmp();
69
106
  await migrateToFlatPhase(base);
@@ -83,6 +120,49 @@ test("migrateToFlatPhase preserves milestone/slice/task counts in DB", async ()
83
120
  assert.equal(getSliceTasks("M001", "S01").length, tasksBefore);
84
121
  });
85
122
 
123
+ test("migrateToFlatPhase prunes legacy milestones artifact rows after flat render", async () => {
124
+ const base = makeTmp();
125
+ insertArtifact({
126
+ path: "milestones/M001/M001-ROADMAP.md",
127
+ artifact_type: "ROADMAP",
128
+ milestone_id: "M001",
129
+ slice_id: null,
130
+ task_id: null,
131
+ full_content: "# M001: Foundation\n",
132
+ });
133
+ insertArtifact({
134
+ path: "milestones/M001/slices/S01/S01-PLAN.md",
135
+ artifact_type: "PLAN",
136
+ milestone_id: "M001",
137
+ slice_id: "S01",
138
+ task_id: null,
139
+ full_content: "# Plan\n",
140
+ });
141
+ insertArtifact({
142
+ path: "milestones/M001/slices/S01/tasks/T01-PLAN.md",
143
+ artifact_type: "PLAN",
144
+ milestone_id: "M001",
145
+ slice_id: "S01",
146
+ task_id: "T01",
147
+ full_content: "# Task Plan\n",
148
+ });
149
+
150
+ await migrateToFlatPhase(base);
151
+
152
+ const rows = _getAdapter()!
153
+ .prepare("SELECT path FROM artifacts ORDER BY path")
154
+ .all() as Array<{ path: string }>;
155
+ assert.equal(
156
+ rows.some((row) => row.path.startsWith("milestones/")),
157
+ false,
158
+ "legacy milestones/ artifact rows should be pruned after successful flat migration",
159
+ );
160
+ assert.ok(
161
+ rows.some((row) => row.path.startsWith("phases/")),
162
+ "flat-phase render should leave replacement projection rows in the artifacts table",
163
+ );
164
+ });
165
+
86
166
  test("migrateToFlatPhase is idempotent (second run is a no-op)", async () => {
87
167
  const base = makeTmp();
88
168
  await migrateToFlatPhase(base);
@@ -7,7 +7,8 @@ import { join } from "node:path";
7
7
  import { tmpdir } from "node:os";
8
8
  import { randomUUID } from "node:crypto";
9
9
 
10
- import { renderPlanFromDb, renderRoadmapFromDb } from "../markdown-renderer.ts";
10
+ import { renderPlanFromDb, renderRoadmapFromDb, renderAssessmentFromDb } from "../markdown-renderer.ts";
11
+ import { clearPathCache } from "../paths.ts";
11
12
  import { openDatabase, closeDatabase, insertMilestone, insertSlice, insertTask } from "../gsd-db.ts";
12
13
 
13
14
  const tmpDirs: string[] = [];
@@ -81,3 +82,26 @@ test("renderPlanFromDb does NOT write per-task plan files", async () => {
81
82
  // taskPlanPaths should be empty — no per-task files written
82
83
  assert.equal(result.taskPlanPaths.length, 0);
83
84
  });
85
+
86
+ // Regression for #1190: a stray slices/SID/ subdir inside a flat-phase milestone
87
+ // must not divert the ASSESSMENT write into slices/SID/ (a hybrid path that
88
+ // auto-mode verification cannot find). It must land at the phase root.
89
+ test("renderAssessmentFromDb writes to the phase root even when a stray slices/SID/ dir exists", async () => {
90
+ const base = makeTmp();
91
+ const plan = await renderPlanFromDb(base, "M001", "S01");
92
+ const phaseDir = plan.planPath.slice(0, plan.planPath.lastIndexOf("01-01-PLAN.md"));
93
+
94
+ // Simulate the anomaly: an earlier planning step created slices/S01/ inside
95
+ // the flat-phase dir.
96
+ mkdirSync(join(phaseDir, "slices", "S01"), { recursive: true });
97
+ clearPathCache();
98
+
99
+ const result = await renderAssessmentFromDb(base, "M001", "S01", {
100
+ verdict: "on-track",
101
+ assessment: "Roadmap is on track.",
102
+ });
103
+
104
+ assert.match(result.assessmentPath, /phases[/\\]01-[^/\\]+[/\\]01-01-ASSESSMENT\.md$/);
105
+ assert.ok(!result.assessmentPath.includes(join("slices", "S01")), "must not write under slices/S01/");
106
+ assert.ok(existsSync(result.assessmentPath), "assessment file should exist at the phase root");
107
+ });
@@ -1,7 +1,6 @@
1
1
  /**
2
- * Regression test for #3453: dynamic model routing must be disabled for
3
- * flat-rate providers like GitHub Copilot where all models cost the same
4
- * per request — routing only degrades quality with no cost benefit.
2
+ * Regression tests for flat-rate provider detection and the explicit opt-out
3
+ * that suppresses dynamic routing for subscription providers.
5
4
  */
6
5
 
7
6
  import { describe, test } from "node:test";
@@ -9,7 +8,7 @@ import assert from "node:assert/strict";
9
8
  import { mkdtempSync, mkdirSync, writeFileSync, rmSync } from "node:fs";
10
9
  import { tmpdir } from "node:os";
11
10
  import { join } from "node:path";
12
- import { buildFlatRateContext, isFlatRateProvider, resolvePreferredModelConfig } from "../auto-model-selection.ts";
11
+ import { buildFlatRateContext, isFlatRateProvider, resolvePreferredModelConfig, selectAndApplyModel } from "../auto-model-selection.ts";
13
12
 
14
13
  describe("flat-rate provider routing guard (#3453)", () => {
15
14
 
@@ -35,23 +34,18 @@ describe("flat-rate provider routing guard (#3453)", () => {
35
34
  assert.equal(isFlatRateProvider("openai"), false);
36
35
  });
37
36
 
38
- test("resolvePreferredModelConfig returns undefined for copilot start model", () => {
37
+ test("resolvePreferredModelConfig synthesizes routing config for copilot start model when routing is enabled", () => {
39
38
  const originalCwd = process.cwd();
40
39
  const originalGsdHome = process.env.GSD_HOME;
41
40
  const tempProject = mkdtempSync(join(tmpdir(), "gsd-flat-rate-project-"));
42
41
  const tempGsdHome = mkdtempSync(join(tmpdir(), "gsd-flat-rate-home-"));
43
42
 
44
- // When the user's start model is on a flat-rate provider,
45
- // resolvePreferredModelConfig should not synthesize a routing
46
- // config from tier_models — it should return undefined so the
47
- // user's selected model is preserved.
48
43
  try {
49
44
  mkdirSync(join(tempProject, ".gsd"), { recursive: true });
50
45
  writeFileSync(
51
46
  join(tempProject, ".gsd", "PREFERENCES.md"),
52
47
  [
53
48
  "---",
54
- "token_profile: burn-max",
55
49
  "dynamic_routing:",
56
50
  " enabled: true",
57
51
  " tier_models:",
@@ -70,10 +64,83 @@ describe("flat-rate provider routing guard (#3453)", () => {
70
64
  id: "claude-sonnet-4",
71
65
  });
72
66
 
73
- // Should be undefined (no routing config created for flat-rate)
74
- // Note: this only tests the synthesis guard — explicit per-unit config
75
- // still takes precedence when the user configured one.
76
- assert.equal(result, undefined, "Should not create routing config for copilot");
67
+ assert.deepEqual(result, {
68
+ primary: "claude-opus-4-6",
69
+ fallbacks: [],
70
+ source: "synthesized",
71
+ });
72
+ } finally {
73
+ process.chdir(originalCwd);
74
+ if (originalGsdHome === undefined) delete process.env.GSD_HOME;
75
+ else process.env.GSD_HOME = originalGsdHome;
76
+ rmSync(tempProject, { recursive: true, force: true });
77
+ rmSync(tempGsdHome, { recursive: true, force: true });
78
+ }
79
+ });
80
+
81
+ test("selectAndApplyModel runs synthesized dynamic routing for flat-rate start model", async () => {
82
+ const originalCwd = process.cwd();
83
+ const originalGsdHome = process.env.GSD_HOME;
84
+ const tempProject = mkdtempSync(join(tmpdir(), "gsd-flat-rate-project-"));
85
+ const tempGsdHome = mkdtempSync(join(tmpdir(), "gsd-flat-rate-home-"));
86
+ const setModelCalls: string[] = [];
87
+
88
+ try {
89
+ mkdirSync(join(tempProject, ".gsd"), { recursive: true });
90
+ writeFileSync(
91
+ join(tempProject, ".gsd", "PREFERENCES.md"),
92
+ [
93
+ "---",
94
+ "dynamic_routing:",
95
+ " enabled: true",
96
+ " hooks: false",
97
+ " budget_pressure: false",
98
+ " tier_models:",
99
+ " light: claude-haiku-4-5",
100
+ " standard: claude-sonnet-4-6",
101
+ " heavy: claude-opus-4-6",
102
+ "---",
103
+ ].join("\n"),
104
+ "utf-8",
105
+ );
106
+ process.env.GSD_HOME = tempGsdHome;
107
+ process.chdir(tempProject);
108
+
109
+ const availableModels = [
110
+ { id: "claude-haiku-4-5", provider: "claude-code", api: "anthropic-messages" },
111
+ { id: "claude-sonnet-4-6", provider: "claude-code", api: "anthropic-messages" },
112
+ { id: "claude-opus-4-6", provider: "claude-code", api: "anthropic-messages" },
113
+ ];
114
+
115
+ const result = await selectAndApplyModel(
116
+ {
117
+ modelRegistry: { getAvailable: () => availableModels },
118
+ sessionManager: { getSessionId: () => "test-session" },
119
+ ui: { notify: () => {} },
120
+ model: { provider: "claude-code", id: "claude-opus-4-6", api: "anthropic-messages" },
121
+ } as any,
122
+ {
123
+ setModel: async (model: { provider: string; id: string }) => {
124
+ setModelCalls.push(`${model.provider}/${model.id}`);
125
+ return true;
126
+ },
127
+ emitBeforeModelSelect: async () => undefined,
128
+ getActiveTools: () => [],
129
+ emitAdjustToolSet: async () => undefined,
130
+ setActiveTools: () => {},
131
+ } as any,
132
+ "execute-task",
133
+ "M001/S01/T01",
134
+ tempProject,
135
+ undefined,
136
+ false,
137
+ { provider: "claude-code", id: "claude-opus-4-6" },
138
+ undefined,
139
+ true,
140
+ );
141
+
142
+ assert.deepEqual(setModelCalls, ["claude-code/claude-sonnet-4-6"]);
143
+ assert.deepEqual(result.routing, { tier: "standard", modelDowngraded: true });
77
144
  } finally {
78
145
  process.chdir(originalCwd);
79
146
  if (originalGsdHome === undefined) delete process.env.GSD_HOME;
@@ -220,9 +287,9 @@ describe("buildFlatRateContext()", () => {
220
287
  });
221
288
  });
222
289
 
223
- // ─── #4386: allow_flat_rate_providers opt-in ────────────────────────────────
290
+ // ─── #4386/#1115: allow_flat_rate_providers override ────────────────────────
224
291
 
225
- describe("flat-rate routing opt-in (#4386)", () => {
292
+ describe("flat-rate routing override (#4386/#1115)", () => {
226
293
  function withPrefs(prefsYaml: string, fn: () => void): void {
227
294
  const originalCwd = process.cwd();
228
295
  const originalGsdHome = process.env.GSD_HOME;
@@ -247,7 +314,7 @@ describe("flat-rate routing opt-in (#4386)", () => {
247
314
  }
248
315
  }
249
316
 
250
- test("default (opt-in absent): flat-rate start model still returns undefined", () => {
317
+ test("default (allow absent): flat-rate start model still synthesizes routing config", () => {
251
318
  withPrefs(
252
319
  [
253
320
  "dynamic_routing:",
@@ -260,12 +327,13 @@ describe("flat-rate routing opt-in (#4386)", () => {
260
327
  provider: "claude-code",
261
328
  id: "claude-opus-4-6",
262
329
  });
263
- assert.equal(result, undefined, "default must preserve #3453 bypass");
330
+ assert.ok(result, "routing config should be synthesized");
331
+ assert.equal(result!.primary, "claude-opus-4-6");
264
332
  },
265
333
  );
266
334
  });
267
335
 
268
- test("opt-in: synthesizes a routing config for flat-rate start model", () => {
336
+ test("explicit allow: synthesizes a routing config for flat-rate start model", () => {
269
337
  withPrefs(
270
338
  [
271
339
  "dynamic_routing:",
@@ -14,6 +14,7 @@ import { tmpdir } from "node:os";
14
14
 
15
15
  import {
16
16
  checkAutoStartAfterDiscuss,
17
+ _getPendingAutoStart,
17
18
  setPendingAutoStart,
18
19
  clearPendingAutoStart,
19
20
  } from "../guided-flow.ts";
@@ -21,6 +22,7 @@ import { drainLogs } from "../workflow-logger.ts";
21
22
  import {
22
23
  openDatabase,
23
24
  closeDatabase,
25
+ getMilestone,
24
26
  insertMilestone,
25
27
  } from "../gsd-db.ts";
26
28
 
@@ -59,6 +61,12 @@ function mkBase(): string {
59
61
  return base;
60
62
  }
61
63
 
64
+ function mkFlatBase(): string {
65
+ const base = mkdtempSync(join(tmpdir(), "gsd-gate1b-flat-"));
66
+ mkdirSync(join(base, ".gsd", "phases", "01-m001"), { recursive: true });
67
+ return base;
68
+ }
69
+
62
70
  function writeContext(base: string): void {
63
71
  writeFileSync(
64
72
  join(base, ".gsd", "milestones", "M001", "M001-CONTEXT.md"),
@@ -66,6 +74,13 @@ function writeContext(base: string): void {
66
74
  );
67
75
  }
68
76
 
77
+ function writeFlatContext(base: string): void {
78
+ writeFileSync(
79
+ join(base, ".gsd", "phases", "01-m001", "01-CONTEXT.md"),
80
+ "# M001: Test Milestone\n\nContext written by discuss phase.\n",
81
+ );
82
+ }
83
+
69
84
  describe("Gate 1b discussion handoff in checkAutoStartAfterDiscuss", () => {
70
85
  let base: string;
71
86
  let cap: MockCapture;
@@ -142,4 +157,78 @@ describe("Gate 1b discussion handoff in checkAutoStartAfterDiscuss", () => {
142
157
  );
143
158
  assert.equal(gate1bLog, undefined, "Gate 1b must not log when CONTEXT.md is absent");
144
159
  });
160
+
161
+ test("flat-phase CONTEXT.md accepts handoff without a legacy milestone context file", () => {
162
+ base = mkFlatBase();
163
+ openDatabase(":memory:");
164
+ insertMilestone({ id: "M001", title: "Test Milestone", status: "queued" });
165
+ writeFlatContext(base);
166
+
167
+ cap = mkCapture();
168
+ setPendingAutoStart(base, {
169
+ basePath: base,
170
+ milestoneId: "M001",
171
+ startAuto: false,
172
+ ctx: mkCtx(cap),
173
+ pi: mkPi(cap),
174
+ });
175
+
176
+ const result = checkAutoStartAfterDiscuss();
177
+
178
+ assert.equal(result, true, "flat-phase context must be found by the handoff");
179
+ assert.equal(cap.messages.length, 0, "startAuto=false must suppress scheduling");
180
+ assert.deepEqual(cap.notifies[0], {
181
+ msg: "Milestone M001 context captured. Continuing the planning pipeline.",
182
+ level: "success",
183
+ });
184
+ });
185
+
186
+ test("DB-unavailable recovery blocks handoff instead of reporting success", () => {
187
+ base = mkFlatBase();
188
+ writeFlatContext(base);
189
+
190
+ cap = mkCapture();
191
+ setPendingAutoStart(base, {
192
+ basePath: base,
193
+ milestoneId: "M001",
194
+ startAuto: false,
195
+ ctx: mkCtx(cap),
196
+ pi: mkPi(cap),
197
+ });
198
+
199
+ const result = checkAutoStartAfterDiscuss();
200
+
201
+ assert.equal(result, false, "handoff must fail closed when the DB row cannot be confirmed");
202
+ assert.equal(cap.messages.length, 0, "must not schedule auto-start when DB is unavailable");
203
+ assert.equal(
204
+ cap.notifies.some(n => n.level === "success"),
205
+ false,
206
+ "must not report a successful handoff when DB recovery was skipped",
207
+ );
208
+ assert.ok(_getPendingAutoStart(base), "pending handoff should remain for a later recovery attempt");
209
+ });
210
+
211
+ test("missing DB row with CONTEXT.md inserts a queued row and accepts handoff", () => {
212
+ base = mkFlatBase();
213
+ openDatabase(":memory:");
214
+ writeFlatContext(base);
215
+
216
+ cap = mkCapture();
217
+ setPendingAutoStart(base, {
218
+ basePath: base,
219
+ milestoneId: "M001",
220
+ startAuto: false,
221
+ ctx: mkCtx(cap),
222
+ pi: mkPi(cap),
223
+ });
224
+
225
+ const result = checkAutoStartAfterDiscuss();
226
+
227
+ assert.equal(result, true, "successful insert should recover the missing row");
228
+ assert.equal(getMilestone("M001")?.status, "queued");
229
+ assert.deepEqual(cap.notifies[0], {
230
+ msg: "Milestone M001 context captured. Continuing the planning pipeline.",
231
+ level: "success",
232
+ });
233
+ });
145
234
  });