gsd-pi 2.77.0-dev.eaa4973bc → 2.78.0-dev.aeeb2ca00

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 (545) hide show
  1. package/README.md +53 -17
  2. package/dist/claude-cli-check.js +46 -10
  3. package/dist/headless.js +49 -4
  4. package/dist/resource-loader.d.ts +40 -0
  5. package/dist/resource-loader.js +32 -13
  6. package/dist/resources/extensions/browser-tools/capture.js +9 -0
  7. package/dist/resources/extensions/browser-tools/tests/browser-tools-integration.test.mjs +8 -59
  8. package/dist/resources/extensions/browser-tools/tests/browser-tools-unit.test.cjs +36 -24
  9. package/dist/resources/extensions/browser-tools/tests/capture-sharp-optional.test.cjs +69 -71
  10. package/dist/resources/extensions/browser-tools/tools/forms.js +5 -1
  11. package/dist/resources/extensions/browser-tools/tools/intent.js +5 -1
  12. package/dist/resources/extensions/claude-code-cli/readiness.js +72 -16
  13. package/dist/resources/extensions/claude-code-cli/stream-adapter.js +481 -17
  14. package/dist/resources/extensions/github-sync/templates.js +103 -0
  15. package/dist/resources/extensions/google-search/index.js +3 -2
  16. package/dist/resources/extensions/gsd/auto/loop.js +124 -2
  17. package/dist/resources/extensions/gsd/auto/phases.js +57 -39
  18. package/dist/resources/extensions/gsd/auto/session.js +6 -2
  19. package/dist/resources/extensions/gsd/auto-dispatch.js +142 -29
  20. package/dist/resources/extensions/gsd/auto-model-selection.js +124 -4
  21. package/dist/resources/extensions/gsd/auto-post-unit.js +150 -64
  22. package/dist/resources/extensions/gsd/auto-prompts.js +372 -104
  23. package/dist/resources/extensions/gsd/auto-recovery.js +197 -48
  24. package/dist/resources/extensions/gsd/auto-start.js +107 -29
  25. package/dist/resources/extensions/gsd/auto-tool-tracking.js +47 -7
  26. package/dist/resources/extensions/gsd/auto-worktree.js +122 -26
  27. package/dist/resources/extensions/gsd/auto.js +76 -21
  28. package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +19 -1
  29. package/dist/resources/extensions/gsd/bootstrap/db-tools.js +209 -0
  30. package/dist/resources/extensions/gsd/bootstrap/provider-error-resume.js +3 -6
  31. package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +7 -3
  32. package/dist/resources/extensions/gsd/bootstrap/write-gate.js +127 -9
  33. package/dist/resources/extensions/gsd/component-loader.js +447 -0
  34. package/dist/resources/extensions/gsd/component-types.js +69 -0
  35. package/dist/resources/extensions/gsd/context-store.js +23 -7
  36. package/dist/resources/extensions/gsd/detection.js +49 -1
  37. package/dist/resources/extensions/gsd/dispatch-guard.js +2 -17
  38. package/dist/resources/extensions/gsd/docs/preferences-reference.md +1 -1
  39. package/dist/resources/extensions/gsd/forensics.js +106 -0
  40. package/dist/resources/extensions/gsd/gate-registry.js +2 -2
  41. package/dist/resources/extensions/gsd/git-constants.js +28 -1
  42. package/dist/resources/extensions/gsd/git-self-heal.js +27 -0
  43. package/dist/resources/extensions/gsd/git-service.js +126 -2
  44. package/dist/resources/extensions/gsd/gsd-db.js +6 -3
  45. package/dist/resources/extensions/gsd/guided-flow.js +39 -13
  46. package/dist/resources/extensions/gsd/memory-extractor.js +7 -1
  47. package/dist/resources/extensions/gsd/milestone-scope-classifier.js +299 -0
  48. package/dist/resources/extensions/gsd/milestone-summary-classifier.js +37 -0
  49. package/dist/resources/extensions/gsd/model-cost-table.js +3 -0
  50. package/dist/resources/extensions/gsd/model-router.js +6 -0
  51. package/dist/resources/extensions/gsd/native-git-bridge.js +34 -4
  52. package/dist/resources/extensions/gsd/preferences-validation.js +23 -0
  53. package/dist/resources/extensions/gsd/prompt-cache-optimizer.js +4 -0
  54. package/dist/resources/extensions/gsd/prompts/complete-milestone.md +6 -2
  55. package/dist/resources/extensions/gsd/prompts/discuss-headless.md +23 -4
  56. package/dist/resources/extensions/gsd/prompts/doctor-heal.md +5 -4
  57. package/dist/resources/extensions/gsd/prompts/plan-slice.md +15 -2
  58. package/dist/resources/extensions/gsd/safety/git-checkpoint.js +11 -0
  59. package/dist/resources/extensions/gsd/service-tier.js +5 -2
  60. package/dist/resources/extensions/gsd/session-lock.js +19 -10
  61. package/dist/resources/extensions/gsd/skill-manifest.js +168 -0
  62. package/dist/resources/extensions/gsd/slice-cadence.js +238 -0
  63. package/dist/resources/extensions/gsd/slice-parallel-orchestrator.js +278 -8
  64. package/dist/resources/extensions/gsd/state-transition-matrix.js +118 -0
  65. package/dist/resources/extensions/gsd/state.js +69 -58
  66. package/dist/resources/extensions/gsd/sync-lock.js +98 -42
  67. package/dist/resources/extensions/gsd/tools/validate-milestone.js +7 -2
  68. package/dist/resources/extensions/gsd/unit-context-composer.js +147 -0
  69. package/dist/resources/extensions/gsd/unit-context-manifest.js +370 -0
  70. package/dist/resources/extensions/gsd/uok/dispatch-envelope.js +33 -0
  71. package/dist/resources/extensions/gsd/uok/execution-graph.js +10 -0
  72. package/dist/resources/extensions/gsd/uok/gate-runner.js +53 -5
  73. package/dist/resources/extensions/gsd/uok/gitops.js +2 -1
  74. package/dist/resources/extensions/gsd/uok/loop-adapter.js +37 -10
  75. package/dist/resources/extensions/gsd/uok/parity-report.js +58 -0
  76. package/dist/resources/extensions/gsd/uok/plan-v2.js +10 -4
  77. package/dist/resources/extensions/gsd/uok/writer.js +82 -0
  78. package/dist/resources/extensions/gsd/workflow-mcp.js +6 -0
  79. package/dist/resources/extensions/gsd/worktree-manager.js +85 -8
  80. package/dist/resources/extensions/gsd/worktree-resolver.js +86 -7
  81. package/dist/resources/extensions/gsd/worktree-telemetry.js +198 -0
  82. package/dist/resources/extensions/mcp-client/index.js +3 -1
  83. package/dist/resources/extensions/ollama/index.js +5 -1
  84. package/dist/resources/extensions/remote-questions/manager.js +11 -5
  85. package/dist/tsconfig.extensions.tsbuildinfo +1 -1
  86. package/dist/web/standalone/.next/BUILD_ID +1 -1
  87. package/dist/web/standalone/.next/app-path-routes-manifest.json +11 -11
  88. package/dist/web/standalone/.next/build-manifest.json +2 -2
  89. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  90. package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
  91. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  92. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  93. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  94. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  95. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  96. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  97. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  98. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  99. package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
  100. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
  101. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  102. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
  103. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  104. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  105. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  106. package/dist/web/standalone/.next/server/app/api/git/route.js +1 -1
  107. package/dist/web/standalone/.next/server/app/index.html +1 -1
  108. package/dist/web/standalone/.next/server/app/index.rsc +1 -1
  109. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
  110. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +1 -1
  111. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  112. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
  113. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  114. package/dist/web/standalone/.next/server/app-paths-manifest.json +11 -11
  115. package/dist/web/standalone/.next/server/chunks/1926.js +1 -1
  116. package/dist/web/standalone/.next/server/chunks/6897.js +1 -1
  117. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  118. package/dist/web/standalone/.next/server/middleware-manifest.json +5 -5
  119. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  120. package/dist/web/standalone/.next/server/pages/500.html +1 -1
  121. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  122. package/package.json +2 -3
  123. package/packages/daemon/package.json +2 -2
  124. package/packages/daemon/src/logger.ts +4 -3
  125. package/packages/mcp-server/dist/server.d.ts +24 -0
  126. package/packages/mcp-server/dist/server.d.ts.map +1 -1
  127. package/packages/mcp-server/dist/server.js +88 -87
  128. package/packages/mcp-server/dist/server.js.map +1 -1
  129. package/packages/mcp-server/dist/workflow-tools.d.ts.map +1 -1
  130. package/packages/mcp-server/dist/workflow-tools.js +15 -6
  131. package/packages/mcp-server/dist/workflow-tools.js.map +1 -1
  132. package/packages/mcp-server/package.json +2 -2
  133. package/packages/mcp-server/src/mcp-server.test.ts +25 -3
  134. package/packages/mcp-server/src/readers/graph.test.ts +87 -15
  135. package/packages/mcp-server/src/secure-env-collect.test.ts +232 -237
  136. package/packages/mcp-server/src/server.ts +131 -105
  137. package/packages/mcp-server/src/workflow-tools.test.ts +85 -0
  138. package/packages/mcp-server/src/workflow-tools.ts +19 -6
  139. package/packages/mcp-server/tsconfig.tsbuildinfo +1 -1
  140. package/packages/native/package.json +2 -2
  141. package/packages/native/src/__tests__/_test-coverage-guard.test.mjs +98 -0
  142. package/packages/native/src/__tests__/module-compat.test.mjs +59 -27
  143. package/packages/native/src/__tests__/ps.test.mjs +14 -8
  144. package/packages/native/src/__tests__/stream-process.test.mjs +23 -2
  145. package/packages/native/src/__tests__/truncate.test.mjs +17 -2
  146. package/packages/pi-agent-core/package.json +1 -1
  147. package/packages/pi-agent-core/src/agent-loop.test.ts +5 -15
  148. package/packages/pi-agent-core/src/agent.test.ts +96 -102
  149. package/packages/pi-agent-core/tsconfig.tsbuildinfo +1 -1
  150. package/packages/pi-ai/dist/models/capability-patches.d.ts.map +1 -1
  151. package/packages/pi-ai/dist/models/capability-patches.js +9 -2
  152. package/packages/pi-ai/dist/models/capability-patches.js.map +1 -1
  153. package/packages/pi-ai/dist/models/generated/index.d.ts +34 -0
  154. package/packages/pi-ai/dist/models/generated/index.d.ts.map +1 -1
  155. package/packages/pi-ai/dist/models/generated/openai-codex.d.ts +17 -0
  156. package/packages/pi-ai/dist/models/generated/openai-codex.d.ts.map +1 -1
  157. package/packages/pi-ai/dist/models/generated/openai-codex.js +17 -0
  158. package/packages/pi-ai/dist/models/generated/openai-codex.js.map +1 -1
  159. package/packages/pi-ai/dist/models/generated/openai.d.ts +17 -0
  160. package/packages/pi-ai/dist/models/generated/openai.d.ts.map +1 -1
  161. package/packages/pi-ai/dist/models/generated/openai.js +17 -0
  162. package/packages/pi-ai/dist/models/generated/openai.js.map +1 -1
  163. package/packages/pi-ai/dist/models.generated.test.js +43 -70
  164. package/packages/pi-ai/dist/models.generated.test.js.map +1 -1
  165. package/packages/pi-ai/dist/models.test.js +36 -11
  166. package/packages/pi-ai/dist/models.test.js.map +1 -1
  167. package/packages/pi-ai/package.json +1 -1
  168. package/packages/pi-ai/scripts/generate-models.ts +44 -0
  169. package/packages/pi-ai/src/models/capability-patches.ts +10 -2
  170. package/packages/pi-ai/src/models/generated/openai-codex.ts +17 -0
  171. package/packages/pi-ai/src/models/generated/openai.ts +17 -0
  172. package/packages/pi-ai/src/models.generated.test.ts +46 -73
  173. package/packages/pi-ai/src/models.test.ts +48 -11
  174. package/packages/pi-ai/tsconfig.tsbuildinfo +1 -1
  175. package/packages/pi-coding-agent/dist/core/agent-session-abort-order.test.js +96 -32
  176. package/packages/pi-coding-agent/dist/core/agent-session-abort-order.test.js.map +1 -1
  177. package/packages/pi-coding-agent/dist/core/agent-session-model-switch.test.js +75 -12
  178. package/packages/pi-coding-agent/dist/core/agent-session-model-switch.test.js.map +1 -1
  179. package/packages/pi-coding-agent/dist/core/agent-session-tool-refresh.test.js +99 -31
  180. package/packages/pi-coding-agent/dist/core/agent-session-tool-refresh.test.js.map +1 -1
  181. package/packages/pi-coding-agent/dist/core/extensions/loader.d.ts +5 -0
  182. package/packages/pi-coding-agent/dist/core/extensions/loader.d.ts.map +1 -1
  183. package/packages/pi-coding-agent/dist/core/extensions/loader.js +61 -0
  184. package/packages/pi-coding-agent/dist/core/extensions/loader.js.map +1 -1
  185. package/packages/pi-coding-agent/dist/core/lsp/lsp-integration.test.js +30 -4
  186. package/packages/pi-coding-agent/dist/core/lsp/lsp-integration.test.js.map +1 -1
  187. package/packages/pi-coding-agent/dist/core/model-registry-auth-mode.test.js +17 -0
  188. package/packages/pi-coding-agent/dist/core/model-registry-auth-mode.test.js.map +1 -1
  189. package/packages/pi-coding-agent/dist/core/resource-loader-cache-reset.test.js +76 -18
  190. package/packages/pi-coding-agent/dist/core/resource-loader-cache-reset.test.js.map +1 -1
  191. package/packages/pi-coding-agent/dist/core/retry-handler.d.ts.map +1 -1
  192. package/packages/pi-coding-agent/dist/core/retry-handler.js +2 -6
  193. package/packages/pi-coding-agent/dist/core/retry-handler.js.map +1 -1
  194. package/packages/pi-coding-agent/dist/core/retry-handler.test.js +5 -1
  195. package/packages/pi-coding-agent/dist/core/retry-handler.test.js.map +1 -1
  196. package/packages/pi-coding-agent/dist/core/retryable-error-regex.d.ts +18 -0
  197. package/packages/pi-coding-agent/dist/core/retryable-error-regex.d.ts.map +1 -0
  198. package/packages/pi-coding-agent/dist/core/retryable-error-regex.js +18 -0
  199. package/packages/pi-coding-agent/dist/core/retryable-error-regex.js.map +1 -0
  200. package/packages/pi-coding-agent/dist/core/system-prompt.d.ts +20 -0
  201. package/packages/pi-coding-agent/dist/core/system-prompt.d.ts.map +1 -1
  202. package/packages/pi-coding-agent/dist/core/system-prompt.js +16 -2
  203. package/packages/pi-coding-agent/dist/core/system-prompt.js.map +1 -1
  204. package/packages/pi-coding-agent/dist/index.d.ts +1 -0
  205. package/packages/pi-coding-agent/dist/index.d.ts.map +1 -1
  206. package/packages/pi-coding-agent/dist/index.js +1 -0
  207. package/packages/pi-coding-agent/dist/index.js.map +1 -1
  208. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/tool-execution.test.js +36 -5
  209. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/tool-execution.test.js.map +1 -1
  210. package/packages/pi-coding-agent/dist/modes/interactive/components/dynamic-border.test.js +20 -13
  211. package/packages/pi-coding-agent/dist/modes/interactive/components/dynamic-border.test.js.map +1 -1
  212. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  213. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js +30 -12
  214. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js.map +1 -1
  215. package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.d.ts.map +1 -1
  216. package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.js +18 -3
  217. package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.js.map +1 -1
  218. package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.test.js +125 -0
  219. package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.test.js.map +1 -1
  220. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-state.d.ts +2 -0
  221. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-state.d.ts.map +1 -1
  222. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-state.js.map +1 -1
  223. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts +4 -0
  224. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  225. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js +105 -13
  226. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
  227. package/packages/pi-coding-agent/dist/tests/system-prompt-skill-filter.test.d.ts +2 -0
  228. package/packages/pi-coding-agent/dist/tests/system-prompt-skill-filter.test.d.ts.map +1 -0
  229. package/packages/pi-coding-agent/dist/tests/system-prompt-skill-filter.test.js +130 -0
  230. package/packages/pi-coding-agent/dist/tests/system-prompt-skill-filter.test.js.map +1 -0
  231. package/packages/pi-coding-agent/package.json +1 -1
  232. package/packages/pi-coding-agent/src/core/agent-session-abort-order.test.ts +113 -37
  233. package/packages/pi-coding-agent/src/core/agent-session-model-switch.test.ts +89 -17
  234. package/packages/pi-coding-agent/src/core/agent-session-tool-refresh.test.ts +112 -43
  235. package/packages/pi-coding-agent/src/core/extensions/loader.ts +58 -0
  236. package/packages/pi-coding-agent/src/core/lsp/lsp-integration.test.ts +35 -4
  237. package/packages/pi-coding-agent/src/core/model-registry-auth-mode.test.ts +20 -0
  238. package/packages/pi-coding-agent/src/core/resource-loader-cache-reset.test.ts +93 -28
  239. package/packages/pi-coding-agent/src/core/retry-handler.test.ts +5 -1
  240. package/packages/pi-coding-agent/src/core/retry-handler.ts +2 -8
  241. package/packages/pi-coding-agent/src/core/retryable-error-regex.ts +18 -0
  242. package/packages/pi-coding-agent/src/core/system-prompt.ts +35 -1
  243. package/packages/pi-coding-agent/src/index.ts +1 -0
  244. package/packages/pi-coding-agent/src/modes/interactive/components/__tests__/tool-execution.test.ts +49 -3
  245. package/packages/pi-coding-agent/src/modes/interactive/components/dynamic-border.test.ts +26 -20
  246. package/packages/pi-coding-agent/src/modes/interactive/components/tool-execution.ts +48 -9
  247. package/packages/pi-coding-agent/src/modes/interactive/controllers/input-controller.test.ts +146 -1
  248. package/packages/pi-coding-agent/src/modes/interactive/controllers/input-controller.ts +20 -3
  249. package/packages/pi-coding-agent/src/modes/interactive/interactive-mode-state.ts +2 -0
  250. package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +119 -13
  251. package/packages/pi-coding-agent/src/tests/system-prompt-skill-filter.test.ts +157 -0
  252. package/packages/pi-coding-agent/tsconfig.tsbuildinfo +1 -1
  253. package/packages/pi-tui/dist/__tests__/autocomplete.test.js +18 -8
  254. package/packages/pi-tui/dist/__tests__/autocomplete.test.js.map +1 -1
  255. package/packages/pi-tui/dist/__tests__/overlay-layout.test.js +128 -17
  256. package/packages/pi-tui/dist/__tests__/overlay-layout.test.js.map +1 -1
  257. package/packages/pi-tui/dist/__tests__/stdin-buffer.test.js +37 -11
  258. package/packages/pi-tui/dist/__tests__/stdin-buffer.test.js.map +1 -1
  259. package/packages/pi-tui/dist/__tests__/tui.test.js +18 -30
  260. package/packages/pi-tui/dist/__tests__/tui.test.js.map +1 -1
  261. package/packages/pi-tui/dist/components/__tests__/input.test.js +10 -3
  262. package/packages/pi-tui/dist/components/__tests__/input.test.js.map +1 -1
  263. package/packages/pi-tui/dist/components/__tests__/loader.test.js +53 -9
  264. package/packages/pi-tui/dist/components/__tests__/loader.test.js.map +1 -1
  265. package/packages/pi-tui/dist/components/__tests__/markdown-maxlines.test.js +6 -2
  266. package/packages/pi-tui/dist/components/__tests__/markdown-maxlines.test.js.map +1 -1
  267. package/packages/pi-tui/dist/components/editor.d.ts +14 -0
  268. package/packages/pi-tui/dist/components/editor.d.ts.map +1 -1
  269. package/packages/pi-tui/dist/components/editor.js +19 -0
  270. package/packages/pi-tui/dist/components/editor.js.map +1 -1
  271. package/packages/pi-tui/dist/components/image.test.js +6 -5
  272. package/packages/pi-tui/dist/components/image.test.js.map +1 -1
  273. package/packages/pi-tui/dist/editor-component.d.ts +2 -0
  274. package/packages/pi-tui/dist/editor-component.d.ts.map +1 -1
  275. package/packages/pi-tui/dist/editor-component.js.map +1 -1
  276. package/packages/pi-tui/package.json +1 -1
  277. package/packages/pi-tui/src/__tests__/autocomplete.test.ts +24 -8
  278. package/packages/pi-tui/src/__tests__/overlay-layout.test.ts +140 -17
  279. package/packages/pi-tui/src/__tests__/stdin-buffer.test.ts +42 -11
  280. package/packages/pi-tui/src/__tests__/tui.test.ts +18 -37
  281. package/packages/pi-tui/src/components/__tests__/input.test.ts +19 -3
  282. package/packages/pi-tui/src/components/__tests__/loader.test.ts +112 -35
  283. package/packages/pi-tui/src/components/__tests__/markdown-maxlines.test.ts +9 -2
  284. package/packages/pi-tui/src/components/editor.ts +22 -0
  285. package/packages/pi-tui/src/components/image.test.ts +10 -5
  286. package/packages/pi-tui/src/editor-component.ts +3 -0
  287. package/packages/pi-tui/tsconfig.tsbuildinfo +1 -1
  288. package/packages/rpc-client/dist/rpc-client.test.js +101 -51
  289. package/packages/rpc-client/dist/rpc-client.test.js.map +1 -1
  290. package/packages/rpc-client/package.json +1 -1
  291. package/packages/rpc-client/src/rpc-client.test.ts +109 -52
  292. package/packages/rpc-client/tsconfig.tsbuildinfo +1 -1
  293. package/pkg/package.json +1 -1
  294. package/scripts/install.js +15 -1
  295. package/src/resources/extensions/browser-tools/capture.ts +12 -0
  296. package/src/resources/extensions/browser-tools/tests/browser-tools-integration.test.mjs +8 -59
  297. package/src/resources/extensions/browser-tools/tests/browser-tools-unit.test.cjs +36 -24
  298. package/src/resources/extensions/browser-tools/tests/capture-sharp-optional.test.cjs +69 -71
  299. package/src/resources/extensions/browser-tools/tools/forms.ts +5 -1
  300. package/src/resources/extensions/browser-tools/tools/intent.ts +5 -1
  301. package/src/resources/extensions/claude-code-cli/readiness.ts +75 -16
  302. package/src/resources/extensions/claude-code-cli/stream-adapter.ts +518 -19
  303. package/src/resources/extensions/claude-code-cli/tests/stream-adapter.test.ts +919 -75
  304. package/src/resources/extensions/github-sync/templates.ts +151 -0
  305. package/src/resources/extensions/github-sync/tests/cli.test.ts +76 -7
  306. package/src/resources/extensions/github-sync/tests/templates.test.ts +92 -1
  307. package/src/resources/extensions/google-search/index.ts +3 -2
  308. package/src/resources/extensions/gsd/auto/loop.ts +142 -2
  309. package/src/resources/extensions/gsd/auto/phases.ts +62 -38
  310. package/src/resources/extensions/gsd/auto/session.ts +7 -2
  311. package/src/resources/extensions/gsd/auto-dispatch.ts +156 -29
  312. package/src/resources/extensions/gsd/auto-model-selection.ts +131 -4
  313. package/src/resources/extensions/gsd/auto-post-unit.ts +163 -73
  314. package/src/resources/extensions/gsd/auto-prompts.ts +385 -93
  315. package/src/resources/extensions/gsd/auto-recovery.ts +230 -51
  316. package/src/resources/extensions/gsd/auto-start.ts +127 -9
  317. package/src/resources/extensions/gsd/auto-tool-tracking.ts +51 -7
  318. package/src/resources/extensions/gsd/auto-worktree.ts +130 -26
  319. package/src/resources/extensions/gsd/auto.ts +90 -23
  320. package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +20 -1
  321. package/src/resources/extensions/gsd/bootstrap/db-tools.ts +221 -0
  322. package/src/resources/extensions/gsd/bootstrap/provider-error-resume.ts +3 -7
  323. package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +7 -3
  324. package/src/resources/extensions/gsd/bootstrap/write-gate.ts +158 -9
  325. package/src/resources/extensions/gsd/component-loader.ts +598 -0
  326. package/src/resources/extensions/gsd/component-types.ts +362 -0
  327. package/src/resources/extensions/gsd/context-store.ts +25 -8
  328. package/src/resources/extensions/gsd/detection.ts +58 -1
  329. package/src/resources/extensions/gsd/dispatch-guard.ts +2 -20
  330. package/src/resources/extensions/gsd/docs/preferences-reference.md +1 -1
  331. package/src/resources/extensions/gsd/forensics.ts +118 -1
  332. package/src/resources/extensions/gsd/gate-registry.ts +2 -2
  333. package/src/resources/extensions/gsd/git-constants.ts +30 -1
  334. package/src/resources/extensions/gsd/git-self-heal.ts +31 -0
  335. package/src/resources/extensions/gsd/git-service.ts +149 -2
  336. package/src/resources/extensions/gsd/gsd-db.ts +6 -3
  337. package/src/resources/extensions/gsd/guided-flow.ts +57 -14
  338. package/src/resources/extensions/gsd/journal.ts +11 -1
  339. package/src/resources/extensions/gsd/memory-extractor.ts +11 -3
  340. package/src/resources/extensions/gsd/milestone-scope-classifier.ts +366 -0
  341. package/src/resources/extensions/gsd/milestone-summary-classifier.ts +42 -0
  342. package/src/resources/extensions/gsd/model-cost-table.ts +3 -0
  343. package/src/resources/extensions/gsd/model-router.ts +6 -0
  344. package/src/resources/extensions/gsd/native-git-bridge.ts +34 -4
  345. package/src/resources/extensions/gsd/preferences-validation.ts +21 -0
  346. package/src/resources/extensions/gsd/prompt-cache-optimizer.ts +4 -0
  347. package/src/resources/extensions/gsd/prompts/complete-milestone.md +6 -2
  348. package/src/resources/extensions/gsd/prompts/discuss-headless.md +23 -4
  349. package/src/resources/extensions/gsd/prompts/doctor-heal.md +5 -4
  350. package/src/resources/extensions/gsd/prompts/plan-slice.md +15 -2
  351. package/src/resources/extensions/gsd/safety/git-checkpoint.ts +15 -0
  352. package/src/resources/extensions/gsd/service-tier.ts +5 -2
  353. package/src/resources/extensions/gsd/session-lock.ts +20 -10
  354. package/src/resources/extensions/gsd/skill-manifest.ts +175 -0
  355. package/src/resources/extensions/gsd/slice-cadence.ts +299 -0
  356. package/src/resources/extensions/gsd/slice-parallel-orchestrator.ts +309 -8
  357. package/src/resources/extensions/gsd/state-transition-matrix.ts +152 -0
  358. package/src/resources/extensions/gsd/state.ts +76 -66
  359. package/src/resources/extensions/gsd/sync-lock.ts +97 -39
  360. package/src/resources/extensions/gsd/tests/artifact-retry-cap.test.ts +270 -0
  361. package/src/resources/extensions/gsd/tests/artifacts-table-preserved-on-cache-invalidate.test.ts +2 -1
  362. package/src/resources/extensions/gsd/tests/auto-deterministic-error-classification-4973.test.ts +341 -0
  363. package/src/resources/extensions/gsd/tests/auto-discuss-milestone-deadlock-4973.test.ts +264 -0
  364. package/src/resources/extensions/gsd/tests/auto-loop.test.ts +133 -292
  365. package/src/resources/extensions/gsd/tests/auto-model-selection-tool-poisoning.test.ts +742 -0
  366. package/src/resources/extensions/gsd/tests/auto-model-selection.test.ts +78 -0
  367. package/src/resources/extensions/gsd/tests/auto-phases-lifecycle.test.ts +61 -0
  368. package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +93 -0
  369. package/src/resources/extensions/gsd/tests/auto-remediate-slice-status.test.ts +4 -1
  370. package/src/resources/extensions/gsd/tests/auto-retry-mcp-churn-fixes.test.ts +8 -194
  371. package/src/resources/extensions/gsd/tests/auto-start-clean-runtime-db-gated.test.ts +3 -2
  372. package/src/resources/extensions/gsd/tests/auto-start-cold-db-bootstrap.test.ts +2 -2
  373. package/src/resources/extensions/gsd/tests/auto-start-needs-discussion.test.ts +15 -58
  374. package/src/resources/extensions/gsd/tests/auto-start-worktree-db-path.test.ts +2 -2
  375. package/src/resources/extensions/gsd/tests/auto-thinking-restore.test.ts +3 -2
  376. package/src/resources/extensions/gsd/tests/auto-warning-noise-regression.test.ts +3 -2
  377. package/src/resources/extensions/gsd/tests/bootstrap-derive-state-db-open.test.ts +2 -1
  378. package/src/resources/extensions/gsd/tests/cache-staleness-regression.test.ts +17 -21
  379. package/src/resources/extensions/gsd/tests/canonical-milestone-root.test.ts +108 -0
  380. package/src/resources/extensions/gsd/tests/complete-milestone-excerpt.test.ts +263 -0
  381. package/src/resources/extensions/gsd/tests/complete-milestone.test.ts +25 -0
  382. package/src/resources/extensions/gsd/tests/complete-slice-composer.test.ts +192 -0
  383. package/src/resources/extensions/gsd/tests/complete-slice-verification-gate.test.ts +2 -1
  384. package/src/resources/extensions/gsd/tests/complete-task.test.ts +16 -8
  385. package/src/resources/extensions/gsd/tests/component-loader.test.ts +589 -0
  386. package/src/resources/extensions/gsd/tests/component-types.test.ts +127 -0
  387. package/src/resources/extensions/gsd/tests/context-store.test.ts +79 -0
  388. package/src/resources/extensions/gsd/tests/copy-planning-artifacts-samepath.test.ts +2 -1
  389. package/src/resources/extensions/gsd/tests/crash-recovery.test.ts +50 -1
  390. package/src/resources/extensions/gsd/tests/custom-engine-loop-integration.test.ts +159 -0
  391. package/src/resources/extensions/gsd/tests/db-access-guardrails.test.ts +1 -0
  392. package/src/resources/extensions/gsd/tests/derive-state-crossval.test.ts +3 -3
  393. package/src/resources/extensions/gsd/tests/derive-state-db-disk-reconcile.test.ts +40 -0
  394. package/src/resources/extensions/gsd/tests/derive-state-db.test.ts +91 -3
  395. package/src/resources/extensions/gsd/tests/derive-state.test.ts +4 -4
  396. package/src/resources/extensions/gsd/tests/discuss-slice-structured-questions.test.ts +2 -1
  397. package/src/resources/extensions/gsd/tests/discuss-tool-scope-leak.test.ts +2 -1
  398. package/src/resources/extensions/gsd/tests/dispatch-complete-milestone-guard.test.ts +5 -0
  399. package/src/resources/extensions/gsd/tests/dispatch-guard.test.ts +25 -0
  400. package/src/resources/extensions/gsd/tests/dispatch-missing-task-plans.test.ts +14 -0
  401. package/src/resources/extensions/gsd/tests/dispatcher-stuck-planning.test.ts +3 -2
  402. package/src/resources/extensions/gsd/tests/double-merge-guard.test.ts +4 -3
  403. package/src/resources/extensions/gsd/tests/empty-content-abort-loop.test.ts +4 -3
  404. package/src/resources/extensions/gsd/tests/execution-entry-missing-context-4671.test.ts +173 -0
  405. package/src/resources/extensions/gsd/tests/extension-bootstrap-isolation.test.ts +139 -129
  406. package/src/resources/extensions/gsd/tests/finalize-timeout-guard.test.ts +8 -104
  407. package/src/resources/extensions/gsd/tests/gate-state-canonicalization.test.ts +102 -0
  408. package/src/resources/extensions/gsd/tests/gate-storage.test.ts +1 -1
  409. package/src/resources/extensions/gsd/tests/google-search-stub.test.ts +14 -4
  410. package/src/resources/extensions/gsd/tests/headless-milestone-parity.test.ts +117 -0
  411. package/src/resources/extensions/gsd/tests/hook-key-parsing.test.ts +4 -55
  412. package/src/resources/extensions/gsd/tests/integration/all-milestones-complete-merge.test.ts +7 -56
  413. package/src/resources/extensions/gsd/tests/integration/auto-recovery.test.ts +20 -0
  414. package/src/resources/extensions/gsd/tests/integration/doctor-proactive.test.ts +18 -2
  415. package/src/resources/extensions/gsd/tests/integration/queue-completed-milestone-perf.test.ts +10 -4
  416. package/src/resources/extensions/gsd/tests/integration/state-machine-edge-cases.test.ts +144 -7
  417. package/src/resources/extensions/gsd/tests/integration/state-machine-live-validation.test.ts +4 -0
  418. package/src/resources/extensions/gsd/tests/integration/state-machine-runtime-failures.test.ts +2 -16
  419. package/src/resources/extensions/gsd/tests/interactive-routing-bypass.test.ts +9 -3
  420. package/src/resources/extensions/gsd/tests/interrupted-session-ui.test.ts +6 -9
  421. package/src/resources/extensions/gsd/tests/journal-integration.test.ts +64 -0
  422. package/src/resources/extensions/gsd/tests/knowledge.test.ts +93 -1
  423. package/src/resources/extensions/gsd/tests/mcp-client-security.test.ts +8 -37
  424. package/src/resources/extensions/gsd/tests/memory-extractor.test.ts +5 -15
  425. package/src/resources/extensions/gsd/tests/merge-conflict-stops-loop.test.ts +227 -55
  426. package/src/resources/extensions/gsd/tests/milestone-scope-classifier.test.ts +187 -0
  427. package/src/resources/extensions/gsd/tests/milestone-summary-classifier.test.ts +30 -0
  428. package/src/resources/extensions/gsd/tests/model-cost-table.test.ts +9 -1
  429. package/src/resources/extensions/gsd/tests/model-router.test.ts +1 -1
  430. package/src/resources/extensions/gsd/tests/native-git-bridge-exec-fallback.test.ts +6 -48
  431. package/src/resources/extensions/gsd/tests/notification-widget.test.ts +6 -3
  432. package/src/resources/extensions/gsd/tests/orphaned-worktree-audit.test.ts +59 -2
  433. package/src/resources/extensions/gsd/tests/parallel-research-dispatch.test.ts +273 -130
  434. package/src/resources/extensions/gsd/tests/pipeline-variant-dispatch.test.ts +301 -0
  435. package/src/resources/extensions/gsd/tests/pre-execution-pause-wiring.test.ts +32 -1
  436. package/src/resources/extensions/gsd/tests/preferences-worktree-sync.test.ts +2 -1
  437. package/src/resources/extensions/gsd/tests/prompt-cache-optimizer.test.ts +12 -0
  438. package/src/resources/extensions/gsd/tests/prompt-step-ordering.test.ts +15 -4
  439. package/src/resources/extensions/gsd/tests/provider-errors.test.ts +23 -24
  440. package/src/resources/extensions/gsd/tests/queue-auto-guard.test.ts +32 -0
  441. package/src/resources/extensions/gsd/tests/queue-draft-detection.test.ts +3 -2
  442. package/src/resources/extensions/gsd/tests/queued-discuss-fast-path.test.ts +4 -5
  443. package/src/resources/extensions/gsd/tests/ready-phrase-no-files-4573.test.ts +75 -2
  444. package/src/resources/extensions/gsd/tests/reassess-default-optin.test.ts +132 -0
  445. package/src/resources/extensions/gsd/tests/recovery-attempts-reset.test.ts +8 -40
  446. package/src/resources/extensions/gsd/tests/regex-hardening.test.ts +136 -256
  447. package/src/resources/extensions/gsd/tests/research-milestone-composer.test.ts +114 -0
  448. package/src/resources/extensions/gsd/tests/restore-tools-after-discuss.test.ts +6 -3
  449. package/src/resources/extensions/gsd/tests/run-uat-composer.test.ts +148 -0
  450. package/src/resources/extensions/gsd/tests/service-tier.test.ts +4 -0
  451. package/src/resources/extensions/gsd/tests/session-lock-regression.test.ts +29 -0
  452. package/src/resources/extensions/gsd/tests/sidecar-queue.test.ts +3 -2
  453. package/src/resources/extensions/gsd/tests/silent-catch-diagnostics.test.ts +55 -95
  454. package/src/resources/extensions/gsd/tests/single-writer-v3-tool-surface.test.ts +158 -0
  455. package/src/resources/extensions/gsd/tests/skill-activation.test.ts +120 -1
  456. package/src/resources/extensions/gsd/tests/skill-manifest.test.ts +112 -0
  457. package/src/resources/extensions/gsd/tests/slice-cadence.test.ts +242 -0
  458. package/src/resources/extensions/gsd/tests/slice-context-injection.test.ts +3 -2
  459. package/src/resources/extensions/gsd/tests/slice-parallel-orchestrator.test.ts +164 -1
  460. package/src/resources/extensions/gsd/tests/smart-entry-draft.test.ts +2 -1
  461. package/src/resources/extensions/gsd/tests/stale-dirlistcache-4648.test.ts +112 -0
  462. package/src/resources/extensions/gsd/tests/state-machine-full-walkthrough.test.ts +29 -5
  463. package/src/resources/extensions/gsd/tests/state-transition-matrix.test.ts +44 -0
  464. package/src/resources/extensions/gsd/tests/stop-auto-race-null-unit.test.ts +3 -3
  465. package/src/resources/extensions/gsd/tests/structured-data-formatter.test.ts +11 -92
  466. package/src/resources/extensions/gsd/tests/subagent-model-dispatch.test.ts +7 -6
  467. package/src/resources/extensions/gsd/tests/survivor-branch-complete.test.ts +102 -101
  468. package/src/resources/extensions/gsd/tests/sync-lock.test.ts +31 -0
  469. package/src/resources/extensions/gsd/tests/sync-worktree-skip-current.test.ts +4 -3
  470. package/src/resources/extensions/gsd/tests/test-helpers.test.ts +98 -0
  471. package/src/resources/extensions/gsd/tests/test-helpers.ts +153 -0
  472. package/src/resources/extensions/gsd/tests/token-profile.test.ts +8 -1
  473. package/src/resources/extensions/gsd/tests/tool-invocation-error-loop-break.test.ts +61 -1
  474. package/src/resources/extensions/gsd/tests/tool-naming.test.ts +8 -1
  475. package/src/resources/extensions/gsd/tests/unit-context-composer.test.ts +355 -0
  476. package/src/resources/extensions/gsd/tests/unit-context-manifest.test.ts +258 -0
  477. package/src/resources/extensions/gsd/tests/uok-contracts.test.ts +51 -0
  478. package/src/resources/extensions/gsd/tests/uok-execution-graph.test.ts +16 -0
  479. package/src/resources/extensions/gsd/tests/uok-gate-runner.test.ts +75 -0
  480. package/src/resources/extensions/gsd/tests/uok-gitops-wiring.test.ts +49 -26
  481. package/src/resources/extensions/gsd/tests/uok-loop-adapter-writer.test.ts +65 -0
  482. package/src/resources/extensions/gsd/tests/uok-parity-report.test.ts +42 -0
  483. package/src/resources/extensions/gsd/tests/uok-plan-v2-wiring.test.ts +19 -2
  484. package/src/resources/extensions/gsd/tests/uok-writer.test.ts +75 -0
  485. package/src/resources/extensions/gsd/tests/validate-milestone.test.ts +12 -0
  486. package/src/resources/extensions/gsd/tests/verify-artifact-tightened.test.ts +144 -80
  487. package/src/resources/extensions/gsd/tests/visualizer-critical-path.test.ts +20 -54
  488. package/src/resources/extensions/gsd/tests/visualizer-overlay.test.ts +342 -277
  489. package/src/resources/extensions/gsd/tests/worker-model-override.test.ts +37 -29
  490. package/src/resources/extensions/gsd/tests/worktree-db.test.ts +226 -266
  491. package/src/resources/extensions/gsd/tests/worktree-health-monorepo.test.ts +103 -67
  492. package/src/resources/extensions/gsd/tests/worktree-nested-git-safety.test.ts +92 -90
  493. package/src/resources/extensions/gsd/tests/worktree-submodule-safety.test.ts +238 -59
  494. package/src/resources/extensions/gsd/tests/worktree-sync-overwrite-loop.test.ts +113 -161
  495. package/src/resources/extensions/gsd/tests/worktree-telemetry.test.ts +210 -0
  496. package/src/resources/extensions/gsd/tests/write-gate-planning-unit.test.ts +262 -0
  497. package/src/resources/extensions/gsd/tests/write-gate-predicates.test.ts +186 -0
  498. package/src/resources/extensions/gsd/tests/write-gate.test.ts +7 -5
  499. package/src/resources/extensions/gsd/tests/zombie-gsd-state.test.ts +80 -96
  500. package/src/resources/extensions/gsd/tools/validate-milestone.ts +8 -2
  501. package/src/resources/extensions/gsd/types.ts +3 -3
  502. package/src/resources/extensions/gsd/unit-context-composer.ts +218 -0
  503. package/src/resources/extensions/gsd/unit-context-manifest.ts +574 -0
  504. package/src/resources/extensions/gsd/uok/contracts.ts +65 -0
  505. package/src/resources/extensions/gsd/uok/dispatch-envelope.ts +56 -0
  506. package/src/resources/extensions/gsd/uok/execution-graph.ts +22 -0
  507. package/src/resources/extensions/gsd/uok/gate-runner.ts +65 -5
  508. package/src/resources/extensions/gsd/uok/gitops.ts +6 -1
  509. package/src/resources/extensions/gsd/uok/loop-adapter.ts +45 -10
  510. package/src/resources/extensions/gsd/uok/parity-report.ts +84 -0
  511. package/src/resources/extensions/gsd/uok/plan-v2.ts +13 -5
  512. package/src/resources/extensions/gsd/uok/writer.ts +113 -0
  513. package/src/resources/extensions/gsd/workflow-mcp.ts +6 -0
  514. package/src/resources/extensions/gsd/worktree-manager.ts +108 -7
  515. package/src/resources/extensions/gsd/worktree-resolver.ts +96 -9
  516. package/src/resources/extensions/gsd/worktree-telemetry.ts +322 -0
  517. package/src/resources/extensions/mcp-client/index.ts +3 -1
  518. package/src/resources/extensions/mcp-client/tests/server-name-spaces.test.ts +70 -36
  519. package/src/resources/extensions/ollama/index.ts +5 -1
  520. package/src/resources/extensions/ollama/ollama-auth-mode.test.ts +123 -15
  521. package/src/resources/extensions/ollama/ollama-status-indicator.test.ts +206 -19
  522. package/src/resources/extensions/remote-questions/manager.ts +36 -4
  523. package/src/resources/extensions/remote-questions/tests/command-polling.test.ts +200 -190
  524. package/src/resources/extensions/shared/tests/interview-preview.test.ts +11 -3
  525. package/src/resources/extensions/voice/tests/linux-ready.test.ts +129 -113
  526. package/packages/pi-ai/dist/utils/oauth/oauth-providers.test.d.ts +0 -2
  527. package/packages/pi-ai/dist/utils/oauth/oauth-providers.test.d.ts.map +0 -1
  528. package/packages/pi-ai/dist/utils/oauth/oauth-providers.test.js +0 -289
  529. package/packages/pi-ai/dist/utils/oauth/oauth-providers.test.js.map +0 -1
  530. package/packages/pi-ai/src/utils/oauth/oauth-providers.test.ts +0 -363
  531. package/src/resources/extensions/gsd/tests/auto-start-model-capture.test.ts +0 -143
  532. package/src/resources/extensions/gsd/tests/complete-milestone-false-merge.test.ts +0 -157
  533. package/src/resources/extensions/gsd/tests/dashboard-model-label-ordering.test.ts +0 -107
  534. package/src/resources/extensions/gsd/tests/find-missing-summaries-closed.test.ts +0 -48
  535. package/src/resources/extensions/gsd/tests/forensics-context-persist.test.ts +0 -159
  536. package/src/resources/extensions/gsd/tests/forensics-db-completion.test.ts +0 -96
  537. package/src/resources/extensions/gsd/tests/forensics-dedup.test.ts +0 -79
  538. package/src/resources/extensions/gsd/tests/forensics-hook-key-parse.test.ts +0 -74
  539. package/src/resources/extensions/gsd/tests/forensics-journal.test.ts +0 -162
  540. package/src/resources/extensions/gsd/tests/gitignore-bg-shell.test.ts +0 -38
  541. package/src/resources/extensions/gsd/tests/gsd-no-project-error.test.ts +0 -73
  542. package/src/resources/extensions/gsd/tests/idle-watchdog-stall-override.test.ts +0 -125
  543. package/src/resources/extensions/gsd/tests/import-done-milestones.test.ts +0 -42
  544. /package/dist/web/standalone/.next/static/{5wbu35_C2_MQ3Jj1lEVDx → cAJH99yNS1UPbeSEiNRrV}/_buildManifest.js +0 -0
  545. /package/dist/web/standalone/.next/static/{5wbu35_C2_MQ3Jj1lEVDx → cAJH99yNS1UPbeSEiNRrV}/_ssgManifest.js +0 -0
@@ -1,8 +1,8 @@
1
- import { test } from 'node:test';
2
- import assert from 'node:assert/strict';
3
- import * as fs from 'node:fs';
4
- import * as path from 'node:path';
5
- import * as os from 'node:os';
1
+ import { test } from "node:test";
2
+ import assert from "node:assert/strict";
3
+ import * as fs from "node:fs";
4
+ import * as path from "node:path";
5
+ import * as os from "node:os";
6
6
  import {
7
7
  openDatabase,
8
8
  closeDatabase,
@@ -17,197 +17,181 @@ import {
17
17
  _getAdapter,
18
18
  copyWorktreeDb,
19
19
  reconcileWorktreeDb,
20
- } from '../gsd-db.ts';
20
+ } from "../gsd-db.ts";
21
21
 
22
-
23
- // ═══════════════════════════════════════════════════════════════════════════
24
- // Helpers
25
- // ═══════════════════════════════════════════════════════════════════════════
22
+ // ─── Helpers ──────────────────────────────────────────────────────────────
26
23
 
27
24
  function tempDir(): string {
28
- return fs.mkdtempSync(path.join(os.tmpdir(), 'gsd-wt-test-'));
29
- }
30
-
31
- function cleanup(...dirs: string[]): void {
32
- closeDatabase();
33
- for (const dir of dirs) {
34
- try {
35
- fs.rmSync(dir, { recursive: true, force: true });
36
- } catch {
37
- // best effort
38
- }
39
- }
25
+ return fs.mkdtempSync(path.join(os.tmpdir(), "gsd-wt-test-"));
40
26
  }
41
27
 
42
28
  function seedMainDb(dbPath: string): void {
43
29
  openDatabase(dbPath);
44
30
  insertDecision({
45
- id: 'D001',
46
- when_context: '2025-01-01',
47
- scope: 'M001/S01',
48
- decision: 'Use SQLite',
49
- choice: 'node:sqlite',
50
- rationale: 'Built-in',
51
- revisable: 'yes',
52
- made_by: 'agent',
31
+ id: "D001",
32
+ when_context: "2025-01-01",
33
+ scope: "M001/S01",
34
+ decision: "Use SQLite",
35
+ choice: "node:sqlite",
36
+ rationale: "Built-in",
37
+ revisable: "yes",
38
+ made_by: "agent",
53
39
  superseded_by: null,
54
40
  });
55
41
  insertRequirement({
56
- id: 'R001',
57
- class: 'functional',
58
- status: 'active',
59
- description: 'Must store decisions',
60
- why: 'Core feature',
61
- source: 'design',
62
- primary_owner: 'S01',
63
- supporting_slices: '',
64
- validation: 'test',
65
- notes: '',
66
- full_content: 'Full requirement text',
42
+ id: "R001",
43
+ class: "functional",
44
+ status: "active",
45
+ description: "Must store decisions",
46
+ why: "Core feature",
47
+ source: "design",
48
+ primary_owner: "S01",
49
+ supporting_slices: "",
50
+ validation: "test",
51
+ notes: "",
52
+ full_content: "Full requirement text",
67
53
  superseded_by: null,
68
54
  });
69
55
  insertArtifact({
70
- path: 'docs/arch.md',
71
- artifact_type: 'plan',
72
- milestone_id: 'M001',
56
+ path: "docs/arch.md",
57
+ artifact_type: "plan",
58
+ milestone_id: "M001",
73
59
  slice_id: null,
74
60
  task_id: null,
75
- full_content: 'Architecture document',
61
+ full_content: "Architecture document",
76
62
  });
77
63
  }
78
64
 
79
- // ═══════════════════════════════════════════════════════════════════════════
80
- // copyWorktreeDb tests
81
- // ═══════════════════════════════════════════════════════════════════════════
65
+ function registerCleanup(t: { after: (fn: () => void) => void }, ...dirs: string[]) {
66
+ t.after(() => {
67
+ closeDatabase();
68
+ for (const dir of dirs) {
69
+ try {
70
+ fs.rmSync(dir, { recursive: true, force: true });
71
+ } catch {
72
+ // best effort
73
+ }
74
+ }
75
+ });
76
+ }
82
77
 
83
- console.log('\n=== worktree-db: copyWorktreeDb ===');
78
+ // ─── copyWorktreeDb ───────────────────────────────────────────────────────
84
79
 
85
- // Test: copies DB file and data is queryable
86
- {
80
+ test("copyWorktreeDb copies DB file and data is queryable", (t) => {
87
81
  const srcDir = tempDir();
88
82
  const destDir = tempDir();
89
- const srcDb = path.join(srcDir, 'gsd.db');
90
- const destDb = path.join(destDir, 'nested', 'gsd.db');
83
+ registerCleanup(t, srcDir, destDir);
84
+
85
+ const srcDb = path.join(srcDir, "gsd.db");
86
+ const destDb = path.join(destDir, "nested", "gsd.db");
91
87
 
92
88
  seedMainDb(srcDb);
93
89
  closeDatabase();
94
90
 
95
91
  const result = copyWorktreeDb(srcDb, destDb);
96
- assert.ok(result === true, 'copyWorktreeDb returns true on success');
97
- assert.ok(fs.existsSync(destDb), 'dest DB file exists after copy');
92
+ assert.equal(result, true, "copyWorktreeDb returns true on success");
93
+ assert.ok(fs.existsSync(destDb), "dest DB file exists after copy");
98
94
 
99
- // Open the copy and verify data is queryable
100
95
  openDatabase(destDb);
101
- const d = getDecisionById('D001');
102
- assert.ok(d !== null, 'decision queryable in copied DB');
103
- assert.deepStrictEqual(d?.choice, 'node:sqlite', 'decision data preserved in copy');
96
+ const d = getDecisionById("D001");
97
+ assert.ok(d !== null, "decision queryable in copied DB");
98
+ assert.equal(d?.choice, "node:sqlite", "decision data preserved in copy");
104
99
 
105
- const r = getRequirementById('R001');
106
- assert.ok(r !== null, 'requirement queryable in copied DB');
107
- assert.deepStrictEqual(r?.description, 'Must store decisions', 'requirement data preserved in copy');
100
+ const r = getRequirementById("R001");
101
+ assert.ok(r !== null, "requirement queryable in copied DB");
102
+ assert.equal(r?.description, "Must store decisions", "requirement data preserved in copy");
103
+ });
108
104
 
109
- cleanup(srcDir, destDir);
110
- }
111
-
112
- // Test: skips -wal and -shm files
113
- {
105
+ test("copyWorktreeDb skips -wal and -shm files", (t) => {
114
106
  const srcDir = tempDir();
115
107
  const destDir = tempDir();
116
- const srcDb = path.join(srcDir, 'gsd.db');
117
- const destDb = path.join(destDir, 'gsd.db');
108
+ registerCleanup(t, srcDir, destDir);
109
+
110
+ const srcDb = path.join(srcDir, "gsd.db");
111
+ const destDb = path.join(destDir, "gsd.db");
118
112
 
119
113
  seedMainDb(srcDb);
120
114
  closeDatabase();
121
115
 
122
- // Create fake WAL/SHM files
123
- fs.writeFileSync(srcDb + '-wal', 'fake wal data');
124
- fs.writeFileSync(srcDb + '-shm', 'fake shm data');
116
+ fs.writeFileSync(srcDb + "-wal", "fake wal data");
117
+ fs.writeFileSync(srcDb + "-shm", "fake shm data");
125
118
 
126
119
  copyWorktreeDb(srcDb, destDb);
127
120
 
128
- assert.ok(fs.existsSync(destDb), 'DB file copied');
129
- assert.ok(!fs.existsSync(destDb + '-wal'), 'WAL file NOT copied');
130
- assert.ok(!fs.existsSync(destDb + '-shm'), 'SHM file NOT copied');
121
+ assert.ok(fs.existsSync(destDb), "DB file copied");
122
+ assert.ok(!fs.existsSync(destDb + "-wal"), "WAL file NOT copied");
123
+ assert.ok(!fs.existsSync(destDb + "-shm"), "SHM file NOT copied");
124
+ });
131
125
 
132
- cleanup(srcDir, destDir);
133
- }
134
-
135
- // Test: returns false when source doesn't exist (no throw)
136
- {
126
+ test("copyWorktreeDb returns false when source doesn't exist", (t) => {
137
127
  const destDir = tempDir();
138
- const result = copyWorktreeDb('/nonexistent/path/gsd.db', path.join(destDir, 'gsd.db'));
139
- assert.deepStrictEqual(result, false, 'returns false for missing source');
140
- cleanup(destDir);
141
- }
128
+ registerCleanup(t, destDir);
142
129
 
143
- // Test: creates dest directory if needed
144
- {
130
+ const missingSrc = path.join(destDir, "missing", "gsd.db");
131
+ const result = copyWorktreeDb(missingSrc, path.join(destDir, "gsd.db"));
132
+ assert.equal(result, false, "returns false for missing source");
133
+ });
134
+
135
+ test("copyWorktreeDb creates deeply nested dest directories", (t) => {
145
136
  const srcDir = tempDir();
146
137
  const destDir = tempDir();
147
- const srcDb = path.join(srcDir, 'gsd.db');
148
- const deepDest = path.join(destDir, 'a', 'b', 'c', 'gsd.db');
138
+ registerCleanup(t, srcDir, destDir);
139
+
140
+ const srcDb = path.join(srcDir, "gsd.db");
141
+ const deepDest = path.join(destDir, "a", "b", "c", "gsd.db");
149
142
 
150
143
  seedMainDb(srcDb);
151
144
  closeDatabase();
152
145
 
153
146
  const result = copyWorktreeDb(srcDb, deepDest);
154
- assert.ok(result === true, 'copyWorktreeDb succeeds with nested dest');
155
- assert.ok(fs.existsSync(deepDest), 'DB file created at deeply nested path');
156
-
157
- cleanup(srcDir, destDir);
158
- }
159
-
160
- // ═══════════════════════════════════════════════════════════════════════════
161
- // reconcileWorktreeDb tests
162
- // ═══════════════════════════════════════════════════════════════════════════
147
+ assert.equal(result, true, "copyWorktreeDb succeeds with nested dest");
148
+ assert.ok(fs.existsSync(deepDest), "DB file created at deeply nested path");
149
+ });
163
150
 
164
- console.log('\n=== worktree-db: reconcileWorktreeDb ===');
151
+ // ─── reconcileWorktreeDb ──────────────────────────────────────────────────
165
152
 
166
- // Test: merges new decisions from worktree into main
167
- {
153
+ test("reconcileWorktreeDb merges new decisions from worktree into main", (t) => {
168
154
  const mainDir = tempDir();
169
155
  const wtDir = tempDir();
170
- const mainDb = path.join(mainDir, 'gsd.db');
171
- const wtDb = path.join(wtDir, 'gsd.db');
156
+ registerCleanup(t, mainDir, wtDir);
157
+
158
+ const mainDb = path.join(mainDir, "gsd.db");
159
+ const wtDb = path.join(wtDir, "gsd.db");
172
160
 
173
- // Seed main with D001
174
161
  seedMainDb(mainDb);
175
162
  closeDatabase();
176
163
 
177
- // Copy to worktree, add D002 in worktree
178
164
  copyWorktreeDb(mainDb, wtDb);
179
165
  openDatabase(wtDb);
180
166
  insertDecision({
181
- id: 'D002',
182
- when_context: '2025-02-01',
183
- scope: 'M001/S02',
184
- decision: 'Use WAL mode',
185
- choice: 'WAL',
186
- rationale: 'Performance',
187
- revisable: 'yes',
188
- made_by: 'agent',
167
+ id: "D002",
168
+ when_context: "2025-02-01",
169
+ scope: "M001/S02",
170
+ decision: "Use WAL mode",
171
+ choice: "WAL",
172
+ rationale: "Performance",
173
+ revisable: "yes",
174
+ made_by: "agent",
189
175
  superseded_by: null,
190
176
  });
191
177
  closeDatabase();
192
178
 
193
- // Re-open main and reconcile
194
179
  openDatabase(mainDb);
195
180
  const result = reconcileWorktreeDb(mainDb, wtDb);
196
181
 
197
- assert.ok(result.decisions > 0, 'decisions merged count > 0');
198
- const d2 = getDecisionById('D002');
199
- assert.ok(d2 !== null, 'D002 from worktree now in main');
200
- assert.deepStrictEqual(d2?.choice, 'WAL', 'D002 data correct after merge');
182
+ assert.ok(result.decisions > 0, "decisions merged count > 0");
183
+ const d2 = getDecisionById("D002");
184
+ assert.ok(d2 !== null, "D002 from worktree now in main");
185
+ assert.equal(d2?.choice, "WAL", "D002 data correct after merge");
186
+ });
201
187
 
202
- cleanup(mainDir, wtDir);
203
- }
204
-
205
- // Test: merges new requirements from worktree into main
206
- {
188
+ test("reconcileWorktreeDb merges new requirements from worktree into main", (t) => {
207
189
  const mainDir = tempDir();
208
190
  const wtDir = tempDir();
209
- const mainDb = path.join(mainDir, 'gsd.db');
210
- const wtDb = path.join(wtDir, 'gsd.db');
191
+ registerCleanup(t, mainDir, wtDir);
192
+
193
+ const mainDb = path.join(mainDir, "gsd.db");
194
+ const wtDb = path.join(wtDir, "gsd.db");
211
195
 
212
196
  seedMainDb(mainDb);
213
197
  closeDatabase();
@@ -215,17 +199,17 @@ console.log('\n=== worktree-db: reconcileWorktreeDb ===');
215
199
 
216
200
  openDatabase(wtDb);
217
201
  insertRequirement({
218
- id: 'R002',
219
- class: 'non-functional',
220
- status: 'active',
221
- description: 'Must be fast',
222
- why: 'UX',
223
- source: 'design',
224
- primary_owner: 'S02',
225
- supporting_slices: '',
226
- validation: 'benchmark',
227
- notes: '',
228
- full_content: 'Performance requirement',
202
+ id: "R002",
203
+ class: "non-functional",
204
+ status: "active",
205
+ description: "Must be fast",
206
+ why: "UX",
207
+ source: "design",
208
+ primary_owner: "S02",
209
+ supporting_slices: "",
210
+ validation: "benchmark",
211
+ notes: "",
212
+ full_content: "Performance requirement",
229
213
  superseded_by: null,
230
214
  });
231
215
  closeDatabase();
@@ -233,20 +217,19 @@ console.log('\n=== worktree-db: reconcileWorktreeDb ===');
233
217
  openDatabase(mainDb);
234
218
  const result = reconcileWorktreeDb(mainDb, wtDb);
235
219
 
236
- assert.ok(result.requirements > 0, 'requirements merged count > 0');
237
- const r2 = getRequirementById('R002');
238
- assert.ok(r2 !== null, 'R002 from worktree now in main');
239
- assert.deepStrictEqual(r2?.description, 'Must be fast', 'R002 data correct after merge');
220
+ assert.ok(result.requirements > 0, "requirements merged count > 0");
221
+ const r2 = getRequirementById("R002");
222
+ assert.ok(r2 !== null, "R002 from worktree now in main");
223
+ assert.equal(r2?.description, "Must be fast", "R002 data correct after merge");
224
+ });
240
225
 
241
- cleanup(mainDir, wtDir);
242
- }
243
-
244
- // Test: merges new artifacts from worktree into main
245
- {
226
+ test("reconcileWorktreeDb merges new artifacts from worktree into main", (t) => {
246
227
  const mainDir = tempDir();
247
228
  const wtDir = tempDir();
248
- const mainDb = path.join(mainDir, 'gsd.db');
249
- const wtDb = path.join(wtDir, 'gsd.db');
229
+ registerCleanup(t, mainDir, wtDir);
230
+
231
+ const mainDb = path.join(mainDir, "gsd.db");
232
+ const wtDb = path.join(wtDir, "gsd.db");
250
233
 
251
234
  seedMainDb(mainDb);
252
235
  closeDatabase();
@@ -254,133 +237,124 @@ console.log('\n=== worktree-db: reconcileWorktreeDb ===');
254
237
 
255
238
  openDatabase(wtDb);
256
239
  insertArtifact({
257
- path: 'docs/api.md',
258
- artifact_type: 'reference',
259
- milestone_id: 'M001',
260
- slice_id: 'S01',
261
- task_id: 'T01',
262
- full_content: 'API documentation',
240
+ path: "docs/api.md",
241
+ artifact_type: "reference",
242
+ milestone_id: "M001",
243
+ slice_id: "S01",
244
+ task_id: "T01",
245
+ full_content: "API documentation",
263
246
  });
264
247
  closeDatabase();
265
248
 
266
249
  openDatabase(mainDb);
267
250
  const result = reconcileWorktreeDb(mainDb, wtDb);
268
251
 
269
- assert.ok(result.artifacts > 0, 'artifacts merged count > 0');
252
+ assert.ok(result.artifacts > 0, "artifacts merged count > 0");
270
253
  const adapter = _getAdapter()!;
271
- const row = adapter.prepare('SELECT * FROM artifacts WHERE path = ?').get('docs/api.md');
272
- assert.ok(row !== null, 'artifact from worktree now in main');
273
- assert.deepStrictEqual(row?.['artifact_type'], 'reference', 'artifact data correct after merge');
274
-
275
- cleanup(mainDir, wtDir);
276
- }
277
-
278
- // Test: detects conflicts (same PK, different content in both DBs)
279
- {
254
+ const row = adapter.prepare("SELECT * FROM artifacts WHERE path = ?").get("docs/api.md");
255
+ // Statement#get returns undefined (not null) when no row matches, so use
256
+ // loose inequality to catch both — strict `!== null` would silently let a
257
+ // missing artifact row pass this assertion.
258
+ assert.ok(row != null, "artifact from worktree now in main");
259
+ assert.equal((row as any)["artifact_type"], "reference", "artifact data correct after merge");
260
+ });
261
+
262
+ test("reconcileWorktreeDb detects conflicts and applies worktree-wins policy", (t) => {
280
263
  const mainDir = tempDir();
281
264
  const wtDir = tempDir();
282
- const mainDb = path.join(mainDir, 'gsd.db');
283
- const wtDb = path.join(wtDir, 'gsd.db');
265
+ registerCleanup(t, mainDir, wtDir);
266
+
267
+ const mainDb = path.join(mainDir, "gsd.db");
268
+ const wtDb = path.join(wtDir, "gsd.db");
284
269
 
285
- // Seed main with D001
286
270
  seedMainDb(mainDb);
287
271
  closeDatabase();
288
272
  copyWorktreeDb(mainDb, wtDb);
289
273
 
290
- // Modify D001 in main
291
274
  openDatabase(mainDb);
292
- const mainAdapter = _getAdapter()!;
293
- mainAdapter.prepare(
275
+ _getAdapter()!.prepare(
294
276
  `UPDATE decisions SET choice = 'better-sqlite3' WHERE id = 'D001'`,
295
277
  ).run();
296
278
  closeDatabase();
297
279
 
298
- // Modify D001 in worktree differently
299
280
  openDatabase(wtDb);
300
- const wtAdapter = _getAdapter()!;
301
- wtAdapter.prepare(
281
+ _getAdapter()!.prepare(
302
282
  `UPDATE decisions SET choice = 'sql.js' WHERE id = 'D001'`,
303
283
  ).run();
304
284
  closeDatabase();
305
285
 
306
- // Reconcile
307
286
  openDatabase(mainDb);
308
287
  const result = reconcileWorktreeDb(mainDb, wtDb);
309
288
 
310
- assert.ok(result.conflicts.length > 0, 'conflicts detected');
289
+ assert.ok(result.conflicts.length > 0, "conflicts detected");
311
290
  assert.ok(
312
- result.conflicts.some(c => c.includes('D001')),
313
- 'conflict mentions D001',
291
+ result.conflicts.some((c) => c.includes("D001")),
292
+ "conflict mentions D001",
314
293
  );
315
294
 
316
- // Worktree-wins: D001 should now have worktree's value
317
- const d1 = getDecisionById('D001');
318
- assert.deepStrictEqual(d1?.choice, 'sql.js', 'worktree wins on conflict (INSERT OR REPLACE)');
319
-
320
- cleanup(mainDir, wtDir);
321
- }
295
+ const d1 = getDecisionById("D001");
296
+ assert.equal(d1?.choice, "sql.js", "worktree wins on conflict (INSERT OR REPLACE)");
297
+ });
322
298
 
323
- // Test: handles missing worktree DB gracefully
324
- {
299
+ test("reconcileWorktreeDb handles missing worktree DB gracefully", (t) => {
325
300
  const mainDir = tempDir();
326
- const mainDb = path.join(mainDir, 'gsd.db');
301
+ registerCleanup(t, mainDir);
327
302
 
303
+ const mainDb = path.join(mainDir, "gsd.db");
328
304
  seedMainDb(mainDb);
329
305
 
330
- const result = reconcileWorktreeDb(mainDb, '/nonexistent/worktree.db');
331
- assert.deepStrictEqual(result.decisions, 0, 'no decisions merged for missing worktree DB');
332
- assert.deepStrictEqual(result.requirements, 0, 'no requirements merged for missing worktree DB');
333
- assert.deepStrictEqual(result.artifacts, 0, 'no artifacts merged for missing worktree DB');
334
- assert.deepStrictEqual(result.conflicts.length, 0, 'no conflicts for missing worktree DB');
306
+ const missingWt = path.join(mainDir, "missing-worktree.db");
307
+ const result = reconcileWorktreeDb(mainDb, missingWt);
308
+ assert.equal(result.decisions, 0, "no decisions merged for missing worktree DB");
309
+ assert.equal(result.requirements, 0, "no requirements merged for missing worktree DB");
310
+ assert.equal(result.artifacts, 0, "no artifacts merged for missing worktree DB");
311
+ assert.equal(result.conflicts.length, 0, "no conflicts for missing worktree DB");
312
+ });
335
313
 
336
- cleanup(mainDir);
337
- }
338
-
339
- // Test: path with spaces works
340
- {
314
+ test("reconcileWorktreeDb handles paths containing spaces", (t) => {
341
315
  const baseDir = tempDir();
342
- const mainDir = path.join(baseDir, 'main dir');
343
- const wtDir = path.join(baseDir, 'worktree dir');
316
+ registerCleanup(t, baseDir);
317
+
318
+ const mainDir = path.join(baseDir, "main dir");
319
+ const wtDir = path.join(baseDir, "worktree dir");
344
320
  fs.mkdirSync(mainDir, { recursive: true });
345
321
  fs.mkdirSync(wtDir, { recursive: true });
346
322
 
347
- const mainDb = path.join(mainDir, 'gsd.db');
348
- const wtDb = path.join(wtDir, 'gsd.db');
323
+ const mainDb = path.join(mainDir, "gsd.db");
324
+ const wtDb = path.join(wtDir, "gsd.db");
349
325
 
350
326
  seedMainDb(mainDb);
351
327
  closeDatabase();
352
328
  copyWorktreeDb(mainDb, wtDb);
353
329
 
354
- // Add a decision in worktree
355
330
  openDatabase(wtDb);
356
331
  insertDecision({
357
- id: 'D003',
358
- when_context: '2025-03-01',
359
- scope: 'M001/S03',
360
- decision: 'Path spaces test',
361
- choice: 'yes',
362
- rationale: 'Robustness',
363
- revisable: 'no',
364
- made_by: 'agent',
332
+ id: "D003",
333
+ when_context: "2025-03-01",
334
+ scope: "M001/S03",
335
+ decision: "Path spaces test",
336
+ choice: "yes",
337
+ rationale: "Robustness",
338
+ revisable: "no",
339
+ made_by: "agent",
365
340
  superseded_by: null,
366
341
  });
367
342
  closeDatabase();
368
343
 
369
344
  openDatabase(mainDb);
370
345
  const result = reconcileWorktreeDb(mainDb, wtDb);
371
- assert.ok(result.decisions > 0, 'reconciliation works with spaces in path');
372
- const d3 = getDecisionById('D003');
373
- assert.ok(d3 !== null, 'D003 merged from worktree with spaces in path');
346
+ assert.ok(result.decisions > 0, "reconciliation works with spaces in path");
347
+ const d3 = getDecisionById("D003");
348
+ assert.ok(d3 !== null, "D003 merged from worktree with spaces in path");
349
+ });
374
350
 
375
- cleanup(baseDir);
376
- }
377
-
378
- // Test: main DB is usable after reconciliation (DETACH cleanup verified)
379
- {
351
+ test("reconcileWorktreeDb leaves main DB usable after DETACH", (t) => {
380
352
  const mainDir = tempDir();
381
353
  const wtDir = tempDir();
382
- const mainDb = path.join(mainDir, 'gsd.db');
383
- const wtDb = path.join(wtDir, 'gsd.db');
354
+ registerCleanup(t, mainDir, wtDir);
355
+
356
+ const mainDb = path.join(mainDir, "gsd.db");
357
+ const wtDb = path.join(wtDir, "gsd.db");
384
358
 
385
359
  seedMainDb(mainDb);
386
360
  closeDatabase();
@@ -389,92 +363,78 @@ console.log('\n=== worktree-db: reconcileWorktreeDb ===');
389
363
  openDatabase(mainDb);
390
364
  reconcileWorktreeDb(mainDb, wtDb);
391
365
 
392
- // Verify main DB is still fully usable after DETACH
393
- assert.ok(isDbAvailable(), 'DB still available after reconciliation');
366
+ assert.ok(isDbAvailable(), "DB still available after reconciliation");
394
367
 
395
368
  insertDecision({
396
- id: 'D099',
397
- when_context: '2025-12-01',
398
- scope: 'test',
399
- decision: 'Post-reconcile insert',
400
- choice: 'works',
401
- rationale: 'Verify DETACH cleanup',
402
- revisable: 'no',
403
- made_by: 'agent',
369
+ id: "D099",
370
+ when_context: "2025-12-01",
371
+ scope: "test",
372
+ decision: "Post-reconcile insert",
373
+ choice: "works",
374
+ rationale: "Verify DETACH cleanup",
375
+ revisable: "no",
376
+ made_by: "agent",
404
377
  superseded_by: null,
405
378
  });
406
379
 
407
- const d99 = getDecisionById('D099');
408
- assert.ok(d99 !== null, 'can insert and query after reconciliation');
409
- assert.deepStrictEqual(d99?.choice, 'works', 'post-reconcile data correct');
380
+ const d99 = getDecisionById("D099");
381
+ assert.ok(d99 !== null, "can insert and query after reconciliation");
382
+ assert.equal(d99?.choice, "works", "post-reconcile data correct");
410
383
 
411
- // Verify no "wt" database still attached
384
+ // Verify wt database is detached
412
385
  const adapter = _getAdapter()!;
413
386
  let wtAccessible = false;
414
387
  try {
415
- adapter.prepare('SELECT count(*) FROM wt.decisions').get();
388
+ adapter.prepare("SELECT count(*) FROM wt.decisions").get();
416
389
  wtAccessible = true;
417
390
  } catch {
418
391
  // Expected — wt should be detached
419
392
  }
420
- assert.ok(!wtAccessible, 'wt database is detached after reconciliation');
393
+ assert.ok(!wtAccessible, "wt database is detached after reconciliation");
394
+ });
421
395
 
422
- cleanup(mainDir, wtDir);
423
- }
424
-
425
- // Test: reconcile with empty worktree DB (no new rows, no conflicts)
426
- {
396
+ test("reconcileWorktreeDb is a no-op when DBs are identical", (t) => {
427
397
  const mainDir = tempDir();
428
398
  const wtDir = tempDir();
429
- const mainDb = path.join(mainDir, 'gsd.db');
430
- const wtDb = path.join(wtDir, 'gsd.db');
399
+ registerCleanup(t, mainDir, wtDir);
400
+
401
+ const mainDb = path.join(mainDir, "gsd.db");
402
+ const wtDb = path.join(wtDir, "gsd.db");
431
403
 
432
404
  seedMainDb(mainDb);
433
405
  closeDatabase();
434
406
  copyWorktreeDb(mainDb, wtDb);
435
407
 
436
- // Don't modify the worktree DB at all — reconcile the identical copy
437
408
  openDatabase(mainDb);
438
409
  const result = reconcileWorktreeDb(mainDb, wtDb);
439
410
 
440
- // Should still report counts for the existing rows (INSERT OR REPLACE touches them)
441
- assert.ok(result.conflicts.length === 0, 'no conflicts when DBs are identical');
442
- assert.ok(isDbAvailable(), 'DB usable after no-change reconciliation');
411
+ assert.equal(result.conflicts.length, 0, "no conflicts when DBs are identical");
412
+ assert.ok(isDbAvailable(), "DB usable after no-change reconciliation");
413
+ });
443
414
 
444
- cleanup(mainDir, wtDir);
445
- }
446
-
447
- // Test: reconcileWorktreeDb must NOT downgrade milestone status complete→active (#4372)
448
- {
415
+ test("reconcileWorktreeDb does not downgrade milestone status complete→active (#4372)", (t) => {
449
416
  const mainDir = tempDir();
450
417
  const wtDir = tempDir();
451
- const mainDb = path.join(mainDir, 'gsd.db');
452
- const wtDb = path.join(wtDir, 'gsd.db');
418
+ registerCleanup(t, mainDir, wtDir);
419
+
420
+ const mainDb = path.join(mainDir, "gsd.db");
421
+ const wtDb = path.join(wtDir, "gsd.db");
453
422
 
454
- // Seed main with a milestone already marked complete
455
423
  seedMainDb(mainDb);
456
424
  const mainAdapter = _getAdapter()!;
457
- insertMilestone({ id: 'M-COMP', title: 'Completed Milestone', status: 'complete' });
458
- // Manually mark completed_at so it's a realistic complete record
425
+ insertMilestone({ id: "M-COMP", title: "Completed Milestone", status: "complete" });
459
426
  mainAdapter.prepare(`UPDATE milestones SET completed_at = '2025-06-01T00:00:00.000Z' WHERE id = 'M-COMP'`).run();
460
427
  closeDatabase();
461
428
 
462
- // Copy to worktree — the worktree has the milestone as 'active' (stale / older snapshot)
463
429
  copyWorktreeDb(mainDb, wtDb);
464
430
  openDatabase(wtDb);
465
- const wtAdapter = _getAdapter()!;
466
- wtAdapter.prepare(`UPDATE milestones SET status = 'active', completed_at = NULL WHERE id = 'M-COMP'`).run();
431
+ _getAdapter()!.prepare(`UPDATE milestones SET status = 'active', completed_at = NULL WHERE id = 'M-COMP'`).run();
467
432
  closeDatabase();
468
433
 
469
- // Reconcile: main should win and keep 'complete'
470
434
  openDatabase(mainDb);
471
435
  reconcileWorktreeDb(mainDb, wtDb);
472
436
 
473
- const m = getMilestone('M-COMP');
474
- assert.ok(m !== null, 'milestone M-COMP still exists after reconcile');
475
- assert.strictEqual(m!.status, 'complete', 'complete milestone must not be downgraded to active by stale worktree');
476
-
477
- cleanup(mainDir, wtDir);
478
- }
479
-
480
- // ─── Final Report ──────────────────────────────────────────────────────────
437
+ const m = getMilestone("M-COMP");
438
+ assert.ok(m !== null, "milestone M-COMP still exists after reconcile");
439
+ assert.equal(m!.status, "complete", "complete milestone must not be downgraded to active by stale worktree");
440
+ });