gsd-pi 2.63.0-dev.d04bbc5 → 2.64.0-dev.05b8a94

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 (245) hide show
  1. package/dist/headless.js +3 -1
  2. package/dist/resources/extensions/bg-shell/bg-shell-lifecycle.js +22 -7
  3. package/dist/resources/extensions/bg-shell/process-manager.js +6 -1
  4. package/dist/resources/extensions/gsd/auto-dashboard.js +5 -5
  5. package/dist/resources/extensions/gsd/auto-post-unit.js +98 -1
  6. package/dist/resources/extensions/gsd/auto-verification.js +138 -1
  7. package/dist/resources/extensions/gsd/auto.js +5 -0
  8. package/dist/resources/extensions/gsd/bootstrap/db-tools.js +24 -13
  9. package/dist/resources/extensions/gsd/bootstrap/notify-interceptor.js +28 -0
  10. package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +8 -0
  11. package/dist/resources/extensions/gsd/bootstrap/register-shortcuts.js +15 -0
  12. package/dist/resources/extensions/gsd/bootstrap/system-context.js +20 -0
  13. package/dist/resources/extensions/gsd/commands/catalog.js +7 -1
  14. package/dist/resources/extensions/gsd/commands/handlers/core.js +1 -0
  15. package/dist/resources/extensions/gsd/commands/handlers/notifications-handler.js +103 -0
  16. package/dist/resources/extensions/gsd/commands/handlers/ops.js +5 -0
  17. package/dist/resources/extensions/gsd/notification-overlay.js +224 -0
  18. package/dist/resources/extensions/gsd/notification-store.js +268 -0
  19. package/dist/resources/extensions/gsd/notification-widget.js +56 -0
  20. package/dist/resources/extensions/gsd/post-execution-checks.js +407 -0
  21. package/dist/resources/extensions/gsd/pre-execution-checks.js +464 -0
  22. package/dist/resources/extensions/gsd/preferences-types.js +4 -0
  23. package/dist/resources/extensions/gsd/preferences-validation.js +33 -0
  24. package/dist/resources/extensions/gsd/preferences.js +4 -0
  25. package/dist/resources/extensions/gsd/verification-evidence.js +18 -0
  26. package/dist/resources/extensions/gsd/workflow-logger.js +8 -0
  27. package/dist/web/standalone/.next/BUILD_ID +1 -1
  28. package/dist/web/standalone/.next/app-path-routes-manifest.json +20 -19
  29. package/dist/web/standalone/.next/build-manifest.json +2 -2
  30. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  31. package/dist/web/standalone/.next/required-server-files.json +1 -1
  32. package/dist/web/standalone/.next/routes-manifest.json +6 -0
  33. package/dist/web/standalone/.next/server/app/_global-error.html +2 -2
  34. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  35. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  36. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  37. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  38. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  39. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  40. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  41. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  42. package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
  43. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
  44. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  45. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
  46. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  47. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  48. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  49. package/dist/web/standalone/.next/server/app/api/notifications/route.js +3 -0
  50. package/dist/web/standalone/.next/server/app/api/notifications/route.js.nft.json +1 -0
  51. package/dist/web/standalone/.next/server/app/api/notifications/route_client-reference-manifest.js +1 -0
  52. package/dist/web/standalone/.next/server/app/index.html +1 -1
  53. package/dist/web/standalone/.next/server/app/index.rsc +1 -1
  54. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
  55. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +1 -1
  56. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  57. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
  58. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  59. package/dist/web/standalone/.next/server/app-paths-manifest.json +20 -19
  60. package/dist/web/standalone/.next/server/functions-config-manifest.json +1 -0
  61. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  62. package/dist/web/standalone/.next/server/pages/500.html +2 -2
  63. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  64. package/dist/web/standalone/.next/static/Vbx2-SrSBOgta6576xj9m/_buildManifest.js +1 -0
  65. package/dist/web/standalone/.next/static/chunks/app/_global-error/page-8805a20e15762c3c.js +1 -0
  66. package/dist/web/standalone/.next/static/chunks/app/api/boot/route-8805a20e15762c3c.js +1 -0
  67. package/dist/web/standalone/.next/static/chunks/app/api/bridge-terminal/input/route-8805a20e15762c3c.js +1 -0
  68. package/dist/web/standalone/.next/static/chunks/app/api/bridge-terminal/resize/route-8805a20e15762c3c.js +1 -0
  69. package/dist/web/standalone/.next/static/chunks/app/api/bridge-terminal/stream/route-8805a20e15762c3c.js +1 -0
  70. package/dist/web/standalone/.next/static/chunks/app/api/browse-directories/route-8805a20e15762c3c.js +1 -0
  71. package/dist/web/standalone/.next/static/chunks/app/api/captures/route-8805a20e15762c3c.js +1 -0
  72. package/dist/web/standalone/.next/static/chunks/app/api/cleanup/route-8805a20e15762c3c.js +1 -0
  73. package/dist/web/standalone/.next/static/chunks/app/api/dev-mode/route-8805a20e15762c3c.js +1 -0
  74. package/dist/web/standalone/.next/static/chunks/app/api/doctor/route-8805a20e15762c3c.js +1 -0
  75. package/dist/web/standalone/.next/static/chunks/app/api/experimental/route-8805a20e15762c3c.js +1 -0
  76. package/dist/web/standalone/.next/static/chunks/app/api/export-data/route-8805a20e15762c3c.js +1 -0
  77. package/dist/web/standalone/.next/static/chunks/app/api/files/route-8805a20e15762c3c.js +1 -0
  78. package/dist/web/standalone/.next/static/chunks/app/api/forensics/route-8805a20e15762c3c.js +1 -0
  79. package/dist/web/standalone/.next/static/chunks/app/api/git/route-8805a20e15762c3c.js +1 -0
  80. package/dist/web/standalone/.next/static/chunks/app/api/history/route-8805a20e15762c3c.js +1 -0
  81. package/dist/web/standalone/.next/static/chunks/app/api/hooks/route-8805a20e15762c3c.js +1 -0
  82. package/dist/web/standalone/.next/static/chunks/app/api/inspect/route-8805a20e15762c3c.js +1 -0
  83. package/dist/web/standalone/.next/static/chunks/app/api/knowledge/route-8805a20e15762c3c.js +1 -0
  84. package/dist/web/standalone/.next/static/chunks/app/api/live-state/route-8805a20e15762c3c.js +1 -0
  85. package/dist/web/standalone/.next/static/chunks/app/api/notifications/route-8805a20e15762c3c.js +1 -0
  86. package/dist/web/standalone/.next/static/chunks/app/api/onboarding/route-8805a20e15762c3c.js +1 -0
  87. package/dist/web/standalone/.next/static/chunks/app/api/preferences/route-8805a20e15762c3c.js +1 -0
  88. package/dist/web/standalone/.next/static/chunks/app/api/projects/route-8805a20e15762c3c.js +1 -0
  89. package/dist/web/standalone/.next/static/chunks/app/api/recovery/route-8805a20e15762c3c.js +1 -0
  90. package/dist/web/standalone/.next/static/chunks/app/api/remote-questions/route-8805a20e15762c3c.js +1 -0
  91. package/dist/web/standalone/.next/static/chunks/app/api/session/browser/route-8805a20e15762c3c.js +1 -0
  92. package/dist/web/standalone/.next/static/chunks/app/api/session/command/route-8805a20e15762c3c.js +1 -0
  93. package/dist/web/standalone/.next/static/chunks/app/api/session/events/route-8805a20e15762c3c.js +1 -0
  94. package/dist/web/standalone/.next/static/chunks/app/api/session/manage/route-8805a20e15762c3c.js +1 -0
  95. package/dist/web/standalone/.next/static/chunks/app/api/settings-data/route-8805a20e15762c3c.js +1 -0
  96. package/dist/web/standalone/.next/static/chunks/app/api/shutdown/route-8805a20e15762c3c.js +1 -0
  97. package/dist/web/standalone/.next/static/chunks/app/api/skill-health/route-8805a20e15762c3c.js +1 -0
  98. package/dist/web/standalone/.next/static/chunks/app/api/steer/route-8805a20e15762c3c.js +1 -0
  99. package/dist/web/standalone/.next/static/chunks/app/api/switch-root/route-8805a20e15762c3c.js +1 -0
  100. package/dist/web/standalone/.next/static/chunks/app/api/terminal/input/route-8805a20e15762c3c.js +1 -0
  101. package/dist/web/standalone/.next/static/chunks/app/api/terminal/resize/route-8805a20e15762c3c.js +1 -0
  102. package/dist/web/standalone/.next/static/chunks/app/api/terminal/sessions/route-8805a20e15762c3c.js +1 -0
  103. package/dist/web/standalone/.next/static/chunks/app/api/terminal/stream/route-8805a20e15762c3c.js +1 -0
  104. package/dist/web/standalone/.next/static/chunks/app/api/terminal/upload/route-8805a20e15762c3c.js +1 -0
  105. package/dist/web/standalone/.next/static/chunks/app/api/undo/route-8805a20e15762c3c.js +1 -0
  106. package/dist/web/standalone/.next/static/chunks/app/api/update/route-8805a20e15762c3c.js +1 -0
  107. package/dist/web/standalone/.next/static/chunks/app/api/visualizer/route-8805a20e15762c3c.js +1 -0
  108. package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/app-error-8805a20e15762c3c.js +1 -0
  109. package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/forbidden-8805a20e15762c3c.js +1 -0
  110. package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/not-found-8805a20e15762c3c.js +1 -0
  111. package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/unauthorized-8805a20e15762c3c.js +1 -0
  112. package/dist/web/standalone/server.js +1 -1
  113. package/package.json +1 -1
  114. package/packages/pi-agent-core/dist/agent-loop.js +26 -9
  115. package/packages/pi-agent-core/dist/agent-loop.js.map +1 -1
  116. package/packages/pi-agent-core/src/agent-loop.test.ts +100 -4
  117. package/packages/pi-agent-core/src/agent-loop.ts +43 -12
  118. package/packages/pi-coding-agent/dist/core/agent-session-tool-refresh.test.d.ts +2 -0
  119. package/packages/pi-coding-agent/dist/core/agent-session-tool-refresh.test.d.ts.map +1 -0
  120. package/packages/pi-coding-agent/dist/core/agent-session-tool-refresh.test.js +38 -0
  121. package/packages/pi-coding-agent/dist/core/agent-session-tool-refresh.test.js.map +1 -0
  122. package/packages/pi-coding-agent/dist/core/agent-session.d.ts.map +1 -1
  123. package/packages/pi-coding-agent/dist/core/agent-session.js +11 -0
  124. package/packages/pi-coding-agent/dist/core/agent-session.js.map +1 -1
  125. package/packages/pi-coding-agent/dist/core/resource-loader-cache-reset.test.d.ts +2 -0
  126. package/packages/pi-coding-agent/dist/core/resource-loader-cache-reset.test.d.ts.map +1 -0
  127. package/packages/pi-coding-agent/dist/core/resource-loader-cache-reset.test.js +24 -0
  128. package/packages/pi-coding-agent/dist/core/resource-loader-cache-reset.test.js.map +1 -0
  129. package/packages/pi-coding-agent/dist/core/resource-loader.d.ts.map +1 -1
  130. package/packages/pi-coding-agent/dist/core/resource-loader.js +4 -1
  131. package/packages/pi-coding-agent/dist/core/resource-loader.js.map +1 -1
  132. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.d.ts +1 -0
  133. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  134. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js +8 -0
  135. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js.map +1 -1
  136. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts +6 -0
  137. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  138. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js +36 -0
  139. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
  140. package/packages/pi-coding-agent/package.json +1 -1
  141. package/packages/pi-coding-agent/src/core/agent-session-tool-refresh.test.ts +64 -0
  142. package/packages/pi-coding-agent/src/core/agent-session.ts +10 -0
  143. package/packages/pi-coding-agent/src/core/resource-loader-cache-reset.test.ts +42 -0
  144. package/packages/pi-coding-agent/src/core/resource-loader.ts +5 -1
  145. package/packages/pi-coding-agent/src/modes/interactive/components/tool-execution.ts +9 -0
  146. package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +33 -0
  147. package/packages/pi-tui/dist/components/loader.d.ts +4 -2
  148. package/packages/pi-tui/dist/components/loader.d.ts.map +1 -1
  149. package/packages/pi-tui/dist/components/loader.js +27 -9
  150. package/packages/pi-tui/dist/components/loader.js.map +1 -1
  151. package/packages/pi-tui/dist/components/text.d.ts.map +1 -1
  152. package/packages/pi-tui/dist/components/text.js +2 -0
  153. package/packages/pi-tui/dist/components/text.js.map +1 -1
  154. package/packages/pi-tui/dist/tui.d.ts +2 -0
  155. package/packages/pi-tui/dist/tui.d.ts.map +1 -1
  156. package/packages/pi-tui/dist/tui.js +35 -0
  157. package/packages/pi-tui/dist/tui.js.map +1 -1
  158. package/packages/pi-tui/src/components/loader.ts +27 -10
  159. package/packages/pi-tui/src/components/text.ts +1 -0
  160. package/packages/pi-tui/src/tui.ts +32 -0
  161. package/pkg/package.json +1 -1
  162. package/src/resources/extensions/bg-shell/bg-shell-lifecycle.ts +19 -7
  163. package/src/resources/extensions/bg-shell/process-manager.ts +8 -2
  164. package/src/resources/extensions/gsd/auto-dashboard.ts +5 -4
  165. package/src/resources/extensions/gsd/auto-post-unit.ts +122 -0
  166. package/src/resources/extensions/gsd/auto-verification.ts +190 -2
  167. package/src/resources/extensions/gsd/auto.ts +4 -0
  168. package/src/resources/extensions/gsd/bootstrap/db-tools.ts +25 -13
  169. package/src/resources/extensions/gsd/bootstrap/notify-interceptor.ts +34 -0
  170. package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +8 -0
  171. package/src/resources/extensions/gsd/bootstrap/register-shortcuts.ts +19 -0
  172. package/src/resources/extensions/gsd/bootstrap/system-context.ts +28 -0
  173. package/src/resources/extensions/gsd/commands/catalog.ts +7 -1
  174. package/src/resources/extensions/gsd/commands/handlers/core.ts +1 -0
  175. package/src/resources/extensions/gsd/commands/handlers/notifications-handler.ts +139 -0
  176. package/src/resources/extensions/gsd/commands/handlers/ops.ts +5 -0
  177. package/src/resources/extensions/gsd/notification-overlay.ts +267 -0
  178. package/src/resources/extensions/gsd/notification-store.ts +288 -0
  179. package/src/resources/extensions/gsd/notification-widget.ts +68 -0
  180. package/src/resources/extensions/gsd/post-execution-checks.ts +539 -0
  181. package/src/resources/extensions/gsd/pre-execution-checks.ts +573 -0
  182. package/src/resources/extensions/gsd/preferences-types.ts +28 -0
  183. package/src/resources/extensions/gsd/preferences-validation.ts +33 -0
  184. package/src/resources/extensions/gsd/preferences.ts +4 -0
  185. package/src/resources/extensions/gsd/tests/auto-start-time-persistence.test.ts +50 -0
  186. package/src/resources/extensions/gsd/tests/complete-slice-string-coercion.test.ts +36 -0
  187. package/src/resources/extensions/gsd/tests/discuss-tool-scope-leak.test.ts +76 -0
  188. package/src/resources/extensions/gsd/tests/enhanced-verification-integration.test.ts +526 -0
  189. package/src/resources/extensions/gsd/tests/notification-store.test.ts +249 -0
  190. package/src/resources/extensions/gsd/tests/post-exec-retry-bypass.test.ts +312 -0
  191. package/src/resources/extensions/gsd/tests/post-execution-checks.test.ts +813 -0
  192. package/src/resources/extensions/gsd/tests/pre-execution-checks.test.ts +999 -0
  193. package/src/resources/extensions/gsd/tests/pre-execution-fail-closed.test.ts +266 -0
  194. package/src/resources/extensions/gsd/tests/pre-execution-pause-wiring.test.ts +457 -0
  195. package/src/resources/extensions/gsd/tests/unstructured-continue-context-injection.test.ts +163 -0
  196. package/src/resources/extensions/gsd/verification-evidence.ts +68 -0
  197. package/src/resources/extensions/gsd/workflow-logger.ts +13 -0
  198. package/dist/web/standalone/.next/static/chunks/app/_global-error/page-c4cc189e7b117ea2.js +0 -1
  199. package/dist/web/standalone/.next/static/chunks/app/api/boot/route-c4cc189e7b117ea2.js +0 -1
  200. package/dist/web/standalone/.next/static/chunks/app/api/bridge-terminal/input/route-c4cc189e7b117ea2.js +0 -1
  201. package/dist/web/standalone/.next/static/chunks/app/api/bridge-terminal/resize/route-c4cc189e7b117ea2.js +0 -1
  202. package/dist/web/standalone/.next/static/chunks/app/api/bridge-terminal/stream/route-c4cc189e7b117ea2.js +0 -1
  203. package/dist/web/standalone/.next/static/chunks/app/api/browse-directories/route-c4cc189e7b117ea2.js +0 -1
  204. package/dist/web/standalone/.next/static/chunks/app/api/captures/route-c4cc189e7b117ea2.js +0 -1
  205. package/dist/web/standalone/.next/static/chunks/app/api/cleanup/route-c4cc189e7b117ea2.js +0 -1
  206. package/dist/web/standalone/.next/static/chunks/app/api/dev-mode/route-c4cc189e7b117ea2.js +0 -1
  207. package/dist/web/standalone/.next/static/chunks/app/api/doctor/route-c4cc189e7b117ea2.js +0 -1
  208. package/dist/web/standalone/.next/static/chunks/app/api/experimental/route-c4cc189e7b117ea2.js +0 -1
  209. package/dist/web/standalone/.next/static/chunks/app/api/export-data/route-c4cc189e7b117ea2.js +0 -1
  210. package/dist/web/standalone/.next/static/chunks/app/api/files/route-c4cc189e7b117ea2.js +0 -1
  211. package/dist/web/standalone/.next/static/chunks/app/api/forensics/route-c4cc189e7b117ea2.js +0 -1
  212. package/dist/web/standalone/.next/static/chunks/app/api/git/route-c4cc189e7b117ea2.js +0 -1
  213. package/dist/web/standalone/.next/static/chunks/app/api/history/route-c4cc189e7b117ea2.js +0 -1
  214. package/dist/web/standalone/.next/static/chunks/app/api/hooks/route-c4cc189e7b117ea2.js +0 -1
  215. package/dist/web/standalone/.next/static/chunks/app/api/inspect/route-c4cc189e7b117ea2.js +0 -1
  216. package/dist/web/standalone/.next/static/chunks/app/api/knowledge/route-c4cc189e7b117ea2.js +0 -1
  217. package/dist/web/standalone/.next/static/chunks/app/api/live-state/route-c4cc189e7b117ea2.js +0 -1
  218. package/dist/web/standalone/.next/static/chunks/app/api/onboarding/route-c4cc189e7b117ea2.js +0 -1
  219. package/dist/web/standalone/.next/static/chunks/app/api/preferences/route-c4cc189e7b117ea2.js +0 -1
  220. package/dist/web/standalone/.next/static/chunks/app/api/projects/route-c4cc189e7b117ea2.js +0 -1
  221. package/dist/web/standalone/.next/static/chunks/app/api/recovery/route-c4cc189e7b117ea2.js +0 -1
  222. package/dist/web/standalone/.next/static/chunks/app/api/remote-questions/route-c4cc189e7b117ea2.js +0 -1
  223. package/dist/web/standalone/.next/static/chunks/app/api/session/browser/route-c4cc189e7b117ea2.js +0 -1
  224. package/dist/web/standalone/.next/static/chunks/app/api/session/command/route-c4cc189e7b117ea2.js +0 -1
  225. package/dist/web/standalone/.next/static/chunks/app/api/session/events/route-c4cc189e7b117ea2.js +0 -1
  226. package/dist/web/standalone/.next/static/chunks/app/api/session/manage/route-c4cc189e7b117ea2.js +0 -1
  227. package/dist/web/standalone/.next/static/chunks/app/api/settings-data/route-c4cc189e7b117ea2.js +0 -1
  228. package/dist/web/standalone/.next/static/chunks/app/api/shutdown/route-c4cc189e7b117ea2.js +0 -1
  229. package/dist/web/standalone/.next/static/chunks/app/api/skill-health/route-c4cc189e7b117ea2.js +0 -1
  230. package/dist/web/standalone/.next/static/chunks/app/api/steer/route-c4cc189e7b117ea2.js +0 -1
  231. package/dist/web/standalone/.next/static/chunks/app/api/switch-root/route-c4cc189e7b117ea2.js +0 -1
  232. package/dist/web/standalone/.next/static/chunks/app/api/terminal/input/route-c4cc189e7b117ea2.js +0 -1
  233. package/dist/web/standalone/.next/static/chunks/app/api/terminal/resize/route-c4cc189e7b117ea2.js +0 -1
  234. package/dist/web/standalone/.next/static/chunks/app/api/terminal/sessions/route-c4cc189e7b117ea2.js +0 -1
  235. package/dist/web/standalone/.next/static/chunks/app/api/terminal/stream/route-c4cc189e7b117ea2.js +0 -1
  236. package/dist/web/standalone/.next/static/chunks/app/api/terminal/upload/route-c4cc189e7b117ea2.js +0 -1
  237. package/dist/web/standalone/.next/static/chunks/app/api/undo/route-c4cc189e7b117ea2.js +0 -1
  238. package/dist/web/standalone/.next/static/chunks/app/api/update/route-c4cc189e7b117ea2.js +0 -1
  239. package/dist/web/standalone/.next/static/chunks/app/api/visualizer/route-c4cc189e7b117ea2.js +0 -1
  240. package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/app-error-c4cc189e7b117ea2.js +0 -1
  241. package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/forbidden-c4cc189e7b117ea2.js +0 -1
  242. package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/not-found-c4cc189e7b117ea2.js +0 -1
  243. package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/unauthorized-c4cc189e7b117ea2.js +0 -1
  244. package/dist/web/standalone/.next/static/vIq9fmvRUaFOpguoX5j4W/_buildManifest.js +0 -1
  245. /package/dist/web/standalone/.next/static/{vIq9fmvRUaFOpguoX5j4W → Vbx2-SrSBOgta6576xj9m}/_ssgManifest.js +0 -0
@@ -18,6 +18,7 @@ import { loadFile, parseSummary, resolveAllOverrides } from "./files.js";
18
18
  import { loadPrompt } from "./prompt-loader.js";
19
19
  import {
20
20
  resolveSliceFile,
21
+ resolveSlicePath,
21
22
  resolveTaskFile,
22
23
  resolveMilestoneFile,
23
24
  resolveTasksDir,
@@ -59,6 +60,10 @@ import { validateFileChanges } from "./safety/file-change-validator.js";
59
60
  import { validateContent } from "./safety/content-validator.js";
60
61
  import { resolveSafetyHarnessConfig } from "./safety/safety-harness.js";
61
62
  import { resolveExpectedArtifactPath as resolveArtifactForContent } from "./auto-artifact-paths.js";
63
+ import { loadEffectiveGSDPreferences } from "./preferences.js";
64
+ import { getSliceTasks } from "./gsd-db.js";
65
+ import { runPreExecutionChecks, type PreExecutionResult } from "./pre-execution-checks.js";
66
+ import { writePreExecutionEvidence } from "./verification-evidence.js";
62
67
 
63
68
  /** Maximum verification retry attempts before escalating to blocker placeholder (#2653). */
64
69
  const MAX_VERIFICATION_RETRIES = 3;
@@ -772,6 +777,123 @@ export async function postUnitPostVerification(pctx: PostUnitContext): Promise<"
772
777
  }
773
778
  }
774
779
 
780
+ // ── Pre-execution checks (after plan-slice completes) ──
781
+ if (
782
+ s.currentUnit &&
783
+ s.currentUnit.type === "plan-slice"
784
+ ) {
785
+ let preExecPauseNeeded = false;
786
+ await runSafely("postUnitPostVerification", "pre-execution-checks", async () => {
787
+ try {
788
+ // Check preferences — respect enhanced_verification and enhanced_verification_pre
789
+ const prefs = loadEffectiveGSDPreferences()?.preferences;
790
+ const enhancedEnabled = prefs?.enhanced_verification !== false; // default true
791
+ const preEnabled = prefs?.enhanced_verification_pre !== false; // default true
792
+
793
+ if (!enhancedEnabled || !preEnabled) {
794
+ debugLog("postUnitPostVerification", {
795
+ phase: "pre-execution-checks",
796
+ skipped: true,
797
+ reason: "disabled by preferences",
798
+ });
799
+ return;
800
+ }
801
+
802
+ // Parse the unit ID to get milestone/slice IDs
803
+ const { milestone: mid, slice: sid } = parseUnitId(s.currentUnit!.id);
804
+ if (!mid || !sid) {
805
+ debugLog("postUnitPostVerification", {
806
+ phase: "pre-execution-checks",
807
+ skipped: true,
808
+ reason: "could not parse milestone/slice from unit ID",
809
+ });
810
+ return;
811
+ }
812
+
813
+ // Get tasks for this slice from DB
814
+ const tasks = getSliceTasks(mid, sid);
815
+ if (tasks.length === 0) {
816
+ debugLog("postUnitPostVerification", {
817
+ phase: "pre-execution-checks",
818
+ skipped: true,
819
+ reason: "no tasks found for slice",
820
+ });
821
+ return;
822
+ }
823
+
824
+ // Run pre-execution checks
825
+ const result: PreExecutionResult = await runPreExecutionChecks(tasks, s.basePath);
826
+
827
+ // Log summary to stderr in existing verification output format
828
+ const emoji = result.status === "pass" ? "✅" : result.status === "warn" ? "⚠️" : "❌";
829
+ process.stderr.write(
830
+ `gsd-pre-exec: ${emoji} Pre-execution checks ${result.status} for ${mid}/${sid} (${result.durationMs}ms)\n`,
831
+ );
832
+
833
+ // Log individual check results
834
+ for (const check of result.checks) {
835
+ const checkEmoji = check.passed ? "✓" : check.blocking ? "✗" : "⚠";
836
+ process.stderr.write(
837
+ `gsd-pre-exec: ${checkEmoji} [${check.category}] ${check.target}: ${check.message}\n`,
838
+ );
839
+ }
840
+
841
+ // Write evidence JSON to slice artifacts directory
842
+ const slicePath = resolveSlicePath(s.basePath, mid, sid);
843
+ if (slicePath) {
844
+ writePreExecutionEvidence(result, slicePath, mid, sid);
845
+ }
846
+
847
+ // Notify UI
848
+ if (result.status === "fail") {
849
+ const blockingCount = result.checks.filter(c => !c.passed && c.blocking).length;
850
+ ctx.ui.notify(
851
+ `Pre-execution checks failed: ${blockingCount} blocking issue${blockingCount === 1 ? "" : "s"} found`,
852
+ "error",
853
+ );
854
+ preExecPauseNeeded = true;
855
+ } else if (result.status === "warn") {
856
+ ctx.ui.notify(
857
+ `Pre-execution checks passed with warnings`,
858
+ "warning",
859
+ );
860
+ // Strict mode: treat warnings as blocking
861
+ if (prefs?.enhanced_verification_strict === true) {
862
+ preExecPauseNeeded = true;
863
+ }
864
+ }
865
+
866
+ debugLog("postUnitPostVerification", {
867
+ phase: "pre-execution-checks",
868
+ status: result.status,
869
+ checkCount: result.checks.length,
870
+ durationMs: result.durationMs,
871
+ });
872
+ } catch (preExecError) {
873
+ // Fail-closed: if runPreExecutionChecks throws, pause auto-mode instead of silently continuing
874
+ const errorMessage = preExecError instanceof Error ? preExecError.message : String(preExecError);
875
+ debugLog("postUnitPostVerification", {
876
+ phase: "pre-execution-checks",
877
+ error: errorMessage,
878
+ failClosed: true,
879
+ });
880
+ logError("engine", `gsd-pre-exec: Pre-execution checks threw an error: ${errorMessage}`);
881
+ ctx.ui.notify(
882
+ `Pre-execution checks error: ${errorMessage} — pausing for human review`,
883
+ "error",
884
+ );
885
+ preExecPauseNeeded = true;
886
+ }
887
+ });
888
+
889
+ // Check for blocking failures after runSafely completes
890
+ if (preExecPauseNeeded) {
891
+ debugLog("postUnitPostVerification", { phase: "pre-execution-checks", pausing: true, reason: "blocking failures detected" });
892
+ await pauseAuto(ctx, pi);
893
+ return "stopped";
894
+ }
895
+ }
896
+
775
897
  // ── Triage check ──
776
898
  if (
777
899
  !s.stepMode &&
@@ -11,9 +11,10 @@
11
11
  */
12
12
 
13
13
  import type { ExtensionContext, ExtensionAPI } from "@gsd/pi-coding-agent";
14
+ import { mkdirSync, writeFileSync } from "node:fs";
14
15
  import { resolveSliceFile, resolveSlicePath } from "./paths.js";
15
16
  import { parseUnitId } from "./unit-id.js";
16
- import { isDbAvailable, getTask } from "./gsd-db.js";
17
+ import { isDbAvailable, getTask, getSliceTasks, type TaskRow } from "./gsd-db.js";
17
18
  import { loadEffectiveGSDPreferences } from "./preferences.js";
18
19
  import {
19
20
  runVerificationGate,
@@ -21,9 +22,11 @@ import {
21
22
  captureRuntimeErrors,
22
23
  runDependencyAudit,
23
24
  } from "./verification-gate.js";
24
- import { writeVerificationJSON } from "./verification-evidence.js";
25
+ import { writeVerificationJSON, type PostExecutionCheckJSON, type EvidenceJSON } from "./verification-evidence.js";
25
26
  import { logWarning } from "./workflow-logger.js";
27
+ import { runPostExecutionChecks, type PostExecutionResult } from "./post-execution-checks.js";
26
28
  import type { AutoSession } from "./auto/session.js";
29
+ import type { VerificationResult as VerificationGateResult } from "./types.js";
27
30
  import { join } from "node:path";
28
31
 
29
32
  export interface VerificationContext {
@@ -183,11 +186,140 @@ export async function runPostUnitVerification(
183
186
  return "continue";
184
187
  }
185
188
 
189
+ // ── Post-execution checks (run after main verification passes for execute-task units) ──
190
+ let postExecChecks: PostExecutionCheckJSON[] | undefined;
191
+ let postExecBlockingFailure = false;
192
+
193
+ if (result.passed && mid && sid && tid) {
194
+ // Check preferences — respect enhanced_verification and enhanced_verification_post
195
+ const enhancedEnabled = prefs?.enhanced_verification !== false; // default true
196
+ const postEnabled = prefs?.enhanced_verification_post !== false; // default true
197
+
198
+ if (enhancedEnabled && postEnabled && isDbAvailable()) {
199
+ try {
200
+ // Get the completed task from DB
201
+ const taskRow = getTask(mid, sid, tid);
202
+ if (taskRow && taskRow.key_files && taskRow.key_files.length > 0) {
203
+ // Get all tasks in the slice
204
+ const allTasks = getSliceTasks(mid, sid);
205
+ // Filter to prior completed tasks (status = 'complete' or 'done', before current task)
206
+ const priorTasks = allTasks.filter(
207
+ (t: TaskRow) =>
208
+ (t.status === "complete" || t.status === "done") &&
209
+ t.id !== tid &&
210
+ t.sequence < taskRow.sequence
211
+ );
212
+
213
+ // Run post-execution checks
214
+ const postExecResult: PostExecutionResult = runPostExecutionChecks(
215
+ taskRow,
216
+ priorTasks,
217
+ s.basePath
218
+ );
219
+
220
+ // Store checks for evidence JSON
221
+ postExecChecks = postExecResult.checks;
222
+
223
+ // Log summary to stderr with gsd-post-exec: prefix
224
+ const emoji =
225
+ postExecResult.status === "pass"
226
+ ? "✅"
227
+ : postExecResult.status === "warn"
228
+ ? "⚠️"
229
+ : "❌";
230
+ process.stderr.write(
231
+ `gsd-post-exec: ${emoji} Post-execution checks ${postExecResult.status} for ${mid}/${sid}/${tid} (${postExecResult.durationMs}ms)\n`
232
+ );
233
+
234
+ // Log individual check results
235
+ for (const check of postExecResult.checks) {
236
+ const checkEmoji = check.passed
237
+ ? "✓"
238
+ : check.blocking
239
+ ? "✗"
240
+ : "⚠";
241
+ process.stderr.write(
242
+ `gsd-post-exec: ${checkEmoji} [${check.category}] ${check.target}: ${check.message}\n`
243
+ );
244
+ }
245
+
246
+ // Check for blocking failures
247
+ if (postExecResult.status === "fail") {
248
+ postExecBlockingFailure = true;
249
+ const blockingCount = postExecResult.checks.filter(
250
+ (c) => !c.passed && c.blocking
251
+ ).length;
252
+ ctx.ui.notify(
253
+ `Post-execution checks failed: ${blockingCount} blocking issue${blockingCount === 1 ? "" : "s"} found`,
254
+ "error"
255
+ );
256
+ } else if (postExecResult.status === "warn") {
257
+ ctx.ui.notify(
258
+ `Post-execution checks passed with warnings`,
259
+ "warning"
260
+ );
261
+ // Strict mode: treat warnings as blocking
262
+ if (prefs?.enhanced_verification_strict === true) {
263
+ postExecBlockingFailure = true;
264
+ }
265
+ }
266
+ }
267
+ } catch (postExecErr) {
268
+ // Post-execution check errors are non-fatal — log and continue
269
+ logWarning("engine", `gsd-post-exec: error — ${(postExecErr as Error).message}`);
270
+ }
271
+ }
272
+ }
273
+
274
+ // Re-write verification evidence JSON with post-execution checks
275
+ if (postExecChecks && postExecChecks.length > 0 && mid && sid && tid) {
276
+ try {
277
+ const sDir = resolveSlicePath(s.basePath, mid, sid);
278
+ if (sDir) {
279
+ const tasksDir = join(sDir, "tasks");
280
+ // Add postExecutionChecks to the result for the JSON write
281
+ const resultWithPostExec = {
282
+ ...result,
283
+ // Mark as failed if there was a blocking post-exec failure
284
+ passed: result.passed && !postExecBlockingFailure,
285
+ };
286
+ // Manually write with postExecutionChecks field
287
+ writeVerificationJSONWithPostExec(
288
+ resultWithPostExec,
289
+ tasksDir,
290
+ tid,
291
+ s.currentUnit.id,
292
+ postExecChecks,
293
+ postExecBlockingFailure ? attempt + 1 : undefined,
294
+ postExecBlockingFailure ? maxRetries : undefined
295
+ );
296
+ }
297
+ } catch (evidenceErr) {
298
+ logWarning("engine", `verification-evidence: post-exec write error — ${(evidenceErr as Error).message}`);
299
+ }
300
+ }
301
+
302
+ // Update result.passed based on post-execution checks
303
+ if (postExecBlockingFailure) {
304
+ result.passed = false;
305
+ }
306
+
186
307
  // ── Auto-fix retry logic ──
187
308
  if (result.passed) {
188
309
  s.verificationRetryCount.delete(s.currentUnit.id);
189
310
  s.pendingVerificationRetry = null;
190
311
  return "continue";
312
+ } else if (postExecBlockingFailure) {
313
+ // Post-execution failures are cross-task consistency issues — retrying the same task won't fix them.
314
+ // Skip retry and pause immediately for human review.
315
+ s.verificationRetryCount.delete(s.currentUnit.id);
316
+ s.pendingVerificationRetry = null;
317
+ ctx.ui.notify(
318
+ `Post-execution checks failed — cross-task consistency issue detected, pausing for human review`,
319
+ "error",
320
+ );
321
+ await pauseAuto(ctx, pi);
322
+ return "pause";
191
323
  } else if (autoFixEnabled && attempt + 1 <= maxRetries) {
192
324
  const nextAttempt = attempt + 1;
193
325
  s.verificationRetryCount.set(s.currentUnit.id, nextAttempt);
@@ -231,3 +363,59 @@ export async function runPostUnitVerification(
231
363
  return "continue";
232
364
  }
233
365
  }
366
+
367
+ /**
368
+ * Write verification evidence JSON with post-execution checks included.
369
+ * This is a variant of writeVerificationJSON that adds the postExecutionChecks field.
370
+ */
371
+ function writeVerificationJSONWithPostExec(
372
+ result: VerificationGateResult,
373
+ tasksDir: string,
374
+ taskId: string,
375
+ unitId: string,
376
+ postExecutionChecks: PostExecutionCheckJSON[],
377
+ retryAttempt?: number,
378
+ maxRetries?: number,
379
+ ): void {
380
+ mkdirSync(tasksDir, { recursive: true });
381
+
382
+ const evidence: EvidenceJSON = {
383
+ schemaVersion: 1,
384
+ taskId,
385
+ unitId: unitId ?? taskId,
386
+ timestamp: result.timestamp,
387
+ passed: result.passed,
388
+ discoverySource: result.discoverySource,
389
+ checks: result.checks.map((check) => ({
390
+ command: check.command,
391
+ exitCode: check.exitCode,
392
+ durationMs: check.durationMs,
393
+ verdict: check.exitCode === 0 ? "pass" : "fail",
394
+ })),
395
+ ...(retryAttempt !== undefined ? { retryAttempt } : {}),
396
+ ...(maxRetries !== undefined ? { maxRetries } : {}),
397
+ postExecutionChecks,
398
+ };
399
+
400
+ if (result.runtimeErrors && result.runtimeErrors.length > 0) {
401
+ evidence.runtimeErrors = result.runtimeErrors.map(e => ({
402
+ source: e.source,
403
+ severity: e.severity,
404
+ message: e.message,
405
+ blocking: e.blocking,
406
+ }));
407
+ }
408
+
409
+ if (result.auditWarnings && result.auditWarnings.length > 0) {
410
+ evidence.auditWarnings = result.auditWarnings.map(w => ({
411
+ name: w.name,
412
+ severity: w.severity,
413
+ title: w.title,
414
+ url: w.url,
415
+ fixAvailable: w.fixAvailable,
416
+ }));
417
+ }
418
+
419
+ const filePath = join(tasksDir, `${taskId}-VERIFY.json`);
420
+ writeFileSync(filePath, JSON.stringify(evidence, null, 2) + "\n", "utf-8");
421
+ }
@@ -895,6 +895,7 @@ export async function pauseAuto(
895
895
  sessionFile: s.pausedSessionFile,
896
896
  activeEngineId: s.activeEngineId,
897
897
  activeRunDir: s.activeRunDir,
898
+ autoStartTime: s.autoStartTime,
898
899
  };
899
900
  const runtimeDir = join(gsdRoot(s.originalBasePath || s.basePath), "runtime");
900
901
  mkdirSync(runtimeDir, { recursive: true });
@@ -1137,6 +1138,7 @@ export async function startAuto(
1137
1138
  s.activeRunDir = meta.activeRunDir ?? null;
1138
1139
  s.originalBasePath = meta.originalBasePath || base;
1139
1140
  s.stepMode = meta.stepMode ?? requestedStepMode;
1141
+ s.autoStartTime = meta.autoStartTime || Date.now();
1140
1142
  s.paused = true;
1141
1143
  try { unlinkSync(pausedPath); } catch (err) { /* non-fatal */
1142
1144
  logWarning("session", `pause file cleanup failed: ${err instanceof Error ? err.message : String(err)}`, { file: "auto.ts" });
@@ -1162,6 +1164,7 @@ export async function startAuto(
1162
1164
  s.currentMilestoneId = meta.milestoneId;
1163
1165
  s.originalBasePath = meta.originalBasePath || base;
1164
1166
  s.stepMode = meta.stepMode ?? requestedStepMode;
1167
+ s.autoStartTime = meta.autoStartTime || Date.now();
1165
1168
  s.paused = true;
1166
1169
  // Clean up the persisted file — we're consuming it
1167
1170
  try { unlinkSync(pausedPath); } catch (err) { /* non-fatal */
@@ -1194,6 +1197,7 @@ export async function startAuto(
1194
1197
  s.cmdCtx = ctx;
1195
1198
  s.basePath = base;
1196
1199
  setLogBasePath(base);
1200
+ if (!s.autoStartTime || s.autoStartTime <= 0) s.autoStartTime = Date.now();
1197
1201
  s.unitDispatchCount.clear();
1198
1202
  s.unitLifetimeDispatches.clear();
1199
1203
  if (!getLedger()) initMetrics(base);
@@ -804,27 +804,39 @@ export function registerDbTools(pi: ExtensionAPI): void {
804
804
  return m ? [m[1].trim(), m[2].trim()] : [s.trim(), ""];
805
805
  };
806
806
  const coerced = { ...params };
807
- coerced.filesModified = (params.filesModified ?? []).map((f: any) => {
807
+ // Coerce simple string-array fields: LLMs sometimes pass a plain string
808
+ // instead of a single-element array (#3585).
809
+ const wrapArray = (v: any): any[] =>
810
+ v == null ? [] : Array.isArray(v) ? v : [v];
811
+ coerced.provides = wrapArray(params.provides);
812
+ coerced.keyFiles = wrapArray(params.keyFiles);
813
+ coerced.keyDecisions = wrapArray(params.keyDecisions);
814
+ coerced.patternsEstablished = wrapArray(params.patternsEstablished);
815
+ coerced.observabilitySurfaces = wrapArray(params.observabilitySurfaces);
816
+ coerced.requirementsSurfaced = wrapArray(params.requirementsSurfaced);
817
+ coerced.drillDownPaths = wrapArray(params.drillDownPaths);
818
+ coerced.affects = wrapArray(params.affects);
819
+ coerced.filesModified = wrapArray(params.filesModified).map((f: any) => {
808
820
  if (typeof f !== "string") return f;
809
821
  const [path, description] = splitPair(f);
810
822
  return { path, description };
811
823
  });
812
- coerced.requires = (params.requires ?? []).map((r: any) => {
824
+ coerced.requires = wrapArray(params.requires).map((r: any) => {
813
825
  if (typeof r !== "string") return r;
814
826
  const [slice, provides] = splitPair(r);
815
827
  return { slice, provides };
816
828
  });
817
- coerced.requirementsAdvanced = (params.requirementsAdvanced ?? []).map((r: any) => {
829
+ coerced.requirementsAdvanced = wrapArray(params.requirementsAdvanced).map((r: any) => {
818
830
  if (typeof r !== "string") return r;
819
831
  const [id, how] = splitPair(r);
820
832
  return { id, how };
821
833
  });
822
- coerced.requirementsValidated = (params.requirementsValidated ?? []).map((r: any) => {
834
+ coerced.requirementsValidated = wrapArray(params.requirementsValidated).map((r: any) => {
823
835
  if (typeof r !== "string") return r;
824
836
  const [id, proof] = splitPair(r);
825
837
  return { id, proof };
826
838
  });
827
- coerced.requirementsInvalidated = (params.requirementsInvalidated ?? []).map((r: any) => {
839
+ coerced.requirementsInvalidated = wrapArray(params.requirementsInvalidated).map((r: any) => {
828
840
  if (typeof r !== "string") return r;
829
841
  const [id, what] = splitPair(r);
830
842
  return { id, what };
@@ -884,14 +896,14 @@ export function registerDbTools(pi: ExtensionAPI): void {
884
896
  deviations: Type.Optional(Type.String({ description: "Deviations from the slice plan, or 'None.'" })),
885
897
  knownLimitations: Type.Optional(Type.String({ description: "Known limitations or gaps, or 'None.'" })),
886
898
  followUps: Type.Optional(Type.String({ description: "Follow-up work discovered during execution, or 'None.'" })),
887
- keyFiles: Type.Optional(Type.Array(Type.String(), { description: "Key files created or modified" })),
888
- keyDecisions: Type.Optional(Type.Array(Type.String(), { description: "Key decisions made during this slice" })),
889
- patternsEstablished: Type.Optional(Type.Array(Type.String(), { description: "Patterns established by this slice" })),
890
- observabilitySurfaces: Type.Optional(Type.Array(Type.String(), { description: "Observability surfaces added" })),
891
- provides: Type.Optional(Type.Array(Type.String(), { description: "What this slice provides to downstream slices" })),
892
- requirementsSurfaced: Type.Optional(Type.Array(Type.String(), { description: "New requirements surfaced" })),
893
- drillDownPaths: Type.Optional(Type.Array(Type.String(), { description: "Paths to task summaries for drill-down" })),
894
- affects: Type.Optional(Type.Array(Type.String(), { description: "Downstream slices affected" })),
899
+ keyFiles: Type.Optional(Type.Union([Type.Array(Type.String()), Type.String()], { description: "Key files created or modified" })),
900
+ keyDecisions: Type.Optional(Type.Union([Type.Array(Type.String()), Type.String()], { description: "Key decisions made during this slice" })),
901
+ patternsEstablished: Type.Optional(Type.Union([Type.Array(Type.String()), Type.String()], { description: "Patterns established by this slice" })),
902
+ observabilitySurfaces: Type.Optional(Type.Union([Type.Array(Type.String()), Type.String()], { description: "Observability surfaces added" })),
903
+ provides: Type.Optional(Type.Union([Type.Array(Type.String()), Type.String()], { description: "What this slice provides to downstream slices" })),
904
+ requirementsSurfaced: Type.Optional(Type.Union([Type.Array(Type.String()), Type.String()], { description: "New requirements surfaced" })),
905
+ drillDownPaths: Type.Optional(Type.Union([Type.Array(Type.String()), Type.String()], { description: "Paths to task summaries for drill-down" })),
906
+ affects: Type.Optional(Type.Union([Type.Array(Type.String()), Type.String()], { description: "Downstream slices affected" })),
895
907
  requirementsAdvanced: Type.Optional(Type.Array(
896
908
  Type.Union([
897
909
  Type.Object({
@@ -0,0 +1,34 @@
1
+ // GSD Extension — Notify Interceptor
2
+ // Wraps ctx.ui.notify() in-place to persist every notification through the
3
+ // notification store. Uses a WeakSet to prevent double-wrapping and handle
4
+ // UI context replacement on /reload gracefully.
5
+
6
+ import type { ExtensionContext } from "@gsd/pi-coding-agent";
7
+
8
+ import { appendNotification, type NotifySeverity } from "../notification-store.js";
9
+
10
+ // Track which ui context objects have been wrapped to prevent double-install.
11
+ // WeakSet allows GC to collect replaced uiContext instances after /reload.
12
+ const _wrappedContexts = new WeakSet<object>();
13
+
14
+ /**
15
+ * Install the notify interceptor on a context's UI object.
16
+ * Mutates ctx.ui.notify in place — the original is called after persistence.
17
+ * Safe to call multiple times; no-ops if already installed on the same ui object.
18
+ */
19
+ export function installNotifyInterceptor(ctx: ExtensionContext): void {
20
+ if (_wrappedContexts.has(ctx.ui)) return;
21
+
22
+ const originalNotify = ctx.ui.notify.bind(ctx.ui);
23
+
24
+ (ctx.ui as any).notify = (message: string, type?: "info" | "warning" | "error" | "success"): void => {
25
+ try {
26
+ appendNotification(message, (type ?? "info") as NotifySeverity, "notify");
27
+ } catch {
28
+ // Non-fatal — never let persistence break the UI
29
+ }
30
+ originalNotify(message, type);
31
+ };
32
+
33
+ _wrappedContexts.add(ctx.ui);
34
+ }
@@ -21,6 +21,9 @@ import { resetAskUserQuestionsCache } from "../../ask-user-questions.js";
21
21
  import { recordToolCall as safetyRecordToolCall, recordToolResult as safetyRecordToolResult } from "../safety/evidence-collector.js";
22
22
  import { classifyCommand } from "../safety/destructive-guard.js";
23
23
  import { logWarning as safetyLogWarning } from "../workflow-logger.js";
24
+ import { installNotifyInterceptor } from "./notify-interceptor.js";
25
+ import { initNotificationStore } from "../notification-store.js";
26
+ import { initNotificationWidget } from "../notification-widget.js";
24
27
 
25
28
  // Skip the welcome screen on the very first session_start — cli.ts already
26
29
  // printed it before the TUI launched. Only re-print on /clear (subsequent sessions).
@@ -33,6 +36,9 @@ async function syncServiceTierStatus(ctx: ExtensionContext): Promise<void> {
33
36
 
34
37
  export function registerHooks(pi: ExtensionAPI): void {
35
38
  pi.on("session_start", async (_event, ctx) => {
39
+ initNotificationStore(process.cwd());
40
+ installNotifyInterceptor(ctx);
41
+ initNotificationWidget(ctx);
36
42
  resetWriteGateState();
37
43
  resetToolCallLoopGuard();
38
44
  resetAskUserQuestionsCache();
@@ -70,6 +76,8 @@ export function registerHooks(pi: ExtensionAPI): void {
70
76
  });
71
77
 
72
78
  pi.on("session_switch", async (_event, ctx) => {
79
+ initNotificationStore(process.cwd());
80
+ installNotifyInterceptor(ctx);
73
81
  resetWriteGateState();
74
82
  resetToolCallLoopGuard();
75
83
  resetAskUserQuestionsCache();
@@ -5,6 +5,7 @@ import type { ExtensionAPI } from "@gsd/pi-coding-agent";
5
5
  import { Key } from "@gsd/pi-tui";
6
6
 
7
7
  import { GSDDashboardOverlay } from "../dashboard-overlay.js";
8
+ import { GSDNotificationOverlay } from "../notification-overlay.js";
8
9
  import { ParallelMonitorOverlay } from "../parallel-monitor-overlay.js";
9
10
  import { shortcutDesc } from "../../shared/mod.js";
10
11
 
@@ -31,6 +32,24 @@ export function registerShortcuts(pi: ExtensionAPI): void {
31
32
  },
32
33
  });
33
34
 
35
+ pi.registerShortcut(Key.ctrlAlt("n"), {
36
+ description: shortcutDesc("Open notification history", "/gsd notifications"),
37
+ handler: async (ctx) => {
38
+ await ctx.ui.custom<void>(
39
+ (tui, theme, _kb, done) => new GSDNotificationOverlay(tui, theme, () => done()),
40
+ {
41
+ overlay: true,
42
+ overlayOptions: {
43
+ width: "80%",
44
+ minWidth: 60,
45
+ maxHeight: "88%",
46
+ anchor: "center",
47
+ },
48
+ },
49
+ );
50
+ },
51
+ });
52
+
34
53
  pi.registerShortcut(Key.ctrlAlt("p"), {
35
54
  description: shortcutDesc("Open parallel worker monitor", "/gsd parallel watch"),
36
55
  handler: async (ctx) => {
@@ -264,6 +264,13 @@ function buildWorktreeContextBlock(): string {
264
264
  return "";
265
265
  }
266
266
 
267
+ /**
268
+ * Low-entropy resume intent patterns — short phrases a user types to
269
+ * continue work after a pause, rate limit, or context reset (#3615).
270
+ * Tested against the trimmed, lowercased prompt with trailing punctuation stripped.
271
+ */
272
+ const RESUME_INTENT_PATTERNS = /^(continue|resume|ok|go|go ahead|proceed|keep going|carry on|next|yes|yeah|yep|sure|do it|let's go|pick up where you left off)$/;
273
+
267
274
  async function buildGuidedExecuteContextInjection(prompt: string, basePath: string): Promise<string | null> {
268
275
  const executeMatch = prompt.match(/Execute the next task:\s+(T\d+)\s+\("([^"]+)"\)\s+in slice\s+(S\d+)\s+of milestone\s+(M\d+(?:-[a-z0-9]{6})?)/i);
269
276
  if (executeMatch) {
@@ -280,6 +287,27 @@ async function buildGuidedExecuteContextInjection(prompt: string, basePath: stri
280
287
  }
281
288
  }
282
289
 
290
+ // Fallback: low-entropy resume prompt (e.g., "continue", "ok", "go ahead")
291
+ // during an active executing task — inject task context so the agent
292
+ // doesn't rebuild from scratch (#3615).
293
+ // Intent-gated: only fire for short, resume-like prompts to avoid hijacking
294
+ // control/help/diagnostic prompts with unrelated execution context.
295
+ // Phase-gated: only fire during "executing" to avoid misrouting during
296
+ // replanning, gate evaluation, or other non-execution phases.
297
+ const trimmed = prompt.trim().toLowerCase().replace(/[.!?,]+$/g, "");
298
+ if (RESUME_INTENT_PATTERNS.test(trimmed)) {
299
+ const state = await deriveState(basePath);
300
+ if (state.phase === "executing" && state.activeTask && state.activeMilestone && state.activeSlice) {
301
+ return buildTaskExecutionContextInjection(
302
+ basePath,
303
+ state.activeMilestone.id,
304
+ state.activeSlice.id,
305
+ state.activeTask.id,
306
+ state.activeTask.title,
307
+ );
308
+ }
309
+ }
310
+
283
311
  return null;
284
312
  }
285
313
 
@@ -15,7 +15,7 @@ export interface GsdCommandDefinition {
15
15
  type CompletionMap = Record<string, readonly GsdCommandDefinition[]>;
16
16
 
17
17
  export const GSD_COMMAND_DESCRIPTION =
18
- "GSD — Get Shit Done: /gsd help|start|templates|next|auto|stop|pause|status|widget|visualize|queue|quick|discuss|capture|triage|dispatch|history|undo|undo-task|reset-slice|rate|skip|export|cleanup|mode|prefs|config|keys|hooks|run-hook|skill-health|doctor|logs|forensics|changelog|migrate|remote|steer|knowledge|new-milestone|parallel|cmux|park|unpark|init|setup|inspect|extensions|update|fast|mcp|rethink|codebase";
18
+ "GSD — Get Shit Done: /gsd help|start|templates|next|auto|stop|pause|status|widget|visualize|queue|quick|discuss|capture|triage|dispatch|history|undo|undo-task|reset-slice|rate|skip|export|cleanup|mode|prefs|config|keys|hooks|run-hook|skill-health|doctor|logs|forensics|changelog|migrate|remote|steer|knowledge|new-milestone|parallel|cmux|park|unpark|init|setup|inspect|extensions|update|fast|mcp|rethink|codebase|notifications";
19
19
 
20
20
  export const TOP_LEVEL_SUBCOMMANDS: readonly GsdCommandDefinition[] = [
21
21
  { cmd: "help", desc: "Categorized command reference with descriptions" },
@@ -48,6 +48,7 @@ export const TOP_LEVEL_SUBCOMMANDS: readonly GsdCommandDefinition[] = [
48
48
  { cmd: "hooks", desc: "Show configured post-unit and pre-dispatch hooks" },
49
49
  { cmd: "run-hook", desc: "Manually trigger a specific hook" },
50
50
  { cmd: "skill-health", desc: "Skill lifecycle dashboard" },
51
+ { cmd: "notifications", desc: "View, filter, and clear persistent notification history" },
51
52
  { cmd: "doctor", desc: "Runtime health checks with auto-fix" },
52
53
  { cmd: "logs", desc: "Browse activity logs, debug logs, and metrics" },
53
54
  { cmd: "forensics", desc: "Examine execution logs" },
@@ -110,6 +111,11 @@ const NESTED_COMPLETIONS: CompletionMap = {
110
111
  { cmd: "keys", desc: "Manage API keys" },
111
112
  { cmd: "prefs", desc: "Configure global preferences" },
112
113
  ],
114
+ notifications: [
115
+ { cmd: "clear", desc: "Clear all notifications" },
116
+ { cmd: "tail", desc: "Show last N notifications (default: 20)" },
117
+ { cmd: "filter", desc: "Filter by severity (error|warning|info|success)" },
118
+ ],
113
119
  logs: [
114
120
  { cmd: "debug", desc: "List or view debug log files" },
115
121
  { cmd: "tail", desc: "Show last N activity log summaries" },
@@ -29,6 +29,7 @@ export function showHelp(ctx: ExtensionCommandContext): void {
29
29
  " /gsd queue Show queued/dispatched units and execution order",
30
30
  " /gsd history View execution history [--cost] [--phase] [--model] [N]",
31
31
  " /gsd changelog Show categorized release notes [version]",
32
+ " /gsd notifications View persistent notification history [clear|tail|filter] (Ctrl+Alt+N)",
32
33
  "",
33
34
  "COURSE CORRECTION",
34
35
  " /gsd steer <desc> Apply user override to active work",