gsd-pi 2.70.1 → 2.71.0-dev.4c35d99

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 (533) hide show
  1. package/README.md +57 -17
  2. package/dist/cli.js +29 -3
  3. package/dist/headless-events.d.ts +2 -0
  4. package/dist/headless-events.js +7 -0
  5. package/dist/headless.js +16 -3
  6. package/dist/mcp-server.js +40 -17
  7. package/dist/provider-migrations.d.ts +10 -0
  8. package/dist/provider-migrations.js +12 -0
  9. package/dist/resource-loader.js +139 -13
  10. package/dist/resources/GSD-WORKFLOW.md +1 -1
  11. package/dist/resources/agents/debugger.md +58 -0
  12. package/dist/resources/agents/doc-writer.md +43 -0
  13. package/dist/resources/agents/git-ops.md +56 -0
  14. package/dist/resources/agents/javascript-pro.md +46 -271
  15. package/dist/resources/agents/planner.md +55 -0
  16. package/dist/resources/agents/refactorer.md +47 -0
  17. package/dist/resources/agents/reviewer.md +48 -0
  18. package/dist/resources/agents/security.md +59 -0
  19. package/dist/resources/agents/tester.md +50 -0
  20. package/dist/resources/agents/typescript-pro.md +41 -235
  21. package/dist/resources/extensions/claude-code-cli/stream-adapter.js +242 -40
  22. package/dist/resources/extensions/get-secrets-from-user.js +17 -1
  23. package/dist/resources/extensions/gsd/auto/infra-errors.js +34 -0
  24. package/dist/resources/extensions/gsd/auto/loop.js +32 -1
  25. package/dist/resources/extensions/gsd/auto/phases.js +5 -1
  26. package/dist/resources/extensions/gsd/auto/session.js +11 -0
  27. package/dist/resources/extensions/gsd/auto-dashboard.js +22 -16
  28. package/dist/resources/extensions/gsd/auto-model-selection.js +10 -2
  29. package/dist/resources/extensions/gsd/auto-prompts.js +88 -33
  30. package/dist/resources/extensions/gsd/auto-start.js +37 -18
  31. package/dist/resources/extensions/gsd/auto-tool-tracking.js +1 -1
  32. package/dist/resources/extensions/gsd/auto-worktree.js +1 -1
  33. package/dist/resources/extensions/gsd/auto.js +56 -0
  34. package/dist/resources/extensions/gsd/bootstrap/db-tools.js +3 -3
  35. package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +6 -0
  36. package/dist/resources/extensions/gsd/bootstrap/register-shortcuts.js +63 -51
  37. package/dist/resources/extensions/gsd/bootstrap/system-context.js +6 -0
  38. package/dist/resources/extensions/gsd/commands/context.js +15 -6
  39. package/dist/resources/extensions/gsd/commands/dispatcher.js +12 -2
  40. package/dist/resources/extensions/gsd/commands/handlers/auto.js +10 -33
  41. package/dist/resources/extensions/gsd/commands/handlers/core.js +56 -11
  42. package/dist/resources/extensions/gsd/commands/handlers/notifications-handler.js +15 -6
  43. package/dist/resources/extensions/gsd/commands/handlers/workflow.js +4 -10
  44. package/dist/resources/extensions/gsd/custom-workflow-engine.js +16 -12
  45. package/dist/resources/extensions/gsd/dashboard-overlay.js +8 -3
  46. package/dist/resources/extensions/gsd/dispatch-guard.js +18 -1
  47. package/dist/resources/extensions/gsd/doctor-providers.js +23 -0
  48. package/dist/resources/extensions/gsd/error-classifier.js +1 -1
  49. package/dist/resources/extensions/gsd/file-lock.js +60 -0
  50. package/dist/resources/extensions/gsd/forensics.js +19 -6
  51. package/dist/resources/extensions/gsd/gate-registry.js +208 -0
  52. package/dist/resources/extensions/gsd/gsd-db.js +41 -0
  53. package/dist/resources/extensions/gsd/guided-flow.js +17 -20
  54. package/dist/resources/extensions/gsd/init-wizard.js +3 -11
  55. package/dist/resources/extensions/gsd/metrics.js +1 -0
  56. package/dist/resources/extensions/gsd/milestone-actions.js +10 -4
  57. package/dist/resources/extensions/gsd/milestone-validation-gates.js +11 -12
  58. package/dist/resources/extensions/gsd/notification-overlay.js +42 -13
  59. package/dist/resources/extensions/gsd/notification-store.js +56 -5
  60. package/dist/resources/extensions/gsd/notification-widget.js +5 -13
  61. package/dist/resources/extensions/gsd/parallel-monitor-overlay.js +8 -3
  62. package/dist/resources/extensions/gsd/pre-execution-checks.js +35 -2
  63. package/dist/resources/extensions/gsd/prompt-validation.js +126 -0
  64. package/dist/resources/extensions/gsd/prompts/complete-slice.md +5 -3
  65. package/dist/resources/extensions/gsd/prompts/discuss.md +33 -13
  66. package/dist/resources/extensions/gsd/prompts/execute-task.md +22 -19
  67. package/dist/resources/extensions/gsd/prompts/guided-discuss-milestone.md +2 -0
  68. package/dist/resources/extensions/gsd/prompts/guided-discuss-slice.md +2 -0
  69. package/dist/resources/extensions/gsd/prompts/guided-resume-task.md +1 -1
  70. package/dist/resources/extensions/gsd/prompts/queue.md +3 -2
  71. package/dist/resources/extensions/gsd/prompts/system.md +1 -0
  72. package/dist/resources/extensions/gsd/prompts/validate-milestone.md +4 -1
  73. package/dist/resources/extensions/gsd/session-model-override.js +25 -0
  74. package/dist/resources/extensions/gsd/shortcut-defs.js +40 -0
  75. package/dist/resources/extensions/gsd/state.js +241 -332
  76. package/dist/resources/extensions/gsd/tools/complete-slice.js +52 -1
  77. package/dist/resources/extensions/gsd/tools/complete-task.js +51 -1
  78. package/dist/resources/extensions/gsd/tools/workflow-tool-executors.js +38 -1
  79. package/dist/resources/extensions/gsd/workflow-events.js +25 -13
  80. package/dist/resources/extensions/gsd/workflow-mcp-auto-prep.js +56 -0
  81. package/dist/resources/extensions/gsd/workflow-mcp.js +1 -1
  82. package/dist/resources/extensions/ollama/index.js +13 -5
  83. package/dist/resources/extensions/shared/gsd-phase-state.js +35 -0
  84. package/dist/resources/extensions/subagent/agents.js +8 -0
  85. package/dist/resources/extensions/subagent/index.js +17 -0
  86. package/dist/resources/skills/create-skill/SKILL.md +2 -0
  87. package/dist/startup-model-validation.d.ts +0 -1
  88. package/dist/startup-model-validation.js +6 -2
  89. package/dist/web/standalone/.next/BUILD_ID +1 -1
  90. package/dist/web/standalone/.next/app-path-routes-manifest.json +17 -17
  91. package/dist/web/standalone/.next/build-manifest.json +4 -4
  92. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  93. package/dist/web/standalone/.next/react-loadable-manifest.json +1 -1
  94. package/dist/web/standalone/.next/required-server-files.json +3 -3
  95. package/dist/web/standalone/.next/server/app/_global-error/page.js +3 -3
  96. package/dist/web/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
  97. package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
  98. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  99. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  100. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  101. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  102. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  103. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  104. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  105. package/dist/web/standalone/.next/server/app/_not-found/page.js +2 -2
  106. package/dist/web/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  107. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  108. package/dist/web/standalone/.next/server/app/_not-found.rsc +3 -3
  109. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +3 -3
  110. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  111. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +3 -3
  112. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  113. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  114. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  115. package/dist/web/standalone/.next/server/app/api/boot/route.js +1 -1
  116. package/dist/web/standalone/.next/server/app/api/boot/route_client-reference-manifest.js +1 -1
  117. package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route.js +1 -1
  118. package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route_client-reference-manifest.js +1 -1
  119. package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route.js +1 -1
  120. package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route_client-reference-manifest.js +1 -1
  121. package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route.js +2 -2
  122. package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route_client-reference-manifest.js +1 -1
  123. package/dist/web/standalone/.next/server/app/api/browse-directories/route.js +1 -1
  124. package/dist/web/standalone/.next/server/app/api/browse-directories/route_client-reference-manifest.js +1 -1
  125. package/dist/web/standalone/.next/server/app/api/captures/route.js +1 -1
  126. package/dist/web/standalone/.next/server/app/api/captures/route_client-reference-manifest.js +1 -1
  127. package/dist/web/standalone/.next/server/app/api/cleanup/route.js +1 -1
  128. package/dist/web/standalone/.next/server/app/api/cleanup/route_client-reference-manifest.js +1 -1
  129. package/dist/web/standalone/.next/server/app/api/dev-mode/route.js +1 -1
  130. package/dist/web/standalone/.next/server/app/api/dev-mode/route_client-reference-manifest.js +1 -1
  131. package/dist/web/standalone/.next/server/app/api/doctor/route.js +1 -1
  132. package/dist/web/standalone/.next/server/app/api/doctor/route_client-reference-manifest.js +1 -1
  133. package/dist/web/standalone/.next/server/app/api/experimental/route.js +2 -2
  134. package/dist/web/standalone/.next/server/app/api/experimental/route_client-reference-manifest.js +1 -1
  135. package/dist/web/standalone/.next/server/app/api/export-data/route.js +1 -1
  136. package/dist/web/standalone/.next/server/app/api/export-data/route_client-reference-manifest.js +1 -1
  137. package/dist/web/standalone/.next/server/app/api/files/route.js +1 -1
  138. package/dist/web/standalone/.next/server/app/api/files/route_client-reference-manifest.js +1 -1
  139. package/dist/web/standalone/.next/server/app/api/forensics/route.js +1 -1
  140. package/dist/web/standalone/.next/server/app/api/forensics/route_client-reference-manifest.js +1 -1
  141. package/dist/web/standalone/.next/server/app/api/git/route.js +1 -1
  142. package/dist/web/standalone/.next/server/app/api/git/route_client-reference-manifest.js +1 -1
  143. package/dist/web/standalone/.next/server/app/api/history/route.js +1 -1
  144. package/dist/web/standalone/.next/server/app/api/history/route_client-reference-manifest.js +1 -1
  145. package/dist/web/standalone/.next/server/app/api/hooks/route.js +1 -1
  146. package/dist/web/standalone/.next/server/app/api/hooks/route_client-reference-manifest.js +1 -1
  147. package/dist/web/standalone/.next/server/app/api/inspect/route.js +1 -1
  148. package/dist/web/standalone/.next/server/app/api/inspect/route_client-reference-manifest.js +1 -1
  149. package/dist/web/standalone/.next/server/app/api/knowledge/route.js +1 -1
  150. package/dist/web/standalone/.next/server/app/api/knowledge/route_client-reference-manifest.js +1 -1
  151. package/dist/web/standalone/.next/server/app/api/live-state/route.js +1 -1
  152. package/dist/web/standalone/.next/server/app/api/live-state/route_client-reference-manifest.js +1 -1
  153. package/dist/web/standalone/.next/server/app/api/notifications/route.js +2 -2
  154. package/dist/web/standalone/.next/server/app/api/notifications/route_client-reference-manifest.js +1 -1
  155. package/dist/web/standalone/.next/server/app/api/onboarding/route.js +1 -1
  156. package/dist/web/standalone/.next/server/app/api/onboarding/route_client-reference-manifest.js +1 -1
  157. package/dist/web/standalone/.next/server/app/api/preferences/route.js +1 -1
  158. package/dist/web/standalone/.next/server/app/api/preferences/route_client-reference-manifest.js +1 -1
  159. package/dist/web/standalone/.next/server/app/api/projects/route.js +1 -1
  160. package/dist/web/standalone/.next/server/app/api/projects/route_client-reference-manifest.js +1 -1
  161. package/dist/web/standalone/.next/server/app/api/recovery/route.js +1 -1
  162. package/dist/web/standalone/.next/server/app/api/recovery/route_client-reference-manifest.js +1 -1
  163. package/dist/web/standalone/.next/server/app/api/remote-questions/route.js +2 -2
  164. package/dist/web/standalone/.next/server/app/api/remote-questions/route_client-reference-manifest.js +1 -1
  165. package/dist/web/standalone/.next/server/app/api/session/browser/route.js +1 -1
  166. package/dist/web/standalone/.next/server/app/api/session/browser/route_client-reference-manifest.js +1 -1
  167. package/dist/web/standalone/.next/server/app/api/session/command/route.js +1 -1
  168. package/dist/web/standalone/.next/server/app/api/session/command/route_client-reference-manifest.js +1 -1
  169. package/dist/web/standalone/.next/server/app/api/session/events/route.js +2 -2
  170. package/dist/web/standalone/.next/server/app/api/session/events/route_client-reference-manifest.js +1 -1
  171. package/dist/web/standalone/.next/server/app/api/session/manage/route.js +1 -1
  172. package/dist/web/standalone/.next/server/app/api/session/manage/route_client-reference-manifest.js +1 -1
  173. package/dist/web/standalone/.next/server/app/api/settings-data/route.js +1 -1
  174. package/dist/web/standalone/.next/server/app/api/settings-data/route_client-reference-manifest.js +1 -1
  175. package/dist/web/standalone/.next/server/app/api/shutdown/route.js +1 -1
  176. package/dist/web/standalone/.next/server/app/api/shutdown/route_client-reference-manifest.js +1 -1
  177. package/dist/web/standalone/.next/server/app/api/skill-health/route.js +1 -1
  178. package/dist/web/standalone/.next/server/app/api/skill-health/route_client-reference-manifest.js +1 -1
  179. package/dist/web/standalone/.next/server/app/api/steer/route.js +1 -1
  180. package/dist/web/standalone/.next/server/app/api/steer/route_client-reference-manifest.js +1 -1
  181. package/dist/web/standalone/.next/server/app/api/switch-root/route.js +1 -1
  182. package/dist/web/standalone/.next/server/app/api/switch-root/route_client-reference-manifest.js +1 -1
  183. package/dist/web/standalone/.next/server/app/api/terminal/input/route.js +1 -1
  184. package/dist/web/standalone/.next/server/app/api/terminal/input/route_client-reference-manifest.js +1 -1
  185. package/dist/web/standalone/.next/server/app/api/terminal/resize/route.js +2 -2
  186. package/dist/web/standalone/.next/server/app/api/terminal/resize/route_client-reference-manifest.js +1 -1
  187. package/dist/web/standalone/.next/server/app/api/terminal/sessions/route.js +1 -1
  188. package/dist/web/standalone/.next/server/app/api/terminal/sessions/route_client-reference-manifest.js +1 -1
  189. package/dist/web/standalone/.next/server/app/api/terminal/stream/route.js +2 -2
  190. package/dist/web/standalone/.next/server/app/api/terminal/stream/route_client-reference-manifest.js +1 -1
  191. package/dist/web/standalone/.next/server/app/api/terminal/upload/route.js +1 -1
  192. package/dist/web/standalone/.next/server/app/api/terminal/upload/route_client-reference-manifest.js +1 -1
  193. package/dist/web/standalone/.next/server/app/api/undo/route.js +1 -1
  194. package/dist/web/standalone/.next/server/app/api/undo/route_client-reference-manifest.js +1 -1
  195. package/dist/web/standalone/.next/server/app/api/update/route.js +1 -1
  196. package/dist/web/standalone/.next/server/app/api/update/route_client-reference-manifest.js +1 -1
  197. package/dist/web/standalone/.next/server/app/api/visualizer/route.js +1 -1
  198. package/dist/web/standalone/.next/server/app/api/visualizer/route_client-reference-manifest.js +1 -1
  199. package/dist/web/standalone/.next/server/app/index.html +1 -1
  200. package/dist/web/standalone/.next/server/app/index.rsc +4 -4
  201. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
  202. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +4 -4
  203. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  204. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +3 -3
  205. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  206. package/dist/web/standalone/.next/server/app/page.js +2 -2
  207. package/dist/web/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
  208. package/dist/web/standalone/.next/server/app-paths-manifest.json +17 -17
  209. package/dist/web/standalone/.next/server/chunks/63.js +3 -3
  210. package/dist/web/standalone/.next/server/chunks/6897.js +1 -1
  211. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  212. package/dist/web/standalone/.next/server/middleware-react-loadable-manifest.js +1 -1
  213. package/dist/web/standalone/.next/server/middleware.js +2 -2
  214. package/dist/web/standalone/.next/server/next-font-manifest.js +1 -1
  215. package/dist/web/standalone/.next/server/next-font-manifest.json +1 -1
  216. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  217. package/dist/web/standalone/.next/server/pages/500.html +1 -1
  218. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  219. package/dist/web/standalone/.next/static/chunks/2826.dd3dc8bbd3025fa5.js +9 -0
  220. package/dist/web/standalone/.next/static/chunks/app/_not-found/{page-2f24283c162b6ab3.js → page-f2a7482d42a5614b.js} +1 -1
  221. package/dist/web/standalone/.next/static/chunks/app/{layout-9ecfd95f343793f0.js → layout-a16c7a7ecdf0c2cf.js} +1 -1
  222. package/dist/web/standalone/.next/static/chunks/app/page-f1e30ab6bb269149.js +1 -0
  223. package/dist/web/standalone/.next/static/chunks/main-app-fdab67f7802d7832.js +1 -0
  224. package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/global-error-459824ffb8c323dd.js +1 -0
  225. package/dist/web/standalone/.next/static/chunks/{webpack-6e4d7e9a4f57bed4.js → webpack-b868033a5834586d.js} +1 -1
  226. package/dist/web/standalone/node_modules/node-pty/build/Makefile +2 -2
  227. package/dist/web/standalone/node_modules/node-pty/build/Release/pty.node +0 -0
  228. package/dist/web/standalone/node_modules/node-pty/build/pty.target.mk +14 -14
  229. package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api.target.mk +14 -14
  230. package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api_except.target.mk +14 -14
  231. package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api_maybe.target.mk +14 -14
  232. package/dist/web/standalone/server.js +1 -1
  233. package/package.json +1 -1
  234. package/packages/mcp-server/dist/env-writer.d.ts +39 -0
  235. package/packages/mcp-server/dist/env-writer.d.ts.map +1 -0
  236. package/packages/mcp-server/dist/env-writer.js +158 -0
  237. package/packages/mcp-server/dist/env-writer.js.map +1 -0
  238. package/packages/mcp-server/dist/server.d.ts +23 -3
  239. package/packages/mcp-server/dist/server.d.ts.map +1 -1
  240. package/packages/mcp-server/dist/server.js +192 -44
  241. package/packages/mcp-server/dist/server.js.map +1 -1
  242. package/packages/mcp-server/dist/workflow-tools.d.ts.map +1 -1
  243. package/packages/mcp-server/dist/workflow-tools.js +22 -12
  244. package/packages/mcp-server/dist/workflow-tools.js.map +1 -1
  245. package/packages/mcp-server/src/env-writer.test.ts +280 -0
  246. package/packages/mcp-server/src/env-writer.ts +183 -0
  247. package/packages/mcp-server/src/secure-env-collect.test.ts +265 -0
  248. package/packages/mcp-server/src/server.ts +247 -41
  249. package/packages/mcp-server/src/workflow-tools.test.ts +110 -0
  250. package/packages/mcp-server/src/workflow-tools.ts +32 -12
  251. package/packages/pi-ai/dist/providers/amazon-bedrock.js +11 -2
  252. package/packages/pi-ai/dist/providers/amazon-bedrock.js.map +1 -1
  253. package/packages/pi-ai/dist/providers/anthropic-auth.test.d.ts +2 -0
  254. package/packages/pi-ai/dist/providers/anthropic-auth.test.d.ts.map +1 -0
  255. package/packages/pi-ai/dist/providers/anthropic-auth.test.js +20 -0
  256. package/packages/pi-ai/dist/providers/anthropic-auth.test.js.map +1 -0
  257. package/packages/pi-ai/dist/providers/anthropic-shared.d.ts +4 -1
  258. package/packages/pi-ai/dist/providers/anthropic-shared.d.ts.map +1 -1
  259. package/packages/pi-ai/dist/providers/anthropic-shared.js +8 -3
  260. package/packages/pi-ai/dist/providers/anthropic-shared.js.map +1 -1
  261. package/packages/pi-ai/dist/providers/anthropic-shared.test.js +44 -1
  262. package/packages/pi-ai/dist/providers/anthropic-shared.test.js.map +1 -1
  263. package/packages/pi-ai/dist/providers/anthropic.d.ts +2 -1
  264. package/packages/pi-ai/dist/providers/anthropic.d.ts.map +1 -1
  265. package/packages/pi-ai/dist/providers/anthropic.js +7 -4
  266. package/packages/pi-ai/dist/providers/anthropic.js.map +1 -1
  267. package/packages/pi-ai/dist/providers/openai-completions.d.ts.map +1 -1
  268. package/packages/pi-ai/dist/providers/openai-completions.js +11 -0
  269. package/packages/pi-ai/dist/providers/openai-completions.js.map +1 -1
  270. package/packages/pi-ai/src/providers/amazon-bedrock.ts +13 -1
  271. package/packages/pi-ai/src/providers/anthropic-auth.test.ts +32 -0
  272. package/packages/pi-ai/src/providers/anthropic-shared.test.ts +55 -1
  273. package/packages/pi-ai/src/providers/anthropic-shared.ts +14 -3
  274. package/packages/pi-ai/src/providers/anthropic.ts +8 -4
  275. package/packages/pi-ai/src/providers/openai-completions.ts +14 -0
  276. package/packages/pi-coding-agent/dist/core/agent-session-renderable-tools.test.d.ts +2 -0
  277. package/packages/pi-coding-agent/dist/core/agent-session-renderable-tools.test.d.ts.map +1 -0
  278. package/packages/pi-coding-agent/dist/core/agent-session-renderable-tools.test.js +61 -0
  279. package/packages/pi-coding-agent/dist/core/agent-session-renderable-tools.test.js.map +1 -0
  280. package/packages/pi-coding-agent/dist/core/agent-session.d.ts.map +1 -1
  281. package/packages/pi-coding-agent/dist/core/agent-session.js +2 -1
  282. package/packages/pi-coding-agent/dist/core/agent-session.js.map +1 -1
  283. package/packages/pi-coding-agent/dist/core/auth-storage.d.ts +10 -0
  284. package/packages/pi-coding-agent/dist/core/auth-storage.d.ts.map +1 -1
  285. package/packages/pi-coding-agent/dist/core/auth-storage.js +27 -0
  286. package/packages/pi-coding-agent/dist/core/auth-storage.js.map +1 -1
  287. package/packages/pi-coding-agent/dist/core/auth-storage.test.js +85 -0
  288. package/packages/pi-coding-agent/dist/core/auth-storage.test.js.map +1 -1
  289. package/packages/pi-coding-agent/dist/core/chat-controller-ordering.test.d.ts +2 -0
  290. package/packages/pi-coding-agent/dist/core/chat-controller-ordering.test.d.ts.map +1 -0
  291. package/packages/pi-coding-agent/dist/core/chat-controller-ordering.test.js +388 -0
  292. package/packages/pi-coding-agent/dist/core/chat-controller-ordering.test.js.map +1 -0
  293. package/packages/pi-coding-agent/dist/core/extensions/types.d.ts +2 -0
  294. package/packages/pi-coding-agent/dist/core/extensions/types.d.ts.map +1 -1
  295. package/packages/pi-coding-agent/dist/core/extensions/types.js.map +1 -1
  296. package/packages/pi-coding-agent/dist/core/model-resolver-initial-model-auth.test.d.ts +2 -0
  297. package/packages/pi-coding-agent/dist/core/model-resolver-initial-model-auth.test.d.ts.map +1 -0
  298. package/packages/pi-coding-agent/dist/core/model-resolver-initial-model-auth.test.js +64 -0
  299. package/packages/pi-coding-agent/dist/core/model-resolver-initial-model-auth.test.js.map +1 -0
  300. package/packages/pi-coding-agent/dist/core/model-resolver.d.ts.map +1 -1
  301. package/packages/pi-coding-agent/dist/core/model-resolver.js +22 -18
  302. package/packages/pi-coding-agent/dist/core/model-resolver.js.map +1 -1
  303. package/packages/pi-coding-agent/dist/core/model-resolver.test.d.ts +8 -0
  304. package/packages/pi-coding-agent/dist/core/model-resolver.test.d.ts.map +1 -0
  305. package/packages/pi-coding-agent/dist/core/model-resolver.test.js +75 -0
  306. package/packages/pi-coding-agent/dist/core/model-resolver.test.js.map +1 -0
  307. package/packages/pi-coding-agent/dist/core/sdk.d.ts +11 -0
  308. package/packages/pi-coding-agent/dist/core/sdk.d.ts.map +1 -1
  309. package/packages/pi-coding-agent/dist/core/sdk.js +38 -5
  310. package/packages/pi-coding-agent/dist/core/sdk.js.map +1 -1
  311. package/packages/pi-coding-agent/dist/core/sdk.test.d.ts +2 -0
  312. package/packages/pi-coding-agent/dist/core/sdk.test.d.ts.map +1 -0
  313. package/packages/pi-coding-agent/dist/core/sdk.test.js +71 -0
  314. package/packages/pi-coding-agent/dist/core/sdk.test.js.map +1 -0
  315. package/packages/pi-coding-agent/dist/index.d.ts +1 -1
  316. package/packages/pi-coding-agent/dist/index.d.ts.map +1 -1
  317. package/packages/pi-coding-agent/dist/index.js +1 -1
  318. package/packages/pi-coding-agent/dist/index.js.map +1 -1
  319. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/login-dialog.test.d.ts +2 -0
  320. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/login-dialog.test.d.ts.map +1 -0
  321. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/login-dialog.test.js +13 -0
  322. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/login-dialog.test.js.map +1 -0
  323. package/packages/pi-coding-agent/dist/modes/interactive/components/dynamic-border.d.ts +19 -2
  324. package/packages/pi-coding-agent/dist/modes/interactive/components/dynamic-border.d.ts.map +1 -1
  325. package/packages/pi-coding-agent/dist/modes/interactive/components/dynamic-border.js +50 -1
  326. package/packages/pi-coding-agent/dist/modes/interactive/components/dynamic-border.js.map +1 -1
  327. package/packages/pi-coding-agent/dist/modes/interactive/components/extension-input.d.ts +1 -0
  328. package/packages/pi-coding-agent/dist/modes/interactive/components/extension-input.d.ts.map +1 -1
  329. package/packages/pi-coding-agent/dist/modes/interactive/components/extension-input.js +1 -0
  330. package/packages/pi-coding-agent/dist/modes/interactive/components/extension-input.js.map +1 -1
  331. package/packages/pi-coding-agent/dist/modes/interactive/components/login-dialog.d.ts +4 -0
  332. package/packages/pi-coding-agent/dist/modes/interactive/components/login-dialog.d.ts.map +1 -1
  333. package/packages/pi-coding-agent/dist/modes/interactive/components/login-dialog.js +24 -2
  334. package/packages/pi-coding-agent/dist/modes/interactive/components/login-dialog.js.map +1 -1
  335. package/packages/pi-coding-agent/dist/modes/interactive/components/model-selector.d.ts.map +1 -1
  336. package/packages/pi-coding-agent/dist/modes/interactive/components/model-selector.js +9 -2
  337. package/packages/pi-coding-agent/dist/modes/interactive/components/model-selector.js.map +1 -1
  338. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.d.ts +4 -0
  339. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  340. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js +43 -0
  341. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js.map +1 -1
  342. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.d.ts.map +1 -1
  343. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js +175 -25
  344. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js.map +1 -1
  345. package/packages/pi-coding-agent/dist/modes/interactive/controllers/model-controller.d.ts.map +1 -1
  346. package/packages/pi-coding-agent/dist/modes/interactive/controllers/model-controller.js +6 -1
  347. package/packages/pi-coding-agent/dist/modes/interactive/controllers/model-controller.js.map +1 -1
  348. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-state.d.ts +1 -0
  349. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-state.d.ts.map +1 -1
  350. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-state.js.map +1 -1
  351. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts +6 -0
  352. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  353. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js +62 -5
  354. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
  355. package/packages/pi-coding-agent/dist/modes/interactive/slash-command-handlers.js +4 -2
  356. package/packages/pi-coding-agent/dist/modes/interactive/slash-command-handlers.js.map +1 -1
  357. package/packages/pi-coding-agent/dist/modes/rpc/rpc-mode.js +1 -1
  358. package/packages/pi-coding-agent/dist/modes/rpc/rpc-mode.js.map +1 -1
  359. package/packages/pi-coding-agent/dist/modes/rpc/rpc-types.d.ts +1 -0
  360. package/packages/pi-coding-agent/dist/modes/rpc/rpc-types.d.ts.map +1 -1
  361. package/packages/pi-coding-agent/dist/modes/rpc/rpc-types.js.map +1 -1
  362. package/packages/pi-coding-agent/package.json +1 -1
  363. package/packages/pi-coding-agent/src/core/agent-session-renderable-tools.test.ts +70 -0
  364. package/packages/pi-coding-agent/src/core/agent-session.ts +2 -1
  365. package/packages/pi-coding-agent/src/core/auth-storage.test.ts +108 -0
  366. package/packages/pi-coding-agent/src/core/auth-storage.ts +30 -0
  367. package/packages/pi-coding-agent/src/core/chat-controller-ordering.test.ts +468 -0
  368. package/packages/pi-coding-agent/src/core/extensions/types.ts +2 -0
  369. package/packages/pi-coding-agent/src/core/model-resolver-initial-model-auth.test.ts +78 -0
  370. package/packages/pi-coding-agent/src/core/model-resolver.test.ts +85 -0
  371. package/packages/pi-coding-agent/src/core/model-resolver.ts +22 -18
  372. package/packages/pi-coding-agent/src/core/sdk.test.ts +89 -0
  373. package/packages/pi-coding-agent/src/core/sdk.ts +45 -9
  374. package/packages/pi-coding-agent/src/index.ts +1 -0
  375. package/packages/pi-coding-agent/src/modes/interactive/components/__tests__/login-dialog.test.ts +24 -0
  376. package/packages/pi-coding-agent/src/modes/interactive/components/dynamic-border.ts +58 -2
  377. package/packages/pi-coding-agent/src/modes/interactive/components/extension-input.ts +2 -0
  378. package/packages/pi-coding-agent/src/modes/interactive/components/login-dialog.ts +30 -2
  379. package/packages/pi-coding-agent/src/modes/interactive/components/model-selector.ts +15 -6
  380. package/packages/pi-coding-agent/src/modes/interactive/components/tool-execution.ts +47 -0
  381. package/packages/pi-coding-agent/src/modes/interactive/controllers/chat-controller.ts +205 -31
  382. package/packages/pi-coding-agent/src/modes/interactive/controllers/model-controller.ts +6 -1
  383. package/packages/pi-coding-agent/src/modes/interactive/interactive-mode-state.ts +1 -0
  384. package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +70 -5
  385. package/packages/pi-coding-agent/src/modes/interactive/slash-command-handlers.ts +4 -2
  386. package/packages/pi-coding-agent/src/modes/rpc/rpc-mode.ts +1 -1
  387. package/packages/pi-coding-agent/src/modes/rpc/rpc-types.ts +1 -0
  388. package/packages/pi-tui/dist/components/__tests__/input.test.js +9 -0
  389. package/packages/pi-tui/dist/components/__tests__/input.test.js.map +1 -1
  390. package/packages/pi-tui/dist/components/__tests__/markdown-maxlines.test.d.ts +2 -0
  391. package/packages/pi-tui/dist/components/__tests__/markdown-maxlines.test.d.ts.map +1 -0
  392. package/packages/pi-tui/dist/components/__tests__/markdown-maxlines.test.js +66 -0
  393. package/packages/pi-tui/dist/components/__tests__/markdown-maxlines.test.js.map +1 -0
  394. package/packages/pi-tui/dist/components/input.d.ts +2 -0
  395. package/packages/pi-tui/dist/components/input.d.ts.map +1 -1
  396. package/packages/pi-tui/dist/components/input.js +7 -4
  397. package/packages/pi-tui/dist/components/input.js.map +1 -1
  398. package/packages/pi-tui/dist/components/markdown.d.ts +3 -0
  399. package/packages/pi-tui/dist/components/markdown.d.ts.map +1 -1
  400. package/packages/pi-tui/dist/components/markdown.js +17 -1
  401. package/packages/pi-tui/dist/components/markdown.js.map +1 -1
  402. package/packages/pi-tui/src/components/__tests__/input.test.ts +11 -0
  403. package/packages/pi-tui/src/components/__tests__/markdown-maxlines.test.ts +75 -0
  404. package/packages/pi-tui/src/components/input.ts +7 -4
  405. package/packages/pi-tui/src/components/markdown.ts +22 -1
  406. package/pkg/package.json +1 -1
  407. package/src/resources/GSD-WORKFLOW.md +1 -1
  408. package/src/resources/agents/debugger.md +58 -0
  409. package/src/resources/agents/doc-writer.md +43 -0
  410. package/src/resources/agents/git-ops.md +56 -0
  411. package/src/resources/agents/javascript-pro.md +46 -271
  412. package/src/resources/agents/planner.md +55 -0
  413. package/src/resources/agents/refactorer.md +47 -0
  414. package/src/resources/agents/reviewer.md +48 -0
  415. package/src/resources/agents/security.md +59 -0
  416. package/src/resources/agents/tester.md +50 -0
  417. package/src/resources/agents/typescript-pro.md +41 -235
  418. package/src/resources/extensions/claude-code-cli/stream-adapter.ts +288 -39
  419. package/src/resources/extensions/claude-code-cli/tests/stream-adapter.test.ts +330 -2
  420. package/src/resources/extensions/get-secrets-from-user.ts +24 -1
  421. package/src/resources/extensions/gsd/auto/infra-errors.ts +38 -0
  422. package/src/resources/extensions/gsd/auto/loop-deps.ts +2 -0
  423. package/src/resources/extensions/gsd/auto/loop.ts +45 -1
  424. package/src/resources/extensions/gsd/auto/phases.ts +6 -0
  425. package/src/resources/extensions/gsd/auto/session.ts +11 -0
  426. package/src/resources/extensions/gsd/auto-dashboard.ts +29 -18
  427. package/src/resources/extensions/gsd/auto-model-selection.ts +9 -1
  428. package/src/resources/extensions/gsd/auto-prompts.ts +111 -33
  429. package/src/resources/extensions/gsd/auto-start.ts +44 -20
  430. package/src/resources/extensions/gsd/auto-tool-tracking.ts +1 -1
  431. package/src/resources/extensions/gsd/auto-worktree.ts +1 -1
  432. package/src/resources/extensions/gsd/auto.ts +72 -0
  433. package/src/resources/extensions/gsd/bootstrap/db-tools.ts +3 -3
  434. package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +6 -0
  435. package/src/resources/extensions/gsd/bootstrap/register-shortcuts.ts +79 -60
  436. package/src/resources/extensions/gsd/bootstrap/system-context.ts +7 -0
  437. package/src/resources/extensions/gsd/commands/context.ts +16 -5
  438. package/src/resources/extensions/gsd/commands/dispatcher.ts +14 -2
  439. package/src/resources/extensions/gsd/commands/handlers/auto.ts +10 -36
  440. package/src/resources/extensions/gsd/commands/handlers/core.ts +58 -11
  441. package/src/resources/extensions/gsd/commands/handlers/notifications-handler.ts +17 -7
  442. package/src/resources/extensions/gsd/commands/handlers/workflow.ts +4 -10
  443. package/src/resources/extensions/gsd/custom-workflow-engine.ts +19 -14
  444. package/src/resources/extensions/gsd/dashboard-overlay.ts +10 -3
  445. package/src/resources/extensions/gsd/dispatch-guard.ts +18 -1
  446. package/src/resources/extensions/gsd/doctor-providers.ts +24 -0
  447. package/src/resources/extensions/gsd/error-classifier.ts +1 -1
  448. package/src/resources/extensions/gsd/file-lock.ts +59 -0
  449. package/src/resources/extensions/gsd/forensics.ts +23 -7
  450. package/src/resources/extensions/gsd/gate-registry.ts +251 -0
  451. package/src/resources/extensions/gsd/gsd-db.ts +51 -0
  452. package/src/resources/extensions/gsd/guided-flow.ts +17 -19
  453. package/src/resources/extensions/gsd/init-wizard.ts +3 -13
  454. package/src/resources/extensions/gsd/interrupted-session.ts +1 -0
  455. package/src/resources/extensions/gsd/metrics.ts +12 -1
  456. package/src/resources/extensions/gsd/milestone-actions.ts +10 -3
  457. package/src/resources/extensions/gsd/milestone-validation-gates.ts +11 -13
  458. package/src/resources/extensions/gsd/notification-overlay.ts +47 -14
  459. package/src/resources/extensions/gsd/notification-store.ts +54 -5
  460. package/src/resources/extensions/gsd/notification-widget.ts +5 -14
  461. package/src/resources/extensions/gsd/parallel-monitor-overlay.ts +10 -3
  462. package/src/resources/extensions/gsd/pre-execution-checks.ts +39 -2
  463. package/src/resources/extensions/gsd/prompt-validation.ts +157 -0
  464. package/src/resources/extensions/gsd/prompts/complete-slice.md +5 -3
  465. package/src/resources/extensions/gsd/prompts/discuss.md +33 -13
  466. package/src/resources/extensions/gsd/prompts/execute-task.md +22 -19
  467. package/src/resources/extensions/gsd/prompts/guided-discuss-milestone.md +2 -0
  468. package/src/resources/extensions/gsd/prompts/guided-discuss-slice.md +2 -0
  469. package/src/resources/extensions/gsd/prompts/guided-resume-task.md +1 -1
  470. package/src/resources/extensions/gsd/prompts/queue.md +3 -2
  471. package/src/resources/extensions/gsd/prompts/system.md +1 -0
  472. package/src/resources/extensions/gsd/prompts/validate-milestone.md +4 -1
  473. package/src/resources/extensions/gsd/session-model-override.ts +36 -0
  474. package/src/resources/extensions/gsd/shortcut-defs.ts +56 -0
  475. package/src/resources/extensions/gsd/state.ts +285 -344
  476. package/src/resources/extensions/gsd/tests/auto-start-model-capture.test.ts +25 -9
  477. package/src/resources/extensions/gsd/tests/auto-start-worktree-db-path.test.ts +28 -0
  478. package/src/resources/extensions/gsd/tests/bootstrap-derive-state-db-open.test.ts +39 -0
  479. package/src/resources/extensions/gsd/tests/complete-slice-gate-closure.test.ts +167 -0
  480. package/src/resources/extensions/gsd/tests/complete-slice-prompt-task-summary-layout.test.ts +18 -0
  481. package/src/resources/extensions/gsd/tests/derive-state-helpers.test.ts +436 -0
  482. package/src/resources/extensions/gsd/tests/discuss-incremental-persistence.test.ts +9 -0
  483. package/src/resources/extensions/gsd/tests/dispatch-guard.test.ts +27 -0
  484. package/src/resources/extensions/gsd/tests/doctor-providers.test.ts +36 -0
  485. package/src/resources/extensions/gsd/tests/execute-task-prompt-existing-artifact-guard.test.ts +33 -0
  486. package/src/resources/extensions/gsd/tests/file-lock.test.ts +103 -0
  487. package/src/resources/extensions/gsd/tests/forensics-stuck-loops.test.ts +62 -0
  488. package/src/resources/extensions/gsd/tests/format-shortcut.test.ts +31 -0
  489. package/src/resources/extensions/gsd/tests/gate-dispatch.test.ts +27 -0
  490. package/src/resources/extensions/gsd/tests/gate-registry.test.ts +140 -0
  491. package/src/resources/extensions/gsd/tests/gsd-no-project-error.test.ts +73 -0
  492. package/src/resources/extensions/gsd/tests/infra-errors-cooldown.test.ts +180 -0
  493. package/src/resources/extensions/gsd/tests/integration/auto-worktree-milestone-merge.test.ts +66 -1
  494. package/src/resources/extensions/gsd/tests/model-isolation.test.ts +36 -51
  495. package/src/resources/extensions/gsd/tests/notification-store.test.ts +35 -0
  496. package/src/resources/extensions/gsd/tests/notification-widget.test.ts +26 -0
  497. package/src/resources/extensions/gsd/tests/notifications-handler.test.ts +90 -0
  498. package/src/resources/extensions/gsd/tests/parallel-monitor-overlay.test.ts +1 -0
  499. package/src/resources/extensions/gsd/tests/park-db-sync.test.ts +18 -0
  500. package/src/resources/extensions/gsd/tests/pre-execution-checks.test.ts +49 -0
  501. package/src/resources/extensions/gsd/tests/prompt-contracts.test.ts +19 -0
  502. package/src/resources/extensions/gsd/tests/prompt-system-gate-coverage.test.ts +208 -0
  503. package/src/resources/extensions/gsd/tests/provider-errors.test.ts +7 -0
  504. package/src/resources/extensions/gsd/tests/register-shortcuts.test.ts +63 -5
  505. package/src/resources/extensions/gsd/tests/secure-env-collect.test.ts +45 -0
  506. package/src/resources/extensions/gsd/tests/session-model-override.test.ts +35 -0
  507. package/src/resources/extensions/gsd/tests/start-auto-detached.test.ts +90 -0
  508. package/src/resources/extensions/gsd/tests/tool-invocation-error-loop-break.test.ts +7 -0
  509. package/src/resources/extensions/gsd/tests/validate-milestone-prompt-verification-classes.test.ts +18 -0
  510. package/src/resources/extensions/gsd/tests/workflow-mcp-auto-prep.test.ts +76 -0
  511. package/src/resources/extensions/gsd/tests/workflow-mcp.test.ts +155 -1
  512. package/src/resources/extensions/gsd/tests/workflow-tool-executors.test.ts +22 -0
  513. package/src/resources/extensions/gsd/tools/complete-slice.ts +63 -0
  514. package/src/resources/extensions/gsd/tools/complete-task.ts +63 -0
  515. package/src/resources/extensions/gsd/tools/workflow-tool-executors.ts +64 -26
  516. package/src/resources/extensions/gsd/types.ts +26 -0
  517. package/src/resources/extensions/gsd/workflow-events.ts +34 -25
  518. package/src/resources/extensions/gsd/workflow-mcp-auto-prep.ts +76 -0
  519. package/src/resources/extensions/gsd/workflow-mcp.ts +1 -1
  520. package/src/resources/extensions/ollama/index.ts +13 -3
  521. package/src/resources/extensions/ollama/ollama-status-indicator.test.ts +28 -0
  522. package/src/resources/extensions/shared/gsd-phase-state.ts +42 -0
  523. package/src/resources/extensions/shared/tests/gsd-phase-state.test.ts +48 -0
  524. package/src/resources/extensions/subagent/agents.ts +10 -0
  525. package/src/resources/extensions/subagent/index.ts +18 -0
  526. package/src/resources/extensions/subagent/tests/agents-conflicts.test.ts +33 -0
  527. package/src/resources/skills/create-skill/SKILL.md +2 -0
  528. package/dist/web/standalone/.next/static/chunks/2826.821e01b07d92e948.js +0 -9
  529. package/dist/web/standalone/.next/static/chunks/app/page-7115e62689b5fd84.js +0 -1
  530. package/dist/web/standalone/.next/static/chunks/main-app-d3d4c336195465f9.js +0 -1
  531. package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/global-error-ab5a8926e07ec673.js +0 -1
  532. /package/dist/web/standalone/.next/static/{9pw9EXtXjdM7EFrCXUEPf → OI4n_CKC-lM8IQbvGJ_tK}/_buildManifest.js +0 -0
  533. /package/dist/web/standalone/.next/static/{9pw9EXtXjdM7EFrCXUEPf → OI4n_CKC-lM8IQbvGJ_tK}/_ssgManifest.js +0 -0
@@ -34,6 +34,7 @@ import {
34
34
  import { injectContext } from "./context-injector.js";
35
35
  import type { WorkflowDefinition, StepDefinition } from "./definition-loader.js";
36
36
  import { parseUnitId } from "./unit-id.js";
37
+ import { withFileLock } from "./file-lock.js";
37
38
 
38
39
  /** Read and parse the frozen DEFINITION.yaml from a run directory. */
39
40
  export function readFrozenDefinition(runDir: string): WorkflowDefinition {
@@ -179,24 +180,28 @@ export class CustomWorkflowEngine implements WorkflowEngine {
179
180
  state: EngineState,
180
181
  completedStep: CompletedStep,
181
182
  ): Promise<ReconcileResult> {
182
- // Re-read the graph from disk so we do not overwrite concurrent
183
- // workflow edits with a stale in-memory snapshot from deriveState().
184
- const graph = readGraph(this.runDir);
183
+ const graphPath = join(this.runDir, "GRAPH.yaml");
185
184
 
186
- // Extract stepId from "<workflowName>/<stepId>"
187
- const { milestone, slice, task } = parseUnitId(completedStep.unitId);
188
- const stepId = task ?? slice ?? milestone;
185
+ return await withFileLock(graphPath, () => {
186
+ // Re-read the graph from disk so we do not overwrite concurrent
187
+ // workflow edits with a stale in-memory snapshot from deriveState().
188
+ const graph = readGraph(this.runDir);
189
189
 
190
- const updatedGraph = markStepComplete(graph, stepId);
191
- writeGraph(this.runDir, updatedGraph);
190
+ // Extract stepId from "<workflowName>/<stepId>"
191
+ const { milestone, slice, task } = parseUnitId(completedStep.unitId);
192
+ const stepId = task ?? slice ?? milestone;
192
193
 
193
- const allDone = updatedGraph.steps.every(
194
- (s) => s.status === "complete" || s.status === "expanded",
195
- );
194
+ const updatedGraph = markStepComplete(graph, stepId);
195
+ writeGraph(this.runDir, updatedGraph);
196
196
 
197
- return {
198
- outcome: allDone ? "milestone-complete" : "continue",
199
- };
197
+ const allDone = updatedGraph.steps.every(
198
+ (s) => s.status === "complete" || s.status === "expanded",
199
+ );
200
+
201
+ return {
202
+ outcome: allDone ? "milestone-complete" : "continue",
203
+ };
204
+ });
200
205
  }
201
206
 
202
207
  /**
@@ -3,7 +3,8 @@
3
3
  *
4
4
  * Full-screen overlay showing auto-mode progress: milestone/slice/task
5
5
  * breakdown, current unit, completed units, timing, and activity log.
6
- * Toggled with Ctrl+Alt+G (⌃⌥G on macOS) or opened from /gsd status.
6
+ * Toggled with Ctrl+Alt+G (⌃⌥G on macOS), Ctrl+Shift+G fallback,
7
+ * or opened from /gsd status.
7
8
  */
8
9
 
9
10
  import type { Theme } from "@gsd/pi-coding-agent";
@@ -26,6 +27,7 @@ import { formatDuration, padRight, joinColumns, centerLine, fitColumns, STATUS_G
26
27
  import { estimateTimeRemaining } from "./auto-dashboard.js";
27
28
  import { computeProgressScore, formatProgressLine } from "./progress-score.js";
28
29
  import { runEnvironmentChecks, type EnvironmentCheckResult } from "./doctor-environment.js";
30
+ import { formattedShortcutPair } from "./shortcut-defs.js";
29
31
 
30
32
  function unitLabel(type: string): string {
31
33
  switch (type) {
@@ -203,7 +205,12 @@ export class GSDDashboardOverlay {
203
205
  }
204
206
 
205
207
  handleInput(data: string): void {
206
- if (matchesKey(data, Key.escape) || matchesKey(data, Key.ctrl("c")) || matchesKey(data, Key.ctrlAlt("g"))) {
208
+ if (
209
+ matchesKey(data, Key.escape) ||
210
+ matchesKey(data, Key.ctrl("c")) ||
211
+ matchesKey(data, Key.ctrlAlt("g")) ||
212
+ matchesKey(data, Key.ctrlShift("g"))
213
+ ) {
207
214
  this.dispose();
208
215
  this.onClose();
209
216
  return;
@@ -587,7 +594,7 @@ export class GSDDashboardOverlay {
587
594
 
588
595
  lines.push(blank());
589
596
  lines.push(hr());
590
- lines.push(centered(th.fg("dim", "↑↓ scroll · g/G top/end · esc close")));
597
+ lines.push(centered(th.fg("dim", `↑↓ scroll · g/G top/end · Esc/${formattedShortcutPair("dashboard")} close`)));
591
598
 
592
599
  return lines;
593
600
  }
@@ -107,10 +107,27 @@ export function getPriorSliceCompletionBlocker(
107
107
  // it may be a cross-milestone reference handled elsewhere.
108
108
  }
109
109
  } else {
110
+ // Positional fallback is only a heuristic for legacy slices with no
111
+ // declared dependencies. Skip any earlier slice that depends on the
112
+ // target, directly or transitively, or we can deadlock a valid zero-dep
113
+ // slice behind its own downstream dependents (#3720).
114
+ const reverseDependents = new Set<string>();
115
+ let changed = true;
116
+ while (changed) {
117
+ changed = false;
118
+ for (const slice of slices) {
119
+ if (reverseDependents.has(slice.id)) continue;
120
+ if (slice.depends.some((depId) => depId === targetSid || reverseDependents.has(depId))) {
121
+ reverseDependents.add(slice.id);
122
+ changed = true;
123
+ }
124
+ }
125
+ }
126
+
110
127
  const targetIndex = slices.findIndex((slice) => slice.id === targetSid);
111
128
  const incomplete = slices
112
129
  .slice(0, targetIndex)
113
- .find((slice) => !slice.done);
130
+ .find((slice) => !slice.done && !reverseDependents.has(slice.id));
114
131
  if (incomplete) {
115
132
  return `Cannot dispatch ${unitType} ${unitId}: earlier slice ${targetMid}/${incomplete.id} is not complete.`;
116
133
  }
@@ -185,11 +185,35 @@ const PROVIDER_ROUTES: Record<string, string[]> = {
185
185
  google: ["google-gemini-cli"],
186
186
  };
187
187
 
188
+ /**
189
+ * Providers that use external CLI authentication (not API keys).
190
+ * These are always considered "ok" — the host CLI handles auth.
191
+ */
192
+ const CLI_AUTH_PROVIDERS = new Set([
193
+ "claude-code",
194
+ "openai-codex",
195
+ "google-gemini-cli",
196
+ "google-antigravity",
197
+ ]);
198
+
188
199
  function checkLlmProviders(): ProviderCheckResult[] {
189
200
  const required = collectConfiguredModelProviders();
190
201
  const results: ProviderCheckResult[] = [];
191
202
 
192
203
  for (const providerId of required) {
204
+ // CLI-authenticated providers don't need API keys — skip key check
205
+ if (CLI_AUTH_PROVIDERS.has(providerId)) {
206
+ const info = PROVIDER_REGISTRY.find(p => p.id === providerId);
207
+ results.push({
208
+ name: providerId,
209
+ label: info?.label ?? providerId,
210
+ category: "llm",
211
+ status: "ok",
212
+ message: `${info?.label ?? providerId} — CLI auth (no key needed)`,
213
+ required: true,
214
+ });
215
+ continue;
216
+ }
193
217
  const info = PROVIDER_REGISTRY.find(p => p.id === providerId);
194
218
  const label = providerId === "anthropic-vertex"
195
219
  ? "Anthropic Vertex"
@@ -47,7 +47,7 @@ const RATE_LIMIT_RE = /rate.?limit|too many requests|429/i;
47
47
  const NETWORK_RE = /network|ECONNRESET|ETIMEDOUT|ECONNREFUSED|socket hang up|fetch failed|connection.*reset|dns/i;
48
48
  const SERVER_RE = /internal server error|500|502|503|overloaded|server_error|api_error|service.?unavailable/i;
49
49
  // ECONNRESET/ECONNREFUSED are in NETWORK_RE (same-model retry first).
50
- const CONNECTION_RE = /terminated|connection.?refused|other side closed|EPIPE|network.?(?:is\s+)?unavailable|stream_exhausted(?:_without_result)?/i;
50
+ const CONNECTION_RE = /terminated|connection.?(?:refused|error)|other side closed|EPIPE|network.?(?:is\s+)?unavailable|stream_exhausted(?:_without_result)?/i;
51
51
  // Catch-all for V8 JSON.parse errors: all modern variants end with "in JSON at position \d+".
52
52
  // This eliminates the need to enumerate every error message variant individually.
53
53
  const STREAM_RE = /in JSON at position \d+|Unexpected end of JSON|SyntaxError.*JSON/i;
@@ -0,0 +1,59 @@
1
+ import { existsSync } from "node:fs";
2
+
3
+ function _require(name: string) {
4
+ try {
5
+ return require(name);
6
+ } catch {
7
+ try {
8
+ const gsdPiRequire = require("module").createRequire(
9
+ require("path").join(process.cwd(), "node_modules", "gsd-pi", "index.js")
10
+ );
11
+ return gsdPiRequire(name);
12
+ } catch {
13
+ return null;
14
+ }
15
+ }
16
+ }
17
+
18
+ export function withFileLockSync<T>(filePath: string, fn: () => T): T {
19
+ const lockfile = _require("proper-lockfile");
20
+ if (!lockfile) return fn();
21
+
22
+ if (!existsSync(filePath)) return fn();
23
+
24
+ try {
25
+ const release = lockfile.lockSync(filePath, { retries: 5, stale: 10000 });
26
+ try {
27
+ return fn();
28
+ } finally {
29
+ release();
30
+ }
31
+ } catch (err: any) {
32
+ if (err.code === "ELOCKED") {
33
+ // Could not get lock after retries, let's fallback to un-locked instead of crashing the whole state machine
34
+ return fn();
35
+ }
36
+ throw err;
37
+ }
38
+ }
39
+
40
+ export async function withFileLock<T>(filePath: string, fn: () => Promise<T> | T): Promise<T> {
41
+ const lockfile = _require("proper-lockfile");
42
+ if (!lockfile) return await fn();
43
+
44
+ if (!existsSync(filePath)) return await fn();
45
+
46
+ try {
47
+ const release = await lockfile.lock(filePath, { retries: 5, stale: 10000 });
48
+ try {
49
+ return await fn();
50
+ } finally {
51
+ await release();
52
+ }
53
+ } catch (err: any) {
54
+ if (err.code === "ELOCKED") {
55
+ return await fn();
56
+ }
57
+ throw err;
58
+ }
59
+ }
@@ -650,19 +650,33 @@ function getDbCompletionCounts(): DbCompletionCounts | null {
650
650
  * Exported for testability.
651
651
  */
652
652
  export function detectStuckLoops(units: UnitMetrics[], anomalies: ForensicAnomaly[]): void {
653
- // First, collect unique startedAt values per type/id key
654
- const dispatchMap = new Map<string, Set<number>>();
653
+ // First, collect unique startedAt values per type/id key, bucketed by
654
+ // autoSessionKey when available so cross-session recovery does not look
655
+ // like a within-session stuck loop.
656
+ const dispatchMap = new Map<string, Map<string, Set<number>>>();
655
657
  for (const u of units) {
656
658
  const key = `${u.type}/${u.id}`;
657
- let starts = dispatchMap.get(key);
659
+ let sessionBuckets = dispatchMap.get(key);
660
+ if (!sessionBuckets) {
661
+ sessionBuckets = new Map();
662
+ dispatchMap.set(key, sessionBuckets);
663
+ }
664
+
665
+ const sessionKey = u.autoSessionKey ?? "__legacy__";
666
+ let starts = sessionBuckets.get(sessionKey);
658
667
  if (!starts) {
659
668
  starts = new Set();
660
- dispatchMap.set(key, starts);
669
+ sessionBuckets.set(sessionKey, starts);
661
670
  }
662
671
  starts.add(u.startedAt);
663
672
  }
664
- for (const [key, starts] of dispatchMap) {
665
- const count = starts.size;
673
+
674
+ for (const [key, sessionBuckets] of dispatchMap) {
675
+ const hasSessionAwareData = Array.from(sessionBuckets.keys()).some((sessionKey) => sessionKey !== "__legacy__");
676
+ const count = hasSessionAwareData
677
+ ? Math.max(...Array.from(sessionBuckets.values(), (starts) => starts.size))
678
+ : (sessionBuckets.get("__legacy__")?.size ?? 0);
679
+
666
680
  if (count > 1) {
667
681
  const [unitType, ...idParts] = key.split("/");
668
682
  anomalies.push({
@@ -671,7 +685,9 @@ export function detectStuckLoops(units: UnitMetrics[], anomalies: ForensicAnomal
671
685
  unitType,
672
686
  unitId: idParts.join("/"),
673
687
  summary: `Unit ${key} was dispatched ${count} times`,
674
- details: `Repeated dispatch suggests the unit completed but its artifacts weren't verified, or the state machine kept returning it.`,
688
+ details: hasSessionAwareData
689
+ ? `Repeated dispatch within the same auto session suggests the unit completed but its artifacts were not verified, or the state machine kept returning it. Cross-session recovery runs are ignored.`
690
+ : `Repeated dispatch suggests the unit completed but its artifacts weren't verified, or the state machine kept returning it.`,
675
691
  });
676
692
  }
677
693
  }
@@ -0,0 +1,251 @@
1
+ /**
2
+ * GSD Gate Registry — single source of truth for quality-gate ownership.
3
+ *
4
+ * Each gate declares which workflow turn owns it, the scope at which it is
5
+ * persisted in the `quality_gates` table, and the question/guidance text used
6
+ * in the prompt that turn sends. The registry replaces the ad-hoc
7
+ * `GATE_QUESTIONS` table that used to live in `auto-prompts.ts`, and every
8
+ * layer of the prompt system (prompt builders, dispatch rules, state
9
+ * derivation, tool handlers) consults it so a pending gate can never be
10
+ * silently dropped.
11
+ *
12
+ * Design notes:
13
+ * - `GATE_REGISTRY` is exhaustiveness-checked against `GateId` via
14
+ * `satisfies Record<GateId, GateDefinition>`, so adding a new GateId
15
+ * without a registry entry is a compile error.
16
+ * - `getGatesForTurn(turn)` returns the definitions a turn owns.
17
+ * - `assertGateCoverage(pending, turn)` throws a GSDError if the pending
18
+ * list for a turn contains unknown gates, or if any gate owned by the
19
+ * turn is missing from the pending list.
20
+ */
21
+
22
+ import { GSDError, GSD_PARSE_ERROR } from "./errors.js";
23
+ import type { GateId, GateRow, GateScope } from "./types.js";
24
+
25
+ /** Which workflow turn is responsible for evaluating / closing a gate. */
26
+ export type OwnerTurn =
27
+ | "gate-evaluate"
28
+ | "execute-task"
29
+ | "complete-slice"
30
+ | "validate-milestone";
31
+
32
+ export interface GateDefinition {
33
+ id: GateId;
34
+ scope: GateScope;
35
+ ownerTurn: OwnerTurn;
36
+ /** One-line question the assistant must answer. */
37
+ question: string;
38
+ /** Markdown guidance describing what a good answer looks like. */
39
+ guidance: string;
40
+ /** H3 section header used in the artifact the turn writes
41
+ * (e.g. "Operational Readiness" for Q8 in the slice summary). */
42
+ promptSection: string;
43
+ }
44
+
45
+ export const GATE_REGISTRY = {
46
+ Q3: {
47
+ id: "Q3",
48
+ scope: "slice",
49
+ ownerTurn: "gate-evaluate",
50
+ question: "How can this be exploited?",
51
+ guidance: [
52
+ "Identify abuse scenarios: parameter tampering, replay attacks, privilege escalation.",
53
+ "Map data exposure risks: PII, tokens, secrets accessible through this slice.",
54
+ "Define input trust boundaries: untrusted user input reaching DB, API, or filesystem.",
55
+ "If none apply, return verdict 'omitted' with rationale explaining why.",
56
+ ].join("\n"),
57
+ promptSection: "Abuse Surface",
58
+ },
59
+ Q4: {
60
+ id: "Q4",
61
+ scope: "slice",
62
+ ownerTurn: "gate-evaluate",
63
+ question: "What existing promises does this break?",
64
+ guidance: [
65
+ "List which existing requirements (R001, R003, etc.) are touched by this slice.",
66
+ "Identify what must be re-tested after shipping.",
67
+ "Flag decisions that should be revisited given the new scope.",
68
+ "If no existing requirements are affected, return verdict 'omitted'.",
69
+ ].join("\n"),
70
+ promptSection: "Broken Promises",
71
+ },
72
+ Q5: {
73
+ id: "Q5",
74
+ scope: "task",
75
+ ownerTurn: "execute-task",
76
+ question: "What breaks when dependencies fail?",
77
+ guidance: [
78
+ "Enumerate the task's external dependencies (APIs, filesystem, network, subprocesses).",
79
+ "Describe the failure path for each: timeout, malformed response, connection loss.",
80
+ "Verify the implementation handles each failure or explicitly bubbles the error.",
81
+ "Return verdict 'omitted' only if the task has no external dependencies.",
82
+ ].join("\n"),
83
+ promptSection: "Failure Modes",
84
+ },
85
+ Q6: {
86
+ id: "Q6",
87
+ scope: "task",
88
+ ownerTurn: "execute-task",
89
+ question: "What is the 10x load breakpoint?",
90
+ guidance: [
91
+ "Identify the resource that saturates first at 10x the expected load.",
92
+ "Describe the protection applied (pool sizing, rate limiting, pagination, caching).",
93
+ "Return verdict 'omitted' if the task has no runtime load dimension.",
94
+ ].join("\n"),
95
+ promptSection: "Load Profile",
96
+ },
97
+ Q7: {
98
+ id: "Q7",
99
+ scope: "task",
100
+ ownerTurn: "execute-task",
101
+ question: "What negative tests protect this task?",
102
+ guidance: [
103
+ "List malformed inputs, error paths, and boundary conditions the tests cover.",
104
+ "Point to the specific test files or cases that assert each negative scenario.",
105
+ "Return verdict 'omitted' only if the task has no meaningful negative surface.",
106
+ ].join("\n"),
107
+ promptSection: "Negative Tests",
108
+ },
109
+ Q8: {
110
+ id: "Q8",
111
+ scope: "slice",
112
+ ownerTurn: "complete-slice",
113
+ question: "How will ops know this slice is healthy or broken?",
114
+ guidance: [
115
+ "Describe the health signal (metric, log line, dashboard) that proves the slice works.",
116
+ "Describe the failure signal that triggers an alert or paging.",
117
+ "Document the recovery procedure and any monitoring gaps.",
118
+ "Return verdict 'omitted' only for slices with no runtime behavior at all.",
119
+ ].join("\n"),
120
+ promptSection: "Operational Readiness",
121
+ },
122
+ MV01: {
123
+ id: "MV01",
124
+ scope: "milestone",
125
+ ownerTurn: "validate-milestone",
126
+ question: "Is every success criterion in the milestone roadmap satisfied?",
127
+ guidance: [
128
+ "Walk the success-criteria checklist from the milestone roadmap.",
129
+ "For each criterion, point to the slice / assessment / verification evidence that proves it.",
130
+ "Return verdict 'flag' if any criterion is unmet or unverifiable.",
131
+ ].join("\n"),
132
+ promptSection: "Success Criteria Checklist",
133
+ },
134
+ MV02: {
135
+ id: "MV02",
136
+ scope: "milestone",
137
+ ownerTurn: "validate-milestone",
138
+ question: "Does every slice have a SUMMARY.md and a passing assessment?",
139
+ guidance: [
140
+ "Confirm every slice listed in the roadmap has a SUMMARY.md.",
141
+ "Confirm each slice has an ASSESSMENT verdict of 'pass' (or justified 'omitted').",
142
+ "Flag missing artifacts and slices with outstanding follow-ups or known limitations.",
143
+ ].join("\n"),
144
+ promptSection: "Slice Delivery Audit",
145
+ },
146
+ MV03: {
147
+ id: "MV03",
148
+ scope: "milestone",
149
+ ownerTurn: "validate-milestone",
150
+ question: "Do the slices integrate end-to-end?",
151
+ guidance: [
152
+ "Trace at least one cross-slice flow proving the pieces compose.",
153
+ "Flag gaps where two slices were built in isolation with no integration evidence.",
154
+ ].join("\n"),
155
+ promptSection: "Cross-Slice Integration",
156
+ },
157
+ MV04: {
158
+ id: "MV04",
159
+ scope: "milestone",
160
+ ownerTurn: "validate-milestone",
161
+ question: "Are all touched requirements covered and still coherent?",
162
+ guidance: [
163
+ "For each requirement advanced, validated, surfaced, or invalidated across the milestone's slices, confirm the milestone-level evidence matches.",
164
+ "Flag requirements that slices claim to advance but no artifact proves.",
165
+ ].join("\n"),
166
+ promptSection: "Requirement Coverage",
167
+ },
168
+ } as const satisfies Record<GateId, GateDefinition>;
169
+
170
+ export type GateRegistry = typeof GATE_REGISTRY;
171
+
172
+ /** Stable ordered lists per owner turn — iteration order matches declaration. */
173
+ const ORDERED_GATES: readonly GateDefinition[] = Object.values(GATE_REGISTRY) as readonly GateDefinition[];
174
+
175
+ /** Return every gate owned by a turn, in stable declaration order. */
176
+ export function getGatesForTurn(turn: OwnerTurn): GateDefinition[] {
177
+ return ORDERED_GATES.filter((g) => g.ownerTurn === turn);
178
+ }
179
+
180
+ /** Return the set of gate ids a turn owns. */
181
+ export function getGateIdsForTurn(turn: OwnerTurn): Set<GateId> {
182
+ return new Set(getGatesForTurn(turn).map((g) => g.id));
183
+ }
184
+
185
+ /** Look up a definition by gate id, or undefined if unknown. */
186
+ export function getGateDefinition(id: string): GateDefinition | undefined {
187
+ return (GATE_REGISTRY as Record<string, GateDefinition>)[id];
188
+ }
189
+
190
+ /** Look up the owner turn for a gate id. Throws if the gate is unknown. */
191
+ export function getOwnerTurn(id: GateId): OwnerTurn {
192
+ const def = GATE_REGISTRY[id];
193
+ if (!def) {
194
+ throw new GSDError(GSD_PARSE_ERROR, `gate-registry: unknown gate id "${id}"`);
195
+ }
196
+ return def.ownerTurn;
197
+ }
198
+
199
+ /**
200
+ * Assert that the pending gate rows for a turn match what the registry says
201
+ * the turn owns. Fails loudly rather than silently skipping.
202
+ *
203
+ * - Every row in `pending` must have a definition whose `ownerTurn` matches `turn`.
204
+ * (The caller is responsible for scoping the pending list — e.g. filtering
205
+ * by slice scope before passing it in.)
206
+ * - `options.requireAll` (default true): every gate the turn owns must appear
207
+ * in `pending`. Set to false for turns like `execute-task` that only need
208
+ * coverage for the subset of gates that were seeded (e.g. tasks with no
209
+ * external dependencies have no Q5 row).
210
+ */
211
+ export function assertGateCoverage(
212
+ pending: ReadonlyArray<Pick<GateRow, "gate_id">>,
213
+ turn: OwnerTurn,
214
+ options: { requireAll?: boolean } = {},
215
+ ): void {
216
+ const requireAll = options.requireAll ?? true;
217
+ const expected = getGateIdsForTurn(turn);
218
+ const pendingIds = new Set(pending.map((g) => g.gate_id));
219
+
220
+ const unknown: string[] = [];
221
+ for (const id of pendingIds) {
222
+ const def = getGateDefinition(id);
223
+ if (!def) {
224
+ unknown.push(id);
225
+ continue;
226
+ }
227
+ if (def.ownerTurn !== turn) {
228
+ unknown.push(`${id} (owned by ${def.ownerTurn}, not ${turn})`);
229
+ }
230
+ }
231
+
232
+ if (unknown.length > 0) {
233
+ throw new GSDError(
234
+ GSD_PARSE_ERROR,
235
+ `assertGateCoverage: turn "${turn}" received pending gates it does not own: ${unknown.join(", ")}`,
236
+ );
237
+ }
238
+
239
+ if (requireAll) {
240
+ const missing: GateId[] = [];
241
+ for (const id of expected) {
242
+ if (!pendingIds.has(id)) missing.push(id);
243
+ }
244
+ if (missing.length > 0) {
245
+ throw new GSDError(
246
+ GSD_PARSE_ERROR,
247
+ `assertGateCoverage: turn "${turn}" is missing required gates: ${missing.join(", ")}`,
248
+ );
249
+ }
250
+ }
251
+ }
@@ -10,6 +10,7 @@ import { existsSync, copyFileSync, mkdirSync, realpathSync } from "node:fs";
10
10
  import { dirname } from "node:path";
11
11
  import type { Decision, Requirement, GateRow, GateId, GateScope, GateStatus, GateVerdict } from "./types.js";
12
12
  import { GSDError, GSD_STALE_STATE } from "./errors.js";
13
+ import { getGateIdsForTurn, type OwnerTurn } from "./gate-registry.js";
13
14
  import { logError, logWarning } from "./workflow-logger.js";
14
15
 
15
16
  const _require = createRequire(import.meta.url);
@@ -2302,3 +2303,53 @@ export function getPendingSliceGateCount(milestoneId: string, sliceId: string):
2302
2303
  ).get({ ":mid": milestoneId, ":sid": sliceId });
2303
2304
  return row ? (row["cnt"] as number) : 0;
2304
2305
  }
2306
+
2307
+ /**
2308
+ * Return pending gate rows owned by a specific workflow turn.
2309
+ *
2310
+ * Unlike `getPendingGates(..., scope)`, this filters by the registry's
2311
+ * `ownerTurn` metadata so callers can distinguish Q3/Q4 (owned by
2312
+ * gate-evaluate) from Q8 (owned by complete-slice) even though both are
2313
+ * scope:"slice". Pass `taskId` to narrow task-scoped results to one task.
2314
+ */
2315
+ export function getPendingGatesForTurn(
2316
+ milestoneId: string,
2317
+ sliceId: string,
2318
+ turn: OwnerTurn,
2319
+ taskId?: string,
2320
+ ): GateRow[] {
2321
+ if (!currentDb) return [];
2322
+ const ids = getGateIdsForTurn(turn);
2323
+ if (ids.size === 0) return [];
2324
+ const idList = [...ids];
2325
+ const placeholders = idList.map((_, i) => `:gid${i}`).join(",");
2326
+ const params: Record<string, unknown> = {
2327
+ ":mid": milestoneId,
2328
+ ":sid": sliceId,
2329
+ };
2330
+ idList.forEach((id, i) => {
2331
+ params[`:gid${i}`] = id;
2332
+ });
2333
+ let sql =
2334
+ `SELECT * FROM quality_gates
2335
+ WHERE milestone_id = :mid AND slice_id = :sid
2336
+ AND status = 'pending'
2337
+ AND gate_id IN (${placeholders})`;
2338
+ if (taskId !== undefined) {
2339
+ sql += ` AND task_id = :tid`;
2340
+ params[":tid"] = taskId;
2341
+ }
2342
+ return currentDb.prepare(sql).all(params).map(rowToGate);
2343
+ }
2344
+
2345
+ /**
2346
+ * Count pending gates for a turn. Convenience wrapper used by state
2347
+ * derivation to decide whether a phase transition should pause.
2348
+ */
2349
+ export function getPendingGateCountForTurn(
2350
+ milestoneId: string,
2351
+ sliceId: string,
2352
+ turn: OwnerTurn,
2353
+ ): number {
2354
+ return getPendingGatesForTurn(milestoneId, sliceId, turn).length;
2355
+ }