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
@@ -15,7 +15,7 @@ import { loadPrompt, inlineTemplate } from "./prompt-loader.js";
15
15
  import { buildSkillActivationBlock } from "./auto-prompts.js";
16
16
  import { deriveState } from "./state.js";
17
17
  import { invalidateAllCaches } from "./cache.js";
18
- import { startAuto } from "./auto.js";
18
+ import { startAutoDetached } from "./auto.js";
19
19
  import { clearLock } from "./crash-recovery.js";
20
20
  import {
21
21
  assessInterruptedSession,
@@ -67,7 +67,6 @@ export {
67
67
  showQueue, handleQueueReorder, showQueueAdd,
68
68
  buildExistingMilestonesContext,
69
69
  } from "./guided-flow-queue.js";
70
- import { getErrorMessage } from "./error-utils.js";
71
70
  import { logWarning } from "./workflow-logger.js";
72
71
 
73
72
  // ─── ID Generation with Reservation ─────────────────────────────────────────
@@ -244,11 +243,7 @@ export function checkAutoStartAfterDiscuss(): boolean {
244
243
 
245
244
  pendingAutoStartMap.delete(basePath);
246
245
  ctx.ui.notify(`Milestone ${milestoneId} ready.`, "info");
247
- startAuto(ctx, pi, basePath, false, { step }).catch((err) => {
248
- ctx.ui.notify(`Auto-start failed: ${getErrorMessage(err)}`, "error");
249
- logWarning("guided", `auto start error: ${getErrorMessage(err)}`);
250
- debugLog("auto-start-failed", { error: getErrorMessage(err) });
251
- });
246
+ startAutoDetached(ctx, pi, basePath, false, { step });
252
247
  return true;
253
248
  }
254
249
 
@@ -426,8 +421,9 @@ function resolveAvailableModel<T extends { id: string; provider: string }>(
426
421
  * Build the discuss-and-plan prompt for a new milestone.
427
422
  * Used by all three "new milestone" paths (first ever, no active, all complete).
428
423
  */
429
- function buildDiscussPrompt(nextId: string, preamble: string, _basePath: string, preparationContext?: string): string {
424
+ function buildDiscussPrompt(nextId: string, preamble: string, _basePath: string, pi: ExtensionAPI, ctx: ExtensionCommandContext, preparationContext?: string): string {
430
425
  const milestoneRel = `.gsd/milestones/${nextId}`;
426
+ const structuredQuestionsAvailable = getStructuredQuestionsAvailability(pi, ctx);
431
427
  const inlinedTemplates = [
432
428
  inlineTemplate("project", "Project"),
433
429
  inlineTemplate("requirements", "Requirements"),
@@ -439,6 +435,7 @@ function buildDiscussPrompt(nextId: string, preamble: string, _basePath: string,
439
435
  milestoneId: nextId,
440
436
  preamble,
441
437
  preparationContext: preparationContext ?? "",
438
+ structuredQuestionsAvailable,
442
439
  contextPath: `${milestoneRel}/${nextId}-CONTEXT.md`,
443
440
  roadmapPath: `${milestoneRel}/${nextId}-ROADMAP.md`,
444
441
  inlinedTemplates,
@@ -486,6 +483,7 @@ function buildHeadlessDiscussPrompt(nextId: string, seedContext: string, _basePa
486
483
  */
487
484
  async function prepareAndBuildDiscussPrompt(
488
485
  ctx: ExtensionCommandContext,
486
+ pi: ExtensionAPI,
489
487
  nextId: string,
490
488
  preamble: string,
491
489
  basePath: string,
@@ -520,7 +518,7 @@ async function prepareAndBuildDiscussPrompt(
520
518
  }
521
519
  }
522
520
 
523
- return buildDiscussPrompt(nextId, preamble, basePath, preparationContext);
521
+ return buildDiscussPrompt(nextId, preamble, basePath, pi, ctx, preparationContext);
524
522
  }
525
523
 
526
524
  /**
@@ -780,7 +778,7 @@ export async function showDiscuss(
780
778
  const uniqueMilestoneIds = !!loadEffectiveGSDPreferences()?.preferences?.unique_milestone_ids;
781
779
  const nextId = nextMilestoneIdReserved(milestoneIds, uniqueMilestoneIds);
782
780
  pendingAutoStartMap.set(basePath, { ctx, pi, basePath, milestoneId: nextId, step: false, createdAt: Date.now() });
783
- await dispatchWorkflow(pi, await prepareAndBuildDiscussPrompt(ctx, nextId, `New milestone ${nextId}.`, basePath), "gsd-run", ctx, "discuss-milestone");
781
+ await dispatchWorkflow(pi, await prepareAndBuildDiscussPrompt(ctx, pi, nextId, `New milestone ${nextId}.`, basePath), "gsd-run", ctx, "discuss-milestone");
784
782
  }
785
783
  return;
786
784
  }
@@ -1185,7 +1183,7 @@ async function handleMilestoneActions(
1185
1183
  const uniqueMilestoneIds = !!loadEffectiveGSDPreferences()?.preferences?.unique_milestone_ids;
1186
1184
  const nextId = nextMilestoneIdReserved(milestoneIds, uniqueMilestoneIds);
1187
1185
  pendingAutoStartMap.set(basePath, { ctx, pi, basePath, milestoneId: nextId, step: stepMode, createdAt: Date.now() });
1188
- await dispatchWorkflow(pi, await prepareAndBuildDiscussPrompt(ctx, nextId,
1186
+ await dispatchWorkflow(pi, await prepareAndBuildDiscussPrompt(ctx, pi, nextId,
1189
1187
  `New milestone ${nextId}.`,
1190
1188
  basePath
1191
1189
  ), "gsd-run", ctx, "discuss-milestone");
@@ -1302,7 +1300,7 @@ export async function showSmartEntry(
1302
1300
  ],
1303
1301
  });
1304
1302
  if (resume === "resume") {
1305
- await startAuto(ctx, pi, basePath, false, {
1303
+ startAutoDetached(ctx, pi, basePath, false, {
1306
1304
  interrupted,
1307
1305
  step: interrupted.pausedSession?.stepMode ?? false,
1308
1306
  });
@@ -1375,7 +1373,7 @@ export async function showSmartEntry(
1375
1373
  if (isFirst) {
1376
1374
  // First ever — skip wizard, just ask directly
1377
1375
  pendingAutoStartMap.set(basePath, { ctx, pi, basePath, milestoneId: nextId, step: stepMode, createdAt: Date.now() });
1378
- await dispatchWorkflow(pi, await prepareAndBuildDiscussPrompt(ctx, nextId,
1376
+ await dispatchWorkflow(pi, await prepareAndBuildDiscussPrompt(ctx, pi, nextId,
1379
1377
  `New project, milestone ${nextId}. Do NOT read or explore .gsd/ — it's empty scaffolding.`,
1380
1378
  basePath
1381
1379
  ), "gsd-run", ctx, "discuss-milestone");
@@ -1396,7 +1394,7 @@ export async function showSmartEntry(
1396
1394
 
1397
1395
  if (choice === "new_milestone") {
1398
1396
  pendingAutoStartMap.set(basePath, { ctx, pi, basePath, milestoneId: nextId, step: stepMode, createdAt: Date.now() });
1399
- await dispatchWorkflow(pi, await prepareAndBuildDiscussPrompt(ctx, nextId,
1397
+ await dispatchWorkflow(pi, await prepareAndBuildDiscussPrompt(ctx, pi, nextId,
1400
1398
  `New milestone ${nextId}.`,
1401
1399
  basePath
1402
1400
  ), "gsd-run", ctx, "discuss-milestone");
@@ -1435,7 +1433,7 @@ export async function showSmartEntry(
1435
1433
  const nextId = nextMilestoneIdReserved(milestoneIds, uniqueMilestoneIds);
1436
1434
 
1437
1435
  pendingAutoStartMap.set(basePath, { ctx, pi, basePath, milestoneId: nextId, step: stepMode, createdAt: Date.now() });
1438
- await dispatchWorkflow(pi, await prepareAndBuildDiscussPrompt(ctx, nextId,
1436
+ await dispatchWorkflow(pi, await prepareAndBuildDiscussPrompt(ctx, pi, nextId,
1439
1437
  `New milestone ${nextId}.`,
1440
1438
  basePath
1441
1439
  ), "gsd-run", ctx, "discuss-milestone");
@@ -1502,7 +1500,7 @@ export async function showSmartEntry(
1502
1500
  const uniqueMilestoneIds = !!loadEffectiveGSDPreferences()?.preferences?.unique_milestone_ids;
1503
1501
  const nextId = nextMilestoneIdReserved(milestoneIds, uniqueMilestoneIds);
1504
1502
  pendingAutoStartMap.set(basePath, { ctx, pi, basePath, milestoneId: nextId, step: stepMode, createdAt: Date.now() });
1505
- await dispatchWorkflow(pi, await prepareAndBuildDiscussPrompt(ctx, nextId,
1503
+ await dispatchWorkflow(pi, await prepareAndBuildDiscussPrompt(ctx, pi, nextId,
1506
1504
  `New milestone ${nextId}.`,
1507
1505
  basePath
1508
1506
  ), "gsd-run", ctx, "discuss-milestone");
@@ -1599,7 +1597,7 @@ export async function showSmartEntry(
1599
1597
  const uniqueMilestoneIds = !!loadEffectiveGSDPreferences()?.preferences?.unique_milestone_ids;
1600
1598
  const nextId = nextMilestoneIdReserved(milestoneIds, uniqueMilestoneIds);
1601
1599
  pendingAutoStartMap.set(basePath, { ctx, pi, basePath, milestoneId: nextId, step: stepMode, createdAt: Date.now() });
1602
- await dispatchWorkflow(pi, await prepareAndBuildDiscussPrompt(ctx, nextId,
1600
+ await dispatchWorkflow(pi, await prepareAndBuildDiscussPrompt(ctx, pi, nextId,
1603
1601
  `New milestone ${nextId}.`,
1604
1602
  basePath
1605
1603
  ), "gsd-run", ctx, "discuss-milestone");
@@ -1644,7 +1642,7 @@ export async function showSmartEntry(
1644
1642
  });
1645
1643
 
1646
1644
  if (choice === "auto") {
1647
- await startAuto(ctx, pi, basePath, false);
1645
+ startAutoDetached(ctx, pi, basePath, false);
1648
1646
  } else if (choice === "status") {
1649
1647
  const { fireStatusViaCommand } = await import("./commands.js");
1650
1648
  await fireStatusViaCommand(ctx);
@@ -1856,7 +1854,7 @@ export async function showSmartEntry(
1856
1854
  });
1857
1855
 
1858
1856
  if (choice === "auto") {
1859
- await startAuto(ctx, pi, basePath, false);
1857
+ startAutoDetached(ctx, pi, basePath, false);
1860
1858
  return;
1861
1859
  }
1862
1860
 
@@ -274,19 +274,9 @@ export async function showProjectInit(
274
274
  // Non-fatal — STATE.md will be regenerated on next /gsd invocation
275
275
  }
276
276
 
277
- if (ctx.model?.provider === "claude-code") {
278
- try {
279
- const { ensureProjectWorkflowMcpConfig } = await import("./mcp-project-config.js");
280
- const result = ensureProjectWorkflowMcpConfig(basePath);
281
- if (result.status !== "unchanged") {
282
- ctx.ui.notify(`Claude Code MCP prepared at ${result.configPath}`, "info");
283
- }
284
- } catch (err) {
285
- ctx.ui.notify(
286
- `Claude Code MCP prep failed: ${err instanceof Error ? err.message : String(err)}`,
287
- "warning",
288
- );
289
- }
277
+ {
278
+ const { prepareWorkflowMcpForProject } = await import("./workflow-mcp-auto-prep.js");
279
+ prepareWorkflowMcpForProject(ctx, basePath);
290
280
  }
291
281
 
292
282
  ctx.ui.notify("GSD initialized. Starting your first milestone...", "info");
@@ -34,6 +34,7 @@ export interface PausedSessionMetadata {
34
34
  activeEngineId?: string;
35
35
  activeRunDir?: string | null;
36
36
  autoStartTime?: number;
37
+ milestoneLock?: string | null;
37
38
  }
38
39
 
39
40
  export interface InterruptedSessionAssessment {
@@ -41,6 +41,7 @@ export interface UnitMetrics {
41
41
  model: string; // model ID used
42
42
  startedAt: number; // ms timestamp
43
43
  finishedAt: number; // ms timestamp
44
+ autoSessionKey?: string; // identifies one auto-mode run across pause/resume
44
45
  tokens: TokenCounts;
45
46
  cost: number; // total USD cost
46
47
  toolCalls: number;
@@ -133,7 +134,16 @@ export function snapshotUnitMetrics(
133
134
  unitId: string,
134
135
  startedAt: number,
135
136
  model: string,
136
- opts?: { tier?: string; modelDowngraded?: boolean; contextWindowTokens?: number; truncationSections?: number; continueHereFired?: boolean; promptCharCount?: number; baselineCharCount?: number },
137
+ opts?: {
138
+ tier?: string;
139
+ modelDowngraded?: boolean;
140
+ contextWindowTokens?: number;
141
+ truncationSections?: number;
142
+ continueHereFired?: boolean;
143
+ promptCharCount?: number;
144
+ baselineCharCount?: number;
145
+ autoSessionKey?: string;
146
+ },
137
147
  ): UnitMetrics | null {
138
148
  if (!ledger) return null;
139
149
 
@@ -181,6 +191,7 @@ export function snapshotUnitMetrics(
181
191
  model,
182
192
  startedAt,
183
193
  finishedAt: Date.now(),
194
+ ...(opts?.autoSessionKey ? { autoSessionKey: opts.autoSessionKey } : {}),
184
195
  tokens,
185
196
  cost,
186
197
  toolCalls,
@@ -20,7 +20,7 @@ import {
20
20
  } from "./paths.js";
21
21
  import { invalidateAllCaches } from "./cache.js";
22
22
  import { loadQueueOrder, saveQueueOrder } from "./queue-order.js";
23
- import { isDbAvailable, updateMilestoneStatus } from "./gsd-db.js";
23
+ import { getMilestone, isDbAvailable, updateMilestoneStatus } from "./gsd-db.js";
24
24
  import { logWarning } from "./workflow-logger.js";
25
25
 
26
26
  // ─── Park ──────────────────────────────────────────────────────────────────
@@ -77,9 +77,16 @@ export function unparkMilestone(basePath: string, milestoneId: string): boolean
77
77
  if (!mDir || !existsSync(mDir)) return false;
78
78
 
79
79
  const parkedPath = join(mDir, buildMilestoneFileName(milestoneId, "PARKED"));
80
- if (!existsSync(parkedPath)) return false; // not parked
80
+ const hadParkedFile = existsSync(parkedPath);
81
+ const dbThinksParked = isDbAvailable() && getMilestone(milestoneId)?.status === "parked";
81
82
 
82
- unlinkSync(parkedPath);
83
+ // Recover the reverse desync too: DB can still say "parked" even when the
84
+ // PARKED marker was lost on disk, and /gsd unpark should repair that state.
85
+ if (!hadParkedFile && !dbThinksParked) return false;
86
+
87
+ if (hadParkedFile) {
88
+ unlinkSync(parkedPath);
89
+ }
83
90
  // Sync DB status so deriveStateFromDb picks up the unparked milestone (#2694)
84
91
  if (isDbAvailable()) {
85
92
  try {
@@ -6,19 +6,13 @@
6
6
  * records in the DB. This module inserts milestone-level validation gates
7
7
  * that correspond to the validation checks performed.
8
8
  *
9
- * Gate IDs for milestone validation:
10
- * MV01 Success criteria checklist
11
- * MV02 Slice delivery audit
12
- * MV03 — Cross-slice integration
13
- * MV04 — Requirement coverage
14
- *
15
- * These use the existing quality_gates table with scope "milestone".
9
+ * Gate IDs for milestone validation (MV01–MV04) are sourced from the
10
+ * gate registry so the definitions stay in lockstep with prompt builders,
11
+ * dispatch rules, and state derivation. See gate-registry.ts.
16
12
  */
17
13
 
18
14
  import { _getAdapter } from "./gsd-db.js";
19
-
20
- /** Milestone validation gate IDs. */
21
- const MILESTONE_GATE_IDS = ["MV01", "MV02", "MV03", "MV04"] as const;
15
+ import { getGatesForTurn } from "./gate-registry.js";
22
16
 
23
17
  /**
24
18
  * Insert milestone-level quality_gates records for a validation run.
@@ -27,6 +21,9 @@ const MILESTONE_GATE_IDS = ["MV01", "MV02", "MV03", "MV04"] as const;
27
21
  * from the overall milestone validation verdict. Individual gate-level
28
22
  * verdicts are not available (the handler receives a single verdict),
29
23
  * so all gates share the overall verdict.
24
+ *
25
+ * Gate IDs come from the registry — adding/removing an MV-scoped gate
26
+ * in gate-registry.ts automatically flows through here.
30
27
  */
31
28
  export function insertMilestoneValidationGates(
32
29
  milestoneId: string,
@@ -38,8 +35,9 @@ export function insertMilestoneValidationGates(
38
35
  if (!db) return;
39
36
 
40
37
  const gateVerdict = verdict === "pass" ? "pass" : "flag";
38
+ const milestoneGates = getGatesForTurn("validate-milestone");
41
39
 
42
- for (const gateId of MILESTONE_GATE_IDS) {
40
+ for (const def of milestoneGates) {
43
41
  db.prepare(
44
42
  `INSERT OR REPLACE INTO quality_gates
45
43
  (milestone_id, slice_id, gate_id, scope, task_id, status, verdict, rationale, findings, evaluated_at)
@@ -47,9 +45,9 @@ export function insertMilestoneValidationGates(
47
45
  ).run({
48
46
  ":mid": milestoneId,
49
47
  ":sid": sliceId,
50
- ":gid": gateId,
48
+ ":gid": def.id,
51
49
  ":verdict": gateVerdict,
52
- ":rationale": `Milestone validation verdict: ${verdict}`,
50
+ ":rationale": `${def.promptSection} — milestone validation verdict: ${verdict}`,
53
51
  ":evaluated_at": evaluatedAt,
54
52
  });
55
53
  }
@@ -1,6 +1,6 @@
1
1
  // GSD Extension — Notification History Overlay
2
2
  // Scrollable panel showing all persisted notifications with severity filtering.
3
- // Toggled with Ctrl+Alt+N (⌃⌥N on macOS) or opened from /gsd notifications.
3
+ // Toggled with Ctrl+Alt+N (⌃⌥N on macOS), Ctrl+Shift+N fallback, or /gsd notifications.
4
4
 
5
5
  import type { Theme } from "@gsd/pi-coding-agent";
6
6
  import { truncateToWidth, visibleWidth, matchesKey, Key } from "@gsd/pi-tui";
@@ -9,11 +9,12 @@ import {
9
9
  readNotifications,
10
10
  markAllRead,
11
11
  clearNotifications,
12
- getUnreadCount,
12
+ onNotificationStoreChange,
13
13
  type NotificationEntry,
14
14
  type NotifySeverity,
15
15
  } from "./notification-store.js";
16
- import { padRight, centerLine, joinColumns, formatDuration } from "../shared/mod.js";
16
+ import { formattedShortcutPair } from "./shortcut-defs.js";
17
+ import { padRight, joinColumns } from "../shared/mod.js";
17
18
 
18
19
  type FilterMode = "all" | "error" | "warning" | "info";
19
20
  const FILTER_CYCLE: FilterMode[] = ["all", "error", "warning", "info"];
@@ -63,6 +64,12 @@ function formatTimestamp(ts: string): string {
63
64
  }
64
65
  }
65
66
 
67
+ function notificationSignature(entries: readonly NotificationEntry[]): string {
68
+ return entries
69
+ .map((entry) => `${entry.ts}|${entry.severity}|${entry.read ? 1 : 0}|${entry.message}`)
70
+ .join("\n");
71
+ }
72
+
66
73
  export class GSDNotificationOverlay {
67
74
  private tui: { requestRender: () => void };
68
75
  private theme: Theme;
@@ -72,9 +79,11 @@ export class GSDNotificationOverlay {
72
79
  private scrollOffset = 0;
73
80
  private filterIndex = 0;
74
81
  private entries: NotificationEntry[] = [];
82
+ private entriesSignature = "";
75
83
  private refreshTimer: ReturnType<typeof setInterval>;
76
84
  private disposed = false;
77
85
  private resizeHandler: (() => void) | null = null;
86
+ private unsubscribeStore: (() => void) | null = null;
78
87
 
79
88
  constructor(
80
89
  tui: { requestRender: () => void },
@@ -88,6 +97,7 @@ export class GSDNotificationOverlay {
88
97
  // Mark all as read on open
89
98
  markAllRead();
90
99
  this.entries = readNotifications();
100
+ this.entriesSignature = notificationSignature(this.entries);
91
101
 
92
102
  // Resize handler
93
103
  this.resizeHandler = () => {
@@ -97,17 +107,17 @@ export class GSDNotificationOverlay {
97
107
  };
98
108
  process.stdout.on("resize", this.resizeHandler);
99
109
 
100
- // Refresh every 3s for new notifications
110
+ // Subscribe to store mutations for immediate updates
111
+ this.unsubscribeStore = onNotificationStoreChange(() => {
112
+ if (this.disposed) return;
113
+ this._refreshFromDisk();
114
+ });
115
+
116
+ // 30s safety-net for cross-process edits (web subprocess, parallel workers)
101
117
  this.refreshTimer = setInterval(() => {
102
118
  if (this.disposed) return;
103
- const fresh = readNotifications();
104
- if (fresh.length !== this.entries.length) {
105
- this.entries = fresh;
106
- markAllRead();
107
- this.invalidate();
108
- this.tui.requestRender();
109
- }
110
- }, 3000);
119
+ this._refreshFromDisk();
120
+ }, 30_000);
111
121
  }
112
122
 
113
123
  private get filter(): FilterMode {
@@ -120,7 +130,12 @@ export class GSDNotificationOverlay {
120
130
  }
121
131
 
122
132
  handleInput(data: string): void {
123
- if (matchesKey(data, Key.escape) || matchesKey(data, Key.ctrl("c")) || matchesKey(data, Key.ctrlAlt("n"))) {
133
+ if (
134
+ matchesKey(data, Key.escape) ||
135
+ matchesKey(data, Key.ctrl("c")) ||
136
+ matchesKey(data, Key.ctrlAlt("n")) ||
137
+ matchesKey(data, Key.ctrlShift("n"))
138
+ ) {
124
139
  this.dispose();
125
140
  this.onClose();
126
141
  return;
@@ -165,6 +180,7 @@ export class GSDNotificationOverlay {
165
180
  if (data === "c") {
166
181
  clearNotifications();
167
182
  this.entries = [];
183
+ this.entriesSignature = notificationSignature(this.entries);
168
184
  this.scrollOffset = 0;
169
185
  this.invalidate();
170
186
  this.tui.requestRender();
@@ -199,12 +215,28 @@ export class GSDNotificationOverlay {
199
215
  dispose(): void {
200
216
  this.disposed = true;
201
217
  clearInterval(this.refreshTimer);
218
+ if (this.unsubscribeStore) {
219
+ this.unsubscribeStore();
220
+ this.unsubscribeStore = null;
221
+ }
202
222
  if (this.resizeHandler) {
203
223
  process.stdout.removeListener("resize", this.resizeHandler);
204
224
  this.resizeHandler = null;
205
225
  }
206
226
  }
207
227
 
228
+ private _refreshFromDisk(): void {
229
+ const fresh = readNotifications();
230
+ const signature = notificationSignature(fresh);
231
+ if (signature !== this.entriesSignature) {
232
+ markAllRead();
233
+ this.entries = readNotifications();
234
+ this.entriesSignature = notificationSignature(this.entries);
235
+ this.invalidate();
236
+ this.tui.requestRender();
237
+ }
238
+ }
239
+
208
240
  private wrapInBox(inner: string[], width: number): string[] {
209
241
  const th = this.theme;
210
242
  const border = (s: string) => th.fg("borderAccent", s);
@@ -250,7 +282,8 @@ export class GSDNotificationOverlay {
250
282
  lines.push(hr());
251
283
 
252
284
  // Controls
253
- lines.push(row(th.fg("dim", "↑/↓ scroll f filter c clear Esc close")));
285
+ const closeShortcut = formattedShortcutPair("notifications");
286
+ lines.push(row(th.fg("dim", `↑/↓ scroll f filter c clear Esc close (${closeShortcut})`)));
254
287
  lines.push(blank());
255
288
 
256
289
  // Entries
@@ -26,12 +26,16 @@ export interface NotificationEntry {
26
26
  const MAX_ENTRIES = 500;
27
27
  const FILENAME = "notifications.jsonl";
28
28
  const LOCKFILE = "notifications.lock";
29
+ const DEDUP_WINDOW_MS = 30_000;
30
+ const DEDUP_PRUNE_THRESHOLD = 200;
29
31
 
30
32
  // ─── Module State ───────────────────────────────────────────────────────
31
33
 
32
34
  let _basePath: string | null = null;
33
35
  let _lineCount = 0; // Hint for rotation — not authoritative for public API
34
36
  let _suppressCount = 0;
37
+ let _recentMessageTimestamps = new Map<string, number>();
38
+ const _changeListeners = new Set<() => void>();
35
39
 
36
40
  // ─── Public API ─────────────────────────────────────────────────────────
37
41
 
@@ -40,6 +44,9 @@ let _suppressCount = 0;
40
44
  * project root. Seeds in-memory counters from the existing file on disk.
41
45
  */
42
46
  export function initNotificationStore(basePath: string): void {
47
+ if (_basePath !== basePath) {
48
+ _recentMessageTimestamps.clear();
49
+ }
43
50
  _basePath = basePath;
44
51
  // Seed line count hint for rotation — public counters read from disk
45
52
  _lineCount = _readEntriesFromDisk(basePath).length;
@@ -56,12 +63,23 @@ export function appendNotification(
56
63
  ): void {
57
64
  if (!_basePath) return;
58
65
  if (_suppressCount > 0) return;
66
+ const persistedMessage = message.length > 500 ? message.slice(0, 500) + "…" : message;
67
+ const dedupKey = `${_basePath}:${severity}:${source}:${persistedMessage}`;
68
+ const now = Date.now();
69
+ const lastSeen = _recentMessageTimestamps.get(dedupKey);
70
+ if (lastSeen !== undefined && now - lastSeen < DEDUP_WINDOW_MS) return;
71
+ _recentMessageTimestamps.set(dedupKey, now);
72
+ if (_recentMessageTimestamps.size > DEDUP_PRUNE_THRESHOLD) {
73
+ for (const [key, ts] of _recentMessageTimestamps) {
74
+ if (now - ts > DEDUP_WINDOW_MS) _recentMessageTimestamps.delete(key);
75
+ }
76
+ }
59
77
 
60
78
  const entry: NotificationEntry = {
61
79
  id: randomUUID(),
62
80
  ts: new Date().toISOString(),
63
81
  severity,
64
- message: message.length > 500 ? message.slice(0, 500) + "…" : message,
82
+ message: persistedMessage,
65
83
  source,
66
84
  read: false,
67
85
  };
@@ -76,6 +94,7 @@ export function appendNotification(
76
94
  if (_lineCount > MAX_ENTRIES) {
77
95
  _rotate();
78
96
  }
97
+ _emitChange();
79
98
  } catch {
80
99
  // Non-fatal — never let persistence break the caller
81
100
  }
@@ -104,6 +123,7 @@ export function markAllRead(basePath?: string): void {
104
123
  const hasUnread = entries.some((e) => !e.read);
105
124
  if (!hasUnread) return;
106
125
 
126
+ let changed = false;
107
127
  try {
108
128
  _withLock(bp, () => {
109
129
  // Re-read inside lock to get freshest state
@@ -111,10 +131,12 @@ export function markAllRead(basePath?: string): void {
111
131
  if (fresh.length === 0 || !fresh.some((e) => !e.read)) return;
112
132
  const lines = fresh.map((e) => JSON.stringify({ ...e, read: true }));
113
133
  _atomicWrite(bp, lines.join("\n") + "\n");
134
+ changed = true;
114
135
  });
115
136
  } catch {
116
137
  // Non-fatal
117
138
  }
139
+ if (changed) _emitChange();
118
140
  }
119
141
 
120
142
  /**
@@ -128,6 +150,8 @@ export function clearNotifications(basePath?: string): void {
128
150
  _withLock(bp, () => {
129
151
  _atomicWrite(bp, "");
130
152
  });
153
+ _lineCount = 0;
154
+ _emitChange();
131
155
  } catch {
132
156
  // Non-fatal
133
157
  }
@@ -172,6 +196,17 @@ export function unsuppressPersistence(): void {
172
196
  _suppressCount = Math.max(0, _suppressCount - 1);
173
197
  }
174
198
 
199
+ /**
200
+ * Subscribe to notification-store mutations (append, mark-read, clear).
201
+ * Returns an unsubscribe function.
202
+ */
203
+ export function onNotificationStoreChange(listener: () => void): () => void {
204
+ _changeListeners.add(listener);
205
+ return () => {
206
+ _changeListeners.delete(listener);
207
+ };
208
+ }
209
+
175
210
  // ─── Test Helpers ───────────────────────────────────────────────────────
176
211
 
177
212
  /**
@@ -181,6 +216,8 @@ export function _resetNotificationStore(): void {
181
216
  _basePath = null;
182
217
  _lineCount = 0;
183
218
  _suppressCount = 0;
219
+ _recentMessageTimestamps = new Map();
220
+ _changeListeners.clear();
184
221
  }
185
222
 
186
223
  // ─── Internal ───────────────────────────────────────────────────────────
@@ -216,12 +253,23 @@ function _rotate(): void {
216
253
  const trimmed = entries.slice(entries.length - MAX_ENTRIES);
217
254
  const lines = trimmed.map((e) => JSON.stringify(e));
218
255
  _atomicWrite(_basePath!, lines.join("\n") + "\n");
256
+ _lineCount = trimmed.length;
219
257
  });
220
258
  } catch {
221
259
  // Non-fatal
222
260
  }
223
261
  }
224
262
 
263
+ function _emitChange(): void {
264
+ for (const listener of _changeListeners) {
265
+ try {
266
+ listener();
267
+ } catch {
268
+ // Non-fatal
269
+ }
270
+ }
271
+ }
272
+
225
273
  /**
226
274
  * Atomic file rewrite via temp-file + rename. Prevents partial reads
227
275
  * by other processes (web API subprocess, parallel workers).
@@ -275,10 +323,11 @@ function _withLock<T>(basePath: string, fn: () => T): T {
275
323
  }
276
324
  }
277
325
 
278
- // Only run the mutation if we actually own the lock
279
- const ownsLock = fd !== null;
326
+ // Best-effort: mutation runs regardless of lock status (idempotent overwrites).
327
+ // createdLock gates cleanup only — never skip fn() on lock failure.
328
+ const createdLock = fd !== null;
280
329
  try {
281
- if (ownsLock && fd !== null) {
330
+ if (createdLock && fd !== null) {
282
331
  // Write our PID timestamp into the lock for stale detection
283
332
  writeFileSync(lockPath, String(Date.now()), "utf-8");
284
333
  closeSync(fd);
@@ -286,7 +335,7 @@ function _withLock<T>(basePath: string, fn: () => T): T {
286
335
  return fn();
287
336
  } finally {
288
337
  // Only delete the lock if we created it — never remove another process's lock
289
- if (ownsLock) {
338
+ if (createdLock) {
290
339
  try { unlinkSync(lockPath); } catch { /* best-effort cleanup */ }
291
340
  }
292
341
  }
@@ -5,8 +5,8 @@
5
5
 
6
6
  import type { ExtensionContext } from "@gsd/pi-coding-agent";
7
7
 
8
- import { getUnreadCount, readNotifications } from "./notification-store.js";
9
- import { formatShortcut } from "./files.js";
8
+ import { getUnreadCount, onNotificationStoreChange } from "./notification-store.js";
9
+ import { formattedShortcutPair } from "./shortcut-defs.js";
10
10
 
11
11
  // ─── Pure rendering ──���────────────────────────���─────────────────────────
12
12
 
@@ -14,18 +14,7 @@ export function buildNotificationWidgetLines(): string[] {
14
14
  const unread = getUnreadCount();
15
15
  if (unread === 0) return [];
16
16
 
17
- const entries = readNotifications();
18
- const latest = entries[0]; // newest-first
19
- if (!latest) return [];
20
-
21
- const icon = latest.severity === "error" ? "✗" : latest.severity === "warning" ? "⚠" : "●";
22
- const badge = `${unread} unread`;
23
- const msgMax = 80;
24
- const truncated = latest.message.length > msgMax
25
- ? latest.message.slice(0, msgMax - 1) + "…"
26
- : latest.message;
27
-
28
- return [` ${icon} [${badge}] ${truncated} (${formatShortcut("Ctrl+Alt+N")} to view)`];
17
+ return [` 🔔 Notifications: ${unread} unread (${formattedShortcutPair("notifications")})`];
29
18
  }
30
19
 
31
20
  // ─── Widget init ────────────────────────────────────────────────────────
@@ -51,6 +40,7 @@ export function initNotificationWidget(ctx: ExtensionContext): void {
51
40
  _tui.requestRender();
52
41
  };
53
42
 
43
+ const unsubscribe = onNotificationStoreChange(refresh);
54
44
  const refreshTimer = setInterval(refresh, REFRESH_INTERVAL_MS);
55
45
 
56
46
  return {
@@ -62,6 +52,7 @@ export function initNotificationWidget(ctx: ExtensionContext): void {
62
52
  cachedLines = undefined;
63
53
  },
64
54
  dispose(): void {
55
+ unsubscribe();
65
56
  clearInterval(refreshTimer);
66
57
  },
67
58
  };