gsd-pi 2.78.0-dev.aeeb2ca00 → 2.78.1-dev.0fdacd524

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 (471) hide show
  1. package/README.md +8 -7
  2. package/dist/bundled-resource-path.d.ts +7 -0
  3. package/dist/bundled-resource-path.js +34 -2
  4. package/dist/claude-cli-check.js +77 -38
  5. package/dist/cli-policy.d.ts +13 -0
  6. package/dist/cli-policy.js +17 -0
  7. package/dist/cli.js +95 -55
  8. package/dist/headless-query.d.ts +22 -0
  9. package/dist/headless-query.js +43 -8
  10. package/dist/headless.d.ts +10 -0
  11. package/dist/headless.js +16 -1
  12. package/dist/loader.js +9 -13
  13. package/dist/onboarding.d.ts +10 -0
  14. package/dist/onboarding.js +2 -2
  15. package/dist/provider-migrations.d.ts +2 -2
  16. package/dist/provider-migrations.js +5 -2
  17. package/dist/resource-loader.d.ts +5 -2
  18. package/dist/resource-loader.js +30 -13
  19. package/dist/resources/.managed-resources-content-hash +1 -0
  20. package/dist/resources/extensions/claude-code-cli/readiness.js +90 -46
  21. package/dist/resources/extensions/google-search/index.js +2 -6
  22. package/dist/resources/extensions/gsd/auto/loop.js +23 -0
  23. package/dist/resources/extensions/gsd/auto/phases.js +5 -13
  24. package/dist/resources/extensions/gsd/auto/run-unit.js +26 -12
  25. package/dist/resources/extensions/gsd/auto/session.js +5 -6
  26. package/dist/resources/extensions/gsd/auto-dashboard.js +3 -2
  27. package/dist/resources/extensions/gsd/auto-direct-dispatch.js +55 -21
  28. package/dist/resources/extensions/gsd/auto-dispatch.js +18 -6
  29. package/dist/resources/extensions/gsd/auto-prompts.js +69 -2
  30. package/dist/resources/extensions/gsd/auto-recovery.js +43 -4
  31. package/dist/resources/extensions/gsd/auto-runtime-state.js +31 -0
  32. package/dist/resources/extensions/gsd/auto-start.js +1 -1
  33. package/dist/resources/extensions/gsd/auto-tool-tracking.js +2 -2
  34. package/dist/resources/extensions/gsd/auto-worktree.js +60 -13
  35. package/dist/resources/extensions/gsd/auto.js +39 -14
  36. package/dist/resources/extensions/gsd/bootstrap/db-tools.js +14 -2
  37. package/dist/resources/extensions/gsd/bootstrap/exec-tools.js +7 -5
  38. package/dist/resources/extensions/gsd/bootstrap/query-tools.js +2 -2
  39. package/dist/resources/extensions/gsd/bootstrap/register-extension.js +5 -4
  40. package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +112 -31
  41. package/dist/resources/extensions/gsd/bootstrap/register-shortcuts.js +11 -6
  42. package/dist/resources/extensions/gsd/bootstrap/subagent-input.js +22 -0
  43. package/dist/resources/extensions/gsd/bootstrap/system-context.js +45 -8
  44. package/dist/resources/extensions/gsd/bootstrap/write-gate.js +121 -3
  45. package/dist/resources/extensions/gsd/commands/catalog.js +76 -5
  46. package/dist/resources/extensions/gsd/commands/handlers/core.js +23 -1
  47. package/dist/resources/extensions/gsd/commands/handlers/ops.js +8 -0
  48. package/dist/resources/extensions/gsd/commands-config.js +3 -2
  49. package/dist/resources/extensions/gsd/commands-extensions.js +46 -3
  50. package/dist/resources/extensions/gsd/commands-handlers.js +3 -2
  51. package/dist/resources/extensions/gsd/commands-mcp-status.js +3 -1
  52. package/dist/resources/extensions/gsd/commands-prefs-wizard.js +10 -1
  53. package/dist/resources/extensions/gsd/commands-worktree.js +309 -0
  54. package/dist/resources/extensions/gsd/dashboard-overlay.js +1 -1
  55. package/dist/resources/extensions/gsd/docs/preferences-reference.md +10 -0
  56. package/dist/resources/extensions/gsd/doctor-providers.js +2 -1
  57. package/dist/resources/extensions/gsd/doctor-runtime-checks.js +39 -1
  58. package/dist/resources/extensions/gsd/error-classifier.js +1 -1
  59. package/dist/resources/extensions/gsd/forensics.js +10 -8
  60. package/dist/resources/extensions/gsd/git-service.js +12 -5
  61. package/dist/resources/extensions/gsd/gsd-db.js +11 -2
  62. package/dist/resources/extensions/gsd/guided-flow.js +25 -24
  63. package/dist/resources/extensions/gsd/home-dir.js +16 -0
  64. package/dist/resources/extensions/gsd/key-manager.js +2 -1
  65. package/dist/resources/extensions/gsd/memory-store.js +66 -31
  66. package/dist/resources/extensions/gsd/migrate/command.js +3 -2
  67. package/dist/resources/extensions/gsd/milestone-id-reservation.js +36 -0
  68. package/dist/resources/extensions/gsd/model-router.js +114 -9
  69. package/dist/resources/extensions/gsd/native-git-bridge.js +7 -1
  70. package/dist/resources/extensions/gsd/preferences-models.js +91 -15
  71. package/dist/resources/extensions/gsd/preferences-types.js +2 -0
  72. package/dist/resources/extensions/gsd/preferences-validation.js +32 -0
  73. package/dist/resources/extensions/gsd/preferences.js +5 -3
  74. package/dist/resources/extensions/gsd/prompt-loader.js +23 -12
  75. package/dist/resources/extensions/gsd/prompts/complete-milestone.md +10 -0
  76. package/dist/resources/extensions/gsd/prompts/complete-slice.md +10 -0
  77. package/dist/resources/extensions/gsd/prompts/guided-discuss-milestone.md +2 -0
  78. package/dist/resources/extensions/gsd/prompts/parallel-research-slices.md +2 -0
  79. package/dist/resources/extensions/gsd/prompts/plan-slice.md +10 -0
  80. package/dist/resources/extensions/gsd/prompts/refine-slice.md +10 -0
  81. package/dist/resources/extensions/gsd/prompts/rewrite-docs.md +2 -0
  82. package/dist/resources/extensions/gsd/slice-parallel-orchestrator.js +9 -3
  83. package/dist/resources/extensions/gsd/state.js +42 -0
  84. package/dist/resources/extensions/gsd/templates/PREFERENCES.md +1 -0
  85. package/dist/resources/extensions/gsd/tools/memory-tools.js +18 -1
  86. package/dist/resources/extensions/gsd/unit-context-manifest.js +29 -4
  87. package/dist/resources/extensions/gsd/visualizer-overlay.js +1 -1
  88. package/dist/resources/extensions/gsd/watch/header-renderer.js +3 -1
  89. package/dist/resources/extensions/gsd/worktree-command.js +26 -46
  90. package/dist/resources/extensions/gsd/worktree-manager.js +20 -1
  91. package/dist/resources/extensions/gsd/worktree-resolver.js +4 -13
  92. package/dist/resources/extensions/gsd/worktree-root.js +124 -0
  93. package/dist/resources/extensions/gsd/worktree-session-state.js +33 -0
  94. package/dist/resources/extensions/gsd/worktree.js +4 -115
  95. package/dist/resources/extensions/mcp-client/index.js +6 -9
  96. package/dist/resources/extensions/ollama/index.js +15 -2
  97. package/dist/resources/extensions/ollama/model-capabilities.js +31 -0
  98. package/dist/resources/extensions/ollama/ollama-client.js +40 -4
  99. package/dist/resources/extensions/slash-commands/create-extension.js +36 -22
  100. package/dist/resources/extensions/subagent/index.js +324 -178
  101. package/dist/resources/skills/create-gsd-extension/SKILL.md +9 -5
  102. package/dist/resources/skills/create-gsd-extension/references/custom-commands.md +1 -1
  103. package/dist/resources/skills/create-gsd-extension/references/custom-rendering.md +5 -5
  104. package/dist/resources/skills/create-gsd-extension/references/custom-tools.md +4 -4
  105. package/dist/resources/skills/create-gsd-extension/references/custom-ui.md +6 -6
  106. package/dist/resources/skills/create-gsd-extension/references/events-reference.md +3 -3
  107. package/dist/resources/skills/create-gsd-extension/references/packaging-distribution.md +1 -1
  108. package/dist/resources/skills/create-gsd-extension/references/remote-execution-overrides.md +3 -3
  109. package/dist/resources/skills/create-gsd-extension/workflows/create-extension.md +32 -12
  110. package/dist/resources/skills/lint/SKILL.md +4 -0
  111. package/dist/resources/skills/review/SKILL.md +4 -0
  112. package/dist/resources/skills/test/SKILL.md +3 -0
  113. package/dist/rtk-shared.d.ts +3 -0
  114. package/dist/rtk-shared.js +17 -0
  115. package/dist/rtk.d.ts +2 -5
  116. package/dist/rtk.js +3 -20
  117. package/dist/runtime-checks.d.ts +27 -0
  118. package/dist/runtime-checks.js +38 -0
  119. package/dist/tsconfig.extensions.tsbuildinfo +1 -1
  120. package/dist/web/standalone/.next/BUILD_ID +1 -1
  121. package/dist/web/standalone/.next/app-path-routes-manifest.json +13 -13
  122. package/dist/web/standalone/.next/build-manifest.json +3 -3
  123. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  124. package/dist/web/standalone/.next/react-loadable-manifest.json +44 -4
  125. package/dist/web/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
  126. package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
  127. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  128. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  129. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  130. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  131. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  132. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  133. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  134. package/dist/web/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  135. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  136. package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
  137. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
  138. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  139. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
  140. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  141. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  142. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  143. package/dist/web/standalone/.next/server/app/api/boot/route.js +1 -1
  144. package/dist/web/standalone/.next/server/app/api/git/route.js +1 -1
  145. package/dist/web/standalone/.next/server/app/api/session/events/route.js +4 -2
  146. package/dist/web/standalone/.next/server/app/api/shutdown/route.js +1 -1
  147. package/dist/web/standalone/.next/server/app/index.html +1 -1
  148. package/dist/web/standalone/.next/server/app/index.rsc +2 -2
  149. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
  150. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +2 -2
  151. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  152. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
  153. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  154. package/dist/web/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
  155. package/dist/web/standalone/.next/server/app-paths-manifest.json +13 -13
  156. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  157. package/dist/web/standalone/.next/server/middleware-manifest.json +5 -5
  158. package/dist/web/standalone/.next/server/middleware-react-loadable-manifest.js +1 -1
  159. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  160. package/dist/web/standalone/.next/server/pages/500.html +1 -1
  161. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  162. package/dist/web/standalone/.next/server/webpack-runtime.js +1 -1
  163. package/dist/web/standalone/.next/static/chunks/2556.0527fea66e123b7f.js +1 -0
  164. package/dist/web/standalone/.next/static/chunks/2824.08296bc2f9654698.js +1 -0
  165. package/dist/web/standalone/.next/static/chunks/3026.3af53b279375f082.js +1 -0
  166. package/dist/web/standalone/.next/static/chunks/315.6f68ae79b67d25cf.js +1 -0
  167. package/dist/web/standalone/.next/static/chunks/3497.4bfc60a3b3dea717.js +1 -0
  168. package/dist/web/standalone/.next/static/chunks/5516.4a07c872b5c3a663.js +1 -0
  169. package/dist/web/standalone/.next/static/chunks/8336.31b019697882acfb.js +10 -0
  170. package/dist/web/standalone/.next/static/chunks/8845.c9702695e8c5a9c5.js +2 -0
  171. package/dist/web/standalone/.next/static/chunks/9058.01ef3a463bda88f1.js +20 -0
  172. package/dist/web/standalone/.next/static/chunks/9441.1081da1125d1764f.js +1 -0
  173. package/dist/web/standalone/.next/static/chunks/app/{page-5b113fd32bc2a1c3.js → page-9bf2e0c50fb2ca05.js} +1 -1
  174. package/dist/web/standalone/.next/static/chunks/webpack-f9f0dc45e4f3ac10.js +1 -0
  175. package/dist/web/standalone/package.json +2 -1
  176. package/dist/welcome-screen.js +27 -1
  177. package/dist/worktree-cli.d.ts +1 -0
  178. package/dist/worktree-cli.js +9 -3
  179. package/dist/worktree-status-banner.d.ts +1 -0
  180. package/dist/worktree-status-banner.js +132 -0
  181. package/package.json +1 -3
  182. package/packages/daemon/package.json +2 -2
  183. package/packages/mcp-server/dist/alias-telemetry.d.ts +8 -0
  184. package/packages/mcp-server/dist/alias-telemetry.d.ts.map +1 -0
  185. package/packages/mcp-server/dist/alias-telemetry.js +30 -0
  186. package/packages/mcp-server/dist/alias-telemetry.js.map +1 -0
  187. package/packages/mcp-server/dist/workflow-tools.d.ts.map +1 -1
  188. package/packages/mcp-server/dist/workflow-tools.js +74 -46
  189. package/packages/mcp-server/dist/workflow-tools.js.map +1 -1
  190. package/packages/mcp-server/package.json +2 -2
  191. package/packages/mcp-server/src/alias-telemetry.test.ts +78 -0
  192. package/packages/mcp-server/src/alias-telemetry.ts +30 -0
  193. package/packages/mcp-server/src/workflow-tools.test.ts +78 -0
  194. package/packages/mcp-server/src/workflow-tools.ts +93 -58
  195. package/packages/mcp-server/tsconfig.tsbuildinfo +1 -1
  196. package/packages/native/package.json +1 -1
  197. package/packages/native/tsconfig.tsbuildinfo +1 -1
  198. package/packages/pi-agent-core/package.json +1 -1
  199. package/packages/pi-agent-core/tsconfig.tsbuildinfo +1 -1
  200. package/packages/pi-ai/dist/providers/anthropic-shared.cache-breakpoint.test.d.ts +2 -0
  201. package/packages/pi-ai/dist/providers/anthropic-shared.cache-breakpoint.test.d.ts.map +1 -0
  202. package/packages/pi-ai/dist/providers/anthropic-shared.cache-breakpoint.test.js +231 -0
  203. package/packages/pi-ai/dist/providers/anthropic-shared.cache-breakpoint.test.js.map +1 -0
  204. package/packages/pi-ai/dist/providers/anthropic-shared.d.ts.map +1 -1
  205. package/packages/pi-ai/dist/providers/anthropic-shared.js +48 -19
  206. package/packages/pi-ai/dist/providers/anthropic-shared.js.map +1 -1
  207. package/packages/pi-ai/dist/types.d.ts +13 -0
  208. package/packages/pi-ai/dist/types.d.ts.map +1 -1
  209. package/packages/pi-ai/dist/types.js.map +1 -1
  210. package/packages/pi-ai/dist/utils/repair-tool-json.d.ts.map +1 -1
  211. package/packages/pi-ai/dist/utils/repair-tool-json.js +24 -3
  212. package/packages/pi-ai/dist/utils/repair-tool-json.js.map +1 -1
  213. package/packages/pi-ai/dist/utils/tests/repair-tool-json.test.js +26 -0
  214. package/packages/pi-ai/dist/utils/tests/repair-tool-json.test.js.map +1 -1
  215. package/packages/pi-ai/package.json +1 -1
  216. package/packages/pi-ai/src/providers/anthropic-shared.cache-breakpoint.test.ts +289 -0
  217. package/packages/pi-ai/src/providers/anthropic-shared.ts +52 -20
  218. package/packages/pi-ai/src/types.ts +13 -0
  219. package/packages/pi-ai/src/utils/repair-tool-json.ts +24 -3
  220. package/packages/pi-ai/src/utils/tests/repair-tool-json.test.ts +32 -0
  221. package/packages/pi-ai/tsconfig.tsbuildinfo +1 -1
  222. package/packages/pi-coding-agent/dist/core/agent-session.d.ts.map +1 -1
  223. package/packages/pi-coding-agent/dist/core/agent-session.js +6 -0
  224. package/packages/pi-coding-agent/dist/core/agent-session.js.map +1 -1
  225. package/packages/pi-coding-agent/dist/core/messages.d.ts.map +1 -1
  226. package/packages/pi-coding-agent/dist/core/messages.js +4 -0
  227. package/packages/pi-coding-agent/dist/core/messages.js.map +1 -1
  228. package/packages/pi-coding-agent/dist/core/model-registry-auth-mode.test.js +19 -2
  229. package/packages/pi-coding-agent/dist/core/model-registry-auth-mode.test.js.map +1 -1
  230. package/packages/pi-coding-agent/dist/core/model-registry.d.ts +10 -0
  231. package/packages/pi-coding-agent/dist/core/model-registry.d.ts.map +1 -1
  232. package/packages/pi-coding-agent/dist/core/model-registry.js +18 -0
  233. package/packages/pi-coding-agent/dist/core/model-registry.js.map +1 -1
  234. package/packages/pi-coding-agent/dist/core/system-prompt.d.ts +13 -0
  235. package/packages/pi-coding-agent/dist/core/system-prompt.d.ts.map +1 -1
  236. package/packages/pi-coding-agent/dist/core/system-prompt.js +20 -16
  237. package/packages/pi-coding-agent/dist/core/system-prompt.js.map +1 -1
  238. package/packages/pi-coding-agent/dist/core/token-telemetry.d.ts +37 -0
  239. package/packages/pi-coding-agent/dist/core/token-telemetry.d.ts.map +1 -0
  240. package/packages/pi-coding-agent/dist/core/token-telemetry.js +49 -0
  241. package/packages/pi-coding-agent/dist/core/token-telemetry.js.map +1 -0
  242. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-card-cleanup-and-success-runtime.test.d.ts +2 -0
  243. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-card-cleanup-and-success-runtime.test.d.ts.map +1 -0
  244. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-card-cleanup-and-success-runtime.test.js +133 -0
  245. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-card-cleanup-and-success-runtime.test.js.map +1 -0
  246. package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.js +1 -1
  247. package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.js.map +1 -1
  248. package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.test.js +14 -1
  249. package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.test.js.map +1 -1
  250. package/packages/pi-coding-agent/dist/tests/system-prompt-cache-stability.test.d.ts +2 -0
  251. package/packages/pi-coding-agent/dist/tests/system-prompt-cache-stability.test.d.ts.map +1 -0
  252. package/packages/pi-coding-agent/dist/tests/system-prompt-cache-stability.test.js +78 -0
  253. package/packages/pi-coding-agent/dist/tests/system-prompt-cache-stability.test.js.map +1 -0
  254. package/packages/pi-coding-agent/dist/tests/token-telemetry.test.d.ts +2 -0
  255. package/packages/pi-coding-agent/dist/tests/token-telemetry.test.d.ts.map +1 -0
  256. package/packages/pi-coding-agent/dist/tests/token-telemetry.test.js +181 -0
  257. package/packages/pi-coding-agent/dist/tests/token-telemetry.test.js.map +1 -0
  258. package/packages/pi-coding-agent/package.json +1 -1
  259. package/packages/pi-coding-agent/src/core/agent-session.ts +7 -0
  260. package/packages/pi-coding-agent/src/core/messages.ts +4 -0
  261. package/packages/pi-coding-agent/src/core/model-registry-auth-mode.test.ts +32 -2
  262. package/packages/pi-coding-agent/src/core/model-registry.ts +21 -0
  263. package/packages/pi-coding-agent/src/core/system-prompt.ts +33 -15
  264. package/packages/pi-coding-agent/src/core/token-telemetry.ts +77 -0
  265. package/packages/pi-coding-agent/src/modes/interactive/components/tool-card-cleanup-and-success-runtime.test.ts +212 -0
  266. package/packages/pi-coding-agent/src/modes/interactive/controllers/input-controller.test.ts +17 -1
  267. package/packages/pi-coding-agent/src/modes/interactive/controllers/input-controller.ts +1 -1
  268. package/packages/pi-coding-agent/src/tests/system-prompt-cache-stability.test.ts +102 -0
  269. package/packages/pi-coding-agent/src/tests/token-telemetry.test.ts +200 -0
  270. package/packages/pi-coding-agent/tsconfig.tsbuildinfo +1 -1
  271. package/packages/pi-tui/dist/__tests__/autocomplete.test.js +17 -3
  272. package/packages/pi-tui/dist/__tests__/autocomplete.test.js.map +1 -1
  273. package/packages/pi-tui/dist/components/__tests__/leak-fixes-runtime.test.d.ts +2 -0
  274. package/packages/pi-tui/dist/components/__tests__/leak-fixes-runtime.test.d.ts.map +1 -0
  275. package/packages/pi-tui/dist/components/__tests__/leak-fixes-runtime.test.js +161 -0
  276. package/packages/pi-tui/dist/components/__tests__/leak-fixes-runtime.test.js.map +1 -0
  277. package/packages/pi-tui/package.json +1 -1
  278. package/packages/pi-tui/src/__tests__/autocomplete.test.ts +20 -3
  279. package/packages/pi-tui/src/components/__tests__/leak-fixes-runtime.test.ts +219 -0
  280. package/packages/pi-tui/tsconfig.tsbuildinfo +1 -1
  281. package/packages/rpc-client/package.json +1 -1
  282. package/pkg/package.json +1 -1
  283. package/src/resources/extensions/claude-code-cli/readiness.ts +92 -47
  284. package/src/resources/extensions/google-search/index.ts +2 -9
  285. package/src/resources/extensions/gsd/auto/loop.ts +24 -2
  286. package/src/resources/extensions/gsd/auto/phases.ts +6 -14
  287. package/src/resources/extensions/gsd/auto/run-unit.ts +26 -12
  288. package/src/resources/extensions/gsd/auto/session.ts +5 -6
  289. package/src/resources/extensions/gsd/auto/types.ts +1 -0
  290. package/src/resources/extensions/gsd/auto-dashboard.ts +3 -2
  291. package/src/resources/extensions/gsd/auto-direct-dispatch.ts +60 -24
  292. package/src/resources/extensions/gsd/auto-dispatch.ts +18 -6
  293. package/src/resources/extensions/gsd/auto-prompts.ts +66 -2
  294. package/src/resources/extensions/gsd/auto-recovery.ts +46 -8
  295. package/src/resources/extensions/gsd/auto-runtime-state.ts +51 -0
  296. package/src/resources/extensions/gsd/auto-start.ts +1 -1
  297. package/src/resources/extensions/gsd/auto-tool-tracking.ts +2 -4
  298. package/src/resources/extensions/gsd/auto-worktree.ts +82 -12
  299. package/src/resources/extensions/gsd/auto.ts +37 -10
  300. package/src/resources/extensions/gsd/bootstrap/db-tools.ts +15 -13
  301. package/src/resources/extensions/gsd/bootstrap/exec-tools.ts +8 -7
  302. package/src/resources/extensions/gsd/bootstrap/query-tools.ts +2 -2
  303. package/src/resources/extensions/gsd/bootstrap/register-extension.ts +10 -9
  304. package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +121 -31
  305. package/src/resources/extensions/gsd/bootstrap/register-shortcuts.ts +12 -6
  306. package/src/resources/extensions/gsd/bootstrap/subagent-input.ts +20 -0
  307. package/src/resources/extensions/gsd/bootstrap/system-context.ts +50 -8
  308. package/src/resources/extensions/gsd/bootstrap/write-gate.ts +141 -11
  309. package/src/resources/extensions/gsd/commands/catalog.ts +82 -5
  310. package/src/resources/extensions/gsd/commands/handlers/core.ts +23 -1
  311. package/src/resources/extensions/gsd/commands/handlers/ops.ts +10 -0
  312. package/src/resources/extensions/gsd/commands-config.ts +3 -2
  313. package/src/resources/extensions/gsd/commands-extensions.ts +43 -3
  314. package/src/resources/extensions/gsd/commands-handlers.ts +3 -2
  315. package/src/resources/extensions/gsd/commands-mcp-status.ts +3 -1
  316. package/src/resources/extensions/gsd/commands-prefs-wizard.ts +15 -1
  317. package/src/resources/extensions/gsd/commands-worktree.ts +383 -0
  318. package/src/resources/extensions/gsd/dashboard-overlay.ts +1 -1
  319. package/src/resources/extensions/gsd/docs/preferences-reference.md +10 -0
  320. package/src/resources/extensions/gsd/doctor-providers.ts +2 -1
  321. package/src/resources/extensions/gsd/doctor-runtime-checks.ts +39 -1
  322. package/src/resources/extensions/gsd/doctor-types.ts +3 -1
  323. package/src/resources/extensions/gsd/error-classifier.ts +1 -1
  324. package/src/resources/extensions/gsd/forensics.ts +12 -7
  325. package/src/resources/extensions/gsd/git-service.ts +13 -5
  326. package/src/resources/extensions/gsd/gsd-db.ts +12 -2
  327. package/src/resources/extensions/gsd/guided-flow.ts +27 -26
  328. package/src/resources/extensions/gsd/home-dir.ts +19 -0
  329. package/src/resources/extensions/gsd/journal.ts +4 -1
  330. package/src/resources/extensions/gsd/key-manager.ts +2 -1
  331. package/src/resources/extensions/gsd/memory-store.ts +81 -28
  332. package/src/resources/extensions/gsd/migrate/command.ts +3 -2
  333. package/src/resources/extensions/gsd/milestone-id-reservation.ts +47 -0
  334. package/src/resources/extensions/gsd/model-router.ts +172 -9
  335. package/src/resources/extensions/gsd/native-git-bridge.ts +7 -1
  336. package/src/resources/extensions/gsd/preferences-models.ts +101 -15
  337. package/src/resources/extensions/gsd/preferences-types.ts +6 -0
  338. package/src/resources/extensions/gsd/preferences-validation.ts +35 -0
  339. package/src/resources/extensions/gsd/preferences.ts +16 -2
  340. package/src/resources/extensions/gsd/prompt-loader.ts +26 -12
  341. package/src/resources/extensions/gsd/prompts/complete-milestone.md +10 -0
  342. package/src/resources/extensions/gsd/prompts/complete-slice.md +10 -0
  343. package/src/resources/extensions/gsd/prompts/guided-discuss-milestone.md +2 -0
  344. package/src/resources/extensions/gsd/prompts/parallel-research-slices.md +2 -0
  345. package/src/resources/extensions/gsd/prompts/plan-slice.md +10 -0
  346. package/src/resources/extensions/gsd/prompts/refine-slice.md +10 -0
  347. package/src/resources/extensions/gsd/prompts/rewrite-docs.md +2 -0
  348. package/src/resources/extensions/gsd/slice-parallel-orchestrator.ts +9 -3
  349. package/src/resources/extensions/gsd/state.ts +42 -0
  350. package/src/resources/extensions/gsd/templates/PREFERENCES.md +1 -0
  351. package/src/resources/extensions/gsd/tests/auto-loop.test.ts +179 -1
  352. package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +58 -0
  353. package/src/resources/extensions/gsd/tests/auto-session-encapsulation.test.ts +24 -5
  354. package/src/resources/extensions/gsd/tests/auto-supervisor.test.mjs +21 -4
  355. package/src/resources/extensions/gsd/tests/bootstrap-derive-state-db-open.test.ts +1 -1
  356. package/src/resources/extensions/gsd/tests/budget-prediction.test.ts +138 -211
  357. package/src/resources/extensions/gsd/tests/bundled-skill-triggers.test.ts +50 -27
  358. package/src/resources/extensions/gsd/tests/commands-extensions-version-compare.test.ts +58 -0
  359. package/src/resources/extensions/gsd/tests/commands-worktree-clean.test.ts +48 -0
  360. package/src/resources/extensions/gsd/tests/complete-slice-verification-gate.test.ts +142 -59
  361. package/src/resources/extensions/gsd/tests/complete-slice.test.ts +7 -4
  362. package/src/resources/extensions/gsd/tests/completed-at-reconcile.test.ts +89 -32
  363. package/src/resources/extensions/gsd/tests/custom-engine-loop-integration.test.ts +41 -23
  364. package/src/resources/extensions/gsd/tests/db-path-worktree-symlink.test.ts +3 -43
  365. package/src/resources/extensions/gsd/tests/debug-logger.test.ts +5 -3
  366. package/src/resources/extensions/gsd/tests/deferred-milestone-dir-4996.test.ts +116 -0
  367. package/src/resources/extensions/gsd/tests/discuss-empty-db-fallback.test.ts +22 -87
  368. package/src/resources/extensions/gsd/tests/discuss-queued-milestones.test.ts +7 -118
  369. package/src/resources/extensions/gsd/tests/discuss-tool-scope-leak.test.ts +18 -60
  370. package/src/resources/extensions/gsd/tests/doctor-orphan-milestone-4996.test.ts +100 -0
  371. package/src/resources/extensions/gsd/tests/double-merge-guard.test.ts +14 -76
  372. package/src/resources/extensions/gsd/tests/ensure-preconditions-guard-4996.test.ts +93 -0
  373. package/src/resources/extensions/gsd/tests/false-degraded-mode-warning.test.ts +22 -83
  374. package/src/resources/extensions/gsd/tests/finalize-timeout-guard.test.ts +1 -63
  375. package/src/resources/extensions/gsd/tests/find-missing-summaries-closed-runtime.test.ts +47 -0
  376. package/src/resources/extensions/gsd/tests/forensics-stuck-loops.test.ts +26 -1
  377. package/src/resources/extensions/gsd/tests/gitignore-bg-shell-runtime.test.ts +63 -0
  378. package/src/resources/extensions/gsd/tests/google-search-stub.test.ts +25 -65
  379. package/src/resources/extensions/gsd/tests/gsd-db.test.ts +30 -0
  380. package/src/resources/extensions/gsd/tests/gsd-no-project-error-runtime.test.ts +81 -0
  381. package/src/resources/extensions/gsd/tests/headless-answers.test.ts +14 -4
  382. package/src/resources/extensions/gsd/tests/health-widget.test.ts +22 -12
  383. package/src/resources/extensions/gsd/tests/help-menu-coverage.test.ts +57 -0
  384. package/src/resources/extensions/gsd/tests/home-dir.test.ts +52 -0
  385. package/src/resources/extensions/gsd/tests/import-done-milestones-runtime.test.ts +145 -0
  386. package/src/resources/extensions/gsd/tests/init-prefs-routing.test.ts +64 -1
  387. package/src/resources/extensions/gsd/tests/integration/auto-worktree.test.ts +72 -1
  388. package/src/resources/extensions/gsd/tests/integration/token-savings.test.ts +0 -23
  389. package/src/resources/extensions/gsd/tests/memory-store.test.ts +128 -0
  390. package/src/resources/extensions/gsd/tests/memory-tools.test.ts +33 -1
  391. package/src/resources/extensions/gsd/tests/merge-self-branch-guard.test.ts +124 -0
  392. package/src/resources/extensions/gsd/tests/milestone-id-gap-reuse-4996.test.ts +152 -0
  393. package/src/resources/extensions/gsd/tests/milestone-report-path.test.ts +18 -1
  394. package/src/resources/extensions/gsd/tests/model-router.test.ts +169 -8
  395. package/src/resources/extensions/gsd/tests/native-git-infra-errors.test.ts +50 -0
  396. package/src/resources/extensions/gsd/tests/orphaned-worktree-audit.test.ts +8 -0
  397. package/src/resources/extensions/gsd/tests/parallel-crash-recovery.test.ts +32 -43
  398. package/src/resources/extensions/gsd/tests/phases-merge-error-stops-auto.test.ts +4 -10
  399. package/src/resources/extensions/gsd/tests/preferences.test.ts +127 -0
  400. package/src/resources/extensions/gsd/tests/prompt-step-ordering.test.ts +16 -0
  401. package/src/resources/extensions/gsd/tests/provider-errors.test.ts +7 -0
  402. package/src/resources/extensions/gsd/tests/quick-turn-end-cleanup.test.ts +6 -6
  403. package/src/resources/extensions/gsd/tests/register-hooks-compaction-checkpoint.test.ts +93 -0
  404. package/src/resources/extensions/gsd/tests/safety-harness-false-positives.test.ts +34 -0
  405. package/src/resources/extensions/gsd/tests/session-start-footer.test.ts +168 -19
  406. package/src/resources/extensions/gsd/tests/slice-parallel-orchestrator.test.ts +7 -1
  407. package/src/resources/extensions/gsd/tests/smart-entry-complete.test.ts +23 -1
  408. package/src/resources/extensions/gsd/tests/steer-worktree-path.test.ts +17 -1
  409. package/src/resources/extensions/gsd/tests/system-context-message-routing.test.ts +101 -0
  410. package/src/resources/extensions/gsd/tests/token-profile.test.ts +51 -4
  411. package/src/resources/extensions/gsd/tests/turn-epoch.test.ts +7 -16
  412. package/src/resources/extensions/gsd/tests/unit-context-manifest.test.ts +38 -3
  413. package/src/resources/extensions/gsd/tests/unstructured-continue-context-injection.test.ts +5 -7
  414. package/src/resources/extensions/gsd/tests/uok-gitops-turn-action.test.ts +15 -1
  415. package/src/resources/extensions/gsd/tests/visualizer-overlay.test.ts +6 -6
  416. package/src/resources/extensions/gsd/tests/worktree-path-injection.test.ts +235 -0
  417. package/src/resources/extensions/gsd/tests/worktree-symlink-removal.test.ts +34 -33
  418. package/src/resources/extensions/gsd/tests/worktree.test.ts +8 -0
  419. package/src/resources/extensions/gsd/tests/write-gate-planning-unit.test.ts +131 -1
  420. package/src/resources/extensions/gsd/tools/memory-tools.ts +17 -1
  421. package/src/resources/extensions/gsd/unit-context-manifest.ts +44 -12
  422. package/src/resources/extensions/gsd/visualizer-overlay.ts +1 -1
  423. package/src/resources/extensions/gsd/watch/header-renderer.ts +3 -1
  424. package/src/resources/extensions/gsd/workflow-logger.ts +1 -0
  425. package/src/resources/extensions/gsd/worktree-command.ts +31 -44
  426. package/src/resources/extensions/gsd/worktree-manager.ts +40 -1
  427. package/src/resources/extensions/gsd/worktree-resolver.ts +4 -14
  428. package/src/resources/extensions/gsd/worktree-root.ts +144 -0
  429. package/src/resources/extensions/gsd/worktree-session-state.ts +35 -0
  430. package/src/resources/extensions/gsd/worktree.ts +8 -119
  431. package/src/resources/extensions/mcp-client/index.ts +6 -10
  432. package/src/resources/extensions/mcp-client/tests/global-config.test.ts +91 -0
  433. package/src/resources/extensions/ollama/index.ts +16 -2
  434. package/src/resources/extensions/ollama/model-capabilities.ts +34 -0
  435. package/src/resources/extensions/ollama/ollama-client.ts +41 -4
  436. package/src/resources/extensions/ollama/tests/model-capabilities.test.ts +96 -0
  437. package/src/resources/extensions/ollama/tests/ollama-client-timeout-env.test.ts +147 -0
  438. package/src/resources/extensions/slash-commands/create-extension.ts +38 -24
  439. package/src/resources/extensions/subagent/index.ts +165 -7
  440. package/src/resources/skills/create-gsd-extension/SKILL.md +9 -5
  441. package/src/resources/skills/create-gsd-extension/references/custom-commands.md +1 -1
  442. package/src/resources/skills/create-gsd-extension/references/custom-rendering.md +5 -5
  443. package/src/resources/skills/create-gsd-extension/references/custom-tools.md +4 -4
  444. package/src/resources/skills/create-gsd-extension/references/custom-ui.md +6 -6
  445. package/src/resources/skills/create-gsd-extension/references/events-reference.md +3 -3
  446. package/src/resources/skills/create-gsd-extension/references/packaging-distribution.md +1 -1
  447. package/src/resources/skills/create-gsd-extension/references/remote-execution-overrides.md +3 -3
  448. package/src/resources/skills/create-gsd-extension/templates/extension-skeleton.ts +2 -2
  449. package/src/resources/skills/create-gsd-extension/templates/stateful-tool-skeleton.ts +3 -3
  450. package/src/resources/skills/create-gsd-extension/templates/templates.test.ts +58 -0
  451. package/src/resources/skills/create-gsd-extension/workflows/create-extension.md +32 -12
  452. package/src/resources/skills/lint/SKILL.md +4 -0
  453. package/src/resources/skills/review/SKILL.md +4 -0
  454. package/src/resources/skills/test/SKILL.md +3 -0
  455. package/dist/resources/extensions/browser-tools/tests/browser-tools-integration.test.mjs +0 -601
  456. package/dist/resources/extensions/browser-tools/tests/browser-tools-unit.test.cjs +0 -651
  457. package/dist/resources/extensions/browser-tools/tests/capture-sharp-optional.test.cjs +0 -91
  458. package/dist/resources/extensions/gsd/tests/auto-supervisor.test.mjs +0 -53
  459. package/dist/resources/extensions/gsd/tests/dist-redirect.mjs +0 -112
  460. package/dist/resources/extensions/gsd/tests/resolve-ts-hooks.mjs +0 -23
  461. package/dist/resources/extensions/gsd/tests/resolve-ts.mjs +0 -5
  462. package/dist/resources/skills/github-workflows/references/gh/tests/__init__.py +0 -0
  463. package/dist/resources/skills/github-workflows/references/gh/tests/test_github_project_setup.py +0 -608
  464. package/dist/web/standalone/.next/static/chunks/2826.e9f5195e91f9cad2.js +0 -11
  465. package/dist/web/standalone/.next/static/chunks/3621.fc7480022c972438.js +0 -20
  466. package/dist/web/standalone/.next/static/chunks/webpack-2e68521d7c82f7c2.js +0 -1
  467. package/src/resources/extensions/gsd/tests/copy-planning-artifacts-samepath.test.ts +0 -22
  468. package/src/resources/extensions/gsd/tests/discuss-slice-structured-questions.test.ts +0 -47
  469. package/src/resources/extensions/gsd/tests/empty-content-abort-loop.test.ts +0 -75
  470. /package/dist/web/standalone/.next/static/{cAJH99yNS1UPbeSEiNRrV → 4iu6IYeYfxOq8OidlDqp6}/_buildManifest.js +0 -0
  471. /package/dist/web/standalone/.next/static/{cAJH99yNS1UPbeSEiNRrV → 4iu6IYeYfxOq8OidlDqp6}/_ssgManifest.js +0 -0
@@ -22,6 +22,29 @@ let sessionSwitchGeneration = 0;
22
22
  */
23
23
  export async function runUnit(ctx, pi, s, unitType, unitId, prompt) {
24
24
  debugLog("runUnit", { phase: "start", unitType, unitId });
25
+ // Ensure cwd matches basePath BEFORE newSession() captures it. The new
26
+ // session reads process.cwd() during construction to anchor its tool
27
+ // runtime and system prompt; if cwd has drifted (async_bash, background
28
+ // jobs, prior unit cleanup), the session would otherwise be rooted to
29
+ // the wrong directory. Must be synchronous — no awaits between chdir
30
+ // and newSession (#1389, #4762 follow-up).
31
+ try {
32
+ if (process.cwd() !== s.basePath) {
33
+ process.chdir(s.basePath);
34
+ }
35
+ }
36
+ catch (e) {
37
+ const msg = `Failed to chdir to basePath before newSession (basePath: ${s.basePath}): ${String(e)}`;
38
+ logWarning("engine", msg, { basePath: s.basePath, error: String(e) });
39
+ return {
40
+ status: "cancelled",
41
+ errorContext: {
42
+ message: msg,
43
+ category: "session-failed",
44
+ isTransient: true,
45
+ },
46
+ };
47
+ }
25
48
  // ── Session creation with timeout ──
26
49
  debugLog("runUnit", { phase: "session-create", unitType, unitId });
27
50
  let sessionResult;
@@ -91,17 +114,6 @@ export async function runUnit(ctx, pi, s, unitType, unitId, prompt) {
91
114
  const unitPromise = new Promise((resolve) => {
92
115
  _setCurrentResolve(resolve);
93
116
  });
94
- // Ensure cwd matches basePath before dispatch (#1389).
95
- // async_bash and background jobs can drift cwd away from the worktree.
96
- // Realigning here prevents commits from landing on the wrong branch.
97
- try {
98
- if (process.cwd() !== s.basePath) {
99
- process.chdir(s.basePath);
100
- }
101
- }
102
- catch (e) {
103
- logWarning("engine", "Failed to chdir to basePath before dispatch", { basePath: s.basePath, error: String(e) });
104
- }
105
117
  // ── Provider request-readiness pre-check (#4555) ──
106
118
  // Verify the provider can accept requests before dispatching. If the token
107
119
  // has expired since bootstrap, return cancelled immediately so the unit is
@@ -138,6 +150,7 @@ export async function runUnit(ctx, pi, s, unitType, unitId, prompt) {
138
150
  const capturedTurnGen = getCurrentTurnGeneration();
139
151
  // ── Send the prompt ──
140
152
  debugLog("runUnit", { phase: "send-message", unitType, unitId });
153
+ const requestDispatchedAt = Date.now();
141
154
  pi.sendMessage({ customType: "gsd-auto", content: prompt, display: s.verbose }, { triggerTurn: true });
142
155
  // ── Await agent_end with absolute timeout (H4 fix) ──
143
156
  // If supervision fails to resolve unitPromise within 30s, treat as cancelled.
@@ -160,6 +173,7 @@ export async function runUnit(ctx, pi, s, unitType, unitId, prompt) {
160
173
  unitId,
161
174
  status: result.status,
162
175
  });
176
+ const finalResult = { ...result, requestDispatchedAt };
163
177
  // Discard trailing follow-up messages (e.g. async_job_result notifications)
164
178
  // from the completed unit. Without this, queued follow-ups trigger wasteful
165
179
  // LLM turns before the next session can start (#1642).
@@ -174,5 +188,5 @@ export async function runUnit(ctx, pi, s, unitType, unitId, prompt) {
174
188
  catch (e) {
175
189
  logWarning("engine", "clearQueue failed after unit completion", { error: String(e) });
176
190
  }
177
- return result;
191
+ return finalResult;
178
192
  }
@@ -15,6 +15,7 @@
15
15
  * auto-session-encapsulation.test.ts enforce that auto.ts has no module-level
16
16
  * `let` or `var` declarations.
17
17
  */
18
+ import { resolveWorktreeProjectRoot } from "../worktree-root.js";
18
19
  // ─── Constants ───────────────────────────────────────────────────────────────
19
20
  export const STUB_RECOVERY_THRESHOLD = 2;
20
21
  export const NEW_SESSION_TIMEOUT_MS = 120_000;
@@ -118,6 +119,8 @@ export class AutoSession {
118
119
  lastPromptCharCount;
119
120
  lastBaselineCharCount;
120
121
  pendingQuickTasks = [];
122
+ /** Timestamp of the last LLM request dispatch (ms since epoch). Used for proactive rate limiting. */
123
+ lastRequestTimestamp = 0;
121
124
  // ── Safety harness ───────────────────────────────────────────────────────
122
125
  /** SHA of the pre-unit git checkpoint ref. Cleared on success or rollback. */
123
126
  checkpointSha = null;
@@ -153,12 +156,7 @@ export class AutoSession {
153
156
  this.unitLifetimeDispatches.clear();
154
157
  }
155
158
  get lockBasePath() {
156
- // Prefer originalBasePath (project root); fall back to basePath.
157
- // Strip /.gsd/worktrees/ suffix if basePath is itself a worktree path
158
- // to avoid reading/writing the lock inside the worktree (#3729).
159
- const resolved = this.originalBasePath || this.basePath;
160
- const markerIdx = resolved.indexOf("/.gsd/worktrees/");
161
- return markerIdx !== -1 ? resolved.slice(0, markerIdx) : resolved;
159
+ return resolveWorktreeProjectRoot(this.basePath, this.originalBasePath);
162
160
  }
163
161
  reset() {
164
162
  this.clearTimers();
@@ -215,6 +213,7 @@ export class AutoSession {
215
213
  this.lastPromptCharCount = undefined;
216
214
  this.lastBaselineCharCount = undefined;
217
215
  this.pendingQuickTasks = [];
216
+ this.lastRequestTimestamp = 0;
218
217
  this.sidecarQueue = [];
219
218
  this.rewriteAttemptCount = 0;
220
219
  this.consecutiveCompleteBootstraps = 0;
@@ -10,6 +10,7 @@ import { getActiveHook } from "./post-unit-hooks.js";
10
10
  import { getLedger, getProjectTotals } from "./metrics.js";
11
11
  import { getErrorMessage } from "./error-utils.js";
12
12
  import { nativeIsRepo } from "./native-git-bridge.js";
13
+ import { getHomeDir } from "./home-dir.js";
13
14
  import { isDbAvailable, getMilestoneSlices, getSliceTasks } from "./gsd-db.js";
14
15
  import { readFileSync, writeFileSync, existsSync } from "node:fs";
15
16
  import { execFileSync } from "node:child_process";
@@ -461,8 +462,8 @@ export function updateProgressWidget(ctx, unitType, unitId, state, accessors, ti
461
462
  let widgetPwd;
462
463
  {
463
464
  let fullPwd = process.cwd();
464
- const widgetHome = process.env.HOME || process.env.USERPROFILE;
465
- if (widgetHome && fullPwd.startsWith(widgetHome)) {
465
+ const widgetHome = getHomeDir();
466
+ if (widgetHome && (fullPwd === widgetHome || fullPwd.startsWith(widgetHome + "/") || fullPwd.startsWith(widgetHome + "\\"))) {
466
467
  fullPwd = `~${fullPwd.slice(widgetHome.length)}`;
467
468
  }
468
469
  const parts = fullPwd.split("/");
@@ -10,6 +10,8 @@ import { resolveMilestoneFile, resolveSliceFile, relSliceFile, } from "./paths.j
10
10
  import { buildResearchSlicePrompt, buildResearchMilestonePrompt, buildPlanSlicePrompt, buildPlanMilestonePrompt, buildExecuteTaskPrompt, buildCompleteSlicePrompt, buildCompleteMilestonePrompt, buildReassessRoadmapPrompt, buildRunUatPrompt, buildReplanSlicePrompt, } from "./auto-prompts.js";
11
11
  import { loadEffectiveGSDPreferences } from "./preferences.js";
12
12
  import { pauseAuto } from "./auto.js";
13
+ import { resolveCanonicalMilestoneRoot } from "./worktree-manager.js";
14
+ import { logWarning } from "./workflow-logger.js";
13
15
  import { getWorkflowTransportSupportError, getRequiredWorkflowToolsForAutoUnit, } from "./workflow-mcp.js";
14
16
  export async function dispatchDirectPhase(ctx, pi, phase, base) {
15
17
  const state = await deriveState(base);
@@ -19,6 +21,12 @@ export async function dispatchDirectPhase(ctx, pi, phase, base) {
19
21
  ctx.ui.notify("Cannot dispatch: no active milestone.", "warning");
20
22
  return;
21
23
  }
24
+ const projectRoot = base;
25
+ // Switch the dispatch base to the canonical milestone worktree if one
26
+ // exists. Without this, /gsd dispatch invoked from the project root would
27
+ // build prompts and create a session anchored to the project root even
28
+ // though the milestone's actual code lives in the worktree.
29
+ const dispatchBase = resolveCanonicalMilestoneRoot(base, mid);
22
30
  const normalized = phase.toLowerCase();
23
31
  let unitType;
24
32
  let unitId;
@@ -37,7 +45,7 @@ export async function dispatchDirectPhase(ctx, pi, phase, base) {
37
45
  }
38
46
  // When require_slice_discussion is enabled, pause auto-mode before
39
47
  // each new slice so the user can discuss requirements first (#789).
40
- const sliceContextFile = resolveSliceFile(base, mid, sid, "CONTEXT");
48
+ const sliceContextFile = resolveSliceFile(dispatchBase, mid, sid, "CONTEXT");
41
49
  const requireDiscussion = loadEffectiveGSDPreferences()?.preferences?.phases?.require_slice_discussion;
42
50
  if (requireDiscussion && !sliceContextFile) {
43
51
  ctx.ui.notify(`Slice ${sid} requires discussion before planning. Run /gsd discuss to discuss this slice, then /gsd auto to resume.`, "info");
@@ -46,12 +54,12 @@ export async function dispatchDirectPhase(ctx, pi, phase, base) {
46
54
  }
47
55
  unitType = "research-slice";
48
56
  unitId = `${mid}/${sid}`;
49
- prompt = await buildResearchSlicePrompt(mid, midTitle, sid, sTitle, base);
57
+ prompt = await buildResearchSlicePrompt(mid, midTitle, sid, sTitle, dispatchBase);
50
58
  }
51
59
  else {
52
60
  unitType = "research-milestone";
53
61
  unitId = mid;
54
- prompt = await buildResearchMilestonePrompt(mid, midTitle, base);
62
+ prompt = await buildResearchMilestonePrompt(mid, midTitle, dispatchBase);
55
63
  }
56
64
  break;
57
65
  }
@@ -68,7 +76,7 @@ export async function dispatchDirectPhase(ctx, pi, phase, base) {
68
76
  }
69
77
  unitType = "plan-slice";
70
78
  unitId = `${mid}/${sid}`;
71
- prompt = await buildPlanSlicePrompt(mid, midTitle, sid, sTitle, base, undefined, {
79
+ prompt = await buildPlanSlicePrompt(mid, midTitle, sid, sTitle, dispatchBase, undefined, {
72
80
  sessionContextWindow: ctx.model?.contextWindow,
73
81
  modelRegistry: ctx.modelRegistry,
74
82
  });
@@ -76,7 +84,7 @@ export async function dispatchDirectPhase(ctx, pi, phase, base) {
76
84
  else {
77
85
  unitType = "plan-milestone";
78
86
  unitId = mid;
79
- prompt = await buildPlanMilestonePrompt(mid, midTitle, base);
87
+ prompt = await buildPlanMilestonePrompt(mid, midTitle, dispatchBase);
80
88
  }
81
89
  break;
82
90
  }
@@ -96,7 +104,7 @@ export async function dispatchDirectPhase(ctx, pi, phase, base) {
96
104
  }
97
105
  unitType = "execute-task";
98
106
  unitId = `${mid}/${sid}/${tid}`;
99
- prompt = await buildExecuteTaskPrompt(mid, sid, sTitle, tid, tTitle, base, {
107
+ prompt = await buildExecuteTaskPrompt(mid, sid, sTitle, tid, tTitle, dispatchBase, {
100
108
  sessionContextWindow: ctx.model?.contextWindow,
101
109
  modelRegistry: ctx.modelRegistry,
102
110
  });
@@ -115,12 +123,12 @@ export async function dispatchDirectPhase(ctx, pi, phase, base) {
115
123
  }
116
124
  unitType = "complete-slice";
117
125
  unitId = `${mid}/${sid}`;
118
- prompt = await buildCompleteSlicePrompt(mid, midTitle, sid, sTitle, base);
126
+ prompt = await buildCompleteSlicePrompt(mid, midTitle, sid, sTitle, dispatchBase);
119
127
  }
120
128
  else {
121
129
  unitType = "complete-milestone";
122
130
  unitId = mid;
123
- prompt = await buildCompleteMilestonePrompt(mid, midTitle, base);
131
+ prompt = await buildCompleteMilestonePrompt(mid, midTitle, dispatchBase);
124
132
  }
125
133
  break;
126
134
  }
@@ -133,7 +141,7 @@ export async function dispatchDirectPhase(ctx, pi, phase, base) {
133
141
  }
134
142
  if (completedSliceIds.length === 0) {
135
143
  // File-based fallback: parse roadmap checkboxes
136
- const roadmapPath = resolveMilestoneFile(base, mid, "ROADMAP");
144
+ const roadmapPath = resolveMilestoneFile(dispatchBase, mid, "ROADMAP");
137
145
  if (roadmapPath) {
138
146
  const roadmapContent = await loadFile(roadmapPath);
139
147
  if (roadmapContent) {
@@ -148,7 +156,7 @@ export async function dispatchDirectPhase(ctx, pi, phase, base) {
148
156
  const completedSliceId = completedSliceIds[completedSliceIds.length - 1];
149
157
  unitType = "reassess-roadmap";
150
158
  unitId = `${mid}/${completedSliceId}`;
151
- prompt = await buildReassessRoadmapPrompt(mid, midTitle, completedSliceId, base);
159
+ prompt = await buildReassessRoadmapPrompt(mid, midTitle, completedSliceId, dispatchBase);
152
160
  break;
153
161
  }
154
162
  case "uat":
@@ -163,7 +171,7 @@ export async function dispatchDirectPhase(ctx, pi, phase, base) {
163
171
  }
164
172
  if (uatCompletedSliceIds.length === 0) {
165
173
  // File-based fallback: parse roadmap checkboxes
166
- const roadmapPath = resolveMilestoneFile(base, mid, "ROADMAP");
174
+ const roadmapPath = resolveMilestoneFile(dispatchBase, mid, "ROADMAP");
167
175
  if (roadmapPath) {
168
176
  const roadmapContent = await loadFile(roadmapPath);
169
177
  if (roadmapContent) {
@@ -176,7 +184,7 @@ export async function dispatchDirectPhase(ctx, pi, phase, base) {
176
184
  return;
177
185
  }
178
186
  const sid = uatCompletedSliceIds[uatCompletedSliceIds.length - 1];
179
- const uatFile = resolveSliceFile(base, mid, sid, "UAT");
187
+ const uatFile = resolveSliceFile(dispatchBase, mid, sid, "UAT");
180
188
  if (!uatFile) {
181
189
  ctx.ui.notify("Cannot dispatch run-uat: no UAT file found.", "warning");
182
190
  return;
@@ -186,10 +194,10 @@ export async function dispatchDirectPhase(ctx, pi, phase, base) {
186
194
  ctx.ui.notify("Cannot dispatch run-uat: UAT file is empty.", "warning");
187
195
  return;
188
196
  }
189
- const uatPath = relSliceFile(base, mid, sid, "UAT");
197
+ const uatPath = relSliceFile(dispatchBase, mid, sid, "UAT");
190
198
  unitType = "run-uat";
191
199
  unitId = `${mid}/${sid}`;
192
- prompt = await buildRunUatPrompt(mid, sid, uatPath, uatContent, base);
200
+ prompt = await buildRunUatPrompt(mid, sid, uatPath, uatContent, dispatchBase);
193
201
  break;
194
202
  }
195
203
  case "replan":
@@ -202,7 +210,7 @@ export async function dispatchDirectPhase(ctx, pi, phase, base) {
202
210
  }
203
211
  unitType = "replan-slice";
204
212
  unitId = `${mid}/${sid}`;
205
- prompt = await buildReplanSlicePrompt(mid, midTitle, sid, sTitle, base);
213
+ prompt = await buildReplanSlicePrompt(mid, midTitle, sid, sTitle, dispatchBase);
206
214
  break;
207
215
  }
208
216
  default:
@@ -210,7 +218,7 @@ export async function dispatchDirectPhase(ctx, pi, phase, base) {
210
218
  return;
211
219
  }
212
220
  const compatibilityError = getWorkflowTransportSupportError(ctx.model?.provider, getRequiredWorkflowToolsForAutoUnit(unitType), {
213
- projectRoot: base,
221
+ projectRoot,
214
222
  surface: "direct phase dispatch",
215
223
  unitType,
216
224
  authMode: ctx.model?.provider ? ctx.modelRegistry.getProviderAuthMode(ctx.model.provider) : undefined,
@@ -221,10 +229,36 @@ export async function dispatchDirectPhase(ctx, pi, phase, base) {
221
229
  return;
222
230
  }
223
231
  ctx.ui.notify(`Dispatching ${unitType} for ${unitId}...`, "info");
224
- const result = await ctx.newSession();
225
- if (result.cancelled) {
226
- ctx.ui.notify("Session creation cancelled.", "warning");
227
- return;
232
+ const originalCwd = process.cwd();
233
+ try {
234
+ // Ensure cwd matches dispatchBase BEFORE newSession() captures it. Synchronous —
235
+ // no awaits between chdir and newSession.
236
+ try {
237
+ if (process.cwd() !== dispatchBase) {
238
+ process.chdir(dispatchBase);
239
+ }
240
+ }
241
+ catch (err) {
242
+ const msg = `Failed to chdir before direct-dispatch newSession (basePath: ${dispatchBase}): ${err instanceof Error ? err.message : String(err)}`;
243
+ logWarning("engine", msg, { file: "auto-direct-dispatch.ts", basePath: dispatchBase, error: err instanceof Error ? err.message : String(err) });
244
+ ctx.ui.notify(`${msg}. Cancelling dispatch to avoid running in the wrong directory.`, "error");
245
+ return;
246
+ }
247
+ const result = await ctx.newSession();
248
+ if (result.cancelled) {
249
+ ctx.ui.notify("Session creation cancelled.", "warning");
250
+ return;
251
+ }
252
+ pi.sendMessage({ customType: "gsd-dispatch", content: prompt, display: false }, { triggerTurn: true });
253
+ }
254
+ finally {
255
+ try {
256
+ if (process.cwd() !== originalCwd) {
257
+ process.chdir(originalCwd);
258
+ }
259
+ }
260
+ catch (err) {
261
+ logWarning("engine", `Failed to restore cwd after direct dispatch: ${err instanceof Error ? err.message : String(err)}`, { file: "auto-direct-dispatch.ts", basePath: originalCwd });
262
+ }
228
263
  }
229
- pi.sendMessage({ customType: "gsd-dispatch", content: prompt, display: false }, { triggerTurn: true });
230
264
  }
@@ -655,14 +655,25 @@ export const DISPATCH_RULES = [
655
655
  return null;
656
656
  if (!state.activeSlice)
657
657
  return null; // fall through
658
- // Only activate when reactive_execution is explicitly enabled
658
+ // Reactive dispatch is on by default when there are enough ready tasks to
659
+ // benefit from parallelism. Users opt out explicitly via
660
+ // `reactive_execution.enabled: false`. The downstream safety checks
661
+ // (graph ambiguity, ready-task count, conflict-free selection) still gate
662
+ // every actual dispatch, so the worst-case "default-on" outcome is the
663
+ // same fall-through to sequential execution as before.
659
664
  const reactiveConfig = prefs?.reactive_execution;
660
- if (!reactiveConfig?.enabled)
665
+ if (reactiveConfig?.enabled === false)
661
666
  return null;
662
667
  const sid = state.activeSlice.id;
663
668
  const sTitle = state.activeSlice.title;
664
- const maxParallel = reactiveConfig.max_parallel ?? 2;
665
- const subagentModel = reactiveConfig.subagent_model ?? resolveModelWithFallbacksForUnit("subagent")?.primary;
669
+ const maxParallel = reactiveConfig?.max_parallel ?? 2;
670
+ const subagentModel = reactiveConfig?.subagent_model ?? resolveModelWithFallbacksForUnit("subagent")?.primary;
671
+ // Default-on safety threshold: only activate reactive dispatch when at
672
+ // least N tasks are ready. Users who explicitly enabled reactive_execution
673
+ // keep the legacy threshold of 2 (matches the prior "any parallelism is
674
+ // better than none" intent). Default-on installs require >=3 to avoid
675
+ // surprising users with parallelism on small slices.
676
+ const minReadyTasksForReactive = reactiveConfig?.enabled === true ? 2 : 3;
666
677
  // Dry-run mode: max_parallel=1 means graph is derived and logged but
667
678
  // execution remains sequential
668
679
  if (maxParallel <= 1)
@@ -678,8 +689,9 @@ export const DISPATCH_RULES = [
678
689
  return null;
679
690
  const completed = new Set(graph.filter((n) => n.done).map((n) => n.id));
680
691
  const readyIds = getReadyTasks(graph, completed, new Set());
681
- // Only activate reactive dispatch when >1 task is ready
682
- if (readyIds.length <= 1)
692
+ // Only activate reactive dispatch when enough tasks are ready.
693
+ // Threshold is 2 when explicitly opted in, 3 when default-on.
694
+ if (readyIds.length < minReadyTasksForReactive)
683
695
  return null;
684
696
  const uokFlags = resolveUokFlags(prefs);
685
697
  const selected = uokFlags.executionGraph
@@ -23,7 +23,7 @@ import { composeInlinedContext } from "./unit-context-composer.js";
23
23
  import { logWarning } from "./workflow-logger.js";
24
24
  import { inlineGraphSubgraph } from "./graph-context.js";
25
25
  import { buildExtractionStepsBlock } from "./commands-extract-learnings.js";
26
- import { warnIfManifestHasMissingSkills } from "./skill-manifest.js";
26
+ import { resolveSkillManifest, warnIfManifestHasMissingSkills } from "./skill-manifest.js";
27
27
  // ─── Preamble Cap ─────────────────────────────────────────────────────────────
28
28
  /**
29
29
  * Historical static ceiling for the preamble cap. Kept as an upper bound even
@@ -675,6 +675,26 @@ function formatSkillActivationBlock(skillNames) {
675
675
  const calls = safe.map(name => `Call Skill({ skill: '${name}' })`).join('. ');
676
676
  return `<skill_activation>${calls}.</skill_activation>`;
677
677
  }
678
+ /**
679
+ * Manifest-driven recommendations block — informational only, does NOT
680
+ * auto-invoke. Lists per-unit-type skills that are installed but not already
681
+ * activated by explicit user intent (always_use_skills / prefer_skills /
682
+ * skill_rules / task-plan skills_used). Surfaces relevant skills to the
683
+ * model so they can be invoked when the model judges them useful.
684
+ *
685
+ * This is the additive complement to the existing activation directive:
686
+ * activation force-invokes (explicit intent), recommendations remind
687
+ * (manifest defaults). User intent is preserved as the stronger signal
688
+ * (RFC #4779 design principle); this block only adds visibility.
689
+ */
690
+ function formatSkillRecommendationsBlock(unitType, skillNames) {
691
+ if (!unitType)
692
+ return "";
693
+ const safe = skillNames.filter(name => SAFE_SKILL_NAME.test(name));
694
+ if (safe.length === 0)
695
+ return "";
696
+ return `<skill_recommendations unit="${unitType}">For this unit type, also consider invoking: ${safe.join(", ")}. Use Skill({ skill: 'name' }) when relevant — these are recommendations, not requirements.</skill_recommendations>`;
697
+ }
678
698
  export function buildSkillActivationBlock(params) {
679
699
  const prefs = params.preferences ?? loadEffectiveGSDPreferences(params.base)?.preferences;
680
700
  const contextTokens = tokenizeSkillContext(params.milestoneId, params.milestoneTitle, params.sliceId, params.sliceTitle, params.taskId, params.taskTitle);
@@ -717,10 +737,51 @@ export function buildSkillActivationBlock(params) {
717
737
  logWarning("prompt", `parseTaskPlanFile failed: ${err instanceof Error ? err.message : String(err)}`);
718
738
  }
719
739
  }
740
+ // Heuristic auto-match (gated on skill_discovery: "auto").
741
+ // For each installed skill, check if its name or description appears in the
742
+ // unit's context tokens (milestone/slice/task titles). Only consider skills
743
+ // already on the unit-type manifest allowlist — this keeps the heuristic
744
+ // narrow and avoids wildly off-topic activations.
745
+ // Users who set `skill_discovery: "off"` or "suggest" do not get
746
+ // auto-matched skills (the recommendations block still surfaces manifest
747
+ // skills passively); only "auto" actually adds them to the activation
748
+ // directive set. Default `skill_discovery` is "suggest", so this is opt-in.
749
+ if ((prefs?.skill_discovery ?? "suggest") === "auto") {
750
+ const manifestAllow = resolveSkillManifest(params.unitType);
751
+ const allowSet = manifestAllow ? new Set(manifestAllow) : null;
752
+ for (const skill of visibleSkills) {
753
+ const normalized = normalizeSkillReference(skill.name);
754
+ if (matched.has(normalized) || avoided.has(normalized))
755
+ continue;
756
+ // Respect the manifest allowlist when present; wildcard (null) lets all
757
+ // installed skills compete for keyword match.
758
+ if (allowSet && !allowSet.has(normalized))
759
+ continue;
760
+ if (skillMatchesContext(skill, contextTokens)) {
761
+ matched.add(normalized);
762
+ }
763
+ }
764
+ }
720
765
  const ordered = [...matched]
721
766
  .filter(name => installedNames.has(name) && !avoided.has(name))
722
767
  .sort();
723
- return formatSkillActivationBlock(ordered);
768
+ const activationBlock = formatSkillActivationBlock(ordered);
769
+ // Manifest-driven recommendations (additive, does not override explicit intent).
770
+ // Only surface skills the manifest declares for this unit type that are
771
+ // installed and not already in matched/avoided.
772
+ const matchedSet = new Set(ordered);
773
+ const manifestList = resolveSkillManifest(params.unitType);
774
+ const recommendations = (manifestList ?? [])
775
+ .filter(name => installedNames.has(name) && !avoided.has(name) && !matchedSet.has(name))
776
+ .sort();
777
+ const recommendationsBlock = formatSkillRecommendationsBlock(params.unitType, recommendations);
778
+ if (!activationBlock && !recommendationsBlock)
779
+ return "";
780
+ if (!activationBlock)
781
+ return recommendationsBlock;
782
+ if (!recommendationsBlock)
783
+ return activationBlock;
784
+ return `${activationBlock}\n${recommendationsBlock}`;
724
785
  }
725
786
  /**
726
787
  * Build the skill discovery template variables for research prompts.
@@ -1059,6 +1120,7 @@ export async function checkNeedsRunUat(base, mid, state, prefs) {
1059
1120
  export async function buildDiscussMilestonePrompt(mid, midTitle, base, structuredQuestionsAvailable = "false") {
1060
1121
  const discussTemplates = inlineTemplate("context", "Context");
1061
1122
  const basePrompt = loadPrompt("guided-discuss-milestone", {
1123
+ workingDirectory: base,
1062
1124
  milestoneId: mid,
1063
1125
  milestoneTitle: midTitle,
1064
1126
  inlinedTemplates: discussTemplates,
@@ -2262,6 +2324,7 @@ export async function buildParallelResearchSlicesPrompt(mid, midTitle, slices, b
2262
2324
  ].join("\n"));
2263
2325
  }
2264
2326
  return loadPrompt("parallel-research-slices", {
2327
+ workingDirectory: basePath,
2265
2328
  mid,
2266
2329
  midTitle,
2267
2330
  sliceCount: String(slices.length),
@@ -2289,11 +2352,14 @@ export async function buildGateEvaluatePrompt(mid, midTitle, sid, sTitle, base,
2289
2352
  const gateDefs = getGatesForTurn("gate-evaluate").filter((def) => pendingIds.has(def.id));
2290
2353
  const subagentSections = [];
2291
2354
  const gateListLines = [];
2355
+ const normalizedBase = base.replaceAll("\\", "/");
2292
2356
  for (const def of gateDefs) {
2293
2357
  gateListLines.push(`- **${def.id}**: ${def.question}`);
2294
2358
  const subPrompt = [
2295
2359
  `You are evaluating quality gate **${def.id}** for slice ${sid} (${sTitle}).`,
2296
2360
  "",
2361
+ `**Working directory:** \`${normalizedBase}\`. All file reads, writes, and shell commands MUST operate relative to this directory. Do NOT \`cd\` to any other directory.`,
2362
+ "",
2297
2363
  `## Question: ${def.question}`,
2298
2364
  "",
2299
2365
  def.guidance,
@@ -2401,6 +2467,7 @@ export async function buildRewriteDocsPrompt(mid, midTitle, activeSlice, base, o
2401
2467
  ].join("\n")).join("\n\n");
2402
2468
  const documentList = docList.length > 0 ? docList.join("\n") : "- No active plan documents found.";
2403
2469
  return loadPrompt("rewrite-docs", {
2470
+ workingDirectory: base,
2404
2471
  milestoneId: mid,
2405
2472
  milestoneTitle: midTitle,
2406
2473
  sliceId: sid ?? "none",
@@ -7,6 +7,7 @@
7
7
  * globals or AutoContext dependency.
8
8
  */
9
9
  import { parseUnitId } from "./unit-id.js";
10
+ import { MILESTONE_ID_RE } from "./milestone-ids.js";
10
11
  import { appendEvent } from "./workflow-events.js";
11
12
  import { atomicWriteSync } from "./atomic-write.js";
12
13
  import { clearParseCache } from "./files.js";
@@ -168,8 +169,35 @@ function getChangedFilesSinceBranch(basePath, targetBranch) {
168
169
  }
169
170
  }
170
171
  function getChangedFilesFromMilestoneTaggedCommits(basePath, milestoneId) {
172
+ // Primary: path-scoped log against .gsd/milestones/<id>. Fast and unbounded
173
+ // by depth when .gsd/ is tracked in git.
174
+ const scoped = scanGsdTaggedCommits(basePath, milestoneId, [
175
+ "log", "--format=%H%x1f%B%x1e", "HEAD", "--", `.gsd/milestones/${milestoneId}`,
176
+ ]);
177
+ if (!scoped.ok)
178
+ return scoped;
179
+ if (scoped.matched)
180
+ return scoped;
181
+ // Fallback (#5033): when .gsd/ is gitignored / external / untracked, the
182
+ // path-scoped scan matches no commits even though GSD-tagged commits
183
+ // referencing the milestone exist on the integration branch. Re-scan all
184
+ // of HEAD's history and rely on commitMatchesMilestone to bind by
185
+ // explicit milestone mention in the message body.
186
+ //
187
+ // Intentionally unbounded — symmetric with the primary scan, and avoids
188
+ // reintroducing the rolling-depth failure class removed in #4699 where
189
+ // milestone evidence aged out behind unrelated activity.
190
+ return scanGsdTaggedCommits(basePath, milestoneId, [
191
+ "log", "--format=%H%x1f%B%x1e", "HEAD",
192
+ ]);
193
+ }
194
+ function scanGsdTaggedCommits(basePath, milestoneId, gitArgs) {
171
195
  try {
172
- const logOutput = execFileSync("git", ["log", "--format=%H%x1f%B%x1e", "HEAD", "--", `.gsd/milestones/${milestoneId}`], { cwd: basePath, stdio: ["ignore", "pipe", "pipe"], encoding: "utf-8" });
196
+ const logOutput = execFileSync("git", [...gitArgs], {
197
+ cwd: basePath,
198
+ stdio: ["ignore", "pipe", "pipe"],
199
+ encoding: "utf-8",
200
+ });
173
201
  const records = logOutput
174
202
  .split("\x1e")
175
203
  .map((record) => record.trim())
@@ -213,13 +241,24 @@ function commitMatchesMilestone(message, milestoneId, files) {
213
241
  if (commitTrailerStartsWithMilestone(message, milestoneId))
214
242
  return true;
215
243
  // Meaningful execute-task commits currently store task scope as Sxx/Tyy
216
- // rather than Mxx/Sxx/Tyy. Bind those commits back to the milestone only
217
- // when the commit also touched this milestone's artifacts.
244
+ // rather than Mxx/Sxx/Tyy. Bind those commits back to the milestone when
245
+ // either the commit touched this milestone's artifacts, or — for projects
246
+ // where .gsd/ is gitignored/external (#5033) — the message explicitly
247
+ // names the milestone.
218
248
  if (/^GSD-Task:\s*S[^/\s]+\/T\S+/m.test(message)) {
219
- return files.some((file) => isMilestoneArtifactPath(file, milestoneId));
249
+ if (files.some((file) => isMilestoneArtifactPath(file, milestoneId)))
250
+ return true;
251
+ if (commitMessageMentionsMilestone(message, milestoneId))
252
+ return true;
220
253
  }
221
254
  return false;
222
255
  }
256
+ function commitMessageMentionsMilestone(message, milestoneId) {
257
+ if (!MILESTONE_ID_RE.test(milestoneId))
258
+ return false;
259
+ const escapedMilestone = milestoneId.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
260
+ return new RegExp(`\\b${escapedMilestone}\\b`).test(message);
261
+ }
223
262
  function commitTrailerStartsWithMilestone(message, milestoneId) {
224
263
  const escapedMilestone = milestoneId.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
225
264
  const trailerPattern = new RegExp(`^GSD-(?:Task|Unit):\\s*${escapedMilestone}(?:$|[\\s/])`, "m");
@@ -0,0 +1,31 @@
1
+ // GSD auto-mode runtime state
2
+ import { AutoSession } from "./auto/session.js";
3
+ import { isDeterministicPolicyError, isQueuedUserMessageSkip, isToolInvocationError, markToolEnd as markTrackedToolEnd, markToolStart as markTrackedToolStart, } from "./auto-tool-tracking.js";
4
+ export const autoSession = new AutoSession();
5
+ export function getAutoRuntimeSnapshot() {
6
+ return {
7
+ active: autoSession.active,
8
+ paused: autoSession.paused,
9
+ currentUnit: autoSession.currentUnit ? { ...autoSession.currentUnit } : null,
10
+ basePath: autoSession.basePath,
11
+ };
12
+ }
13
+ export function isAutoActive() {
14
+ return autoSession.active;
15
+ }
16
+ export function isAutoPaused() {
17
+ return autoSession.paused;
18
+ }
19
+ export function markToolStart(toolCallId, toolName) {
20
+ markTrackedToolStart(toolCallId, autoSession.active, toolName);
21
+ }
22
+ export function markToolEnd(toolCallId) {
23
+ markTrackedToolEnd(toolCallId);
24
+ }
25
+ export function recordToolInvocationError(toolName, errorMsg) {
26
+ if (!autoSession.active)
27
+ return;
28
+ if (isToolInvocationError(errorMsg) || isQueuedUserMessageSkip(errorMsg) || isDeterministicPolicyError(errorMsg)) {
29
+ autoSession.lastToolInvocationError = `${toolName}: ${errorMsg}`;
30
+ }
31
+ }
@@ -208,7 +208,7 @@ export function auditOrphanedMilestoneBranches(basePath, isolationMode) {
208
208
  else {
209
209
  // Branch is NOT merged — preserve for safety, warn the user
210
210
  warnings.push(`Branch ${branch} exists for completed milestone ${milestoneId} but is NOT merged into ${mainBranch}. ` +
211
- `This may contain unmerged work. Merge manually or run \`/gsd health --fix\` to resolve.`);
211
+ `This may contain unmerged work. Merge manually or run \`/gsd doctor fix\` to resolve.`);
212
212
  // #4764 telemetry
213
213
  try {
214
214
  emitWorktreeOrphaned(basePath, milestoneId, {
@@ -139,6 +139,6 @@ export const DETERMINISTIC_POLICY_ERROR_STRINGS = [
139
139
  export function isDeterministicPolicyError(errorMsg) {
140
140
  if (!errorMsg)
141
141
  return false;
142
- return (DETERMINISTIC_POLICY_ERROR_RE.test(errorMsg) ||
143
- DETERMINISTIC_POLICY_ERROR_STRINGS.some(s => errorMsg.includes(s)));
142
+ return DETERMINISTIC_POLICY_ERROR_RE.test(errorMsg)
143
+ || DETERMINISTIC_POLICY_ERROR_STRINGS.some(s => errorMsg.includes(s));
144
144
  }