gsd-pi 2.54.0 → 2.56.0-dev.b753b00

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 (262) hide show
  1. package/dist/cli.js +19 -19
  2. package/dist/headless-ui.d.ts +27 -1
  3. package/dist/headless-ui.js +203 -13
  4. package/dist/headless.js +60 -3
  5. package/dist/resources/extensions/bg-shell/bg-shell-lifecycle.js +2 -2
  6. package/dist/resources/extensions/bg-shell/utilities.js +34 -5
  7. package/dist/resources/extensions/gsd/auto/phases.js +19 -3
  8. package/dist/resources/extensions/gsd/auto-dispatch.js +1 -1
  9. package/dist/resources/extensions/gsd/auto-model-selection.js +17 -1
  10. package/dist/resources/extensions/gsd/auto-prompts.js +9 -0
  11. package/dist/resources/extensions/gsd/auto-start.js +12 -5
  12. package/dist/resources/extensions/gsd/auto-worktree.js +39 -14
  13. package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +5 -1
  14. package/dist/resources/extensions/gsd/bootstrap/provider-error-resume.js +18 -0
  15. package/dist/resources/extensions/gsd/bootstrap/register-extension.js +18 -5
  16. package/dist/resources/extensions/gsd/bootstrap/register-shortcuts.js +20 -0
  17. package/dist/resources/extensions/gsd/commands/catalog.js +2 -1
  18. package/dist/resources/extensions/gsd/commands/handlers/parallel.js +15 -1
  19. package/dist/resources/extensions/gsd/crash-recovery.js +2 -2
  20. package/dist/resources/extensions/gsd/parallel-monitor-overlay.js +413 -0
  21. package/dist/resources/extensions/gsd/parallel-orchestrator.js +5 -1
  22. package/dist/resources/extensions/gsd/session-lock.js +46 -12
  23. package/dist/resources/extensions/gsd/skill-health.js +2 -2
  24. package/dist/resources/extensions/gsd/visualizer-overlay.js +3 -3
  25. package/dist/resources/extensions/shared/format-utils.js +1 -1
  26. package/dist/resources/extensions/subagent/worker-registry.js +2 -1
  27. package/dist/web/standalone/.next/BUILD_ID +1 -1
  28. package/dist/web/standalone/.next/app-path-routes-manifest.json +18 -18
  29. package/dist/web/standalone/.next/build-manifest.json +4 -4
  30. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  31. package/dist/web/standalone/.next/react-loadable-manifest.json +2 -2
  32. package/dist/web/standalone/.next/required-server-files.json +3 -3
  33. package/dist/web/standalone/.next/server/app/_global-error/page.js +3 -3
  34. package/dist/web/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
  35. package/dist/web/standalone/.next/server/app/_global-error.html +2 -2
  36. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  37. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  38. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  39. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  40. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  41. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  42. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  43. package/dist/web/standalone/.next/server/app/_not-found/page.js +2 -2
  44. package/dist/web/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  45. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  46. package/dist/web/standalone/.next/server/app/_not-found.rsc +3 -3
  47. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +3 -3
  48. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  49. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +3 -3
  50. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  51. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  52. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  53. package/dist/web/standalone/.next/server/app/api/boot/route.js +1 -1
  54. package/dist/web/standalone/.next/server/app/api/boot/route_client-reference-manifest.js +1 -1
  55. package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route.js +1 -1
  56. package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route_client-reference-manifest.js +1 -1
  57. package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route.js +1 -1
  58. package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route_client-reference-manifest.js +1 -1
  59. package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route.js +2 -2
  60. package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route_client-reference-manifest.js +1 -1
  61. package/dist/web/standalone/.next/server/app/api/browse-directories/route.js +1 -1
  62. package/dist/web/standalone/.next/server/app/api/browse-directories/route_client-reference-manifest.js +1 -1
  63. package/dist/web/standalone/.next/server/app/api/captures/route.js +1 -1
  64. package/dist/web/standalone/.next/server/app/api/captures/route_client-reference-manifest.js +1 -1
  65. package/dist/web/standalone/.next/server/app/api/cleanup/route.js +1 -1
  66. package/dist/web/standalone/.next/server/app/api/cleanup/route_client-reference-manifest.js +1 -1
  67. package/dist/web/standalone/.next/server/app/api/dev-mode/route.js +1 -1
  68. package/dist/web/standalone/.next/server/app/api/dev-mode/route_client-reference-manifest.js +1 -1
  69. package/dist/web/standalone/.next/server/app/api/doctor/route.js +1 -1
  70. package/dist/web/standalone/.next/server/app/api/doctor/route_client-reference-manifest.js +1 -1
  71. package/dist/web/standalone/.next/server/app/api/experimental/route.js +2 -2
  72. package/dist/web/standalone/.next/server/app/api/experimental/route_client-reference-manifest.js +1 -1
  73. package/dist/web/standalone/.next/server/app/api/export-data/route.js +1 -1
  74. package/dist/web/standalone/.next/server/app/api/export-data/route_client-reference-manifest.js +1 -1
  75. package/dist/web/standalone/.next/server/app/api/files/route.js +1 -1
  76. package/dist/web/standalone/.next/server/app/api/files/route_client-reference-manifest.js +1 -1
  77. package/dist/web/standalone/.next/server/app/api/forensics/route.js +1 -1
  78. package/dist/web/standalone/.next/server/app/api/forensics/route_client-reference-manifest.js +1 -1
  79. package/dist/web/standalone/.next/server/app/api/git/route.js +1 -1
  80. package/dist/web/standalone/.next/server/app/api/git/route_client-reference-manifest.js +1 -1
  81. package/dist/web/standalone/.next/server/app/api/history/route.js +1 -1
  82. package/dist/web/standalone/.next/server/app/api/history/route_client-reference-manifest.js +1 -1
  83. package/dist/web/standalone/.next/server/app/api/hooks/route.js +1 -1
  84. package/dist/web/standalone/.next/server/app/api/hooks/route_client-reference-manifest.js +1 -1
  85. package/dist/web/standalone/.next/server/app/api/inspect/route.js +1 -1
  86. package/dist/web/standalone/.next/server/app/api/inspect/route_client-reference-manifest.js +1 -1
  87. package/dist/web/standalone/.next/server/app/api/knowledge/route.js +1 -1
  88. package/dist/web/standalone/.next/server/app/api/knowledge/route_client-reference-manifest.js +1 -1
  89. package/dist/web/standalone/.next/server/app/api/live-state/route.js +1 -1
  90. package/dist/web/standalone/.next/server/app/api/live-state/route_client-reference-manifest.js +1 -1
  91. package/dist/web/standalone/.next/server/app/api/onboarding/route.js +1 -1
  92. package/dist/web/standalone/.next/server/app/api/onboarding/route_client-reference-manifest.js +1 -1
  93. package/dist/web/standalone/.next/server/app/api/preferences/route.js +1 -1
  94. package/dist/web/standalone/.next/server/app/api/preferences/route_client-reference-manifest.js +1 -1
  95. package/dist/web/standalone/.next/server/app/api/projects/route.js +1 -1
  96. package/dist/web/standalone/.next/server/app/api/projects/route_client-reference-manifest.js +1 -1
  97. package/dist/web/standalone/.next/server/app/api/recovery/route.js +1 -1
  98. package/dist/web/standalone/.next/server/app/api/recovery/route_client-reference-manifest.js +1 -1
  99. package/dist/web/standalone/.next/server/app/api/remote-questions/route.js +2 -2
  100. package/dist/web/standalone/.next/server/app/api/remote-questions/route_client-reference-manifest.js +1 -1
  101. package/dist/web/standalone/.next/server/app/api/session/browser/route.js +1 -1
  102. package/dist/web/standalone/.next/server/app/api/session/browser/route_client-reference-manifest.js +1 -1
  103. package/dist/web/standalone/.next/server/app/api/session/command/route.js +1 -1
  104. package/dist/web/standalone/.next/server/app/api/session/command/route_client-reference-manifest.js +1 -1
  105. package/dist/web/standalone/.next/server/app/api/session/events/route.js +2 -2
  106. package/dist/web/standalone/.next/server/app/api/session/events/route_client-reference-manifest.js +1 -1
  107. package/dist/web/standalone/.next/server/app/api/session/manage/route.js +1 -1
  108. package/dist/web/standalone/.next/server/app/api/session/manage/route_client-reference-manifest.js +1 -1
  109. package/dist/web/standalone/.next/server/app/api/settings-data/route.js +1 -1
  110. package/dist/web/standalone/.next/server/app/api/settings-data/route_client-reference-manifest.js +1 -1
  111. package/dist/web/standalone/.next/server/app/api/shutdown/route.js +1 -1
  112. package/dist/web/standalone/.next/server/app/api/shutdown/route_client-reference-manifest.js +1 -1
  113. package/dist/web/standalone/.next/server/app/api/skill-health/route.js +1 -1
  114. package/dist/web/standalone/.next/server/app/api/skill-health/route_client-reference-manifest.js +1 -1
  115. package/dist/web/standalone/.next/server/app/api/steer/route.js +1 -1
  116. package/dist/web/standalone/.next/server/app/api/steer/route_client-reference-manifest.js +1 -1
  117. package/dist/web/standalone/.next/server/app/api/switch-root/route.js +1 -1
  118. package/dist/web/standalone/.next/server/app/api/switch-root/route_client-reference-manifest.js +1 -1
  119. package/dist/web/standalone/.next/server/app/api/terminal/input/route.js +2 -2
  120. package/dist/web/standalone/.next/server/app/api/terminal/input/route_client-reference-manifest.js +1 -1
  121. package/dist/web/standalone/.next/server/app/api/terminal/resize/route.js +2 -2
  122. package/dist/web/standalone/.next/server/app/api/terminal/resize/route_client-reference-manifest.js +1 -1
  123. package/dist/web/standalone/.next/server/app/api/terminal/sessions/route.js +2 -2
  124. package/dist/web/standalone/.next/server/app/api/terminal/sessions/route_client-reference-manifest.js +1 -1
  125. package/dist/web/standalone/.next/server/app/api/terminal/stream/route.js +4 -4
  126. package/dist/web/standalone/.next/server/app/api/terminal/stream/route_client-reference-manifest.js +1 -1
  127. package/dist/web/standalone/.next/server/app/api/terminal/upload/route.js +1 -1
  128. package/dist/web/standalone/.next/server/app/api/terminal/upload/route_client-reference-manifest.js +1 -1
  129. package/dist/web/standalone/.next/server/app/api/undo/route.js +1 -1
  130. package/dist/web/standalone/.next/server/app/api/undo/route_client-reference-manifest.js +1 -1
  131. package/dist/web/standalone/.next/server/app/api/update/route.js +1 -1
  132. package/dist/web/standalone/.next/server/app/api/update/route_client-reference-manifest.js +1 -1
  133. package/dist/web/standalone/.next/server/app/api/visualizer/route.js +1 -1
  134. package/dist/web/standalone/.next/server/app/api/visualizer/route_client-reference-manifest.js +1 -1
  135. package/dist/web/standalone/.next/server/app/index.html +1 -1
  136. package/dist/web/standalone/.next/server/app/index.rsc +4 -4
  137. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
  138. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +4 -4
  139. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  140. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +3 -3
  141. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  142. package/dist/web/standalone/.next/server/app/page.js +2 -2
  143. package/dist/web/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
  144. package/dist/web/standalone/.next/server/app-paths-manifest.json +18 -18
  145. package/dist/web/standalone/.next/server/chunks/2229.js +2 -2
  146. package/dist/web/standalone/.next/server/chunks/7471.js +3 -3
  147. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  148. package/dist/web/standalone/.next/server/middleware-react-loadable-manifest.js +1 -1
  149. package/dist/web/standalone/.next/server/middleware.js +2 -2
  150. package/dist/web/standalone/.next/server/next-font-manifest.js +1 -1
  151. package/dist/web/standalone/.next/server/next-font-manifest.json +1 -1
  152. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  153. package/dist/web/standalone/.next/server/pages/500.html +2 -2
  154. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  155. package/dist/web/standalone/.next/static/chunks/6502.2305d0afd2385711.js +9 -0
  156. package/dist/web/standalone/.next/static/chunks/app/_not-found/{page-2f24283c162b6ab3.js → page-f2a7482d42a5614b.js} +1 -1
  157. package/dist/web/standalone/.next/static/chunks/app/{layout-9ecfd95f343793f0.js → layout-a16c7a7ecdf0c2cf.js} +1 -1
  158. package/dist/web/standalone/.next/static/chunks/app/page-0c485498795110d6.js +1 -0
  159. package/dist/web/standalone/.next/static/chunks/main-app-fdab67f7802d7832.js +1 -0
  160. package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/global-error-459824ffb8c323dd.js +1 -0
  161. package/dist/web/standalone/.next/static/chunks/{webpack-bca0e732db0dcec3.js → webpack-4332cbd5dd1be584.js} +1 -1
  162. package/dist/web/standalone/node_modules/node-pty/build/Makefile +2 -2
  163. package/dist/web/standalone/node_modules/node-pty/build/Release/pty.node +0 -0
  164. package/dist/web/standalone/node_modules/node-pty/build/pty.target.mk +14 -14
  165. package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api.target.mk +14 -14
  166. package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api_except.target.mk +14 -14
  167. package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api_maybe.target.mk +14 -14
  168. package/dist/web/standalone/server.js +1 -1
  169. package/package.json +6 -4
  170. package/packages/pi-coding-agent/dist/core/model-registry.d.ts +1 -1
  171. package/packages/pi-coding-agent/dist/core/model-registry.d.ts.map +1 -1
  172. package/packages/pi-coding-agent/dist/core/model-registry.js.map +1 -1
  173. package/packages/pi-coding-agent/dist/modes/interactive/components/provider-manager.d.ts +2 -0
  174. package/packages/pi-coding-agent/dist/modes/interactive/components/provider-manager.d.ts.map +1 -1
  175. package/packages/pi-coding-agent/dist/modes/interactive/components/provider-manager.js +14 -2
  176. package/packages/pi-coding-agent/dist/modes/interactive/components/provider-manager.js.map +1 -1
  177. package/packages/pi-coding-agent/package.json +1 -1
  178. package/packages/pi-coding-agent/src/core/model-registry.ts +1 -1
  179. package/packages/pi-coding-agent/src/modes/interactive/components/provider-manager.ts +16 -2
  180. package/pkg/package.json +1 -1
  181. package/scripts/ensure-workspace-builds.cjs +45 -41
  182. package/src/resources/extensions/bg-shell/bg-shell-lifecycle.ts +2 -2
  183. package/src/resources/extensions/bg-shell/utilities.ts +39 -4
  184. package/src/resources/extensions/gsd/auto/phases.ts +25 -4
  185. package/src/resources/extensions/gsd/auto-dispatch.ts +1 -1
  186. package/src/resources/extensions/gsd/auto-model-selection.ts +21 -1
  187. package/src/resources/extensions/gsd/auto-prompts.ts +15 -0
  188. package/src/resources/extensions/gsd/auto-start.ts +13 -5
  189. package/src/resources/extensions/gsd/auto-worktree.ts +46 -13
  190. package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +5 -4
  191. package/src/resources/extensions/gsd/bootstrap/provider-error-resume.ts +53 -0
  192. package/src/resources/extensions/gsd/bootstrap/register-extension.ts +19 -6
  193. package/src/resources/extensions/gsd/bootstrap/register-shortcuts.ts +24 -0
  194. package/src/resources/extensions/gsd/commands/catalog.ts +2 -1
  195. package/src/resources/extensions/gsd/commands/handlers/parallel.ts +19 -1
  196. package/src/resources/extensions/gsd/crash-recovery.ts +2 -3
  197. package/src/resources/extensions/gsd/parallel-monitor-overlay.ts +497 -0
  198. package/src/resources/extensions/gsd/parallel-orchestrator.ts +6 -1
  199. package/src/resources/extensions/gsd/session-lock.ts +46 -12
  200. package/src/resources/extensions/gsd/skill-health.ts +2 -2
  201. package/src/resources/extensions/gsd/tests/auto-model-selection.test.ts +139 -0
  202. package/src/resources/extensions/gsd/tests/auto-start-model-capture.test.ts +28 -0
  203. package/src/resources/extensions/gsd/tests/{all-milestones-complete-merge.test.ts → integration/all-milestones-complete-merge.test.ts} +3 -3
  204. package/src/resources/extensions/gsd/tests/{atomic-task-closeout.test.ts → integration/atomic-task-closeout.test.ts} +1 -1
  205. package/src/resources/extensions/gsd/tests/{auto-preflight.test.ts → integration/auto-preflight.test.ts} +1 -1
  206. package/src/resources/extensions/gsd/tests/{auto-recovery.test.ts → integration/auto-recovery.test.ts} +7 -7
  207. package/src/resources/extensions/gsd/tests/{auto-secrets-gate.test.ts → integration/auto-secrets-gate.test.ts} +2 -2
  208. package/src/resources/extensions/gsd/tests/{auto-stash-merge.test.ts → integration/auto-stash-merge.test.ts} +3 -3
  209. package/src/resources/extensions/gsd/tests/{auto-worktree-milestone-merge.test.ts → integration/auto-worktree-milestone-merge.test.ts} +4 -4
  210. package/src/resources/extensions/gsd/tests/{auto-worktree.test.ts → integration/auto-worktree.test.ts} +5 -5
  211. package/src/resources/extensions/gsd/tests/{continue-here.test.ts → integration/continue-here.test.ts} +3 -3
  212. package/src/resources/extensions/gsd/tests/{doctor-completion-deferral.test.ts → integration/doctor-completion-deferral.test.ts} +1 -1
  213. package/src/resources/extensions/gsd/tests/{doctor-delimiter-fix.test.ts → integration/doctor-delimiter-fix.test.ts} +1 -1
  214. package/src/resources/extensions/gsd/tests/{doctor-enhancements.test.ts → integration/doctor-enhancements.test.ts} +3 -3
  215. package/src/resources/extensions/gsd/tests/{doctor-environment-worktree.test.ts → integration/doctor-environment-worktree.test.ts} +1 -1
  216. package/src/resources/extensions/gsd/tests/{doctor-environment.test.ts → integration/doctor-environment.test.ts} +1 -1
  217. package/src/resources/extensions/gsd/tests/{doctor-fixlevel.test.ts → integration/doctor-fixlevel.test.ts} +2 -2
  218. package/src/resources/extensions/gsd/tests/{doctor-git.test.ts → integration/doctor-git.test.ts} +1 -1
  219. package/src/resources/extensions/gsd/tests/{doctor-proactive.test.ts → integration/doctor-proactive.test.ts} +1 -1
  220. package/src/resources/extensions/gsd/tests/{doctor-roadmap-summary-atomicity.test.ts → integration/doctor-roadmap-summary-atomicity.test.ts} +1 -1
  221. package/src/resources/extensions/gsd/tests/{doctor-runtime.test.ts → integration/doctor-runtime.test.ts} +1 -1
  222. package/src/resources/extensions/gsd/tests/{doctor.test.ts → integration/doctor.test.ts} +1 -1
  223. package/src/resources/extensions/gsd/tests/{e2e-workflow-pipeline-integration.test.ts → integration/e2e-workflow-pipeline-integration.test.ts} +5 -5
  224. package/src/resources/extensions/gsd/tests/{feature-branch-lifecycle-integration.test.ts → integration/feature-branch-lifecycle-integration.test.ts} +4 -4
  225. package/src/resources/extensions/gsd/tests/{git-locale.test.ts → integration/git-locale.test.ts} +4 -4
  226. package/src/resources/extensions/gsd/tests/{git-self-heal.test.ts → integration/git-self-heal.test.ts} +1 -1
  227. package/src/resources/extensions/gsd/tests/{git-service.test.ts → integration/git-service.test.ts} +4 -4
  228. package/src/resources/extensions/gsd/tests/{gitignore-tracked-gsd.test.ts → integration/gitignore-tracked-gsd.test.ts} +2 -2
  229. package/src/resources/extensions/gsd/tests/{idle-recovery.test.ts → integration/idle-recovery.test.ts} +3 -3
  230. package/src/resources/extensions/gsd/tests/{inherited-repo-home-dir.test.ts → integration/inherited-repo-home-dir.test.ts} +1 -1
  231. package/src/resources/extensions/gsd/tests/{integration-lifecycle.test.ts → integration/integration-lifecycle.test.ts} +4 -4
  232. package/src/resources/extensions/gsd/tests/{integration-mixed-milestones.test.ts → integration/integration-mixed-milestones.test.ts} +6 -6
  233. package/src/resources/extensions/gsd/tests/{integration-proof.test.ts → integration/integration-proof.test.ts} +12 -12
  234. package/src/resources/extensions/gsd/tests/{migrate-command.test.ts → integration/migrate-command.test.ts} +2 -2
  235. package/src/resources/extensions/gsd/tests/{milestone-transition-worktree.test.ts → integration/milestone-transition-worktree.test.ts} +3 -3
  236. package/src/resources/extensions/gsd/tests/{parallel-merge.test.ts → integration/parallel-merge.test.ts} +3 -3
  237. package/src/resources/extensions/gsd/tests/{parallel-workers-multi-milestone-e2e.test.ts → integration/parallel-workers-multi-milestone-e2e.test.ts} +3 -3
  238. package/src/resources/extensions/gsd/tests/{paths.test.ts → integration/paths.test.ts} +1 -1
  239. package/src/resources/extensions/gsd/tests/{plugin-importer-live.test.ts → integration/plugin-importer-live.test.ts} +2 -2
  240. package/src/resources/extensions/gsd/tests/{queue-completed-milestone-perf.test.ts → integration/queue-completed-milestone-perf.test.ts} +3 -3
  241. package/src/resources/extensions/gsd/tests/{queue-reorder-e2e.test.ts → integration/queue-reorder-e2e.test.ts} +5 -5
  242. package/src/resources/extensions/gsd/tests/{quick-branch-lifecycle.test.ts → integration/quick-branch-lifecycle.test.ts} +5 -5
  243. package/src/resources/extensions/gsd/tests/{run-uat.test.ts → integration/run-uat.test.ts} +4 -4
  244. package/src/resources/extensions/gsd/tests/{token-savings.test.ts → integration/token-savings.test.ts} +3 -3
  245. package/src/resources/extensions/gsd/tests/{worktree-e2e.test.ts → integration/worktree-e2e.test.ts} +4 -4
  246. package/src/resources/extensions/gsd/tests/journal-integration.test.ts +55 -0
  247. package/src/resources/extensions/gsd/tests/parallel-monitor-overlay.test.ts +60 -0
  248. package/src/resources/extensions/gsd/tests/parallel-worker-lock-contention.test.ts +226 -0
  249. package/src/resources/extensions/gsd/tests/plan-milestone-queue-context.test.ts +48 -0
  250. package/src/resources/extensions/gsd/tests/preferences-worktree-sync.test.ts +61 -19
  251. package/src/resources/extensions/gsd/tests/provider-errors.test.ts +98 -0
  252. package/src/resources/extensions/gsd/tests/register-extension-guard.test.ts +59 -0
  253. package/src/resources/extensions/gsd/tests/worktree-preferences-sync.test.ts +49 -24
  254. package/src/resources/extensions/gsd/visualizer-overlay.ts +3 -3
  255. package/src/resources/extensions/shared/format-utils.ts +1 -1
  256. package/src/resources/extensions/subagent/worker-registry.ts +2 -1
  257. package/dist/web/standalone/.next/static/chunks/4024.87fd909ae0110f50.js +0 -9
  258. package/dist/web/standalone/.next/static/chunks/app/page-fbecd1237e2d6d1f.js +0 -1
  259. package/dist/web/standalone/.next/static/chunks/main-app-d3d4c336195465f9.js +0 -1
  260. package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/global-error-ab5a8926e07ec673.js +0 -1
  261. /package/dist/web/standalone/.next/static/{KixbEdSRlU9zzYdZdrJ7A → ZQGF6SPE1F4YPUZu1vXqt}/_buildManifest.js +0 -0
  262. /package/dist/web/standalone/.next/static/{KixbEdSRlU9zzYdZdrJ7A → ZQGF6SPE1F4YPUZu1vXqt}/_ssgManifest.js +0 -0
package/dist/cli.js CHANGED
@@ -103,19 +103,6 @@ const cliFlags = parseCliArgs(process.argv);
103
103
  const isPrintMode = cliFlags.print || cliFlags.mode !== undefined;
104
104
  // Early resource-skew check — must run before TTY gate so version mismatch
105
105
  // errors surface even in non-TTY environments.
106
- exitIfManagedResourcesAreNewer(agentDir);
107
- // Early TTY check — must come before heavy initialization to avoid dangling
108
- // handles that prevent process.exit() from completing promptly.
109
- const hasSubcommand = cliFlags.messages.length > 0;
110
- if (!process.stdin.isTTY && !isPrintMode && !hasSubcommand && !cliFlags.listModels && !cliFlags.web) {
111
- process.stderr.write('[gsd] Error: Interactive mode requires a terminal (TTY).\n');
112
- process.stderr.write('[gsd] Non-interactive alternatives:\n');
113
- process.stderr.write('[gsd] gsd --print "your message" Single-shot prompt\n');
114
- process.stderr.write('[gsd] gsd --mode rpc JSON-RPC over stdin/stdout\n');
115
- process.stderr.write('[gsd] gsd --mode mcp MCP server over stdin/stdout\n');
116
- process.stderr.write('[gsd] gsd --mode text "message" Text output mode\n');
117
- process.exit(1);
118
- }
119
106
  async function ensureRtkBootstrap() {
120
107
  if (ensureRtkBootstrap._done)
121
108
  return;
@@ -136,6 +123,25 @@ async function ensureRtkBootstrap() {
136
123
  process.stderr.write(`[gsd] Warning: RTK unavailable — continuing without shell-command compression (${rtkStatus.reason}).\n`);
137
124
  }
138
125
  }
126
+ // `gsd update` — update to the latest version via npm
127
+ if (cliFlags.messages[0] === 'update') {
128
+ const { runUpdate } = await import('./update-cmd.js');
129
+ await runUpdate();
130
+ process.exit(0);
131
+ }
132
+ exitIfManagedResourcesAreNewer(agentDir);
133
+ // Early TTY check — must come before heavy initialization to avoid dangling
134
+ // handles that prevent process.exit() from completing promptly.
135
+ const hasSubcommand = cliFlags.messages.length > 0;
136
+ if (!process.stdin.isTTY && !isPrintMode && !hasSubcommand && !cliFlags.listModels && !cliFlags.web) {
137
+ process.stderr.write('[gsd] Error: Interactive mode requires a terminal (TTY).\n');
138
+ process.stderr.write('[gsd] Non-interactive alternatives:\n');
139
+ process.stderr.write('[gsd] gsd --print "your message" Single-shot prompt\n');
140
+ process.stderr.write('[gsd] gsd --mode rpc JSON-RPC over stdin/stdout\n');
141
+ process.stderr.write('[gsd] gsd --mode mcp MCP server over stdin/stdout\n');
142
+ process.stderr.write('[gsd] gsd --mode text "message" Text output mode\n');
143
+ process.exit(1);
144
+ }
139
145
  // `gsd <subcommand> --help` — show subcommand-specific help
140
146
  const subcommand = cliFlags.messages[0];
141
147
  if (subcommand && process.argv.includes('--help')) {
@@ -162,12 +168,6 @@ if (cliFlags.messages[0] === 'config') {
162
168
  await runOnboarding(authStorage);
163
169
  process.exit(0);
164
170
  }
165
- // `gsd update` — update to the latest version via npm
166
- if (cliFlags.messages[0] === 'update') {
167
- const { runUpdate } = await import('./update-cmd.js');
168
- await runUpdate();
169
- process.exit(0);
170
- }
171
171
  // `gsd web stop [path|all]` — stop web server before anything else
172
172
  if (cliFlags.messages[0] === 'web' && cliFlags.messages[1] === 'stop') {
173
173
  const webFlags = parseWebCliArgs(process.argv);
@@ -18,6 +18,32 @@ interface ExtensionUIRequest {
18
18
  [key: string]: unknown;
19
19
  }
20
20
  export type { ExtensionUIRequest };
21
+ /** Context passed alongside an event for richer formatting. */
22
+ export interface ProgressContext {
23
+ verbose: boolean;
24
+ toolDuration?: number;
25
+ lastCost?: {
26
+ costUsd: number;
27
+ inputTokens: number;
28
+ outputTokens: number;
29
+ };
30
+ thinkingPreview?: string;
31
+ isError?: boolean;
32
+ }
33
+ /**
34
+ * Produce a short human-readable summary of tool arguments.
35
+ * Returns a string like "path/to/file.ts" or "grep pattern *.ts" — never the
36
+ * full JSON blob.
37
+ */
38
+ export declare function summarizeToolArgs(toolName: unknown, toolInput: unknown): string;
21
39
  export declare function handleExtensionUIRequest(event: ExtensionUIRequest, client: RpcClient): void;
22
- export declare function formatProgress(event: Record<string, unknown>, verbose: boolean): string | null;
40
+ export declare function formatProgress(event: Record<string, unknown>, ctx: ProgressContext): string | null;
41
+ /**
42
+ * Format a thinking preview line from accumulated LLM text deltas.
43
+ */
44
+ export declare function formatThinkingLine(text: string): string;
45
+ /**
46
+ * Format a cost line (used for periodic cost updates in verbose mode).
47
+ */
48
+ export declare function formatCostLine(costUsd: number, inputTokens: number, outputTokens: number): string;
23
49
  export declare function startSupervisedStdinReader(client: RpcClient, onResponse: (id: string) => void): () => void;
@@ -7,6 +7,101 @@
7
7
  */
8
8
  import { attachJsonlLineReader } from '@gsd/pi-coding-agent';
9
9
  // ---------------------------------------------------------------------------
10
+ // ANSI Color Helpers
11
+ // ---------------------------------------------------------------------------
12
+ const _c = {
13
+ reset: '\x1b[0m',
14
+ bold: '\x1b[1m',
15
+ dim: '\x1b[2m',
16
+ italic: '\x1b[3m',
17
+ red: '\x1b[31m',
18
+ green: '\x1b[32m',
19
+ yellow: '\x1b[33m',
20
+ cyan: '\x1b[36m',
21
+ gray: '\x1b[90m',
22
+ };
23
+ /** Build a no-op color map (all codes empty). */
24
+ function noColor() {
25
+ const nc = {};
26
+ for (const k of Object.keys(_c))
27
+ nc[k] = '';
28
+ return nc;
29
+ }
30
+ const colorsDisabled = !!process.env['NO_COLOR'] || !process.stderr.isTTY;
31
+ const c = colorsDisabled ? noColor() : _c;
32
+ // ---------------------------------------------------------------------------
33
+ // Tool-Arg Summarizer
34
+ // ---------------------------------------------------------------------------
35
+ /**
36
+ * Produce a short human-readable summary of tool arguments.
37
+ * Returns a string like "path/to/file.ts" or "grep pattern *.ts" — never the
38
+ * full JSON blob.
39
+ */
40
+ export function summarizeToolArgs(toolName, toolInput) {
41
+ const name = String(toolName ?? '');
42
+ const input = (toolInput && typeof toolInput === 'object') ? toolInput : {};
43
+ switch (name) {
44
+ case 'Read':
45
+ case 'read':
46
+ return shortPath(input.file_path) || '';
47
+ case 'Write':
48
+ case 'write':
49
+ return shortPath(input.file_path) || '';
50
+ case 'Edit':
51
+ case 'edit':
52
+ return shortPath(input.file_path) || '';
53
+ case 'Bash':
54
+ case 'bash': {
55
+ const cmd = String(input.command ?? '');
56
+ return cmd.length > 80 ? cmd.slice(0, 77) + '...' : cmd;
57
+ }
58
+ case 'Glob':
59
+ case 'glob':
60
+ return String(input.pattern ?? '');
61
+ case 'Grep':
62
+ case 'grep':
63
+ case 'Search':
64
+ case 'search': {
65
+ const pat = String(input.pattern ?? '');
66
+ const g = input.glob ? ` ${input.glob}` : '';
67
+ return `${pat}${g}`;
68
+ }
69
+ case 'Task':
70
+ case 'task': {
71
+ const desc = String(input.description ?? input.prompt ?? '');
72
+ return desc.length > 60 ? desc.slice(0, 57) + '...' : desc;
73
+ }
74
+ default: {
75
+ // Fallback: show first string-valued key up to 60 chars
76
+ for (const v of Object.values(input)) {
77
+ if (typeof v === 'string' && v.length > 0) {
78
+ return v.length > 60 ? v.slice(0, 57) + '...' : v;
79
+ }
80
+ }
81
+ return '';
82
+ }
83
+ }
84
+ }
85
+ function shortPath(p) {
86
+ if (typeof p !== 'string')
87
+ return '';
88
+ // Strip common CWD prefix to save space
89
+ const cwd = process.cwd();
90
+ if (p.startsWith(cwd + '/'))
91
+ return p.slice(cwd.length + 1);
92
+ // Strip /Users/*/Developer/ prefix
93
+ return p.replace(/^\/Users\/[^/]+\/Developer\//, '');
94
+ }
95
+ // ---------------------------------------------------------------------------
96
+ // Format Duration
97
+ // ---------------------------------------------------------------------------
98
+ function formatDuration(ms) {
99
+ if (ms < 1000)
100
+ return `${ms}ms`;
101
+ const s = (ms / 1000).toFixed(1);
102
+ return `${s}s`;
103
+ }
104
+ // ---------------------------------------------------------------------------
10
105
  // Extension UI Auto-Responder
11
106
  // ---------------------------------------------------------------------------
12
107
  export function handleExtensionUIRequest(event, client) {
@@ -50,29 +145,124 @@ export function handleExtensionUIRequest(event, client) {
50
145
  // ---------------------------------------------------------------------------
51
146
  // Progress Formatter
52
147
  // ---------------------------------------------------------------------------
53
- export function formatProgress(event, verbose) {
148
+ export function formatProgress(event, ctx) {
54
149
  const type = String(event.type ?? '');
150
+ // Emit accumulated thinking preview before tool calls
151
+ if (ctx.thinkingPreview) {
152
+ // thinkingPreview is handled by the caller in headless.ts — it prepends
153
+ // the thinking line before the current event's line. We return the thinking
154
+ // line as a prefix joined with newline.
155
+ }
55
156
  switch (type) {
56
- case 'tool_execution_start':
57
- if (verbose)
58
- return ` [tool] ${event.toolName ?? 'unknown'}`;
59
- return null;
157
+ case 'tool_execution_start': {
158
+ if (!ctx.verbose)
159
+ return null;
160
+ const name = String(event.toolName ?? 'unknown');
161
+ const args = summarizeToolArgs(event.toolName, event.args);
162
+ const argStr = args ? ` ${c.dim}${args}${c.reset}` : '';
163
+ return ` ${c.dim}[tool]${c.reset} ${name}${argStr}`;
164
+ }
165
+ case 'tool_execution_end': {
166
+ if (!ctx.verbose)
167
+ return null;
168
+ const name = String(event.toolName ?? 'unknown');
169
+ const durationStr = ctx.toolDuration != null ? ` ${c.dim}${formatDuration(ctx.toolDuration)}${c.reset}` : '';
170
+ if (ctx.isError) {
171
+ return ` ${c.red}[tool] ${name} error${c.reset}${durationStr}`;
172
+ }
173
+ return ` ${c.dim}[tool] ${name} done${c.reset}${durationStr}`;
174
+ }
60
175
  case 'agent_start':
61
- return '[agent] Session started';
62
- case 'agent_end':
63
- return '[agent] Session ended';
64
- case 'extension_ui_request':
65
- if (event.method === 'notify') {
66
- return `[gsd] ${event.message ?? ''}`;
176
+ return `${c.dim}[agent] Session started${c.reset}`;
177
+ case 'agent_end': {
178
+ let line = `${c.dim}[agent] Session ended${c.reset}`;
179
+ if (ctx.lastCost) {
180
+ const cost = `$${ctx.lastCost.costUsd.toFixed(4)}`;
181
+ const tokens = `${ctx.lastCost.inputTokens + ctx.lastCost.outputTokens} tokens`;
182
+ line += ` ${c.dim}(${cost}, ${tokens})${c.reset}`;
67
183
  }
68
- if (event.method === 'setStatus') {
69
- return `[status] ${event.message ?? ''}`;
184
+ return line;
185
+ }
186
+ case 'extension_ui_request': {
187
+ const method = String(event.method ?? '');
188
+ if (method === 'notify') {
189
+ const msg = String(event.message ?? '');
190
+ if (!msg)
191
+ return null;
192
+ // Bold important notifications
193
+ const isImportant = /^(committed:|verification gate:|milestone|blocked:)/i.test(msg);
194
+ return isImportant
195
+ ? `${c.bold}[gsd] ${msg}${c.reset}`
196
+ : `[gsd] ${msg}`;
197
+ }
198
+ if (method === 'setStatus') {
199
+ // Parse statusKey for phase transitions
200
+ const statusKey = String(event.statusKey ?? '');
201
+ const msg = String(event.message ?? '');
202
+ if (!statusKey && !msg)
203
+ return null; // suppress empty status lines
204
+ // Show meaningful phase transitions
205
+ if (statusKey) {
206
+ const label = parsePhaseLabel(statusKey, msg);
207
+ if (label)
208
+ return `${c.cyan}[phase] ${label}${c.reset}`;
209
+ }
210
+ // Fallback: show message if non-empty
211
+ if (msg)
212
+ return `${c.cyan}[phase] ${msg}${c.reset}`;
213
+ return null;
70
214
  }
71
215
  return null;
216
+ }
72
217
  default:
73
218
  return null;
74
219
  }
75
220
  }
221
+ /**
222
+ * Format a thinking preview line from accumulated LLM text deltas.
223
+ */
224
+ export function formatThinkingLine(text) {
225
+ const trimmed = text.replace(/\s+/g, ' ').trim();
226
+ const truncated = trimmed.length > 120 ? trimmed.slice(0, 117) + '...' : trimmed;
227
+ return `${c.dim}${c.italic}[thinking] ${truncated}${c.reset}`;
228
+ }
229
+ /**
230
+ * Format a cost line (used for periodic cost updates in verbose mode).
231
+ */
232
+ export function formatCostLine(costUsd, inputTokens, outputTokens) {
233
+ return `${c.dim}[cost] $${costUsd.toFixed(4)} (${inputTokens + outputTokens} tokens)${c.reset}`;
234
+ }
235
+ // ---------------------------------------------------------------------------
236
+ // Phase Label Parser
237
+ // ---------------------------------------------------------------------------
238
+ /**
239
+ * Parse a statusKey into a human-readable phase label.
240
+ * statusKey format varies but common patterns:
241
+ * "milestone:M1", "slice:S1.1", "task:T1.1.1", "phase:discuss", etc.
242
+ */
243
+ function parsePhaseLabel(statusKey, message) {
244
+ // Direct phase/milestone/slice/task keys
245
+ const parts = statusKey.split(':');
246
+ if (parts.length >= 2) {
247
+ const [kind, value] = parts;
248
+ switch (kind.toLowerCase()) {
249
+ case 'milestone':
250
+ return `Milestone ${value}${message ? ' -- ' + message : ''}`;
251
+ case 'slice':
252
+ return `Slice ${value}${message ? ' -- ' + message : ''}`;
253
+ case 'task':
254
+ return `Task ${value}${message ? ' -- ' + message : ''}`;
255
+ case 'phase':
256
+ return `Phase: ${value}${message ? ' -- ' + message : ''}`;
257
+ default:
258
+ return `${kind}: ${value}${message ? ' -- ' + message : ''}`;
259
+ }
260
+ }
261
+ // Single-word status keys with a message
262
+ if (message)
263
+ return `${statusKey}: ${message}`;
264
+ return statusKey || null;
265
+ }
76
266
  // ---------------------------------------------------------------------------
77
267
  // Supervised Stdin Reader
78
268
  // ---------------------------------------------------------------------------
package/dist/headless.js CHANGED
@@ -19,7 +19,7 @@ import { getProjectSessionsDir } from './project-sessions.js';
19
19
  import { loadAndValidateAnswerFile, AnswerInjector } from './headless-answers.js';
20
20
  import { isTerminalNotification, isBlockedNotification, isMilestoneReadyNotification, isQuickCommand, FIRE_AND_FORGET_METHODS, IDLE_TIMEOUT_MS, NEW_MILESTONE_IDLE_TIMEOUT_MS, EXIT_SUCCESS, EXIT_ERROR, EXIT_BLOCKED, EXIT_CANCELLED, mapStatusToExitCode, } from './headless-events.js';
21
21
  import { VALID_OUTPUT_FORMATS } from './headless-types.js';
22
- import { handleExtensionUIRequest, formatProgress, startSupervisedStdinReader, } from './headless-ui.js';
22
+ import { handleExtensionUIRequest, formatProgress, formatThinkingLine, startSupervisedStdinReader, } from './headless-ui.js';
23
23
  import { loadContext, bootstrapGsdProject, } from './headless-context.js';
24
24
  /**
25
25
  * Resolve a session prefix to a single session.
@@ -266,6 +266,8 @@ async function runHeadlessOnce(options, restartCount) {
266
266
  if (injector) {
267
267
  clientOptions.env = injector.getSecretEnvVars();
268
268
  }
269
+ // Signal headless mode to the GSD extension (skips UAT human pause, etc.)
270
+ clientOptions.env = { ...(clientOptions.env || {}), GSD_HEADLESS: '1' };
269
271
  // Propagate --bare to the child process
270
272
  if (options.bare) {
271
273
  clientOptions.args = [...(clientOptions.args || []), '--bare'];
@@ -286,6 +288,10 @@ async function runHeadlessOnce(options, restartCount) {
286
288
  let cumulativeCacheReadTokens = 0;
287
289
  let cumulativeCacheWriteTokens = 0;
288
290
  let lastSessionId;
291
+ // Verbose text-mode state
292
+ const toolStartTimes = new Map();
293
+ let lastCostData;
294
+ let thinkingBuffer = '';
289
295
  // Emit HeadlessJsonResult to stdout for --output-format json batch mode
290
296
  function emitBatchJsonResult() {
291
297
  if (options.outputFormat !== 'json')
@@ -410,8 +416,59 @@ async function runHeadlessOnce(options, restartCount) {
410
416
  }
411
417
  }
412
418
  else if (!options.json) {
413
- // Progress output to stderr
414
- const line = formatProgress(eventObj, !!options.verbose);
419
+ // Progress output to stderr with verbose state tracking
420
+ const eventType = String(eventObj.type ?? '');
421
+ // Track cost_update events for agent_end summary
422
+ if (eventType === 'cost_update') {
423
+ const data = eventObj;
424
+ const cumCost = data.cumulativeCost;
425
+ if (cumCost) {
426
+ const tokens = data.tokens;
427
+ lastCostData = {
428
+ costUsd: Number(cumCost.costUsd ?? 0),
429
+ inputTokens: tokens?.input ?? 0,
430
+ outputTokens: tokens?.output ?? 0,
431
+ };
432
+ }
433
+ }
434
+ // Accumulate thinking text from message_update text_delta events
435
+ if (eventType === 'message_update') {
436
+ const ame = eventObj.assistantMessageEvent;
437
+ if (ame?.type === 'text_delta') {
438
+ thinkingBuffer += String(ame.text ?? '');
439
+ }
440
+ }
441
+ // Track tool execution start timestamps
442
+ if (eventType === 'tool_execution_start') {
443
+ const toolCallId = String(eventObj.toolCallId ?? eventObj.id ?? '');
444
+ if (toolCallId)
445
+ toolStartTimes.set(toolCallId, Date.now());
446
+ }
447
+ // Flush thinking buffer before tool calls or message end
448
+ if (options.verbose && thinkingBuffer.trim() &&
449
+ (eventType === 'tool_execution_start' || eventType === 'message_end')) {
450
+ process.stderr.write(formatThinkingLine(thinkingBuffer) + '\n');
451
+ thinkingBuffer = '';
452
+ }
453
+ // Compute tool duration for tool_execution_end
454
+ let toolDuration;
455
+ let isToolError = false;
456
+ if (eventType === 'tool_execution_end') {
457
+ const toolCallId = String(eventObj.toolCallId ?? eventObj.id ?? '');
458
+ const startTime = toolStartTimes.get(toolCallId);
459
+ if (startTime) {
460
+ toolDuration = Date.now() - startTime;
461
+ toolStartTimes.delete(toolCallId);
462
+ }
463
+ isToolError = eventObj.isError === true || eventObj.error != null;
464
+ }
465
+ const ctx = {
466
+ verbose: !!options.verbose,
467
+ toolDuration,
468
+ isError: isToolError,
469
+ lastCost: eventType === 'agent_end' ? lastCostData : undefined,
470
+ };
471
+ const line = formatProgress(eventObj, ctx);
415
472
  if (line)
416
473
  process.stderr.write(line + '\n');
417
474
  }
@@ -4,7 +4,7 @@
4
4
  */
5
5
  import { truncateToWidth, visibleWidth, } from "@gsd/pi-tui";
6
6
  import { processes, pendingAlerts, cleanupAll, cleanupSessionProcesses, persistManifest, loadManifest, pruneDeadProcesses, } from "./process-manager.js";
7
- import { formatUptime, resolveBgShellPersistenceCwd } from "./utilities.js";
7
+ import { formatUptime, getBgShellLiveCwd, resolveBgShellPersistenceCwd } from "./utilities.js";
8
8
  import { formatTokenCount } from "../shared/format-utils.js";
9
9
  export function registerBgShellLifecycle(pi, state) {
10
10
  function syncLatestCtxCwd() {
@@ -161,7 +161,7 @@ export function registerBgShellLifecycle(pi, state) {
161
161
  return {
162
162
  render(width) {
163
163
  // ── Line 1: pwd (branch) [session] ... bg status ──
164
- let pwd = process.cwd();
164
+ let pwd = getBgShellLiveCwd(state.latestCtx?.cwd);
165
165
  const home = process.env.HOME || process.env.USERPROFILE;
166
166
  if (home && pwd.startsWith(home)) {
167
167
  pwd = `~${pwd.slice(home.length)}`;
@@ -36,15 +36,44 @@ export const formatUptime = formatDuration;
36
36
  export function formatTimeAgo(timestamp) {
37
37
  return formatDuration(Date.now() - timestamp) + " ago";
38
38
  }
39
- export function resolveBgShellPersistenceCwd(cachedCwd, liveCwd = process.cwd(), pathExists = existsSync) {
39
+ function deriveProjectRootFromAutoWorktree(cachedCwd) {
40
+ if (!cachedCwd)
41
+ return undefined;
42
+ const match = cachedCwd.match(/^(.*?)[\\/]\.gsd[\\/]worktrees[\\/][^\\/]+(?:[\\/].*)?$/);
43
+ return match?.[1];
44
+ }
45
+ export function getBgShellLiveCwd(cachedCwd, pathExists = existsSync, getCwd = () => process.cwd(), chdir = (path) => process.chdir(path)) {
46
+ try {
47
+ return getCwd();
48
+ }
49
+ catch {
50
+ const projectRoot = deriveProjectRootFromAutoWorktree(cachedCwd);
51
+ const home = process.env.HOME || process.env.USERPROFILE;
52
+ const fallbacks = [projectRoot, cachedCwd, home, "/"].filter((candidate) => Boolean(candidate));
53
+ for (const candidate of fallbacks) {
54
+ if (candidate !== "/" && !pathExists(candidate))
55
+ continue;
56
+ try {
57
+ chdir(candidate);
58
+ }
59
+ catch {
60
+ // Best-effort only. Returning a known-good fallback is enough to avoid crashes.
61
+ }
62
+ return candidate;
63
+ }
64
+ return "/";
65
+ }
66
+ }
67
+ export function resolveBgShellPersistenceCwd(cachedCwd, liveCwd = undefined, pathExists = existsSync) {
68
+ const resolvedLiveCwd = liveCwd ?? getBgShellLiveCwd(cachedCwd, pathExists);
40
69
  const cachedIsAutoWorktree = /(?:^|[\\/])\.gsd[\\/]worktrees[\\/]/.test(cachedCwd);
41
70
  if (!cachedIsAutoWorktree)
42
71
  return cachedCwd;
43
- if (cachedCwd === liveCwd && pathExists(cachedCwd))
72
+ if (cachedCwd === resolvedLiveCwd && pathExists(cachedCwd))
44
73
  return cachedCwd;
45
74
  if (!pathExists(cachedCwd))
46
- return liveCwd;
47
- if (liveCwd !== cachedCwd)
48
- return liveCwd;
75
+ return resolvedLiveCwd;
76
+ if (resolvedLiveCwd !== cachedCwd)
77
+ return resolvedLiveCwd;
49
78
  return cachedCwd;
50
79
  }
@@ -29,6 +29,14 @@ import { writeUnitRuntimeRecord } from "../unit-runtime.js";
29
29
  export function _resolveReportBasePath(s) {
30
30
  return s.originalBasePath || s.basePath;
31
31
  }
32
+ /**
33
+ * Resolve the authoritative project base for dispatch guards.
34
+ * Prior-milestone completion lives at the project root, even when the active
35
+ * unit is running inside an auto worktree.
36
+ */
37
+ export function _resolveDispatchGuardBasePath(s) {
38
+ return s.originalBasePath || s.basePath;
39
+ }
32
40
  /**
33
41
  * Generate and write an HTML milestone report snapshot.
34
42
  * Extracted from the milestone-transition block in autoLoop.
@@ -459,7 +467,8 @@ export async function runDispatch(ic, preData, loopState) {
459
467
  else if (preDispatchResult.prompt) {
460
468
  prompt = preDispatchResult.prompt;
461
469
  }
462
- const priorSliceBlocker = deps.getPriorSliceCompletionBlocker(s.basePath, deps.getMainBranch(s.basePath), unitType, unitId);
470
+ const guardBasePath = _resolveDispatchGuardBasePath(s);
471
+ const priorSliceBlocker = deps.getPriorSliceCompletionBlocker(guardBasePath, deps.getMainBranch(guardBasePath), unitType, unitId);
463
472
  if (priorSliceBlocker) {
464
473
  await deps.stopAuto(ctx, pi, priorSliceBlocker);
465
474
  debugLog("autoLoop", { phase: "exit", reason: "prior-slice-blocker" });
@@ -487,8 +496,15 @@ export async function runGuards(ic, mid) {
487
496
  const budgetCeiling = prefs?.budget_ceiling;
488
497
  if (budgetCeiling !== undefined && budgetCeiling > 0) {
489
498
  const currentLedger = deps.getLedger();
490
- const totalCost = currentLedger
491
- ? deps.getProjectTotals(currentLedger.units).cost
499
+ // In parallel worker mode, only count cost from the current auto-mode session
500
+ // to avoid hitting the ceiling due to historical project-wide spend (#2184).
501
+ let costUnits = currentLedger?.units;
502
+ if (process.env.GSD_PARALLEL_WORKER && s.autoStartTime && Array.isArray(costUnits)) {
503
+ const sessionStartISO = new Date(s.autoStartTime).toISOString();
504
+ costUnits = costUnits.filter((u) => u.startedAt != null && u.startedAt >= sessionStartISO);
505
+ }
506
+ const totalCost = costUnits
507
+ ? deps.getProjectTotals(costUnits).cost
492
508
  : 0;
493
509
  const budgetPct = totalCost / budgetCeiling;
494
510
  const budgetAlertLevel = deps.getBudgetAlertLevel(budgetPct);
@@ -115,7 +115,7 @@ export const DISPATCH_RULES = [
115
115
  unitType: "run-uat",
116
116
  unitId: `${mid}/${sliceId}`,
117
117
  prompt: await buildRunUatPrompt(mid, sliceId, relSliceFile(basePath, mid, sliceId, "UAT"), uatContent ?? "", basePath),
118
- pauseAfterDispatch: uatType !== "artifact-driven" && uatType !== "browser-executable" && uatType !== "runtime-executable",
118
+ pauseAfterDispatch: !process.env.GSD_HEADLESS && uatType !== "artifact-driven" && uatType !== "browser-executable" && uatType !== "runtime-executable",
119
119
  };
120
120
  },
121
121
  },
@@ -8,6 +8,22 @@ import { classifyUnitComplexity, tierLabel } from "./complexity-classifier.js";
8
8
  import { resolveModelForComplexity, escalateTier } from "./model-router.js";
9
9
  import { getLedger, getProjectTotals } from "./metrics.js";
10
10
  import { unitPhaseLabel } from "./auto-dashboard.js";
11
+ export function resolvePreferredModelConfig(unitType, autoModeStartModel) {
12
+ const explicitConfig = resolveModelWithFallbacksForUnit(unitType);
13
+ if (explicitConfig)
14
+ return explicitConfig;
15
+ const routingConfig = resolveDynamicRoutingConfig();
16
+ if (!routingConfig.enabled || !routingConfig.tier_models)
17
+ return undefined;
18
+ const ceilingModel = routingConfig.tier_models.heavy
19
+ ?? (autoModeStartModel ? `${autoModeStartModel.provider}/${autoModeStartModel.id}` : undefined);
20
+ if (!ceilingModel)
21
+ return undefined;
22
+ return {
23
+ primary: ceilingModel,
24
+ fallbacks: [],
25
+ };
26
+ }
11
27
  /**
12
28
  * Select and apply the appropriate model for a unit dispatch.
13
29
  * Handles: per-unit-type model preferences, dynamic complexity routing,
@@ -16,7 +32,7 @@ import { unitPhaseLabel } from "./auto-dashboard.js";
16
32
  * Returns routing metadata for metrics tracking.
17
33
  */
18
34
  export async function selectAndApplyModel(ctx, pi, unitType, unitId, basePath, prefs, verbose, autoModeStartModel, retryContext) {
19
- const modelConfig = resolveModelWithFallbacksForUnit(unitType);
35
+ const modelConfig = resolvePreferredModelConfig(unitType, autoModeStartModel);
20
36
  let routing = null;
21
37
  if (modelConfig) {
22
38
  const availableModels = ctx.modelRegistry.getAvailable();
@@ -66,6 +66,10 @@ function buildSourceFilePaths(base, mid, sid) {
66
66
  if (existsSync(decisionsPath)) {
67
67
  paths.push(`- **Decisions**: \`${relGsdRootFile("DECISIONS")}\``);
68
68
  }
69
+ const queuePath = resolveGsdRootFile(base, "QUEUE");
70
+ if (existsSync(queuePath)) {
71
+ paths.push(`- **Queue**: \`${relGsdRootFile("QUEUE")}\``);
72
+ }
69
73
  const contextPath = resolveMilestoneFile(base, mid, "CONTEXT");
70
74
  if (contextPath) {
71
75
  paths.push(`- **Milestone Context**: \`${relMilestoneFile(base, mid, "CONTEXT")}\``);
@@ -812,6 +816,11 @@ export async function buildPlanMilestonePrompt(mid, midTitle, base, level) {
812
816
  if (decisionsInline)
813
817
  inlined.push(decisionsInline);
814
818
  }
819
+ const queuePath = resolveGsdRootFile(base, "QUEUE");
820
+ if (existsSync(queuePath)) {
821
+ const queueInline = await inlineFileSmart(queuePath, relGsdRootFile("QUEUE"), "Project Queue", `${mid} ${midTitle}`);
822
+ inlined.push(queueInline);
823
+ }
815
824
  const knowledgeInlinePM = await inlineGsdRootFile(base, "knowledge.md", "Project Knowledge");
816
825
  if (knowledgeInlinePM)
817
826
  inlined.push(knowledgeInlinePM);
@@ -64,6 +64,14 @@ export async function bootstrapAutoSession(s, ctx, pi, base, verboseMode, reques
64
64
  clearLock(base);
65
65
  return false;
66
66
  }
67
+ // Capture the user's session model before guided-flow dispatch can apply a
68
+ // phase-specific planning model for a discuss turn (#2829).
69
+ const startModelSnapshot = ctx.model
70
+ ? {
71
+ provider: ctx.model.provider,
72
+ id: ctx.model.id,
73
+ }
74
+ : null;
67
75
  try {
68
76
  // Validate GSD_PROJECT_ID early so the user gets immediate feedback
69
77
  const customProjectId = process.env.GSD_PROJECT_ID;
@@ -410,12 +418,11 @@ export async function bootstrapAutoSession(s, ctx, pi, base, verboseMode, reques
410
418
  initMetrics(s.basePath);
411
419
  // Initialize routing history
412
420
  initRoutingHistory(s.basePath);
413
- // Capture session's model at auto-mode start (#650)
414
- const currentModel = ctx.model;
415
- if (currentModel) {
421
+ // Restore the model that was active when auto bootstrap began (#650, #2829).
422
+ if (startModelSnapshot) {
416
423
  s.autoModeStartModel = {
417
- provider: currentModel.provider,
418
- id: currentModel.id,
424
+ provider: startModelSnapshot.provider,
425
+ id: startModelSnapshot.id,
419
426
  };
420
427
  }
421
428
  // Snapshot installed skills