gsd-pi 2.77.0-dev.1d17f366c → 2.77.0-dev.2daa994b6

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 (368) hide show
  1. package/dist/headless.js +25 -4
  2. package/dist/resource-loader.d.ts +40 -0
  3. package/dist/resource-loader.js +32 -13
  4. package/dist/resources/extensions/browser-tools/capture.js +9 -0
  5. package/dist/resources/extensions/browser-tools/tests/browser-tools-integration.test.mjs +8 -59
  6. package/dist/resources/extensions/browser-tools/tests/browser-tools-unit.test.cjs +36 -24
  7. package/dist/resources/extensions/browser-tools/tests/capture-sharp-optional.test.cjs +69 -71
  8. package/dist/resources/extensions/browser-tools/tools/forms.js +5 -1
  9. package/dist/resources/extensions/browser-tools/tools/intent.js +5 -1
  10. package/dist/resources/extensions/gsd/auto/phases.js +5 -18
  11. package/dist/resources/extensions/gsd/auto/session.js +6 -0
  12. package/dist/resources/extensions/gsd/auto-dispatch.js +37 -8
  13. package/dist/resources/extensions/gsd/auto-post-unit.js +79 -0
  14. package/dist/resources/extensions/gsd/auto-prompts.js +372 -104
  15. package/dist/resources/extensions/gsd/auto-start.js +75 -24
  16. package/dist/resources/extensions/gsd/auto.js +34 -0
  17. package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +9 -1
  18. package/dist/resources/extensions/gsd/bootstrap/write-gate.js +7 -1
  19. package/dist/resources/extensions/gsd/component-loader.js +447 -0
  20. package/dist/resources/extensions/gsd/component-types.js +69 -0
  21. package/dist/resources/extensions/gsd/context-store.js +23 -7
  22. package/dist/resources/extensions/gsd/detection.js +49 -1
  23. package/dist/resources/extensions/gsd/docs/preferences-reference.md +1 -1
  24. package/dist/resources/extensions/gsd/forensics.js +106 -0
  25. package/dist/resources/extensions/gsd/gsd-db.js +1 -1
  26. package/dist/resources/extensions/gsd/guided-flow.js +2 -4
  27. package/dist/resources/extensions/gsd/memory-extractor.js +7 -1
  28. package/dist/resources/extensions/gsd/milestone-scope-classifier.js +299 -0
  29. package/dist/resources/extensions/gsd/model-cost-table.js +3 -0
  30. package/dist/resources/extensions/gsd/model-router.js +6 -0
  31. package/dist/resources/extensions/gsd/preferences-validation.js +23 -0
  32. package/dist/resources/extensions/gsd/prompt-cache-optimizer.js +4 -0
  33. package/dist/resources/extensions/gsd/prompts/complete-milestone.md +5 -1
  34. package/dist/resources/extensions/gsd/prompts/plan-slice.md +15 -2
  35. package/dist/resources/extensions/gsd/service-tier.js +5 -2
  36. package/dist/resources/extensions/gsd/skill-manifest.js +168 -0
  37. package/dist/resources/extensions/gsd/slice-cadence.js +238 -0
  38. package/dist/resources/extensions/gsd/tools/validate-milestone.js +7 -2
  39. package/dist/resources/extensions/gsd/unit-context-composer.js +147 -0
  40. package/dist/resources/extensions/gsd/unit-context-manifest.js +334 -0
  41. package/dist/resources/extensions/gsd/worktree-manager.js +51 -0
  42. package/dist/resources/extensions/gsd/worktree-resolver.js +86 -7
  43. package/dist/resources/extensions/gsd/worktree-telemetry.js +198 -0
  44. package/dist/resources/extensions/mcp-client/index.js +3 -1
  45. package/dist/resources/extensions/ollama/index.js +5 -1
  46. package/dist/resources/extensions/remote-questions/manager.js +11 -5
  47. package/dist/tsconfig.extensions.tsbuildinfo +1 -1
  48. package/dist/web/standalone/.next/BUILD_ID +1 -1
  49. package/dist/web/standalone/.next/app-path-routes-manifest.json +17 -17
  50. package/dist/web/standalone/.next/build-manifest.json +2 -2
  51. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  52. package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
  53. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  54. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  55. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  56. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  57. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  58. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  59. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  60. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  61. package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
  62. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
  63. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  64. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
  65. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  66. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  67. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  68. package/dist/web/standalone/.next/server/app/index.html +1 -1
  69. package/dist/web/standalone/.next/server/app/index.rsc +1 -1
  70. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
  71. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +1 -1
  72. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  73. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
  74. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  75. package/dist/web/standalone/.next/server/app-paths-manifest.json +17 -17
  76. package/dist/web/standalone/.next/server/chunks/6897.js +1 -1
  77. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  78. package/dist/web/standalone/.next/server/middleware-manifest.json +5 -5
  79. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  80. package/dist/web/standalone/.next/server/pages/500.html +1 -1
  81. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  82. package/package.json +1 -3
  83. package/packages/mcp-server/src/mcp-server.test.ts +25 -3
  84. package/packages/mcp-server/src/readers/graph.test.ts +87 -15
  85. package/packages/mcp-server/src/workflow-tools.test.ts +80 -39
  86. package/packages/native/package.json +1 -1
  87. package/packages/native/src/__tests__/_test-coverage-guard.test.mjs +98 -0
  88. package/packages/native/src/__tests__/module-compat.test.mjs +59 -27
  89. package/packages/native/src/__tests__/ps.test.mjs +14 -8
  90. package/packages/native/src/__tests__/stream-process.test.mjs +23 -2
  91. package/packages/native/src/__tests__/truncate.test.mjs +17 -2
  92. package/packages/pi-agent-core/src/agent-loop.test.ts +5 -15
  93. package/packages/pi-agent-core/src/agent.test.ts +96 -102
  94. package/packages/pi-agent-core/tsconfig.tsbuildinfo +1 -1
  95. package/packages/pi-ai/dist/models/generated/index.d.ts +34 -0
  96. package/packages/pi-ai/dist/models/generated/index.d.ts.map +1 -1
  97. package/packages/pi-ai/dist/models/generated/openai-codex.d.ts +17 -0
  98. package/packages/pi-ai/dist/models/generated/openai-codex.d.ts.map +1 -1
  99. package/packages/pi-ai/dist/models/generated/openai-codex.js +17 -0
  100. package/packages/pi-ai/dist/models/generated/openai-codex.js.map +1 -1
  101. package/packages/pi-ai/dist/models/generated/openai.d.ts +17 -0
  102. package/packages/pi-ai/dist/models/generated/openai.d.ts.map +1 -1
  103. package/packages/pi-ai/dist/models/generated/openai.js +17 -0
  104. package/packages/pi-ai/dist/models/generated/openai.js.map +1 -1
  105. package/packages/pi-ai/dist/models.generated.test.js +43 -70
  106. package/packages/pi-ai/dist/models.generated.test.js.map +1 -1
  107. package/packages/pi-ai/dist/models.test.js +29 -11
  108. package/packages/pi-ai/dist/models.test.js.map +1 -1
  109. package/packages/pi-ai/scripts/generate-models.ts +44 -0
  110. package/packages/pi-ai/src/models/generated/openai-codex.ts +17 -0
  111. package/packages/pi-ai/src/models/generated/openai.ts +17 -0
  112. package/packages/pi-ai/src/models.generated.test.ts +46 -73
  113. package/packages/pi-ai/src/models.test.ts +39 -11
  114. package/packages/pi-ai/tsconfig.tsbuildinfo +1 -1
  115. package/packages/pi-coding-agent/dist/core/agent-session-abort-order.test.js +96 -32
  116. package/packages/pi-coding-agent/dist/core/agent-session-abort-order.test.js.map +1 -1
  117. package/packages/pi-coding-agent/dist/core/agent-session-model-switch.test.js +75 -12
  118. package/packages/pi-coding-agent/dist/core/agent-session-model-switch.test.js.map +1 -1
  119. package/packages/pi-coding-agent/dist/core/agent-session-tool-refresh.test.js +99 -31
  120. package/packages/pi-coding-agent/dist/core/agent-session-tool-refresh.test.js.map +1 -1
  121. package/packages/pi-coding-agent/dist/core/extensions/loader.d.ts +5 -0
  122. package/packages/pi-coding-agent/dist/core/extensions/loader.d.ts.map +1 -1
  123. package/packages/pi-coding-agent/dist/core/extensions/loader.js +61 -0
  124. package/packages/pi-coding-agent/dist/core/extensions/loader.js.map +1 -1
  125. package/packages/pi-coding-agent/dist/core/lsp/lsp-integration.test.js +30 -4
  126. package/packages/pi-coding-agent/dist/core/lsp/lsp-integration.test.js.map +1 -1
  127. package/packages/pi-coding-agent/dist/core/model-registry-auth-mode.test.js +17 -0
  128. package/packages/pi-coding-agent/dist/core/model-registry-auth-mode.test.js.map +1 -1
  129. package/packages/pi-coding-agent/dist/core/resource-loader-cache-reset.test.js +76 -18
  130. package/packages/pi-coding-agent/dist/core/resource-loader-cache-reset.test.js.map +1 -1
  131. package/packages/pi-coding-agent/dist/core/retry-handler.d.ts.map +1 -1
  132. package/packages/pi-coding-agent/dist/core/retry-handler.js +2 -6
  133. package/packages/pi-coding-agent/dist/core/retry-handler.js.map +1 -1
  134. package/packages/pi-coding-agent/dist/core/retry-handler.test.js +5 -1
  135. package/packages/pi-coding-agent/dist/core/retry-handler.test.js.map +1 -1
  136. package/packages/pi-coding-agent/dist/core/retryable-error-regex.d.ts +18 -0
  137. package/packages/pi-coding-agent/dist/core/retryable-error-regex.d.ts.map +1 -0
  138. package/packages/pi-coding-agent/dist/core/retryable-error-regex.js +18 -0
  139. package/packages/pi-coding-agent/dist/core/retryable-error-regex.js.map +1 -0
  140. package/packages/pi-coding-agent/dist/core/system-prompt.d.ts +20 -0
  141. package/packages/pi-coding-agent/dist/core/system-prompt.d.ts.map +1 -1
  142. package/packages/pi-coding-agent/dist/core/system-prompt.js +16 -2
  143. package/packages/pi-coding-agent/dist/core/system-prompt.js.map +1 -1
  144. package/packages/pi-coding-agent/dist/index.d.ts +1 -0
  145. package/packages/pi-coding-agent/dist/index.d.ts.map +1 -1
  146. package/packages/pi-coding-agent/dist/index.js +1 -0
  147. package/packages/pi-coding-agent/dist/index.js.map +1 -1
  148. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/tool-execution.test.js +36 -5
  149. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/tool-execution.test.js.map +1 -1
  150. package/packages/pi-coding-agent/dist/modes/interactive/components/dynamic-border.test.js +20 -13
  151. package/packages/pi-coding-agent/dist/modes/interactive/components/dynamic-border.test.js.map +1 -1
  152. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  153. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js +30 -12
  154. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js.map +1 -1
  155. package/packages/pi-coding-agent/dist/tests/system-prompt-skill-filter.test.d.ts +2 -0
  156. package/packages/pi-coding-agent/dist/tests/system-prompt-skill-filter.test.d.ts.map +1 -0
  157. package/packages/pi-coding-agent/dist/tests/system-prompt-skill-filter.test.js +130 -0
  158. package/packages/pi-coding-agent/dist/tests/system-prompt-skill-filter.test.js.map +1 -0
  159. package/packages/pi-coding-agent/src/core/agent-session-abort-order.test.ts +113 -37
  160. package/packages/pi-coding-agent/src/core/agent-session-model-switch.test.ts +89 -17
  161. package/packages/pi-coding-agent/src/core/agent-session-tool-refresh.test.ts +112 -43
  162. package/packages/pi-coding-agent/src/core/extensions/loader.ts +58 -0
  163. package/packages/pi-coding-agent/src/core/lsp/lsp-integration.test.ts +35 -4
  164. package/packages/pi-coding-agent/src/core/model-registry-auth-mode.test.ts +20 -0
  165. package/packages/pi-coding-agent/src/core/resource-loader-cache-reset.test.ts +93 -28
  166. package/packages/pi-coding-agent/src/core/retry-handler.test.ts +5 -1
  167. package/packages/pi-coding-agent/src/core/retry-handler.ts +2 -8
  168. package/packages/pi-coding-agent/src/core/retryable-error-regex.ts +18 -0
  169. package/packages/pi-coding-agent/src/core/system-prompt.ts +35 -1
  170. package/packages/pi-coding-agent/src/index.ts +1 -0
  171. package/packages/pi-coding-agent/src/modes/interactive/components/__tests__/tool-execution.test.ts +49 -3
  172. package/packages/pi-coding-agent/src/modes/interactive/components/dynamic-border.test.ts +26 -20
  173. package/packages/pi-coding-agent/src/modes/interactive/components/tool-execution.ts +48 -9
  174. package/packages/pi-coding-agent/src/tests/system-prompt-skill-filter.test.ts +157 -0
  175. package/packages/pi-coding-agent/tsconfig.tsbuildinfo +1 -1
  176. package/packages/pi-tui/dist/__tests__/autocomplete.test.js +18 -8
  177. package/packages/pi-tui/dist/__tests__/autocomplete.test.js.map +1 -1
  178. package/packages/pi-tui/dist/__tests__/overlay-layout.test.js +128 -17
  179. package/packages/pi-tui/dist/__tests__/overlay-layout.test.js.map +1 -1
  180. package/packages/pi-tui/dist/__tests__/stdin-buffer.test.js +36 -12
  181. package/packages/pi-tui/dist/__tests__/stdin-buffer.test.js.map +1 -1
  182. package/packages/pi-tui/dist/__tests__/tui.test.js +18 -30
  183. package/packages/pi-tui/dist/__tests__/tui.test.js.map +1 -1
  184. package/packages/pi-tui/dist/components/__tests__/input.test.js +10 -3
  185. package/packages/pi-tui/dist/components/__tests__/input.test.js.map +1 -1
  186. package/packages/pi-tui/dist/components/__tests__/loader.test.js +53 -9
  187. package/packages/pi-tui/dist/components/__tests__/loader.test.js.map +1 -1
  188. package/packages/pi-tui/dist/components/__tests__/markdown-maxlines.test.js +6 -2
  189. package/packages/pi-tui/dist/components/__tests__/markdown-maxlines.test.js.map +1 -1
  190. package/packages/pi-tui/dist/components/image.test.js +6 -5
  191. package/packages/pi-tui/dist/components/image.test.js.map +1 -1
  192. package/packages/pi-tui/src/__tests__/autocomplete.test.ts +24 -8
  193. package/packages/pi-tui/src/__tests__/overlay-layout.test.ts +140 -17
  194. package/packages/pi-tui/src/__tests__/stdin-buffer.test.ts +41 -12
  195. package/packages/pi-tui/src/__tests__/tui.test.ts +18 -37
  196. package/packages/pi-tui/src/components/__tests__/input.test.ts +19 -3
  197. package/packages/pi-tui/src/components/__tests__/loader.test.ts +112 -35
  198. package/packages/pi-tui/src/components/__tests__/markdown-maxlines.test.ts +9 -2
  199. package/packages/pi-tui/src/components/image.test.ts +10 -5
  200. package/packages/pi-tui/tsconfig.tsbuildinfo +1 -1
  201. package/packages/rpc-client/dist/rpc-client.test.js +101 -51
  202. package/packages/rpc-client/dist/rpc-client.test.js.map +1 -1
  203. package/packages/rpc-client/src/rpc-client.test.ts +109 -52
  204. package/packages/rpc-client/tsconfig.tsbuildinfo +1 -1
  205. package/scripts/install.js +15 -1
  206. package/src/resources/extensions/browser-tools/capture.ts +12 -0
  207. package/src/resources/extensions/browser-tools/tests/browser-tools-integration.test.mjs +8 -59
  208. package/src/resources/extensions/browser-tools/tests/browser-tools-unit.test.cjs +36 -24
  209. package/src/resources/extensions/browser-tools/tests/capture-sharp-optional.test.cjs +69 -71
  210. package/src/resources/extensions/browser-tools/tools/forms.ts +5 -1
  211. package/src/resources/extensions/browser-tools/tools/intent.ts +5 -1
  212. package/src/resources/extensions/claude-code-cli/tests/stream-adapter.test.ts +80 -72
  213. package/src/resources/extensions/github-sync/tests/cli.test.ts +76 -7
  214. package/src/resources/extensions/github-sync/tests/templates.test.ts +33 -1
  215. package/src/resources/extensions/gsd/auto/phases.ts +6 -17
  216. package/src/resources/extensions/gsd/auto/session.ts +7 -0
  217. package/src/resources/extensions/gsd/auto-dispatch.ts +40 -8
  218. package/src/resources/extensions/gsd/auto-post-unit.ts +81 -0
  219. package/src/resources/extensions/gsd/auto-prompts.ts +385 -93
  220. package/src/resources/extensions/gsd/auto-start.ts +97 -4
  221. package/src/resources/extensions/gsd/auto.ts +37 -0
  222. package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +9 -1
  223. package/src/resources/extensions/gsd/bootstrap/write-gate.ts +7 -1
  224. package/src/resources/extensions/gsd/component-loader.ts +598 -0
  225. package/src/resources/extensions/gsd/component-types.ts +362 -0
  226. package/src/resources/extensions/gsd/context-store.ts +25 -8
  227. package/src/resources/extensions/gsd/detection.ts +58 -1
  228. package/src/resources/extensions/gsd/docs/preferences-reference.md +1 -1
  229. package/src/resources/extensions/gsd/forensics.ts +118 -1
  230. package/src/resources/extensions/gsd/git-service.ts +16 -0
  231. package/src/resources/extensions/gsd/gsd-db.ts +1 -1
  232. package/src/resources/extensions/gsd/guided-flow.ts +2 -4
  233. package/src/resources/extensions/gsd/journal.ts +11 -1
  234. package/src/resources/extensions/gsd/memory-extractor.ts +11 -3
  235. package/src/resources/extensions/gsd/milestone-scope-classifier.ts +366 -0
  236. package/src/resources/extensions/gsd/model-cost-table.ts +3 -0
  237. package/src/resources/extensions/gsd/model-router.ts +6 -0
  238. package/src/resources/extensions/gsd/preferences-validation.ts +21 -0
  239. package/src/resources/extensions/gsd/prompt-cache-optimizer.ts +4 -0
  240. package/src/resources/extensions/gsd/prompts/complete-milestone.md +5 -1
  241. package/src/resources/extensions/gsd/prompts/plan-slice.md +15 -2
  242. package/src/resources/extensions/gsd/service-tier.ts +5 -2
  243. package/src/resources/extensions/gsd/skill-manifest.ts +175 -0
  244. package/src/resources/extensions/gsd/slice-cadence.ts +299 -0
  245. package/src/resources/extensions/gsd/tests/artifacts-table-preserved-on-cache-invalidate.test.ts +2 -1
  246. package/src/resources/extensions/gsd/tests/auto-loop.test.ts +25 -292
  247. package/src/resources/extensions/gsd/tests/auto-remediate-slice-status.test.ts +4 -1
  248. package/src/resources/extensions/gsd/tests/auto-retry-mcp-churn-fixes.test.ts +8 -194
  249. package/src/resources/extensions/gsd/tests/auto-start-clean-runtime-db-gated.test.ts +3 -2
  250. package/src/resources/extensions/gsd/tests/auto-start-cold-db-bootstrap.test.ts +2 -2
  251. package/src/resources/extensions/gsd/tests/auto-start-needs-discussion.test.ts +15 -58
  252. package/src/resources/extensions/gsd/tests/auto-start-worktree-db-path.test.ts +2 -2
  253. package/src/resources/extensions/gsd/tests/auto-thinking-restore.test.ts +3 -2
  254. package/src/resources/extensions/gsd/tests/auto-warning-noise-regression.test.ts +3 -2
  255. package/src/resources/extensions/gsd/tests/bootstrap-derive-state-db-open.test.ts +2 -1
  256. package/src/resources/extensions/gsd/tests/cache-staleness-regression.test.ts +17 -21
  257. package/src/resources/extensions/gsd/tests/canonical-milestone-root.test.ts +108 -0
  258. package/src/resources/extensions/gsd/tests/complete-milestone-excerpt.test.ts +263 -0
  259. package/src/resources/extensions/gsd/tests/complete-slice-composer.test.ts +192 -0
  260. package/src/resources/extensions/gsd/tests/complete-slice-verification-gate.test.ts +2 -1
  261. package/src/resources/extensions/gsd/tests/complete-task.test.ts +8 -4
  262. package/src/resources/extensions/gsd/tests/component-loader.test.ts +589 -0
  263. package/src/resources/extensions/gsd/tests/component-types.test.ts +127 -0
  264. package/src/resources/extensions/gsd/tests/context-store.test.ts +79 -0
  265. package/src/resources/extensions/gsd/tests/copy-planning-artifacts-samepath.test.ts +2 -1
  266. package/src/resources/extensions/gsd/tests/discuss-slice-structured-questions.test.ts +2 -1
  267. package/src/resources/extensions/gsd/tests/discuss-tool-scope-leak.test.ts +2 -1
  268. package/src/resources/extensions/gsd/tests/double-merge-guard.test.ts +4 -3
  269. package/src/resources/extensions/gsd/tests/empty-content-abort-loop.test.ts +4 -3
  270. package/src/resources/extensions/gsd/tests/extension-bootstrap-isolation.test.ts +139 -129
  271. package/src/resources/extensions/gsd/tests/finalize-timeout-guard.test.ts +8 -104
  272. package/src/resources/extensions/gsd/tests/hook-key-parsing.test.ts +4 -55
  273. package/src/resources/extensions/gsd/tests/integration/all-milestones-complete-merge.test.ts +7 -56
  274. package/src/resources/extensions/gsd/tests/integration/doctor-proactive.test.ts +18 -2
  275. package/src/resources/extensions/gsd/tests/integration/queue-completed-milestone-perf.test.ts +10 -4
  276. package/src/resources/extensions/gsd/tests/integration/state-machine-edge-cases.test.ts +1 -1
  277. package/src/resources/extensions/gsd/tests/interactive-routing-bypass.test.ts +9 -3
  278. package/src/resources/extensions/gsd/tests/interrupted-session-ui.test.ts +6 -9
  279. package/src/resources/extensions/gsd/tests/knowledge.test.ts +93 -1
  280. package/src/resources/extensions/gsd/tests/mcp-client-security.test.ts +8 -37
  281. package/src/resources/extensions/gsd/tests/memory-extractor.test.ts +5 -15
  282. package/src/resources/extensions/gsd/tests/merge-conflict-stops-loop.test.ts +227 -55
  283. package/src/resources/extensions/gsd/tests/milestone-scope-classifier.test.ts +187 -0
  284. package/src/resources/extensions/gsd/tests/model-cost-table.test.ts +9 -1
  285. package/src/resources/extensions/gsd/tests/model-router.test.ts +1 -1
  286. package/src/resources/extensions/gsd/tests/native-git-bridge-exec-fallback.test.ts +6 -48
  287. package/src/resources/extensions/gsd/tests/notification-widget.test.ts +6 -3
  288. package/src/resources/extensions/gsd/tests/orphaned-worktree-audit.test.ts +59 -2
  289. package/src/resources/extensions/gsd/tests/parallel-research-dispatch.test.ts +273 -130
  290. package/src/resources/extensions/gsd/tests/pipeline-variant-dispatch.test.ts +301 -0
  291. package/src/resources/extensions/gsd/tests/preferences-worktree-sync.test.ts +2 -1
  292. package/src/resources/extensions/gsd/tests/prompt-cache-optimizer.test.ts +12 -0
  293. package/src/resources/extensions/gsd/tests/prompt-step-ordering.test.ts +15 -4
  294. package/src/resources/extensions/gsd/tests/provider-errors.test.ts +22 -16
  295. package/src/resources/extensions/gsd/tests/queue-draft-detection.test.ts +3 -2
  296. package/src/resources/extensions/gsd/tests/queued-discuss-fast-path.test.ts +4 -5
  297. package/src/resources/extensions/gsd/tests/reassess-default-optin.test.ts +132 -0
  298. package/src/resources/extensions/gsd/tests/recovery-attempts-reset.test.ts +8 -40
  299. package/src/resources/extensions/gsd/tests/regex-hardening.test.ts +136 -256
  300. package/src/resources/extensions/gsd/tests/research-milestone-composer.test.ts +114 -0
  301. package/src/resources/extensions/gsd/tests/restore-tools-after-discuss.test.ts +6 -3
  302. package/src/resources/extensions/gsd/tests/run-uat-composer.test.ts +148 -0
  303. package/src/resources/extensions/gsd/tests/service-tier.test.ts +4 -0
  304. package/src/resources/extensions/gsd/tests/sidecar-queue.test.ts +3 -2
  305. package/src/resources/extensions/gsd/tests/silent-catch-diagnostics.test.ts +55 -95
  306. package/src/resources/extensions/gsd/tests/skill-activation.test.ts +120 -1
  307. package/src/resources/extensions/gsd/tests/skill-manifest.test.ts +112 -0
  308. package/src/resources/extensions/gsd/tests/slice-cadence.test.ts +242 -0
  309. package/src/resources/extensions/gsd/tests/slice-context-injection.test.ts +3 -2
  310. package/src/resources/extensions/gsd/tests/smart-entry-draft.test.ts +2 -1
  311. package/src/resources/extensions/gsd/tests/stop-auto-race-null-unit.test.ts +3 -3
  312. package/src/resources/extensions/gsd/tests/structured-data-formatter.test.ts +11 -92
  313. package/src/resources/extensions/gsd/tests/subagent-model-dispatch.test.ts +7 -6
  314. package/src/resources/extensions/gsd/tests/survivor-branch-complete.test.ts +102 -101
  315. package/src/resources/extensions/gsd/tests/sync-worktree-skip-current.test.ts +4 -3
  316. package/src/resources/extensions/gsd/tests/test-helpers.test.ts +98 -0
  317. package/src/resources/extensions/gsd/tests/test-helpers.ts +153 -0
  318. package/src/resources/extensions/gsd/tests/token-profile.test.ts +8 -1
  319. package/src/resources/extensions/gsd/tests/unit-context-composer.test.ts +355 -0
  320. package/src/resources/extensions/gsd/tests/unit-context-manifest.test.ts +203 -0
  321. package/src/resources/extensions/gsd/tests/uok-gitops-wiring.test.ts +49 -26
  322. package/src/resources/extensions/gsd/tests/validate-milestone.test.ts +1 -0
  323. package/src/resources/extensions/gsd/tests/verify-artifact-tightened.test.ts +144 -80
  324. package/src/resources/extensions/gsd/tests/visualizer-critical-path.test.ts +20 -54
  325. package/src/resources/extensions/gsd/tests/visualizer-overlay.test.ts +342 -277
  326. package/src/resources/extensions/gsd/tests/worker-model-override.test.ts +37 -29
  327. package/src/resources/extensions/gsd/tests/worktree-db.test.ts +226 -266
  328. package/src/resources/extensions/gsd/tests/worktree-health-monorepo.test.ts +103 -67
  329. package/src/resources/extensions/gsd/tests/worktree-nested-git-safety.test.ts +92 -90
  330. package/src/resources/extensions/gsd/tests/worktree-submodule-safety.test.ts +238 -59
  331. package/src/resources/extensions/gsd/tests/worktree-sync-overwrite-loop.test.ts +113 -161
  332. package/src/resources/extensions/gsd/tests/worktree-telemetry.test.ts +210 -0
  333. package/src/resources/extensions/gsd/tests/zombie-gsd-state.test.ts +80 -96
  334. package/src/resources/extensions/gsd/tools/validate-milestone.ts +8 -2
  335. package/src/resources/extensions/gsd/unit-context-composer.ts +218 -0
  336. package/src/resources/extensions/gsd/unit-context-manifest.ts +492 -0
  337. package/src/resources/extensions/gsd/worktree-manager.ts +53 -0
  338. package/src/resources/extensions/gsd/worktree-resolver.ts +96 -9
  339. package/src/resources/extensions/gsd/worktree-telemetry.ts +322 -0
  340. package/src/resources/extensions/mcp-client/index.ts +3 -1
  341. package/src/resources/extensions/mcp-client/tests/server-name-spaces.test.ts +70 -36
  342. package/src/resources/extensions/ollama/index.ts +5 -1
  343. package/src/resources/extensions/ollama/ollama-auth-mode.test.ts +123 -15
  344. package/src/resources/extensions/ollama/ollama-status-indicator.test.ts +206 -19
  345. package/src/resources/extensions/remote-questions/manager.ts +36 -4
  346. package/src/resources/extensions/remote-questions/tests/command-polling.test.ts +200 -190
  347. package/src/resources/extensions/shared/tests/interview-preview.test.ts +11 -3
  348. package/src/resources/extensions/voice/tests/linux-ready.test.ts +129 -113
  349. package/packages/pi-ai/dist/utils/oauth/oauth-providers.test.d.ts +0 -2
  350. package/packages/pi-ai/dist/utils/oauth/oauth-providers.test.d.ts.map +0 -1
  351. package/packages/pi-ai/dist/utils/oauth/oauth-providers.test.js +0 -289
  352. package/packages/pi-ai/dist/utils/oauth/oauth-providers.test.js.map +0 -1
  353. package/packages/pi-ai/src/utils/oauth/oauth-providers.test.ts +0 -363
  354. package/src/resources/extensions/gsd/tests/auto-start-model-capture.test.ts +0 -143
  355. package/src/resources/extensions/gsd/tests/complete-milestone-false-merge.test.ts +0 -157
  356. package/src/resources/extensions/gsd/tests/dashboard-model-label-ordering.test.ts +0 -107
  357. package/src/resources/extensions/gsd/tests/find-missing-summaries-closed.test.ts +0 -48
  358. package/src/resources/extensions/gsd/tests/forensics-context-persist.test.ts +0 -159
  359. package/src/resources/extensions/gsd/tests/forensics-db-completion.test.ts +0 -96
  360. package/src/resources/extensions/gsd/tests/forensics-dedup.test.ts +0 -79
  361. package/src/resources/extensions/gsd/tests/forensics-hook-key-parse.test.ts +0 -74
  362. package/src/resources/extensions/gsd/tests/forensics-journal.test.ts +0 -162
  363. package/src/resources/extensions/gsd/tests/gitignore-bg-shell.test.ts +0 -38
  364. package/src/resources/extensions/gsd/tests/gsd-no-project-error.test.ts +0 -73
  365. package/src/resources/extensions/gsd/tests/idle-watchdog-stall-override.test.ts +0 -125
  366. package/src/resources/extensions/gsd/tests/import-done-milestones.test.ts +0 -42
  367. /package/dist/web/standalone/.next/static/{vidAVJkURvTJ0_V2-64ro → gYYky7yfxW8txb9vU2TrJ}/_buildManifest.js +0 -0
  368. /package/dist/web/standalone/.next/static/{vidAVJkURvTJ0_V2-64ro → gYYky7yfxW8txb9vU2TrJ}/_ssgManifest.js +0 -0
@@ -0,0 +1,69 @@
1
+ /**
2
+ * Unified Component Type Definitions
3
+ *
4
+ * Shared metadata for installable/discoverable skills and agents.
5
+ *
6
+ * Replaces the separate type systems in:
7
+ * - packages/pi-coding-agent/src/core/skills.ts (SkillFrontmatter, Skill)
8
+ * - src/resources/extensions/subagent/agents.ts (AgentConfig)
9
+ *
10
+ * Legacy skill and agent formats are supported via backward-compatible loading.
11
+ */
12
+ // ============================================================================
13
+ // Validation
14
+ // ============================================================================
15
+ /** Max name length per spec */
16
+ export const MAX_NAME_LENGTH = 64;
17
+ /** Max description length per spec */
18
+ export const MAX_DESCRIPTION_LENGTH = 1024;
19
+ /** Valid name pattern: lowercase a-z, 0-9, hyphens, no leading/trailing/consecutive hyphens */
20
+ export const NAME_PATTERN = /^[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$/;
21
+ /**
22
+ * Validate a component name.
23
+ * @returns Array of error messages (empty if valid).
24
+ */
25
+ export function validateComponentName(name) {
26
+ const errors = [];
27
+ if (!name || name.trim() === '') {
28
+ errors.push('name is required');
29
+ return errors;
30
+ }
31
+ if (name.length > MAX_NAME_LENGTH) {
32
+ errors.push(`name exceeds ${MAX_NAME_LENGTH} characters (${name.length})`);
33
+ }
34
+ if (name.includes('--')) {
35
+ errors.push('name must not contain consecutive hyphens');
36
+ }
37
+ if (!NAME_PATTERN.test(name)) {
38
+ if (/[A-Z]/.test(name)) {
39
+ errors.push('name must be lowercase');
40
+ }
41
+ else if (name.startsWith('-') || name.endsWith('-')) {
42
+ errors.push('name must not start or end with a hyphen');
43
+ }
44
+ else if (!name.includes('--')) {
45
+ errors.push('name must contain only lowercase a-z, 0-9, and hyphens');
46
+ }
47
+ }
48
+ return errors;
49
+ }
50
+ /**
51
+ * Validate a component description.
52
+ * @returns Array of error messages (empty if valid).
53
+ */
54
+ export function validateComponentDescription(description) {
55
+ const errors = [];
56
+ if (!description || description.trim() === '') {
57
+ errors.push('description is required');
58
+ }
59
+ else if (description.length > MAX_DESCRIPTION_LENGTH) {
60
+ errors.push(`description exceeds ${MAX_DESCRIPTION_LENGTH} characters (${description.length})`);
61
+ }
62
+ return errors;
63
+ }
64
+ /**
65
+ * Compute the canonical ID for a component.
66
+ */
67
+ export function computeComponentId(name, namespace) {
68
+ return namespace ? `${namespace}:${name}` : name;
69
+ }
@@ -180,7 +180,13 @@ export function queryProject() {
180
180
  // ─── Knowledge Query ───────────────────────────────────────────────────────
181
181
  /**
182
182
  * Filter KNOWLEDGE.md sections by keyword matching.
183
- * Uses H2 sections, matches keywords case-insensitively against:
183
+ *
184
+ * Structure-adaptive (issue #4719): files that organise entries as H3 items
185
+ * under one or more H2 topics are filtered at H3 granularity. Files with only
186
+ * H2 topic headers (no H3) fall back to H2-level filtering for backwards
187
+ * compatibility.
188
+ *
189
+ * Matches keywords case-insensitively against:
184
190
  * 1. Section header text
185
191
  * 2. First paragraph of section content (up to first blank line or next heading)
186
192
  *
@@ -189,28 +195,38 @@ export function queryProject() {
189
195
  *
190
196
  * @param content - Full KNOWLEDGE.md content
191
197
  * @param keywords - Keywords to match (case-insensitive)
192
- * @returns Concatenated matching sections with H2 headers, or empty string
198
+ * @returns Concatenated matching sections with their original heading prefix, or empty string
193
199
  */
194
200
  export async function queryKnowledge(content, keywords) {
195
201
  if (!content || keywords.length === 0)
196
202
  return '';
197
203
  // Lazy import to avoid circular dependency
198
204
  const { extractAllSections } = await import('./files.js');
199
- const sections = extractAllSections(content, 2);
205
+ // Prefer H3 granularity when available; fall back to H2 for H2-only files.
206
+ // This prevents single-H2-with-many-H3 layouts from returning the entire
207
+ // file on a keyword match against the H2 header or its first paragraph.
208
+ const h3Sections = extractAllSections(content, 3);
209
+ const useH3 = h3Sections.size > 0;
210
+ const sections = useH3 ? h3Sections : extractAllSections(content, 2);
200
211
  if (sections.size === 0)
201
212
  return '';
202
- // Normalize keywords for case-insensitive matching
203
- const normalizedKeywords = keywords.map(k => k.toLowerCase());
213
+ const prefix = useH3 ? '###' : '##';
214
+ // Trim, lowercase, drop empties, and de-dupe so callers can pass raw
215
+ // user-provided strings without risking empty-string / whitespace matches.
216
+ const normalizedKeywords = [...new Set(keywords
217
+ .map(k => k.trim().toLowerCase())
218
+ .filter(k => k.length > 0))];
219
+ if (normalizedKeywords.length === 0)
220
+ return '';
204
221
  const matchingSections = [];
205
222
  for (const [header, body] of sections) {
206
223
  // Extract first paragraph: everything up to first blank line or next heading
207
224
  const firstParagraph = body.split(/\n\s*\n|\n#/)[0] || '';
208
- // Check if any keyword matches header or first paragraph
209
225
  const headerLower = header.toLowerCase();
210
226
  const paragraphLower = firstParagraph.toLowerCase();
211
227
  const matches = normalizedKeywords.some(kw => headerLower.includes(kw) || paragraphLower.includes(kw));
212
228
  if (matches) {
213
- matchingSections.push(`## ${header}\n\n${body}`);
229
+ matchingSections.push(`${prefix} ${header}\n\n${body}`);
214
230
  }
215
231
  }
216
232
  return matchingSections.join('\n\n');
@@ -6,7 +6,7 @@
6
6
  * flow to show when entering a project directory.
7
7
  */
8
8
  import { existsSync, openSync, readSync, closeSync, readdirSync, readFileSync, statSync } from "node:fs";
9
- import { join } from "node:path";
9
+ import { dirname, join, parse as parsePath } from "node:path";
10
10
  import { homedir } from "node:os";
11
11
  import { gsdRoot } from "./paths.js";
12
12
  const gsdHome = process.env.GSD_HOME || join(homedir(), ".gsd");
@@ -951,6 +951,54 @@ function resolveVersionCatalogAccessors(basePath, versionCatalogFiles, settingsF
951
951
  }
952
952
  return accessors;
953
953
  }
954
+ /**
955
+ * Walk ancestor directories of `startDir` looking for any file in
956
+ * `PROJECT_FILES`. Stops at the filesystem root or at a `.git` boundary
957
+ * (so ancestors above a git repo root — e.g. `$HOME` or `/usr/local` —
958
+ * can't trigger false positives). Returns true if an ancestor contains
959
+ * one of the project markers.
960
+ *
961
+ * Used by the worktree health check (#2347) to avoid warning about
962
+ * monorepos where package.json / Cargo.toml / etc. live in a parent
963
+ * directory rather than in the worktree's own checkout.
964
+ *
965
+ * `existsFn` is injectable so this remains deterministically testable
966
+ * without touching the real filesystem; defaults to `fs.existsSync`.
967
+ */
968
+ export function hasProjectFileInAncestor(startDir, existsFn = existsSync) {
969
+ let checkDir = dirname(startDir);
970
+ const { root } = parsePath(checkDir);
971
+ while (checkDir !== root) {
972
+ if (PROJECT_FILES.some((f) => existsFn(join(checkDir, f)))) {
973
+ return true;
974
+ }
975
+ // Stop at git repository boundary — ancestors above the repo root
976
+ // may contain unrelated project files. Check AFTER project-file scan
977
+ // so a repo root containing both .git and a marker is still recognized.
978
+ if (existsFn(join(checkDir, ".git")))
979
+ return false;
980
+ checkDir = dirname(checkDir);
981
+ }
982
+ return false;
983
+ }
984
+ /**
985
+ * Check whether a project's `.gsd/` directory contains the bootstrap artifacts
986
+ * (`PREFERENCES.md` or `milestones/`) that indicate a completed init run.
987
+ *
988
+ * A zombie `.gsd/` state — symlink exists but neither artifact is present —
989
+ * must be treated as "needs init wizard". The previous guard checked only
990
+ * `existsSync(gsdRoot(basePath))`, which accepted zombie states and skipped
991
+ * the wizard (#2942).
992
+ *
993
+ * `existsFn` is injectable so tests can run deterministically; defaults to
994
+ * `fs.existsSync`.
995
+ */
996
+ export function hasGsdBootstrapArtifacts(gsdPath, existsFn = existsSync) {
997
+ return (existsFn(gsdPath) &&
998
+ (existsFn(join(gsdPath, "PREFERENCES.md")) ||
999
+ existsFn(join(gsdPath, "preferences.md")) ||
1000
+ existsFn(join(gsdPath, "milestones"))));
1001
+ }
954
1002
  export function scanProjectFiles(basePath) {
955
1003
  const files = [];
956
1004
  const queue = [{ path: basePath, depth: 0 }];
@@ -159,7 +159,7 @@ Setting `prefer_skills: []` does **not** disable skill discovery — it just mea
159
159
 
160
160
  - `phases`: fine-grained control over which phases run. Usually set by `token_profile`, but can be overridden. Keys:
161
161
  - `skip_research`: boolean — skip milestone-level research. Default: `false`.
162
- - `reassess_after_slice`: boolean — run roadmap reassessment after each completed slice. Default: `true`.
162
+ - `reassess_after_slice`: boolean — run a dedicated roadmap-reassessment unit after each completed slice. Default: `false` (per ADR-003 §4). The plan-slice agent for the next slice performs JIT reassessment via a prompt preamble at zero additional token cost; a dedicated reassess session is opt-in. Set to `true` (e.g. via the `burn-max` profile) if you want the explicit session.
163
163
  - `skip_reassess`: boolean — force-disable roadmap reassessment even if `reassess_after_slice` is enabled. Default: `false`.
164
164
  - `skip_slice_research`: boolean — skip per-slice research. Default: `false`.
165
165
 
@@ -29,6 +29,7 @@ import { getAutoWorktreePath } from "./auto-worktree.js";
29
29
  import { loadEffectiveGSDPreferences, loadGlobalGSDPreferences, getGlobalGSDPreferencesPath } from "./preferences.js";
30
30
  import { showNextAction } from "../shared/tui.js";
31
31
  import { ensurePreferencesFile, serializePreferencesToFrontmatter } from "./commands-prefs-wizard.js";
32
+ import { summarizeWorktreeTelemetry, percentile } from "./worktree-telemetry.js";
32
33
  // ─── Duplicate Detection ──────────────────────────────────────────────────────
33
34
  const DEDUP_PROMPT_SECTION = `
34
35
  ## Pre-Investigation: Duplicate Check (REQUIRED)
@@ -214,6 +215,16 @@ export async function buildForensicReport(basePath) {
214
215
  detectCrash(crashLock, anomalies);
215
216
  detectDoctorIssues(doctorIssues, anomalies);
216
217
  detectErrorTraces(unitTraces, anomalies);
218
+ // 11b. #4764 — worktree lifecycle telemetry
219
+ let worktreeTelemetry = null;
220
+ try {
221
+ worktreeTelemetry = summarizeWorktreeTelemetry(basePath);
222
+ detectWorktreeOrphans(worktreeTelemetry, anomalies);
223
+ }
224
+ catch {
225
+ // Telemetry is best-effort — do not let an aggregator failure block the
226
+ // rest of the forensic report.
227
+ }
217
228
  detectJournalAnomalies(journalSummary, anomalies);
218
229
  return {
219
230
  gsdVersion,
@@ -232,6 +243,7 @@ export async function buildForensicReport(basePath) {
232
243
  recentUnits,
233
244
  journalSummary,
234
245
  activityLogMeta,
246
+ worktreeTelemetry,
235
247
  };
236
248
  }
237
249
  // ─── Activity Log Scanner ─────────────────────────────────────────────────────
@@ -630,6 +642,45 @@ function detectMissingArtifacts(completedKeys, basePath, activeMilestone, anomal
630
642
  }
631
643
  }
632
644
  }
645
+ /**
646
+ * #4764 — surface worktree lifecycle and orphan signals in the forensic report.
647
+ *
648
+ * Consumes only the aggregated summary (not raw journal events) to respect
649
+ * the forensics memory-bloat guard in forensics-journal.test.ts — per-event
650
+ * detail stays in the journal itself where the LLM can query it on demand.
651
+ */
652
+ function detectWorktreeOrphans(summary, anomalies) {
653
+ // 1. Orphan aggregate — severity depends on reason. In-progress orphans are
654
+ // the #4761 consumer-side signal (live work sitting on an unmerged branch).
655
+ for (const [reason, count] of Object.entries(summary.orphansByReason)) {
656
+ if (count <= 0)
657
+ continue;
658
+ const severity = reason === "in-progress-unmerged" ? "warning" : "info";
659
+ anomalies.push({
660
+ type: "worktree-orphan",
661
+ severity,
662
+ summary: `${count} worktree orphan(s) detected (${reason})`,
663
+ details: reason === "in-progress-unmerged"
664
+ ? "Auto-mode exited without completing a milestone; live work sits on an unmerged milestone branch. Run `/gsd auto` to resume, or merge manually."
665
+ : reason === "complete-unmerged"
666
+ ? "A completed milestone's branch was never merged back to main. Run `/gsd health --fix` to resolve."
667
+ : `Reason: ${reason}.`,
668
+ });
669
+ }
670
+ // 2. Auto-exit producer signal — #4761's upstream cause.
671
+ if (summary.exitsWithUnmergedWork > 0) {
672
+ const reasonBreakdown = Object.entries(summary.exitsByReason)
673
+ .filter(([, n]) => n > 0)
674
+ .map(([r, n]) => `${r}=${n}`)
675
+ .join(", ");
676
+ anomalies.push({
677
+ type: "worktree-unmerged-exit",
678
+ severity: "warning",
679
+ summary: `${summary.exitsWithUnmergedWork} auto-exit(s) left milestone work unmerged`,
680
+ details: `Exit reasons: ${reasonBreakdown || "(none)"} · Producer-side signal for #4761-class orphans. Inspect .gsd/journal/*.jsonl with eventType:"auto-exit" for per-exit detail.`,
681
+ });
682
+ }
683
+ }
633
684
  function detectCrash(crashLock, anomalies) {
634
685
  if (!crashLock)
635
686
  return;
@@ -808,6 +859,39 @@ function saveForensicReport(basePath, report, problemDescription) {
808
859
  sections.push(`- Newest: ${meta.newestFile}`);
809
860
  sections.push(``);
810
861
  }
862
+ // #4764 — Worktree telemetry summary
863
+ if (report.worktreeTelemetry) {
864
+ const t = report.worktreeTelemetry;
865
+ const p50 = percentile(t.mergeDurationsMs, 0.5);
866
+ const p95 = percentile(t.mergeDurationsMs, 0.95);
867
+ sections.push(`## Worktree Telemetry`, ``);
868
+ sections.push(`- Worktrees created: ${t.worktreesCreated}`);
869
+ sections.push(`- Worktrees merged: ${t.worktreesMerged}`);
870
+ sections.push(`- Orphans detected: ${t.orphansDetected}`);
871
+ if (t.orphansDetected > 0) {
872
+ const breakdown = Object.entries(t.orphansByReason)
873
+ .map(([r, n]) => `${r}=${n}`).join(", ");
874
+ sections.push(` - By reason: ${breakdown}`);
875
+ }
876
+ sections.push(`- Merge conflicts: ${t.mergeConflicts}`);
877
+ if (t.mergeDurationsMs.length > 0) {
878
+ sections.push(`- Merge duration p50 / p95: ${p50 ?? "-"} / ${p95 ?? "-"} ms (n=${t.mergeDurationsMs.length})`);
879
+ }
880
+ sections.push(`- Auto-exits leaving unmerged work: ${t.exitsWithUnmergedWork}`);
881
+ if (Object.keys(t.exitsByReason).length > 0) {
882
+ const breakdown = Object.entries(t.exitsByReason)
883
+ .sort((a, b) => b[1] - a[1])
884
+ .map(([r, n]) => `${r}=${n}`).join(", ");
885
+ sections.push(` - Exit reasons: ${breakdown}`);
886
+ }
887
+ sections.push(`- Canonical-root redirects (#4761 fix fired): ${t.canonicalRedirects}`);
888
+ // #4765 slice-cadence counters
889
+ if (t.slicesMerged + t.sliceMergeConflicts + t.milestoneResquashes > 0) {
890
+ sections.push(`- Slices merged: ${t.slicesMerged} · Slice merge conflicts: ${t.sliceMergeConflicts}`);
891
+ sections.push(`- Milestone re-squashes: ${t.milestoneResquashes}`);
892
+ }
893
+ sections.push(``);
894
+ }
811
895
  // Journal summary
812
896
  if (report.journalSummary) {
813
897
  const js = report.journalSummary;
@@ -940,6 +1024,28 @@ function formatReportForPrompt(report) {
940
1024
  sections.push(`- Total duration: ${formatDuration(totals.duration)}`);
941
1025
  sections.push("");
942
1026
  }
1027
+ // #4764 — worktree telemetry (compact prompt form)
1028
+ if (report.worktreeTelemetry) {
1029
+ const t = report.worktreeTelemetry;
1030
+ const hasSignal = t.worktreesCreated + t.worktreesMerged + t.orphansDetected +
1031
+ t.exitsWithUnmergedWork + t.canonicalRedirects +
1032
+ t.slicesMerged + t.milestoneResquashes > 0;
1033
+ if (hasSignal) {
1034
+ sections.push("### Worktree Telemetry");
1035
+ sections.push(`- Created: ${t.worktreesCreated} · Merged: ${t.worktreesMerged} · Conflicts: ${t.mergeConflicts}`);
1036
+ sections.push(`- Orphans: ${t.orphansDetected} · Unmerged exits: ${t.exitsWithUnmergedWork} · Redirects (#4761): ${t.canonicalRedirects}`);
1037
+ if (t.orphansDetected > 0) {
1038
+ const breakdown = Object.entries(t.orphansByReason)
1039
+ .map(([r, n]) => `${r}=${n}`).join(", ");
1040
+ sections.push(`- Orphan reasons: ${breakdown}`);
1041
+ }
1042
+ // #4765 — slice-cadence counters (only shown when the feature was exercised)
1043
+ if (t.slicesMerged + t.sliceMergeConflicts + t.milestoneResquashes > 0) {
1044
+ sections.push(`- Slices merged: ${t.slicesMerged} · Slice conflicts: ${t.sliceMergeConflicts} · Re-squashes: ${t.milestoneResquashes}`);
1045
+ }
1046
+ sections.push("");
1047
+ }
1048
+ }
943
1049
  // Activity log metadata
944
1050
  if (report.activityLogMeta) {
945
1051
  const meta = report.activityLogMeta;
@@ -135,7 +135,7 @@ function openRawDb(path) {
135
135
  const Database = providerModule;
136
136
  return new Database(path);
137
137
  }
138
- const SCHEMA_VERSION = 22;
138
+ export const SCHEMA_VERSION = 22;
139
139
  function indexExists(db, name) {
140
140
  return !!db.prepare("SELECT 1 as present FROM sqlite_master WHERE type = 'index' AND name = ?").get(name);
141
141
  }
@@ -28,7 +28,7 @@ import { ensureGitignore, ensurePreferences, untrackRuntimeFiles } from "./gitig
28
28
  import { loadEffectiveGSDPreferences } from "./preferences.js";
29
29
  import { resolveUokFlags } from "./uok/flags.js";
30
30
  import { ensurePlanV2Graph, isMissingFinalizedContextResult } from "./uok/plan-v2.js";
31
- import { detectProjectState } from "./detection.js";
31
+ import { detectProjectState, hasGsdBootstrapArtifacts } from "./detection.js";
32
32
  import { showProjectInit, offerMigration } from "./init-wizard.js";
33
33
  import { validateDirectory } from "./validate-directory.js";
34
34
  import { showConfirm } from "../shared/tui.js";
@@ -1244,9 +1244,7 @@ export async function showSmartEntry(ctx, pi, basePath, options) {
1244
1244
  // A zombie .gsd/ state (symlink exists but missing PREFERENCES.md and
1245
1245
  // milestones/) must trigger the init wizard, not skip it (#2942).
1246
1246
  const gsdPath = gsdRoot(basePath);
1247
- const hasBootstrapArtifacts = existsSync(gsdPath)
1248
- && (existsSync(join(gsdPath, "PREFERENCES.md"))
1249
- || existsSync(join(gsdPath, "milestones")));
1247
+ const hasBootstrapArtifacts = hasGsdBootstrapArtifacts(gsdPath);
1250
1248
  if (!hasBootstrapArtifacts) {
1251
1249
  const detection = detectProjectState(basePath);
1252
1250
  // v1 .planning/ detected — offer migration before anything else
@@ -62,7 +62,9 @@ export function buildMemoryLLMCall(ctx) {
62
62
  // which returns undefined for OAuth users (Claude Max / Claude Pro).
63
63
  // See: https://github.com/gsd-build/gsd-2/issues/2959
64
64
  const resolvedKeyPromise = ctx.modelRegistry.getApiKey(selectedModel).catch(() => undefined);
65
- return async (system, user) => {
65
+ // Expose on the returned fn so tests can await resolution deterministically
66
+ // (avoids arbitrary setTimeout polling for an internal microtask).
67
+ const llmCall = async (system, user) => {
66
68
  const { completeSimple } = await import('@gsd/pi-ai');
67
69
  const resolvedApiKey = await resolvedKeyPromise;
68
70
  const result = await completeSimple(selectedModel, {
@@ -79,6 +81,10 @@ export function buildMemoryLLMCall(ctx) {
79
81
  .map(c => c.text);
80
82
  return textParts.join('');
81
83
  };
84
+ // Attach the in-flight API-key resolution so tests (and callers) can
85
+ // `await llmCall.apiKeyReady` rather than relying on setTimeout polling.
86
+ llmCall.apiKeyReady = resolvedKeyPromise;
87
+ return llmCall;
82
88
  }
83
89
  catch {
84
90
  return null;