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
@@ -277,6 +277,14 @@ function buildDispatchCtx(
277
277
  };
278
278
  }
279
279
 
280
+ function getUatVerdictGate(): import("../../auto-dispatch.ts").DispatchRule {
281
+ const rule = DISPATCH_RULES.find(
282
+ r => r.name === "uat-verdict-gate (non-PASS blocks progression)",
283
+ );
284
+ assert.ok(rule, "uat-verdict-gate rule should be registered");
285
+ return rule;
286
+ }
287
+
280
288
  // ═══════════════════════════════════════════════════════════════════════════
281
289
  // Test Suite
282
290
  // ═══════════════════════════════════════════════════════════════════════════
@@ -355,10 +363,13 @@ describe("state derivation failures", () => {
355
363
  const state2 = await deriveState(base);
356
364
  assert.equal(state2.phase, "executing", "cached result should still show executing");
357
365
 
358
- // After explicit invalidation, should reflect the DB mutation
366
+ // After explicit invalidation, should reflect the DB mutation and reconcile
367
+ // missing plan tasks instead of prematurely summarizing a partial DB row set.
359
368
  invalidateStateCache();
360
369
  const state3 = await deriveState(base);
361
- assert.equal(state3.phase, "summarizing", "after cache invalidation should show summarizing");
370
+ assert.equal(state3.phase, "executing", "after cache invalidation should continue with the missing plan task");
371
+ assert.equal(state3.activeTask?.id, "T02", "missing plan task T02 should be imported and selected");
372
+ assert.deepEqual(state3.progress?.tasks, { done: 1, total: 2 });
362
373
  });
363
374
 
364
375
  test("corrupt ROADMAP: binary content does not crash deriveState", async () => {
@@ -691,7 +702,7 @@ describe("transition boundary failures", () => {
691
702
  );
692
703
  });
693
704
 
694
- test("blocked state: all slices have unmet deps → fallback picks slice", async () => {
705
+ test("blocked state: all slices have unmet deps → blocks", async () => {
695
706
  base = makeTempDir();
696
707
  const mDir = join(base, ".gsd", "milestones", "M001");
697
708
  mkdirSync(join(mDir, "slices", "S01", "tasks"), { recursive: true });
@@ -736,9 +747,9 @@ describe("transition boundary failures", () => {
736
747
 
737
748
  invalidateAllCaches();
738
749
  const state = await deriveStateFromDb(base);
739
- // With partial-dep fallback, circular deps no longer block fallback picks first eligible slice
740
- assert.equal(state.phase, "planning", "circular deps: fallback picks a slice instead of blocking");
741
- assert.ok(state.activeSlice !== null, "activeSlice set via fallback");
750
+ assert.equal(state.phase, "blocked", "circular deps: no slice should be selected through unmet deps");
751
+ assert.equal(state.activeSlice, null, "activeSlice should remain null when all deps are blocked");
752
+ assert.ok(state.blockers.some(b => b.includes("No slice eligible")));
742
753
  });
743
754
  });
744
755
 
@@ -868,6 +879,132 @@ describe("dispatch failure modes", () => {
868
879
  // run-uat should come before uat-verdict-gate
869
880
  assert.ok(runUatIdx < uatGateIdx, "run-uat should precede uat-verdict-gate");
870
881
  });
882
+
883
+ test("UAT verdict gate: ASSESSMENT FAIL blocks closed slice progression", async () => {
884
+ base = createFullFixture();
885
+ openDatabase(join(base, ".gsd", "gsd.db"));
886
+ insertMilestone({ id: "M001", title: "Active", status: "active" });
887
+ insertSlice({ id: "S01", milestoneId: "M001", title: "First", status: "complete" });
888
+ insertSlice({ id: "S02", milestoneId: "M001", title: "Second", status: "pending" });
889
+
890
+ const s01Dir = join(base, ".gsd", "milestones", "M001", "slices", "S01");
891
+ writeFileSync(
892
+ join(s01Dir, "S01-UAT.md"),
893
+ "# UAT File\n\n## UAT Type\n\n- UAT mode: artifact-driven\n",
894
+ );
895
+ writeFileSync(
896
+ join(s01Dir, "S01-ASSESSMENT.md"),
897
+ "---\nverdict: FAIL\n---\n# UAT Assessment\n",
898
+ );
899
+
900
+ const ctx = buildDispatchCtx(base, "M001", {
901
+ phase: "planning",
902
+ activeSlice: { id: "S02", title: "Second" },
903
+ activeTask: null,
904
+ });
905
+ ctx.prefs = { uat_dispatch: true } as any;
906
+
907
+ const result = await getUatVerdictGate().match(ctx);
908
+ assert.equal(result?.action, "stop", "ASSESSMENT FAIL should block progression");
909
+ assert.ok(
910
+ (result as any).reason?.includes('UAT verdict for S01 is "fail"'),
911
+ "stop reason should report normalized ASSESSMENT verdict",
912
+ );
913
+ });
914
+
915
+ test("UAT verdict gate: ROADMAP fallback gates done slices when DB is unavailable", async () => {
916
+ base = createFullFixture();
917
+ const mDir = join(base, ".gsd", "milestones", "M001");
918
+ writeFileSync(
919
+ join(mDir, "M001-ROADMAP.md"),
920
+ [
921
+ "# M001: Edge Case Milestone",
922
+ "",
923
+ "## Vision",
924
+ "Prove edge case correctness.",
925
+ "",
926
+ "## Success Criteria",
927
+ "- All edge cases handled",
928
+ "",
929
+ "## Slices",
930
+ "",
931
+ "- [x] **S01: First Feature** `risk:low` `depends:[]`",
932
+ " - After this: First feature proven.",
933
+ "",
934
+ "- [ ] **S02: Second Feature** `risk:low` `depends:[]`",
935
+ " - After this: Second feature proven.",
936
+ "",
937
+ "## Boundary Map",
938
+ "",
939
+ "| From | To | Produces | Consumes |",
940
+ "|------|----|----------|----------|",
941
+ "| S01 | terminal | feature-a | nothing |",
942
+ "| S02 | terminal | feature-b | nothing |",
943
+ ].join("\n"),
944
+ );
945
+
946
+ const s01Dir = join(base, ".gsd", "milestones", "M001", "slices", "S01");
947
+ writeFileSync(
948
+ join(s01Dir, "S01-UAT.md"),
949
+ "# UAT File\n\n## UAT Type\n\n- UAT mode: artifact-driven\n",
950
+ );
951
+ writeFileSync(
952
+ join(s01Dir, "S01-ASSESSMENT.md"),
953
+ "---\nverdict: needs-remediation\n---\n# UAT Assessment\n",
954
+ );
955
+
956
+ const ctx = buildDispatchCtx(base, "M001", {
957
+ phase: "planning",
958
+ activeSlice: { id: "S02", title: "Second" },
959
+ activeTask: null,
960
+ });
961
+ ctx.prefs = { uat_dispatch: true } as any;
962
+
963
+ const result = await getUatVerdictGate().match(ctx);
964
+ assert.equal(result?.action, "stop", "ROADMAP done slices should be gated without DB");
965
+ assert.ok(
966
+ (result as any).reason?.includes('UAT verdict for S01 is "needs-remediation"'),
967
+ "stop reason should report normalized ASSESSMENT verdict from disk fallback",
968
+ );
969
+ });
970
+
971
+ for (const status of ["done", "skipped"]) {
972
+ test(`UAT verdict gate: legacy closed status "${status}" is gated`, async () => {
973
+ base = createFullFixture();
974
+ openDatabase(join(base, ".gsd", "gsd.db"));
975
+ insertMilestone({ id: "M001", title: "Active", status: "active" });
976
+ insertSlice({ id: "S01", milestoneId: "M001", title: "First", status });
977
+ insertSlice({ id: "S02", milestoneId: "M001", title: "Second", status: "pending" });
978
+
979
+ const s01Dir = join(base, ".gsd", "milestones", "M001", "slices", "S01");
980
+ writeFileSync(
981
+ join(s01Dir, "S01-UAT.md"),
982
+ "# UAT File\n\n## UAT Type\n\n- UAT mode: artifact-driven\n",
983
+ );
984
+ writeFileSync(
985
+ join(s01Dir, "S01-ASSESSMENT.md"),
986
+ "---\nverdict: needs-remediation\n---\n# UAT Assessment\n",
987
+ );
988
+
989
+ const ctx = buildDispatchCtx(base, "M001", {
990
+ phase: "planning",
991
+ activeSlice: { id: "S02", title: "Second" },
992
+ activeTask: null,
993
+ });
994
+ ctx.prefs = { uat_dispatch: true } as any;
995
+
996
+ const result = await getUatVerdictGate().match(ctx);
997
+ assert.equal(
998
+ result?.action,
999
+ "stop",
1000
+ `${status} slices should be treated as closed for UAT verdict gating`,
1001
+ );
1002
+ assert.ok(
1003
+ (result as any).reason?.includes('UAT verdict for S01 is "needs-remediation"'),
1004
+ "stop reason should report normalized ASSESSMENT verdict",
1005
+ );
1006
+ });
1007
+ }
871
1008
  });
872
1009
 
873
1010
  // ─────────────────────────────────────────────────────────────────────────
@@ -1155,7 +1292,7 @@ describe("dispatch guard integration", () => {
1155
1292
  assert.ok(existsSync(validationPath), "VALIDATION file should be written");
1156
1293
  const content = readFileSync(validationPath, "utf-8");
1157
1294
  assert.ok(content.includes("verdict: pass"), "should contain pass verdict");
1158
- assert.ok(content.includes("skipped by preference"), "should note it was skipped");
1295
+ assert.ok(content.includes("`skip_milestone_validation` preference"), "should note it was skipped via the preference path (#4781)");
1159
1296
  });
1160
1297
 
1161
1298
  test("rewrite-docs circuit breaker: exceeding MAX attempts resolves all overrides", async () => {
@@ -936,9 +936,11 @@ describe("state-machine-live-validation", () => {
936
936
  insertMilestone({ id: "M001", title: "Active", status: "active" });
937
937
  insertSlice({ id: "S01", milestoneId: "M001", title: "First", status: "in_progress" });
938
938
  insertTask({ id: "T01", sliceId: "S01", milestoneId: "M001", status: "pending" });
939
+ insertTask({ id: "T02", sliceId: "S01", milestoneId: "M001", status: "pending" });
939
940
 
940
941
  // Complete task + slice
941
942
  await handleCompleteTask(makeTaskParams("T01", "S01", "M001") as any, base);
943
+ await handleCompleteTask(makeTaskParams("T02", "S01", "M001") as any, base);
942
944
  await handleCompleteSlice(makeSliceParams("S01", "M001") as any, base);
943
945
  assert.ok(isClosedStatus(getSlice("M001", "S01")!.status));
944
946
 
@@ -946,9 +948,11 @@ describe("state-machine-live-validation", () => {
946
948
  await handleReopenSlice({ milestoneId: "M001", sliceId: "S01" }, base);
947
949
  assert.equal(getSlice("M001", "S01")!.status, "in_progress");
948
950
  assert.equal(getTask("M001", "S01", "T01")!.status, "pending");
951
+ assert.equal(getTask("M001", "S01", "T02")!.status, "pending");
949
952
 
950
953
  // Re-complete task + slice succeeds
951
954
  await handleCompleteTask(makeTaskParams("T01", "S01", "M001") as any, base);
955
+ await handleCompleteTask(makeTaskParams("T02", "S01", "M001") as any, base);
952
956
  const r = await handleCompleteSlice(makeSliceParams("S01", "M001") as any, base);
953
957
  assert.ok(!("error" in r), `re-complete slice: ${JSON.stringify(r)}`);
954
958
  assert.ok(isClosedStatus(getSlice("M001", "S01")!.status));
@@ -48,9 +48,7 @@ import type { WindowEntry } from "../../auto/types.ts";
48
48
  import {
49
49
  AutoSession,
50
50
  NEW_SESSION_TIMEOUT_MS,
51
- MAX_UNIT_DISPATCHES,
52
51
  STUB_RECOVERY_THRESHOLD,
53
- MAX_LIFETIME_DISPATCHES,
54
52
  } from "../../auto/session.ts";
55
53
 
56
54
  // ── Auto-loop types ──────────────────────────────────────────────────────
@@ -364,14 +362,6 @@ describe("session management", () => {
364
362
  assert.equal(NEW_SESSION_TIMEOUT_MS, 120_000, "session timeout should be 120s");
365
363
  });
366
364
 
367
- test("MAX_UNIT_DISPATCHES limits retries for a single unit", () => {
368
- assert.equal(MAX_UNIT_DISPATCHES, 3, "max unit dispatches should be 3");
369
- });
370
-
371
- test("MAX_LIFETIME_DISPATCHES is the absolute limit per unit", () => {
372
- assert.equal(MAX_LIFETIME_DISPATCHES, 6, "max lifetime dispatches should be 6");
373
- });
374
-
375
365
  test("STUB_RECOVERY_THRESHOLD triggers recovery after N stub completions", () => {
376
366
  assert.equal(STUB_RECOVERY_THRESHOLD, 2, "stub recovery threshold should be 2");
377
367
  });
@@ -392,12 +382,8 @@ describe("session management", () => {
392
382
  s.unitDispatchCount.set(unitId, 2);
393
383
  assert.equal(s.unitDispatchCount.get(unitId), 2);
394
384
 
395
- // Exceeding MAX_UNIT_DISPATCHES
396
- s.unitDispatchCount.set(unitId, MAX_UNIT_DISPATCHES + 1);
397
- assert.ok(
398
- s.unitDispatchCount.get(unitId)! > MAX_UNIT_DISPATCHES,
399
- "should track count beyond max for detection",
400
- );
385
+ s.unitDispatchCount.set(unitId, 4);
386
+ assert.equal(s.unitDispatchCount.get(unitId), 4);
401
387
  });
402
388
 
403
389
  test("AutoSession toJSON() provides diagnostic snapshot", () => {
@@ -8,6 +8,7 @@ import assert from "node:assert/strict";
8
8
  import { readFileSync } from "node:fs";
9
9
  import { join, dirname } from "node:path";
10
10
  import { fileURLToPath } from "node:url";
11
+ import { extractSourceRegion } from "./test-helpers.ts";
11
12
 
12
13
  const __dirname = dirname(fileURLToPath(import.meta.url));
13
14
 
@@ -62,7 +63,7 @@ describe("interactive routing bypass (#3962)", () => {
62
63
  );
63
64
  // The function should check isAutoMode before routing synthesis
64
65
  const fnIdx = modelSelectionSrc.indexOf("function resolvePreferredModelConfig");
65
- const fnBody = modelSelectionSrc.slice(fnIdx, fnIdx + 900);
66
+ const fnBody = extractSourceRegion(modelSelectionSrc, "function resolvePreferredModelConfig");
66
67
  assert.ok(
67
68
  fnBody.includes("isAutoMode"),
68
69
  "resolvePreferredModelConfig should accept isAutoMode parameter",
@@ -137,8 +138,13 @@ describe("model downgrade notifications always visible (#3962)", () => {
137
138
  const escalatedIdx = modelSelectionSrc.indexOf("if (escalated)");
138
139
  assert.ok(escalatedIdx > 0, "escalation block should exist");
139
140
 
140
- // Get the block from "if (escalated)" to the next closing brace pattern
141
- const block = modelSelectionSrc.slice(escalatedIdx, escalatedIdx + 400);
141
+ // Get the block from "if (escalated)" to the next distinctive marker
142
+ // (the capability-override loading that immediately follows).
143
+ const block = extractSourceRegion(
144
+ modelSelectionSrc,
145
+ "if (escalated)",
146
+ "// Load user capability overrides",
147
+ );
142
148
  assert.ok(
143
149
  block.includes("Tier escalation:"),
144
150
  "escalation block should contain the notification",
@@ -1,6 +1,6 @@
1
1
  import test from "node:test";
2
2
  import assert from "node:assert/strict";
3
- import { mkdirSync, readFileSync, rmSync, writeFileSync } from "node:fs";
3
+ import { mkdirSync, rmSync, writeFileSync } from "node:fs";
4
4
  import { join } from "node:path";
5
5
  import { tmpdir } from "node:os";
6
6
  import { randomUUID } from "node:crypto";
@@ -126,11 +126,8 @@ test("guided-flow stale paused-session scenario is suppressed when no resumable
126
126
  }
127
127
  });
128
128
 
129
- test("guided-flow source uses step-aware resume and clears stale paused metadata without changing discuss handoff semantics", () => {
130
- const source = readFileSync(join(import.meta.dirname, "..", "guided-flow.ts"), "utf-8");
131
- assert.ok(source.includes('const interrupted = await assessInterruptedSession(basePath);'));
132
- assert.ok(source.includes('resumeLabel = interrupted.pausedSession?.stepMode'));
133
- assert.ok(source.includes('step: interrupted.pausedSession?.stepMode ?? false'));
134
- assert.ok(source.includes('unlinkSync(join(gsdRoot(basePath), "runtime", "paused-session.json"))'));
135
- assert.ok(source.includes('pendingAutoStartMap.set(basePath,'));
136
- });
129
+ // Note: the prior source-grep test that scanned guided-flow.ts for five
130
+ // string literals was removed under #4827. The invariants it encoded
131
+ // (step-aware resume + stale paused-session cleanup + pendingAutoStartMap
132
+ // side effect) should be covered by a runtime drive of guided-flow —
133
+ // tracked as a follow-up.
@@ -21,6 +21,13 @@ import type { IterationContext, LoopState, PreDispatchData, IterationData } from
21
21
  import type { SessionLockStatus } from "../session-lock.js";
22
22
  import { runDispatch, runUnitPhase, runPreDispatch, runFinalize } from "../auto/phases.js";
23
23
  import { readUnitRuntimeRecord } from "../unit-runtime.js";
24
+ import {
25
+ closeDatabase,
26
+ insertMilestone,
27
+ insertSlice,
28
+ insertTask,
29
+ openDatabase,
30
+ } from "../gsd-db.js";
24
31
 
25
32
  // ─── Helpers ─────────────────────────────────────────────────────────────────
26
33
 
@@ -644,6 +651,63 @@ test("terminal event is emitted on blocked state", async () => {
644
651
  assert.deepEqual((terminalEvents[0].data as any).blockers, ["Missing API key"]);
645
652
  });
646
653
 
654
+ test("#4671: plan-v2 missing CONTEXT.md reaches dispatch recovery instead of pausing", async () => {
655
+ const basePath = mkdtempSync(join(tmpdir(), "gsd-4671-predispatch-"));
656
+ mkdirSync(join(basePath, ".gsd", "milestones", "M001", "slices", "S01", "tasks"), { recursive: true });
657
+ openDatabase(join(basePath, ".gsd", "gsd.db"));
658
+ try {
659
+ insertMilestone({ id: "M001", title: "Test", status: "active" });
660
+ insertSlice({
661
+ id: "S01",
662
+ milestoneId: "M001",
663
+ title: "Slice 1",
664
+ status: "in_progress",
665
+ sequence: 1,
666
+ });
667
+ insertTask({
668
+ id: "T01",
669
+ milestoneId: "M001",
670
+ sliceId: "S01",
671
+ title: "Task 1",
672
+ status: "pending",
673
+ keyFiles: ["src/task.ts"],
674
+ sequence: 1,
675
+ });
676
+
677
+ let pauseCalls = 0;
678
+ const capture = createEventCapture();
679
+ const deps = makeMockDeps(capture, {
680
+ pauseAuto: async () => { pauseCalls++; },
681
+ deriveState: async () => ({
682
+ phase: "executing",
683
+ activeMilestone: { id: "M001", title: "Test", status: "active" },
684
+ activeSlice: { id: "S01", title: "Slice 1" },
685
+ activeTask: { id: "T01", title: "Task 1" },
686
+ registry: [{ id: "M001", status: "active" }],
687
+ blockers: [],
688
+ recentDecisions: [],
689
+ nextAction: "dispatch",
690
+ }) as any,
691
+ });
692
+ const ic = makeIC(deps, {
693
+ prefs: { uok: { plan_v2: { enabled: true } } } as any,
694
+ });
695
+ ic.s.basePath = basePath;
696
+
697
+ const result = await runPreDispatch(ic, {
698
+ recentUnits: [],
699
+ stuckRecoveryAttempts: 0,
700
+ consecutiveFinalizeTimeouts: 0,
701
+ });
702
+
703
+ assert.equal(result.action, "next");
704
+ assert.equal(pauseCalls, 0, "missing CONTEXT.md should be handled by dispatch recovery, not plan gate pause");
705
+ } finally {
706
+ closeDatabase();
707
+ rmSync(basePath, { recursive: true, force: true });
708
+ }
709
+ });
710
+
647
711
  test("milestone-transition event is emitted when milestone changes", async () => {
648
712
  const capture = createEventCapture();
649
713
  const deps = makeMockDeps(capture, {
@@ -15,7 +15,7 @@ import { mkdtempSync, mkdirSync, writeFileSync, readFileSync, rmSync, realpathSy
15
15
  import { join } from 'node:path';
16
16
  import { tmpdir } from 'node:os';
17
17
  import { GSD_ROOT_FILES, resolveGsdRootFile } from '../paths.ts';
18
- import { inlineGsdRootFile } from '../auto-prompts.ts';
18
+ import { inlineGsdRootFile, inlineKnowledgeBudgeted } from '../auto-prompts.ts';
19
19
  import { appendKnowledge } from '../files.ts';
20
20
  import { loadKnowledgeBlock } from '../bootstrap/system-context.ts';
21
21
 
@@ -248,3 +248,95 @@ test('loadKnowledgeBlock: reports globalSizeKb above 4KB threshold', () => {
248
248
 
249
249
  rmSync(tmp, { recursive: true, force: true });
250
250
  });
251
+
252
+ // ─── inlineKnowledgeBudgeted — issue #4719 ─────────────────────────────────
253
+ // Milestone-phase prompts must not inject the full KNOWLEDGE.md. The budgeted
254
+ // helper scopes by milestone-level keywords and caps the injected size.
255
+
256
+ test('inlineKnowledgeBudgeted: returns scoped H3 entries for single-H2 file', async () => {
257
+ const tmp = realpathSync(mkdtempSync(join(tmpdir(), 'gsd-knowledge-')));
258
+ const gsdDir = join(tmp, '.gsd');
259
+ mkdirSync(gsdDir, { recursive: true });
260
+
261
+ const content = `# Project Knowledge
262
+
263
+ ## Patterns
264
+
265
+ ### Database: prepared statements
266
+ Always use prepared statements with SQLite.
267
+
268
+ ### API: versioned paths
269
+ Use /v1/resource style versioning.
270
+
271
+ ### Testing: node:test
272
+ Prefer node:test over external frameworks.
273
+ `;
274
+ writeFileSync(join(gsdDir, 'KNOWLEDGE.md'), content);
275
+
276
+ const result = await inlineKnowledgeBudgeted(tmp, ['database']);
277
+ assert.ok(result !== null, 'should return content');
278
+ assert.ok(result!.includes('Database: prepared statements'), 'includes matching H3');
279
+ assert.ok(!result!.includes('API: versioned paths'), 'excludes non-matching H3');
280
+
281
+ rmSync(tmp, { recursive: true, force: true });
282
+ });
283
+
284
+ test('inlineKnowledgeBudgeted: caps payload below budget for large files', async () => {
285
+ const tmp = realpathSync(mkdtempSync(join(tmpdir(), 'gsd-knowledge-')));
286
+ const gsdDir = join(tmp, '.gsd');
287
+ mkdirSync(gsdDir, { recursive: true });
288
+
289
+ // Build a 200KB KNOWLEDGE with 500 H3 entries all matching 'shared'
290
+ const entries = Array.from({ length: 500 }, (_, i) =>
291
+ `### Entry ${i}: shared topic\n${'filler text '.repeat(30)}\n`,
292
+ ).join('\n');
293
+ const content = `# Project Knowledge\n\n## Patterns\n\n${entries}`;
294
+ writeFileSync(join(gsdDir, 'KNOWLEDGE.md'), content);
295
+
296
+ const BUDGET_CHARS = 30_000;
297
+ const result = await inlineKnowledgeBudgeted(tmp, ['shared'], { maxChars: BUDGET_CHARS });
298
+ assert.ok(result !== null, 'should return content');
299
+ // Allow some overhead for header formatting, but must stay close to budget
300
+ assert.ok(
301
+ result!.length <= BUDGET_CHARS + 500,
302
+ `payload ${result!.length} chars should be <= budget ${BUDGET_CHARS} (+overhead)`,
303
+ );
304
+ // Far smaller than the raw file
305
+ assert.ok(
306
+ result!.length < content.length / 4,
307
+ `payload should be much smaller than full content (${content.length} chars)`,
308
+ );
309
+ assert.match(
310
+ result!,
311
+ /\[\.\.\.truncated \d+ chars; rerun with narrower scope if needed\]/,
312
+ 'should include truncation note when budget is exceeded',
313
+ );
314
+
315
+ rmSync(tmp, { recursive: true, force: true });
316
+ });
317
+
318
+ test('inlineKnowledgeBudgeted: returns null when no KNOWLEDGE.md exists', async () => {
319
+ const tmp = realpathSync(mkdtempSync(join(tmpdir(), 'gsd-knowledge-')));
320
+ const gsdDir = join(tmp, '.gsd');
321
+ mkdirSync(gsdDir, { recursive: true });
322
+
323
+ const result = await inlineKnowledgeBudgeted(tmp, ['database']);
324
+ assert.strictEqual(result, null);
325
+
326
+ rmSync(tmp, { recursive: true, force: true });
327
+ });
328
+
329
+ test('inlineKnowledgeBudgeted: returns null when no entries match', async () => {
330
+ const tmp = realpathSync(mkdtempSync(join(tmpdir(), 'gsd-knowledge-')));
331
+ const gsdDir = join(tmp, '.gsd');
332
+ mkdirSync(gsdDir, { recursive: true });
333
+ writeFileSync(
334
+ join(gsdDir, 'KNOWLEDGE.md'),
335
+ '# Project Knowledge\n\n## Patterns\n\n### Database\nuse it\n',
336
+ );
337
+
338
+ const result = await inlineKnowledgeBudgeted(tmp, ['nonexistent']);
339
+ assert.strictEqual(result, null);
340
+
341
+ rmSync(tmp, { recursive: true, force: true });
342
+ });
@@ -1,12 +1,19 @@
1
1
  import test from "node:test";
2
2
  import assert from "node:assert/strict";
3
- import { readFileSync } from "node:fs";
4
3
 
5
4
  import {
6
5
  _buildMcpChildEnvForTest,
7
6
  _buildMcpTrustConfirmOptionsForTest,
8
7
  } from "../../mcp-client/index.ts";
9
8
 
9
+ // Note: four source-grep tests that scanned `mcp-client/index.ts` for
10
+ // Map<> shapes, catch-block structure, and closeAll body were removed
11
+ // under #4827. They encoded implementation shape rather than behaviour —
12
+ // any refactor (extracted helper, different Map key type, rearranged
13
+ // cleanup order) broke the greps without a real regression. Runtime
14
+ // coverage of connectServer/closeAll with a mocked failing transport
15
+ // is tracked as a follow-up.
16
+
10
17
  test("MCP stdio child env only includes safe inherited keys plus explicit config env", () => {
11
18
  const previousSecret = process.env.SECRET_MCP_TEST_TOKEN;
12
19
  const previousPath = process.env.PATH;
@@ -38,39 +45,3 @@ test("MCP stdio trust confirmation is abort-aware", () => {
38
45
  assert.equal(options.timeout, 120_000);
39
46
  assert.equal(options.signal, controller.signal);
40
47
  });
41
-
42
- test("MCP client uses a single in-flight connection per canonical server", () => {
43
- const source = readFileSync(new URL("../../mcp-client/index.ts", import.meta.url), "utf8");
44
-
45
- assert.match(source, /const pendingConnections = new Map<string, Promise<Client>>\(\)/);
46
- assert.match(source, /const pending = pendingConnections\.get\(config\.name\)/);
47
- assert.match(source, /pendingConnections\.set\(config\.name, connectionPromise\)/);
48
- assert.match(source, /pendingConnections\.delete\(config\.name\)/);
49
- assert.match(source, /env: config\.env \?\? \{\}/);
50
- });
51
-
52
- test("MCP stdio trust is persisted only after a successful connection", () => {
53
- const source = readFileSync(new URL("../../mcp-client/index.ts", import.meta.url), "utf8");
54
- const connectIndex = source.indexOf("await client.connect(transport");
55
- const trustIndex = source.indexOf("trustedStdioServers.add(approvedTrustKey)");
56
-
57
- assert.ok(connectIndex > -1, "connectServer should await client.connect");
58
- assert.ok(trustIndex > connectIndex, "trust should be recorded after client.connect succeeds");
59
- assert.doesNotMatch(source, /assertTrustedStdioServer[\s\S]*trustedStdioServers\.add\(trustKey\)/);
60
- });
61
-
62
- test("MCP client closes transports after failed connection attempts", () => {
63
- const source = readFileSync(new URL("../../mcp-client/index.ts", import.meta.url), "utf8");
64
-
65
- assert.match(source, /catch \(err\) \{[\s\S]*await transport\.close\(\)/);
66
- assert.match(source, /catch \(err\) \{[\s\S]*await client\.close\(\)/);
67
- assert.match(source, /catch \(err\) \{[\s\S]*throw err/);
68
- });
69
-
70
- test("MCP client clears process-local trust and closes transports on session cleanup", () => {
71
- const source = readFileSync(new URL("../../mcp-client/index.ts", import.meta.url), "utf8");
72
-
73
- assert.match(source, /async function closeAll\(\)[\s\S]*await conn\.transport\.close\(\)/);
74
- assert.match(source, /async function closeAll\(\)[\s\S]*pendingConnections\.clear\(\)/);
75
- assert.match(source, /async function closeAll\(\)[\s\S]*trustedStdioServers\.clear\(\)/);
76
- });
@@ -1,4 +1,4 @@
1
- import { parseMemoryResponse, _resetExtractionState, buildMemoryLLMCall } from '../memory-extractor.ts';
1
+ import { parseMemoryResponse, buildMemoryLLMCall } from '../memory-extractor.ts';
2
2
  import {
3
3
  openDatabase,
4
4
  closeDatabase,
@@ -159,16 +159,6 @@ test('integration: mixed action lifecycle', () => {
159
159
  closeDatabase();
160
160
  });
161
161
 
162
- // ═══════════════════════════════════════════════════════════════════════════
163
- // memory-extractor: _resetExtractionState
164
- // ═══════════════════════════════════════════════════════════════════════════
165
-
166
- test('memory-extractor: reset extraction state', () => {
167
- // Just verify it doesn't throw
168
- _resetExtractionState();
169
- assert.ok(true, '_resetExtractionState should not throw');
170
- });
171
-
172
162
  // ═══════════════════════════════════════════════════════════════════════════
173
163
  // memory-extractor: buildMemoryLLMCall resolves OAuth API key via modelRegistry
174
164
  // Regression test for #2959 — OAuth users had broken memory extraction
@@ -200,8 +190,8 @@ test('memory-extractor: buildMemoryLLMCall resolves API key from modelRegistry f
200
190
  assert.ok(llmCallFn !== null, 'buildMemoryLLMCall should return a function when models are available');
201
191
 
202
192
  // The function should have resolved the API key eagerly via modelRegistry.getApiKey.
203
- // Give the async getApiKey a tick to resolve.
204
- await new Promise(resolve => setTimeout(resolve, 50));
193
+ // Await the exposed promise deterministically instead of polling via setTimeout.
194
+ await llmCallFn!.apiKeyReady;
205
195
  assert.ok(getApiKeyCalled, 'buildMemoryLLMCall must call modelRegistry.getApiKey() to resolve OAuth tokens');
206
196
  });
207
197
 
@@ -246,8 +236,8 @@ test('memory-extractor: buildMemoryLLMCall prefers haiku model', async () => {
246
236
  const llmCallFn = buildMemoryLLMCall(ctx);
247
237
  assert.ok(llmCallFn !== null, 'should return a function');
248
238
 
249
- // Wait for the async getApiKey to resolve
250
- await new Promise(resolve => setTimeout(resolve, 50));
239
+ // Await the exposed API-key-ready promise deterministically.
240
+ await llmCallFn!.apiKeyReady;
251
241
  assert.strictEqual(resolvedModelId, 'claude-3-5-haiku-20241022',
252
242
  'should resolve API key for haiku model, not sonnet');
253
243
  });