gsd-pi 2.81.0-dev.72a81bdf3 → 2.82.0-dev.20138ae42

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 (463) hide show
  1. package/README.md +50 -31
  2. package/dist/resources/.managed-resources-content-hash +1 -1
  3. package/dist/resources/GSD-WORKFLOW.md +10 -1
  4. package/dist/resources/extensions/browser-tools/tools/screenshot.js +1 -0
  5. package/dist/resources/extensions/browser-tools/tools/zoom.js +1 -0
  6. package/dist/resources/extensions/claude-code-cli/partial-builder.js +2 -1
  7. package/dist/resources/extensions/cmux/index.js +5 -0
  8. package/dist/resources/extensions/gsd/auto/infra-errors.js +9 -3
  9. package/dist/resources/extensions/gsd/auto/loop.js +5 -5
  10. package/dist/resources/extensions/gsd/auto/orchestrator.js +124 -6
  11. package/dist/resources/extensions/gsd/auto/phases.js +30 -1
  12. package/dist/resources/extensions/gsd/auto/workflow-memory-pressure.js +12 -0
  13. package/dist/resources/extensions/gsd/auto-dashboard.js +66 -1
  14. package/dist/resources/extensions/gsd/auto-dispatch.js +13 -6
  15. package/dist/resources/extensions/gsd/auto-model-selection.js +2 -0
  16. package/dist/resources/extensions/gsd/auto-post-unit.js +233 -127
  17. package/dist/resources/extensions/gsd/auto-prompts.js +13 -5
  18. package/dist/resources/extensions/gsd/auto-recovery.js +31 -1
  19. package/dist/resources/extensions/gsd/auto-start.js +85 -12
  20. package/dist/resources/extensions/gsd/auto-verification.js +28 -22
  21. package/dist/resources/extensions/gsd/auto-worktree.js +111 -1
  22. package/dist/resources/extensions/gsd/auto.js +158 -55
  23. package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +25 -6
  24. package/dist/resources/extensions/gsd/bootstrap/db-tools.js +9 -8
  25. package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +9 -2
  26. package/dist/resources/extensions/gsd/bootstrap/subagent-input.js +21 -9
  27. package/dist/resources/extensions/gsd/bootstrap/system-context.js +55 -12
  28. package/dist/resources/extensions/gsd/bootstrap/write-gate.js +16 -2
  29. package/dist/resources/extensions/gsd/clean-root-preflight.js +170 -8
  30. package/dist/resources/extensions/gsd/commands/catalog.js +4 -1
  31. package/dist/resources/extensions/gsd/commands/handlers/core.js +38 -1
  32. package/dist/resources/extensions/gsd/commands-bootstrap.js +5 -0
  33. package/dist/resources/extensions/gsd/commands-handlers.js +15 -2
  34. package/dist/resources/extensions/gsd/context-store.js +112 -0
  35. package/dist/resources/extensions/gsd/crash-recovery.js +31 -5
  36. package/dist/resources/extensions/gsd/db/unit-dispatches.js +3 -2
  37. package/dist/resources/extensions/gsd/db-writer.js +150 -84
  38. package/dist/resources/extensions/gsd/dispatch-guard.js +2 -2
  39. package/dist/resources/extensions/gsd/docs/preferences-reference.md +1 -1
  40. package/dist/resources/extensions/gsd/doctor-git-checks.js +41 -6
  41. package/dist/resources/extensions/gsd/doctor-runtime-checks.js +28 -11
  42. package/dist/resources/extensions/gsd/doctor.js +2 -28
  43. package/dist/resources/extensions/gsd/export-html.js +27 -425
  44. package/dist/resources/extensions/gsd/git-service.js +39 -1
  45. package/dist/resources/extensions/gsd/gsd-db.js +1 -0
  46. package/dist/resources/extensions/gsd/guided-flow.js +93 -111
  47. package/dist/resources/extensions/gsd/guided-unit-context.js +23 -0
  48. package/dist/resources/extensions/gsd/knowledge-backfill.js +144 -0
  49. package/dist/resources/extensions/gsd/knowledge-capture.js +136 -0
  50. package/dist/resources/extensions/gsd/knowledge-parser.js +154 -0
  51. package/dist/resources/extensions/gsd/knowledge-projection.js +210 -0
  52. package/dist/resources/extensions/gsd/markdown-renderer.js +6 -1
  53. package/dist/resources/extensions/gsd/md-importer.js +1 -1
  54. package/dist/resources/extensions/gsd/memory-backfill.js +73 -17
  55. package/dist/resources/extensions/gsd/memory-consolidation-scanner.js +222 -0
  56. package/dist/resources/extensions/gsd/migrate/command.js +5 -0
  57. package/dist/resources/extensions/gsd/migrate/parsers.js +10 -0
  58. package/dist/resources/extensions/gsd/migrate/preview.js +9 -0
  59. package/dist/resources/extensions/gsd/migrate/transformer.js +51 -4
  60. package/dist/resources/extensions/gsd/migrate/writer.js +11 -1
  61. package/dist/resources/extensions/gsd/migration-auto-check.js +12 -17
  62. package/dist/resources/extensions/gsd/milestone-actions.js +11 -4
  63. package/dist/resources/extensions/gsd/native-git-bridge.js +48 -12
  64. package/dist/resources/extensions/gsd/pending-auto-start.js +52 -0
  65. package/dist/resources/extensions/gsd/post-execution-checks.js +73 -2
  66. package/dist/resources/extensions/gsd/pre-execution-checks.js +28 -1
  67. package/dist/resources/extensions/gsd/prompt-loader.js +1 -1
  68. package/dist/resources/extensions/gsd/prompts/complete-milestone.md +1 -1
  69. package/dist/resources/extensions/gsd/prompts/complete-slice.md +1 -1
  70. package/dist/resources/extensions/gsd/prompts/discuss-headless.md +8 -8
  71. package/dist/resources/extensions/gsd/prompts/discuss.md +9 -9
  72. package/dist/resources/extensions/gsd/prompts/guided-discuss-project.md +4 -4
  73. package/dist/resources/extensions/gsd/prompts/guided-discuss-requirements.md +3 -3
  74. package/dist/resources/extensions/gsd/prompts/plan-slice.md +4 -4
  75. package/dist/resources/extensions/gsd/prompts/queue.md +4 -4
  76. package/dist/resources/extensions/gsd/prompts/refine-slice.md +2 -2
  77. package/dist/resources/extensions/gsd/prompts/rewrite-docs.md +1 -1
  78. package/dist/resources/extensions/gsd/prompts/system.md +2 -2
  79. package/dist/resources/extensions/gsd/provider-switch-observer.js +146 -0
  80. package/dist/resources/extensions/gsd/smart-entry-routing.js +36 -0
  81. package/dist/resources/extensions/gsd/state-reconciliation/drift/merge-state.js +6 -1
  82. package/dist/resources/extensions/gsd/state-reconciliation/drift/project-md.js +9 -14
  83. package/dist/resources/extensions/gsd/state-reconciliation/drift/roadmap.js +19 -24
  84. package/dist/resources/extensions/gsd/status-guards.js +4 -0
  85. package/dist/resources/extensions/gsd/templates/knowledge.md +2 -2
  86. package/dist/resources/extensions/gsd/templates/plan.md +8 -5
  87. package/dist/resources/extensions/gsd/templates/task-plan.md +4 -2
  88. package/dist/resources/extensions/gsd/tools/complete-milestone.js +6 -8
  89. package/dist/resources/extensions/gsd/tools/complete-slice.js +6 -8
  90. package/dist/resources/extensions/gsd/tools/plan-milestone.js +7 -1
  91. package/dist/resources/extensions/gsd/tools/plan-slice.js +89 -14
  92. package/dist/resources/extensions/gsd/tools/workflow-tool-executors.js +119 -0
  93. package/dist/resources/extensions/gsd/unit-context-manifest.js +32 -10
  94. package/dist/resources/extensions/gsd/validation.js +23 -1
  95. package/dist/resources/extensions/gsd/verification-gate.js +68 -7
  96. package/dist/resources/extensions/gsd/verification-verdict.js +26 -0
  97. package/dist/resources/extensions/gsd/workflow-projections.js +6 -8
  98. package/dist/resources/extensions/gsd/worktree-lifecycle.js +54 -10
  99. package/dist/resources/extensions/shared/html-shell.js +388 -0
  100. package/dist/resources/extensions/subagent/index.js +448 -78
  101. package/dist/resources/extensions/subagent/launch.js +77 -0
  102. package/dist/resources/extensions/subagent/run-store.js +148 -0
  103. package/dist/resources/extensions/visual-brief/artifact-policy.js +29 -0
  104. package/dist/resources/extensions/visual-brief/extension-manifest.json +8 -0
  105. package/dist/resources/extensions/visual-brief/index.js +5 -0
  106. package/dist/resources/extensions/visual-brief/page-contract.js +124 -0
  107. package/dist/resources/extensions/visual-brief/prompts.js +140 -0
  108. package/dist/tsconfig.extensions.tsbuildinfo +1 -1
  109. package/dist/web/standalone/.next/BUILD_ID +1 -1
  110. package/dist/web/standalone/.next/app-path-routes-manifest.json +12 -12
  111. package/dist/web/standalone/.next/build-manifest.json +3 -3
  112. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  113. package/dist/web/standalone/.next/react-loadable-manifest.json +3 -3
  114. package/dist/web/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
  115. package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
  116. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  117. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  118. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  119. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  120. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  121. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  122. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  123. package/dist/web/standalone/.next/server/app/_not-found/page.js +2 -2
  124. package/dist/web/standalone/.next/server/app/_not-found/page.js.nft.json +1 -1
  125. package/dist/web/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  126. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  127. package/dist/web/standalone/.next/server/app/_not-found.rsc +4 -7
  128. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +4 -7
  129. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  130. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +4 -5
  131. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  132. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  133. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -5
  134. package/dist/web/standalone/.next/server/app/api/git/route.js +1 -1
  135. package/dist/web/standalone/.next/server/app/index.html +1 -1
  136. package/dist/web/standalone/.next/server/app/index.rsc +4 -7
  137. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
  138. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +4 -7
  139. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  140. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +4 -5
  141. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +2 -5
  142. package/dist/web/standalone/.next/server/app/page.js +2 -2
  143. package/dist/web/standalone/.next/server/app/page.js.nft.json +1 -1
  144. package/dist/web/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
  145. package/dist/web/standalone/.next/server/app-paths-manifest.json +12 -12
  146. package/dist/web/standalone/.next/server/chunks/4266.js +2 -0
  147. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  148. package/dist/web/standalone/.next/server/middleware-react-loadable-manifest.js +1 -1
  149. package/dist/web/standalone/.next/server/next-font-manifest.js +1 -1
  150. package/dist/web/standalone/.next/server/next-font-manifest.json +1 -1
  151. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  152. package/dist/web/standalone/.next/server/pages/500.html +1 -1
  153. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  154. package/dist/web/standalone/.next/static/chunks/2973.33f26573894b6153.js +2 -0
  155. package/dist/web/standalone/.next/static/chunks/{8359.e059d86b255fce1c.js → 8359.7eb3bb8f8ecf4c01.js} +2 -2
  156. package/dist/web/standalone/.next/static/chunks/app/layout-8c10ec293ae0f1d5.js +1 -0
  157. package/dist/web/standalone/.next/static/chunks/{webpack-de742b64187e13fe.js → webpack-9a4db269f9ed63ad.js} +1 -1
  158. package/dist/web/standalone/.next/static/css/746ee28c929d1880.css +1 -0
  159. package/package.json +6 -5
  160. package/packages/contracts/dist/rpc.test.js +7 -0
  161. package/packages/contracts/dist/rpc.test.js.map +1 -1
  162. package/packages/contracts/dist/workflow.d.ts +21 -0
  163. package/packages/contracts/dist/workflow.d.ts.map +1 -1
  164. package/packages/contracts/dist/workflow.js +24 -0
  165. package/packages/contracts/dist/workflow.js.map +1 -1
  166. package/packages/contracts/src/rpc.test.ts +8 -0
  167. package/packages/contracts/src/workflow.ts +24 -0
  168. package/packages/daemon/package.json +2 -2
  169. package/packages/mcp-server/README.md +14 -3
  170. package/packages/mcp-server/dist/workflow-tools.d.ts +0 -3
  171. package/packages/mcp-server/dist/workflow-tools.d.ts.map +1 -1
  172. package/packages/mcp-server/dist/workflow-tools.js +80 -0
  173. package/packages/mcp-server/dist/workflow-tools.js.map +1 -1
  174. package/packages/mcp-server/package.json +2 -2
  175. package/packages/mcp-server/src/workflow-tools-parity.test.ts +244 -0
  176. package/packages/mcp-server/src/workflow-tools.test.ts +23 -1
  177. package/packages/mcp-server/src/workflow-tools.ts +168 -0
  178. package/packages/mcp-server/tsconfig.tsbuildinfo +1 -1
  179. package/packages/native/package.json +1 -1
  180. package/packages/native/tsconfig.json +2 -1
  181. package/packages/native/tsconfig.tsbuildinfo +1 -1
  182. package/packages/pi-agent-core/package.json +1 -1
  183. package/packages/pi-agent-core/tsconfig.tsbuildinfo +1 -1
  184. package/packages/pi-ai/dist/index.d.ts +2 -2
  185. package/packages/pi-ai/dist/index.d.ts.map +1 -1
  186. package/packages/pi-ai/dist/index.js +1 -1
  187. package/packages/pi-ai/dist/index.js.map +1 -1
  188. package/packages/pi-ai/dist/providers/openai-codex-responses.d.ts.map +1 -1
  189. package/packages/pi-ai/dist/providers/openai-codex-responses.js +82 -1
  190. package/packages/pi-ai/dist/providers/openai-codex-responses.js.map +1 -1
  191. package/packages/pi-ai/dist/providers/openai-codex-responses.test.d.ts +2 -0
  192. package/packages/pi-ai/dist/providers/openai-codex-responses.test.d.ts.map +1 -0
  193. package/packages/pi-ai/dist/providers/openai-codex-responses.test.js +52 -0
  194. package/packages/pi-ai/dist/providers/openai-codex-responses.test.js.map +1 -0
  195. package/packages/pi-ai/dist/providers/simple-options.d.ts +2 -4
  196. package/packages/pi-ai/dist/providers/simple-options.d.ts.map +1 -1
  197. package/packages/pi-ai/dist/providers/simple-options.js +5 -6
  198. package/packages/pi-ai/dist/providers/simple-options.js.map +1 -1
  199. package/packages/pi-ai/dist/providers/simple-options.test.d.ts +2 -0
  200. package/packages/pi-ai/dist/providers/simple-options.test.d.ts.map +1 -0
  201. package/packages/pi-ai/dist/providers/simple-options.test.js +50 -0
  202. package/packages/pi-ai/dist/providers/simple-options.test.js.map +1 -0
  203. package/packages/pi-ai/dist/providers/transform-messages.d.ts +11 -0
  204. package/packages/pi-ai/dist/providers/transform-messages.d.ts.map +1 -1
  205. package/packages/pi-ai/dist/providers/transform-messages.js +20 -0
  206. package/packages/pi-ai/dist/providers/transform-messages.js.map +1 -1
  207. package/packages/pi-ai/package.json +1 -1
  208. package/packages/pi-ai/src/index.ts +7 -2
  209. package/packages/pi-ai/src/providers/openai-codex-responses.test.ts +63 -0
  210. package/packages/pi-ai/src/providers/openai-codex-responses.ts +91 -1
  211. package/packages/pi-ai/src/providers/simple-options.test.ts +60 -0
  212. package/packages/pi-ai/src/providers/simple-options.ts +5 -6
  213. package/packages/pi-ai/src/providers/transform-messages.ts +24 -0
  214. package/packages/pi-ai/tsconfig.tsbuildinfo +1 -1
  215. package/packages/pi-coding-agent/dist/core/agent-session-thinking-level.test.d.ts +2 -0
  216. package/packages/pi-coding-agent/dist/core/agent-session-thinking-level.test.d.ts.map +1 -0
  217. package/packages/pi-coding-agent/dist/core/agent-session-thinking-level.test.js +66 -0
  218. package/packages/pi-coding-agent/dist/core/agent-session-thinking-level.test.js.map +1 -0
  219. package/packages/pi-coding-agent/dist/core/agent-session.js +1 -1
  220. package/packages/pi-coding-agent/dist/core/agent-session.js.map +1 -1
  221. package/packages/pi-coding-agent/dist/core/system-prompt.js +4 -4
  222. package/packages/pi-coding-agent/dist/core/system-prompt.js.map +1 -1
  223. package/packages/pi-coding-agent/dist/modes/interactive/components/footer.d.ts.map +1 -1
  224. package/packages/pi-coding-agent/dist/modes/interactive/components/footer.js +24 -6
  225. package/packages/pi-coding-agent/dist/modes/interactive/components/footer.js.map +1 -1
  226. package/packages/pi-coding-agent/dist/tests/system-prompt-file-safety.test.d.ts +2 -0
  227. package/packages/pi-coding-agent/dist/tests/system-prompt-file-safety.test.d.ts.map +1 -0
  228. package/packages/pi-coding-agent/dist/tests/system-prompt-file-safety.test.js +17 -0
  229. package/packages/pi-coding-agent/dist/tests/system-prompt-file-safety.test.js.map +1 -0
  230. package/packages/pi-coding-agent/package.json +1 -1
  231. package/packages/pi-coding-agent/src/core/agent-session-thinking-level.test.ts +79 -0
  232. package/packages/pi-coding-agent/src/core/agent-session.ts +1 -1
  233. package/packages/pi-coding-agent/src/core/system-prompt.ts +4 -4
  234. package/packages/pi-coding-agent/src/modes/interactive/components/footer.ts +23 -7
  235. package/packages/pi-coding-agent/src/tests/system-prompt-file-safety.test.ts +22 -0
  236. package/packages/pi-coding-agent/tsconfig.tsbuildinfo +1 -1
  237. package/packages/pi-tui/dist/tui.d.ts.map +1 -1
  238. package/packages/pi-tui/dist/tui.js +5 -0
  239. package/packages/pi-tui/dist/tui.js.map +1 -1
  240. package/packages/pi-tui/package.json +1 -1
  241. package/packages/pi-tui/src/tui.ts +6 -0
  242. package/packages/pi-tui/tsconfig.tsbuildinfo +1 -1
  243. package/packages/rpc-client/package.json +1 -1
  244. package/packages/rpc-client/tsconfig.tsbuildinfo +1 -1
  245. package/pkg/package.json +1 -1
  246. package/src/resources/GSD-WORKFLOW.md +10 -1
  247. package/src/resources/extensions/browser-tools/tools/screenshot.ts +1 -0
  248. package/src/resources/extensions/browser-tools/tools/zoom.ts +1 -0
  249. package/src/resources/extensions/claude-code-cli/partial-builder.ts +2 -1
  250. package/src/resources/extensions/claude-code-cli/tests/partial-builder.test.ts +19 -2
  251. package/src/resources/extensions/cmux/index.ts +6 -0
  252. package/src/resources/extensions/gsd/auto/contracts.ts +59 -16
  253. package/src/resources/extensions/gsd/auto/infra-errors.ts +9 -3
  254. package/src/resources/extensions/gsd/auto/loop.ts +8 -5
  255. package/src/resources/extensions/gsd/auto/orchestrator.ts +129 -6
  256. package/src/resources/extensions/gsd/auto/phases.ts +36 -1
  257. package/src/resources/extensions/gsd/auto/workflow-memory-pressure.ts +13 -0
  258. package/src/resources/extensions/gsd/auto-dashboard.ts +72 -1
  259. package/src/resources/extensions/gsd/auto-dispatch.ts +14 -6
  260. package/src/resources/extensions/gsd/auto-model-selection.ts +2 -1
  261. package/src/resources/extensions/gsd/auto-post-unit.ts +266 -139
  262. package/src/resources/extensions/gsd/auto-prompts.ts +13 -5
  263. package/src/resources/extensions/gsd/auto-recovery.ts +29 -0
  264. package/src/resources/extensions/gsd/auto-start.ts +92 -9
  265. package/src/resources/extensions/gsd/auto-verification.ts +36 -34
  266. package/src/resources/extensions/gsd/auto-worktree.ts +119 -1
  267. package/src/resources/extensions/gsd/auto.ts +167 -53
  268. package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +33 -6
  269. package/src/resources/extensions/gsd/bootstrap/db-tools.ts +9 -8
  270. package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +10 -2
  271. package/src/resources/extensions/gsd/bootstrap/subagent-input.ts +19 -7
  272. package/src/resources/extensions/gsd/bootstrap/system-context.ts +58 -15
  273. package/src/resources/extensions/gsd/bootstrap/write-gate.ts +19 -3
  274. package/src/resources/extensions/gsd/clean-root-preflight.ts +174 -8
  275. package/src/resources/extensions/gsd/commands/catalog.ts +4 -1
  276. package/src/resources/extensions/gsd/commands/handlers/core.ts +41 -1
  277. package/src/resources/extensions/gsd/commands-bootstrap.ts +10 -0
  278. package/src/resources/extensions/gsd/commands-handlers.ts +19 -2
  279. package/src/resources/extensions/gsd/context-store.ts +120 -1
  280. package/src/resources/extensions/gsd/crash-recovery.ts +30 -4
  281. package/src/resources/extensions/gsd/db/unit-dispatches.ts +4 -3
  282. package/src/resources/extensions/gsd/db-writer.ts +167 -84
  283. package/src/resources/extensions/gsd/dispatch-guard.ts +2 -2
  284. package/src/resources/extensions/gsd/docs/preferences-reference.md +1 -1
  285. package/src/resources/extensions/gsd/doctor-git-checks.ts +44 -6
  286. package/src/resources/extensions/gsd/doctor-runtime-checks.ts +25 -13
  287. package/src/resources/extensions/gsd/doctor-types.ts +2 -0
  288. package/src/resources/extensions/gsd/doctor.ts +2 -27
  289. package/src/resources/extensions/gsd/export-html.ts +27 -427
  290. package/src/resources/extensions/gsd/git-service.ts +45 -1
  291. package/src/resources/extensions/gsd/gsd-db.ts +3 -0
  292. package/src/resources/extensions/gsd/guided-flow.ts +126 -128
  293. package/src/resources/extensions/gsd/guided-unit-context.ts +30 -0
  294. package/src/resources/extensions/gsd/knowledge-backfill.ts +164 -0
  295. package/src/resources/extensions/gsd/knowledge-capture.ts +160 -0
  296. package/src/resources/extensions/gsd/knowledge-parser.ts +174 -0
  297. package/src/resources/extensions/gsd/knowledge-projection.ts +241 -0
  298. package/src/resources/extensions/gsd/markdown-renderer.ts +6 -1
  299. package/src/resources/extensions/gsd/md-importer.ts +1 -1
  300. package/src/resources/extensions/gsd/memory-backfill.ts +89 -17
  301. package/src/resources/extensions/gsd/memory-consolidation-scanner.ts +277 -0
  302. package/src/resources/extensions/gsd/migrate/command.ts +5 -0
  303. package/src/resources/extensions/gsd/migrate/parsers.ts +11 -0
  304. package/src/resources/extensions/gsd/migrate/preview.ts +10 -0
  305. package/src/resources/extensions/gsd/migrate/transformer.ts +58 -4
  306. package/src/resources/extensions/gsd/migrate/writer.ts +14 -1
  307. package/src/resources/extensions/gsd/migration-auto-check.ts +15 -23
  308. package/src/resources/extensions/gsd/milestone-actions.ts +10 -4
  309. package/src/resources/extensions/gsd/native-git-bridge.ts +54 -12
  310. package/src/resources/extensions/gsd/pending-auto-start.ts +79 -0
  311. package/src/resources/extensions/gsd/post-execution-checks.ts +87 -2
  312. package/src/resources/extensions/gsd/pre-execution-checks.ts +32 -1
  313. package/src/resources/extensions/gsd/prompt-loader.ts +1 -1
  314. package/src/resources/extensions/gsd/prompts/complete-milestone.md +1 -1
  315. package/src/resources/extensions/gsd/prompts/complete-slice.md +1 -1
  316. package/src/resources/extensions/gsd/prompts/discuss-headless.md +8 -8
  317. package/src/resources/extensions/gsd/prompts/discuss.md +9 -9
  318. package/src/resources/extensions/gsd/prompts/guided-discuss-project.md +4 -4
  319. package/src/resources/extensions/gsd/prompts/guided-discuss-requirements.md +3 -3
  320. package/src/resources/extensions/gsd/prompts/plan-slice.md +4 -4
  321. package/src/resources/extensions/gsd/prompts/queue.md +4 -4
  322. package/src/resources/extensions/gsd/prompts/refine-slice.md +2 -2
  323. package/src/resources/extensions/gsd/prompts/rewrite-docs.md +1 -1
  324. package/src/resources/extensions/gsd/prompts/system.md +2 -2
  325. package/src/resources/extensions/gsd/provider-switch-observer.ts +185 -0
  326. package/src/resources/extensions/gsd/smart-entry-routing.ts +77 -0
  327. package/src/resources/extensions/gsd/state-reconciliation/drift/merge-state.ts +8 -1
  328. package/src/resources/extensions/gsd/state-reconciliation/drift/project-md.ts +12 -15
  329. package/src/resources/extensions/gsd/state-reconciliation/drift/roadmap.ts +17 -25
  330. package/src/resources/extensions/gsd/status-guards.ts +5 -0
  331. package/src/resources/extensions/gsd/templates/knowledge.md +2 -2
  332. package/src/resources/extensions/gsd/templates/plan.md +8 -5
  333. package/src/resources/extensions/gsd/templates/task-plan.md +4 -2
  334. package/src/resources/extensions/gsd/tests/auto-dashboard.test.ts +71 -0
  335. package/src/resources/extensions/gsd/tests/auto-deterministic-error-classification-4973.test.ts +116 -0
  336. package/src/resources/extensions/gsd/tests/auto-loop.test.ts +129 -0
  337. package/src/resources/extensions/gsd/tests/auto-orchestrator.test.ts +487 -4
  338. package/src/resources/extensions/gsd/tests/auto-paused-ui-cleanup.test.ts +12 -11
  339. package/src/resources/extensions/gsd/tests/auto-phases-lifecycle.test.ts +53 -2
  340. package/src/resources/extensions/gsd/tests/auto-post-unit-step-message.test.ts +12 -1
  341. package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +15 -1
  342. package/src/resources/extensions/gsd/tests/auto-runtime-state.test.ts +4 -4
  343. package/src/resources/extensions/gsd/tests/auto-start-orphan-bootstrap.test.ts +1 -0
  344. package/src/resources/extensions/gsd/tests/auto-worktree-registry.test.ts +69 -1
  345. package/src/resources/extensions/gsd/tests/brief-command.test.ts +89 -0
  346. package/src/resources/extensions/gsd/tests/browser-tools-compatibility-declarations.test.ts +62 -0
  347. package/src/resources/extensions/gsd/tests/clean-root-preflight.test.ts +107 -2
  348. package/src/resources/extensions/gsd/tests/clear-stale-autostart.test.ts +11 -2
  349. package/src/resources/extensions/gsd/tests/closeout-git-deferral.test.ts +16 -0
  350. package/src/resources/extensions/gsd/tests/complete-milestone.test.ts +4 -1
  351. package/src/resources/extensions/gsd/tests/complete-slice.test.ts +5 -9
  352. package/src/resources/extensions/gsd/tests/complete-task.test.ts +3 -1
  353. package/src/resources/extensions/gsd/tests/context-store-decisions-from-memories.test.ts +312 -0
  354. package/src/resources/extensions/gsd/tests/crash-recovery-via-db.test.ts +43 -2
  355. package/src/resources/extensions/gsd/tests/db-authority-regression.test.ts +208 -0
  356. package/src/resources/extensions/gsd/tests/db-writer.test.ts +13 -8
  357. package/src/resources/extensions/gsd/tests/decisions-projection-from-memories.test.ts +453 -0
  358. package/src/resources/extensions/gsd/tests/decisions-stop-table-writes.test.ts +348 -0
  359. package/src/resources/extensions/gsd/tests/deep-project-auto-loop.test.ts +59 -2
  360. package/src/resources/extensions/gsd/tests/dispatch-complete-milestone-guard.test.ts +39 -0
  361. package/src/resources/extensions/gsd/tests/dispatch-guard.test.ts +27 -0
  362. package/src/resources/extensions/gsd/tests/evidence-cross-ref.test.ts +38 -0
  363. package/src/resources/extensions/gsd/tests/export-html-enhancements.test.ts +8 -0
  364. package/src/resources/extensions/gsd/tests/freeform-decisions.test.ts +8 -4
  365. package/src/resources/extensions/gsd/tests/gsd-tools.test.ts +11 -7
  366. package/src/resources/extensions/gsd/tests/guided-discuss-project-prompt-rendering.test.ts +2 -0
  367. package/src/resources/extensions/gsd/tests/guided-dispatch-root.test.ts +106 -0
  368. package/src/resources/extensions/gsd/tests/guided-flow-session-isolation.test.ts +59 -11
  369. package/src/resources/extensions/gsd/tests/guided-flow.test.ts +21 -0
  370. package/src/resources/extensions/gsd/tests/guided-tool-contract.test.ts +65 -0
  371. package/src/resources/extensions/gsd/tests/headless-milestone-parity.test.ts +7 -7
  372. package/src/resources/extensions/gsd/tests/hook-model-resolution.test.ts +5 -0
  373. package/src/resources/extensions/gsd/tests/infra-error.test.ts +2 -2
  374. package/src/resources/extensions/gsd/tests/infra-errors-cooldown.test.ts +9 -0
  375. package/src/resources/extensions/gsd/tests/integration/doctor-git.test.ts +44 -0
  376. package/src/resources/extensions/gsd/tests/integration/doctor-runtime.test.ts +20 -0
  377. package/src/resources/extensions/gsd/tests/integration/git-service.test.ts +103 -1
  378. package/src/resources/extensions/gsd/tests/integration/integration-lifecycle.test.ts +13 -5
  379. package/src/resources/extensions/gsd/tests/integration/migrate-command.test.ts +48 -3
  380. package/src/resources/extensions/gsd/tests/integration/state-machine-runtime-failures.test.ts +6 -1
  381. package/src/resources/extensions/gsd/tests/knowledge-backfill-projection.test.ts +323 -0
  382. package/src/resources/extensions/gsd/tests/knowledge-capture.test.ts +242 -0
  383. package/src/resources/extensions/gsd/tests/knowledge.test.ts +47 -2
  384. package/src/resources/extensions/gsd/tests/load-knowledge-block-rules-only.test.ts +209 -0
  385. package/src/resources/extensions/gsd/tests/memory-consolidation-scanner.test.ts +316 -0
  386. package/src/resources/extensions/gsd/tests/migrate-transformer.test.ts +5 -1
  387. package/src/resources/extensions/gsd/tests/migrate-validator-parsers.test.ts +24 -1
  388. package/src/resources/extensions/gsd/tests/migrate-writer-integration.test.ts +6 -1
  389. package/src/resources/extensions/gsd/tests/migration-auto-check.test.ts +26 -18
  390. package/src/resources/extensions/gsd/tests/native-git-bridge-exec-fallback.test.ts +63 -2
  391. package/src/resources/extensions/gsd/tests/orphaned-worktree-audit.test.ts +121 -1
  392. package/src/resources/extensions/gsd/tests/park-db-sync.test.ts +55 -1
  393. package/src/resources/extensions/gsd/tests/pending-autostart-scope.test.ts +29 -5
  394. package/src/resources/extensions/gsd/tests/plan-milestone-sketch-render.test.ts +157 -0
  395. package/src/resources/extensions/gsd/tests/plan-milestone.test.ts +26 -0
  396. package/src/resources/extensions/gsd/tests/plan-slice-prompt.test.ts +2 -0
  397. package/src/resources/extensions/gsd/tests/plan-slice.test.ts +225 -1
  398. package/src/resources/extensions/gsd/tests/plan-task.test.ts +17 -0
  399. package/src/resources/extensions/gsd/tests/post-exec-retry-bypass.test.ts +79 -1
  400. package/src/resources/extensions/gsd/tests/post-execution-checks.test.ts +86 -0
  401. package/src/resources/extensions/gsd/tests/post-unit-git-failure.test.ts +1 -1
  402. package/src/resources/extensions/gsd/tests/pre-execution-checks.test.ts +53 -0
  403. package/src/resources/extensions/gsd/tests/prompt-contracts.test.ts +8 -0
  404. package/src/resources/extensions/gsd/tests/prompt-loader.test.ts +23 -0
  405. package/src/resources/extensions/gsd/tests/provider-errors.test.ts +20 -1
  406. package/src/resources/extensions/gsd/tests/provider-switch-observer.test.ts +252 -0
  407. package/src/resources/extensions/gsd/tests/remediation-completion-guard.test.ts +46 -2
  408. package/src/resources/extensions/gsd/tests/session-start-footer.test.ts +16 -4
  409. package/src/resources/extensions/gsd/tests/session-switch-abort-misclassification.test.ts +10 -0
  410. package/src/resources/extensions/gsd/tests/smart-entry-routing.test.ts +113 -0
  411. package/src/resources/extensions/gsd/tests/start-auto-detached.test.ts +53 -2
  412. package/src/resources/extensions/gsd/tests/state-corruption-2945.test.ts +6 -0
  413. package/src/resources/extensions/gsd/tests/state-reconciliation-drift.test.ts +119 -23
  414. package/src/resources/extensions/gsd/tests/stuck-state-via-db.test.ts +64 -1
  415. package/src/resources/extensions/gsd/tests/summary-render-parity.test.ts +7 -3
  416. package/src/resources/extensions/gsd/tests/unit-context-manifest.test.ts +86 -7
  417. package/src/resources/extensions/gsd/tests/verification-gate.test.ts +110 -1
  418. package/src/resources/extensions/gsd/tests/verification-verdict.test.ts +78 -0
  419. package/src/resources/extensions/gsd/tests/workflow-mcp.test.ts +1 -1
  420. package/src/resources/extensions/gsd/tests/workflow-memory-pressure.test.ts +21 -1
  421. package/src/resources/extensions/gsd/tests/workflow-tool-executors.test.ts +1 -1
  422. package/src/resources/extensions/gsd/tests/worktree-git-pathspec.test.ts +39 -0
  423. package/src/resources/extensions/gsd/tests/worktree-journal-events.test.ts +64 -12
  424. package/src/resources/extensions/gsd/tests/worktree-lifecycle.test.ts +25 -0
  425. package/src/resources/extensions/gsd/tests/write-gate-planning-unit.test.ts +54 -0
  426. package/src/resources/extensions/gsd/tools/complete-milestone.ts +8 -10
  427. package/src/resources/extensions/gsd/tools/complete-slice.ts +6 -8
  428. package/src/resources/extensions/gsd/tools/plan-milestone.ts +5 -1
  429. package/src/resources/extensions/gsd/tools/plan-slice.ts +98 -12
  430. package/src/resources/extensions/gsd/tools/workflow-tool-executors.ts +135 -0
  431. package/src/resources/extensions/gsd/types.ts +1 -1
  432. package/src/resources/extensions/gsd/unit-context-manifest.ts +47 -11
  433. package/src/resources/extensions/gsd/validation.ts +23 -1
  434. package/src/resources/extensions/gsd/verification-gate.ts +78 -6
  435. package/src/resources/extensions/gsd/verification-verdict.ts +47 -0
  436. package/src/resources/extensions/gsd/workflow-logger.ts +4 -0
  437. package/src/resources/extensions/gsd/workflow-projections.ts +6 -8
  438. package/src/resources/extensions/gsd/worktree-lifecycle.ts +61 -10
  439. package/src/resources/extensions/shared/html-shell.ts +412 -0
  440. package/src/resources/extensions/subagent/index.ts +567 -103
  441. package/src/resources/extensions/subagent/launch.ts +131 -0
  442. package/src/resources/extensions/subagent/run-store.ts +218 -0
  443. package/src/resources/extensions/subagent/tests/launch.test.ts +115 -0
  444. package/src/resources/extensions/subagent/tests/run-store.test.ts +111 -0
  445. package/src/resources/extensions/visual-brief/artifact-policy.ts +41 -0
  446. package/src/resources/extensions/visual-brief/extension-manifest.json +8 -0
  447. package/src/resources/extensions/visual-brief/index.ts +8 -0
  448. package/src/resources/extensions/visual-brief/page-contract.ts +136 -0
  449. package/src/resources/extensions/visual-brief/prompts.ts +183 -0
  450. package/src/resources/extensions/visual-brief/tests/visual-brief.test.ts +212 -0
  451. package/dist/web/standalone/.next/server/chunks/5822.js +0 -2
  452. package/dist/web/standalone/.next/static/chunks/2556.0527fea66e123b7f.js +0 -1
  453. package/dist/web/standalone/.next/static/chunks/app/layout-a16c7a7ecdf0c2cf.js +0 -1
  454. package/dist/web/standalone/.next/static/css/54ec2745c1da488b.css +0 -1
  455. package/dist/web/standalone/.next/static/css/de70bee13400563f.css +0 -1
  456. package/dist/web/standalone/.next/static/media/4cf2300e9c8272f7-s.p.woff2 +0 -0
  457. package/dist/web/standalone/.next/static/media/747892c23ea88013-s.woff2 +0 -0
  458. package/dist/web/standalone/.next/static/media/8d697b304b401681-s.woff2 +0 -0
  459. package/dist/web/standalone/.next/static/media/93f479601ee12b01-s.p.woff2 +0 -0
  460. package/dist/web/standalone/.next/static/media/9610d9e46709d722-s.woff2 +0 -0
  461. package/dist/web/standalone/.next/static/media/ba015fad6dcf6784-s.woff2 +0 -0
  462. /package/dist/web/standalone/.next/static/{rIkMv4YSNlfSeqmGqWVns → xRy4LqKSNKdT7y6ATYyEl}/_buildManifest.js +0 -0
  463. /package/dist/web/standalone/.next/static/{rIkMv4YSNlfSeqmGqWVns → xRy4LqKSNKdT7y6ATYyEl}/_ssgManifest.js +0 -0
@@ -187,7 +187,7 @@ test('loadKnowledgeBlock: uses project knowledge alone when no global file', ()
187
187
  writeFileSync(join(cwd, '.gsd', 'KNOWLEDGE.md'), 'K001: Use real DB');
188
188
 
189
189
  const result = loadKnowledgeBlock(gsdHome, cwd);
190
- assert.ok(result.block.includes('[KNOWLEDGE — Rules, patterns, and lessons learned]'));
190
+ assert.ok(result.block.includes('[KNOWLEDGE — Rules from KNOWLEDGE.md'));
191
191
  assert.ok(result.block.includes('## Project Knowledge'));
192
192
  assert.ok(result.block.includes('K001: Use real DB'));
193
193
  assert.ok(!result.block.includes('## Global Knowledge'));
@@ -205,7 +205,7 @@ test('loadKnowledgeBlock: uses global knowledge alone when no project file', ()
205
205
  writeFileSync(join(gsdHome, 'agent', 'KNOWLEDGE.md'), 'G001: Respond in English');
206
206
 
207
207
  const result = loadKnowledgeBlock(gsdHome, cwd);
208
- assert.ok(result.block.includes('[KNOWLEDGE — Rules, patterns, and lessons learned]'));
208
+ assert.ok(result.block.includes('[KNOWLEDGE — Rules from KNOWLEDGE.md'));
209
209
  assert.ok(result.block.includes('## Global Knowledge'));
210
210
  assert.ok(result.block.includes('G001: Respond in English'));
211
211
  assert.ok(!result.block.includes('## Project Knowledge'));
@@ -234,6 +234,51 @@ test('loadKnowledgeBlock: merges global before project when both exist', () => {
234
234
  rmSync(tmp, { recursive: true, force: true });
235
235
  });
236
236
 
237
+ test('loadKnowledgeBlock: strips patterns and lessons from project knowledge', () => {
238
+ const tmp = realpathSync(mkdtempSync(join(tmpdir(), 'gsd-kb-strip-')));
239
+ const gsdHome = join(tmp, 'home');
240
+ const cwd = join(tmp, 'project');
241
+ mkdirSync(join(cwd, '.gsd'), { recursive: true });
242
+ mkdirSync(join(gsdHome, 'agent'), { recursive: true });
243
+ writeFileSync(
244
+ join(cwd, '.gsd', 'KNOWLEDGE.md'),
245
+ [
246
+ '# Project Knowledge',
247
+ '',
248
+ 'Intro note that should stay with manual rules.',
249
+ '',
250
+ '## Rules',
251
+ '',
252
+ '| ID | Rule | Notes |',
253
+ '|---|---|---|',
254
+ '| K001 | Use real DB | - |',
255
+ '',
256
+ '## Patterns',
257
+ '',
258
+ '| ID | Pattern | Where | Notes |',
259
+ '|---|---|---|---|',
260
+ '| P001 | Prefer async | server | - |',
261
+ '',
262
+ '## Lessons Learned',
263
+ '',
264
+ '| ID | What Happened | Root Cause | Fix | Scope |',
265
+ '|---|---|---|---|---|',
266
+ '| L001 | Missed cache | N/A | Add TTL | project |',
267
+ ].join('\n'),
268
+ );
269
+
270
+ const result = loadKnowledgeBlock(gsdHome, cwd);
271
+ assert.ok(result.block.includes('[KNOWLEDGE — Rules from KNOWLEDGE.md'));
272
+ assert.ok(result.block.includes('Intro note that should stay with manual rules.'));
273
+ assert.ok(result.block.includes('K001'), 'rules entry should be present');
274
+ assert.ok(!result.block.includes('P001'), 'patterns should be stripped and injected via memories');
275
+ assert.ok(!result.block.includes('L001'), 'lessons should be stripped and injected via memories');
276
+ assert.ok(!result.block.includes('## Patterns'), 'Patterns heading should not appear');
277
+ assert.ok(!result.block.includes('## Lessons Learned'), 'Lessons heading should not appear');
278
+
279
+ rmSync(tmp, { recursive: true, force: true });
280
+ });
281
+
237
282
  test('loadKnowledgeBlock: reports globalSizeKb above 4KB threshold', () => {
238
283
  const tmp = realpathSync(mkdtempSync(join(tmpdir(), 'gsd-kb-')));
239
284
  const gsdHome = join(tmp, 'home');
@@ -0,0 +1,209 @@
1
+ // ADR-013 follow-up — loadKnowledgeBlock injects only Rules from project
2
+ // KNOWLEDGE.md to avoid duplicating Patterns + Lessons content already
3
+ // injected via loadMemoryBlock (Stage 2b cutover).
4
+ //
5
+ // Global KNOWLEDGE.md (~/.gsd/agent/KNOWLEDGE.md) is NOT memory-projected
6
+ // and still passes through with all three sections intact.
7
+
8
+ import test from "node:test";
9
+ import assert from "node:assert/strict";
10
+ import { mkdtempSync, mkdirSync, rmSync, writeFileSync } from "node:fs";
11
+ import { join } from "node:path";
12
+ import { tmpdir } from "node:os";
13
+
14
+ import { loadKnowledgeBlock } from "../bootstrap/system-context.ts";
15
+ import { extractIntroAndRules } from "../knowledge-parser.ts";
16
+
17
+ function makeTmpProject(): string {
18
+ const base = mkdtempSync(join(tmpdir(), "gsd-knowledge-rules-only-"));
19
+ mkdirSync(join(base, ".gsd"), { recursive: true });
20
+ return base;
21
+ }
22
+
23
+ function makeTmpHome(): string {
24
+ const home = mkdtempSync(join(tmpdir(), "gsd-knowledge-home-"));
25
+ mkdirSync(join(home, "agent"), { recursive: true });
26
+ return home;
27
+ }
28
+
29
+ function cleanup(...dirs: string[]): void {
30
+ for (const dir of dirs) {
31
+ try {
32
+ rmSync(dir, { recursive: true, force: true });
33
+ } catch {
34
+ /* noop */
35
+ }
36
+ }
37
+ }
38
+
39
+ const FULL_KNOWLEDGE = `# Project Knowledge
40
+
41
+ Append-only register of project-specific rules, patterns, and lessons learned.
42
+
43
+ ## Rules
44
+
45
+ | # | Scope | Rule | Why | Added |
46
+ |---|-------|------|-----|-------|
47
+ | K001 | project | All timestamps in UTC | clarity | 2026-01-01 |
48
+ | K002 | M001 | Never trust user input | safety | 2026-01-02 |
49
+
50
+ ## Patterns
51
+
52
+ | # | Pattern | Where | Notes |
53
+ |---|---------|-------|-------|
54
+ | P001 | Repository pattern | services/ | guards |
55
+
56
+ ## Lessons Learned
57
+
58
+ | # | What Happened | Root Cause | Fix | Scope |
59
+ |---|--------------|------------|-----|-------|
60
+ | L001 | Cache poisoning | reused key | versioned key | project |
61
+ `;
62
+
63
+ // ─── extractIntroAndRules unit tests ───────────────────────────────────────
64
+
65
+ test("extractIntroAndRules keeps intro + Rules, drops Patterns + Lessons", () => {
66
+ const out = extractIntroAndRules(FULL_KNOWLEDGE);
67
+ assert.match(out, /# Project Knowledge/);
68
+ assert.match(out, /## Rules/);
69
+ assert.match(out, /\| K001 \| project \| All timestamps in UTC/);
70
+ assert.match(out, /\| K002 \| M001 \| Never trust user input/);
71
+
72
+ assert.equal(out.includes("## Patterns"), false, "Patterns heading must be dropped");
73
+ assert.equal(out.includes("P001"), false, "Pattern rows must be dropped");
74
+ assert.equal(out.includes("## Lessons Learned"), false, "Lessons heading must be dropped");
75
+ assert.equal(out.includes("L001"), false, "Lesson rows must be dropped");
76
+ });
77
+
78
+ test("extractIntroAndRules returns content unchanged when no `## Rules` heading", () => {
79
+ const content = "# Notes\n\nfreeform content without standard sections\n";
80
+ assert.equal(extractIntroAndRules(content), content);
81
+ });
82
+
83
+ test("extractIntroAndRules returns empty for empty input", () => {
84
+ assert.equal(extractIntroAndRules(""), "");
85
+ assert.equal(extractIntroAndRules(" \n\n"), "");
86
+ });
87
+
88
+ test("extractIntroAndRules handles Rules as the only section (no Patterns/Lessons to drop)", () => {
89
+ const content = `# Project Knowledge
90
+
91
+ ## Rules
92
+
93
+ | # | Scope | Rule | Why | Added |
94
+ |---|-------|------|-----|-------|
95
+ | K001 | project | only rule | reason | 2026-01-01 |
96
+ `;
97
+ const out = extractIntroAndRules(content);
98
+ assert.match(out, /K001/);
99
+ assert.match(out, /## Rules/);
100
+ });
101
+
102
+ // ─── loadKnowledgeBlock integration ────────────────────────────────────────
103
+
104
+ test("loadKnowledgeBlock trims project KNOWLEDGE.md to intro + Rules", () => {
105
+ const base = makeTmpProject();
106
+ const home = makeTmpHome();
107
+ try {
108
+ writeFileSync(join(base, ".gsd", "KNOWLEDGE.md"), FULL_KNOWLEDGE, "utf-8");
109
+ const { block } = loadKnowledgeBlock(home, base);
110
+
111
+ assert.match(block, /## Project Knowledge/);
112
+ assert.match(block, /K001/);
113
+ assert.match(block, /K002/);
114
+ assert.equal(block.includes("P001"), false, "project Patterns must not appear in the block");
115
+ assert.equal(block.includes("L001"), false, "project Lessons must not appear in the block");
116
+ assert.equal(block.includes("## Patterns"), false);
117
+ assert.equal(block.includes("## Lessons Learned"), false);
118
+ } finally {
119
+ cleanup(base, home);
120
+ }
121
+ });
122
+
123
+ test("loadKnowledgeBlock leaves global KNOWLEDGE.md intact (no memory projection there)", () => {
124
+ const base = makeTmpProject();
125
+ const home = makeTmpHome();
126
+ try {
127
+ writeFileSync(join(home, "agent", "KNOWLEDGE.md"), FULL_KNOWLEDGE, "utf-8");
128
+ const { block, globalSizeKb } = loadKnowledgeBlock(home, base);
129
+
130
+ assert.match(block, /## Global Knowledge/);
131
+ // Global is full-fidelity: all three sections intact.
132
+ assert.match(block, /K001/);
133
+ assert.match(block, /P001/);
134
+ assert.match(block, /L001/);
135
+ assert.match(block, /## Patterns/);
136
+ assert.match(block, /## Lessons Learned/);
137
+ assert.ok(globalSizeKb > 0, "globalSizeKb should report the global file size");
138
+ } finally {
139
+ cleanup(base, home);
140
+ }
141
+ });
142
+
143
+ test("loadKnowledgeBlock with both global and project: global keeps full content, project trimmed", () => {
144
+ const base = makeTmpProject();
145
+ const home = makeTmpHome();
146
+ try {
147
+ writeFileSync(join(home, "agent", "KNOWLEDGE.md"), FULL_KNOWLEDGE, "utf-8");
148
+ writeFileSync(join(base, ".gsd", "KNOWLEDGE.md"), FULL_KNOWLEDGE, "utf-8");
149
+ const { block } = loadKnowledgeBlock(home, base);
150
+
151
+ // Both sections present.
152
+ assert.match(block, /## Global Knowledge/);
153
+ assert.match(block, /## Project Knowledge/);
154
+
155
+ // Project's Patterns/Lessons headings must be gone. But global keeps
156
+ // them, so a substring count of e.g. "## Patterns" should equal 1.
157
+ const patternsCount = (block.match(/## Patterns/g) ?? []).length;
158
+ const lessonsCount = (block.match(/## Lessons Learned/g) ?? []).length;
159
+ assert.equal(patternsCount, 1, "Patterns heading appears exactly once (in global)");
160
+ assert.equal(lessonsCount, 1, "Lessons heading appears exactly once (in global)");
161
+
162
+ // K/P/L rows: K appears twice (global + project), P/L appear once (global).
163
+ const k001Count = (block.match(/K001/g) ?? []).length;
164
+ const p001Count = (block.match(/P001/g) ?? []).length;
165
+ const l001Count = (block.match(/L001/g) ?? []).length;
166
+ assert.equal(k001Count, 2, "K001 in both global and project");
167
+ assert.equal(p001Count, 1, "P001 only in global");
168
+ assert.equal(l001Count, 1, "L001 only in global");
169
+ } finally {
170
+ cleanup(base, home);
171
+ }
172
+ });
173
+
174
+ test("loadKnowledgeBlock returns empty block when neither file exists", () => {
175
+ const base = makeTmpProject();
176
+ const home = makeTmpHome();
177
+ try {
178
+ const result = loadKnowledgeBlock(home, base);
179
+ assert.equal(result.block, "");
180
+ assert.equal(result.globalSizeKb, 0);
181
+ } finally {
182
+ cleanup(base, home);
183
+ }
184
+ });
185
+
186
+ test("loadKnowledgeBlock injects only Rules when project KNOWLEDGE.md has no Patterns/Lessons", () => {
187
+ const base = makeTmpProject();
188
+ const home = makeTmpHome();
189
+ try {
190
+ writeFileSync(
191
+ join(base, ".gsd", "KNOWLEDGE.md"),
192
+ `# Project Knowledge
193
+
194
+ ## Rules
195
+
196
+ | # | Scope | Rule | Why | Added |
197
+ |---|-------|------|-----|-------|
198
+ | K001 | project | rule one | reason | 2026-01-01 |
199
+ `,
200
+ "utf-8",
201
+ );
202
+ const { block } = loadKnowledgeBlock(home, base);
203
+ assert.match(block, /K001/);
204
+ // Block heading reflects the new contract.
205
+ assert.match(block, /Rules from KNOWLEDGE\.md/);
206
+ } finally {
207
+ cleanup(base, home);
208
+ }
209
+ });
@@ -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
+ });
@@ -497,6 +497,7 @@ test('Scenario 11: Requirements edge cases', () => {
497
497
  makeRequirement('', 'Another No ID', 'validated'),
498
498
  makeRequirement('R005', 'Has ID', 'something-weird'),
499
499
  makeRequirement('R006', 'Deferred One', 'DEFERRED'),
500
+ makeRequirement('AUTH-7', 'Legacy ID', 'active'),
500
501
  ],
501
502
  phases: {
502
503
  '1-req-edge': makePhase('1-req-edge', 1, 'req-edge'),
@@ -510,6 +511,8 @@ test('Scenario 11: Requirements edge cases', () => {
510
511
  assert.deepStrictEqual(result.requirements[2]?.id, 'R005', 'req-edge: existing id preserved');
511
512
  assert.deepStrictEqual(result.requirements[2]?.status, 'active', 'req-edge: unknown status normalized to active');
512
513
  assert.deepStrictEqual(result.requirements[3]?.status, 'deferred', 'req-edge: uppercase DEFERRED normalized');
514
+ assert.deepStrictEqual(result.requirements[4]?.id, 'R003', 'req-edge: non-R legacy id gets next canonical id');
515
+ assert.ok(result.requirements[4]?.description.includes('Legacy ID: AUTH-7'), 'req-edge: original legacy id is preserved in description');
513
516
  });
514
517
 
515
518
  // ─── Scenario 12: Vision derivation ────────────────────────────────────────
@@ -553,6 +556,8 @@ test('Scenario 13: Decisions content', () => {
553
556
  const result = transformToGSD(project);
554
557
 
555
558
  assert.ok(result.decisionsContent.includes('decision-01'), 'decisions: extracts key-decisions from summaries');
559
+ assert.ok(result.decisionsContent.includes('| D001 |'), 'decisions: writes DB-importable decision ID');
560
+ assert.ok(result.decisionsContent.includes('| # | When | Scope | Decision | Choice | Rationale | Revisable? | Made By |'), 'decisions: writes canonical table header');
556
561
  });
557
562
 
558
563
  // ─── Scenario 14: No undefined values in output ───────────────────────────
@@ -616,4 +621,3 @@ test('Scenario 15: Empty research', () => {
616
621
  });
617
622
 
618
623
  // ─── Results ───────────────────────────────────────────────────────────────
619
-
@@ -41,6 +41,15 @@ const SAMPLE_ROADMAP = `# Project Roadmap
41
41
  - [ ] 31 — Notifications
42
42
  `;
43
43
 
44
+ const SAMPLE_VERSION_PREFIX_ROADMAP = `# Project Roadmap
45
+
46
+ ## Phases
47
+
48
+ - ✅ **v1.0 MVP** — Phases 1-6 (shipped 2026-02-24)
49
+ - ✅ **v1.1 Onboarding** — Phases 7-9 (shipped 2026-03-01)
50
+ - 🚧 **v1.8 Production** — Phases 44-53
51
+ `;
52
+
44
53
  const SAMPLE_PROJECT = `# My Project
45
54
 
46
55
  A sample project for testing the migration parser.
@@ -246,6 +255,21 @@ test('parseOldRoadmap: flat format', () => {
246
255
  assert.deepStrictEqual(roadmap.phases[1].done, false, 'flat roadmap: second phase not done');
247
256
  });
248
257
 
258
+ test('parseOldRoadmap: emoji version-prefix phase ranges', () => {
259
+ const roadmap = parseOldRoadmap(SAMPLE_VERSION_PREFIX_ROADMAP);
260
+ assert.deepStrictEqual(roadmap.milestones.length, 0, 'version roadmap: no milestone sections');
261
+ assert.deepStrictEqual(roadmap.phases.length, 3, 'version roadmap: 3 phase ranges');
262
+ assert.deepStrictEqual(roadmap.phases[0].number, 1, 'version roadmap: first range starts at phase 1');
263
+ assert.deepStrictEqual(roadmap.phases[0].title, 'MVP', 'version roadmap: first title');
264
+ assert.deepStrictEqual(roadmap.phases[0].done, true, 'version roadmap: first range done');
265
+ assert.deepStrictEqual(roadmap.phases[1].number, 7, 'version roadmap: second range starts at phase 7');
266
+ assert.deepStrictEqual(roadmap.phases[1].title, 'Onboarding', 'version roadmap: second title');
267
+ assert.deepStrictEqual(roadmap.phases[1].done, true, 'version roadmap: second range done');
268
+ assert.deepStrictEqual(roadmap.phases[2].number, 44, 'version roadmap: third range starts at phase 44');
269
+ assert.deepStrictEqual(roadmap.phases[2].title, 'Production', 'version roadmap: third title');
270
+ assert.deepStrictEqual(roadmap.phases[2].done, false, 'version roadmap: third range in progress');
271
+ });
272
+
249
273
  test('parseOldRoadmap: milestone-sectioned with <details>', () => {
250
274
  const roadmap = parseOldRoadmap(SAMPLE_MILESTONE_SECTIONED_ROADMAP);
251
275
  assert.ok(roadmap.milestones.length >= 2, 'ms roadmap: has milestone sections');
@@ -387,4 +411,3 @@ test('parseOldProject', () => {
387
411
  const project = parseOldProject(SAMPLE_PROJECT);
388
412
  assert.deepStrictEqual(project, SAMPLE_PROJECT, 'project: returns raw content');
389
413
  });
390
-
@@ -14,7 +14,7 @@ import { parseSummary } from '../files.ts';
14
14
  import { deriveState } from '../state.ts';
15
15
  import { invalidateAllCaches } from '../cache.ts';
16
16
  import { ensureDbOpen } from '../bootstrap/dynamic-tools.ts';
17
- import { closeDatabase, getAllMilestones } from '../gsd-db.ts';
17
+ import { closeDatabase, getAllMilestones, getArtifact } from '../gsd-db.ts';
18
18
  import { importWrittenMigrationToDb } from '../migrate/command.ts';
19
19
  import type {
20
20
  GSDProject,
@@ -336,7 +336,12 @@ test('Scenario 2: Fully complete project — deriveState phase', async () => {
336
336
  assert.deepStrictEqual(preview.taskCompletionPct, 100, 'complete: preview taskCompletionPct');
337
337
  assert.deepStrictEqual(preview.requirements.total, 0, 'complete: preview requirements total');
338
338
 
339
+ const imported = await importWrittenMigrationToDb(base, preview);
340
+ assert.ok(imported.artifacts >= 6, 'complete: imports generated milestone artifacts');
341
+ assert.ok(getArtifact('milestones/M001/M001-VALIDATION.md') !== null, 'complete: M001-VALIDATION.md imported as artifact');
342
+ assert.ok(getArtifact('milestones/M001/M001-SUMMARY.md') !== null, 'complete: M001-SUMMARY.md imported as artifact');
339
343
  } finally {
344
+ closeDatabase();
340
345
  rmSync(base, { recursive: true, force: true });
341
346
  }
342
347
  });