gsd-pi 2.76.0-dev.82e249f7b → 2.76.0-dev.97f5583d9

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 (271) hide show
  1. package/dist/claude-cli-check.js +32 -3
  2. package/dist/mcp-server.d.ts +7 -0
  3. package/dist/mcp-server.js +35 -1
  4. package/dist/resource-loader.d.ts +1 -1
  5. package/dist/resource-loader.js +2 -8
  6. package/dist/resources/extensions/claude-code-cli/readiness.js +4 -3
  7. package/dist/resources/extensions/claude-code-cli/stream-adapter.js +77 -17
  8. package/dist/resources/extensions/gsd/auto/phases.js +42 -1
  9. package/dist/resources/extensions/gsd/auto/run-unit.js +27 -0
  10. package/dist/resources/extensions/gsd/auto/session.js +12 -0
  11. package/dist/resources/extensions/gsd/auto-dispatch.js +16 -3
  12. package/dist/resources/extensions/gsd/auto-model-selection.js +1 -1
  13. package/dist/resources/extensions/gsd/auto-post-unit.js +25 -2
  14. package/dist/resources/extensions/gsd/auto-prompts.js +14 -0
  15. package/dist/resources/extensions/gsd/auto-recovery.js +13 -0
  16. package/dist/resources/extensions/gsd/auto-start.js +27 -18
  17. package/dist/resources/extensions/gsd/auto-worktree.js +51 -53
  18. package/dist/resources/extensions/gsd/auto.js +55 -27
  19. package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +17 -1
  20. package/dist/resources/extensions/gsd/bootstrap/db-tools.js +39 -9
  21. package/dist/resources/extensions/gsd/bootstrap/exec-tools.js +93 -0
  22. package/dist/resources/extensions/gsd/bootstrap/register-extension.js +2 -0
  23. package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +51 -5
  24. package/dist/resources/extensions/gsd/bootstrap/write-gate.js +34 -2
  25. package/dist/resources/extensions/gsd/clean-root-preflight.js +93 -0
  26. package/dist/resources/extensions/gsd/commands-prefs-wizard.js +968 -23
  27. package/dist/resources/extensions/gsd/compaction-snapshot.js +121 -0
  28. package/dist/resources/extensions/gsd/error-classifier.js +10 -3
  29. package/dist/resources/extensions/gsd/exec-history.js +120 -0
  30. package/dist/resources/extensions/gsd/exec-sandbox.js +258 -0
  31. package/dist/resources/extensions/gsd/gsd-db.js +115 -7
  32. package/dist/resources/extensions/gsd/guided-flow.js +189 -0
  33. package/dist/resources/extensions/gsd/health-widget.js +4 -1
  34. package/dist/resources/extensions/gsd/init-wizard.js +15 -1
  35. package/dist/resources/extensions/gsd/key-manager.js +6 -0
  36. package/dist/resources/extensions/gsd/model-router.js +36 -3
  37. package/dist/resources/extensions/gsd/pre-execution-checks.js +35 -9
  38. package/dist/resources/extensions/gsd/preferences-types.js +9 -0
  39. package/dist/resources/extensions/gsd/preferences-validation.js +83 -0
  40. package/dist/resources/extensions/gsd/preferences.js +17 -17
  41. package/dist/resources/extensions/gsd/prompts/discuss-headless.md +8 -0
  42. package/dist/resources/extensions/gsd/prompts/discuss.md +29 -2
  43. package/dist/resources/extensions/gsd/prompts/parallel-research-slices.md +5 -2
  44. package/dist/resources/extensions/gsd/safety/evidence-collector.js +96 -0
  45. package/dist/resources/extensions/gsd/safety/file-change-validator.js +13 -5
  46. package/dist/resources/extensions/gsd/safety/safety-harness.js +5 -1
  47. package/dist/resources/extensions/gsd/token-counter.js +22 -5
  48. package/dist/resources/extensions/gsd/tools/exec-search-tool.js +59 -0
  49. package/dist/resources/extensions/gsd/tools/exec-tool.js +126 -0
  50. package/dist/resources/extensions/gsd/tools/resume-tool.js +23 -0
  51. package/dist/resources/extensions/gsd/uok/plan-v2.js +20 -3
  52. package/dist/resources/extensions/gsd/workflow-mcp.js +3 -0
  53. package/dist/resources/skills/verify-before-complete/SKILL.md +2 -1
  54. package/dist/resources/skills/write-docs/SKILL.md +2 -1
  55. package/dist/tsconfig.extensions.tsbuildinfo +1 -1
  56. package/dist/web/standalone/.next/BUILD_ID +1 -1
  57. package/dist/web/standalone/.next/app-path-routes-manifest.json +10 -10
  58. package/dist/web/standalone/.next/build-manifest.json +2 -2
  59. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  60. package/dist/web/standalone/.next/required-server-files.json +1 -1
  61. package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
  62. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  63. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  64. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  65. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  66. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  67. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  68. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  69. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  70. package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
  71. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
  72. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  73. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
  74. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  75. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  76. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  77. package/dist/web/standalone/.next/server/app/index.html +1 -1
  78. package/dist/web/standalone/.next/server/app/index.rsc +1 -1
  79. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
  80. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +1 -1
  81. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  82. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
  83. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  84. package/dist/web/standalone/.next/server/app-paths-manifest.json +10 -10
  85. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  86. package/dist/web/standalone/.next/server/middleware-manifest.json +5 -5
  87. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  88. package/dist/web/standalone/.next/server/pages/500.html +1 -1
  89. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  90. package/dist/web/standalone/server.js +1 -1
  91. package/package.json +1 -1
  92. package/packages/mcp-server/dist/remote-questions.d.ts +45 -0
  93. package/packages/mcp-server/dist/remote-questions.d.ts.map +1 -0
  94. package/packages/mcp-server/dist/remote-questions.js +732 -0
  95. package/packages/mcp-server/dist/remote-questions.js.map +1 -0
  96. package/packages/mcp-server/dist/server.d.ts +7 -0
  97. package/packages/mcp-server/dist/server.d.ts.map +1 -1
  98. package/packages/mcp-server/dist/server.js +41 -4
  99. package/packages/mcp-server/dist/server.js.map +1 -1
  100. package/packages/mcp-server/dist/workflow-tools.d.ts.map +1 -1
  101. package/packages/mcp-server/dist/workflow-tools.js +64 -25
  102. package/packages/mcp-server/dist/workflow-tools.js.map +1 -1
  103. package/packages/mcp-server/package.json +2 -1
  104. package/packages/mcp-server/src/mcp-server.test.ts +30 -0
  105. package/packages/mcp-server/src/remote-questions.test.ts +294 -0
  106. package/packages/mcp-server/src/remote-questions.ts +916 -0
  107. package/packages/mcp-server/src/server.ts +62 -10
  108. package/packages/mcp-server/src/workflow-tools.test.ts +146 -1
  109. package/packages/mcp-server/src/workflow-tools.ts +84 -43
  110. package/packages/mcp-server/tsconfig.test.json +19 -0
  111. package/packages/mcp-server/tsconfig.tsbuildinfo +1 -1
  112. package/packages/pi-ai/dist/providers/anthropic-auth.test.js +1 -1
  113. package/packages/pi-ai/dist/providers/anthropic-auth.test.js.map +1 -1
  114. package/packages/pi-ai/dist/providers/anthropic-shared.d.ts.map +1 -1
  115. package/packages/pi-ai/dist/providers/anthropic-shared.js +27 -4
  116. package/packages/pi-ai/dist/providers/anthropic-shared.js.map +1 -1
  117. package/packages/pi-ai/dist/providers/anthropic.d.ts.map +1 -1
  118. package/packages/pi-ai/dist/providers/anthropic.js +8 -3
  119. package/packages/pi-ai/dist/providers/anthropic.js.map +1 -1
  120. package/packages/pi-ai/dist/providers/minimax-tool-name.test.d.ts +2 -0
  121. package/packages/pi-ai/dist/providers/minimax-tool-name.test.d.ts.map +1 -0
  122. package/packages/pi-ai/dist/providers/minimax-tool-name.test.js +80 -0
  123. package/packages/pi-ai/dist/providers/minimax-tool-name.test.js.map +1 -0
  124. package/packages/pi-ai/dist/providers/simple-options.d.ts +10 -0
  125. package/packages/pi-ai/dist/providers/simple-options.d.ts.map +1 -1
  126. package/packages/pi-ai/dist/providers/simple-options.js +16 -1
  127. package/packages/pi-ai/dist/providers/simple-options.js.map +1 -1
  128. package/packages/pi-ai/src/providers/anthropic-auth.test.ts +1 -1
  129. package/packages/pi-ai/src/providers/anthropic-shared.ts +26 -5
  130. package/packages/pi-ai/src/providers/anthropic.ts +9 -3
  131. package/packages/pi-ai/src/providers/minimax-tool-name.test.ts +98 -0
  132. package/packages/pi-ai/src/providers/simple-options.ts +17 -1
  133. package/packages/pi-ai/tsconfig.tsbuildinfo +1 -1
  134. package/packages/pi-coding-agent/dist/core/model-registry-custom-caps.test.d.ts +2 -0
  135. package/packages/pi-coding-agent/dist/core/model-registry-custom-caps.test.d.ts.map +1 -0
  136. package/packages/pi-coding-agent/dist/core/model-registry-custom-caps.test.js +203 -0
  137. package/packages/pi-coding-agent/dist/core/model-registry-custom-caps.test.js.map +1 -0
  138. package/packages/pi-coding-agent/dist/core/model-registry.d.ts.map +1 -1
  139. package/packages/pi-coding-agent/dist/core/model-registry.js +14 -0
  140. package/packages/pi-coding-agent/dist/core/model-registry.js.map +1 -1
  141. package/packages/pi-coding-agent/dist/core/redact-secrets.d.ts +2 -0
  142. package/packages/pi-coding-agent/dist/core/redact-secrets.d.ts.map +1 -0
  143. package/packages/pi-coding-agent/dist/core/redact-secrets.js +49 -0
  144. package/packages/pi-coding-agent/dist/core/redact-secrets.js.map +1 -0
  145. package/packages/pi-coding-agent/dist/core/redact-secrets.test.d.ts +2 -0
  146. package/packages/pi-coding-agent/dist/core/redact-secrets.test.d.ts.map +1 -0
  147. package/packages/pi-coding-agent/dist/core/redact-secrets.test.js +67 -0
  148. package/packages/pi-coding-agent/dist/core/redact-secrets.test.js.map +1 -0
  149. package/packages/pi-coding-agent/dist/core/session-manager.d.ts.map +1 -1
  150. package/packages/pi-coding-agent/dist/core/session-manager.js +9 -5
  151. package/packages/pi-coding-agent/dist/core/session-manager.js.map +1 -1
  152. package/packages/pi-coding-agent/dist/core/session-manager.test.js +25 -1
  153. package/packages/pi-coding-agent/dist/core/session-manager.test.js.map +1 -1
  154. package/packages/pi-coding-agent/dist/modes/interactive/components/chat-frame.d.ts +1 -1
  155. package/packages/pi-coding-agent/dist/modes/interactive/components/chat-frame.d.ts.map +1 -1
  156. package/packages/pi-coding-agent/dist/modes/interactive/components/chat-frame.js +5 -4
  157. package/packages/pi-coding-agent/dist/modes/interactive/components/chat-frame.js.map +1 -1
  158. package/packages/pi-coding-agent/dist/modes/interactive/components/skill-invocation-message.d.ts +7 -6
  159. package/packages/pi-coding-agent/dist/modes/interactive/components/skill-invocation-message.d.ts.map +1 -1
  160. package/packages/pi-coding-agent/dist/modes/interactive/components/skill-invocation-message.js +29 -21
  161. package/packages/pi-coding-agent/dist/modes/interactive/components/skill-invocation-message.js.map +1 -1
  162. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  163. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js +13 -1
  164. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
  165. package/packages/pi-coding-agent/src/core/model-registry-custom-caps.test.ts +245 -0
  166. package/packages/pi-coding-agent/src/core/model-registry.ts +16 -0
  167. package/packages/pi-coding-agent/src/core/redact-secrets.test.ts +86 -0
  168. package/packages/pi-coding-agent/src/core/redact-secrets.ts +58 -0
  169. package/packages/pi-coding-agent/src/core/session-manager.test.ts +36 -1
  170. package/packages/pi-coding-agent/src/core/session-manager.ts +9 -5
  171. package/packages/pi-coding-agent/src/modes/interactive/components/chat-frame.ts +6 -6
  172. package/packages/pi-coding-agent/src/modes/interactive/components/skill-invocation-message.ts +36 -22
  173. package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +13 -1
  174. package/packages/pi-coding-agent/tsconfig.tsbuildinfo +1 -1
  175. package/src/resources/extensions/claude-code-cli/readiness.ts +4 -3
  176. package/src/resources/extensions/claude-code-cli/stream-adapter.ts +78 -17
  177. package/src/resources/extensions/claude-code-cli/tests/stream-adapter.test.ts +149 -5
  178. package/src/resources/extensions/gsd/auto/loop-deps.ts +13 -0
  179. package/src/resources/extensions/gsd/auto/phases.ts +66 -1
  180. package/src/resources/extensions/gsd/auto/run-unit.ts +29 -0
  181. package/src/resources/extensions/gsd/auto/session.ts +22 -0
  182. package/src/resources/extensions/gsd/auto-dispatch.ts +16 -3
  183. package/src/resources/extensions/gsd/auto-model-selection.ts +1 -1
  184. package/src/resources/extensions/gsd/auto-post-unit.ts +29 -3
  185. package/src/resources/extensions/gsd/auto-prompts.ts +28 -1
  186. package/src/resources/extensions/gsd/auto-recovery.ts +15 -0
  187. package/src/resources/extensions/gsd/auto-start.ts +29 -19
  188. package/src/resources/extensions/gsd/auto-worktree.ts +62 -63
  189. package/src/resources/extensions/gsd/auto.ts +58 -27
  190. package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +23 -1
  191. package/src/resources/extensions/gsd/bootstrap/db-tools.ts +40 -9
  192. package/src/resources/extensions/gsd/bootstrap/exec-tools.ts +109 -0
  193. package/src/resources/extensions/gsd/bootstrap/register-extension.ts +2 -0
  194. package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +53 -5
  195. package/src/resources/extensions/gsd/bootstrap/write-gate.ts +35 -2
  196. package/src/resources/extensions/gsd/clean-root-preflight.ts +111 -0
  197. package/src/resources/extensions/gsd/commands-prefs-wizard.ts +898 -32
  198. package/src/resources/extensions/gsd/compaction-snapshot.ts +165 -0
  199. package/src/resources/extensions/gsd/error-classifier.ts +10 -3
  200. package/src/resources/extensions/gsd/exec-history.ts +153 -0
  201. package/src/resources/extensions/gsd/exec-sandbox.ts +326 -0
  202. package/src/resources/extensions/gsd/gsd-db.ts +122 -7
  203. package/src/resources/extensions/gsd/guided-flow.ts +221 -0
  204. package/src/resources/extensions/gsd/health-widget.ts +3 -1
  205. package/src/resources/extensions/gsd/init-wizard.ts +15 -1
  206. package/src/resources/extensions/gsd/journal.ts +2 -1
  207. package/src/resources/extensions/gsd/key-manager.ts +6 -0
  208. package/src/resources/extensions/gsd/model-router.ts +42 -1
  209. package/src/resources/extensions/gsd/pre-execution-checks.ts +36 -10
  210. package/src/resources/extensions/gsd/preferences-types.ts +46 -0
  211. package/src/resources/extensions/gsd/preferences-validation.ts +79 -0
  212. package/src/resources/extensions/gsd/preferences.ts +17 -17
  213. package/src/resources/extensions/gsd/prompts/discuss-headless.md +8 -0
  214. package/src/resources/extensions/gsd/prompts/discuss.md +29 -2
  215. package/src/resources/extensions/gsd/prompts/parallel-research-slices.md +5 -2
  216. package/src/resources/extensions/gsd/safety/evidence-collector.ts +119 -0
  217. package/src/resources/extensions/gsd/safety/file-change-validator.ts +17 -4
  218. package/src/resources/extensions/gsd/safety/safety-harness.ts +9 -0
  219. package/src/resources/extensions/gsd/tests/auto-loop.test.ts +119 -1
  220. package/src/resources/extensions/gsd/tests/auto-paused-session-validation.test.ts +12 -0
  221. package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +49 -0
  222. package/src/resources/extensions/gsd/tests/clean-root-preflight.test.ts +186 -0
  223. package/src/resources/extensions/gsd/tests/compaction-snapshot.test.ts +123 -0
  224. package/src/resources/extensions/gsd/tests/complete-slice.test.ts +2 -2
  225. package/src/resources/extensions/gsd/tests/complete-task.test.ts +2 -2
  226. package/src/resources/extensions/gsd/tests/custom-engine-loop-integration.test.ts +2 -0
  227. package/src/resources/extensions/gsd/tests/doctor-providers.test.ts +31 -0
  228. package/src/resources/extensions/gsd/tests/double-merge-guard.test.ts +1 -1
  229. package/src/resources/extensions/gsd/tests/ensure-db-open.test.ts +1 -1
  230. package/src/resources/extensions/gsd/tests/escalation.test.ts +1 -1
  231. package/src/resources/extensions/gsd/tests/exec-history.test.ts +124 -0
  232. package/src/resources/extensions/gsd/tests/exec-sandbox.test.ts +210 -0
  233. package/src/resources/extensions/gsd/tests/file-change-validator.test.ts +58 -0
  234. package/src/resources/extensions/gsd/tests/gsd-db.test.ts +152 -1
  235. package/src/resources/extensions/gsd/tests/init-wizard.test.ts +27 -0
  236. package/src/resources/extensions/gsd/tests/isolation-none-branch-guard.test.ts +1 -1
  237. package/src/resources/extensions/gsd/tests/issue-4540-regressions.test.ts +288 -0
  238. package/src/resources/extensions/gsd/tests/journal-integration.test.ts +2 -0
  239. package/src/resources/extensions/gsd/tests/key-manager.test.ts +7 -0
  240. package/src/resources/extensions/gsd/tests/md-importer.test.ts +1 -1
  241. package/src/resources/extensions/gsd/tests/memory-store.test.ts +2 -2
  242. package/src/resources/extensions/gsd/tests/parallel-research-dispatch.test.ts +19 -0
  243. package/src/resources/extensions/gsd/tests/pre-exec-backtick-strip.test.ts +14 -0
  244. package/src/resources/extensions/gsd/tests/pre-exec-gate-loop.test.ts +272 -0
  245. package/src/resources/extensions/gsd/tests/pre-execution-checks.test.ts +234 -0
  246. package/src/resources/extensions/gsd/tests/preferences.test.ts +110 -0
  247. package/src/resources/extensions/gsd/tests/prefs-wizard-coverage.test.ts +44 -0
  248. package/src/resources/extensions/gsd/tests/provider-errors.test.ts +48 -0
  249. package/src/resources/extensions/gsd/tests/ready-phrase-no-files-4573.test.ts +388 -0
  250. package/src/resources/extensions/gsd/tests/restore-tools-after-discuss.test.ts +9 -3
  251. package/src/resources/extensions/gsd/tests/safety-harness-false-positives.test.ts +205 -0
  252. package/src/resources/extensions/gsd/tests/save-gate-result-render.test.ts +95 -0
  253. package/src/resources/extensions/gsd/tests/session-start-footer.test.ts +32 -40
  254. package/src/resources/extensions/gsd/tests/stash-queued-context-files.test.ts +56 -0
  255. package/src/resources/extensions/gsd/tests/token-counter.test.ts +105 -1
  256. package/src/resources/extensions/gsd/tests/tool-compatibility.test.ts +107 -0
  257. package/src/resources/extensions/gsd/tests/uok-plan-v2-wiring.test.ts +23 -0
  258. package/src/resources/extensions/gsd/tests/workflow-tool-executors.test.ts +65 -2
  259. package/src/resources/extensions/gsd/tests/write-gate.test.ts +64 -0
  260. package/src/resources/extensions/gsd/tests/zombie-gsd-state.test.ts +3 -1
  261. package/src/resources/extensions/gsd/token-counter.ts +22 -5
  262. package/src/resources/extensions/gsd/tools/exec-search-tool.ts +81 -0
  263. package/src/resources/extensions/gsd/tools/exec-tool.ts +183 -0
  264. package/src/resources/extensions/gsd/tools/resume-tool.ts +40 -0
  265. package/src/resources/extensions/gsd/uok/plan-v2.ts +26 -3
  266. package/src/resources/extensions/gsd/workflow-logger.ts +3 -1
  267. package/src/resources/extensions/gsd/workflow-mcp.ts +3 -0
  268. package/src/resources/skills/verify-before-complete/SKILL.md +2 -1
  269. package/src/resources/skills/write-docs/SKILL.md +2 -1
  270. /package/dist/web/standalone/.next/static/{ecSsu49rxxcpbNmVP4mLD → lLdDRDspgYzfz0bJAmUSz}/_buildManifest.js +0 -0
  271. /package/dist/web/standalone/.next/static/{ecSsu49rxxcpbNmVP4mLD → lLdDRDspgYzfz0bJAmUSz}/_ssgManifest.js +0 -0
@@ -55,7 +55,7 @@ import { hasPendingCaptures, loadPendingCaptures, revertExecutorResolvedCaptures
55
55
  import { debugLog } from "./debug-logger.js";
56
56
  import { runSafely } from "./auto-utils.js";
57
57
  import type { AutoSession, SidecarItem } from "./auto/session.js";
58
- import { getEvidence } from "./safety/evidence-collector.js";
58
+ import { getEvidence, clearEvidenceFromDisk } from "./safety/evidence-collector.js";
59
59
  import { validateFileChanges } from "./safety/file-change-validator.js";
60
60
  // crossReferenceEvidence available for future use when verification_evidence is stored in DB
61
61
  // import { crossReferenceEvidence, type ClaimedEvidence } from "./safety/evidence-cross-ref.js";
@@ -107,7 +107,6 @@ import {
107
107
  updateProgressWidget as _updateProgressWidget,
108
108
  updateSliceProgressCache,
109
109
  unitVerb,
110
- hideFooter,
111
110
  describeNextUnit,
112
111
  } from "./auto-dashboard.js";
113
112
  import { existsSync, unlinkSync } from "node:fs";
@@ -654,7 +653,7 @@ export async function postUnitPreVerification(pctx: PostUnitContext, opts?: PreV
654
653
  if (taskRow) {
655
654
  const expectedOutput = taskRow.expected_output ?? [];
656
655
  const plannedFiles = taskRow.files ?? [];
657
- const audit = validateFileChanges(s.basePath, expectedOutput, plannedFiles);
656
+ const audit = validateFileChanges(s.basePath, expectedOutput, plannedFiles, safetyConfig.file_change_allowlist);
658
657
  if (audit && audit.violations.length > 0) {
659
658
  const warnings = audit.violations.filter(v => v.severity === "warning");
660
659
  for (const v of warnings) {
@@ -712,6 +711,16 @@ export async function postUnitPreVerification(pctx: PostUnitContext, opts?: PreV
712
711
  debugLog("postUnit", { phase: "safety-content-validation", error: String(e) });
713
712
  }
714
713
  }
714
+
715
+ // Clear persisted evidence file now that post-unit processing is complete
716
+ // (Bug #4385 — prevents stale evidence from affecting retries of same unit ID).
717
+ if (safetyConfig.evidence_collection && s.currentUnit.type === "execute-task" && sMid && sSid && sTid) {
718
+ try {
719
+ clearEvidenceFromDisk(s.basePath, sMid, sSid, sTid);
720
+ } catch (e) {
721
+ debugLog("postUnit", { phase: "safety-evidence-clear", error: String(e) });
722
+ }
723
+ }
715
724
  }
716
725
  } catch (e) {
717
726
  debugLog("postUnit", { phase: "safety-harness", error: String(e) });
@@ -1134,6 +1143,15 @@ export async function postUnitPostVerification(pctx: PostUnitContext): Promise<"
1134
1143
  `Pre-execution checks failed: ${blockingCount} blocking issue${blockingCount === 1 ? "" : "s"} found\n${details}${suffix}${evidenceNote}`,
1135
1144
  "error",
1136
1145
  );
1146
+ // Persist failure context so the next plan-slice re-dispatch can inject
1147
+ // it into the prompt and break the infinite loop (#4551).
1148
+ s.lastPreExecFailure = {
1149
+ unitId: currentUnit.id,
1150
+ blockingFindings: blockingChecks.map(
1151
+ c => `[${c.category}] ${c.target}: ${c.message}`,
1152
+ ),
1153
+ verdictExcerpt: `status=${result.status}; ${blockingCount} blocking issue${blockingCount === 1 ? "" : "s"} detected`,
1154
+ };
1137
1155
  preExecPauseNeeded = true;
1138
1156
  } else if (result.status === "warn") {
1139
1157
  ctx.ui.notify(
@@ -1142,6 +1160,14 @@ export async function postUnitPostVerification(pctx: PostUnitContext): Promise<"
1142
1160
  );
1143
1161
  // Strict mode: treat warnings as blocking
1144
1162
  if (prefs?.enhanced_verification_strict === true) {
1163
+ const warnChecks = result.checks.filter(c => !c.passed);
1164
+ s.lastPreExecFailure = {
1165
+ unitId: currentUnit.id,
1166
+ blockingFindings: warnChecks.map(
1167
+ c => `[${c.category}] ${c.target}: ${c.message}`,
1168
+ ),
1169
+ verdictExcerpt: `status=${result.status} (strict mode); ${warnChecks.length} warning${warnChecks.length === 1 ? "" : "s"} treated as blocking`,
1170
+ };
1145
1171
  preExecPauseNeeded = true;
1146
1172
  }
1147
1173
  }
@@ -1380,7 +1380,18 @@ async function renderSlicePrompt(options: {
1380
1380
 
1381
1381
  export async function buildPlanSlicePrompt(
1382
1382
  mid: string, _midTitle: string, sid: string, sTitle: string, base: string, level?: InlineLevel,
1383
- options?: { softScopeHint?: string; sessionContextWindow?: number; modelRegistry?: MinimalModelRegistry },
1383
+ options?: {
1384
+ softScopeHint?: string;
1385
+ sessionContextWindow?: number;
1386
+ modelRegistry?: MinimalModelRegistry;
1387
+ /** Failure context from a prior pre-exec gate run (#4551). When present, a
1388
+ * "Fix these specific issues" section is appended so the LLM addresses the
1389
+ * exact problems instead of producing an identical plan that fails again. */
1390
+ priorPreExecFailure?: {
1391
+ blockingFindings: string[];
1392
+ verdictExcerpt: string;
1393
+ };
1394
+ },
1384
1395
  ): Promise<string> {
1385
1396
  const prependBlocks: string[] = [];
1386
1397
  // ADR-011: when the refining-phase dispatch rule gracefully downgrades to
@@ -1393,6 +1404,22 @@ export async function buildPlanSlicePrompt(
1393
1404
  `This scope was captured during an earlier progressive-planning pass that was later disabled. Treat it as context only — you may plan beyond it if the work genuinely requires more scope. Do NOT treat this as a hard boundary.`,
1394
1405
  );
1395
1406
  }
1407
+ // #4551: inject pre-exec failure context so the re-dispatched plan-slice
1408
+ // addresses the exact blocked references rather than reproducing the same plan.
1409
+ if (options?.priorPreExecFailure) {
1410
+ const { blockingFindings, verdictExcerpt } = options.priorPreExecFailure;
1411
+ const findingsList = blockingFindings.length > 0
1412
+ ? blockingFindings.map(f => `- ${f}`).join("\n")
1413
+ : "- (no specific findings recorded)";
1414
+ prependBlocks.push(
1415
+ `## Fix these specific issues from the prior pre-exec check\n\n` +
1416
+ `The previous plan-slice attempt was blocked by pre-execution validation.\n` +
1417
+ `Gate verdict: ${verdictExcerpt}\n\n` +
1418
+ `Blocked references that must be resolved in this plan:\n${findingsList}\n\n` +
1419
+ `Revise the plan so that every reference listed above is satisfied before execution begins. ` +
1420
+ `Do not reproduce the same file paths, package names, or task ordering that caused these failures.`,
1421
+ );
1422
+ }
1396
1423
  return renderSlicePrompt({
1397
1424
  mid, sid, sTitle, base,
1398
1425
  level: level ?? resolveInlineLevel(),
@@ -268,11 +268,26 @@ export function verifyExpectedArtifact(
268
268
  // RESEARCH file. Without this, resolveExpectedArtifactPath returns null and
269
269
  // the retry/escalation machinery silently re-dispatches forever.
270
270
  //
271
+ // #4068: Also treat a PARALLEL-BLOCKER placeholder as a terminal completion
272
+ // so that timeout-recovery can write the blocker, have verifyExpectedArtifact
273
+ // return true, and let the dispatch loop advance past this unit. Without
274
+ // this, the blocker is written but verification still returns false, the unit
275
+ // is never cleared from unitDispatchCount, and on the next iteration the
276
+ // dispatch rule (which correctly skips parallel-research when PARALLEL-BLOCKER
277
+ // exists) returns null — leaving the loop stuck re-deriving indefinitely.
278
+ //
271
279
  // NOTE: this predicate mirrors the dispatch rule at
272
280
  // auto-dispatch.ts parallel-research-slices — keep the two in sync.
273
281
  if (unitType === "research-slice" && unitId.endsWith("/parallel-research")) {
274
282
  const { milestone: mid } = parseUnitId(unitId);
275
283
  if (!mid) return false;
284
+
285
+ // #4068: PARALLEL-BLOCKER written by timeout-recovery is a terminal state.
286
+ const blockerPath = resolveExpectedArtifactPath(unitType, unitId, base);
287
+ if (blockerPath && existsSync(blockerPath)) {
288
+ return true;
289
+ }
290
+
276
291
  const roadmapFile = resolveMilestoneFile(base, mid, "ROADMAP");
277
292
  if (!roadmapFile || !existsSync(roadmapFile)) {
278
293
  logWarning("recovery", `verify-fail ${unitType} ${unitId}: roadmap missing`);
@@ -60,8 +60,8 @@ import { initRoutingHistory } from "./routing-history.js";
60
60
  import { restoreHookState, resetHookState } from "./post-unit-hooks.js";
61
61
  import { resetProactiveHealing, setLevelChangeCallback } from "./doctor-proactive.js";
62
62
  import { snapshotSkills } from "./skill-discovery.js";
63
- import { isDbAvailable, getMilestone, openDatabase } from "./gsd-db.js";
64
- import { hideFooter } from "./auto-dashboard.js";
63
+ import { isDbAvailable, getMilestone, openDatabase, getDbStatus } from "./gsd-db.js";
64
+
65
65
  import {
66
66
  debugLog,
67
67
  enableDebug,
@@ -92,7 +92,7 @@ import type { WorktreeResolver } from "./worktree-resolver.js";
92
92
  import { getSessionModelOverride } from "./session-model-override.js";
93
93
 
94
94
  export interface BootstrapDeps {
95
- shouldUseWorktreeIsolation: () => boolean;
95
+ shouldUseWorktreeIsolation: (basePath?: string) => boolean;
96
96
  registerSigtermHandler: (basePath: string) => void;
97
97
  lockBase: () => string;
98
98
  buildResolver: () => WorktreeResolver;
@@ -343,7 +343,7 @@ export async function bootstrapAutoSession(
343
343
  const hasLocalGit = existsSync(join(base, ".git"));
344
344
  if (!hasLocalGit || isInheritedRepo(base)) {
345
345
  const mainBranch =
346
- loadEffectiveGSDPreferences()?.preferences?.git?.main_branch || "main";
346
+ loadEffectiveGSDPreferences(base)?.preferences?.git?.main_branch || "main";
347
347
  nativeInit(base, mainBranch);
348
348
  }
349
349
 
@@ -361,7 +361,7 @@ export async function bootstrapAutoSession(
361
361
  // Ensure .gitignore has baseline patterns.
362
362
  // ensureGitignore checks for git-tracked .gsd/ files and skips the
363
363
  // ".gsd" pattern if the project intentionally tracks .gsd/ in git.
364
- const gitPrefs = loadEffectiveGSDPreferences()?.preferences?.git;
364
+ const gitPrefs = loadEffectiveGSDPreferences(base)?.preferences?.git;
365
365
  const manageGitignore = gitPrefs?.manage_gitignore;
366
366
  ensureGitignore(base, { manageGitignore });
367
367
  if (manageGitignore !== false) untrackRuntimeFiles(base);
@@ -390,7 +390,7 @@ export async function bootstrapAutoSession(
390
390
  // Initialize GitServiceImpl
391
391
  s.gitService = new GitServiceImpl(
392
392
  s.basePath,
393
- loadEffectiveGSDPreferences()?.preferences?.git ?? {},
393
+ loadEffectiveGSDPreferences(base)?.preferences?.git ?? {},
394
394
  );
395
395
 
396
396
  // ── Debug mode ──
@@ -434,7 +434,7 @@ export async function bootstrapAutoSession(
434
434
  // was lost due to session ending between completion and teardown.
435
435
  // Must run after DB open and before worktree entry.
436
436
  try {
437
- const auditResult = auditOrphanedMilestoneBranches(base, getIsolationMode());
437
+ const auditResult = auditOrphanedMilestoneBranches(base, getIsolationMode(base));
438
438
  for (const msg of auditResult.recovered) {
439
439
  ctx.ui.notify(`Orphan audit: ${msg}`, "info");
440
440
  }
@@ -454,7 +454,7 @@ export async function bootstrapAutoSession(
454
454
  // Stale worktree state recovery (#654)
455
455
  if (
456
456
  state.activeMilestone &&
457
- shouldUseWorktreeIsolation() &&
457
+ shouldUseWorktreeIsolation(base) &&
458
458
  !detectWorktreeName(base)
459
459
  ) {
460
460
  const wtPath = getAutoWorktreePath(base, state.activeMilestone.id);
@@ -472,7 +472,7 @@ export async function bootstrapAutoSession(
472
472
  if (
473
473
  state.activeMilestone &&
474
474
  (state.phase === "pre-planning" || state.phase === "complete") &&
475
- getIsolationMode() !== "none" &&
475
+ getIsolationMode(base) !== "none" &&
476
476
  !detectWorktreeName(base) &&
477
477
  !base.includes(`${pathSep}.gsd${pathSep}worktrees${pathSep}`)
478
478
  ) {
@@ -676,7 +676,7 @@ export async function bootstrapAutoSession(
676
676
 
677
677
  // Capture integration branch
678
678
  if (s.currentMilestoneId) {
679
- if (getIsolationMode() !== "none") {
679
+ if (getIsolationMode(base) !== "none") {
680
680
  captureIntegrationBranch(base, s.currentMilestoneId);
681
681
  }
682
682
  setActiveMilestoneId(base, s.currentMilestoneId);
@@ -685,7 +685,7 @@ export async function bootstrapAutoSession(
685
685
  // Guard against stale milestone branch when isolation:none (#3613).
686
686
  // A prior session with isolation:branch/worktree may have left HEAD on
687
687
  // milestone/<MID>. Auto-checkout back to the integration branch.
688
- if (getIsolationMode() === "none" && nativeIsRepo(base)) {
688
+ if (getIsolationMode(base) === "none" && nativeIsRepo(base)) {
689
689
  try {
690
690
  const currentBranch = nativeGetCurrentBranch(base);
691
691
  if (currentBranch.startsWith("milestone/")) {
@@ -716,7 +716,7 @@ export async function bootstrapAutoSession(
716
716
 
717
717
  if (
718
718
  s.currentMilestoneId &&
719
- getIsolationMode() !== "none" &&
719
+ getIsolationMode(base) !== "none" &&
720
720
  !detectWorktreeName(base) &&
721
721
  !isUnderGsdWorktrees(base)
722
722
  ) {
@@ -762,9 +762,22 @@ export async function bootstrapAutoSession(
762
762
  // call returns "db_unavailable", triggering artifact-retry which
763
763
  // re-dispatches the same task — producing an infinite loop (#2419).
764
764
  if (existsSync(gsdDbPath) && !isDbAvailable()) {
765
+ const dbStatus = getDbStatus();
766
+ const phaseHint = dbStatus.lastPhase === "open"
767
+ ? "The database file could not be opened"
768
+ : dbStatus.lastPhase === "initSchema"
769
+ ? "The database schema could not be initialized"
770
+ : dbStatus.lastPhase === "vacuum-recovery"
771
+ ? "Corruption recovery (VACUUM) failed"
772
+ : dbStatus.attempted
773
+ ? "The database could not be opened (phase unknown)"
774
+ : "The database provider could not be loaded";
775
+ const errorDetail = dbStatus.lastError ? ` (${dbStatus.lastError.message})` : "";
776
+ const providerHint = dbStatus.provider
777
+ ? ` Provider: ${dbStatus.provider}.`
778
+ : " No SQLite provider available — check Node >= 22 or install better-sqlite3.";
765
779
  ctx.ui.notify(
766
- "SQLite database exists but failed to open. Auto-mode cannot proceed without a working database provider. " +
767
- "Check for corrupt gsd.db or missing native SQLite bindings.",
780
+ `SQLite database exists but failed to open: ${gsdDbPath}. ${phaseHint}${errorDetail}.${providerHint}`,
768
781
  "error",
769
782
  );
770
783
  return releaseLockAndReturn();
@@ -806,14 +819,11 @@ export async function bootstrapAutoSession(
806
819
  }
807
820
 
808
821
  // Snapshot installed skills
809
- if (resolveSkillDiscoveryMode() !== "off") {
822
+ if (resolveSkillDiscoveryMode(base) !== "off") {
810
823
  snapshotSkills();
811
824
  }
812
825
 
813
826
  ctx.ui.setStatus("gsd-auto", s.stepMode ? "next" : "auto");
814
- ctx.ui.setFooter(hideFooter);
815
- // Hide gsd-health during AUTO — gsd-progress is the single source of truth
816
- // for last-commit / cost / health signal while auto is running.
817
827
  ctx.ui.setWidget("gsd-health", undefined);
818
828
  const modeLabel = s.stepMode ? "Step-mode" : "Auto-mode";
819
829
  const pendingCount = (state.registry ?? []).filter(
@@ -840,7 +850,7 @@ export async function bootstrapAutoSession(
840
850
  // FlatRateContext used by selectAndApplyModel so user-declared
841
851
  // flat-rate providers and externalCli auto-detection are respected.
842
852
  const { isFlatRateProvider, buildFlatRateContext } = await import("./auto-model-selection.js");
843
- const bannerPrefs = loadEffectiveGSDPreferences()?.preferences;
853
+ const bannerPrefs = loadEffectiveGSDPreferences(base)?.preferences;
844
854
  const effectiveProvider = s.autoModeStartModel?.provider ?? ctx.model?.provider;
845
855
  const effectivelyEnabled = routingConfig.enabled
846
856
  && (routingConfig.allow_flat_rate_providers
@@ -238,14 +238,6 @@ function clearProjectRootStateFiles(basePath: string, milestoneId: string): void
238
238
  }
239
239
  }
240
240
 
241
- function isProjectGsdSymlink(basePath: string): boolean {
242
- try {
243
- return lstatSyncFn(join(basePath, ".gsd")).isSymbolicLink();
244
- } catch {
245
- return false;
246
- }
247
- }
248
-
249
241
  // ─── Build Artifact Auto-Resolve ─────────────────────────────────────────────
250
242
 
251
243
  /** Patterns for machine-generated build artifacts that can be safely
@@ -1664,54 +1656,15 @@ export function mergeMilestoneToMain(
1664
1656
  }
1665
1657
  }
1666
1658
 
1667
- // 7. Stash any pre-existing dirty files so the squash merge is not
1668
- // blocked by unrelated local changes (#2151). clearProjectRootStateFiles
1669
- // only removes untracked .gsd/ files; tracked dirty files elsewhere (e.g.
1670
- // .planning/work-state.json with stash conflict markers) are invisible to
1671
- // that cleanup but will cause `git merge --squash` to reject.
1672
- let stashed = false;
1673
- try {
1674
- const status = execFileSync("git", ["status", "--porcelain"], {
1675
- cwd: originalBasePath_,
1676
- stdio: ["ignore", "pipe", "pipe"],
1677
- encoding: "utf-8",
1678
- }).trim();
1679
- if (status) {
1680
- // Use --include-untracked to stash untracked files that would block
1681
- // the squash merge, but EXCLUDE .gsd/milestones/ (#2505).
1682
- // --include-untracked without exclusion sweeps queued milestone
1683
- // CONTEXT files into the stash. If stash pop later fails, those files
1684
- // are permanently trapped in the stash entry and lost on the next
1685
- // stash push or drop.
1686
- //
1687
- // When `.gsd` itself is a symlink, Git rejects pathspecs below it
1688
- // ("beyond a symbolic link"). In that layout, exclude the whole symlink
1689
- // and keep stashing real project files that could block the merge.
1690
- const stashPathspecs = isProjectGsdSymlink(originalBasePath_)
1691
- ? [".", ":(exclude).gsd"]
1692
- : [":(exclude).gsd/milestones"];
1693
- execFileSync(
1694
- "git",
1695
- [
1696
- "stash", "push", "--include-untracked",
1697
- "-m", `gsd: pre-merge stash for ${milestoneId}`,
1698
- "--", ...stashPathspecs,
1699
- ],
1700
- { cwd: originalBasePath_, stdio: ["ignore", "pipe", "pipe"], encoding: "utf-8" },
1701
- );
1702
- stashed = true;
1703
- }
1704
- } catch (err) {
1705
- // Stash failure is non-fatal — proceed without stash and let the merge
1706
- // report the dirty tree if it fails.
1707
- logWarning("worktree", `git stash failed: ${err instanceof Error ? err.message : String(err)}`);
1708
- }
1709
-
1710
- // 7a. Shelter queued milestone directories before the squash merge (#2505).
1659
+ // 7. Shelter queued milestone directories before the squash merge (#2505).
1711
1660
  // The milestone branch may contain copies of queued milestone dirs (via
1712
1661
  // copyPlanningArtifacts), so `git merge --squash` rejects when those same
1713
1662
  // files exist as untracked in the working tree. Temporarily move them to
1714
1663
  // a backup location, then restore after the merge+commit.
1664
+ //
1665
+ // MUST run BEFORE the pre-merge stash (step 7a) so `--include-untracked`
1666
+ // does not sweep queued CONTEXT files into the stash. If stash pop later
1667
+ // fails, files trapped inside the stash are permanently lost (#2505).
1715
1668
  const milestonesDir = join(gsdRoot(originalBasePath_), "milestones");
1716
1669
  const shelterDir = join(gsdRoot(originalBasePath_), ".milestone-shelter");
1717
1670
  const shelteredDirs: string[] = [];
@@ -1759,6 +1712,35 @@ export function mergeMilestoneToMain(
1759
1712
  logWarning("worktree", `milestone shelter operation failed: ${err instanceof Error ? err.message : String(err)}`);
1760
1713
  }
1761
1714
 
1715
+ // 7a. Stash pre-existing dirty files so the squash merge is not blocked by
1716
+ // unrelated local changes (#2151). Includes untracked files to handle
1717
+ // locally-added files that conflict with tracked files on the milestone
1718
+ // branch. Passing NO pathspec lets git skip gitignored paths silently;
1719
+ // adding an explicit pathspec trips a `git add`-style fatal on ignored
1720
+ // entries (e.g. a gitignored `.gsd` symlink under ADR-002) (#4573).
1721
+ // Queued CONTEXT files under `.gsd/milestones/*` are already sheltered
1722
+ // in step 7 above, so they won't be swept into the stash.
1723
+ let stashed = false;
1724
+ try {
1725
+ const status = execFileSync("git", ["status", "--porcelain"], {
1726
+ cwd: originalBasePath_,
1727
+ stdio: ["ignore", "pipe", "pipe"],
1728
+ encoding: "utf-8",
1729
+ }).trim();
1730
+ if (status) {
1731
+ execFileSync(
1732
+ "git",
1733
+ ["stash", "push", "--include-untracked", "-m", `gsd: pre-merge stash for ${milestoneId}`],
1734
+ { cwd: originalBasePath_, stdio: ["ignore", "pipe", "pipe"], encoding: "utf-8" },
1735
+ );
1736
+ stashed = true;
1737
+ }
1738
+ } catch (err) {
1739
+ // Stash failure is non-fatal — proceed without stash and let the merge
1740
+ // report the dirty tree if it fails.
1741
+ logWarning("worktree", `git stash failed: ${err instanceof Error ? err.message : String(err)}`);
1742
+ }
1743
+
1762
1744
  // 7b. Clean up stale merge state before attempting squash merge (#2912).
1763
1745
  // A leftover MERGE_HEAD (from a previous failed merge, libgit2 native path,
1764
1746
  // or interrupted operation) causes `git merge --squash` to refuse with
@@ -2012,21 +1994,38 @@ export function mergeMilestoneToMain(
2012
1994
  // When a milestone only produced .gsd/ metadata (summaries, roadmaps) but no
2013
1995
  // real code, the user sees "milestone complete" but nothing changed in their
2014
1996
  // codebase. Surface this so the caller can warn the user.
1997
+ //
1998
+ // Bug #4385 fix: use `git diff-tree --root` instead of `git diff HEAD~1 HEAD`.
1999
+ // `HEAD~1` does not exist on initial commits and is unreliable on shallow clones
2000
+ // and merge commits. `diff-tree --root` handles all three cases correctly.
2001
+ // The empty-tree hash (4b825dc…) is the universal fallback for refs that don't exist.
2002
+ const GIT_EMPTY_TREE = "4b825dc642cb6eb9a060e54bf8d69288fbee4904";
2015
2003
  let codeFilesChanged = false;
2016
2004
  if (!nothingToCommit) {
2017
2005
  try {
2018
- const mergedFiles = nativeDiffNumstat(
2019
- originalBasePath_,
2020
- "HEAD~1",
2021
- "HEAD",
2022
- );
2023
- codeFilesChanged = mergedFiles.some(
2024
- (entry) => !entry.path.startsWith(".gsd/"),
2025
- );
2006
+ const diffTreeOutput = execFileSync(
2007
+ "git",
2008
+ ["diff-tree", "--root", "--no-commit-id", "-r", "--name-only", "HEAD"],
2009
+ { cwd: originalBasePath_, stdio: ["ignore", "pipe", "pipe"], encoding: "utf-8" },
2010
+ ).trim();
2011
+ const mergedFiles = diffTreeOutput ? diffTreeOutput.split("\n").filter(Boolean) : [];
2012
+ codeFilesChanged = mergedFiles.some((f) => !f.startsWith(".gsd/"));
2026
2013
  } catch (e) {
2027
- // If HEAD~1 doesn't exist (first commit), assume code was changed
2028
- logWarning("worktree", `diff numstat failed (assuming code changed): ${(e as Error).message}`);
2029
- codeFilesChanged = true;
2014
+ // diff-tree failed (e.g. unborn HEAD in a brand-new repo) fall back to
2015
+ // comparing against the empty tree so initial-commit repos still report changes.
2016
+ try {
2017
+ const fallbackOutput = execFileSync(
2018
+ "git",
2019
+ ["diff", "--name-only", GIT_EMPTY_TREE, "HEAD"],
2020
+ { cwd: originalBasePath_, stdio: ["ignore", "pipe", "pipe"], encoding: "utf-8" },
2021
+ ).trim();
2022
+ const fallbackFiles = fallbackOutput ? fallbackOutput.split("\n").filter(Boolean) : [];
2023
+ codeFilesChanged = fallbackFiles.some((f) => !f.startsWith(".gsd/"));
2024
+ } catch {
2025
+ // Truly unable to determine — assume code was changed to avoid silent data loss
2026
+ logWarning("worktree", `diff-tree and empty-tree fallback both failed (assuming code changed): ${(e as Error).message}`);
2027
+ codeFilesChanged = true;
2028
+ }
2030
2029
  }
2031
2030
  }
2032
2031