gsd-pi 2.81.0 → 2.82.0-dev.725028083

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 (482) 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/phases.js +199 -97
  7. package/dist/resources/extensions/gsd/auto/run-unit.js +66 -3
  8. package/dist/resources/extensions/gsd/auto/session.js +9 -0
  9. package/dist/resources/extensions/gsd/auto/verification-retry-policy.js +43 -0
  10. package/dist/resources/extensions/gsd/auto-dashboard.js +182 -178
  11. package/dist/resources/extensions/gsd/auto-dispatch.js +14 -11
  12. package/dist/resources/extensions/gsd/auto-post-unit.js +7 -1
  13. package/dist/resources/extensions/gsd/auto-prompts.js +11 -3
  14. package/dist/resources/extensions/gsd/auto-recovery.js +6 -181
  15. package/dist/resources/extensions/gsd/auto-runtime-state.js +5 -0
  16. package/dist/resources/extensions/gsd/auto-start.js +20 -23
  17. package/dist/resources/extensions/gsd/auto-unit-closeout.js +33 -5
  18. package/dist/resources/extensions/gsd/auto-verification.js +12 -6
  19. package/dist/resources/extensions/gsd/auto-worktree.js +8 -0
  20. package/dist/resources/extensions/gsd/auto.js +265 -76
  21. package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +13 -6
  22. package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +13 -2
  23. package/dist/resources/extensions/gsd/bootstrap/register-shortcuts.js +4 -8
  24. package/dist/resources/extensions/gsd/bootstrap/system-context.js +55 -12
  25. package/dist/resources/extensions/gsd/commands/handlers/core.js +1 -1
  26. package/dist/resources/extensions/gsd/commands/handlers/notifications-handler.js +4 -10
  27. package/dist/resources/extensions/gsd/commands/handlers/parallel.js +9 -0
  28. package/dist/resources/extensions/gsd/commands-handlers.js +15 -2
  29. package/dist/resources/extensions/gsd/context-store.js +112 -0
  30. package/dist/resources/extensions/gsd/db-writer.js +150 -84
  31. package/dist/resources/extensions/gsd/docs/preferences-reference.md +1 -1
  32. package/dist/resources/extensions/gsd/doctor-git-checks.js +41 -6
  33. package/dist/resources/extensions/gsd/git-service.js +2 -1
  34. package/dist/resources/extensions/gsd/gsd-db.js +7 -23
  35. package/dist/resources/extensions/gsd/health-widget-core.js +1 -1
  36. package/dist/resources/extensions/gsd/health-widget.js +4 -10
  37. package/dist/resources/extensions/gsd/knowledge-backfill.js +144 -0
  38. package/dist/resources/extensions/gsd/knowledge-capture.js +136 -0
  39. package/dist/resources/extensions/gsd/knowledge-parser.js +154 -0
  40. package/dist/resources/extensions/gsd/knowledge-projection.js +210 -0
  41. package/dist/resources/extensions/gsd/markdown-renderer.js +6 -96
  42. package/dist/resources/extensions/gsd/memory-backfill.js +73 -17
  43. package/dist/resources/extensions/gsd/memory-consolidation-scanner.js +222 -0
  44. package/dist/resources/extensions/gsd/native-git-bridge.js +14 -14
  45. package/dist/resources/extensions/gsd/notification-overlay.js +35 -40
  46. package/dist/resources/extensions/gsd/parallel-merge.js +53 -30
  47. package/dist/resources/extensions/gsd/parallel-monitor-overlay.js +25 -33
  48. package/dist/resources/extensions/gsd/prompts/complete-slice.md +14 -12
  49. package/dist/resources/extensions/gsd/prompts/discuss-headless.md +20 -2
  50. package/dist/resources/extensions/gsd/prompts/discuss.md +20 -2
  51. package/dist/resources/extensions/gsd/prompts/system.md +2 -2
  52. package/dist/resources/extensions/gsd/provider-switch-observer.js +146 -0
  53. package/dist/resources/extensions/gsd/recovery-classification.js +15 -1
  54. package/dist/resources/extensions/gsd/session-lock.js +40 -0
  55. package/dist/resources/extensions/gsd/state-reconciliation/drift/completion.js +131 -0
  56. package/dist/resources/extensions/gsd/state-reconciliation/drift/merge-state.js +247 -0
  57. package/dist/resources/extensions/gsd/state-reconciliation/drift/project-md.js +50 -0
  58. package/dist/resources/extensions/gsd/state-reconciliation/drift/roadmap.js +87 -0
  59. package/dist/resources/extensions/gsd/state-reconciliation/drift/sketch-flag.js +50 -0
  60. package/dist/resources/extensions/gsd/state-reconciliation/drift/stale-render.js +124 -0
  61. package/dist/resources/extensions/gsd/state-reconciliation/drift/stale-worker.js +32 -0
  62. package/dist/resources/extensions/gsd/state-reconciliation/errors.js +41 -0
  63. package/dist/resources/extensions/gsd/state-reconciliation/index.js +99 -0
  64. package/dist/resources/extensions/gsd/state-reconciliation/registry.js +24 -0
  65. package/dist/resources/extensions/gsd/state-reconciliation/spawn-gate.js +43 -0
  66. package/dist/resources/extensions/gsd/state-reconciliation/types.js +3 -0
  67. package/dist/resources/extensions/gsd/state-reconciliation.js +5 -26
  68. package/dist/resources/extensions/gsd/templates/knowledge.md +2 -2
  69. package/dist/resources/extensions/gsd/tui/render-kit.js +74 -0
  70. package/dist/resources/extensions/gsd/watch/header-renderer.js +92 -69
  71. package/dist/resources/extensions/gsd/watch/splash-palette.js +10 -0
  72. package/dist/resources/extensions/gsd/workflow-mcp.js +2 -2
  73. package/dist/resources/extensions/gsd/worktree-lifecycle.js +722 -316
  74. package/dist/resources/extensions/gsd/worktree-telemetry.js +3 -1
  75. package/dist/tsconfig.extensions.tsbuildinfo +1 -1
  76. package/dist/web/standalone/.next/BUILD_ID +1 -1
  77. package/dist/web/standalone/.next/app-path-routes-manifest.json +15 -15
  78. package/dist/web/standalone/.next/build-manifest.json +3 -3
  79. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  80. package/dist/web/standalone/.next/required-server-files.json +3 -3
  81. package/dist/web/standalone/.next/server/app/_global-error/page.js +3 -3
  82. package/dist/web/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
  83. package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
  84. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  85. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  86. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  87. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  88. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  89. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  90. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  91. package/dist/web/standalone/.next/server/app/_not-found/page.js +2 -2
  92. package/dist/web/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  93. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  94. package/dist/web/standalone/.next/server/app/_not-found.rsc +3 -3
  95. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +3 -3
  96. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  97. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +3 -3
  98. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  99. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  100. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  101. package/dist/web/standalone/.next/server/app/api/boot/route.js +1 -1
  102. package/dist/web/standalone/.next/server/app/api/boot/route_client-reference-manifest.js +1 -1
  103. package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route.js +1 -1
  104. package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route_client-reference-manifest.js +1 -1
  105. package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route.js +1 -1
  106. package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route_client-reference-manifest.js +1 -1
  107. package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route.js +2 -2
  108. package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route_client-reference-manifest.js +1 -1
  109. package/dist/web/standalone/.next/server/app/api/browse-directories/route.js +1 -1
  110. package/dist/web/standalone/.next/server/app/api/browse-directories/route_client-reference-manifest.js +1 -1
  111. package/dist/web/standalone/.next/server/app/api/captures/route.js +1 -1
  112. package/dist/web/standalone/.next/server/app/api/captures/route_client-reference-manifest.js +1 -1
  113. package/dist/web/standalone/.next/server/app/api/cleanup/route.js +1 -1
  114. package/dist/web/standalone/.next/server/app/api/cleanup/route_client-reference-manifest.js +1 -1
  115. package/dist/web/standalone/.next/server/app/api/dev-mode/route.js +1 -1
  116. package/dist/web/standalone/.next/server/app/api/dev-mode/route_client-reference-manifest.js +1 -1
  117. package/dist/web/standalone/.next/server/app/api/doctor/route.js +1 -1
  118. package/dist/web/standalone/.next/server/app/api/doctor/route_client-reference-manifest.js +1 -1
  119. package/dist/web/standalone/.next/server/app/api/experimental/route.js +2 -2
  120. package/dist/web/standalone/.next/server/app/api/experimental/route_client-reference-manifest.js +1 -1
  121. package/dist/web/standalone/.next/server/app/api/export-data/route.js +1 -1
  122. package/dist/web/standalone/.next/server/app/api/export-data/route_client-reference-manifest.js +1 -1
  123. package/dist/web/standalone/.next/server/app/api/files/route.js +1 -1
  124. package/dist/web/standalone/.next/server/app/api/files/route_client-reference-manifest.js +1 -1
  125. package/dist/web/standalone/.next/server/app/api/forensics/route.js +1 -1
  126. package/dist/web/standalone/.next/server/app/api/forensics/route_client-reference-manifest.js +1 -1
  127. package/dist/web/standalone/.next/server/app/api/git/route.js +1 -1
  128. package/dist/web/standalone/.next/server/app/api/git/route_client-reference-manifest.js +1 -1
  129. package/dist/web/standalone/.next/server/app/api/history/route.js +1 -1
  130. package/dist/web/standalone/.next/server/app/api/history/route_client-reference-manifest.js +1 -1
  131. package/dist/web/standalone/.next/server/app/api/hooks/route.js +1 -1
  132. package/dist/web/standalone/.next/server/app/api/hooks/route_client-reference-manifest.js +1 -1
  133. package/dist/web/standalone/.next/server/app/api/inspect/route.js +1 -1
  134. package/dist/web/standalone/.next/server/app/api/inspect/route_client-reference-manifest.js +1 -1
  135. package/dist/web/standalone/.next/server/app/api/knowledge/route.js +1 -1
  136. package/dist/web/standalone/.next/server/app/api/knowledge/route_client-reference-manifest.js +1 -1
  137. package/dist/web/standalone/.next/server/app/api/live-state/route.js +1 -1
  138. package/dist/web/standalone/.next/server/app/api/live-state/route_client-reference-manifest.js +1 -1
  139. package/dist/web/standalone/.next/server/app/api/notifications/route.js +2 -2
  140. package/dist/web/standalone/.next/server/app/api/notifications/route_client-reference-manifest.js +1 -1
  141. package/dist/web/standalone/.next/server/app/api/onboarding/route.js +1 -1
  142. package/dist/web/standalone/.next/server/app/api/onboarding/route_client-reference-manifest.js +1 -1
  143. package/dist/web/standalone/.next/server/app/api/preferences/route.js +1 -1
  144. package/dist/web/standalone/.next/server/app/api/preferences/route_client-reference-manifest.js +1 -1
  145. package/dist/web/standalone/.next/server/app/api/projects/route.js +1 -1
  146. package/dist/web/standalone/.next/server/app/api/projects/route_client-reference-manifest.js +1 -1
  147. package/dist/web/standalone/.next/server/app/api/recovery/route.js +1 -1
  148. package/dist/web/standalone/.next/server/app/api/recovery/route_client-reference-manifest.js +1 -1
  149. package/dist/web/standalone/.next/server/app/api/remote-questions/route.js +2 -2
  150. package/dist/web/standalone/.next/server/app/api/remote-questions/route_client-reference-manifest.js +1 -1
  151. package/dist/web/standalone/.next/server/app/api/session/browser/route.js +1 -1
  152. package/dist/web/standalone/.next/server/app/api/session/browser/route_client-reference-manifest.js +1 -1
  153. package/dist/web/standalone/.next/server/app/api/session/command/route.js +1 -1
  154. package/dist/web/standalone/.next/server/app/api/session/command/route_client-reference-manifest.js +1 -1
  155. package/dist/web/standalone/.next/server/app/api/session/events/route.js +2 -2
  156. package/dist/web/standalone/.next/server/app/api/session/events/route_client-reference-manifest.js +1 -1
  157. package/dist/web/standalone/.next/server/app/api/session/manage/route.js +1 -1
  158. package/dist/web/standalone/.next/server/app/api/session/manage/route_client-reference-manifest.js +1 -1
  159. package/dist/web/standalone/.next/server/app/api/settings-data/route.js +1 -1
  160. package/dist/web/standalone/.next/server/app/api/settings-data/route_client-reference-manifest.js +1 -1
  161. package/dist/web/standalone/.next/server/app/api/shutdown/route.js +1 -1
  162. package/dist/web/standalone/.next/server/app/api/shutdown/route_client-reference-manifest.js +1 -1
  163. package/dist/web/standalone/.next/server/app/api/skill-health/route.js +1 -1
  164. package/dist/web/standalone/.next/server/app/api/skill-health/route_client-reference-manifest.js +1 -1
  165. package/dist/web/standalone/.next/server/app/api/steer/route.js +1 -1
  166. package/dist/web/standalone/.next/server/app/api/steer/route_client-reference-manifest.js +1 -1
  167. package/dist/web/standalone/.next/server/app/api/switch-root/route.js +1 -1
  168. package/dist/web/standalone/.next/server/app/api/switch-root/route_client-reference-manifest.js +1 -1
  169. package/dist/web/standalone/.next/server/app/api/terminal/input/route.js +1 -1
  170. package/dist/web/standalone/.next/server/app/api/terminal/input/route_client-reference-manifest.js +1 -1
  171. package/dist/web/standalone/.next/server/app/api/terminal/resize/route.js +2 -2
  172. package/dist/web/standalone/.next/server/app/api/terminal/resize/route_client-reference-manifest.js +1 -1
  173. package/dist/web/standalone/.next/server/app/api/terminal/sessions/route.js +1 -1
  174. package/dist/web/standalone/.next/server/app/api/terminal/sessions/route_client-reference-manifest.js +1 -1
  175. package/dist/web/standalone/.next/server/app/api/terminal/stream/route.js +2 -2
  176. package/dist/web/standalone/.next/server/app/api/terminal/stream/route_client-reference-manifest.js +1 -1
  177. package/dist/web/standalone/.next/server/app/api/terminal/upload/route.js +1 -1
  178. package/dist/web/standalone/.next/server/app/api/terminal/upload/route_client-reference-manifest.js +1 -1
  179. package/dist/web/standalone/.next/server/app/api/undo/route.js +1 -1
  180. package/dist/web/standalone/.next/server/app/api/undo/route_client-reference-manifest.js +1 -1
  181. package/dist/web/standalone/.next/server/app/api/update/route.js +1 -1
  182. package/dist/web/standalone/.next/server/app/api/update/route_client-reference-manifest.js +1 -1
  183. package/dist/web/standalone/.next/server/app/api/visualizer/route.js +1 -1
  184. package/dist/web/standalone/.next/server/app/api/visualizer/route_client-reference-manifest.js +1 -1
  185. package/dist/web/standalone/.next/server/app/index.html +1 -1
  186. package/dist/web/standalone/.next/server/app/index.rsc +4 -4
  187. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
  188. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +4 -4
  189. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  190. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +3 -3
  191. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  192. package/dist/web/standalone/.next/server/app/page.js +2 -2
  193. package/dist/web/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
  194. package/dist/web/standalone/.next/server/app-paths-manifest.json +15 -15
  195. package/dist/web/standalone/.next/server/chunks/63.js +3 -3
  196. package/dist/web/standalone/.next/server/chunks/6897.js +1 -1
  197. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  198. package/dist/web/standalone/.next/server/middleware.js +2 -2
  199. package/dist/web/standalone/.next/server/next-font-manifest.js +1 -1
  200. package/dist/web/standalone/.next/server/next-font-manifest.json +1 -1
  201. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  202. package/dist/web/standalone/.next/server/pages/500.html +1 -1
  203. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  204. package/dist/web/standalone/.next/static/chunks/app/_not-found/{page-2f24283c162b6ab3.js → page-f2a7482d42a5614b.js} +1 -1
  205. package/dist/web/standalone/.next/static/chunks/app/{layout-9ecfd95f343793f0.js → layout-a16c7a7ecdf0c2cf.js} +1 -1
  206. package/dist/web/standalone/.next/static/chunks/app/page-752f1e2ebdaa3e45.js +1 -0
  207. package/dist/web/standalone/.next/static/chunks/main-app-fdab67f7802d7832.js +1 -0
  208. package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/global-error-459824ffb8c323dd.js +1 -0
  209. package/dist/web/standalone/node_modules/node-pty/build/Makefile +2 -2
  210. package/dist/web/standalone/node_modules/node-pty/build/Release/pty.node +0 -0
  211. package/dist/web/standalone/node_modules/node-pty/build/pty.target.mk +14 -14
  212. package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api.target.mk +14 -14
  213. package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api_except.target.mk +14 -14
  214. package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api_maybe.target.mk +14 -14
  215. package/dist/web/standalone/server.js +1 -1
  216. package/dist/welcome-screen.d.ts +0 -7
  217. package/dist/welcome-screen.js +60 -69
  218. package/package.json +3 -2
  219. package/packages/daemon/package.json +2 -2
  220. package/packages/mcp-server/README.md +2 -0
  221. package/packages/mcp-server/package.json +2 -2
  222. package/packages/mcp-server/src/workflow-tools-parity.test.ts +244 -0
  223. package/packages/native/package.json +1 -1
  224. package/packages/pi-agent-core/package.json +1 -1
  225. package/packages/pi-agent-core/tsconfig.tsbuildinfo +1 -1
  226. package/packages/pi-ai/dist/index.d.ts +2 -2
  227. package/packages/pi-ai/dist/index.d.ts.map +1 -1
  228. package/packages/pi-ai/dist/index.js +1 -1
  229. package/packages/pi-ai/dist/index.js.map +1 -1
  230. package/packages/pi-ai/dist/providers/transform-messages.d.ts +11 -0
  231. package/packages/pi-ai/dist/providers/transform-messages.d.ts.map +1 -1
  232. package/packages/pi-ai/dist/providers/transform-messages.js +20 -0
  233. package/packages/pi-ai/dist/providers/transform-messages.js.map +1 -1
  234. package/packages/pi-ai/package.json +1 -1
  235. package/packages/pi-ai/src/index.ts +7 -2
  236. package/packages/pi-ai/src/providers/transform-messages.ts +24 -0
  237. package/packages/pi-ai/tsconfig.tsbuildinfo +1 -1
  238. package/packages/pi-coding-agent/dist/core/system-prompt.js +4 -4
  239. package/packages/pi-coding-agent/dist/core/system-prompt.js.map +1 -1
  240. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/assistant-message-design.test.d.ts +2 -0
  241. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/assistant-message-design.test.d.ts.map +1 -0
  242. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/assistant-message-design.test.js +47 -0
  243. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/assistant-message-design.test.js.map +1 -0
  244. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/tool-execution.test.js +76 -9
  245. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/tool-execution.test.js.map +1 -1
  246. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/user-message-design.test.d.ts +2 -0
  247. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/user-message-design.test.d.ts.map +1 -0
  248. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/user-message-design.test.js +40 -0
  249. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/user-message-design.test.js.map +1 -0
  250. package/packages/pi-coding-agent/dist/modes/interactive/components/adaptive-layout.d.ts +0 -1
  251. package/packages/pi-coding-agent/dist/modes/interactive/components/adaptive-layout.d.ts.map +1 -1
  252. package/packages/pi-coding-agent/dist/modes/interactive/components/adaptive-layout.js +30 -29
  253. package/packages/pi-coding-agent/dist/modes/interactive/components/adaptive-layout.js.map +1 -1
  254. package/packages/pi-coding-agent/dist/modes/interactive/components/adaptive-layout.test.js +10 -3
  255. package/packages/pi-coding-agent/dist/modes/interactive/components/adaptive-layout.test.js.map +1 -1
  256. package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
  257. package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.js +13 -13
  258. package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.js.map +1 -1
  259. package/packages/pi-coding-agent/dist/modes/interactive/components/bash-execution.d.ts +1 -3
  260. package/packages/pi-coding-agent/dist/modes/interactive/components/bash-execution.d.ts.map +1 -1
  261. package/packages/pi-coding-agent/dist/modes/interactive/components/bash-execution.js +58 -3
  262. package/packages/pi-coding-agent/dist/modes/interactive/components/bash-execution.js.map +1 -1
  263. package/packages/pi-coding-agent/dist/modes/interactive/components/diff.d.ts +2 -2
  264. package/packages/pi-coding-agent/dist/modes/interactive/components/diff.d.ts.map +1 -1
  265. package/packages/pi-coding-agent/dist/modes/interactive/components/diff.js +12 -6
  266. package/packages/pi-coding-agent/dist/modes/interactive/components/diff.js.map +1 -1
  267. package/packages/pi-coding-agent/dist/modes/interactive/components/footer.d.ts.map +1 -1
  268. package/packages/pi-coding-agent/dist/modes/interactive/components/footer.js +14 -41
  269. package/packages/pi-coding-agent/dist/modes/interactive/components/footer.js.map +1 -1
  270. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.d.ts +0 -1
  271. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  272. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js +86 -82
  273. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js.map +1 -1
  274. package/packages/pi-coding-agent/dist/modes/interactive/components/transcript-design.d.ts +35 -0
  275. package/packages/pi-coding-agent/dist/modes/interactive/components/transcript-design.d.ts.map +1 -0
  276. package/packages/pi-coding-agent/dist/modes/interactive/components/transcript-design.js +152 -0
  277. package/packages/pi-coding-agent/dist/modes/interactive/components/transcript-design.js.map +1 -0
  278. package/packages/pi-coding-agent/dist/modes/interactive/components/tui-style-kit.d.ts +16 -0
  279. package/packages/pi-coding-agent/dist/modes/interactive/components/tui-style-kit.d.ts.map +1 -0
  280. package/packages/pi-coding-agent/dist/modes/interactive/components/tui-style-kit.js +73 -0
  281. package/packages/pi-coding-agent/dist/modes/interactive/components/tui-style-kit.js.map +1 -0
  282. package/packages/pi-coding-agent/dist/modes/interactive/components/user-message.d.ts +1 -1
  283. package/packages/pi-coding-agent/dist/modes/interactive/components/user-message.d.ts.map +1 -1
  284. package/packages/pi-coding-agent/dist/modes/interactive/components/user-message.js +12 -8
  285. package/packages/pi-coding-agent/dist/modes/interactive/components/user-message.js.map +1 -1
  286. package/packages/pi-coding-agent/dist/modes/interactive/theme/theme-highlight.test.d.ts +2 -0
  287. package/packages/pi-coding-agent/dist/modes/interactive/theme/theme-highlight.test.d.ts.map +1 -0
  288. package/packages/pi-coding-agent/dist/modes/interactive/theme/theme-highlight.test.js +17 -0
  289. package/packages/pi-coding-agent/dist/modes/interactive/theme/theme-highlight.test.js.map +1 -0
  290. package/packages/pi-coding-agent/dist/modes/interactive/theme/theme.d.ts.map +1 -1
  291. package/packages/pi-coding-agent/dist/modes/interactive/theme/theme.js +105 -1
  292. package/packages/pi-coding-agent/dist/modes/interactive/theme/theme.js.map +1 -1
  293. package/packages/pi-coding-agent/dist/modes/interactive/theme/themes.d.ts.map +1 -1
  294. package/packages/pi-coding-agent/dist/modes/interactive/theme/themes.js +27 -26
  295. package/packages/pi-coding-agent/dist/modes/interactive/theme/themes.js.map +1 -1
  296. package/packages/pi-coding-agent/dist/modes/interactive/tui-mode.test.js +9 -6
  297. package/packages/pi-coding-agent/dist/modes/interactive/tui-mode.test.js.map +1 -1
  298. package/packages/pi-coding-agent/dist/tests/system-prompt-file-safety.test.d.ts +2 -0
  299. package/packages/pi-coding-agent/dist/tests/system-prompt-file-safety.test.d.ts.map +1 -0
  300. package/packages/pi-coding-agent/dist/tests/system-prompt-file-safety.test.js +17 -0
  301. package/packages/pi-coding-agent/dist/tests/system-prompt-file-safety.test.js.map +1 -0
  302. package/packages/pi-coding-agent/package.json +1 -1
  303. package/packages/pi-coding-agent/src/core/system-prompt.ts +4 -4
  304. package/packages/pi-coding-agent/src/modes/interactive/components/__tests__/assistant-message-design.test.ts +56 -0
  305. package/packages/pi-coding-agent/src/modes/interactive/components/__tests__/tool-execution.test.ts +113 -9
  306. package/packages/pi-coding-agent/src/modes/interactive/components/__tests__/user-message-design.test.ts +48 -0
  307. package/packages/pi-coding-agent/src/modes/interactive/components/adaptive-layout.test.ts +10 -3
  308. package/packages/pi-coding-agent/src/modes/interactive/components/adaptive-layout.ts +43 -42
  309. package/packages/pi-coding-agent/src/modes/interactive/components/assistant-message.ts +14 -14
  310. package/packages/pi-coding-agent/src/modes/interactive/components/bash-execution.ts +64 -3
  311. package/packages/pi-coding-agent/src/modes/interactive/components/diff.ts +13 -7
  312. package/packages/pi-coding-agent/src/modes/interactive/components/footer.ts +15 -42
  313. package/packages/pi-coding-agent/src/modes/interactive/components/tool-execution.ts +84 -104
  314. package/packages/pi-coding-agent/src/modes/interactive/components/transcript-design.ts +196 -0
  315. package/packages/pi-coding-agent/src/modes/interactive/components/tui-style-kit.ts +94 -0
  316. package/packages/pi-coding-agent/src/modes/interactive/components/user-message.ts +14 -9
  317. package/packages/pi-coding-agent/src/modes/interactive/theme/theme-highlight.test.ts +23 -0
  318. package/packages/pi-coding-agent/src/modes/interactive/theme/theme.ts +106 -1
  319. package/packages/pi-coding-agent/src/modes/interactive/theme/themes.ts +27 -26
  320. package/packages/pi-coding-agent/src/modes/interactive/tui-mode.test.ts +9 -6
  321. package/packages/pi-coding-agent/src/tests/system-prompt-file-safety.test.ts +22 -0
  322. package/packages/pi-coding-agent/tsconfig.tsbuildinfo +1 -1
  323. package/packages/pi-tui/dist/__tests__/overlay-layout.test.js +14 -1
  324. package/packages/pi-tui/dist/__tests__/overlay-layout.test.js.map +1 -1
  325. package/packages/pi-tui/dist/overlay-layout.d.ts.map +1 -1
  326. package/packages/pi-tui/dist/overlay-layout.js +9 -6
  327. package/packages/pi-tui/dist/overlay-layout.js.map +1 -1
  328. package/packages/pi-tui/package.json +1 -1
  329. package/packages/pi-tui/src/__tests__/overlay-layout.test.ts +20 -1
  330. package/packages/pi-tui/src/overlay-layout.ts +10 -7
  331. package/packages/pi-tui/tsconfig.tsbuildinfo +1 -1
  332. package/packages/rpc-client/package.json +1 -1
  333. package/pkg/dist/modes/interactive/theme/theme-highlight.test.d.ts +2 -0
  334. package/pkg/dist/modes/interactive/theme/theme-highlight.test.d.ts.map +1 -0
  335. package/pkg/dist/modes/interactive/theme/theme-highlight.test.js +17 -0
  336. package/pkg/dist/modes/interactive/theme/theme-highlight.test.js.map +1 -0
  337. package/pkg/dist/modes/interactive/theme/theme.d.ts.map +1 -1
  338. package/pkg/dist/modes/interactive/theme/theme.js +105 -1
  339. package/pkg/dist/modes/interactive/theme/theme.js.map +1 -1
  340. package/pkg/dist/modes/interactive/theme/themes.d.ts.map +1 -1
  341. package/pkg/dist/modes/interactive/theme/themes.js +27 -26
  342. package/pkg/dist/modes/interactive/theme/themes.js.map +1 -1
  343. package/pkg/package.json +1 -1
  344. package/src/resources/extensions/browser-tools/tools/screenshot.ts +1 -0
  345. package/src/resources/extensions/browser-tools/tools/zoom.ts +1 -0
  346. package/src/resources/extensions/gsd/auto/loop-deps.ts +9 -5
  347. package/src/resources/extensions/gsd/auto/loop.ts +113 -9
  348. package/src/resources/extensions/gsd/auto/phases.ts +158 -19
  349. package/src/resources/extensions/gsd/auto/run-unit.ts +69 -4
  350. package/src/resources/extensions/gsd/auto/session.ts +10 -0
  351. package/src/resources/extensions/gsd/auto/verification-retry-policy.ts +82 -0
  352. package/src/resources/extensions/gsd/auto-dashboard.ts +230 -183
  353. package/src/resources/extensions/gsd/auto-dispatch.ts +15 -1
  354. package/src/resources/extensions/gsd/auto-post-unit.ts +7 -1
  355. package/src/resources/extensions/gsd/auto-prompts.ts +11 -3
  356. package/src/resources/extensions/gsd/auto-recovery.ts +7 -209
  357. package/src/resources/extensions/gsd/auto-runtime-state.ts +5 -0
  358. package/src/resources/extensions/gsd/auto-start.ts +22 -22
  359. package/src/resources/extensions/gsd/auto-unit-closeout.ts +51 -0
  360. package/src/resources/extensions/gsd/auto-verification.ts +12 -6
  361. package/src/resources/extensions/gsd/auto-worktree.ts +8 -0
  362. package/src/resources/extensions/gsd/auto.ts +295 -75
  363. package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +21 -6
  364. package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +12 -2
  365. package/src/resources/extensions/gsd/bootstrap/register-shortcuts.ts +5 -8
  366. package/src/resources/extensions/gsd/bootstrap/system-context.ts +58 -15
  367. package/src/resources/extensions/gsd/commands/handlers/core.ts +1 -1
  368. package/src/resources/extensions/gsd/commands/handlers/notifications-handler.ts +4 -10
  369. package/src/resources/extensions/gsd/commands/handlers/parallel.ts +12 -0
  370. package/src/resources/extensions/gsd/commands-handlers.ts +19 -2
  371. package/src/resources/extensions/gsd/context-store.ts +120 -1
  372. package/src/resources/extensions/gsd/db-writer.ts +167 -84
  373. package/src/resources/extensions/gsd/docs/preferences-reference.md +1 -1
  374. package/src/resources/extensions/gsd/doctor-git-checks.ts +44 -6
  375. package/src/resources/extensions/gsd/doctor-types.ts +2 -0
  376. package/src/resources/extensions/gsd/git-service.ts +2 -0
  377. package/src/resources/extensions/gsd/gsd-db.ts +7 -23
  378. package/src/resources/extensions/gsd/health-widget-core.ts +1 -1
  379. package/src/resources/extensions/gsd/health-widget.ts +6 -10
  380. package/src/resources/extensions/gsd/journal.ts +2 -0
  381. package/src/resources/extensions/gsd/knowledge-backfill.ts +164 -0
  382. package/src/resources/extensions/gsd/knowledge-capture.ts +160 -0
  383. package/src/resources/extensions/gsd/knowledge-parser.ts +174 -0
  384. package/src/resources/extensions/gsd/knowledge-projection.ts +241 -0
  385. package/src/resources/extensions/gsd/markdown-renderer.ts +10 -96
  386. package/src/resources/extensions/gsd/memory-backfill.ts +89 -17
  387. package/src/resources/extensions/gsd/memory-consolidation-scanner.ts +277 -0
  388. package/src/resources/extensions/gsd/native-git-bridge.ts +14 -13
  389. package/src/resources/extensions/gsd/notification-overlay.ts +50 -46
  390. package/src/resources/extensions/gsd/parallel-merge.ts +61 -34
  391. package/src/resources/extensions/gsd/parallel-monitor-overlay.ts +33 -35
  392. package/src/resources/extensions/gsd/prompts/complete-slice.md +14 -12
  393. package/src/resources/extensions/gsd/prompts/discuss-headless.md +20 -2
  394. package/src/resources/extensions/gsd/prompts/discuss.md +20 -2
  395. package/src/resources/extensions/gsd/prompts/system.md +2 -2
  396. package/src/resources/extensions/gsd/provider-switch-observer.ts +185 -0
  397. package/src/resources/extensions/gsd/recovery-classification.ts +18 -1
  398. package/src/resources/extensions/gsd/session-lock.ts +41 -0
  399. package/src/resources/extensions/gsd/state-reconciliation/drift/completion.ts +172 -0
  400. package/src/resources/extensions/gsd/state-reconciliation/drift/merge-state.ts +337 -0
  401. package/src/resources/extensions/gsd/state-reconciliation/drift/project-md.ts +69 -0
  402. package/src/resources/extensions/gsd/state-reconciliation/drift/roadmap.ts +109 -0
  403. package/src/resources/extensions/gsd/state-reconciliation/drift/sketch-flag.ts +68 -0
  404. package/src/resources/extensions/gsd/state-reconciliation/drift/stale-render.ts +185 -0
  405. package/src/resources/extensions/gsd/state-reconciliation/drift/stale-worker.ts +46 -0
  406. package/src/resources/extensions/gsd/state-reconciliation/errors.ts +67 -0
  407. package/src/resources/extensions/gsd/state-reconciliation/index.ts +142 -0
  408. package/src/resources/extensions/gsd/state-reconciliation/registry.ts +27 -0
  409. package/src/resources/extensions/gsd/state-reconciliation/spawn-gate.ts +60 -0
  410. package/src/resources/extensions/gsd/state-reconciliation/types.ts +83 -0
  411. package/src/resources/extensions/gsd/state-reconciliation.ts +21 -53
  412. package/src/resources/extensions/gsd/templates/knowledge.md +2 -2
  413. package/src/resources/extensions/gsd/tests/artifact-retry-cap.test.ts +1 -1
  414. package/src/resources/extensions/gsd/tests/auto-dashboard.test.ts +99 -0
  415. package/src/resources/extensions/gsd/tests/auto-loop.test.ts +729 -176
  416. package/src/resources/extensions/gsd/tests/auto-paused-ui-cleanup.test.ts +291 -4
  417. package/src/resources/extensions/gsd/tests/auto-runtime-state.test.ts +16 -1
  418. package/src/resources/extensions/gsd/tests/auto-start-orphan-bootstrap.test.ts +18 -0
  419. package/src/resources/extensions/gsd/tests/auto-unit-closeout.test.ts +68 -0
  420. package/src/resources/extensions/gsd/tests/browser-tools-compatibility-declarations.test.ts +62 -0
  421. package/src/resources/extensions/gsd/tests/context-store-decisions-from-memories.test.ts +312 -0
  422. package/src/resources/extensions/gsd/tests/custom-engine-loop-integration.test.ts +28 -1
  423. package/src/resources/extensions/gsd/tests/db-writer.test.ts +13 -8
  424. package/src/resources/extensions/gsd/tests/decisions-projection-from-memories.test.ts +453 -0
  425. package/src/resources/extensions/gsd/tests/decisions-stop-table-writes.test.ts +348 -0
  426. package/src/resources/extensions/gsd/tests/deep-project-auto-loop.test.ts +20 -2
  427. package/src/resources/extensions/gsd/tests/dispatch-complete-milestone-guard.test.ts +44 -0
  428. package/src/resources/extensions/gsd/tests/freeform-decisions.test.ts +8 -4
  429. package/src/resources/extensions/gsd/tests/gsd-tools.test.ts +11 -7
  430. package/src/resources/extensions/gsd/tests/header-renderer.test.ts +40 -0
  431. package/src/resources/extensions/gsd/tests/headless-milestone-parity.test.ts +10 -0
  432. package/src/resources/extensions/gsd/tests/health-widget.test.ts +14 -4
  433. package/src/resources/extensions/gsd/tests/integration/doctor-git.test.ts +44 -0
  434. package/src/resources/extensions/gsd/tests/integration/git-service.test.ts +26 -0
  435. package/src/resources/extensions/gsd/tests/integration/integration-lifecycle.test.ts +13 -5
  436. package/src/resources/extensions/gsd/tests/integration/integration-proof.test.ts +1 -1
  437. package/src/resources/extensions/gsd/tests/integration/parallel-merge.test.ts +116 -24
  438. package/src/resources/extensions/gsd/tests/journal-integration.test.ts +0 -1
  439. package/src/resources/extensions/gsd/tests/knowledge-backfill-projection.test.ts +323 -0
  440. package/src/resources/extensions/gsd/tests/knowledge-capture.test.ts +242 -0
  441. package/src/resources/extensions/gsd/tests/knowledge.test.ts +47 -2
  442. package/src/resources/extensions/gsd/tests/load-knowledge-block-rules-only.test.ts +209 -0
  443. package/src/resources/extensions/gsd/tests/markdown-renderer.test.ts +1 -1
  444. package/src/resources/extensions/gsd/tests/memory-consolidation-scanner.test.ts +316 -0
  445. package/src/resources/extensions/gsd/tests/merge-conflict-stops-loop.test.ts +46 -11
  446. package/src/resources/extensions/gsd/tests/notification-overlay.test.ts +78 -41
  447. package/src/resources/extensions/gsd/tests/notifications-handler.test.ts +44 -0
  448. package/src/resources/extensions/gsd/tests/originalbase-path-comparison.test.ts +12 -217
  449. package/src/resources/extensions/gsd/tests/parallel-monitor-overlay.test.ts +38 -6
  450. package/src/resources/extensions/gsd/tests/plan-milestone-sketch-render.test.ts +157 -0
  451. package/src/resources/extensions/gsd/tests/post-exec-retry-bypass.test.ts +2 -2
  452. package/src/resources/extensions/gsd/tests/progressive-planning.test.ts +1 -1
  453. package/src/resources/extensions/gsd/tests/prompt-contracts.test.ts +32 -1
  454. package/src/resources/extensions/gsd/tests/provider-switch-observer.test.ts +252 -0
  455. package/src/resources/extensions/gsd/tests/resume-dispatch-worktree.test.ts +7 -3
  456. package/src/resources/extensions/gsd/tests/runtime-invariant-modules.test.ts +6 -3
  457. package/src/resources/extensions/gsd/tests/session-start-footer.test.ts +16 -4
  458. package/src/resources/extensions/gsd/tests/session-switch-abort-misclassification.test.ts +24 -0
  459. package/src/resources/extensions/gsd/tests/state-corruption-2945.test.ts +65 -58
  460. package/src/resources/extensions/gsd/tests/state-reconciliation-drift.test.ts +952 -0
  461. package/src/resources/extensions/gsd/tests/token-tool-gating.test.ts +4 -0
  462. package/src/resources/extensions/gsd/tests/tui-header-lifecycle.test.ts +121 -1
  463. package/src/resources/extensions/gsd/tests/tui-render-kit.test.ts +66 -0
  464. package/src/resources/extensions/gsd/tests/verification-retry-policy.test.ts +83 -0
  465. package/src/resources/extensions/gsd/tests/workflow-mcp.test.ts +6 -0
  466. package/src/resources/extensions/gsd/tests/worktree-journal-events.test.ts +158 -58
  467. package/src/resources/extensions/gsd/tests/worktree-lifecycle.test.ts +572 -118
  468. package/src/resources/extensions/gsd/tests/worktree-telemetry.test.ts +59 -2
  469. package/src/resources/extensions/gsd/tests/write-gate-planning-unit.test.ts +18 -0
  470. package/src/resources/extensions/gsd/tui/render-kit.ts +109 -0
  471. package/src/resources/extensions/gsd/watch/header-renderer.ts +121 -79
  472. package/src/resources/extensions/gsd/watch/splash-palette.ts +11 -0
  473. package/src/resources/extensions/gsd/workflow-logger.ts +4 -0
  474. package/src/resources/extensions/gsd/workflow-mcp.ts +2 -2
  475. package/src/resources/extensions/gsd/worktree-lifecycle.ts +1151 -524
  476. package/src/resources/extensions/gsd/worktree-telemetry.ts +7 -2
  477. package/dist/web/standalone/.next/static/chunks/app/page-200592a7f3baf579.js +0 -1
  478. package/dist/web/standalone/.next/static/chunks/main-app-d3d4c336195465f9.js +0 -1
  479. package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/global-error-ab5a8926e07ec673.js +0 -1
  480. package/src/resources/extensions/gsd/tests/worktree-resolver.test.ts +0 -1544
  481. /package/dist/web/standalone/.next/static/{drLMkgfHQ8lzS229_HWYR → KDRTXR-22LPCsa80X9dey}/_buildManifest.js +0 -0
  482. /package/dist/web/standalone/.next/static/{drLMkgfHQ8lzS229_HWYR → KDRTXR-22LPCsa80X9dey}/_ssgManifest.js +0 -0
@@ -0,0 +1,316 @@
1
+ // GSD-2 — ADR-013 Phase 6 preflight scanner tests.
2
+ //
3
+ // Locks in the four states the scanner must distinguish:
4
+ // 1. Clean — no gaps, no warning emitted.
5
+ // 2. Decisions gap — active decisions without a migrated memory.
6
+ // 3. KNOWLEDGE.md gap — rows in the legacy markdown without migration.
7
+ // 4. Both gaps — combined summary message.
8
+
9
+ import test from "node:test";
10
+ import assert from "node:assert/strict";
11
+ import { mkdtempSync, mkdirSync, rmSync, writeFileSync } from "node:fs";
12
+ import { join } from "node:path";
13
+ import { tmpdir } from "node:os";
14
+
15
+ import {
16
+ openDatabase,
17
+ closeDatabase,
18
+ insertDecision,
19
+ } from "../gsd-db.ts";
20
+ import { createMemory } from "../memory-store.ts";
21
+ import {
22
+ _resetNotificationStore,
23
+ initNotificationStore,
24
+ readNotifications,
25
+ } from "../notification-store.ts";
26
+ import {
27
+ parseKnowledgeRows,
28
+ reportConsolidationGaps,
29
+ scanConsolidationGaps,
30
+ } from "../memory-consolidation-scanner.ts";
31
+
32
+ function makeTmpBase(): string {
33
+ const base = mkdtempSync(join(tmpdir(), "gsd-consolidation-scan-"));
34
+ mkdirSync(join(base, ".gsd"), { recursive: true });
35
+ openDatabase(join(base, ".gsd", "gsd.db"));
36
+ initNotificationStore(base);
37
+ return base;
38
+ }
39
+
40
+ function cleanup(base: string): void {
41
+ try {
42
+ closeDatabase();
43
+ } catch {
44
+ /* noop */
45
+ }
46
+ _resetNotificationStore();
47
+ try {
48
+ rmSync(base, { recursive: true, force: true });
49
+ } catch {
50
+ /* noop */
51
+ }
52
+ }
53
+
54
+ function writeKnowledgeMd(base: string, body: string): void {
55
+ writeFileSync(join(base, ".gsd", "KNOWLEDGE.md"), body, "utf-8");
56
+ }
57
+
58
+ // ─── parseKnowledgeRows ─────────────────────────────────────────────────────
59
+
60
+ test("parseKnowledgeRows extracts entries from the three legacy tables", () => {
61
+ const content = `# Project Knowledge
62
+
63
+ Append-only register.
64
+
65
+ ## Rules
66
+
67
+ | # | Scope | Rule | Why | Added |
68
+ |---|-------|------|-----|-------|
69
+ | K001 | project | Always pin SQLite version | corruption | 2026-01-01 |
70
+ | K002 | M001 | Use UTC | clarity | 2026-01-02 |
71
+
72
+ ## Patterns
73
+
74
+ | # | Pattern | Where | Notes |
75
+ |---|---------|-------|-------|
76
+ | P001 | Repository pattern | services/ | guards |
77
+
78
+ ## Lessons Learned
79
+
80
+ | # | What Happened | Root Cause | Fix | Scope |
81
+ |---|--------------|------------|-----|-------|
82
+ | L001 | Cache poisoning | reused key | versioned key | project |
83
+ `;
84
+
85
+ const rows = parseKnowledgeRows(content);
86
+ assert.equal(rows.length, 4, "should extract 2 rules + 1 pattern + 1 lesson");
87
+ assert.deepEqual(
88
+ rows.map((r) => ({ table: r.table, id: r.id })),
89
+ [
90
+ { table: "rules", id: "K001" },
91
+ { table: "rules", id: "K002" },
92
+ { table: "patterns", id: "P001" },
93
+ { table: "lessons", id: "L001" },
94
+ ],
95
+ );
96
+ });
97
+
98
+ test("parseKnowledgeRows skips header/separator rows and unrecognized sections", () => {
99
+ const content = `## Rules
100
+
101
+ | # | Scope | Rule | Why | Added |
102
+ |---|-------|------|-----|-------|
103
+
104
+ ## Other Section
105
+
106
+ | # | Foo |
107
+ |---|-----|
108
+ | X999 | bar |
109
+ `;
110
+
111
+ // Empty Rules table → 0 rows. Unrecognized "Other Section" is ignored.
112
+ assert.equal(parseKnowledgeRows(content).length, 0);
113
+ });
114
+
115
+ test("parseKnowledgeRows returns empty for empty input", () => {
116
+ assert.deepEqual(parseKnowledgeRows(""), []);
117
+ assert.deepEqual(parseKnowledgeRows(" \n\n"), []);
118
+ });
119
+
120
+ // ─── scanConsolidationGaps ─────────────────────────────────────────────────
121
+
122
+ test("scanConsolidationGaps reports zero gaps when both surfaces are empty", () => {
123
+ const base = makeTmpBase();
124
+ try {
125
+ const report = scanConsolidationGaps(base);
126
+ assert.equal(report.decisions.total, 0);
127
+ assert.equal(report.knowledge.total, 0);
128
+ assert.equal(report.totalGaps, 0);
129
+ assert.match(report.summary, /all decisions and KNOWLEDGE\.md rows are in memories/);
130
+ } finally {
131
+ cleanup(base);
132
+ }
133
+ });
134
+
135
+ test("scanConsolidationGaps detects unmigrated decisions and ignores migrated ones", () => {
136
+ const base = makeTmpBase();
137
+ try {
138
+ insertDecision({
139
+ id: "D001",
140
+ when_context: "2026-01-01",
141
+ scope: "M001",
142
+ decision: "Decision needing migration",
143
+ choice: "A",
144
+ rationale: "because",
145
+ revisable: "yes",
146
+ made_by: "agent",
147
+ superseded_by: null,
148
+ });
149
+ insertDecision({
150
+ id: "D002",
151
+ when_context: "2026-01-02",
152
+ scope: "M001",
153
+ decision: "Already migrated decision",
154
+ choice: "B",
155
+ rationale: "covered",
156
+ revisable: "yes",
157
+ made_by: "agent",
158
+ superseded_by: null,
159
+ });
160
+ // D002 has a corresponding migrated memory; D001 doesn't.
161
+ createMemory({
162
+ category: "architecture",
163
+ content: "Already migrated decision Chose: B. Rationale: covered.",
164
+ scope: "M001",
165
+ structuredFields: { sourceDecisionId: "D002" },
166
+ });
167
+
168
+ const report = scanConsolidationGaps(base);
169
+ assert.equal(report.decisions.total, 2);
170
+ assert.equal(report.decisions.migrated, 1);
171
+ assert.equal(report.decisions.unmigrated, 1);
172
+ assert.equal(report.decisions.samples.length, 1);
173
+ assert.equal(report.decisions.samples[0]?.id, "D001");
174
+ assert.equal(report.totalGaps, 1);
175
+ assert.match(report.summary, /1 of 2 active decisions/);
176
+ } finally {
177
+ cleanup(base);
178
+ }
179
+ });
180
+
181
+ test("scanConsolidationGaps skips superseded decisions (historical record only)", () => {
182
+ const base = makeTmpBase();
183
+ try {
184
+ insertDecision({
185
+ id: "D001",
186
+ when_context: "2026-01-01",
187
+ scope: "M001",
188
+ decision: "Superseded — does not need migration",
189
+ choice: "A",
190
+ rationale: "old",
191
+ revisable: "yes",
192
+ made_by: "agent",
193
+ superseded_by: "D002",
194
+ });
195
+
196
+ const report = scanConsolidationGaps(base);
197
+ assert.equal(report.decisions.total, 0, "superseded decisions excluded from active count");
198
+ assert.equal(report.totalGaps, 0);
199
+ } finally {
200
+ cleanup(base);
201
+ }
202
+ });
203
+
204
+ test("scanConsolidationGaps detects unmigrated KNOWLEDGE.md rows by table", () => {
205
+ const base = makeTmpBase();
206
+ try {
207
+ writeKnowledgeMd(
208
+ base,
209
+ `## Rules
210
+
211
+ | # | Scope | Rule | Why | Added |
212
+ |---|-------|------|-----|-------|
213
+ | K001 | project | Pin SQLite | corruption | 2026-01-01 |
214
+ | K002 | M001 | UTC only | clarity | 2026-01-02 |
215
+
216
+ ## Patterns
217
+
218
+ | # | Pattern | Where | Notes |
219
+ |---|---------|-------|-------|
220
+ | P001 | Repository | services/ | guards |
221
+
222
+ ## Lessons Learned
223
+
224
+ | # | What Happened | Root Cause | Fix | Scope |
225
+ |---|--------------|------------|-----|-------|
226
+ `,
227
+ );
228
+
229
+ const report = scanConsolidationGaps(base);
230
+ assert.equal(report.knowledge.total, 3);
231
+ assert.equal(report.knowledge.unmigrated, 3, "no sourceKnowledgeId markers exist yet");
232
+ assert.deepEqual(report.knowledge.byTable, { rules: 2, patterns: 1, lessons: 0 });
233
+ assert.equal(report.knowledge.samples.length, 3);
234
+ assert.equal(report.totalGaps, 3);
235
+ assert.match(report.summary, /3 of 3 KNOWLEDGE\.md rows/);
236
+ } finally {
237
+ cleanup(base);
238
+ }
239
+ });
240
+
241
+ test("scanConsolidationGaps combines decisions and KNOWLEDGE.md gaps in summary", () => {
242
+ const base = makeTmpBase();
243
+ try {
244
+ insertDecision({
245
+ id: "D001",
246
+ when_context: "2026-01-01",
247
+ scope: "M001",
248
+ decision: "Unmigrated decision",
249
+ choice: "A",
250
+ rationale: "x",
251
+ revisable: "yes",
252
+ made_by: "agent",
253
+ superseded_by: null,
254
+ });
255
+ writeKnowledgeMd(
256
+ base,
257
+ `## Rules
258
+
259
+ | # | Scope | Rule | Why | Added |
260
+ |---|-------|------|-----|-------|
261
+ | K001 | project | Some rule | reason | 2026-01-01 |
262
+ `,
263
+ );
264
+
265
+ const report = scanConsolidationGaps(base);
266
+ assert.equal(report.totalGaps, 2);
267
+ assert.match(report.summary, /1 of 1 active decisions/);
268
+ assert.match(report.summary, /1 of 1 KNOWLEDGE\.md rows/);
269
+ } finally {
270
+ cleanup(base);
271
+ }
272
+ });
273
+
274
+ // ─── reportConsolidationGaps ───────────────────────────────────────────────
275
+
276
+ test("reportConsolidationGaps emits a notification + warning when gaps exist", () => {
277
+ const base = makeTmpBase();
278
+ try {
279
+ insertDecision({
280
+ id: "D001",
281
+ when_context: "2026-01-01",
282
+ scope: "M001",
283
+ decision: "Unmigrated",
284
+ choice: "A",
285
+ rationale: "x",
286
+ revisable: "yes",
287
+ made_by: "agent",
288
+ superseded_by: null,
289
+ });
290
+
291
+ const report = reportConsolidationGaps(base);
292
+ assert.ok(report);
293
+ assert.equal(report.totalGaps, 1);
294
+
295
+ const notifications = readNotifications(base);
296
+ const gapNotifs = notifications.filter((n) => n.message.includes("Memory consolidation"));
297
+ assert.ok(gapNotifs.length >= 1, "a consolidation notification should be persisted");
298
+ assert.equal(gapNotifs[0]?.severity, "warning");
299
+ } finally {
300
+ cleanup(base);
301
+ }
302
+ });
303
+
304
+ test("reportConsolidationGaps stays silent when there are no gaps", () => {
305
+ const base = makeTmpBase();
306
+ try {
307
+ const report = reportConsolidationGaps(base);
308
+ assert.ok(report);
309
+ assert.equal(report.totalGaps, 0);
310
+ const notifications = readNotifications(base);
311
+ const gapNotifs = notifications.filter((n) => n.message.includes("not yet in memories"));
312
+ assert.equal(gapNotifs.length, 0, "no warning notification when clean");
313
+ } finally {
314
+ cleanup(base);
315
+ }
316
+ });
@@ -29,20 +29,25 @@
29
29
 
30
30
  import { describe, test, beforeEach, afterEach } from "node:test";
31
31
  import assert from "node:assert/strict";
32
- import { mkdtempSync, rmSync, mkdirSync } from "node:fs";
32
+ import { mkdtempSync, rmSync, mkdirSync, writeFileSync } from "node:fs";
33
33
  import { join } from "node:path";
34
34
  import { tmpdir } from "node:os";
35
35
 
36
- import { WorktreeLifecycle, type WorktreeLifecycleDeps } from "../worktree-lifecycle.ts";
36
+ import {
37
+ WorktreeLifecycle,
38
+ type WorktreeLifecycleDeps,
39
+ type WorktreeLifecycleTestOverrides,
40
+ } from "../worktree-lifecycle.ts";
37
41
  import { WorktreeStateProjection } from "../worktree-state-projection.ts";
38
42
  import { MergeConflictError } from "../git-service.ts";
39
43
  import type { AutoSession } from "../auto/session.ts";
40
44
 
41
- // Test-local: LegacyTestDeps had three fields Lifecycle does not need
42
- // (shouldUseWorktreeIsolation, syncWorktreeStateBack, captureIntegrationBranch).
43
- // Permit them in test fixtures so existing override patterns keep working —
44
- // Lifecycle ignores the extras via structural typing.
45
- type LegacyTestDeps = WorktreeLifecycleDeps & {
45
+ // Test-local: extras the WorktreeResolver-era fixture passed but Lifecycle
46
+ // does not need (shouldUseWorktreeIsolation, syncWorktreeStateBack,
47
+ // captureIntegrationBranch). Lifecycle ignores them via structural typing.
48
+ // The C1-C4-inlined primitive overrides come from
49
+ // `WorktreeLifecycleTestOverrides`, the test seam exported by the Module.
50
+ type LegacyTestDeps = WorktreeLifecycleDeps & WorktreeLifecycleTestOverrides & {
46
51
  shouldUseWorktreeIsolation?: () => boolean;
47
52
  syncWorktreeStateBack?: (
48
53
  mainBasePath: string,
@@ -50,6 +55,7 @@ type LegacyTestDeps = WorktreeLifecycleDeps & {
50
55
  milestoneId: string,
51
56
  ) => { synced: string[] };
52
57
  captureIntegrationBranch?: (basePath: string, mid: string | undefined) => void;
58
+ GitServiceImpl?: new (basePath: string, gitConfig: unknown) => unknown;
53
59
  };
54
60
 
55
61
  /**
@@ -96,7 +102,12 @@ function makeDeps(
96
102
  enterAutoWorktree: () => "",
97
103
  enterBranchModeForMilestone: () => undefined,
98
104
  getAutoWorktreePath: () => null,
99
- autoCommitCurrentBranch: () => undefined,
105
+ autoCommitCurrentBranch: (
106
+ _basePath: string,
107
+ _unitType: string,
108
+ _unitId: string,
109
+ _taskContext?: unknown,
110
+ ) => null,
100
111
  getCurrentBranch: () => "worktree/M001",
101
112
  checkoutBranch: () => undefined,
102
113
  autoWorktreeBranch: (mid: string) => `worktree/${mid}`,
@@ -109,6 +120,8 @@ function makeDeps(
109
120
  invalidateAllCaches: () => undefined,
110
121
  captureIntegrationBranch: () => undefined,
111
122
  worktreeProjection: new WorktreeStateProjection(),
123
+ // ADR-016 phase 2 / C4 (#5627): GitServiceImpl constructor → factory.
124
+ gitServiceFactory: () => ({}) as never,
112
125
  ...overrides,
113
126
  };
114
127
  }
@@ -128,14 +141,36 @@ function makeNotifyCtx(): {
128
141
 
129
142
  describe("WorktreeResolver.mergeAndExit re-throws MergeConflictError (#2330)", () => {
130
143
  let baseDir: string;
144
+ const savedCwd = process.cwd();
131
145
 
132
146
  beforeEach(() => {
133
147
  baseDir = mkdtempSync(join(tmpdir(), "merge-conflict-stops-loop-"));
134
148
  // Fake out a milestone directory so mergeAndExit reaches mergeMilestoneToMain.
135
149
  mkdirSync(join(baseDir, ".gsd", "milestones", "M001"), { recursive: true });
150
+ // ADR-016 phase 2 / C1 (#5624): worktree-lifecycle.ts now calls
151
+ // node:fs.readFileSync directly (the dep was retired), so the roadmap
152
+ // file must exist on disk for the test to reach mergeMilestoneToMain.
153
+ writeFileSync(
154
+ join(baseDir, ".gsd", "milestones", "M001", "M001-ROADMAP.md"),
155
+ "# M001\n",
156
+ );
157
+ // ADR-016 phase 2 / C3 (#5626): `getIsolationMode` is also inlined.
158
+ // Without explicit isolation preferences the mode defaults to "none"
159
+ // and the merge short-circuits before the test's mocked
160
+ // `mergeMilestoneToMain` is reached. Write a preferences file so the
161
+ // standalone routes through worktree-mode merge.
162
+ writeFileSync(
163
+ join(baseDir, ".gsd", "preferences.md"),
164
+ "## Git\n- isolation: worktree\n",
165
+ );
136
166
  });
137
167
 
138
168
  afterEach(() => {
169
+ // ADR-016 phase 2 / C2 (#5625): the inlined `mergeMilestoneStandalone`
170
+ // chdirs into the project root before the merge body runs. Restore
171
+ // cwd before deleting `baseDir` so the next test's `process.cwd()`
172
+ // doesn't fail with ENOENT.
173
+ try { process.chdir(savedCwd); } catch { /* best-effort */ }
139
174
  try {
140
175
  rmSync(baseDir, { recursive: true, force: true });
141
176
  } catch {
@@ -147,7 +182,7 @@ describe("WorktreeResolver.mergeAndExit re-throws MergeConflictError (#2330)", (
147
182
  const conflicted = ["src/feature.ts", "README.md"];
148
183
  const roadmapPath = join(baseDir, ".gsd", "milestones", "M001", "M001-ROADMAP.md");
149
184
  const deps = makeDeps({
150
- resolveMilestoneFile: (_base, _mid, type) =>
185
+ resolveMilestoneFile: (_base: string, _mid: string, type: string) =>
151
186
  type === "ROADMAP" ? roadmapPath : null,
152
187
  readFileSync: () => "# M001\n",
153
188
  mergeMilestoneToMain: () => {
@@ -178,7 +213,7 @@ describe("WorktreeResolver.mergeAndExit re-throws MergeConflictError (#2330)", (
178
213
  const roadmapPath = join(baseDir, ".gsd", "milestones", "M001", "M001-ROADMAP.md");
179
214
  class FakePermError extends Error {}
180
215
  const deps = makeDeps({
181
- resolveMilestoneFile: (_base, _mid, type) =>
216
+ resolveMilestoneFile: (_base: string, _mid: string, type: string) =>
182
217
  type === "ROADMAP" ? roadmapPath : null,
183
218
  readFileSync: () => "# M001\n",
184
219
  mergeMilestoneToMain: () => {
@@ -204,7 +239,7 @@ describe("WorktreeResolver.mergeAndExit re-throws MergeConflictError (#2330)", (
204
239
  test("successful merge does not throw", () => {
205
240
  const roadmapPath = join(baseDir, ".gsd", "milestones", "M001", "M001-ROADMAP.md");
206
241
  const deps = makeDeps({
207
- resolveMilestoneFile: (_base, _mid, type) =>
242
+ resolveMilestoneFile: (_base: string, _mid: string, type: string) =>
208
243
  type === "ROADMAP" ? roadmapPath : null,
209
244
  readFileSync: () => "# M001\n",
210
245
  mergeMilestoneToMain: () => ({ pushed: false, codeFilesChanged: true }),
@@ -1,55 +1,53 @@
1
- // GSD Extension — Notification Overlay Tests
2
- // Tests for message wrapping in the notification panel.
3
- // Mirrors the private wrapText from notification-overlay.ts so its contract
4
- // can be exercised without exporting internals.
1
+ // Project/App: GSD-2
2
+ // File Purpose: Regression tests for notification overlay wrapping and width-safe rendering.
5
3
 
6
4
  import { describe, test } from "node:test";
7
5
  import assert from "node:assert/strict";
6
+ import { mkdtempSync, rmSync } from "node:fs";
7
+ import { tmpdir } from "node:os";
8
+ import { join } from "node:path";
8
9
 
9
- import { truncateToWidth, visibleWidth, wrapTextWithAnsi } from "@gsd/pi-tui";
10
+ import { visibleWidth } from "@gsd/pi-tui";
11
+ import { appendNotification, initNotificationStore, _resetNotificationStore } from "../notification-store.ts";
12
+ import { GSDNotificationOverlay, notificationOverlayOptions } from "../notification-overlay.ts";
13
+ import { wrapVisibleText } from "../tui/render-kit.ts";
10
14
 
11
- // ── wrapText logic (mirrors the private function in notification-overlay.ts) ──
15
+ const fakeTheme = {
16
+ fg: (_color: string, text: string) => text,
17
+ bold: (text: string) => text,
18
+ };
12
19
 
13
- function wrapText(text: string, maxWidth: number): string[] {
14
- if (maxWidth <= 0) return [text];
15
- const lines = wrapTextWithAnsi(text, maxWidth);
16
- return lines.map((l) =>
17
- visibleWidth(l) > maxWidth ? truncateToWidth(l, maxWidth, "") : l,
18
- );
20
+ function assertLinesFit(lines: string[], width: number): void {
21
+ for (const line of lines) {
22
+ assert.ok(
23
+ visibleWidth(line) <= width,
24
+ `line exceeds maxWidth: visibleWidth=${visibleWidth(line)} max=${width}: "${line}"`,
25
+ );
26
+ }
19
27
  }
20
28
 
21
29
  describe("notification overlay — wrapText", () => {
22
30
  test("short text returns single line", () => {
23
- const result = wrapText("hello world", 80);
31
+ const result = wrapVisibleText("hello world", 80);
24
32
  assert.deepStrictEqual(result, ["hello world"]);
25
33
  });
26
34
 
27
35
  test("long text wraps at word boundaries without exceeding maxWidth", () => {
28
36
  const text = "This is a long notification message that should wrap across multiple lines";
29
- const result = wrapText(text, 40);
37
+ const result = wrapVisibleText(text, 40);
30
38
  assert.ok(result.length > 1, `expected multiple lines, got ${result.length}`);
31
- for (const line of result) {
32
- assert.ok(
33
- visibleWidth(line) <= 40,
34
- `line exceeds maxWidth: "${line}" (${visibleWidth(line)})`,
35
- );
36
- }
39
+ assertLinesFit(result, 40);
37
40
  });
38
41
 
39
42
  test("single word exceeding maxWidth is broken to fit column budget", () => {
40
- const result = wrapText("superlongwordthatexceedsmaxwidth", 10);
41
- for (const line of result) {
42
- assert.ok(
43
- visibleWidth(line) <= 10,
44
- `line exceeds maxWidth: "${line}" (${visibleWidth(line)})`,
45
- );
46
- }
43
+ const result = wrapVisibleText("superlongwordthatexceedsmaxwidth", 10);
44
+ assertLinesFit(result, 10);
47
45
  });
48
46
 
49
47
  test("preserves all words across wrapped lines", () => {
50
48
  const words = ["alpha", "bravo", "charlie", "delta", "echo", "foxtrot"];
51
49
  const text = words.join(" ");
52
- const result = wrapText(text, 15);
50
+ const result = wrapVisibleText(text, 15);
53
51
  const rejoined = result.join(" ");
54
52
  for (const w of words) {
55
53
  assert.ok(rejoined.includes(w), `missing word: ${w}`);
@@ -70,23 +68,62 @@ describe("notification overlay — wrapText", () => {
70
68
  "(expired — will auto-refresh) ✗ google — not configured " +
71
69
  "(aistudio.google.com/apikey) ✗ groq — not configured";
72
70
  const maxWidth = 118;
73
- const result = wrapText(msg, maxWidth);
74
- for (const line of result) {
75
- assert.ok(
76
- visibleWidth(line) <= maxWidth,
77
- `line exceeds column budget: visibleWidth=${visibleWidth(line)} max=${maxWidth}: "${line}"`,
78
- );
79
- }
71
+ const result = wrapVisibleText(msg, maxWidth);
72
+ assertLinesFit(result, maxWidth);
80
73
  });
81
74
 
82
75
  test("unbreakable long token (URL) is clamped to maxWidth", () => {
83
76
  const url = "https://example.com/" + "a".repeat(200);
84
- const result = wrapText(url, 40);
85
- for (const line of result) {
86
- assert.ok(
87
- visibleWidth(line) <= 40,
88
- `line exceeds maxWidth: visibleWidth=${visibleWidth(line)} line="${line}"`,
89
- );
77
+ const result = wrapVisibleText(url, 40);
78
+ assertLinesFit(result, 40);
79
+ });
80
+
81
+ test("real overlay render fits common terminal widths", (t) => {
82
+ const dir = mkdtempSync(join(tmpdir(), "gsd-notification-overlay-"));
83
+ t.after(() => {
84
+ _resetNotificationStore();
85
+ rmSync(dir, { recursive: true, force: true });
86
+ });
87
+
88
+ initNotificationStore(dir);
89
+ appendNotification("A long notification with " + "x".repeat(180), "warning");
90
+
91
+ const overlay = new GSDNotificationOverlay({ requestRender() {} }, fakeTheme as any, () => {});
92
+ t.after(() => overlay.dispose());
93
+
94
+ for (const width of [40, 80, 120]) {
95
+ assertLinesFit(overlay.render(width), width);
96
+ overlay.invalidate();
90
97
  }
91
98
  });
99
+
100
+ test("rendered height stays within the configured overlay max height", (t) => {
101
+ const dir = mkdtempSync(join(tmpdir(), "gsd-notification-overlay-height-"));
102
+ const originalRowsDescriptor = Object.getOwnPropertyDescriptor(process.stdout, "rows");
103
+ Object.defineProperty(process.stdout, "rows", { value: 40, configurable: true });
104
+
105
+ t.after(() => {
106
+ if (originalRowsDescriptor) {
107
+ Object.defineProperty(process.stdout, "rows", originalRowsDescriptor);
108
+ } else {
109
+ delete (process.stdout as { rows?: number }).rows;
110
+ }
111
+ _resetNotificationStore();
112
+ rmSync(dir, { recursive: true, force: true });
113
+ });
114
+
115
+ initNotificationStore(dir);
116
+ for (let i = 0; i < 80; i++) {
117
+ appendNotification(`notification-${i + 1} with enough text to exercise clipping`, "warning");
118
+ }
119
+
120
+ const overlay = new GSDNotificationOverlay({ requestRender() {} }, fakeTheme as any, () => {});
121
+ t.after(() => overlay.dispose());
122
+
123
+ const rendered = overlay.render(100);
124
+ const maxHeight = Math.floor((40 * 52) / 100);
125
+ assert.ok(rendered.length <= maxHeight, `expected ${rendered.length} lines to fit maxHeight ${maxHeight}`);
126
+ assert.ok(rendered.at(-1)?.includes("╯"), "bottom border should remain visible");
127
+ assert.equal(notificationOverlayOptions().maxHeight, "52%");
128
+ });
92
129
  });
@@ -1,3 +1,6 @@
1
+ // Project/App: GSD-2
2
+ // File Purpose: Tests for /gsd notifications command handling and overlay launch behavior.
3
+
1
4
  import test from "node:test";
2
5
  import assert from "node:assert/strict";
3
6
  import { join } from "node:path";
@@ -58,6 +61,47 @@ test("notifications command falls back to text output when overlay returns undef
58
61
  assert.match(notices[0].message, /Recent notifications:/);
59
62
  });
60
63
 
64
+ test("notifications command opens a compact bounded overlay", async (t) => {
65
+ const base = makeTempDir("overlay-options");
66
+ initNotificationStore(base);
67
+ appendNotification("Build complete", "success");
68
+
69
+ t.after(() => {
70
+ _resetNotificationStore();
71
+ cleanup(base);
72
+ });
73
+
74
+ const notices: Array<{ message: string; level?: string }> = [];
75
+ let capturedOptions: any;
76
+ await handleNotificationsCommand(
77
+ "",
78
+ {
79
+ hasUI: true,
80
+ ui: {
81
+ custom: async (_factory: any, options: any) => {
82
+ capturedOptions = options;
83
+ return true;
84
+ },
85
+ notify: (message: string, level?: string) => {
86
+ notices.push({ message, level });
87
+ },
88
+ },
89
+ } as any,
90
+ {} as any,
91
+ );
92
+
93
+ assert.deepEqual(capturedOptions?.overlayOptions, {
94
+ width: "58%",
95
+ minWidth: 68,
96
+ maxHeight: "52%",
97
+ anchor: "top-center",
98
+ row: "24%",
99
+ margin: { top: 2, right: 2, bottom: 6, left: 2 },
100
+ backdrop: true,
101
+ });
102
+ assert.equal(notices.length, 0, "successful overlay should not emit text fallback");
103
+ });
104
+
61
105
  test("notifications tail caps inline output and hints to open overlay", async (t) => {
62
106
  const base = makeTempDir("tail-cap");
63
107
  initNotificationStore(base);