gsd-pi 2.54.0 → 2.55.0-dev.9ec7cdf

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 +15 -15
  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 +15 -15
  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 → k92jvAf8IfV4dZE3nnrAr}/_buildManifest.js +0 -0
  262. /package/dist/web/standalone/.next/static/{KixbEdSRlU9zzYdZdrJ7A → k92jvAf8IfV4dZE3nnrAr}/_ssgManifest.js +0 -0
@@ -22,7 +22,7 @@ import {
22
22
  loadManifest,
23
23
  pruneDeadProcesses,
24
24
  } from "./process-manager.js";
25
- import { formatUptime, resolveBgShellPersistenceCwd } from "./utilities.js";
25
+ import { formatUptime, getBgShellLiveCwd, resolveBgShellPersistenceCwd } from "./utilities.js";
26
26
  import { formatTokenCount } from "../shared/format-utils.js";
27
27
 
28
28
  import type { BgShellSharedState } from "./index.js";
@@ -213,7 +213,7 @@ export function registerBgShellLifecycle(pi: ExtensionAPI, state: BgShellSharedS
213
213
  return {
214
214
  render(width: number): string[] {
215
215
  // ── Line 1: pwd (branch) [session] ... bg status ──
216
- let pwd = process.cwd();
216
+ let pwd = getBgShellLiveCwd(state.latestCtx?.cwd);
217
217
  const home = process.env.HOME || process.env.USERPROFILE;
218
218
  if (home && pwd.startsWith(home)) {
219
219
  pwd = `~${pwd.slice(home.length)}`;
@@ -42,16 +42,51 @@ export function formatTimeAgo(timestamp: number): string {
42
42
  return formatDuration(Date.now() - timestamp) + " ago";
43
43
  }
44
44
 
45
+ function deriveProjectRootFromAutoWorktree(cachedCwd?: string): string | undefined {
46
+ if (!cachedCwd) return undefined;
47
+ const match = cachedCwd.match(/^(.*?)[\\/]\.gsd[\\/]worktrees[\\/][^\\/]+(?:[\\/].*)?$/);
48
+ return match?.[1];
49
+ }
50
+
51
+ export function getBgShellLiveCwd(
52
+ cachedCwd?: string,
53
+ pathExists: (path: string) => boolean = existsSync,
54
+ getCwd: () => string = () => process.cwd(),
55
+ chdir: (path: string) => void = (path) => process.chdir(path),
56
+ ): string {
57
+ try {
58
+ return getCwd();
59
+ } catch {
60
+ const projectRoot = deriveProjectRootFromAutoWorktree(cachedCwd);
61
+ const home = process.env.HOME || process.env.USERPROFILE;
62
+ const fallbacks = [projectRoot, cachedCwd, home, "/"].filter(
63
+ (candidate): candidate is string => Boolean(candidate),
64
+ );
65
+
66
+ for (const candidate of fallbacks) {
67
+ if (candidate !== "/" && !pathExists(candidate)) continue;
68
+ try {
69
+ chdir(candidate);
70
+ } catch {
71
+ // Best-effort only. Returning a known-good fallback is enough to avoid crashes.
72
+ }
73
+ return candidate;
74
+ }
75
+
76
+ return "/";
77
+ }
78
+ }
45
79
 
46
80
  export function resolveBgShellPersistenceCwd(
47
81
  cachedCwd: string,
48
- liveCwd = process.cwd(),
82
+ liveCwd: string | undefined = undefined,
49
83
  pathExists: (path: string) => boolean = existsSync,
50
84
  ): string {
85
+ const resolvedLiveCwd = liveCwd ?? getBgShellLiveCwd(cachedCwd, pathExists);
51
86
  const cachedIsAutoWorktree = /(?:^|[\\/])\.gsd[\\/]worktrees[\\/]/.test(cachedCwd);
52
87
  if (!cachedIsAutoWorktree) return cachedCwd;
53
- if (cachedCwd === liveCwd && pathExists(cachedCwd)) return cachedCwd;
54
- if (!pathExists(cachedCwd)) return liveCwd;
55
- if (liveCwd !== cachedCwd) return liveCwd;
88
+ if (cachedCwd === resolvedLiveCwd && pathExists(cachedCwd)) return cachedCwd;
89
+ if (!pathExists(cachedCwd)) return resolvedLiveCwd;
90
+ if (resolvedLiveCwd !== cachedCwd) return resolvedLiveCwd;
56
91
  return cachedCwd;
57
92
  }
@@ -45,6 +45,17 @@ export function _resolveReportBasePath(s: Pick<AutoSession, "originalBasePath" |
45
45
  return s.originalBasePath || s.basePath;
46
46
  }
47
47
 
48
+ /**
49
+ * Resolve the authoritative project base for dispatch guards.
50
+ * Prior-milestone completion lives at the project root, even when the active
51
+ * unit is running inside an auto worktree.
52
+ */
53
+ export function _resolveDispatchGuardBasePath(
54
+ s: Pick<AutoSession, "originalBasePath" | "basePath">,
55
+ ): string {
56
+ return s.originalBasePath || s.basePath;
57
+ }
58
+
48
59
  /**
49
60
  * Generate and write an HTML milestone report snapshot.
50
61
  * Extracted from the milestone-transition block in autoLoop.
@@ -667,9 +678,10 @@ export async function runDispatch(
667
678
  prompt = preDispatchResult.prompt;
668
679
  }
669
680
 
681
+ const guardBasePath = _resolveDispatchGuardBasePath(s);
670
682
  const priorSliceBlocker = deps.getPriorSliceCompletionBlocker(
671
- s.basePath,
672
- deps.getMainBranch(s.basePath),
683
+ guardBasePath,
684
+ deps.getMainBranch(guardBasePath),
673
685
  unitType,
674
686
  unitId,
675
687
  );
@@ -707,8 +719,17 @@ export async function runGuards(
707
719
  const budgetCeiling = prefs?.budget_ceiling;
708
720
  if (budgetCeiling !== undefined && budgetCeiling > 0) {
709
721
  const currentLedger = deps.getLedger() as { units: unknown } | null;
710
- const totalCost = currentLedger
711
- ? deps.getProjectTotals(currentLedger.units).cost
722
+ // In parallel worker mode, only count cost from the current auto-mode session
723
+ // to avoid hitting the ceiling due to historical project-wide spend (#2184).
724
+ let costUnits = currentLedger?.units;
725
+ if (process.env.GSD_PARALLEL_WORKER && s.autoStartTime && Array.isArray(costUnits)) {
726
+ const sessionStartISO = new Date(s.autoStartTime).toISOString();
727
+ costUnits = costUnits.filter(
728
+ (u: { startedAt?: string }) => u.startedAt != null && u.startedAt >= sessionStartISO,
729
+ );
730
+ }
731
+ const totalCost = costUnits
732
+ ? deps.getProjectTotals(costUnits).cost
712
733
  : 0;
713
734
  const budgetPct = totalCost / budgetCeiling;
714
735
  const budgetAlertLevel = deps.getBudgetAlertLevel(budgetPct);
@@ -200,7 +200,7 @@ export const DISPATCH_RULES: DispatchRule[] = [
200
200
  uatContent ?? "",
201
201
  basePath,
202
202
  ),
203
- pauseAfterDispatch: uatType !== "artifact-driven" && uatType !== "browser-executable" && uatType !== "runtime-executable",
203
+ pauseAfterDispatch: !process.env.GSD_HEADLESS && uatType !== "artifact-driven" && uatType !== "browser-executable" && uatType !== "runtime-executable",
204
204
  };
205
205
  },
206
206
  },
@@ -18,6 +18,26 @@ export interface ModelSelectionResult {
18
18
  routing: { tier: string; modelDowngraded: boolean } | null;
19
19
  }
20
20
 
21
+ export function resolvePreferredModelConfig(
22
+ unitType: string,
23
+ autoModeStartModel: { provider: string; id: string } | null,
24
+ ) {
25
+ const explicitConfig = resolveModelWithFallbacksForUnit(unitType);
26
+ if (explicitConfig) return explicitConfig;
27
+
28
+ const routingConfig = resolveDynamicRoutingConfig();
29
+ if (!routingConfig.enabled || !routingConfig.tier_models) return undefined;
30
+
31
+ const ceilingModel = routingConfig.tier_models.heavy
32
+ ?? (autoModeStartModel ? `${autoModeStartModel.provider}/${autoModeStartModel.id}` : undefined);
33
+ if (!ceilingModel) return undefined;
34
+
35
+ return {
36
+ primary: ceilingModel,
37
+ fallbacks: [],
38
+ };
39
+ }
40
+
21
41
  /**
22
42
  * Select and apply the appropriate model for a unit dispatch.
23
43
  * Handles: per-unit-type model preferences, dynamic complexity routing,
@@ -36,7 +56,7 @@ export async function selectAndApplyModel(
36
56
  autoModeStartModel: { provider: string; id: string } | null,
37
57
  retryContext?: { isRetry: boolean; previousTier?: string },
38
58
  ): Promise<ModelSelectionResult> {
39
- const modelConfig = resolveModelWithFallbacksForUnit(unitType);
59
+ const modelConfig = resolvePreferredModelConfig(unitType, autoModeStartModel);
40
60
  let routing: { tier: string; modelDowngraded: boolean } | null = null;
41
61
 
42
62
  if (modelConfig) {
@@ -87,6 +87,11 @@ function buildSourceFilePaths(
87
87
  paths.push(`- **Decisions**: \`${relGsdRootFile("DECISIONS")}\``);
88
88
  }
89
89
 
90
+ const queuePath = resolveGsdRootFile(base, "QUEUE");
91
+ if (existsSync(queuePath)) {
92
+ paths.push(`- **Queue**: \`${relGsdRootFile("QUEUE")}\``);
93
+ }
94
+
90
95
  const contextPath = resolveMilestoneFile(base, mid, "CONTEXT");
91
96
  if (contextPath) {
92
97
  paths.push(`- **Milestone Context**: \`${relMilestoneFile(base, mid, "CONTEXT")}\``);
@@ -915,6 +920,16 @@ export async function buildPlanMilestonePrompt(mid: string, midTitle: string, ba
915
920
  const decisionsInline = await inlineDecisionsFromDb(base, mid, undefined, inlineLevel);
916
921
  if (decisionsInline) inlined.push(decisionsInline);
917
922
  }
923
+ const queuePath = resolveGsdRootFile(base, "QUEUE");
924
+ if (existsSync(queuePath)) {
925
+ const queueInline = await inlineFileSmart(
926
+ queuePath,
927
+ relGsdRootFile("QUEUE"),
928
+ "Project Queue",
929
+ `${mid} ${midTitle}`,
930
+ );
931
+ inlined.push(queueInline);
932
+ }
918
933
  const knowledgeInlinePM = await inlineGsdRootFile(base, "knowledge.md", "Project Knowledge");
919
934
  if (knowledgeInlinePM) inlined.push(knowledgeInlinePM);
920
935
  inlined.push(inlineTemplate("roadmap", "Roadmap"));
@@ -131,6 +131,15 @@ export async function bootstrapAutoSession(
131
131
  return false;
132
132
  }
133
133
 
134
+ // Capture the user's session model before guided-flow dispatch can apply a
135
+ // phase-specific planning model for a discuss turn (#2829).
136
+ const startModelSnapshot = ctx.model
137
+ ? {
138
+ provider: ctx.model.provider,
139
+ id: ctx.model.id,
140
+ }
141
+ : null;
142
+
134
143
  try {
135
144
  // Validate GSD_PROJECT_ID early so the user gets immediate feedback
136
145
  const customProjectId = process.env.GSD_PROJECT_ID;
@@ -576,12 +585,11 @@ export async function bootstrapAutoSession(
576
585
  // Initialize routing history
577
586
  initRoutingHistory(s.basePath);
578
587
 
579
- // Capture session's model at auto-mode start (#650)
580
- const currentModel = ctx.model;
581
- if (currentModel) {
588
+ // Restore the model that was active when auto bootstrap began (#650, #2829).
589
+ if (startModelSnapshot) {
582
590
  s.autoModeStartModel = {
583
- provider: currentModel.provider,
584
- id: currentModel.id,
591
+ provider: startModelSnapshot.provider,
592
+ id: startModelSnapshot.id,
585
593
  };
586
594
  }
587
595
 
@@ -65,6 +65,8 @@ import {
65
65
  } from "./native-git-bridge.js";
66
66
 
67
67
  const gsdHome = process.env.GSD_HOME || join(homedir(), ".gsd");
68
+ const PROJECT_PREFERENCES_FILE = "PREFERENCES.md";
69
+ const LEGACY_PROJECT_PREFERENCES_FILE = "preferences.md";
68
70
 
69
71
  // ─── Shared Constants & Helpers ─────────────────────────────────────────────
70
72
 
@@ -82,7 +84,7 @@ const ROOT_STATE_FILES = [
82
84
  "QUEUE.md",
83
85
  "completed-units.json",
84
86
  "metrics.json",
85
- // NOTE: preferences.md is intentionally NOT in ROOT_STATE_FILES.
87
+ // NOTE: project preferences are intentionally NOT in ROOT_STATE_FILES.
86
88
  // Forward-sync (main → worktree) is handled explicitly in syncGsdStateToWorktree().
87
89
  // Back-sync (worktree → main) must NEVER overwrite the project root's copy
88
90
  // because the project root is authoritative for preferences (#2684).
@@ -196,6 +198,11 @@ export function syncProjectRootToWorktree(
196
198
  const prGsd = join(projectRoot, ".gsd");
197
199
  const wtGsd = join(worktreePath_, ".gsd");
198
200
 
201
+ // When .gsd is a symlink to the same external directory in both locations,
202
+ // cpSync rejects the copy because source === destination (ERR_FS_CP_EINVAL).
203
+ // Compare realpaths and skip when they resolve to the same physical path (#2184).
204
+ if (isSamePath(prGsd, wtGsd)) return;
205
+
199
206
  // Copy milestone directory from project root to worktree — additive only.
200
207
  // force:false prevents cpSync from overwriting existing worktree files.
201
208
  // Without this, worktree-authoritative files (e.g. VALIDATION.md written
@@ -245,6 +252,11 @@ export function syncStateToProjectRoot(
245
252
  const wtGsd = join(worktreePath_, ".gsd");
246
253
  const prGsd = join(projectRoot, ".gsd");
247
254
 
255
+ // When .gsd is a symlink to the same external directory in both locations,
256
+ // cpSync rejects the copy because source === destination (ERR_FS_CP_EINVAL).
257
+ // Compare realpaths and skip when they resolve to the same physical path (#2184).
258
+ if (isSamePath(wtGsd, prGsd)) return;
259
+
248
260
  // 1. STATE.md — the quick-glance status used by initial deriveState()
249
261
  safeCopy(join(wtGsd, "STATE.md"), join(prGsd, "STATE.md"), { force: true });
250
262
 
@@ -439,18 +451,25 @@ export function syncGsdStateToWorktree(
439
451
  }
440
452
  }
441
453
 
442
- // Forward-sync preferences.md from project root to worktree (additive only).
443
- // NOT in ROOT_STATE_FILES because syncWorktreeStateBack() must never overwrite
444
- // the project root's preferences the project root is authoritative (#2684).
454
+ // Forward-sync project preferences from project root to worktree (additive only).
455
+ // Prefer the canonical uppercase file name, but keep the legacy lowercase
456
+ // fallback so older repos still work on case-sensitive filesystems.
445
457
  {
446
- const src = join(mainGsd, "preferences.md");
447
- const dst = join(wtGsd, "preferences.md");
448
- if (existsSync(src) && !existsSync(dst)) {
449
- try {
450
- cpSync(src, dst);
451
- synced.push("preferences.md");
452
- } catch {
453
- /* non-fatal */
458
+ const worktreeHasPreferences = existsSync(join(wtGsd, PROJECT_PREFERENCES_FILE))
459
+ || existsSync(join(wtGsd, LEGACY_PROJECT_PREFERENCES_FILE));
460
+ if (!worktreeHasPreferences) {
461
+ for (const file of [PROJECT_PREFERENCES_FILE, LEGACY_PROJECT_PREFERENCES_FILE] as const) {
462
+ const src = join(mainGsd, file);
463
+ const dst = join(wtGsd, file);
464
+ if (existsSync(src)) {
465
+ try {
466
+ cpSync(src, dst);
467
+ synced.push(file);
468
+ } catch {
469
+ /* non-fatal */
470
+ }
471
+ break;
472
+ }
454
473
  }
455
474
  }
456
475
  }
@@ -985,11 +1004,25 @@ function copyPlanningArtifacts(srcBase: string, wtPath: string): void {
985
1004
  "STATE.md",
986
1005
  "KNOWLEDGE.md",
987
1006
  "OVERRIDES.md",
988
- "preferences.md",
989
1007
  ]) {
990
1008
  safeCopy(join(srcGsd, file), join(dstGsd, file), { force: true });
991
1009
  }
992
1010
 
1011
+ // Seed canonical PREFERENCES.md when available; fall back to legacy lowercase.
1012
+ if (existsSync(join(srcGsd, PROJECT_PREFERENCES_FILE))) {
1013
+ safeCopy(
1014
+ join(srcGsd, PROJECT_PREFERENCES_FILE),
1015
+ join(dstGsd, PROJECT_PREFERENCES_FILE),
1016
+ { force: true },
1017
+ );
1018
+ } else if (existsSync(join(srcGsd, LEGACY_PROJECT_PREFERENCES_FILE))) {
1019
+ safeCopy(
1020
+ join(srcGsd, LEGACY_PROJECT_PREFERENCES_FILE),
1021
+ join(dstGsd, LEGACY_PROJECT_PREFERENCES_FILE),
1022
+ { force: true },
1023
+ );
1024
+ }
1025
+
993
1026
  // Shared WAL (R012): worktrees use the project root's DB directly.
994
1027
  // No longer copy gsd.db into the worktree — the DB path resolver in
995
1028
  // ensureDbOpen() detects the worktree location and opens the root DB.
@@ -7,6 +7,7 @@ import { pauseAutoForProviderError } from "../provider-error-pause.js";
7
7
  import { isSessionSwitchInFlight, resolveAgentEnd } from "../auto-loop.js";
8
8
  import { resolveModelId } from "../auto-model-selection.js";
9
9
  import { clearDiscussionFlowState } from "./write-gate.js";
10
+ import { resumeAutoAfterProviderDelay } from "./provider-error-resume.js";
10
11
  import {
11
12
  classifyError,
12
13
  createRetryState,
@@ -44,10 +45,10 @@ async function pauseTransientWithBackoff(
44
45
  retryAfterMs,
45
46
  resume: allowAutoResume
46
47
  ? () => {
47
- pi.sendMessage(
48
- { customType: "gsd-auto-timeout-recovery", content: "Continue execution provider error recovery delay elapsed.", display: false },
49
- { triggerTurn: true },
50
- );
48
+ void resumeAutoAfterProviderDelay(pi, ctx).catch((err) => {
49
+ const message = err instanceof Error ? err.message : String(err);
50
+ ctx.ui.notify(`Provider error recovery delay elapsed, but auto-mode failed to resume: ${message}`, "error");
51
+ });
51
52
  }
52
53
  : undefined,
53
54
  });
@@ -0,0 +1,53 @@
1
+ import type {
2
+ ExtensionAPI,
3
+ ExtensionCommandContext,
4
+ ExtensionContext,
5
+ } from "@gsd/pi-coding-agent";
6
+
7
+ import { getAutoDashboardData, startAuto, type AutoDashboardData } from "../auto.js";
8
+
9
+ type AutoResumeSnapshot = Pick<AutoDashboardData, "active" | "paused" | "stepMode" | "basePath">;
10
+
11
+ export interface ProviderErrorResumeDeps {
12
+ getSnapshot(): AutoResumeSnapshot;
13
+ startAuto(
14
+ ctx: ExtensionCommandContext,
15
+ pi: ExtensionAPI,
16
+ base: string,
17
+ verboseMode: boolean,
18
+ options?: { step?: boolean },
19
+ ): Promise<void>;
20
+ }
21
+
22
+ const defaultDeps: ProviderErrorResumeDeps = {
23
+ getSnapshot: () => getAutoDashboardData(),
24
+ startAuto,
25
+ };
26
+
27
+ export async function resumeAutoAfterProviderDelay(
28
+ pi: ExtensionAPI,
29
+ ctx: ExtensionContext,
30
+ deps: ProviderErrorResumeDeps = defaultDeps,
31
+ ): Promise<"resumed" | "already-active" | "not-paused" | "missing-base"> {
32
+ const snapshot = deps.getSnapshot();
33
+
34
+ if (snapshot.active) return "already-active";
35
+ if (!snapshot.paused) return "not-paused";
36
+
37
+ if (!snapshot.basePath) {
38
+ ctx.ui.notify(
39
+ "Provider error recovery delay elapsed, but no paused auto-mode base path was available. Leaving auto-mode paused.",
40
+ "warning",
41
+ );
42
+ return "missing-base";
43
+ }
44
+
45
+ await deps.startAuto(
46
+ ctx as ExtensionCommandContext,
47
+ pi,
48
+ snapshot.basePath,
49
+ false,
50
+ { step: snapshot.stepMode },
51
+ );
52
+ return "resumed";
53
+ }
@@ -9,14 +9,28 @@ import { registerJournalTools } from "./journal-tools.js";
9
9
  import { registerHooks } from "./register-hooks.js";
10
10
  import { registerShortcuts } from "./register-shortcuts.js";
11
11
 
12
+ export function handleRecoverableExtensionProcessError(err: Error): boolean {
13
+ if ((err as NodeJS.ErrnoException).code === "EPIPE") {
14
+ process.exit(0);
15
+ }
16
+ if ((err as NodeJS.ErrnoException).code === "ENOENT") {
17
+ const syscall = (err as NodeJS.ErrnoException).syscall;
18
+ if (syscall?.startsWith("spawn")) {
19
+ process.stderr.write(`[gsd] spawn ENOENT: ${(err as any).path ?? "unknown"} — command not found\n`);
20
+ return true;
21
+ }
22
+ if (syscall === "uv_cwd") {
23
+ process.stderr.write(`[gsd] ENOENT (${syscall}): ${err.message}\n`);
24
+ return true;
25
+ }
26
+ }
27
+ return false;
28
+ }
29
+
12
30
  function installEpipeGuard(): void {
13
31
  if (!process.listeners("uncaughtException").some((listener) => listener.name === "_gsdEpipeGuard")) {
14
32
  const _gsdEpipeGuard = (err: Error): void => {
15
- if ((err as NodeJS.ErrnoException).code === "EPIPE") {
16
- process.exit(0);
17
- }
18
- if ((err as NodeJS.ErrnoException).code === "ENOENT" && (err as any).syscall?.startsWith("spawn")) {
19
- process.stderr.write(`[gsd] spawn ENOENT: ${(err as any).path ?? "unknown"} — command not found\n`);
33
+ if (handleRecoverableExtensionProcessError(err)) {
20
34
  return;
21
35
  }
22
36
  throw err;
@@ -45,4 +59,3 @@ export function registerGsdExtension(pi: ExtensionAPI): void {
45
59
  registerShortcuts(pi);
46
60
  registerHooks(pi);
47
61
  }
48
-
@@ -5,6 +5,7 @@ import type { ExtensionAPI } from "@gsd/pi-coding-agent";
5
5
  import { Key } from "@gsd/pi-tui";
6
6
 
7
7
  import { GSDDashboardOverlay } from "../dashboard-overlay.js";
8
+ import { ParallelMonitorOverlay } from "../parallel-monitor-overlay.js";
8
9
  import { shortcutDesc } from "../../shared/mod.js";
9
10
 
10
11
  export function registerShortcuts(pi: ExtensionAPI): void {
@@ -29,4 +30,27 @@ export function registerShortcuts(pi: ExtensionAPI): void {
29
30
  );
30
31
  },
31
32
  });
33
+
34
+ pi.registerShortcut(Key.ctrlAlt("p"), {
35
+ description: shortcutDesc("Open parallel worker monitor", "/gsd parallel watch"),
36
+ handler: async (ctx) => {
37
+ const parallelDir = join(process.cwd(), ".gsd", "parallel");
38
+ if (!existsSync(parallelDir)) {
39
+ ctx.ui.notify("No parallel workers found. Run /gsd parallel start first.", "info");
40
+ return;
41
+ }
42
+ await ctx.ui.custom<void>(
43
+ (tui, theme, _kb, done) => new ParallelMonitorOverlay(tui, theme, () => done()),
44
+ {
45
+ overlay: true,
46
+ overlayOptions: {
47
+ width: "90%",
48
+ minWidth: 80,
49
+ maxHeight: "92%",
50
+ anchor: "center",
51
+ },
52
+ },
53
+ );
54
+ },
55
+ });
32
56
  }
@@ -59,7 +59,7 @@ export const TOP_LEVEL_SUBCOMMANDS: readonly GsdCommandDefinition[] = [
59
59
  { cmd: "inspect", desc: "Show SQLite DB diagnostics" },
60
60
  { cmd: "knowledge", desc: "Add persistent project knowledge (rule, pattern, or lesson)" },
61
61
  { cmd: "new-milestone", desc: "Create a milestone from a specification document (headless)" },
62
- { cmd: "parallel", desc: "Parallel milestone orchestration (start, status, stop, merge)" },
62
+ { cmd: "parallel", desc: "Parallel milestone orchestration (start, status, stop, merge, watch)" },
63
63
  { cmd: "cmux", desc: "Manage cmux integration (status, sidebar, notifications, splits)" },
64
64
  { cmd: "park", desc: "Park a milestone — skip without deleting" },
65
65
  { cmd: "unpark", desc: "Reactivate a parked milestone" },
@@ -100,6 +100,7 @@ const NESTED_COMPLETIONS: CompletionMap = {
100
100
  { cmd: "pause", desc: "Pause a specific worker" },
101
101
  { cmd: "resume", desc: "Resume a paused worker" },
102
102
  { cmd: "merge", desc: "Merge completed milestone branches" },
103
+ { cmd: "watch", desc: "Live TUI dashboard monitoring all workers" },
103
104
  ],
104
105
  setup: [
105
106
  { cmd: "llm", desc: "Configure LLM provider settings" },
@@ -111,7 +111,25 @@ export async function handleParallelCommand(trimmed: string, _ctx: ExtensionComm
111
111
  return true;
112
112
  }
113
113
 
114
- emitParallelMessage(pi, `Unknown parallel subcommand "${subcommand}". Usage: /gsd parallel [start|status|stop|pause|resume|merge]`);
114
+ if (subcommand === "watch") {
115
+ const root = projectRoot();
116
+ const { ParallelMonitorOverlay } = await import("../../parallel-monitor-overlay.js");
117
+ await _ctx.ui.custom<void>(
118
+ (tui, theme, _kb, done) => new ParallelMonitorOverlay(tui, theme, () => done(), root),
119
+ {
120
+ overlay: true,
121
+ overlayOptions: {
122
+ width: "90%",
123
+ minWidth: 80,
124
+ maxHeight: "92%",
125
+ anchor: "center",
126
+ },
127
+ },
128
+ );
129
+ return true;
130
+ }
131
+
132
+ emitParallelMessage(pi, `Unknown parallel subcommand "${subcommand}". Usage: /gsd parallel [start|status|stop|pause|resume|merge|watch]`);
115
133
  return true;
116
134
  }
117
135
 
@@ -14,8 +14,7 @@ import { readFileSync, unlinkSync, existsSync } from "node:fs";
14
14
  import { join } from "node:path";
15
15
  import { gsdRoot } from "./paths.js";
16
16
  import { atomicWriteSync } from "./atomic-write.js";
17
-
18
- const LOCK_FILE = "auto.lock";
17
+ import { effectiveLockFile } from "./session-lock.js";
19
18
 
20
19
  export interface LockData {
21
20
  pid: number;
@@ -28,7 +27,7 @@ export interface LockData {
28
27
  }
29
28
 
30
29
  function lockPath(basePath: string): string {
31
- return join(gsdRoot(basePath), LOCK_FILE);
30
+ return join(gsdRoot(basePath), effectiveLockFile());
32
31
  }
33
32
 
34
33
  /** Write or update the lock file with current auto-mode state. */