gsd-pi 2.81.0 → 2.82.0-dev.ed17d078d

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 (503) hide show
  1. package/README.md +60 -30
  2. package/dist/resources/.managed-resources-content-hash +1 -1
  3. package/dist/resources/extensions/browser-tools/tools/screenshot.js +1 -0
  4. package/dist/resources/extensions/browser-tools/tools/zoom.js +1 -0
  5. package/dist/resources/extensions/gsd/auto/loop.js +111 -8
  6. package/dist/resources/extensions/gsd/auto/orchestrator.js +113 -6
  7. package/dist/resources/extensions/gsd/auto/phases.js +199 -97
  8. package/dist/resources/extensions/gsd/auto/run-unit.js +66 -3
  9. package/dist/resources/extensions/gsd/auto/session.js +9 -0
  10. package/dist/resources/extensions/gsd/auto/verification-retry-policy.js +43 -0
  11. package/dist/resources/extensions/gsd/auto-dashboard.js +182 -178
  12. package/dist/resources/extensions/gsd/auto-dispatch.js +14 -11
  13. package/dist/resources/extensions/gsd/auto-post-unit.js +7 -1
  14. package/dist/resources/extensions/gsd/auto-prompts.js +11 -3
  15. package/dist/resources/extensions/gsd/auto-recovery.js +6 -181
  16. package/dist/resources/extensions/gsd/auto-runtime-state.js +5 -0
  17. package/dist/resources/extensions/gsd/auto-start.js +20 -23
  18. package/dist/resources/extensions/gsd/auto-unit-closeout.js +33 -5
  19. package/dist/resources/extensions/gsd/auto-verification.js +12 -6
  20. package/dist/resources/extensions/gsd/auto-worktree.js +8 -0
  21. package/dist/resources/extensions/gsd/auto.js +386 -106
  22. package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +13 -6
  23. package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +13 -2
  24. package/dist/resources/extensions/gsd/bootstrap/register-shortcuts.js +4 -8
  25. package/dist/resources/extensions/gsd/bootstrap/system-context.js +55 -12
  26. package/dist/resources/extensions/gsd/commands/handlers/core.js +1 -1
  27. package/dist/resources/extensions/gsd/commands/handlers/notifications-handler.js +4 -10
  28. package/dist/resources/extensions/gsd/commands/handlers/parallel.js +9 -0
  29. package/dist/resources/extensions/gsd/commands-handlers.js +15 -2
  30. package/dist/resources/extensions/gsd/context-store.js +112 -0
  31. package/dist/resources/extensions/gsd/db-writer.js +150 -84
  32. package/dist/resources/extensions/gsd/docs/preferences-reference.md +1 -1
  33. package/dist/resources/extensions/gsd/doctor-git-checks.js +41 -6
  34. package/dist/resources/extensions/gsd/git-service.js +2 -1
  35. package/dist/resources/extensions/gsd/gsd-db.js +7 -23
  36. package/dist/resources/extensions/gsd/health-widget-core.js +1 -1
  37. package/dist/resources/extensions/gsd/health-widget.js +4 -10
  38. package/dist/resources/extensions/gsd/knowledge-backfill.js +144 -0
  39. package/dist/resources/extensions/gsd/knowledge-capture.js +136 -0
  40. package/dist/resources/extensions/gsd/knowledge-parser.js +154 -0
  41. package/dist/resources/extensions/gsd/knowledge-projection.js +210 -0
  42. package/dist/resources/extensions/gsd/markdown-renderer.js +6 -96
  43. package/dist/resources/extensions/gsd/md-importer.js +1 -1
  44. package/dist/resources/extensions/gsd/memory-backfill.js +73 -17
  45. package/dist/resources/extensions/gsd/memory-consolidation-scanner.js +222 -0
  46. package/dist/resources/extensions/gsd/migrate/command.js +5 -0
  47. package/dist/resources/extensions/gsd/migrate/preview.js +9 -0
  48. package/dist/resources/extensions/gsd/migrate/transformer.js +51 -4
  49. package/dist/resources/extensions/gsd/migrate/writer.js +11 -1
  50. package/dist/resources/extensions/gsd/native-git-bridge.js +14 -14
  51. package/dist/resources/extensions/gsd/notification-overlay.js +35 -40
  52. package/dist/resources/extensions/gsd/parallel-merge.js +53 -30
  53. package/dist/resources/extensions/gsd/parallel-monitor-overlay.js +25 -33
  54. package/dist/resources/extensions/gsd/prompts/complete-slice.md +14 -12
  55. package/dist/resources/extensions/gsd/prompts/discuss-headless.md +20 -2
  56. package/dist/resources/extensions/gsd/prompts/discuss.md +20 -2
  57. package/dist/resources/extensions/gsd/prompts/system.md +2 -2
  58. package/dist/resources/extensions/gsd/provider-switch-observer.js +146 -0
  59. package/dist/resources/extensions/gsd/recovery-classification.js +15 -1
  60. package/dist/resources/extensions/gsd/session-lock.js +40 -0
  61. package/dist/resources/extensions/gsd/state-reconciliation/drift/completion.js +131 -0
  62. package/dist/resources/extensions/gsd/state-reconciliation/drift/merge-state.js +247 -0
  63. package/dist/resources/extensions/gsd/state-reconciliation/drift/project-md.js +50 -0
  64. package/dist/resources/extensions/gsd/state-reconciliation/drift/roadmap.js +87 -0
  65. package/dist/resources/extensions/gsd/state-reconciliation/drift/sketch-flag.js +50 -0
  66. package/dist/resources/extensions/gsd/state-reconciliation/drift/stale-render.js +124 -0
  67. package/dist/resources/extensions/gsd/state-reconciliation/drift/stale-worker.js +32 -0
  68. package/dist/resources/extensions/gsd/state-reconciliation/errors.js +41 -0
  69. package/dist/resources/extensions/gsd/state-reconciliation/index.js +99 -0
  70. package/dist/resources/extensions/gsd/state-reconciliation/registry.js +24 -0
  71. package/dist/resources/extensions/gsd/state-reconciliation/spawn-gate.js +43 -0
  72. package/dist/resources/extensions/gsd/state-reconciliation/types.js +3 -0
  73. package/dist/resources/extensions/gsd/state-reconciliation.js +5 -26
  74. package/dist/resources/extensions/gsd/templates/knowledge.md +2 -2
  75. package/dist/resources/extensions/gsd/tui/render-kit.js +74 -0
  76. package/dist/resources/extensions/gsd/watch/header-renderer.js +92 -69
  77. package/dist/resources/extensions/gsd/watch/splash-palette.js +10 -0
  78. package/dist/resources/extensions/gsd/workflow-mcp.js +2 -2
  79. package/dist/resources/extensions/gsd/worktree-lifecycle.js +722 -316
  80. package/dist/resources/extensions/gsd/worktree-telemetry.js +3 -1
  81. package/dist/tsconfig.extensions.tsbuildinfo +1 -1
  82. package/dist/web/standalone/.next/BUILD_ID +1 -1
  83. package/dist/web/standalone/.next/app-path-routes-manifest.json +6 -6
  84. package/dist/web/standalone/.next/build-manifest.json +3 -3
  85. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  86. package/dist/web/standalone/.next/required-server-files.json +3 -3
  87. package/dist/web/standalone/.next/server/app/_global-error/page.js +3 -3
  88. package/dist/web/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
  89. package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
  90. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  91. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  92. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  93. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  94. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  95. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  96. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  97. package/dist/web/standalone/.next/server/app/_not-found/page.js +2 -2
  98. package/dist/web/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  99. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  100. package/dist/web/standalone/.next/server/app/_not-found.rsc +3 -3
  101. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +3 -3
  102. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  103. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +3 -3
  104. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  105. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  106. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  107. package/dist/web/standalone/.next/server/app/api/boot/route.js +1 -1
  108. package/dist/web/standalone/.next/server/app/api/boot/route_client-reference-manifest.js +1 -1
  109. package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route.js +1 -1
  110. package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route_client-reference-manifest.js +1 -1
  111. package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route.js +1 -1
  112. package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route_client-reference-manifest.js +1 -1
  113. package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route.js +2 -2
  114. package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route_client-reference-manifest.js +1 -1
  115. package/dist/web/standalone/.next/server/app/api/browse-directories/route.js +1 -1
  116. package/dist/web/standalone/.next/server/app/api/browse-directories/route_client-reference-manifest.js +1 -1
  117. package/dist/web/standalone/.next/server/app/api/captures/route.js +1 -1
  118. package/dist/web/standalone/.next/server/app/api/captures/route_client-reference-manifest.js +1 -1
  119. package/dist/web/standalone/.next/server/app/api/cleanup/route.js +1 -1
  120. package/dist/web/standalone/.next/server/app/api/cleanup/route_client-reference-manifest.js +1 -1
  121. package/dist/web/standalone/.next/server/app/api/dev-mode/route.js +1 -1
  122. package/dist/web/standalone/.next/server/app/api/dev-mode/route_client-reference-manifest.js +1 -1
  123. package/dist/web/standalone/.next/server/app/api/doctor/route.js +1 -1
  124. package/dist/web/standalone/.next/server/app/api/doctor/route_client-reference-manifest.js +1 -1
  125. package/dist/web/standalone/.next/server/app/api/experimental/route.js +2 -2
  126. package/dist/web/standalone/.next/server/app/api/experimental/route_client-reference-manifest.js +1 -1
  127. package/dist/web/standalone/.next/server/app/api/export-data/route.js +1 -1
  128. package/dist/web/standalone/.next/server/app/api/export-data/route_client-reference-manifest.js +1 -1
  129. package/dist/web/standalone/.next/server/app/api/files/route.js +1 -1
  130. package/dist/web/standalone/.next/server/app/api/files/route_client-reference-manifest.js +1 -1
  131. package/dist/web/standalone/.next/server/app/api/forensics/route.js +1 -1
  132. package/dist/web/standalone/.next/server/app/api/forensics/route_client-reference-manifest.js +1 -1
  133. package/dist/web/standalone/.next/server/app/api/git/route.js +1 -1
  134. package/dist/web/standalone/.next/server/app/api/git/route_client-reference-manifest.js +1 -1
  135. package/dist/web/standalone/.next/server/app/api/history/route.js +1 -1
  136. package/dist/web/standalone/.next/server/app/api/history/route_client-reference-manifest.js +1 -1
  137. package/dist/web/standalone/.next/server/app/api/hooks/route.js +1 -1
  138. package/dist/web/standalone/.next/server/app/api/hooks/route_client-reference-manifest.js +1 -1
  139. package/dist/web/standalone/.next/server/app/api/inspect/route.js +1 -1
  140. package/dist/web/standalone/.next/server/app/api/inspect/route_client-reference-manifest.js +1 -1
  141. package/dist/web/standalone/.next/server/app/api/knowledge/route.js +1 -1
  142. package/dist/web/standalone/.next/server/app/api/knowledge/route_client-reference-manifest.js +1 -1
  143. package/dist/web/standalone/.next/server/app/api/live-state/route.js +1 -1
  144. package/dist/web/standalone/.next/server/app/api/live-state/route_client-reference-manifest.js +1 -1
  145. package/dist/web/standalone/.next/server/app/api/notifications/route.js +2 -2
  146. package/dist/web/standalone/.next/server/app/api/notifications/route_client-reference-manifest.js +1 -1
  147. package/dist/web/standalone/.next/server/app/api/onboarding/route.js +1 -1
  148. package/dist/web/standalone/.next/server/app/api/onboarding/route_client-reference-manifest.js +1 -1
  149. package/dist/web/standalone/.next/server/app/api/preferences/route.js +1 -1
  150. package/dist/web/standalone/.next/server/app/api/preferences/route_client-reference-manifest.js +1 -1
  151. package/dist/web/standalone/.next/server/app/api/projects/route.js +1 -1
  152. package/dist/web/standalone/.next/server/app/api/projects/route_client-reference-manifest.js +1 -1
  153. package/dist/web/standalone/.next/server/app/api/recovery/route.js +1 -1
  154. package/dist/web/standalone/.next/server/app/api/recovery/route_client-reference-manifest.js +1 -1
  155. package/dist/web/standalone/.next/server/app/api/remote-questions/route.js +2 -2
  156. package/dist/web/standalone/.next/server/app/api/remote-questions/route_client-reference-manifest.js +1 -1
  157. package/dist/web/standalone/.next/server/app/api/session/browser/route.js +1 -1
  158. package/dist/web/standalone/.next/server/app/api/session/browser/route_client-reference-manifest.js +1 -1
  159. package/dist/web/standalone/.next/server/app/api/session/command/route.js +1 -1
  160. package/dist/web/standalone/.next/server/app/api/session/command/route_client-reference-manifest.js +1 -1
  161. package/dist/web/standalone/.next/server/app/api/session/events/route.js +2 -2
  162. package/dist/web/standalone/.next/server/app/api/session/events/route_client-reference-manifest.js +1 -1
  163. package/dist/web/standalone/.next/server/app/api/session/manage/route.js +1 -1
  164. package/dist/web/standalone/.next/server/app/api/session/manage/route_client-reference-manifest.js +1 -1
  165. package/dist/web/standalone/.next/server/app/api/settings-data/route.js +1 -1
  166. package/dist/web/standalone/.next/server/app/api/settings-data/route_client-reference-manifest.js +1 -1
  167. package/dist/web/standalone/.next/server/app/api/shutdown/route.js +1 -1
  168. package/dist/web/standalone/.next/server/app/api/shutdown/route_client-reference-manifest.js +1 -1
  169. package/dist/web/standalone/.next/server/app/api/skill-health/route.js +1 -1
  170. package/dist/web/standalone/.next/server/app/api/skill-health/route_client-reference-manifest.js +1 -1
  171. package/dist/web/standalone/.next/server/app/api/steer/route.js +1 -1
  172. package/dist/web/standalone/.next/server/app/api/steer/route_client-reference-manifest.js +1 -1
  173. package/dist/web/standalone/.next/server/app/api/switch-root/route.js +1 -1
  174. package/dist/web/standalone/.next/server/app/api/switch-root/route_client-reference-manifest.js +1 -1
  175. package/dist/web/standalone/.next/server/app/api/terminal/input/route.js +1 -1
  176. package/dist/web/standalone/.next/server/app/api/terminal/input/route_client-reference-manifest.js +1 -1
  177. package/dist/web/standalone/.next/server/app/api/terminal/resize/route.js +2 -2
  178. package/dist/web/standalone/.next/server/app/api/terminal/resize/route_client-reference-manifest.js +1 -1
  179. package/dist/web/standalone/.next/server/app/api/terminal/sessions/route.js +1 -1
  180. package/dist/web/standalone/.next/server/app/api/terminal/sessions/route_client-reference-manifest.js +1 -1
  181. package/dist/web/standalone/.next/server/app/api/terminal/stream/route.js +2 -2
  182. package/dist/web/standalone/.next/server/app/api/terminal/stream/route_client-reference-manifest.js +1 -1
  183. package/dist/web/standalone/.next/server/app/api/terminal/upload/route.js +1 -1
  184. package/dist/web/standalone/.next/server/app/api/terminal/upload/route_client-reference-manifest.js +1 -1
  185. package/dist/web/standalone/.next/server/app/api/undo/route.js +1 -1
  186. package/dist/web/standalone/.next/server/app/api/undo/route_client-reference-manifest.js +1 -1
  187. package/dist/web/standalone/.next/server/app/api/update/route.js +1 -1
  188. package/dist/web/standalone/.next/server/app/api/update/route_client-reference-manifest.js +1 -1
  189. package/dist/web/standalone/.next/server/app/api/visualizer/route.js +1 -1
  190. package/dist/web/standalone/.next/server/app/api/visualizer/route_client-reference-manifest.js +1 -1
  191. package/dist/web/standalone/.next/server/app/index.html +1 -1
  192. package/dist/web/standalone/.next/server/app/index.rsc +4 -4
  193. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
  194. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +4 -4
  195. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  196. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +3 -3
  197. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  198. package/dist/web/standalone/.next/server/app/page.js +2 -2
  199. package/dist/web/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
  200. package/dist/web/standalone/.next/server/app-paths-manifest.json +6 -6
  201. package/dist/web/standalone/.next/server/chunks/63.js +3 -3
  202. package/dist/web/standalone/.next/server/chunks/6897.js +1 -1
  203. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  204. package/dist/web/standalone/.next/server/middleware.js +2 -2
  205. package/dist/web/standalone/.next/server/next-font-manifest.js +1 -1
  206. package/dist/web/standalone/.next/server/next-font-manifest.json +1 -1
  207. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  208. package/dist/web/standalone/.next/server/pages/500.html +1 -1
  209. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  210. package/dist/web/standalone/.next/static/chunks/app/_not-found/{page-2f24283c162b6ab3.js → page-f2a7482d42a5614b.js} +1 -1
  211. package/dist/web/standalone/.next/static/chunks/app/{layout-9ecfd95f343793f0.js → layout-a16c7a7ecdf0c2cf.js} +1 -1
  212. package/dist/web/standalone/.next/static/chunks/app/page-752f1e2ebdaa3e45.js +1 -0
  213. package/dist/web/standalone/.next/static/chunks/main-app-fdab67f7802d7832.js +1 -0
  214. package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/global-error-459824ffb8c323dd.js +1 -0
  215. package/dist/web/standalone/node_modules/node-pty/build/Makefile +2 -2
  216. package/dist/web/standalone/node_modules/node-pty/build/Release/pty.node +0 -0
  217. package/dist/web/standalone/node_modules/node-pty/build/pty.target.mk +14 -14
  218. package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api.target.mk +14 -14
  219. package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api_except.target.mk +14 -14
  220. package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api_maybe.target.mk +14 -14
  221. package/dist/web/standalone/server.js +1 -1
  222. package/dist/welcome-screen.d.ts +0 -7
  223. package/dist/welcome-screen.js +60 -69
  224. package/package.json +3 -2
  225. package/packages/daemon/package.json +2 -2
  226. package/packages/mcp-server/README.md +2 -0
  227. package/packages/mcp-server/package.json +2 -2
  228. package/packages/mcp-server/src/workflow-tools-parity.test.ts +244 -0
  229. package/packages/native/package.json +1 -1
  230. package/packages/pi-agent-core/package.json +1 -1
  231. package/packages/pi-agent-core/tsconfig.tsbuildinfo +1 -1
  232. package/packages/pi-ai/dist/index.d.ts +2 -2
  233. package/packages/pi-ai/dist/index.d.ts.map +1 -1
  234. package/packages/pi-ai/dist/index.js +1 -1
  235. package/packages/pi-ai/dist/index.js.map +1 -1
  236. package/packages/pi-ai/dist/providers/transform-messages.d.ts +11 -0
  237. package/packages/pi-ai/dist/providers/transform-messages.d.ts.map +1 -1
  238. package/packages/pi-ai/dist/providers/transform-messages.js +20 -0
  239. package/packages/pi-ai/dist/providers/transform-messages.js.map +1 -1
  240. package/packages/pi-ai/package.json +1 -1
  241. package/packages/pi-ai/src/index.ts +7 -2
  242. package/packages/pi-ai/src/providers/transform-messages.ts +24 -0
  243. package/packages/pi-ai/tsconfig.tsbuildinfo +1 -1
  244. package/packages/pi-coding-agent/dist/core/system-prompt.js +4 -4
  245. package/packages/pi-coding-agent/dist/core/system-prompt.js.map +1 -1
  246. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/assistant-message-design.test.d.ts +2 -0
  247. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/assistant-message-design.test.d.ts.map +1 -0
  248. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/assistant-message-design.test.js +47 -0
  249. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/assistant-message-design.test.js.map +1 -0
  250. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/tool-execution.test.js +76 -9
  251. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/tool-execution.test.js.map +1 -1
  252. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/user-message-design.test.d.ts +2 -0
  253. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/user-message-design.test.d.ts.map +1 -0
  254. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/user-message-design.test.js +40 -0
  255. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/user-message-design.test.js.map +1 -0
  256. package/packages/pi-coding-agent/dist/modes/interactive/components/adaptive-layout.d.ts +0 -1
  257. package/packages/pi-coding-agent/dist/modes/interactive/components/adaptive-layout.d.ts.map +1 -1
  258. package/packages/pi-coding-agent/dist/modes/interactive/components/adaptive-layout.js +30 -29
  259. package/packages/pi-coding-agent/dist/modes/interactive/components/adaptive-layout.js.map +1 -1
  260. package/packages/pi-coding-agent/dist/modes/interactive/components/adaptive-layout.test.js +10 -3
  261. package/packages/pi-coding-agent/dist/modes/interactive/components/adaptive-layout.test.js.map +1 -1
  262. package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
  263. package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.js +13 -13
  264. package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.js.map +1 -1
  265. package/packages/pi-coding-agent/dist/modes/interactive/components/bash-execution.d.ts +1 -3
  266. package/packages/pi-coding-agent/dist/modes/interactive/components/bash-execution.d.ts.map +1 -1
  267. package/packages/pi-coding-agent/dist/modes/interactive/components/bash-execution.js +58 -3
  268. package/packages/pi-coding-agent/dist/modes/interactive/components/bash-execution.js.map +1 -1
  269. package/packages/pi-coding-agent/dist/modes/interactive/components/diff.d.ts +2 -2
  270. package/packages/pi-coding-agent/dist/modes/interactive/components/diff.d.ts.map +1 -1
  271. package/packages/pi-coding-agent/dist/modes/interactive/components/diff.js +12 -6
  272. package/packages/pi-coding-agent/dist/modes/interactive/components/diff.js.map +1 -1
  273. package/packages/pi-coding-agent/dist/modes/interactive/components/footer.d.ts.map +1 -1
  274. package/packages/pi-coding-agent/dist/modes/interactive/components/footer.js +14 -41
  275. package/packages/pi-coding-agent/dist/modes/interactive/components/footer.js.map +1 -1
  276. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.d.ts +0 -1
  277. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  278. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js +86 -82
  279. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js.map +1 -1
  280. package/packages/pi-coding-agent/dist/modes/interactive/components/transcript-design.d.ts +35 -0
  281. package/packages/pi-coding-agent/dist/modes/interactive/components/transcript-design.d.ts.map +1 -0
  282. package/packages/pi-coding-agent/dist/modes/interactive/components/transcript-design.js +152 -0
  283. package/packages/pi-coding-agent/dist/modes/interactive/components/transcript-design.js.map +1 -0
  284. package/packages/pi-coding-agent/dist/modes/interactive/components/tui-style-kit.d.ts +16 -0
  285. package/packages/pi-coding-agent/dist/modes/interactive/components/tui-style-kit.d.ts.map +1 -0
  286. package/packages/pi-coding-agent/dist/modes/interactive/components/tui-style-kit.js +73 -0
  287. package/packages/pi-coding-agent/dist/modes/interactive/components/tui-style-kit.js.map +1 -0
  288. package/packages/pi-coding-agent/dist/modes/interactive/components/user-message.d.ts +1 -1
  289. package/packages/pi-coding-agent/dist/modes/interactive/components/user-message.d.ts.map +1 -1
  290. package/packages/pi-coding-agent/dist/modes/interactive/components/user-message.js +12 -8
  291. package/packages/pi-coding-agent/dist/modes/interactive/components/user-message.js.map +1 -1
  292. package/packages/pi-coding-agent/dist/modes/interactive/theme/theme-highlight.test.d.ts +2 -0
  293. package/packages/pi-coding-agent/dist/modes/interactive/theme/theme-highlight.test.d.ts.map +1 -0
  294. package/packages/pi-coding-agent/dist/modes/interactive/theme/theme-highlight.test.js +17 -0
  295. package/packages/pi-coding-agent/dist/modes/interactive/theme/theme-highlight.test.js.map +1 -0
  296. package/packages/pi-coding-agent/dist/modes/interactive/theme/theme.d.ts.map +1 -1
  297. package/packages/pi-coding-agent/dist/modes/interactive/theme/theme.js +105 -1
  298. package/packages/pi-coding-agent/dist/modes/interactive/theme/theme.js.map +1 -1
  299. package/packages/pi-coding-agent/dist/modes/interactive/theme/themes.d.ts.map +1 -1
  300. package/packages/pi-coding-agent/dist/modes/interactive/theme/themes.js +27 -26
  301. package/packages/pi-coding-agent/dist/modes/interactive/theme/themes.js.map +1 -1
  302. package/packages/pi-coding-agent/dist/modes/interactive/tui-mode.test.js +9 -6
  303. package/packages/pi-coding-agent/dist/modes/interactive/tui-mode.test.js.map +1 -1
  304. package/packages/pi-coding-agent/dist/tests/system-prompt-file-safety.test.d.ts +2 -0
  305. package/packages/pi-coding-agent/dist/tests/system-prompt-file-safety.test.d.ts.map +1 -0
  306. package/packages/pi-coding-agent/dist/tests/system-prompt-file-safety.test.js +17 -0
  307. package/packages/pi-coding-agent/dist/tests/system-prompt-file-safety.test.js.map +1 -0
  308. package/packages/pi-coding-agent/package.json +1 -1
  309. package/packages/pi-coding-agent/src/core/system-prompt.ts +4 -4
  310. package/packages/pi-coding-agent/src/modes/interactive/components/__tests__/assistant-message-design.test.ts +56 -0
  311. package/packages/pi-coding-agent/src/modes/interactive/components/__tests__/tool-execution.test.ts +113 -9
  312. package/packages/pi-coding-agent/src/modes/interactive/components/__tests__/user-message-design.test.ts +48 -0
  313. package/packages/pi-coding-agent/src/modes/interactive/components/adaptive-layout.test.ts +10 -3
  314. package/packages/pi-coding-agent/src/modes/interactive/components/adaptive-layout.ts +43 -42
  315. package/packages/pi-coding-agent/src/modes/interactive/components/assistant-message.ts +14 -14
  316. package/packages/pi-coding-agent/src/modes/interactive/components/bash-execution.ts +64 -3
  317. package/packages/pi-coding-agent/src/modes/interactive/components/diff.ts +13 -7
  318. package/packages/pi-coding-agent/src/modes/interactive/components/footer.ts +15 -42
  319. package/packages/pi-coding-agent/src/modes/interactive/components/tool-execution.ts +84 -104
  320. package/packages/pi-coding-agent/src/modes/interactive/components/transcript-design.ts +196 -0
  321. package/packages/pi-coding-agent/src/modes/interactive/components/tui-style-kit.ts +94 -0
  322. package/packages/pi-coding-agent/src/modes/interactive/components/user-message.ts +14 -9
  323. package/packages/pi-coding-agent/src/modes/interactive/theme/theme-highlight.test.ts +23 -0
  324. package/packages/pi-coding-agent/src/modes/interactive/theme/theme.ts +106 -1
  325. package/packages/pi-coding-agent/src/modes/interactive/theme/themes.ts +27 -26
  326. package/packages/pi-coding-agent/src/modes/interactive/tui-mode.test.ts +9 -6
  327. package/packages/pi-coding-agent/src/tests/system-prompt-file-safety.test.ts +22 -0
  328. package/packages/pi-coding-agent/tsconfig.tsbuildinfo +1 -1
  329. package/packages/pi-tui/dist/__tests__/overlay-layout.test.js +14 -1
  330. package/packages/pi-tui/dist/__tests__/overlay-layout.test.js.map +1 -1
  331. package/packages/pi-tui/dist/overlay-layout.d.ts.map +1 -1
  332. package/packages/pi-tui/dist/overlay-layout.js +9 -6
  333. package/packages/pi-tui/dist/overlay-layout.js.map +1 -1
  334. package/packages/pi-tui/dist/tui.d.ts.map +1 -1
  335. package/packages/pi-tui/dist/tui.js +5 -0
  336. package/packages/pi-tui/dist/tui.js.map +1 -1
  337. package/packages/pi-tui/package.json +1 -1
  338. package/packages/pi-tui/src/__tests__/overlay-layout.test.ts +20 -1
  339. package/packages/pi-tui/src/overlay-layout.ts +10 -7
  340. package/packages/pi-tui/src/tui.ts +6 -0
  341. package/packages/pi-tui/tsconfig.tsbuildinfo +1 -1
  342. package/packages/rpc-client/package.json +1 -1
  343. package/pkg/dist/modes/interactive/theme/theme-highlight.test.d.ts +2 -0
  344. package/pkg/dist/modes/interactive/theme/theme-highlight.test.d.ts.map +1 -0
  345. package/pkg/dist/modes/interactive/theme/theme-highlight.test.js +17 -0
  346. package/pkg/dist/modes/interactive/theme/theme-highlight.test.js.map +1 -0
  347. package/pkg/dist/modes/interactive/theme/theme.d.ts.map +1 -1
  348. package/pkg/dist/modes/interactive/theme/theme.js +105 -1
  349. package/pkg/dist/modes/interactive/theme/theme.js.map +1 -1
  350. package/pkg/dist/modes/interactive/theme/themes.d.ts.map +1 -1
  351. package/pkg/dist/modes/interactive/theme/themes.js +27 -26
  352. package/pkg/dist/modes/interactive/theme/themes.js.map +1 -1
  353. package/pkg/package.json +1 -1
  354. package/src/resources/extensions/browser-tools/tools/screenshot.ts +1 -0
  355. package/src/resources/extensions/browser-tools/tools/zoom.ts +1 -0
  356. package/src/resources/extensions/gsd/auto/contracts.ts +46 -11
  357. package/src/resources/extensions/gsd/auto/loop-deps.ts +9 -5
  358. package/src/resources/extensions/gsd/auto/loop.ts +113 -9
  359. package/src/resources/extensions/gsd/auto/orchestrator.ts +118 -6
  360. package/src/resources/extensions/gsd/auto/phases.ts +158 -19
  361. package/src/resources/extensions/gsd/auto/run-unit.ts +69 -4
  362. package/src/resources/extensions/gsd/auto/session.ts +10 -0
  363. package/src/resources/extensions/gsd/auto/verification-retry-policy.ts +82 -0
  364. package/src/resources/extensions/gsd/auto-dashboard.ts +230 -183
  365. package/src/resources/extensions/gsd/auto-dispatch.ts +15 -1
  366. package/src/resources/extensions/gsd/auto-post-unit.ts +7 -1
  367. package/src/resources/extensions/gsd/auto-prompts.ts +11 -3
  368. package/src/resources/extensions/gsd/auto-recovery.ts +7 -209
  369. package/src/resources/extensions/gsd/auto-runtime-state.ts +5 -0
  370. package/src/resources/extensions/gsd/auto-start.ts +22 -22
  371. package/src/resources/extensions/gsd/auto-unit-closeout.ts +51 -0
  372. package/src/resources/extensions/gsd/auto-verification.ts +12 -6
  373. package/src/resources/extensions/gsd/auto-worktree.ts +8 -0
  374. package/src/resources/extensions/gsd/auto.ts +424 -106
  375. package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +21 -6
  376. package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +12 -2
  377. package/src/resources/extensions/gsd/bootstrap/register-shortcuts.ts +5 -8
  378. package/src/resources/extensions/gsd/bootstrap/system-context.ts +58 -15
  379. package/src/resources/extensions/gsd/commands/handlers/core.ts +1 -1
  380. package/src/resources/extensions/gsd/commands/handlers/notifications-handler.ts +4 -10
  381. package/src/resources/extensions/gsd/commands/handlers/parallel.ts +12 -0
  382. package/src/resources/extensions/gsd/commands-handlers.ts +19 -2
  383. package/src/resources/extensions/gsd/context-store.ts +120 -1
  384. package/src/resources/extensions/gsd/db-writer.ts +167 -84
  385. package/src/resources/extensions/gsd/docs/preferences-reference.md +1 -1
  386. package/src/resources/extensions/gsd/doctor-git-checks.ts +44 -6
  387. package/src/resources/extensions/gsd/doctor-types.ts +2 -0
  388. package/src/resources/extensions/gsd/git-service.ts +2 -0
  389. package/src/resources/extensions/gsd/gsd-db.ts +7 -23
  390. package/src/resources/extensions/gsd/health-widget-core.ts +1 -1
  391. package/src/resources/extensions/gsd/health-widget.ts +6 -10
  392. package/src/resources/extensions/gsd/journal.ts +2 -0
  393. package/src/resources/extensions/gsd/knowledge-backfill.ts +164 -0
  394. package/src/resources/extensions/gsd/knowledge-capture.ts +160 -0
  395. package/src/resources/extensions/gsd/knowledge-parser.ts +174 -0
  396. package/src/resources/extensions/gsd/knowledge-projection.ts +241 -0
  397. package/src/resources/extensions/gsd/markdown-renderer.ts +10 -96
  398. package/src/resources/extensions/gsd/md-importer.ts +1 -1
  399. package/src/resources/extensions/gsd/memory-backfill.ts +89 -17
  400. package/src/resources/extensions/gsd/memory-consolidation-scanner.ts +277 -0
  401. package/src/resources/extensions/gsd/migrate/command.ts +5 -0
  402. package/src/resources/extensions/gsd/migrate/preview.ts +10 -0
  403. package/src/resources/extensions/gsd/migrate/transformer.ts +58 -4
  404. package/src/resources/extensions/gsd/migrate/writer.ts +14 -1
  405. package/src/resources/extensions/gsd/native-git-bridge.ts +14 -13
  406. package/src/resources/extensions/gsd/notification-overlay.ts +50 -46
  407. package/src/resources/extensions/gsd/parallel-merge.ts +61 -34
  408. package/src/resources/extensions/gsd/parallel-monitor-overlay.ts +33 -35
  409. package/src/resources/extensions/gsd/prompts/complete-slice.md +14 -12
  410. package/src/resources/extensions/gsd/prompts/discuss-headless.md +20 -2
  411. package/src/resources/extensions/gsd/prompts/discuss.md +20 -2
  412. package/src/resources/extensions/gsd/prompts/system.md +2 -2
  413. package/src/resources/extensions/gsd/provider-switch-observer.ts +185 -0
  414. package/src/resources/extensions/gsd/recovery-classification.ts +18 -1
  415. package/src/resources/extensions/gsd/session-lock.ts +41 -0
  416. package/src/resources/extensions/gsd/state-reconciliation/drift/completion.ts +172 -0
  417. package/src/resources/extensions/gsd/state-reconciliation/drift/merge-state.ts +337 -0
  418. package/src/resources/extensions/gsd/state-reconciliation/drift/project-md.ts +69 -0
  419. package/src/resources/extensions/gsd/state-reconciliation/drift/roadmap.ts +109 -0
  420. package/src/resources/extensions/gsd/state-reconciliation/drift/sketch-flag.ts +68 -0
  421. package/src/resources/extensions/gsd/state-reconciliation/drift/stale-render.ts +185 -0
  422. package/src/resources/extensions/gsd/state-reconciliation/drift/stale-worker.ts +46 -0
  423. package/src/resources/extensions/gsd/state-reconciliation/errors.ts +67 -0
  424. package/src/resources/extensions/gsd/state-reconciliation/index.ts +142 -0
  425. package/src/resources/extensions/gsd/state-reconciliation/registry.ts +27 -0
  426. package/src/resources/extensions/gsd/state-reconciliation/spawn-gate.ts +60 -0
  427. package/src/resources/extensions/gsd/state-reconciliation/types.ts +83 -0
  428. package/src/resources/extensions/gsd/state-reconciliation.ts +21 -53
  429. package/src/resources/extensions/gsd/templates/knowledge.md +2 -2
  430. package/src/resources/extensions/gsd/tests/artifact-retry-cap.test.ts +1 -1
  431. package/src/resources/extensions/gsd/tests/auto-dashboard.test.ts +99 -0
  432. package/src/resources/extensions/gsd/tests/auto-loop.test.ts +729 -176
  433. package/src/resources/extensions/gsd/tests/auto-orchestrator.test.ts +408 -4
  434. package/src/resources/extensions/gsd/tests/auto-paused-ui-cleanup.test.ts +291 -4
  435. package/src/resources/extensions/gsd/tests/auto-runtime-state.test.ts +20 -5
  436. package/src/resources/extensions/gsd/tests/auto-start-orphan-bootstrap.test.ts +18 -0
  437. package/src/resources/extensions/gsd/tests/auto-unit-closeout.test.ts +68 -0
  438. package/src/resources/extensions/gsd/tests/browser-tools-compatibility-declarations.test.ts +62 -0
  439. package/src/resources/extensions/gsd/tests/context-store-decisions-from-memories.test.ts +312 -0
  440. package/src/resources/extensions/gsd/tests/custom-engine-loop-integration.test.ts +28 -1
  441. package/src/resources/extensions/gsd/tests/db-writer.test.ts +13 -8
  442. package/src/resources/extensions/gsd/tests/decisions-projection-from-memories.test.ts +453 -0
  443. package/src/resources/extensions/gsd/tests/decisions-stop-table-writes.test.ts +348 -0
  444. package/src/resources/extensions/gsd/tests/deep-project-auto-loop.test.ts +20 -2
  445. package/src/resources/extensions/gsd/tests/dispatch-complete-milestone-guard.test.ts +44 -0
  446. package/src/resources/extensions/gsd/tests/freeform-decisions.test.ts +8 -4
  447. package/src/resources/extensions/gsd/tests/gsd-tools.test.ts +11 -7
  448. package/src/resources/extensions/gsd/tests/header-renderer.test.ts +40 -0
  449. package/src/resources/extensions/gsd/tests/headless-milestone-parity.test.ts +10 -0
  450. package/src/resources/extensions/gsd/tests/health-widget.test.ts +14 -4
  451. package/src/resources/extensions/gsd/tests/integration/doctor-git.test.ts +44 -0
  452. package/src/resources/extensions/gsd/tests/integration/git-service.test.ts +26 -0
  453. package/src/resources/extensions/gsd/tests/integration/integration-lifecycle.test.ts +13 -5
  454. package/src/resources/extensions/gsd/tests/integration/integration-proof.test.ts +1 -1
  455. package/src/resources/extensions/gsd/tests/integration/migrate-command.test.ts +48 -3
  456. package/src/resources/extensions/gsd/tests/integration/parallel-merge.test.ts +116 -24
  457. package/src/resources/extensions/gsd/tests/journal-integration.test.ts +0 -1
  458. package/src/resources/extensions/gsd/tests/knowledge-backfill-projection.test.ts +323 -0
  459. package/src/resources/extensions/gsd/tests/knowledge-capture.test.ts +242 -0
  460. package/src/resources/extensions/gsd/tests/knowledge.test.ts +47 -2
  461. package/src/resources/extensions/gsd/tests/load-knowledge-block-rules-only.test.ts +209 -0
  462. package/src/resources/extensions/gsd/tests/markdown-renderer.test.ts +1 -1
  463. package/src/resources/extensions/gsd/tests/memory-consolidation-scanner.test.ts +316 -0
  464. package/src/resources/extensions/gsd/tests/merge-conflict-stops-loop.test.ts +46 -11
  465. package/src/resources/extensions/gsd/tests/migrate-transformer.test.ts +5 -1
  466. package/src/resources/extensions/gsd/tests/migrate-writer-integration.test.ts +6 -1
  467. package/src/resources/extensions/gsd/tests/notification-overlay.test.ts +78 -41
  468. package/src/resources/extensions/gsd/tests/notifications-handler.test.ts +44 -0
  469. package/src/resources/extensions/gsd/tests/originalbase-path-comparison.test.ts +12 -217
  470. package/src/resources/extensions/gsd/tests/parallel-monitor-overlay.test.ts +38 -6
  471. package/src/resources/extensions/gsd/tests/plan-milestone-sketch-render.test.ts +157 -0
  472. package/src/resources/extensions/gsd/tests/post-exec-retry-bypass.test.ts +2 -2
  473. package/src/resources/extensions/gsd/tests/progressive-planning.test.ts +1 -1
  474. package/src/resources/extensions/gsd/tests/prompt-contracts.test.ts +32 -1
  475. package/src/resources/extensions/gsd/tests/provider-switch-observer.test.ts +252 -0
  476. package/src/resources/extensions/gsd/tests/resume-dispatch-worktree.test.ts +7 -3
  477. package/src/resources/extensions/gsd/tests/runtime-invariant-modules.test.ts +6 -3
  478. package/src/resources/extensions/gsd/tests/session-start-footer.test.ts +16 -4
  479. package/src/resources/extensions/gsd/tests/session-switch-abort-misclassification.test.ts +24 -0
  480. package/src/resources/extensions/gsd/tests/state-corruption-2945.test.ts +65 -58
  481. package/src/resources/extensions/gsd/tests/state-reconciliation-drift.test.ts +952 -0
  482. package/src/resources/extensions/gsd/tests/token-tool-gating.test.ts +4 -0
  483. package/src/resources/extensions/gsd/tests/tui-header-lifecycle.test.ts +121 -1
  484. package/src/resources/extensions/gsd/tests/tui-render-kit.test.ts +66 -0
  485. package/src/resources/extensions/gsd/tests/verification-retry-policy.test.ts +83 -0
  486. package/src/resources/extensions/gsd/tests/workflow-mcp.test.ts +6 -0
  487. package/src/resources/extensions/gsd/tests/worktree-journal-events.test.ts +158 -58
  488. package/src/resources/extensions/gsd/tests/worktree-lifecycle.test.ts +572 -118
  489. package/src/resources/extensions/gsd/tests/worktree-telemetry.test.ts +59 -2
  490. package/src/resources/extensions/gsd/tests/write-gate-planning-unit.test.ts +18 -0
  491. package/src/resources/extensions/gsd/tui/render-kit.ts +109 -0
  492. package/src/resources/extensions/gsd/watch/header-renderer.ts +121 -79
  493. package/src/resources/extensions/gsd/watch/splash-palette.ts +11 -0
  494. package/src/resources/extensions/gsd/workflow-logger.ts +4 -0
  495. package/src/resources/extensions/gsd/workflow-mcp.ts +2 -2
  496. package/src/resources/extensions/gsd/worktree-lifecycle.ts +1151 -524
  497. package/src/resources/extensions/gsd/worktree-telemetry.ts +7 -2
  498. package/dist/web/standalone/.next/static/chunks/app/page-200592a7f3baf579.js +0 -1
  499. package/dist/web/standalone/.next/static/chunks/main-app-d3d4c336195465f9.js +0 -1
  500. package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/global-error-ab5a8926e07ec673.js +0 -1
  501. package/src/resources/extensions/gsd/tests/worktree-resolver.test.ts +0 -1544
  502. /package/dist/web/standalone/.next/static/{drLMkgfHQ8lzS229_HWYR → YEvjuT-fsFfYQhDSWtueS}/_buildManifest.js +0 -0
  503. /package/dist/web/standalone/.next/static/{drLMkgfHQ8lzS229_HWYR → YEvjuT-fsFfYQhDSWtueS}/_ssgManifest.js +0 -0
@@ -0,0 +1,146 @@
1
+ // GSD-2 — ADR-005 Phase 3b: surface ProviderSwitchReport from pi-ai.
2
+ //
3
+ // pi-ai builds a ProviderSwitchReport on every cross-provider transform but
4
+ // only logs it to stderr when GSD_VERBOSE=1. This module installs a
5
+ // single-subscriber observer that surfaces non-empty reports through GSD's
6
+ // three usual telemetry surfaces:
7
+ //
8
+ // 1. UOK audit event (category model-policy, type provider-switch) — only
9
+ // when an auto trace is active.
10
+ // 2. Persistent notification (.gsd/notifications.jsonl, severity warning) —
11
+ // whenever the GSD basePath is known, so users see the loss in the
12
+ // dashboard / status surface without GSD_VERBOSE.
13
+ // 3. In-memory counter, exposed via getProviderSwitchStats() so any
14
+ // caller (dashboard, doctor, tests) can read the rollup.
15
+ import { setProviderSwitchObserver } from "@gsd/pi-ai";
16
+ import { autoSession } from "./auto-runtime-state.js";
17
+ import { appendNotification } from "./notification-store.js";
18
+ import { buildAuditEnvelope, emitUokAuditEvent } from "./uok/audit.js";
19
+ const INTERACTIVE_TRACE_KEY = "interactive";
20
+ let installed = false;
21
+ let totalSwitches = 0;
22
+ const totals = {
23
+ thinkingBlocksDropped: 0,
24
+ thinkingBlocksDowngraded: 0,
25
+ toolCallIdsRemapped: 0,
26
+ syntheticToolResultsInserted: 0,
27
+ thoughtSignaturesDropped: 0,
28
+ };
29
+ const byTrace = new Map();
30
+ let lastReport = null;
31
+ let lastAt = null;
32
+ /** Format a one-line summary suitable for a notification message. */
33
+ function summarize(report) {
34
+ const parts = [];
35
+ if (report.thinkingBlocksDropped > 0)
36
+ parts.push(`${report.thinkingBlocksDropped} thinking dropped`);
37
+ if (report.thinkingBlocksDowngraded > 0)
38
+ parts.push(`${report.thinkingBlocksDowngraded} thinking downgraded`);
39
+ if (report.toolCallIdsRemapped > 0)
40
+ parts.push(`${report.toolCallIdsRemapped} tool ids remapped`);
41
+ if (report.syntheticToolResultsInserted > 0)
42
+ parts.push(`${report.syntheticToolResultsInserted} synthetic tool results`);
43
+ if (report.thoughtSignaturesDropped > 0)
44
+ parts.push(`${report.thoughtSignaturesDropped} thought signatures dropped`);
45
+ return `Provider switch ${report.fromApi} → ${report.toApi}: ${parts.join(", ")}`;
46
+ }
47
+ function recordReport(report) {
48
+ const now = new Date().toISOString();
49
+ totalSwitches += 1;
50
+ totals.thinkingBlocksDropped += report.thinkingBlocksDropped;
51
+ totals.thinkingBlocksDowngraded += report.thinkingBlocksDowngraded;
52
+ totals.toolCallIdsRemapped += report.toolCallIdsRemapped;
53
+ totals.syntheticToolResultsInserted += report.syntheticToolResultsInserted;
54
+ totals.thoughtSignaturesDropped += report.thoughtSignaturesDropped;
55
+ lastReport = report;
56
+ lastAt = now;
57
+ const traceKey = autoSession.currentTraceId ?? INTERACTIVE_TRACE_KEY;
58
+ const existing = byTrace.get(traceKey);
59
+ if (existing) {
60
+ existing.switches += 1;
61
+ existing.lastReport = report;
62
+ existing.lastAt = now;
63
+ }
64
+ else {
65
+ byTrace.set(traceKey, { switches: 1, lastReport: report, lastAt: now });
66
+ }
67
+ }
68
+ function emitAudit(report) {
69
+ const traceId = autoSession.currentTraceId;
70
+ const basePath = autoSession.basePath;
71
+ if (!traceId || !basePath)
72
+ return;
73
+ try {
74
+ emitUokAuditEvent(basePath, buildAuditEnvelope({
75
+ traceId,
76
+ category: "model-policy",
77
+ type: "provider-switch",
78
+ payload: {
79
+ fromApi: report.fromApi,
80
+ toApi: report.toApi,
81
+ thinkingBlocksDropped: report.thinkingBlocksDropped,
82
+ thinkingBlocksDowngraded: report.thinkingBlocksDowngraded,
83
+ toolCallIdsRemapped: report.toolCallIdsRemapped,
84
+ syntheticToolResultsInserted: report.syntheticToolResultsInserted,
85
+ thoughtSignaturesDropped: report.thoughtSignaturesDropped,
86
+ },
87
+ }));
88
+ }
89
+ catch {
90
+ // Audit emission is best-effort. Counter + notification still fire.
91
+ }
92
+ }
93
+ function emitNotification(report) {
94
+ try {
95
+ appendNotification(summarize(report), "warning", "workflow-logger");
96
+ }
97
+ catch {
98
+ // Notification persistence is best-effort.
99
+ }
100
+ }
101
+ function handleReport(report) {
102
+ recordReport(report);
103
+ emitAudit(report);
104
+ emitNotification(report);
105
+ }
106
+ /**
107
+ * Install the pi-ai observer. Idempotent — calling more than once is a no-op
108
+ * after the first install.
109
+ */
110
+ export function installProviderSwitchObserver() {
111
+ if (installed)
112
+ return;
113
+ setProviderSwitchObserver(handleReport);
114
+ installed = true;
115
+ }
116
+ /** Uninstall the observer. Intended for tests. */
117
+ export function uninstallProviderSwitchObserver() {
118
+ setProviderSwitchObserver(undefined);
119
+ installed = false;
120
+ }
121
+ /** Read-only snapshot of the in-memory rollup. */
122
+ export function getProviderSwitchStats() {
123
+ const trace = {};
124
+ for (const [key, value] of byTrace) {
125
+ trace[key] = { switches: value.switches, lastReport: { ...value.lastReport }, lastAt: value.lastAt };
126
+ }
127
+ return {
128
+ totalSwitches,
129
+ totals: { ...totals },
130
+ byTrace: trace,
131
+ lastReport: lastReport ? { ...lastReport } : null,
132
+ lastAt,
133
+ };
134
+ }
135
+ /** Reset the in-memory rollup. Intended for tests. */
136
+ export function _resetProviderSwitchStats() {
137
+ totalSwitches = 0;
138
+ totals.thinkingBlocksDropped = 0;
139
+ totals.thinkingBlocksDowngraded = 0;
140
+ totals.toolCallIdsRemapped = 0;
141
+ totals.syntheticToolResultsInserted = 0;
142
+ totals.thoughtSignaturesDropped = 0;
143
+ byTrace.clear();
144
+ lastReport = null;
145
+ lastAt = null;
146
+ }
@@ -1,9 +1,15 @@
1
1
  // Project/App: GSD-2
2
2
  // File Purpose: ADR-015 Recovery Classification module for runtime failure taxonomy.
3
3
  import { classifyError, isTransient } from "./error-classifier.js";
4
+ import { ReconciliationFailedError } from "./state-reconciliation.js";
4
5
  export function classifyFailure(input) {
5
6
  const message = errorMessage(input.error);
6
- const failureKind = input.failureKind ?? inferFailureKind(message);
7
+ // ADR-017: ReconciliationFailedError is a typed throw from the State
8
+ // Reconciliation Module. Recognize it by class regardless of caller-supplied
9
+ // failureKind so the taxonomy stays consistent.
10
+ const failureKind = input.error instanceof ReconciliationFailedError
11
+ ? "reconciliation-drift"
12
+ : input.failureKind ?? inferFailureKind(message);
7
13
  switch (failureKind) {
8
14
  case "tool-schema":
9
15
  return {
@@ -45,6 +51,14 @@ export function classifyFailure(input) {
45
51
  exitReason: "verification-drift",
46
52
  remediation: "Inspect the verification artifact and reconcile the state snapshot before resuming.",
47
53
  };
54
+ case "reconciliation-drift":
55
+ return {
56
+ failureKind,
57
+ action: "escalate",
58
+ reason: `Reconciliation drift${unitSuffix(input)}: ${message}`,
59
+ exitReason: "reconciliation-drift",
60
+ remediation: "Inspect the persistent or repair-failed drift kinds reported by the State Reconciliation Module before resuming.",
61
+ };
48
62
  case "provider": {
49
63
  const providerClass = classifyError(message, input.retryAfterMs);
50
64
  return {
@@ -521,6 +521,46 @@ export function readSessionLockData(basePath) {
521
521
  export function isSessionLockProcessAlive(data) {
522
522
  return isPidAlive(data.pid);
523
523
  }
524
+ /**
525
+ * ADR-017 raw primitive: remove orphaned lock artifacts (lock dir + lock file)
526
+ * when the recorded PID is dead or no metadata is present. Mirrors the
527
+ * pre-flight cleanup logic in acquireSessionLock so the stale-worker drift
528
+ * handler can clear the orphan proactively without going through the full
529
+ * acquire path. No-op when the lock is held by an alive process.
530
+ *
531
+ * Returns true when artifacts were removed (drift was present).
532
+ */
533
+ export function removeStaleSessionLock(basePath) {
534
+ const lp = lockPath(basePath);
535
+ const gsdDir = gsdRoot(basePath);
536
+ const lockTarget = effectiveLockTarget(gsdDir);
537
+ const lockDir = lockTarget + ".lock";
538
+ const existingData = readExistingLockData(lp);
539
+ const isOrphan = !existingData ||
540
+ (typeof existingData.pid === "number" && !isPidAlive(existingData.pid));
541
+ if (!isOrphan)
542
+ return false;
543
+ let removed = false;
544
+ if (existsSync(lockDir)) {
545
+ try {
546
+ rmSync(lockDir, { recursive: true, force: true });
547
+ removed = true;
548
+ }
549
+ catch {
550
+ /* best-effort */
551
+ }
552
+ }
553
+ if (existsSync(lp)) {
554
+ try {
555
+ unlinkSync(lp);
556
+ removed = true;
557
+ }
558
+ catch {
559
+ /* best-effort */
560
+ }
561
+ }
562
+ return removed;
563
+ }
524
564
  /**
525
565
  * Returns true if we currently hold a session lock for the given path.
526
566
  */
@@ -0,0 +1,131 @@
1
+ // Project/App: GSD-2
2
+ // File Purpose: ADR-017 missing-completion-timestamp drift handler. Detects
3
+ // tasks/slices/milestones marked complete (status = 'complete' | 'done') in
4
+ // the DB but whose `completed_at` column is null, and where the on-disk
5
+ // SUMMARY.md attests to completion. Backfills `completed_at` from the
6
+ // SUMMARY.md mtime — deterministic and idempotent (re-running yields the
7
+ // same value).
8
+ import { existsSync, statSync } from "node:fs";
9
+ import { getMilestone, getMilestoneSlices, getSliceTasks, isDbAvailable, updateMilestoneStatus, updateSliceStatus, updateTaskStatus, } from "../../gsd-db.js";
10
+ import { resolveMilestoneFile, resolveSliceFile, resolveTaskFile, } from "../../paths.js";
11
+ const COMPLETE_STATUSES = new Set(["complete", "done"]);
12
+ function summaryMtimeIso(path) {
13
+ try {
14
+ return statSync(path).mtime.toISOString();
15
+ }
16
+ catch {
17
+ return null;
18
+ }
19
+ }
20
+ export function detectMissingCompletionTimestampDrift(state, ctx) {
21
+ if (!isDbAvailable())
22
+ return [];
23
+ const mid = state.activeMilestone?.id;
24
+ if (!mid)
25
+ return [];
26
+ const milestone = getMilestone(mid);
27
+ if (!milestone)
28
+ return [];
29
+ const drifts = [];
30
+ // Milestone-level
31
+ if (COMPLETE_STATUSES.has(milestone.status) &&
32
+ milestone.completed_at === null) {
33
+ const summary = resolveMilestoneFile(ctx.basePath, mid, "SUMMARY");
34
+ if (summary && existsSync(summary)) {
35
+ drifts.push({
36
+ kind: "missing-completion-timestamp",
37
+ entity: "milestone",
38
+ ids: [mid],
39
+ });
40
+ }
41
+ }
42
+ // Slice and task levels iterate independently — tasks can complete before
43
+ // the parent slice closes, so task drift must be checked even when the
44
+ // slice is still pending.
45
+ for (const slice of getMilestoneSlices(mid)) {
46
+ if (COMPLETE_STATUSES.has(slice.status) &&
47
+ slice.completed_at === null) {
48
+ const summary = resolveSliceFile(ctx.basePath, mid, slice.id, "SUMMARY");
49
+ if (summary && existsSync(summary)) {
50
+ drifts.push({
51
+ kind: "missing-completion-timestamp",
52
+ entity: "slice",
53
+ ids: [`${mid}/${slice.id}`],
54
+ });
55
+ }
56
+ }
57
+ for (const task of getSliceTasks(mid, slice.id)) {
58
+ if (!COMPLETE_STATUSES.has(task.status))
59
+ continue;
60
+ if (task.completed_at !== null)
61
+ continue;
62
+ const taskSummary = resolveTaskFile(ctx.basePath, mid, slice.id, task.id, "SUMMARY");
63
+ if (taskSummary && existsSync(taskSummary)) {
64
+ drifts.push({
65
+ kind: "missing-completion-timestamp",
66
+ entity: "task",
67
+ ids: [`${mid}/${slice.id}/${task.id}`],
68
+ });
69
+ }
70
+ }
71
+ }
72
+ return drifts;
73
+ }
74
+ export function repairMissingCompletionTimestamp(record, ctx) {
75
+ const composite = record.ids[0];
76
+ if (!composite)
77
+ return;
78
+ const parts = composite.split("/");
79
+ if (record.entity === "milestone") {
80
+ const [mid] = parts;
81
+ if (!mid)
82
+ return;
83
+ const milestone = getMilestone(mid);
84
+ if (!milestone ||
85
+ milestone.completed_at !== null ||
86
+ !COMPLETE_STATUSES.has(milestone.status))
87
+ return;
88
+ const summary = resolveMilestoneFile(ctx.basePath, mid, "SUMMARY");
89
+ const ts = summary ? summaryMtimeIso(summary) : null;
90
+ if (!ts)
91
+ return;
92
+ updateMilestoneStatus(mid, milestone.status, ts);
93
+ return;
94
+ }
95
+ if (record.entity === "slice") {
96
+ const [mid, sid] = parts;
97
+ if (!mid || !sid)
98
+ return;
99
+ const slice = getMilestoneSlices(mid).find((s) => s.id === sid);
100
+ if (!slice ||
101
+ slice.completed_at !== null ||
102
+ !COMPLETE_STATUSES.has(slice.status))
103
+ return;
104
+ const summary = resolveSliceFile(ctx.basePath, mid, sid, "SUMMARY");
105
+ const ts = summary ? summaryMtimeIso(summary) : null;
106
+ if (!ts)
107
+ return;
108
+ updateSliceStatus(mid, sid, slice.status, ts);
109
+ return;
110
+ }
111
+ if (record.entity === "task") {
112
+ const [mid, sid, tid] = parts;
113
+ if (!mid || !sid || !tid)
114
+ return;
115
+ const task = getSliceTasks(mid, sid).find((t) => t.id === tid);
116
+ if (!task ||
117
+ task.completed_at !== null ||
118
+ !COMPLETE_STATUSES.has(task.status))
119
+ return;
120
+ const summary = resolveTaskFile(ctx.basePath, mid, sid, tid, "SUMMARY");
121
+ const ts = summary ? summaryMtimeIso(summary) : null;
122
+ if (!ts)
123
+ return;
124
+ updateTaskStatus(mid, sid, tid, task.status, ts);
125
+ }
126
+ }
127
+ export const completionTimestampHandler = {
128
+ kind: "missing-completion-timestamp",
129
+ detect: detectMissingCompletionTimestampDrift,
130
+ repair: repairMissingCompletionTimestamp,
131
+ };
@@ -0,0 +1,247 @@
1
+ // Project/App: GSD-2
2
+ // File Purpose: ADR-017 unmerged-merge-state drift handler. Relocated from
3
+ // auto-recovery.ts as part of issue #5701. Owns:
4
+ // - rebase/cherry-pick/revert leftover cleanup (#4980 HIGH-7)
5
+ // - MERGE_HEAD / SQUASH_MSG reconciliation with auto-resolve of .gsd/
6
+ // conflicts (#530, #2542)
7
+ import { execFileSync } from "node:child_process";
8
+ import { existsSync, unlinkSync } from "node:fs";
9
+ import { isAbsolute, join, resolve } from "node:path";
10
+ import { getErrorMessage } from "../../error-utils.js";
11
+ import { nativeAddPaths, nativeCheckoutTheirs, nativeCommit, nativeConflictFiles, nativeMergeAbort, nativeRebaseAbort, nativeResetHard, } from "../../native-git-bridge.js";
12
+ import { logError, logWarning } from "../../workflow-logger.js";
13
+ const SILENT_NOTIFY = () => { };
14
+ function resolveGitDir(basePath) {
15
+ try {
16
+ const gitDir = execFileSync("git", ["rev-parse", "--git-dir"], {
17
+ cwd: basePath,
18
+ stdio: ["ignore", "pipe", "pipe"],
19
+ encoding: "utf-8",
20
+ }).trim();
21
+ if (gitDir.length > 0) {
22
+ return isAbsolute(gitDir) ? gitDir : resolve(basePath, gitDir);
23
+ }
24
+ }
25
+ catch (err) {
26
+ logWarning("recovery", `gitdir resolution failed: ${getErrorMessage(err)}`);
27
+ }
28
+ return join(basePath, ".git");
29
+ }
30
+ /**
31
+ * Best-effort abort of a pending merge/squash and hard-reset to HEAD.
32
+ * Handles both real merges (MERGE_HEAD) and squash merges (SQUASH_MSG).
33
+ */
34
+ function abortAndResetMerge(basePath, hasMergeHead, squashMsgPath) {
35
+ if (hasMergeHead) {
36
+ try {
37
+ nativeMergeAbort(basePath);
38
+ }
39
+ catch (err) {
40
+ /* best-effort */
41
+ logWarning("recovery", `git merge-abort failed: ${err instanceof Error ? err.message : String(err)}`);
42
+ }
43
+ }
44
+ else if (squashMsgPath) {
45
+ try {
46
+ unlinkSync(squashMsgPath);
47
+ }
48
+ catch (err) {
49
+ /* best-effort */
50
+ logWarning("recovery", `file unlink failed: ${err instanceof Error ? err.message : String(err)}`);
51
+ }
52
+ }
53
+ try {
54
+ nativeResetHard(basePath);
55
+ }
56
+ catch (err) {
57
+ /* best-effort */
58
+ logError("recovery", `git reset failed: ${err instanceof Error ? err.message : String(err)}`);
59
+ }
60
+ }
61
+ /**
62
+ * Detect and abort other in-progress git operations left behind by a SIGKILL'd
63
+ * worker (rebase, cherry-pick, revert). Without this, a killed worker
64
+ * mid-rebase leaves `.git/rebase-merge/` or `.git/CHERRY_PICK_HEAD` and the
65
+ * worktree is wedged until the user manually runs the matching `--abort`.
66
+ *
67
+ * Called before merge-state reconciliation because these states block any
68
+ * subsequent merge/commit operation. (#4980 HIGH-7)
69
+ */
70
+ function reconcileOtherInProgressGitOps(basePath, notify) {
71
+ const gitDir = resolveGitDir(basePath);
72
+ const states = [
73
+ {
74
+ label: "rebase",
75
+ indicators: [join(gitDir, "rebase-merge"), join(gitDir, "rebase-apply")],
76
+ abort: () => nativeRebaseAbort(basePath),
77
+ },
78
+ {
79
+ label: "cherry-pick",
80
+ indicators: [join(gitDir, "CHERRY_PICK_HEAD")],
81
+ abort: () => {
82
+ try {
83
+ execFileSync("git", ["cherry-pick", "--abort"], {
84
+ cwd: basePath,
85
+ stdio: ["ignore", "pipe", "pipe"],
86
+ encoding: "utf-8",
87
+ });
88
+ }
89
+ catch (err) {
90
+ throw new Error(`cherry-pick --abort failed: ${getErrorMessage(err)}`);
91
+ }
92
+ },
93
+ },
94
+ {
95
+ label: "revert",
96
+ indicators: [join(gitDir, "REVERT_HEAD")],
97
+ abort: () => {
98
+ try {
99
+ execFileSync("git", ["revert", "--abort"], {
100
+ cwd: basePath,
101
+ stdio: ["ignore", "pipe", "pipe"],
102
+ encoding: "utf-8",
103
+ });
104
+ }
105
+ catch (err) {
106
+ throw new Error(`revert --abort failed: ${getErrorMessage(err)}`);
107
+ }
108
+ },
109
+ },
110
+ ];
111
+ let reconciled = false;
112
+ for (const s of states) {
113
+ const present = s.indicators.some((p) => existsSync(p));
114
+ if (!present)
115
+ continue;
116
+ try {
117
+ s.abort();
118
+ notify(`Detected leftover ${s.label} state from prior session — aborted.`, "warning");
119
+ reconciled = true;
120
+ }
121
+ catch (err) {
122
+ logError("recovery", `${s.label} abort failed: ${getErrorMessage(err)}`);
123
+ notify(`Detected leftover ${s.label} state but auto-abort failed. ` +
124
+ `Run \`git ${s.label} --abort\` manually before retrying.`, "error");
125
+ return "blocked";
126
+ }
127
+ }
128
+ return reconciled ? "reconciled" : "clean";
129
+ }
130
+ /**
131
+ * Core: detect leftover merge state and reconcile it. Takes a NotifyFn so the
132
+ * legacy reconcileMergeState(basePath, ctx) wrapper and the drift handler can
133
+ * both call it — the drift handler uses SILENT_NOTIFY.
134
+ */
135
+ function reconcileMergeStateCore(basePath, notify) {
136
+ // First, abort any rebase/cherry-pick/revert left over from a SIGKILL'd
137
+ // worker. Doing this before the merge-state check unblocks any merge that
138
+ // would otherwise refuse with "you have unfinished operation". (HIGH-7)
139
+ const otherOpsResult = reconcileOtherInProgressGitOps(basePath, notify);
140
+ if (otherOpsResult === "blocked")
141
+ return "blocked";
142
+ const gitDir = resolveGitDir(basePath);
143
+ const mergeHeadPath = join(gitDir, "MERGE_HEAD");
144
+ const squashMsgPath = join(gitDir, "SQUASH_MSG");
145
+ const hasMergeHead = existsSync(mergeHeadPath);
146
+ const hasSquashMsg = existsSync(squashMsgPath);
147
+ if (!hasMergeHead && !hasSquashMsg) {
148
+ return otherOpsResult === "reconciled" ? "reconciled" : "clean";
149
+ }
150
+ const conflictedFiles = nativeConflictFiles(basePath);
151
+ if (conflictedFiles.length === 0) {
152
+ // All conflicts resolved — finalize the merge/squash commit
153
+ try {
154
+ const commitSha = nativeCommit(basePath, "chore(gsd): reconcile merge state");
155
+ if (commitSha) {
156
+ const mode = hasMergeHead ? "merge" : "squash commit";
157
+ notify(`Finalized leftover ${mode} from prior session.`, "info");
158
+ }
159
+ else {
160
+ notify("No new commit needed for leftover merge/squash state — already committed.", "info");
161
+ }
162
+ }
163
+ catch (err) {
164
+ const errorMessage = getErrorMessage(err);
165
+ notify(`Failed to finalize leftover merge/squash commit: ${errorMessage}`, "error");
166
+ return "blocked";
167
+ }
168
+ }
169
+ else {
170
+ // Still conflicted — try auto-resolving .gsd/ state file conflicts (#530)
171
+ const gsdConflicts = conflictedFiles.filter((f) => f.startsWith(".gsd/"));
172
+ const codeConflicts = conflictedFiles.filter((f) => !f.startsWith(".gsd/"));
173
+ if (gsdConflicts.length > 0 && codeConflicts.length === 0) {
174
+ let resolved = true;
175
+ try {
176
+ nativeCheckoutTheirs(basePath, gsdConflicts);
177
+ nativeAddPaths(basePath, gsdConflicts);
178
+ }
179
+ catch (e) {
180
+ logError("recovery", `auto-resolve .gsd/ conflicts failed: ${e.message}`);
181
+ resolved = false;
182
+ }
183
+ if (resolved) {
184
+ try {
185
+ nativeCommit(basePath, "chore: auto-resolve .gsd/ state file conflicts");
186
+ notify(`Auto-resolved ${gsdConflicts.length} .gsd/ state file conflict(s) from prior merge.`, "info");
187
+ }
188
+ catch (e) {
189
+ logError("recovery", `auto-commit .gsd/ conflict resolution failed: ${e.message}`);
190
+ resolved = false;
191
+ }
192
+ }
193
+ if (!resolved) {
194
+ abortAndResetMerge(basePath, hasMergeHead, squashMsgPath);
195
+ notify("Detected leftover merge state — auto-resolve failed, cleaned up. Re-deriving state.", "warning");
196
+ }
197
+ }
198
+ else {
199
+ // Code conflicts present — fail safe and preserve any manual resolution
200
+ // work instead of discarding it with merge --abort/reset --hard.
201
+ notify("Detected leftover merge state with unresolved code conflicts. Auto-mode will pause without modifying the worktree so manual conflict resolution is preserved.", "error");
202
+ return "blocked";
203
+ }
204
+ }
205
+ return "reconciled";
206
+ }
207
+ /**
208
+ * Legacy entry point preserved for existing callers (auto.ts, auto/phases.ts
209
+ * via loop-deps, integration tests). New code prefers the drift handler.
210
+ */
211
+ export function reconcileMergeState(basePath, ctx) {
212
+ return reconcileMergeStateCore(basePath, (message, severity) => ctx.ui.notify(message, severity));
213
+ }
214
+ function hasMergeStateLeftovers(basePath) {
215
+ const gitDir = resolveGitDir(basePath);
216
+ return (existsSync(join(gitDir, "MERGE_HEAD")) ||
217
+ existsSync(join(gitDir, "SQUASH_MSG")) ||
218
+ existsSync(join(gitDir, "rebase-merge")) ||
219
+ existsSync(join(gitDir, "rebase-apply")) ||
220
+ existsSync(join(gitDir, "CHERRY_PICK_HEAD")) ||
221
+ existsSync(join(gitDir, "REVERT_HEAD")));
222
+ }
223
+ export function detectMergeStateDrift(_state, ctx) {
224
+ if (hasMergeStateLeftovers(ctx.basePath)) {
225
+ return [{ kind: "unmerged-merge-state", basePath: ctx.basePath }];
226
+ }
227
+ return [];
228
+ }
229
+ /**
230
+ * Repair: invoke the reconciliation core with a silent notify. If the
231
+ * underlying reconciliation reports "blocked" (e.g., unresolved code
232
+ * conflicts present), throw so reconcileBeforeDispatch surfaces the drift
233
+ * via ReconciliationFailedError.
234
+ */
235
+ export function repairMergeStateDrift(record) {
236
+ const result = reconcileMergeStateCore(record.basePath, SILENT_NOTIFY);
237
+ if (result === "blocked") {
238
+ throw new Error(`Merge state reconciliation blocked for ${record.basePath} — likely unresolved code conflicts. Manual intervention required.`);
239
+ }
240
+ }
241
+ export const mergeStateHandler = {
242
+ kind: "unmerged-merge-state",
243
+ detect: detectMergeStateDrift,
244
+ repair: (record) => {
245
+ repairMergeStateDrift(record);
246
+ },
247
+ };
@@ -0,0 +1,50 @@
1
+ // Project/App: GSD-2
2
+ // File Purpose: ADR-017 unregistered-milestone drift handler. Detects
3
+ // milestones whose on-disk directory has meaningful content (ROADMAP/
4
+ // CONTEXT/SUMMARY) but no DB row, then runs the markdown importer to
5
+ // reconcile. PROJECT.md is the human-facing index — the importer's source
6
+ // of truth is the .gsd/milestones/ directory tree.
7
+ import { existsSync } from "node:fs";
8
+ import { getMilestone, isDbAvailable } from "../../gsd-db.js";
9
+ import { migrateHierarchyToDb } from "../../md-importer.js";
10
+ import { findMilestoneIds } from "../../milestone-ids.js";
11
+ import { resolveMilestoneFile } from "../../paths.js";
12
+ function milestoneHasContent(basePath, milestoneId) {
13
+ const roadmap = resolveMilestoneFile(basePath, milestoneId, "ROADMAP");
14
+ const context = resolveMilestoneFile(basePath, milestoneId, "CONTEXT");
15
+ const summary = resolveMilestoneFile(basePath, milestoneId, "SUMMARY");
16
+ return ((roadmap !== null && existsSync(roadmap)) ||
17
+ (context !== null && existsSync(context)) ||
18
+ (summary !== null && existsSync(summary)));
19
+ }
20
+ export function detectUnregisteredMilestoneDrift(_state, ctx) {
21
+ if (!isDbAvailable())
22
+ return [];
23
+ const drifts = [];
24
+ for (const milestoneId of findMilestoneIds(ctx.basePath)) {
25
+ if (getMilestone(milestoneId))
26
+ continue;
27
+ if (!milestoneHasContent(ctx.basePath, milestoneId))
28
+ continue;
29
+ drifts.push({ kind: "unregistered-milestone", milestoneId });
30
+ }
31
+ return drifts;
32
+ }
33
+ /**
34
+ * Repair: invoke the markdown importer. migrateHierarchyToDb walks the same
35
+ * findMilestoneIds list the detector uses and INSERTs OR IGNOREs every
36
+ * missing milestone (and its slices/tasks) — idempotent under cap=2 retry.
37
+ *
38
+ * Note: even though we receive one record at a time, the importer is a
39
+ * project-wide operation. Repeated invocation across multiple drift records
40
+ * in the same pass is wasteful but safe; a future optimization could
41
+ * coalesce by checking whether the importer has already run this pass.
42
+ */
43
+ export function repairUnregisteredMilestone(_record, ctx) {
44
+ migrateHierarchyToDb(ctx.basePath);
45
+ }
46
+ export const unregisteredMilestoneHandler = {
47
+ kind: "unregistered-milestone",
48
+ detect: detectUnregisteredMilestoneDrift,
49
+ repair: repairUnregisteredMilestone,
50
+ };