gsd-pi 2.76.0 → 2.77.0

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 (536) hide show
  1. package/README.md +45 -25
  2. package/dist/claude-cli-check.js +32 -3
  3. package/dist/mcp-server.d.ts +7 -0
  4. package/dist/mcp-server.js +35 -1
  5. package/dist/onboarding.js +45 -0
  6. package/dist/resource-loader.d.ts +1 -1
  7. package/dist/resource-loader.js +2 -8
  8. package/dist/resources/agents/researcher.md +1 -1
  9. package/dist/resources/extensions/claude-code-cli/readiness.js +31 -8
  10. package/dist/resources/extensions/claude-code-cli/stream-adapter.js +77 -17
  11. package/dist/resources/extensions/gsd/auto/loop.js +9 -0
  12. package/dist/resources/extensions/gsd/auto/phases.js +104 -11
  13. package/dist/resources/extensions/gsd/auto/run-unit.js +38 -2
  14. package/dist/resources/extensions/gsd/auto/session.js +22 -1
  15. package/dist/resources/extensions/gsd/auto-dispatch.js +16 -3
  16. package/dist/resources/extensions/gsd/auto-model-selection.js +53 -16
  17. package/dist/resources/extensions/gsd/auto-post-unit.js +25 -2
  18. package/dist/resources/extensions/gsd/auto-prompts.js +14 -0
  19. package/dist/resources/extensions/gsd/auto-recovery.js +32 -1
  20. package/dist/resources/extensions/gsd/auto-start.js +58 -57
  21. package/dist/resources/extensions/gsd/auto-verification.js +33 -0
  22. package/dist/resources/extensions/gsd/auto-worktree.js +51 -53
  23. package/dist/resources/extensions/gsd/auto.js +70 -28
  24. package/dist/resources/extensions/gsd/blocked-models.js +68 -0
  25. package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +93 -1
  26. package/dist/resources/extensions/gsd/bootstrap/db-tools.js +39 -9
  27. package/dist/resources/extensions/gsd/bootstrap/exec-tools.js +93 -0
  28. package/dist/resources/extensions/gsd/bootstrap/memory-tools.js +3 -0
  29. package/dist/resources/extensions/gsd/bootstrap/register-extension.js +12 -0
  30. package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +52 -6
  31. package/dist/resources/extensions/gsd/bootstrap/system-context.js +84 -23
  32. package/dist/resources/extensions/gsd/bootstrap/write-gate.js +34 -2
  33. package/dist/resources/extensions/gsd/clean-root-preflight.js +93 -0
  34. package/dist/resources/extensions/gsd/commands-extract-learnings.js +54 -89
  35. package/dist/resources/extensions/gsd/commands-prefs-wizard.js +968 -23
  36. package/dist/resources/extensions/gsd/compaction-snapshot.js +121 -0
  37. package/dist/resources/extensions/gsd/complexity-classifier.js +5 -3
  38. package/dist/resources/extensions/gsd/db-writer.js +88 -16
  39. package/dist/resources/extensions/gsd/doctor-git-checks.js +23 -29
  40. package/dist/resources/extensions/gsd/doctor-providers.js +51 -5
  41. package/dist/resources/extensions/gsd/ecosystem/gsd-extension-api.js +1 -0
  42. package/dist/resources/extensions/gsd/error-classifier.js +31 -3
  43. package/dist/resources/extensions/gsd/exec-history.js +120 -0
  44. package/dist/resources/extensions/gsd/exec-sandbox.js +258 -0
  45. package/dist/resources/extensions/gsd/gitignore.js +1 -0
  46. package/dist/resources/extensions/gsd/gsd-db.js +168 -23
  47. package/dist/resources/extensions/gsd/guided-flow.js +190 -1
  48. package/dist/resources/extensions/gsd/health-widget.js +4 -1
  49. package/dist/resources/extensions/gsd/hook-emitter.js +108 -0
  50. package/dist/resources/extensions/gsd/init-wizard.js +15 -1
  51. package/dist/resources/extensions/gsd/key-manager.js +28 -0
  52. package/dist/resources/extensions/gsd/memory-backfill.js +126 -0
  53. package/dist/resources/extensions/gsd/memory-store.js +19 -0
  54. package/dist/resources/extensions/gsd/model-router.js +36 -3
  55. package/dist/resources/extensions/gsd/pre-execution-checks.js +44 -9
  56. package/dist/resources/extensions/gsd/preferences-types.js +9 -0
  57. package/dist/resources/extensions/gsd/preferences-validation.js +83 -0
  58. package/dist/resources/extensions/gsd/preferences.js +17 -17
  59. package/dist/resources/extensions/gsd/prompt-loader.js +22 -7
  60. package/dist/resources/extensions/gsd/prompts/complete-milestone.md +1 -1
  61. package/dist/resources/extensions/gsd/prompts/complete-slice.md +2 -2
  62. package/dist/resources/extensions/gsd/prompts/debug-diagnose.md +2 -0
  63. package/dist/resources/extensions/gsd/prompts/discuss-headless.md +8 -0
  64. package/dist/resources/extensions/gsd/prompts/discuss.md +29 -2
  65. package/dist/resources/extensions/gsd/prompts/execute-task.md +3 -2
  66. package/dist/resources/extensions/gsd/prompts/parallel-research-slices.md +5 -2
  67. package/dist/resources/extensions/gsd/prompts/plan-slice.md +1 -0
  68. package/dist/resources/extensions/gsd/prompts/research-slice.md +1 -0
  69. package/dist/resources/extensions/gsd/safety/evidence-collector.js +96 -0
  70. package/dist/resources/extensions/gsd/safety/file-change-validator.js +13 -5
  71. package/dist/resources/extensions/gsd/safety/safety-harness.js +5 -1
  72. package/dist/resources/extensions/gsd/state.js +43 -4
  73. package/dist/resources/extensions/gsd/token-counter.js +22 -5
  74. package/dist/resources/extensions/gsd/tools/complete-milestone.js +16 -10
  75. package/dist/resources/extensions/gsd/tools/exec-search-tool.js +59 -0
  76. package/dist/resources/extensions/gsd/tools/exec-tool.js +126 -0
  77. package/dist/resources/extensions/gsd/tools/memory-tools.js +26 -1
  78. package/dist/resources/extensions/gsd/tools/resume-tool.js +23 -0
  79. package/dist/resources/extensions/gsd/uok/plan-v2.js +20 -3
  80. package/dist/resources/extensions/gsd/workflow-mcp.js +3 -0
  81. package/dist/resources/extensions/gsd/workflow-templates/spike.md +6 -0
  82. package/dist/resources/extensions/gsd/worktree-resolver.js +50 -10
  83. package/dist/resources/extensions/search-the-web/command-search-provider.js +5 -4
  84. package/dist/resources/extensions/search-the-web/native-search.js +45 -13
  85. package/dist/resources/skills/api-design/SKILL.md +190 -0
  86. package/dist/resources/skills/create-mcp-server/SKILL.md +121 -0
  87. package/dist/resources/skills/decompose-into-slices/SKILL.md +139 -0
  88. package/dist/resources/skills/dependency-upgrade/SKILL.md +158 -0
  89. package/dist/resources/skills/design-an-interface/SKILL.md +102 -0
  90. package/dist/resources/skills/forensics/SKILL.md +153 -0
  91. package/dist/resources/skills/grill-me/SKILL.md +93 -0
  92. package/dist/resources/skills/handoff/SKILL.md +121 -0
  93. package/dist/resources/skills/observability/SKILL.md +174 -0
  94. package/dist/resources/skills/security-review/SKILL.md +181 -0
  95. package/dist/resources/skills/spike-wrap-up/SKILL.md +138 -0
  96. package/dist/resources/skills/tdd/SKILL.md +112 -0
  97. package/dist/resources/skills/verify-before-complete/SKILL.md +98 -0
  98. package/dist/resources/skills/write-docs/SKILL.md +82 -0
  99. package/dist/resources/skills/write-milestone-brief/SKILL.md +135 -0
  100. package/dist/tsconfig.extensions.tsbuildinfo +1 -1
  101. package/dist/web/standalone/.next/BUILD_ID +1 -1
  102. package/dist/web/standalone/.next/app-path-routes-manifest.json +10 -10
  103. package/dist/web/standalone/.next/build-manifest.json +2 -2
  104. package/dist/web/standalone/.next/required-server-files.json +1 -1
  105. package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
  106. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  107. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  108. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  109. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  110. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  111. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  112. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  113. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  114. package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
  115. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
  116. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  117. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
  118. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  119. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  120. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  121. package/dist/web/standalone/.next/server/app/index.html +1 -1
  122. package/dist/web/standalone/.next/server/app/index.rsc +1 -1
  123. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
  124. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +1 -1
  125. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  126. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
  127. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  128. package/dist/web/standalone/.next/server/app-paths-manifest.json +10 -10
  129. package/dist/web/standalone/.next/server/chunks/6897.js +2 -2
  130. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  131. package/dist/web/standalone/.next/server/middleware-manifest.json +1 -1
  132. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  133. package/dist/web/standalone/.next/server/pages/500.html +1 -1
  134. package/dist/web/standalone/server.js +1 -1
  135. package/dist/welcome-screen.js +6 -1
  136. package/dist/wizard.js +2 -0
  137. package/package.json +1 -1
  138. package/packages/daemon/package.json +2 -2
  139. package/packages/mcp-server/dist/remote-questions.d.ts +45 -0
  140. package/packages/mcp-server/dist/remote-questions.d.ts.map +1 -0
  141. package/packages/mcp-server/dist/remote-questions.js +732 -0
  142. package/packages/mcp-server/dist/remote-questions.js.map +1 -0
  143. package/packages/mcp-server/dist/server.d.ts +7 -0
  144. package/packages/mcp-server/dist/server.d.ts.map +1 -1
  145. package/packages/mcp-server/dist/server.js +70 -8
  146. package/packages/mcp-server/dist/server.js.map +1 -1
  147. package/packages/mcp-server/dist/session-manager.d.ts +14 -0
  148. package/packages/mcp-server/dist/session-manager.d.ts.map +1 -1
  149. package/packages/mcp-server/dist/session-manager.js +49 -1
  150. package/packages/mcp-server/dist/session-manager.js.map +1 -1
  151. package/packages/mcp-server/dist/workflow-tools.d.ts +1 -1
  152. package/packages/mcp-server/dist/workflow-tools.d.ts.map +1 -1
  153. package/packages/mcp-server/dist/workflow-tools.js +163 -25
  154. package/packages/mcp-server/dist/workflow-tools.js.map +1 -1
  155. package/packages/mcp-server/package.json +4 -3
  156. package/packages/mcp-server/src/mcp-server.test.ts +67 -0
  157. package/packages/mcp-server/src/remote-questions.test.ts +294 -0
  158. package/packages/mcp-server/src/remote-questions.ts +916 -0
  159. package/packages/mcp-server/src/server.ts +89 -14
  160. package/packages/mcp-server/src/session-manager.ts +43 -1
  161. package/packages/mcp-server/src/workflow-tools.test.ts +146 -1
  162. package/packages/mcp-server/src/workflow-tools.ts +215 -43
  163. package/packages/mcp-server/tsconfig.test.json +19 -0
  164. package/packages/mcp-server/tsconfig.tsbuildinfo +1 -1
  165. package/packages/native/package.json +1 -1
  166. package/packages/pi-agent-core/dist/agent-loop.js +12 -0
  167. package/packages/pi-agent-core/dist/agent-loop.js.map +1 -1
  168. package/packages/pi-agent-core/dist/types.d.ts +30 -0
  169. package/packages/pi-agent-core/dist/types.d.ts.map +1 -1
  170. package/packages/pi-agent-core/dist/types.js.map +1 -1
  171. package/packages/pi-agent-core/package.json +1 -1
  172. package/packages/pi-agent-core/src/agent-loop.ts +14 -0
  173. package/packages/pi-agent-core/src/types.ts +34 -0
  174. package/packages/pi-agent-core/tsconfig.tsbuildinfo +1 -1
  175. package/packages/pi-ai/dist/models/custom.d.ts +38 -0
  176. package/packages/pi-ai/dist/models/custom.d.ts.map +1 -1
  177. package/packages/pi-ai/dist/models/custom.js +41 -0
  178. package/packages/pi-ai/dist/models/custom.js.map +1 -1
  179. package/packages/pi-ai/dist/providers/anthropic-auth.test.js +1 -1
  180. package/packages/pi-ai/dist/providers/anthropic-auth.test.js.map +1 -1
  181. package/packages/pi-ai/dist/providers/anthropic-bearer-auth.test.d.ts +2 -0
  182. package/packages/pi-ai/dist/providers/anthropic-bearer-auth.test.d.ts.map +1 -0
  183. package/packages/pi-ai/dist/providers/anthropic-bearer-auth.test.js +13 -0
  184. package/packages/pi-ai/dist/providers/anthropic-bearer-auth.test.js.map +1 -0
  185. package/packages/pi-ai/dist/providers/anthropic-shared.d.ts.map +1 -1
  186. package/packages/pi-ai/dist/providers/anthropic-shared.js +27 -4
  187. package/packages/pi-ai/dist/providers/anthropic-shared.js.map +1 -1
  188. package/packages/pi-ai/dist/providers/anthropic.d.ts.map +1 -1
  189. package/packages/pi-ai/dist/providers/anthropic.js +13 -4
  190. package/packages/pi-ai/dist/providers/anthropic.js.map +1 -1
  191. package/packages/pi-ai/dist/providers/minimax-tool-name.test.d.ts +2 -0
  192. package/packages/pi-ai/dist/providers/minimax-tool-name.test.d.ts.map +1 -0
  193. package/packages/pi-ai/dist/providers/minimax-tool-name.test.js +80 -0
  194. package/packages/pi-ai/dist/providers/minimax-tool-name.test.js.map +1 -0
  195. package/packages/pi-ai/dist/providers/openai-completions.d.ts.map +1 -1
  196. package/packages/pi-ai/dist/providers/openai-completions.js +60 -15
  197. package/packages/pi-ai/dist/providers/openai-completions.js.map +1 -1
  198. package/packages/pi-ai/dist/providers/simple-options.d.ts +10 -0
  199. package/packages/pi-ai/dist/providers/simple-options.d.ts.map +1 -1
  200. package/packages/pi-ai/dist/providers/simple-options.js +16 -1
  201. package/packages/pi-ai/dist/providers/simple-options.js.map +1 -1
  202. package/packages/pi-ai/dist/providers/think-tag-parser.d.ts +17 -0
  203. package/packages/pi-ai/dist/providers/think-tag-parser.d.ts.map +1 -0
  204. package/packages/pi-ai/dist/providers/think-tag-parser.js +75 -0
  205. package/packages/pi-ai/dist/providers/think-tag-parser.js.map +1 -0
  206. package/packages/pi-ai/dist/providers/think-tag-parser.test.d.ts +2 -0
  207. package/packages/pi-ai/dist/providers/think-tag-parser.test.d.ts.map +1 -0
  208. package/packages/pi-ai/dist/providers/think-tag-parser.test.js +41 -0
  209. package/packages/pi-ai/dist/providers/think-tag-parser.test.js.map +1 -0
  210. package/packages/pi-ai/dist/utils/oauth/github-copilot.d.ts.map +1 -1
  211. package/packages/pi-ai/dist/utils/oauth/github-copilot.js +12 -2
  212. package/packages/pi-ai/dist/utils/oauth/github-copilot.js.map +1 -1
  213. package/packages/pi-ai/dist/utils/oauth/github-copilot.test.js +164 -14
  214. package/packages/pi-ai/dist/utils/oauth/github-copilot.test.js.map +1 -1
  215. package/packages/pi-ai/dist/utils/oauth/google-antigravity.d.ts.map +1 -1
  216. package/packages/pi-ai/dist/utils/oauth/google-antigravity.js +15 -3
  217. package/packages/pi-ai/dist/utils/oauth/google-antigravity.js.map +1 -1
  218. package/packages/pi-ai/dist/utils/oauth/google-antigravity.test.d.ts +2 -0
  219. package/packages/pi-ai/dist/utils/oauth/google-antigravity.test.d.ts.map +1 -0
  220. package/packages/pi-ai/dist/utils/oauth/google-antigravity.test.js +67 -0
  221. package/packages/pi-ai/dist/utils/oauth/google-antigravity.test.js.map +1 -0
  222. package/packages/pi-ai/dist/utils/oauth/google-gemini-cli.d.ts.map +1 -1
  223. package/packages/pi-ai/dist/utils/oauth/google-gemini-cli.js +16 -3
  224. package/packages/pi-ai/dist/utils/oauth/google-gemini-cli.js.map +1 -1
  225. package/packages/pi-ai/dist/utils/oauth/google-gemini-cli.test.d.ts +2 -0
  226. package/packages/pi-ai/dist/utils/oauth/google-gemini-cli.test.d.ts.map +1 -0
  227. package/packages/pi-ai/dist/utils/oauth/google-gemini-cli.test.js +67 -0
  228. package/packages/pi-ai/dist/utils/oauth/google-gemini-cli.test.js.map +1 -0
  229. package/packages/pi-ai/dist/utils/oauth/oauth-providers.test.d.ts +2 -0
  230. package/packages/pi-ai/dist/utils/oauth/oauth-providers.test.d.ts.map +1 -0
  231. package/packages/pi-ai/dist/utils/oauth/oauth-providers.test.js +289 -0
  232. package/packages/pi-ai/dist/utils/oauth/oauth-providers.test.js.map +1 -0
  233. package/packages/pi-ai/package.json +1 -1
  234. package/packages/pi-ai/src/models/custom.ts +42 -0
  235. package/packages/pi-ai/src/providers/anthropic-auth.test.ts +1 -1
  236. package/packages/pi-ai/src/providers/anthropic-bearer-auth.test.ts +26 -0
  237. package/packages/pi-ai/src/providers/anthropic-shared.ts +26 -5
  238. package/packages/pi-ai/src/providers/anthropic.ts +15 -4
  239. package/packages/pi-ai/src/providers/minimax-tool-name.test.ts +98 -0
  240. package/packages/pi-ai/src/providers/openai-completions.ts +57 -16
  241. package/packages/pi-ai/src/providers/simple-options.ts +17 -1
  242. package/packages/pi-ai/src/providers/think-tag-parser.test.ts +44 -0
  243. package/packages/pi-ai/src/providers/think-tag-parser.ts +94 -0
  244. package/packages/pi-ai/src/utils/oauth/github-copilot.test.ts +200 -23
  245. package/packages/pi-ai/src/utils/oauth/github-copilot.ts +12 -2
  246. package/packages/pi-ai/src/utils/oauth/google-antigravity.test.ts +84 -0
  247. package/packages/pi-ai/src/utils/oauth/google-antigravity.ts +15 -5
  248. package/packages/pi-ai/src/utils/oauth/google-gemini-cli.test.ts +84 -0
  249. package/packages/pi-ai/src/utils/oauth/google-gemini-cli.ts +16 -5
  250. package/packages/pi-ai/src/utils/oauth/oauth-providers.test.ts +363 -0
  251. package/packages/pi-ai/tsconfig.tsbuildinfo +1 -1
  252. package/packages/pi-coding-agent/dist/core/agent-session-abort-order.test.js +3 -2
  253. package/packages/pi-coding-agent/dist/core/agent-session-abort-order.test.js.map +1 -1
  254. package/packages/pi-coding-agent/dist/core/agent-session.d.ts +2 -0
  255. package/packages/pi-coding-agent/dist/core/agent-session.d.ts.map +1 -1
  256. package/packages/pi-coding-agent/dist/core/agent-session.js +32 -2
  257. package/packages/pi-coding-agent/dist/core/agent-session.js.map +1 -1
  258. package/packages/pi-coding-agent/dist/core/extensions/index.d.ts +1 -1
  259. package/packages/pi-coding-agent/dist/core/extensions/index.d.ts.map +1 -1
  260. package/packages/pi-coding-agent/dist/core/extensions/index.js.map +1 -1
  261. package/packages/pi-coding-agent/dist/core/extensions/loader.d.ts.map +1 -1
  262. package/packages/pi-coding-agent/dist/core/extensions/loader.js +4 -0
  263. package/packages/pi-coding-agent/dist/core/extensions/loader.js.map +1 -1
  264. package/packages/pi-coding-agent/dist/core/extensions/runner.d.ts +35 -2
  265. package/packages/pi-coding-agent/dist/core/extensions/runner.d.ts.map +1 -1
  266. package/packages/pi-coding-agent/dist/core/extensions/runner.js +233 -0
  267. package/packages/pi-coding-agent/dist/core/extensions/runner.js.map +1 -1
  268. package/packages/pi-coding-agent/dist/core/extensions/types.d.ts +205 -2
  269. package/packages/pi-coding-agent/dist/core/extensions/types.d.ts.map +1 -1
  270. package/packages/pi-coding-agent/dist/core/extensions/types.js.map +1 -1
  271. package/packages/pi-coding-agent/dist/core/hooks-runner.d.ts +53 -0
  272. package/packages/pi-coding-agent/dist/core/hooks-runner.d.ts.map +1 -0
  273. package/packages/pi-coding-agent/dist/core/hooks-runner.js +337 -0
  274. package/packages/pi-coding-agent/dist/core/hooks-runner.js.map +1 -0
  275. package/packages/pi-coding-agent/dist/core/hooks-runner.test.d.ts +2 -0
  276. package/packages/pi-coding-agent/dist/core/hooks-runner.test.d.ts.map +1 -0
  277. package/packages/pi-coding-agent/dist/core/hooks-runner.test.js +234 -0
  278. package/packages/pi-coding-agent/dist/core/hooks-runner.test.js.map +1 -0
  279. package/packages/pi-coding-agent/dist/core/index.d.ts +1 -0
  280. package/packages/pi-coding-agent/dist/core/index.d.ts.map +1 -1
  281. package/packages/pi-coding-agent/dist/core/index.js +1 -0
  282. package/packages/pi-coding-agent/dist/core/index.js.map +1 -1
  283. package/packages/pi-coding-agent/dist/core/model-discovery.d.ts +3 -1
  284. package/packages/pi-coding-agent/dist/core/model-discovery.d.ts.map +1 -1
  285. package/packages/pi-coding-agent/dist/core/model-discovery.js +92 -12
  286. package/packages/pi-coding-agent/dist/core/model-discovery.js.map +1 -1
  287. package/packages/pi-coding-agent/dist/core/model-discovery.test.js +16 -1
  288. package/packages/pi-coding-agent/dist/core/model-discovery.test.js.map +1 -1
  289. package/packages/pi-coding-agent/dist/core/model-registry-auth-header.test.d.ts +2 -0
  290. package/packages/pi-coding-agent/dist/core/model-registry-auth-header.test.d.ts.map +1 -0
  291. package/packages/pi-coding-agent/dist/core/model-registry-auth-header.test.js +40 -0
  292. package/packages/pi-coding-agent/dist/core/model-registry-auth-header.test.js.map +1 -0
  293. package/packages/pi-coding-agent/dist/core/model-registry-custom-caps.test.d.ts +2 -0
  294. package/packages/pi-coding-agent/dist/core/model-registry-custom-caps.test.d.ts.map +1 -0
  295. package/packages/pi-coding-agent/dist/core/model-registry-custom-caps.test.js +203 -0
  296. package/packages/pi-coding-agent/dist/core/model-registry-custom-caps.test.js.map +1 -0
  297. package/packages/pi-coding-agent/dist/core/model-registry-discovery.test.js +61 -1
  298. package/packages/pi-coding-agent/dist/core/model-registry-discovery.test.js.map +1 -1
  299. package/packages/pi-coding-agent/dist/core/model-registry.d.ts +5 -0
  300. package/packages/pi-coding-agent/dist/core/model-registry.d.ts.map +1 -1
  301. package/packages/pi-coding-agent/dist/core/model-registry.js +90 -10
  302. package/packages/pi-coding-agent/dist/core/model-registry.js.map +1 -1
  303. package/packages/pi-coding-agent/dist/core/redact-secrets.d.ts +2 -0
  304. package/packages/pi-coding-agent/dist/core/redact-secrets.d.ts.map +1 -0
  305. package/packages/pi-coding-agent/dist/core/redact-secrets.js +49 -0
  306. package/packages/pi-coding-agent/dist/core/redact-secrets.js.map +1 -0
  307. package/packages/pi-coding-agent/dist/core/redact-secrets.test.d.ts +2 -0
  308. package/packages/pi-coding-agent/dist/core/redact-secrets.test.d.ts.map +1 -0
  309. package/packages/pi-coding-agent/dist/core/redact-secrets.test.js +67 -0
  310. package/packages/pi-coding-agent/dist/core/redact-secrets.test.js.map +1 -0
  311. package/packages/pi-coding-agent/dist/core/session-manager.d.ts.map +1 -1
  312. package/packages/pi-coding-agent/dist/core/session-manager.js +10 -6
  313. package/packages/pi-coding-agent/dist/core/session-manager.js.map +1 -1
  314. package/packages/pi-coding-agent/dist/core/session-manager.test.js +45 -1
  315. package/packages/pi-coding-agent/dist/core/session-manager.test.js.map +1 -1
  316. package/packages/pi-coding-agent/dist/core/settings-manager.d.ts +55 -0
  317. package/packages/pi-coding-agent/dist/core/settings-manager.d.ts.map +1 -1
  318. package/packages/pi-coding-agent/dist/core/settings-manager.js.map +1 -1
  319. package/packages/pi-coding-agent/dist/index.d.ts +1 -1
  320. package/packages/pi-coding-agent/dist/index.d.ts.map +1 -1
  321. package/packages/pi-coding-agent/dist/index.js.map +1 -1
  322. package/packages/pi-coding-agent/dist/modes/interactive/components/chat-frame.d.ts +1 -1
  323. package/packages/pi-coding-agent/dist/modes/interactive/components/chat-frame.d.ts.map +1 -1
  324. package/packages/pi-coding-agent/dist/modes/interactive/components/chat-frame.js +5 -4
  325. package/packages/pi-coding-agent/dist/modes/interactive/components/chat-frame.js.map +1 -1
  326. package/packages/pi-coding-agent/dist/modes/interactive/components/provider-manager.d.ts.map +1 -1
  327. package/packages/pi-coding-agent/dist/modes/interactive/components/provider-manager.js +13 -7
  328. package/packages/pi-coding-agent/dist/modes/interactive/components/provider-manager.js.map +1 -1
  329. package/packages/pi-coding-agent/dist/modes/interactive/components/skill-invocation-message.d.ts +7 -6
  330. package/packages/pi-coding-agent/dist/modes/interactive/components/skill-invocation-message.d.ts.map +1 -1
  331. package/packages/pi-coding-agent/dist/modes/interactive/components/skill-invocation-message.js +29 -21
  332. package/packages/pi-coding-agent/dist/modes/interactive/components/skill-invocation-message.js.map +1 -1
  333. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  334. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js +13 -1
  335. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
  336. package/packages/pi-coding-agent/package.json +1 -1
  337. package/packages/pi-coding-agent/src/core/agent-session-abort-order.test.ts +3 -2
  338. package/packages/pi-coding-agent/src/core/agent-session.ts +38 -2
  339. package/packages/pi-coding-agent/src/core/extensions/index.ts +16 -0
  340. package/packages/pi-coding-agent/src/core/extensions/loader.ts +5 -0
  341. package/packages/pi-coding-agent/src/core/extensions/runner.ts +351 -0
  342. package/packages/pi-coding-agent/src/core/extensions/types.ts +258 -0
  343. package/packages/pi-coding-agent/src/core/hooks-runner.test.ts +269 -0
  344. package/packages/pi-coding-agent/src/core/hooks-runner.ts +460 -0
  345. package/packages/pi-coding-agent/src/core/index.ts +10 -0
  346. package/packages/pi-coding-agent/src/core/model-discovery.test.ts +19 -0
  347. package/packages/pi-coding-agent/src/core/model-discovery.ts +99 -12
  348. package/packages/pi-coding-agent/src/core/model-registry-auth-header.test.ts +44 -0
  349. package/packages/pi-coding-agent/src/core/model-registry-custom-caps.test.ts +245 -0
  350. package/packages/pi-coding-agent/src/core/model-registry-discovery.test.ts +75 -0
  351. package/packages/pi-coding-agent/src/core/model-registry.ts +102 -10
  352. package/packages/pi-coding-agent/src/core/redact-secrets.test.ts +86 -0
  353. package/packages/pi-coding-agent/src/core/redact-secrets.ts +58 -0
  354. package/packages/pi-coding-agent/src/core/session-manager.test.ts +65 -1
  355. package/packages/pi-coding-agent/src/core/session-manager.ts +10 -6
  356. package/packages/pi-coding-agent/src/core/settings-manager.ts +57 -0
  357. package/packages/pi-coding-agent/src/index.ts +16 -0
  358. package/packages/pi-coding-agent/src/modes/interactive/components/chat-frame.ts +6 -6
  359. package/packages/pi-coding-agent/src/modes/interactive/components/provider-manager.ts +16 -7
  360. package/packages/pi-coding-agent/src/modes/interactive/components/skill-invocation-message.ts +36 -22
  361. package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +13 -1
  362. package/packages/pi-coding-agent/tsconfig.tsbuildinfo +1 -1
  363. package/packages/pi-tui/package.json +1 -1
  364. package/packages/rpc-client/package.json +1 -1
  365. package/pkg/package.json +1 -1
  366. package/scripts/link-workspace-packages.cjs +1 -0
  367. package/src/resources/agents/researcher.md +1 -1
  368. package/src/resources/extensions/claude-code-cli/readiness.ts +32 -8
  369. package/src/resources/extensions/claude-code-cli/stream-adapter.ts +78 -17
  370. package/src/resources/extensions/claude-code-cli/tests/stream-adapter.test.ts +149 -5
  371. package/src/resources/extensions/gsd/auto/loop-deps.ts +14 -0
  372. package/src/resources/extensions/gsd/auto/loop.ts +9 -0
  373. package/src/resources/extensions/gsd/auto/phases.ts +131 -10
  374. package/src/resources/extensions/gsd/auto/run-unit.ts +40 -2
  375. package/src/resources/extensions/gsd/auto/session.ts +35 -2
  376. package/src/resources/extensions/gsd/auto-dispatch.ts +16 -3
  377. package/src/resources/extensions/gsd/auto-model-selection.ts +71 -15
  378. package/src/resources/extensions/gsd/auto-post-unit.ts +29 -3
  379. package/src/resources/extensions/gsd/auto-prompts.ts +28 -1
  380. package/src/resources/extensions/gsd/auto-recovery.ts +26 -1
  381. package/src/resources/extensions/gsd/auto-start.ts +60 -68
  382. package/src/resources/extensions/gsd/auto-verification.ts +33 -0
  383. package/src/resources/extensions/gsd/auto-worktree.ts +62 -63
  384. package/src/resources/extensions/gsd/auto.ts +73 -28
  385. package/src/resources/extensions/gsd/blocked-models.ts +98 -0
  386. package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +120 -1
  387. package/src/resources/extensions/gsd/bootstrap/db-tools.ts +40 -9
  388. package/src/resources/extensions/gsd/bootstrap/exec-tools.ts +109 -0
  389. package/src/resources/extensions/gsd/bootstrap/memory-tools.ts +5 -0
  390. package/src/resources/extensions/gsd/bootstrap/register-extension.ts +15 -0
  391. package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +54 -6
  392. package/src/resources/extensions/gsd/bootstrap/system-context.ts +89 -26
  393. package/src/resources/extensions/gsd/bootstrap/write-gate.ts +35 -2
  394. package/src/resources/extensions/gsd/clean-root-preflight.ts +111 -0
  395. package/src/resources/extensions/gsd/commands-extract-learnings.ts +55 -90
  396. package/src/resources/extensions/gsd/commands-prefs-wizard.ts +898 -32
  397. package/src/resources/extensions/gsd/compaction-snapshot.ts +165 -0
  398. package/src/resources/extensions/gsd/complexity-classifier.ts +5 -3
  399. package/src/resources/extensions/gsd/db-writer.ts +88 -17
  400. package/src/resources/extensions/gsd/doctor-git-checks.ts +23 -27
  401. package/src/resources/extensions/gsd/doctor-providers.ts +59 -6
  402. package/src/resources/extensions/gsd/ecosystem/gsd-extension-api.ts +2 -0
  403. package/src/resources/extensions/gsd/error-classifier.ts +36 -3
  404. package/src/resources/extensions/gsd/exec-history.ts +153 -0
  405. package/src/resources/extensions/gsd/exec-sandbox.ts +326 -0
  406. package/src/resources/extensions/gsd/gitignore.ts +1 -1
  407. package/src/resources/extensions/gsd/gsd-db.ts +186 -23
  408. package/src/resources/extensions/gsd/guided-flow.ts +222 -1
  409. package/src/resources/extensions/gsd/health-widget.ts +3 -1
  410. package/src/resources/extensions/gsd/hook-emitter.ts +188 -0
  411. package/src/resources/extensions/gsd/init-wizard.ts +15 -1
  412. package/src/resources/extensions/gsd/journal.ts +2 -1
  413. package/src/resources/extensions/gsd/key-manager.ts +28 -0
  414. package/src/resources/extensions/gsd/memory-backfill.ts +140 -0
  415. package/src/resources/extensions/gsd/memory-store.ts +26 -0
  416. package/src/resources/extensions/gsd/model-router.ts +42 -1
  417. package/src/resources/extensions/gsd/pre-execution-checks.ts +46 -10
  418. package/src/resources/extensions/gsd/preferences-types.ts +46 -0
  419. package/src/resources/extensions/gsd/preferences-validation.ts +79 -0
  420. package/src/resources/extensions/gsd/preferences.ts +17 -17
  421. package/src/resources/extensions/gsd/prompt-loader.ts +30 -7
  422. package/src/resources/extensions/gsd/prompts/complete-milestone.md +1 -1
  423. package/src/resources/extensions/gsd/prompts/complete-slice.md +2 -2
  424. package/src/resources/extensions/gsd/prompts/debug-diagnose.md +2 -0
  425. package/src/resources/extensions/gsd/prompts/discuss-headless.md +8 -0
  426. package/src/resources/extensions/gsd/prompts/discuss.md +29 -2
  427. package/src/resources/extensions/gsd/prompts/execute-task.md +3 -2
  428. package/src/resources/extensions/gsd/prompts/parallel-research-slices.md +5 -2
  429. package/src/resources/extensions/gsd/prompts/plan-slice.md +1 -0
  430. package/src/resources/extensions/gsd/prompts/research-slice.md +1 -0
  431. package/src/resources/extensions/gsd/safety/evidence-collector.ts +119 -0
  432. package/src/resources/extensions/gsd/safety/file-change-validator.ts +17 -4
  433. package/src/resources/extensions/gsd/safety/safety-harness.ts +9 -0
  434. package/src/resources/extensions/gsd/state.ts +45 -4
  435. package/src/resources/extensions/gsd/tests/auto-loop.test.ts +188 -2
  436. package/src/resources/extensions/gsd/tests/auto-model-selection.test.ts +95 -1
  437. package/src/resources/extensions/gsd/tests/auto-paused-session-validation.test.ts +12 -0
  438. package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +49 -0
  439. package/src/resources/extensions/gsd/tests/auto-start-bootstrap-await-3420.test.ts +141 -0
  440. package/src/resources/extensions/gsd/tests/auto-start-model-capture.test.ts +33 -3
  441. package/src/resources/extensions/gsd/tests/auto-thinking-restore.test.ts +38 -0
  442. package/src/resources/extensions/gsd/tests/auto-wrapup-inflight-guard.test.ts +23 -0
  443. package/src/resources/extensions/gsd/tests/blocked-models.test.ts +98 -0
  444. package/src/resources/extensions/gsd/tests/bundled-skill-triggers.test.ts +54 -0
  445. package/src/resources/extensions/gsd/tests/clean-root-preflight.test.ts +186 -0
  446. package/src/resources/extensions/gsd/tests/commands-extract-learnings.test.ts +68 -66
  447. package/src/resources/extensions/gsd/tests/compaction-snapshot.test.ts +123 -0
  448. package/src/resources/extensions/gsd/tests/complete-milestone.test.ts +61 -1
  449. package/src/resources/extensions/gsd/tests/complete-slice.test.ts +2 -2
  450. package/src/resources/extensions/gsd/tests/complete-task.test.ts +2 -2
  451. package/src/resources/extensions/gsd/tests/complexity-classifier.test.ts +3 -3
  452. package/src/resources/extensions/gsd/tests/custom-engine-loop-integration.test.ts +2 -0
  453. package/src/resources/extensions/gsd/tests/derive-state-db.test.ts +42 -0
  454. package/src/resources/extensions/gsd/tests/derive-state-helpers.test.ts +8 -4
  455. package/src/resources/extensions/gsd/tests/doctor-providers.test.ts +148 -3
  456. package/src/resources/extensions/gsd/tests/double-merge-guard.test.ts +1 -1
  457. package/src/resources/extensions/gsd/tests/ensure-db-open.test.ts +306 -1
  458. package/src/resources/extensions/gsd/tests/escalation.test.ts +1 -1
  459. package/src/resources/extensions/gsd/tests/exec-history.test.ts +237 -0
  460. package/src/resources/extensions/gsd/tests/exec-sandbox.test.ts +210 -0
  461. package/src/resources/extensions/gsd/tests/file-change-validator.test.ts +58 -0
  462. package/src/resources/extensions/gsd/tests/flat-rate-routing-guard.test.ts +40 -9
  463. package/src/resources/extensions/gsd/tests/freeform-decisions.test.ts +62 -0
  464. package/src/resources/extensions/gsd/tests/gsd-db.test.ts +447 -1
  465. package/src/resources/extensions/gsd/tests/init-wizard.test.ts +27 -0
  466. package/src/resources/extensions/gsd/tests/integration/doctor-git-symlink-cwd.test.ts +11 -0
  467. package/src/resources/extensions/gsd/tests/integration/doctor-git.test.ts +78 -0
  468. package/src/resources/extensions/gsd/tests/integration/git-service.test.ts +1 -0
  469. package/src/resources/extensions/gsd/tests/integration/gitignore-tracked-gsd.test.ts +1 -0
  470. package/src/resources/extensions/gsd/tests/integration/idle-recovery.test.ts +30 -0
  471. package/src/resources/extensions/gsd/tests/interactive-routing-bypass.test.ts +1 -1
  472. package/src/resources/extensions/gsd/tests/isolation-none-branch-guard.test.ts +1 -1
  473. package/src/resources/extensions/gsd/tests/issue-4540-regressions.test.ts +288 -0
  474. package/src/resources/extensions/gsd/tests/journal-integration.test.ts +37 -0
  475. package/src/resources/extensions/gsd/tests/key-manager.test.ts +9 -0
  476. package/src/resources/extensions/gsd/tests/load-memory-block.test.ts +36 -0
  477. package/src/resources/extensions/gsd/tests/md-importer.test.ts +1 -1
  478. package/src/resources/extensions/gsd/tests/memory-pressure-stuck-state.test.ts +12 -0
  479. package/src/resources/extensions/gsd/tests/memory-store.test.ts +2 -2
  480. package/src/resources/extensions/gsd/tests/parallel-research-dispatch.test.ts +19 -0
  481. package/src/resources/extensions/gsd/tests/plan-gate-failed-doctor-heal-hint.test.ts +37 -0
  482. package/src/resources/extensions/gsd/tests/pre-exec-backtick-strip.test.ts +14 -0
  483. package/src/resources/extensions/gsd/tests/pre-exec-gate-loop.test.ts +272 -0
  484. package/src/resources/extensions/gsd/tests/pre-execution-checks.test.ts +356 -0
  485. package/src/resources/extensions/gsd/tests/preferences.test.ts +110 -0
  486. package/src/resources/extensions/gsd/tests/prefs-wizard-coverage.test.ts +44 -0
  487. package/src/resources/extensions/gsd/tests/prompt-loader-extension-dir.test.ts +49 -0
  488. package/src/resources/extensions/gsd/tests/provider-errors.test.ts +103 -4
  489. package/src/resources/extensions/gsd/tests/ready-phrase-no-files-4573.test.ts +388 -0
  490. package/src/resources/extensions/gsd/tests/restore-tools-after-discuss.test.ts +9 -3
  491. package/src/resources/extensions/gsd/tests/resume-dispatch-worktree.test.ts +230 -0
  492. package/src/resources/extensions/gsd/tests/safety-harness-false-positives.test.ts +205 -0
  493. package/src/resources/extensions/gsd/tests/save-gate-result-render.test.ts +95 -0
  494. package/src/resources/extensions/gsd/tests/schema-v21-sequence.test.ts +413 -0
  495. package/src/resources/extensions/gsd/tests/session-start-footer.test.ts +32 -40
  496. package/src/resources/extensions/gsd/tests/stash-queued-context-files.test.ts +56 -0
  497. package/src/resources/extensions/gsd/tests/token-counter.test.ts +105 -1
  498. package/src/resources/extensions/gsd/tests/tool-compatibility.test.ts +107 -0
  499. package/src/resources/extensions/gsd/tests/uok-plan-v2-wiring.test.ts +23 -0
  500. package/src/resources/extensions/gsd/tests/validate-milestone.test.ts +9 -3
  501. package/src/resources/extensions/gsd/tests/workflow-tool-executors.test.ts +65 -2
  502. package/src/resources/extensions/gsd/tests/worktree-db.test.ts +35 -0
  503. package/src/resources/extensions/gsd/tests/worktree-journal-events.test.ts +6 -1
  504. package/src/resources/extensions/gsd/tests/worktree-resolver.test.ts +78 -5
  505. package/src/resources/extensions/gsd/tests/write-gate.test.ts +64 -0
  506. package/src/resources/extensions/gsd/tests/zombie-gsd-state.test.ts +3 -1
  507. package/src/resources/extensions/gsd/token-counter.ts +22 -5
  508. package/src/resources/extensions/gsd/tools/complete-milestone.ts +15 -9
  509. package/src/resources/extensions/gsd/tools/exec-search-tool.ts +81 -0
  510. package/src/resources/extensions/gsd/tools/exec-tool.ts +183 -0
  511. package/src/resources/extensions/gsd/tools/memory-tools.ts +31 -1
  512. package/src/resources/extensions/gsd/tools/resume-tool.ts +40 -0
  513. package/src/resources/extensions/gsd/uok/plan-v2.ts +26 -3
  514. package/src/resources/extensions/gsd/workflow-logger.ts +4 -1
  515. package/src/resources/extensions/gsd/workflow-mcp.ts +3 -0
  516. package/src/resources/extensions/gsd/workflow-templates/spike.md +6 -0
  517. package/src/resources/extensions/gsd/worktree-resolver.ts +54 -9
  518. package/src/resources/extensions/search-the-web/command-search-provider.ts +5 -4
  519. package/src/resources/extensions/search-the-web/native-search.ts +48 -12
  520. package/src/resources/skills/api-design/SKILL.md +190 -0
  521. package/src/resources/skills/create-mcp-server/SKILL.md +121 -0
  522. package/src/resources/skills/decompose-into-slices/SKILL.md +139 -0
  523. package/src/resources/skills/dependency-upgrade/SKILL.md +158 -0
  524. package/src/resources/skills/design-an-interface/SKILL.md +102 -0
  525. package/src/resources/skills/forensics/SKILL.md +153 -0
  526. package/src/resources/skills/grill-me/SKILL.md +93 -0
  527. package/src/resources/skills/handoff/SKILL.md +121 -0
  528. package/src/resources/skills/observability/SKILL.md +174 -0
  529. package/src/resources/skills/security-review/SKILL.md +181 -0
  530. package/src/resources/skills/spike-wrap-up/SKILL.md +138 -0
  531. package/src/resources/skills/tdd/SKILL.md +112 -0
  532. package/src/resources/skills/verify-before-complete/SKILL.md +98 -0
  533. package/src/resources/skills/write-docs/SKILL.md +82 -0
  534. package/src/resources/skills/write-milestone-brief/SKILL.md +135 -0
  535. /package/dist/web/standalone/.next/static/{ssX7BLv3Dw9Fb4CtrCGeR → pV-mPo7rYGb5JBC09C8GG}/_buildManifest.js +0 -0
  536. /package/dist/web/standalone/.next/static/{ssX7BLv3Dw9Fb4CtrCGeR → pV-mPo7rYGb5JBC09C8GG}/_ssgManifest.js +0 -0
@@ -0,0 +1,258 @@
1
+ // GSD Exec Sandbox — tool-output sandboxing for sub-sessions.
2
+ //
3
+ // Runs a script in a subprocess and persists stdout/stderr to
4
+ // `.gsd/exec/<id>.{stdout,stderr,meta.json}`. Only a short digest is
5
+ // returned to the calling agent's context, keeping large outputs
6
+ // (e.g. Playwright snapshots, issue dumps) out of the window.
7
+ //
8
+ // Inspired by mksglu/context-mode (Elastic License 2.0). Independent
9
+ // implementation — no upstream code incorporated.
10
+ import { spawn } from "node:child_process";
11
+ import { existsSync, mkdirSync, writeFileSync } from "node:fs";
12
+ import { randomUUID } from "node:crypto";
13
+ import { resolve } from "node:path";
14
+ const ALWAYS_FORWARD_ENV = ["PATH", "HOME"];
15
+ export const EXEC_DEFAULTS = {
16
+ clampTimeoutMs: 600_000,
17
+ defaultTimeoutMs: 30_000,
18
+ stdoutCapBytes: 1_048_576,
19
+ stderrCapBytes: 262_144,
20
+ digestChars: 300,
21
+ envAllowlist: [
22
+ "LANG",
23
+ "LC_ALL",
24
+ "TERM",
25
+ "TZ",
26
+ "SHELL",
27
+ "USER",
28
+ "LOGNAME",
29
+ "TMPDIR",
30
+ "NODE_OPTIONS",
31
+ "PYTHONPATH",
32
+ "PYTHONIOENCODING",
33
+ ],
34
+ };
35
+ function buildChildEnv(opts) {
36
+ const source = opts.env ?? process.env;
37
+ const out = {};
38
+ const allowed = new Set([...ALWAYS_FORWARD_ENV, ...opts.env_allowlist]);
39
+ for (const key of allowed) {
40
+ const value = source[key];
41
+ if (typeof value === "string")
42
+ out[key] = value;
43
+ }
44
+ return out;
45
+ }
46
+ function clampTimeout(request, opts) {
47
+ const requested = typeof request.timeout_ms === "number" && Number.isFinite(request.timeout_ms)
48
+ ? Math.floor(request.timeout_ms)
49
+ : opts.default_timeout_ms;
50
+ if (requested < 1)
51
+ return 1;
52
+ if (requested > opts.clamp_timeout_ms)
53
+ return opts.clamp_timeout_ms;
54
+ return requested;
55
+ }
56
+ function resolveCommand(runtime) {
57
+ switch (runtime) {
58
+ case "bash":
59
+ return { cmd: "bash", args: ["-c"] };
60
+ case "node":
61
+ return { cmd: process.execPath, args: ["-e"] };
62
+ case "python":
63
+ return { cmd: "python3", args: ["-c"] };
64
+ }
65
+ }
66
+ function tail(buf, chars) {
67
+ if (chars <= 0)
68
+ return "";
69
+ const text = buf.toString("utf-8");
70
+ return text.length <= chars ? text : text.slice(text.length - chars);
71
+ }
72
+ /**
73
+ * Run a script in a subprocess, capture stdout/stderr to files under
74
+ * `.gsd/exec/<id>.{stdout,stderr,meta.json}`, and return an `ExecSandboxResult`
75
+ * containing the digest plus metadata.
76
+ *
77
+ * Errors from spawn failures resolve (not reject) with `exit_code=null`.
78
+ * The function is pure with respect to its inputs — no global state beyond
79
+ * filesystem writes under `baseDir`.
80
+ */
81
+ export function runExecSandbox(request, opts) {
82
+ return new Promise((resolveP) => {
83
+ const id = (opts.generateId ?? defaultGenerateId)();
84
+ const now = (opts.now ?? (() => new Date()))();
85
+ const execDir = resolve(opts.baseDir, ".gsd", "exec");
86
+ if (!existsSync(execDir))
87
+ mkdirSync(execDir, { recursive: true });
88
+ const stdoutPath = resolve(execDir, `${id}.stdout`);
89
+ const stderrPath = resolve(execDir, `${id}.stderr`);
90
+ const metaPath = resolve(execDir, `${id}.meta.json`);
91
+ const timeoutMs = clampTimeout(request, opts);
92
+ const { cmd, args } = resolveCommand(request.runtime);
93
+ const env = buildChildEnv(opts);
94
+ const useProcessGroup = process.platform !== "win32";
95
+ const started = Date.now();
96
+ let child;
97
+ try {
98
+ child = spawn(cmd, [...args, request.script], {
99
+ cwd: opts.baseDir,
100
+ env,
101
+ stdio: ["ignore", "pipe", "pipe"],
102
+ ...(useProcessGroup ? { detached: true } : {}),
103
+ });
104
+ }
105
+ catch (err) {
106
+ const duration = Date.now() - started;
107
+ const message = err instanceof Error ? err.message : String(err);
108
+ writeFileSync(stdoutPath, "");
109
+ writeFileSync(stderrPath, `spawn error: ${message}\n`);
110
+ const result = {
111
+ id,
112
+ runtime: request.runtime,
113
+ exit_code: null,
114
+ signal: null,
115
+ timed_out: false,
116
+ duration_ms: duration,
117
+ stdout_bytes: 0,
118
+ stderr_bytes: Buffer.byteLength(`spawn error: ${message}\n`),
119
+ stdout_truncated: false,
120
+ stderr_truncated: false,
121
+ stdout_path: stdoutPath,
122
+ stderr_path: stderrPath,
123
+ meta_path: metaPath,
124
+ digest: `[spawn error: ${message}]`,
125
+ };
126
+ writeMeta(metaPath, result, request, now);
127
+ resolveP(result);
128
+ return;
129
+ }
130
+ const stdoutChunks = [];
131
+ const stderrChunks = [];
132
+ let stdoutBytes = 0;
133
+ let stderrBytes = 0;
134
+ let stdoutTruncated = false;
135
+ let stderrTruncated = false;
136
+ child.stdout?.on("data", (chunk) => {
137
+ const remaining = opts.stdout_cap_bytes - stdoutBytes;
138
+ if (remaining <= 0) {
139
+ stdoutTruncated = true;
140
+ return;
141
+ }
142
+ if (chunk.length <= remaining) {
143
+ stdoutChunks.push(chunk);
144
+ stdoutBytes += chunk.length;
145
+ }
146
+ else {
147
+ stdoutChunks.push(chunk.subarray(0, remaining));
148
+ stdoutBytes += remaining;
149
+ stdoutTruncated = true;
150
+ }
151
+ });
152
+ child.stderr?.on("data", (chunk) => {
153
+ const remaining = opts.stderr_cap_bytes - stderrBytes;
154
+ if (remaining <= 0) {
155
+ stderrTruncated = true;
156
+ return;
157
+ }
158
+ if (chunk.length <= remaining) {
159
+ stderrChunks.push(chunk);
160
+ stderrBytes += chunk.length;
161
+ }
162
+ else {
163
+ stderrChunks.push(chunk.subarray(0, remaining));
164
+ stderrBytes += remaining;
165
+ stderrTruncated = true;
166
+ }
167
+ });
168
+ let timedOut = false;
169
+ const timer = setTimeout(() => {
170
+ timedOut = true;
171
+ if (useProcessGroup && child.pid != null) {
172
+ try {
173
+ process.kill(-child.pid, "SIGKILL");
174
+ }
175
+ catch {
176
+ child.kill("SIGKILL");
177
+ }
178
+ }
179
+ else {
180
+ child.kill("SIGKILL");
181
+ }
182
+ }, timeoutMs);
183
+ timer.unref?.();
184
+ const finalize = (exitCode, signal) => {
185
+ clearTimeout(timer);
186
+ const duration = Date.now() - started;
187
+ const stdoutBuf = Buffer.concat(stdoutChunks);
188
+ const stderrBuf = Buffer.concat(stderrChunks);
189
+ const stdoutSuffix = stdoutTruncated ? "\n[truncated: stdout cap reached]\n" : "";
190
+ const stderrSuffix = stderrTruncated ? "\n[truncated: stderr cap reached]\n" : "";
191
+ writeFileSync(stdoutPath, Buffer.concat([stdoutBuf, Buffer.from(stdoutSuffix, "utf-8")]));
192
+ writeFileSync(stderrPath, Buffer.concat([stderrBuf, Buffer.from(stderrSuffix, "utf-8")]));
193
+ const digestBody = tail(stdoutBuf, opts.digest_chars);
194
+ const digest = digestBody.length > 0
195
+ ? digestBody
196
+ : timedOut
197
+ ? "[no stdout — timed out]"
198
+ : stderrBuf.length > 0
199
+ ? `[no stdout — tail of stderr]\n${tail(stderrBuf, opts.digest_chars)}`
200
+ : "[no output]";
201
+ const result = {
202
+ id,
203
+ runtime: request.runtime,
204
+ exit_code: exitCode,
205
+ signal,
206
+ timed_out: timedOut,
207
+ duration_ms: duration,
208
+ stdout_bytes: stdoutBytes,
209
+ stderr_bytes: stderrBytes,
210
+ stdout_truncated: stdoutTruncated,
211
+ stderr_truncated: stderrTruncated,
212
+ stdout_path: stdoutPath,
213
+ stderr_path: stderrPath,
214
+ meta_path: metaPath,
215
+ digest,
216
+ };
217
+ writeMeta(metaPath, result, request, now);
218
+ resolveP(result);
219
+ };
220
+ child.on("error", (err) => {
221
+ const message = err instanceof Error ? err.message : String(err);
222
+ const line = `child error: ${message}\n`;
223
+ const remaining = opts.stderr_cap_bytes - stderrBytes;
224
+ if (remaining > 0) {
225
+ const chunk = Buffer.from(line, "utf-8").subarray(0, remaining);
226
+ stderrChunks.push(chunk);
227
+ stderrBytes += chunk.length;
228
+ if (chunk.length < Buffer.byteLength(line, "utf-8"))
229
+ stderrTruncated = true;
230
+ }
231
+ });
232
+ child.on("close", (code, signal) => finalize(code, signal));
233
+ });
234
+ }
235
+ function defaultGenerateId() {
236
+ return randomUUID();
237
+ }
238
+ function writeMeta(path, result, request, now) {
239
+ const meta = {
240
+ id: result.id,
241
+ runtime: result.runtime,
242
+ purpose: request.purpose ?? null,
243
+ script_chars: request.script.length,
244
+ started_at: now.toISOString(),
245
+ finished_at: new Date(now.getTime() + result.duration_ms).toISOString(),
246
+ exit_code: result.exit_code,
247
+ signal: result.signal,
248
+ timed_out: result.timed_out,
249
+ duration_ms: result.duration_ms,
250
+ stdout_bytes: result.stdout_bytes,
251
+ stderr_bytes: result.stderr_bytes,
252
+ stdout_truncated: result.stdout_truncated,
253
+ stderr_truncated: result.stderr_truncated,
254
+ stdout_path: result.stdout_path,
255
+ stderr_path: result.stderr_path,
256
+ };
257
+ writeFileSync(path, `${JSON.stringify(meta, null, 2)}\n`);
258
+ }
@@ -45,6 +45,7 @@ const BASELINE_PATTERNS = [
45
45
  // ── GSD state directory (symlink to external storage) ──
46
46
  ".gsd",
47
47
  ".gsd-id",
48
+ ".mcp.json",
48
49
  ".bg-shell/",
49
50
  // ── OS junk ──
50
51
  ".DS_Store",
@@ -135,7 +135,7 @@ function openRawDb(path) {
135
135
  const Database = providerModule;
136
136
  return new Database(path);
137
137
  }
138
- const SCHEMA_VERSION = 20;
138
+ 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
  }
@@ -234,7 +234,8 @@ function initSchema(db, fileBacked) {
234
234
  superseded_by TEXT DEFAULT NULL,
235
235
  hit_count INTEGER NOT NULL DEFAULT 0,
236
236
  scope TEXT NOT NULL DEFAULT 'project',
237
- tags TEXT NOT NULL DEFAULT '[]'
237
+ tags TEXT NOT NULL DEFAULT '[]',
238
+ structured_fields TEXT DEFAULT NULL
238
239
  )
239
240
  `);
240
241
  db.exec(`
@@ -490,11 +491,6 @@ function initSchema(db, fileBacked) {
490
491
  )
491
492
  `);
492
493
  db.exec("CREATE INDEX IF NOT EXISTS idx_memories_active ON memories(superseded_by)");
493
- db.exec("CREATE INDEX IF NOT EXISTS idx_memories_scope ON memories(scope)");
494
- db.exec("CREATE INDEX IF NOT EXISTS idx_memory_sources_kind ON memory_sources(kind)");
495
- db.exec("CREATE INDEX IF NOT EXISTS idx_memory_sources_scope ON memory_sources(scope)");
496
- db.exec("CREATE INDEX IF NOT EXISTS idx_memory_relations_from ON memory_relations(from_id)");
497
- db.exec("CREATE INDEX IF NOT EXISTS idx_memory_relations_to ON memory_relations(to_id)");
498
494
  db.exec("CREATE INDEX IF NOT EXISTS idx_replan_history_milestone ON replan_history(milestone_id, created_at)");
499
495
  // v13 indexes — hot-path dispatch queries
500
496
  db.exec("CREATE INDEX IF NOT EXISTS idx_tasks_active ON tasks(milestone_id, slice_id, status)");
@@ -510,14 +506,21 @@ function initSchema(db, fileBacked) {
510
506
  db.exec("CREATE INDEX IF NOT EXISTS idx_turn_git_tx_turn ON turn_git_transactions(trace_id, turn_id)");
511
507
  db.exec("CREATE INDEX IF NOT EXISTS idx_audit_events_trace ON audit_events(trace_id, ts)");
512
508
  db.exec("CREATE INDEX IF NOT EXISTS idx_audit_events_turn ON audit_events(trace_id, turn_id, ts)");
513
- // ADR-011 Phase 2 — also created by the v17 migration; fresh installs
514
- // skip migrations so the index must be created here too.
515
- db.exec("CREATE INDEX IF NOT EXISTS idx_tasks_escalation_pending ON tasks(milestone_id, slice_id, escalation_pending)");
516
509
  db.exec(`CREATE VIEW IF NOT EXISTS active_decisions AS SELECT * FROM decisions WHERE superseded_by IS NULL`);
517
510
  db.exec(`CREATE VIEW IF NOT EXISTS active_requirements AS SELECT * FROM requirements WHERE superseded_by IS NULL`);
518
511
  db.exec(`CREATE VIEW IF NOT EXISTS active_memories AS SELECT * FROM memories WHERE superseded_by IS NULL`);
519
512
  const existing = db.prepare("SELECT count(*) as cnt FROM schema_version").get();
520
513
  if (existing && existing["cnt"] === 0) {
514
+ // Fresh install — all tables are created above with the full current schema,
515
+ // so it is safe to create all migration-specific indexes here. For existing
516
+ // databases these indexes are created inside the individual migration guards
517
+ // in migrateSchema() after the corresponding columns have been added.
518
+ db.exec("CREATE INDEX IF NOT EXISTS idx_tasks_escalation_pending ON tasks(milestone_id, slice_id, escalation_pending)");
519
+ db.exec("CREATE INDEX IF NOT EXISTS idx_memories_scope ON memories(scope)");
520
+ db.exec("CREATE INDEX IF NOT EXISTS idx_memory_sources_kind ON memory_sources(kind)");
521
+ db.exec("CREATE INDEX IF NOT EXISTS idx_memory_sources_scope ON memory_sources(scope)");
522
+ db.exec("CREATE INDEX IF NOT EXISTS idx_memory_relations_from ON memory_relations(from_id)");
523
+ db.exec("CREATE INDEX IF NOT EXISTS idx_memory_relations_to ON memory_relations(to_id)");
521
524
  db.prepare("INSERT INTO schema_version (version, applied_at) VALUES (:version, :applied_at)").run({
522
525
  ":version": SCHEMA_VERSION,
523
526
  ":applied_at": new Date().toISOString(),
@@ -842,19 +845,24 @@ function migrateSchema(db) {
842
845
  });
843
846
  }
844
847
  if (currentVersion < 12) {
848
+ // NOTE: The original DDL used COALESCE(task_id, '') in the PRIMARY KEY
849
+ // expression, which is invalid SQLite syntax and causes startup errors on
850
+ // DBs that migrate through v12. The corrected DDL uses
851
+ // task_id TEXT NOT NULL DEFAULT '' with a plain column list PK. DBs that
852
+ // were created with the broken DDL are repaired by the v22 migration below.
845
853
  db.exec(`
846
854
  CREATE TABLE IF NOT EXISTS quality_gates (
847
855
  milestone_id TEXT NOT NULL,
848
856
  slice_id TEXT NOT NULL,
849
857
  gate_id TEXT NOT NULL,
850
858
  scope TEXT NOT NULL DEFAULT 'slice',
851
- task_id TEXT DEFAULT NULL,
859
+ task_id TEXT NOT NULL DEFAULT '',
852
860
  status TEXT NOT NULL DEFAULT 'pending',
853
861
  verdict TEXT NOT NULL DEFAULT '',
854
862
  rationale TEXT NOT NULL DEFAULT '',
855
863
  findings TEXT NOT NULL DEFAULT '',
856
864
  evaluated_at TEXT DEFAULT NULL,
857
- PRIMARY KEY (milestone_id, slice_id, gate_id, COALESCE(task_id, '')),
865
+ PRIMARY KEY (milestone_id, slice_id, gate_id, task_id),
858
866
  FOREIGN KEY (milestone_id, slice_id) REFERENCES slices(milestone_id, id)
859
867
  )
860
868
  `);
@@ -1006,6 +1014,10 @@ function migrateSchema(db) {
1006
1014
  tags TEXT NOT NULL DEFAULT '[]'
1007
1015
  )
1008
1016
  `);
1017
+ // If memory_sources already existed before v18 (created by an earlier
1018
+ // version of initSchema that lacked scope/tags), add the missing columns.
1019
+ ensureColumn(db, "memory_sources", "scope", `ALTER TABLE memory_sources ADD COLUMN scope TEXT NOT NULL DEFAULT 'project'`);
1020
+ ensureColumn(db, "memory_sources", "tags", `ALTER TABLE memory_sources ADD COLUMN tags TEXT NOT NULL DEFAULT '[]'`);
1009
1021
  db.exec("CREATE INDEX IF NOT EXISTS idx_memories_scope ON memories(scope)");
1010
1022
  db.exec("CREATE INDEX IF NOT EXISTS idx_memory_sources_kind ON memory_sources(kind)");
1011
1023
  db.exec("CREATE INDEX IF NOT EXISTS idx_memory_sources_scope ON memory_sources(scope)");
@@ -1059,6 +1071,65 @@ function migrateSchema(db) {
1059
1071
  ":applied_at": new Date().toISOString(),
1060
1072
  });
1061
1073
  }
1074
+ if (currentVersion < 21) {
1075
+ // ADR-013 Step 2: preserve structured fields (gsd_save_decision's
1076
+ // scope/decision/choice/rationale/made_by/revisable) on memories rows so
1077
+ // the eventual decisions->memories cutover does not lose schema fidelity.
1078
+ // Nullable JSON column — existing rows stay NULL until backfilled in Step 5.
1079
+ // Use ensureColumn for race-safety (matches v15-v18 pattern; bare ALTER
1080
+ // throws "duplicate column" on the loser of a concurrent open race even
1081
+ // though the transaction wrapper protects the schema_version row).
1082
+ ensureColumn(db, "memories", "structured_fields", "ALTER TABLE memories ADD COLUMN structured_fields TEXT DEFAULT NULL");
1083
+ db.prepare("INSERT INTO schema_version (version, applied_at) VALUES (:version, :applied_at)").run({
1084
+ ":version": 21,
1085
+ ":applied_at": new Date().toISOString(),
1086
+ });
1087
+ }
1088
+ if (currentVersion < 22) {
1089
+ // v22: Repair quality_gates tables that were created by the broken v12
1090
+ // migration (which used COALESCE(task_id, '') as a PK expression — invalid
1091
+ // SQLite DDL). Those DBs have task_id nullable (dflt_value NULL, notnull 0).
1092
+ // Rebuild the table with the correct schema, migrating existing rows via
1093
+ // COALESCE so no data is lost.
1094
+ const qgInfo = db.prepare("PRAGMA table_info(quality_gates)").all();
1095
+ const taskIdCol = qgInfo.find((r) => r["name"] === "task_id");
1096
+ const needsRepair = taskIdCol && (taskIdCol["notnull"] === 0 || taskIdCol["notnull"] === "0");
1097
+ if (needsRepair) {
1098
+ db.exec(`
1099
+ CREATE TABLE quality_gates_new (
1100
+ milestone_id TEXT NOT NULL,
1101
+ slice_id TEXT NOT NULL,
1102
+ gate_id TEXT NOT NULL,
1103
+ scope TEXT NOT NULL DEFAULT 'slice',
1104
+ task_id TEXT NOT NULL DEFAULT '',
1105
+ status TEXT NOT NULL DEFAULT 'pending',
1106
+ verdict TEXT NOT NULL DEFAULT '',
1107
+ rationale TEXT NOT NULL DEFAULT '',
1108
+ findings TEXT NOT NULL DEFAULT '',
1109
+ evaluated_at TEXT DEFAULT NULL,
1110
+ PRIMARY KEY (milestone_id, slice_id, gate_id, task_id),
1111
+ FOREIGN KEY (milestone_id, slice_id) REFERENCES slices(milestone_id, id)
1112
+ )
1113
+ `);
1114
+ db.exec(`
1115
+ INSERT OR IGNORE INTO quality_gates_new
1116
+ (milestone_id, slice_id, gate_id, scope, task_id, status, verdict, rationale, findings, evaluated_at)
1117
+ SELECT milestone_id, slice_id, gate_id, scope, COALESCE(task_id, ''), status, verdict, rationale, findings, evaluated_at
1118
+ FROM quality_gates
1119
+ `);
1120
+ db.exec("DROP TABLE quality_gates");
1121
+ db.exec("ALTER TABLE quality_gates_new RENAME TO quality_gates");
1122
+ db.exec("CREATE INDEX IF NOT EXISTS idx_quality_gates_pending ON quality_gates(milestone_id, slice_id, status)");
1123
+ }
1124
+ // Ensure scope column exists on quality_gates and assessments (guard
1125
+ // against DBs that somehow lack it after a partial migration).
1126
+ ensureColumn(db, "quality_gates", "scope", "ALTER TABLE quality_gates ADD COLUMN scope TEXT NOT NULL DEFAULT 'slice'");
1127
+ ensureColumn(db, "assessments", "scope", "ALTER TABLE assessments ADD COLUMN scope TEXT NOT NULL DEFAULT ''");
1128
+ db.prepare("INSERT INTO schema_version (version, applied_at) VALUES (:version, :applied_at)").run({
1129
+ ":version": 22,
1130
+ ":applied_at": new Date().toISOString(),
1131
+ });
1132
+ }
1062
1133
  db.exec("COMMIT");
1063
1134
  }
1064
1135
  catch (err) {
@@ -1071,6 +1142,8 @@ let currentPath = null;
1071
1142
  let currentPid = 0;
1072
1143
  let _exitHandlerRegistered = false;
1073
1144
  let _dbOpenAttempted = false;
1145
+ let _lastDbError = null;
1146
+ let _lastDbPhase = null;
1074
1147
  export function getDbProvider() {
1075
1148
  loadProvider();
1076
1149
  return providerName;
@@ -1087,13 +1160,54 @@ export function isDbAvailable() {
1087
1160
  export function wasDbOpenAttempted() {
1088
1161
  return _dbOpenAttempted;
1089
1162
  }
1163
+ export function getDbStatus() {
1164
+ loadProvider();
1165
+ return {
1166
+ available: currentDb !== null,
1167
+ provider: providerName,
1168
+ attempted: _dbOpenAttempted,
1169
+ lastError: _lastDbError,
1170
+ lastPhase: _lastDbPhase,
1171
+ };
1172
+ }
1090
1173
  export function openDatabase(path) {
1091
1174
  _dbOpenAttempted = true;
1092
1175
  if (currentDb && currentPath !== path)
1093
1176
  closeDatabase();
1094
1177
  if (currentDb && currentPath === path)
1095
1178
  return true;
1096
- const rawDb = openRawDb(path);
1179
+ // Reset error state only when a new open attempt is actually going to run.
1180
+ _lastDbError = null;
1181
+ _lastDbPhase = null;
1182
+ let rawDb;
1183
+ let fallbackProvider = null;
1184
+ let fallbackModule = null;
1185
+ try {
1186
+ rawDb = openRawDb(path);
1187
+ }
1188
+ catch (primaryErr) {
1189
+ _lastDbPhase = "open";
1190
+ _lastDbError = primaryErr instanceof Error ? primaryErr : new Error(String(primaryErr));
1191
+ // node:sqlite loaded but failed to open this file — try better-sqlite3 as fallback.
1192
+ if (providerName === "node:sqlite") {
1193
+ try {
1194
+ const mod = _require("better-sqlite3");
1195
+ const Db = (mod && mod.default) ? mod.default : mod;
1196
+ if (typeof Db === "function") {
1197
+ rawDb = new Db(path);
1198
+ fallbackProvider = "better-sqlite3";
1199
+ fallbackModule = Db;
1200
+ _lastDbError = null;
1201
+ _lastDbPhase = null;
1202
+ }
1203
+ }
1204
+ catch {
1205
+ // fallback unavailable; surface original error
1206
+ }
1207
+ }
1208
+ if (!rawDb)
1209
+ throw primaryErr;
1210
+ }
1097
1211
  if (!rawDb)
1098
1212
  return false;
1099
1213
  const adapter = createAdapter(rawDb);
@@ -1111,6 +1225,8 @@ export function openDatabase(path) {
1111
1225
  process.stderr.write("gsd-db: recovered corrupt database via VACUUM\n");
1112
1226
  }
1113
1227
  catch (retryErr) {
1228
+ _lastDbPhase = "vacuum-recovery";
1229
+ _lastDbError = retryErr instanceof Error ? retryErr : new Error(String(retryErr));
1114
1230
  try {
1115
1231
  adapter.close();
1116
1232
  }
@@ -1121,15 +1237,22 @@ export function openDatabase(path) {
1121
1237
  }
1122
1238
  }
1123
1239
  else {
1240
+ _lastDbPhase = "initSchema";
1241
+ _lastDbError = err instanceof Error ? err : new Error(String(err));
1124
1242
  try {
1125
1243
  adapter.close();
1126
1244
  }
1127
1245
  catch (e) {
1128
- logWarning("db", `close after VACUUM failed: ${e.message}`);
1246
+ logWarning("db", `close after initSchema failed: ${e.message}`);
1129
1247
  }
1130
1248
  throw err;
1131
1249
  }
1132
1250
  }
1251
+ // Commit fallback provider switch only after open + schema both succeeded.
1252
+ if (fallbackProvider) {
1253
+ providerName = fallbackProvider;
1254
+ providerModule = fallbackModule;
1255
+ }
1133
1256
  currentDb = adapter;
1134
1257
  currentPath = path;
1135
1258
  currentPid = process.pid;
@@ -1168,8 +1291,12 @@ export function closeDatabase() {
1168
1291
  currentDb = null;
1169
1292
  currentPath = null;
1170
1293
  currentPid = 0;
1171
- _dbOpenAttempted = false;
1172
1294
  }
1295
+ // Reset session-scoped state unconditionally so stale error info from a
1296
+ // failed open doesn't persist into the next open attempt or status check.
1297
+ _dbOpenAttempted = false;
1298
+ _lastDbError = null;
1299
+ _lastDbPhase = null;
1173
1300
  }
1174
1301
  /** Run a full VACUUM — call sparingly (e.g. after milestone completion). */
1175
1302
  export function vacuumDatabase() {
@@ -2269,7 +2396,10 @@ export function reconcileWorktreeDb(mainDbPath, worktreeDbPath) {
2269
2396
  SELECT path, artifact_type, milestone_id, slice_id, task_id, full_content, imported_at
2270
2397
  FROM wt.artifacts
2271
2398
  `).run());
2272
- // Merge milestones — worktree may have updated status/planning fields
2399
+ // Merge milestones — worktree may have updated status/planning fields.
2400
+ // Never downgrade status: complete > active > pre-planning (#4372).
2401
+ // A stale worktree may carry an older 'active' status for a milestone
2402
+ // that the main DB has already marked 'complete'; preserve the higher status.
2273
2403
  merged.milestones = countChanges(adapter.prepare(`
2274
2404
  INSERT OR REPLACE INTO milestones (
2275
2405
  id, title, status, depends_on, created_at, completed_at,
@@ -2277,11 +2407,25 @@ export function reconcileWorktreeDb(mainDbPath, worktreeDbPath) {
2277
2407
  verification_contract, verification_integration, verification_operational, verification_uat,
2278
2408
  definition_of_done, requirement_coverage, boundary_map_markdown
2279
2409
  )
2280
- SELECT id, title, status, depends_on, created_at, completed_at,
2281
- vision, success_criteria, key_risks, proof_strategy,
2282
- verification_contract, verification_integration, verification_operational, verification_uat,
2283
- definition_of_done, requirement_coverage, boundary_map_markdown
2284
- FROM wt.milestones
2410
+ SELECT w.id, w.title,
2411
+ CASE
2412
+ WHEN m.status IN ('complete', 'done') AND w.status NOT IN ('complete', 'done')
2413
+ THEN m.status ELSE w.status
2414
+ END,
2415
+ w.depends_on,
2416
+ CASE
2417
+ WHEN m.status IN ('complete', 'done') AND w.status NOT IN ('complete', 'done')
2418
+ THEN m.created_at ELSE w.created_at
2419
+ END,
2420
+ CASE
2421
+ WHEN m.status IN ('complete', 'done') AND w.status NOT IN ('complete', 'done')
2422
+ THEN m.completed_at ELSE w.completed_at
2423
+ END,
2424
+ w.vision, w.success_criteria, w.key_risks, w.proof_strategy,
2425
+ w.verification_contract, w.verification_integration, w.verification_operational, w.verification_uat,
2426
+ w.definition_of_done, w.requirement_coverage, w.boundary_map_markdown
2427
+ FROM wt.milestones w
2428
+ LEFT JOIN milestones m ON m.id = w.id
2285
2429
  `).run());
2286
2430
  // Merge slices — preserve worktree progress but never downgrade completed status (#2558).
2287
2431
  // ADR-011 Phase 1: carry is_sketch + sketch_scope so reconcile doesn't
@@ -2948,8 +3092,8 @@ export function bulkInsertLegacyHierarchy(payload) {
2948
3092
  export function insertMemoryRow(args) {
2949
3093
  if (!currentDb)
2950
3094
  throw new GSDError(GSD_STALE_STATE, "gsd-db: No database open");
2951
- currentDb.prepare(`INSERT INTO memories (id, category, content, confidence, source_unit_type, source_unit_id, created_at, updated_at, scope, tags)
2952
- VALUES (:id, :category, :content, :confidence, :source_unit_type, :source_unit_id, :created_at, :updated_at, :scope, :tags)`).run({
3095
+ currentDb.prepare(`INSERT INTO memories (id, category, content, confidence, source_unit_type, source_unit_id, created_at, updated_at, scope, tags, structured_fields)
3096
+ VALUES (:id, :category, :content, :confidence, :source_unit_type, :source_unit_id, :created_at, :updated_at, :scope, :tags, :structured_fields)`).run({
2953
3097
  ":id": args.id,
2954
3098
  ":category": args.category,
2955
3099
  ":content": args.content,
@@ -2960,6 +3104,7 @@ export function insertMemoryRow(args) {
2960
3104
  ":updated_at": args.updatedAt,
2961
3105
  ":scope": args.scope ?? "project",
2962
3106
  ":tags": JSON.stringify(args.tags ?? []),
3107
+ ":structured_fields": args.structuredFields == null ? null : JSON.stringify(args.structuredFields),
2963
3108
  });
2964
3109
  }
2965
3110
  export function insertMemorySourceRow(args) {