@opengsd/gsd-pi 1.4.0 → 1.5.0-dev.4fb2d460

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 (657) hide show
  1. package/README.md +11 -11
  2. package/dist/onboarding.js +11 -0
  3. package/dist/resources/.managed-resources-content-hash +1 -1
  4. package/dist/resources/GSD-WORKFLOW.md +20 -25
  5. package/dist/resources/extensions/ask-user-questions.js +1 -1
  6. package/dist/resources/extensions/claude-code-cli/stream-adapter.js +118 -53
  7. package/dist/resources/extensions/cursor-cli/index.js +16 -0
  8. package/dist/resources/extensions/cursor-cli/models.js +63 -0
  9. package/dist/resources/extensions/cursor-cli/package.json +11 -0
  10. package/dist/resources/extensions/cursor-cli/readiness.js +128 -0
  11. package/dist/resources/extensions/cursor-cli/stream-adapter.js +353 -0
  12. package/dist/resources/extensions/gsd/activity-log.js +4 -1
  13. package/dist/resources/extensions/gsd/artifact-verification.js +25 -9
  14. package/dist/resources/extensions/gsd/auto/closeout.js +137 -42
  15. package/dist/resources/extensions/gsd/auto/finalize.js +9 -0
  16. package/dist/resources/extensions/gsd/auto/orchestrator.js +4 -3
  17. package/dist/resources/extensions/gsd/auto/pre-dispatch.js +6 -3
  18. package/dist/resources/extensions/gsd/auto/run-unit.js +5 -2
  19. package/dist/resources/extensions/gsd/auto/schedule-wakeup.js +3 -0
  20. package/dist/resources/extensions/gsd/auto/unit-phase.js +5 -9
  21. package/dist/resources/extensions/gsd/auto-artifact-paths.js +12 -3
  22. package/dist/resources/extensions/gsd/auto-direct-dispatch.js +11 -7
  23. package/dist/resources/extensions/gsd/auto-dispatch.js +31 -7
  24. package/dist/resources/extensions/gsd/auto-model-selection.js +36 -18
  25. package/dist/resources/extensions/gsd/auto-prompts.js +76 -2
  26. package/dist/resources/extensions/gsd/auto-recovery.js +50 -6
  27. package/dist/resources/extensions/gsd/auto-start.js +8 -6
  28. package/dist/resources/extensions/gsd/auto-timeout-recovery.js +4 -0
  29. package/dist/resources/extensions/gsd/auto-worktree-branch-lifecycle.js +189 -0
  30. package/dist/resources/extensions/gsd/auto-worktree-cleanup.js +133 -0
  31. package/dist/resources/extensions/gsd/auto-worktree-conflict-auto-resolve.js +35 -0
  32. package/dist/resources/extensions/gsd/auto-worktree-creation.js +130 -0
  33. package/dist/resources/extensions/gsd/auto-worktree-entry.js +118 -0
  34. package/dist/resources/extensions/gsd/auto-worktree-merge-already-merged.js +98 -0
  35. package/dist/resources/extensions/gsd/auto-worktree-merge-branch-head.js +52 -0
  36. package/dist/resources/extensions/gsd/auto-worktree-merge-cleanup.js +87 -0
  37. package/dist/resources/extensions/gsd/auto-worktree-merge-code-changes.js +46 -0
  38. package/dist/resources/extensions/gsd/auto-worktree-merge-db-ready.js +68 -0
  39. package/dist/resources/extensions/gsd/auto-worktree-merge-integration-branch.js +51 -0
  40. package/dist/resources/extensions/gsd/auto-worktree-merge-message.js +106 -0
  41. package/dist/resources/extensions/gsd/auto-worktree-merge-pre-teardown.js +64 -0
  42. package/dist/resources/extensions/gsd/auto-worktree-merge-stash.js +168 -0
  43. package/dist/resources/extensions/gsd/auto-worktree-merge.js +302 -0
  44. package/dist/resources/extensions/gsd/auto-worktree-milestone-shelter.js +119 -0
  45. package/dist/resources/extensions/gsd/auto-worktree-path-resolution.js +5 -0
  46. package/dist/resources/extensions/gsd/auto-worktree-path-utils.js +5 -0
  47. package/dist/resources/extensions/gsd/auto-worktree-resource-version.js +41 -0
  48. package/dist/resources/extensions/gsd/auto-worktree-runtime-cleanup.js +99 -0
  49. package/dist/resources/extensions/gsd/auto-worktree-session-registry.js +57 -0
  50. package/dist/resources/extensions/gsd/auto-worktree-sync.js +249 -0
  51. package/dist/resources/extensions/gsd/auto-worktree-teardown.js +120 -0
  52. package/dist/resources/extensions/gsd/auto-worktree.js +20 -2046
  53. package/dist/resources/extensions/gsd/auto.js +31 -5
  54. package/dist/resources/extensions/gsd/bootstrap/db-tools.js +3 -0
  55. package/dist/resources/extensions/gsd/bootstrap/dynamic-tools.js +1 -1
  56. package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +134 -7
  57. package/dist/resources/extensions/gsd/bootstrap/schedule-wakeup-tool.js +58 -9
  58. package/dist/resources/extensions/gsd/bootstrap/system-context.js +1 -1
  59. package/dist/resources/extensions/gsd/bootstrap/tool-call-loop-guard.js +194 -28
  60. package/dist/resources/extensions/gsd/bootstrap/write-gate.js +14 -1
  61. package/dist/resources/extensions/gsd/codebase-generator.js +164 -20
  62. package/dist/resources/extensions/gsd/commands/handlers/core.js +40 -4
  63. package/dist/resources/extensions/gsd/commands-handlers.js +1 -1
  64. package/dist/resources/extensions/gsd/commands-prefs-wizard.js +153 -1
  65. package/dist/resources/extensions/gsd/commands-workflow-templates.js +3 -3
  66. package/dist/resources/extensions/gsd/commands-worktree.js +11 -2
  67. package/dist/resources/extensions/gsd/db/queries.js +48 -9
  68. package/dist/resources/extensions/gsd/db/writers/cascades.js +20 -2
  69. package/dist/resources/extensions/gsd/discussion-handoff.js +8 -3
  70. package/dist/resources/extensions/gsd/docs/preferences-reference.md +8 -2
  71. package/dist/resources/extensions/gsd/doctor-engine-checks.js +292 -18
  72. package/dist/resources/extensions/gsd/doctor-providers.js +38 -10
  73. package/dist/resources/extensions/gsd/doctor.js +93 -3
  74. package/dist/resources/extensions/gsd/exec-sandbox.js +6 -2
  75. package/dist/resources/extensions/gsd/flat-phase-migration.js +106 -26
  76. package/dist/resources/extensions/gsd/forensics.js +1 -1
  77. package/dist/resources/extensions/gsd/git-conflict-resolve.js +2 -2
  78. package/dist/resources/extensions/gsd/git-service.js +59 -18
  79. package/dist/resources/extensions/gsd/gsd-db.js +75 -11
  80. package/dist/resources/extensions/gsd/guidance.js +1 -0
  81. package/dist/resources/extensions/gsd/guided-flow.js +62 -19
  82. package/dist/resources/extensions/gsd/key-manager.js +1 -0
  83. package/dist/resources/extensions/gsd/markdown-renderer.js +40 -11
  84. package/dist/resources/extensions/gsd/md-importer.js +89 -23
  85. package/dist/resources/extensions/gsd/migrate-external.js +24 -7
  86. package/dist/resources/extensions/gsd/migration-auto-check.js +30 -3
  87. package/dist/resources/extensions/gsd/milestone-merge-transaction.js +14 -3
  88. package/dist/resources/extensions/gsd/milestone-settlement.js +1 -1
  89. package/dist/resources/extensions/gsd/parallel-merge.js +1 -1
  90. package/dist/resources/extensions/gsd/parallel-orchestrator.js +3 -1
  91. package/dist/resources/extensions/gsd/paths.js +17 -3
  92. package/dist/resources/extensions/gsd/preferences-diagnostics.js +24 -1
  93. package/dist/resources/extensions/gsd/preferences-models.js +6 -4
  94. package/dist/resources/extensions/gsd/preferences-skills.js +10 -16
  95. package/dist/resources/extensions/gsd/preferences-types.js +1 -0
  96. package/dist/resources/extensions/gsd/preferences-validation.js +107 -2
  97. package/dist/resources/extensions/gsd/preferences.js +49 -2
  98. package/dist/resources/extensions/gsd/prompts/plan-slice.md +4 -2
  99. package/dist/resources/extensions/gsd/prompts/system.md +6 -6
  100. package/dist/resources/extensions/gsd/quick.js +12 -3
  101. package/dist/resources/extensions/gsd/redact-secrets.js +37 -0
  102. package/dist/resources/extensions/gsd/repo-identity.js +16 -0
  103. package/dist/resources/extensions/gsd/repository-registry.js +6 -1
  104. package/dist/resources/extensions/gsd/root-write-leak-guard.js +4 -2
  105. package/dist/resources/extensions/gsd/safe-fs.js +23 -2
  106. package/dist/resources/extensions/gsd/skill-discovery.js +36 -23
  107. package/dist/resources/extensions/gsd/skills/gsd-headless/SKILL.md +7 -9
  108. package/dist/resources/extensions/gsd/skills/gsd-headless/references/commands.md +1 -0
  109. package/dist/resources/extensions/gsd/slice-parallel-orchestrator.js +2 -1
  110. package/dist/resources/extensions/gsd/state/derive/from-db.js +88 -153
  111. package/dist/resources/extensions/gsd/tool-contract.js +14 -0
  112. package/dist/resources/extensions/gsd/tools/plan-task.js +76 -8
  113. package/dist/resources/extensions/gsd/tools/reopen-slice.js +5 -0
  114. package/dist/resources/extensions/gsd/tools/reopen-task.js +13 -5
  115. package/dist/resources/extensions/gsd/tools/workflow-tool-executors.js +40 -0
  116. package/dist/resources/extensions/gsd/unit-context-manifest.js +5 -4
  117. package/dist/resources/extensions/gsd/unit-registry.js +37 -2
  118. package/dist/resources/extensions/gsd/unit-runtime.js +21 -0
  119. package/dist/resources/extensions/gsd/unmerged-milestone-guard.js +1 -1
  120. package/dist/resources/extensions/gsd/validation-block-guard.js +2 -1
  121. package/dist/resources/extensions/gsd/workspace-git-preflight.js +2 -2
  122. package/dist/resources/extensions/gsd/workspace.js +26 -8
  123. package/dist/resources/extensions/gsd/worktree-command.js +1 -1
  124. package/dist/resources/extensions/gsd/worktree-lifecycle.js +81 -14
  125. package/dist/resources/extensions/gsd/worktree-manager.js +97 -4
  126. package/dist/resources/extensions/gsd/worktree-reentry.js +2 -1
  127. package/dist/resources/extensions/shared/interview-ui.js +62 -9
  128. package/dist/tsconfig.extensions.tsbuildinfo +1 -1
  129. package/dist/web/standalone/.next/BUILD_ID +1 -1
  130. package/dist/web/standalone/.next/app-path-routes-manifest.json +9 -9
  131. package/dist/web/standalone/.next/build-manifest.json +3 -3
  132. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  133. package/dist/web/standalone/.next/required-server-files.json +3 -3
  134. package/dist/web/standalone/.next/server/app/_global-error/page.js +3 -3
  135. package/dist/web/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
  136. package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
  137. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  138. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  139. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  140. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  141. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  142. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  143. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  144. package/dist/web/standalone/.next/server/app/_not-found/page.js +2 -2
  145. package/dist/web/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  146. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  147. package/dist/web/standalone/.next/server/app/_not-found.rsc +3 -3
  148. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +3 -3
  149. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  150. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +3 -3
  151. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  152. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  153. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  154. package/dist/web/standalone/.next/server/app/api/boot/route.js +1 -1
  155. package/dist/web/standalone/.next/server/app/api/boot/route_client-reference-manifest.js +1 -1
  156. package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route.js +1 -1
  157. package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route_client-reference-manifest.js +1 -1
  158. package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route.js +1 -1
  159. package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route_client-reference-manifest.js +1 -1
  160. package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route.js +2 -2
  161. package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route_client-reference-manifest.js +1 -1
  162. package/dist/web/standalone/.next/server/app/api/browse-directories/route.js +1 -1
  163. package/dist/web/standalone/.next/server/app/api/browse-directories/route_client-reference-manifest.js +1 -1
  164. package/dist/web/standalone/.next/server/app/api/captures/route.js +1 -1
  165. package/dist/web/standalone/.next/server/app/api/captures/route_client-reference-manifest.js +1 -1
  166. package/dist/web/standalone/.next/server/app/api/cleanup/route.js +1 -1
  167. package/dist/web/standalone/.next/server/app/api/cleanup/route_client-reference-manifest.js +1 -1
  168. package/dist/web/standalone/.next/server/app/api/dev-mode/route.js +1 -1
  169. package/dist/web/standalone/.next/server/app/api/dev-mode/route_client-reference-manifest.js +1 -1
  170. package/dist/web/standalone/.next/server/app/api/doctor/route.js +1 -1
  171. package/dist/web/standalone/.next/server/app/api/doctor/route_client-reference-manifest.js +1 -1
  172. package/dist/web/standalone/.next/server/app/api/experimental/route.js +2 -2
  173. package/dist/web/standalone/.next/server/app/api/experimental/route_client-reference-manifest.js +1 -1
  174. package/dist/web/standalone/.next/server/app/api/export-data/route.js +1 -1
  175. package/dist/web/standalone/.next/server/app/api/export-data/route_client-reference-manifest.js +1 -1
  176. package/dist/web/standalone/.next/server/app/api/files/route.js +1 -1
  177. package/dist/web/standalone/.next/server/app/api/files/route_client-reference-manifest.js +1 -1
  178. package/dist/web/standalone/.next/server/app/api/forensics/route.js +1 -1
  179. package/dist/web/standalone/.next/server/app/api/forensics/route_client-reference-manifest.js +1 -1
  180. package/dist/web/standalone/.next/server/app/api/git/route.js +1 -1
  181. package/dist/web/standalone/.next/server/app/api/git/route_client-reference-manifest.js +1 -1
  182. package/dist/web/standalone/.next/server/app/api/history/route.js +1 -1
  183. package/dist/web/standalone/.next/server/app/api/history/route_client-reference-manifest.js +1 -1
  184. package/dist/web/standalone/.next/server/app/api/hooks/route.js +1 -1
  185. package/dist/web/standalone/.next/server/app/api/hooks/route_client-reference-manifest.js +1 -1
  186. package/dist/web/standalone/.next/server/app/api/inspect/route.js +1 -1
  187. package/dist/web/standalone/.next/server/app/api/inspect/route_client-reference-manifest.js +1 -1
  188. package/dist/web/standalone/.next/server/app/api/knowledge/route.js +1 -1
  189. package/dist/web/standalone/.next/server/app/api/knowledge/route_client-reference-manifest.js +1 -1
  190. package/dist/web/standalone/.next/server/app/api/live-state/route.js +1 -1
  191. package/dist/web/standalone/.next/server/app/api/live-state/route_client-reference-manifest.js +1 -1
  192. package/dist/web/standalone/.next/server/app/api/mcp-connections/route.js +1 -1
  193. package/dist/web/standalone/.next/server/app/api/mcp-connections/route_client-reference-manifest.js +1 -1
  194. package/dist/web/standalone/.next/server/app/api/notifications/route.js +2 -2
  195. package/dist/web/standalone/.next/server/app/api/notifications/route_client-reference-manifest.js +1 -1
  196. package/dist/web/standalone/.next/server/app/api/onboarding/route.js +1 -1
  197. package/dist/web/standalone/.next/server/app/api/onboarding/route_client-reference-manifest.js +1 -1
  198. package/dist/web/standalone/.next/server/app/api/preferences/route.js +1 -1
  199. package/dist/web/standalone/.next/server/app/api/preferences/route_client-reference-manifest.js +1 -1
  200. package/dist/web/standalone/.next/server/app/api/projects/route.js +1 -1
  201. package/dist/web/standalone/.next/server/app/api/projects/route_client-reference-manifest.js +1 -1
  202. package/dist/web/standalone/.next/server/app/api/recovery/route.js +1 -1
  203. package/dist/web/standalone/.next/server/app/api/recovery/route_client-reference-manifest.js +1 -1
  204. package/dist/web/standalone/.next/server/app/api/remote-questions/route.js +2 -2
  205. package/dist/web/standalone/.next/server/app/api/remote-questions/route_client-reference-manifest.js +1 -1
  206. package/dist/web/standalone/.next/server/app/api/session/browser/route.js +1 -1
  207. package/dist/web/standalone/.next/server/app/api/session/browser/route_client-reference-manifest.js +1 -1
  208. package/dist/web/standalone/.next/server/app/api/session/command/route.js +1 -1
  209. package/dist/web/standalone/.next/server/app/api/session/command/route_client-reference-manifest.js +1 -1
  210. package/dist/web/standalone/.next/server/app/api/session/events/route.js +2 -2
  211. package/dist/web/standalone/.next/server/app/api/session/events/route_client-reference-manifest.js +1 -1
  212. package/dist/web/standalone/.next/server/app/api/session/manage/route.js +1 -1
  213. package/dist/web/standalone/.next/server/app/api/session/manage/route_client-reference-manifest.js +1 -1
  214. package/dist/web/standalone/.next/server/app/api/settings-data/route.js +1 -1
  215. package/dist/web/standalone/.next/server/app/api/settings-data/route_client-reference-manifest.js +1 -1
  216. package/dist/web/standalone/.next/server/app/api/shutdown/route.js +1 -1
  217. package/dist/web/standalone/.next/server/app/api/shutdown/route_client-reference-manifest.js +1 -1
  218. package/dist/web/standalone/.next/server/app/api/skill-health/route.js +1 -1
  219. package/dist/web/standalone/.next/server/app/api/skill-health/route_client-reference-manifest.js +1 -1
  220. package/dist/web/standalone/.next/server/app/api/steer/route.js +1 -1
  221. package/dist/web/standalone/.next/server/app/api/steer/route_client-reference-manifest.js +1 -1
  222. package/dist/web/standalone/.next/server/app/api/switch-root/route.js +1 -1
  223. package/dist/web/standalone/.next/server/app/api/switch-root/route_client-reference-manifest.js +1 -1
  224. package/dist/web/standalone/.next/server/app/api/terminal/input/route.js +1 -1
  225. package/dist/web/standalone/.next/server/app/api/terminal/input/route_client-reference-manifest.js +1 -1
  226. package/dist/web/standalone/.next/server/app/api/terminal/resize/route.js +2 -2
  227. package/dist/web/standalone/.next/server/app/api/terminal/resize/route_client-reference-manifest.js +1 -1
  228. package/dist/web/standalone/.next/server/app/api/terminal/sessions/route.js +1 -1
  229. package/dist/web/standalone/.next/server/app/api/terminal/sessions/route_client-reference-manifest.js +1 -1
  230. package/dist/web/standalone/.next/server/app/api/terminal/stream/route.js +4 -4
  231. package/dist/web/standalone/.next/server/app/api/terminal/stream/route_client-reference-manifest.js +1 -1
  232. package/dist/web/standalone/.next/server/app/api/terminal/upload/route.js +1 -1
  233. package/dist/web/standalone/.next/server/app/api/terminal/upload/route_client-reference-manifest.js +1 -1
  234. package/dist/web/standalone/.next/server/app/api/undo/route.js +1 -1
  235. package/dist/web/standalone/.next/server/app/api/undo/route_client-reference-manifest.js +1 -1
  236. package/dist/web/standalone/.next/server/app/api/update/route.js +1 -1
  237. package/dist/web/standalone/.next/server/app/api/update/route_client-reference-manifest.js +1 -1
  238. package/dist/web/standalone/.next/server/app/api/visualizer/route.js +1 -1
  239. package/dist/web/standalone/.next/server/app/api/visualizer/route_client-reference-manifest.js +1 -1
  240. package/dist/web/standalone/.next/server/app/index.html +1 -1
  241. package/dist/web/standalone/.next/server/app/index.rsc +4 -4
  242. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
  243. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +4 -4
  244. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  245. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +3 -3
  246. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  247. package/dist/web/standalone/.next/server/app/page.js +2 -2
  248. package/dist/web/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
  249. package/dist/web/standalone/.next/server/app-paths-manifest.json +9 -9
  250. package/dist/web/standalone/.next/server/chunks/2842.js +4 -4
  251. package/dist/web/standalone/.next/server/chunks/8357.js +2 -2
  252. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  253. package/dist/web/standalone/.next/server/middleware.js +3 -3
  254. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  255. package/dist/web/standalone/.next/server/pages/500.html +1 -1
  256. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  257. package/dist/web/standalone/.next/static/chunks/app/_not-found/page-a6fb1847f67f167c.js +1 -0
  258. package/dist/web/standalone/.next/static/chunks/app/{layout-b35cbfff38aaf4cf.js → layout-4ae2d68984392bbf.js} +1 -1
  259. package/dist/web/standalone/.next/static/chunks/app/page-72a856634ad14c10.js +1 -0
  260. package/dist/web/standalone/.next/static/chunks/{main-app-590a74400e35f685.js → main-app-90d1d8d5e5d2dc6b.js} +1 -1
  261. package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/global-error-1115d46ac61b9823.js +1 -0
  262. package/dist/web/standalone/node_modules/@gsd/native/package.json +1 -1
  263. package/dist/web/standalone/node_modules/node-pty/build/Makefile +2 -2
  264. package/dist/web/standalone/node_modules/node-pty/build/Release/pty.node +0 -0
  265. package/dist/web/standalone/node_modules/node-pty/build/pty.target.mk +14 -14
  266. package/dist/web/standalone/server.js +1 -1
  267. package/dist/wizard.d.ts +8 -0
  268. package/dist/wizard.js +8 -1
  269. package/integrations/hermes/CONTEXT.md +47 -0
  270. package/integrations/hermes/README.md +21 -0
  271. package/integrations/hermes/__init__.py +31 -0
  272. package/integrations/hermes/docs/issue-1162-grilling.md +197 -0
  273. package/integrations/hermes/docs/setup.md +4 -0
  274. package/integrations/hermes/open_gsd_hermes/commands.py +141 -0
  275. package/integrations/hermes/open_gsd_hermes/config.py +2 -0
  276. package/integrations/hermes/open_gsd_hermes/gsd_client.py +591 -39
  277. package/integrations/hermes/open_gsd_hermes/notifications.py +10 -1
  278. package/integrations/hermes/plugin.yaml +4 -0
  279. package/integrations/hermes/tests/test_config.py +6 -0
  280. package/integrations/hermes/tests/test_directory_loader.py +37 -0
  281. package/integrations/hermes/tests/test_gsd_client_cache.py +3 -0
  282. package/integrations/hermes/tests/test_gsd_client_execute.py +35 -0
  283. package/integrations/hermes/tests/test_gsd_client_process_cwd.py +22 -0
  284. package/integrations/hermes/tests/test_gsd_client_timeout.py +98 -0
  285. package/integrations/hermes/tests/test_milestone_client.py +447 -0
  286. package/integrations/hermes/tests/test_new_milestone_command.py +313 -0
  287. package/integrations/hermes/tests/test_supervisor_fsm.py +40 -0
  288. package/package.json +8 -8
  289. package/packages/cloud-mcp-gateway/dist/auth-store.d.ts +1 -0
  290. package/packages/cloud-mcp-gateway/dist/auth-store.d.ts.map +1 -1
  291. package/packages/cloud-mcp-gateway/dist/auth-store.js +21 -1
  292. package/packages/cloud-mcp-gateway/dist/auth-store.js.map +1 -1
  293. package/packages/cloud-mcp-gateway/dist/auth-store.test.js +34 -0
  294. package/packages/cloud-mcp-gateway/dist/auth-store.test.js.map +1 -1
  295. package/packages/cloud-mcp-gateway/package.json +2 -2
  296. package/packages/contracts/package.json +1 -1
  297. package/packages/daemon/dist/cloud-runtime.d.ts +2 -0
  298. package/packages/daemon/dist/cloud-runtime.d.ts.map +1 -1
  299. package/packages/daemon/dist/cloud-runtime.js +25 -1
  300. package/packages/daemon/dist/cloud-runtime.js.map +1 -1
  301. package/packages/daemon/dist/cloud-runtime.test.js +51 -0
  302. package/packages/daemon/dist/cloud-runtime.test.js.map +1 -1
  303. package/packages/daemon/dist/message-batcher.d.ts +7 -0
  304. package/packages/daemon/dist/message-batcher.d.ts.map +1 -1
  305. package/packages/daemon/dist/message-batcher.js +13 -0
  306. package/packages/daemon/dist/message-batcher.js.map +1 -1
  307. package/packages/daemon/dist/message-batcher.test.js +48 -0
  308. package/packages/daemon/dist/message-batcher.test.js.map +1 -1
  309. package/packages/daemon/dist/session-manager.js +1 -1
  310. package/packages/daemon/dist/session-manager.js.map +1 -1
  311. package/packages/daemon/package.json +5 -5
  312. package/packages/gsd-agent-core/dist/compaction/compaction.d.ts +13 -1
  313. package/packages/gsd-agent-core/dist/compaction/compaction.d.ts.map +1 -1
  314. package/packages/gsd-agent-core/dist/compaction/compaction.js +15 -1
  315. package/packages/gsd-agent-core/dist/compaction/compaction.js.map +1 -1
  316. package/packages/gsd-agent-core/dist/export-html/template.js +53 -4
  317. package/packages/gsd-agent-core/dist/session/agent-session-navigation.d.ts.map +1 -1
  318. package/packages/gsd-agent-core/dist/session/agent-session-navigation.js +4 -1
  319. package/packages/gsd-agent-core/dist/session/agent-session-navigation.js.map +1 -1
  320. package/packages/gsd-agent-core/package.json +5 -5
  321. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.d.ts.map +1 -1
  322. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.js +3 -2
  323. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.js.map +1 -1
  324. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-segment-walker.d.ts.map +1 -1
  325. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-segment-walker.js +1 -0
  326. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-segment-walker.js.map +1 -1
  327. package/packages/gsd-agent-modes/dist/modes/rpc/rpc-client.js +1 -1
  328. package/packages/gsd-agent-modes/dist/modes/rpc/rpc-client.js.map +1 -1
  329. package/packages/gsd-agent-modes/package.json +7 -7
  330. package/packages/mcp-server/dist/server.d.ts +18 -5
  331. package/packages/mcp-server/dist/server.d.ts.map +1 -1
  332. package/packages/mcp-server/dist/server.js +46 -5
  333. package/packages/mcp-server/dist/server.js.map +1 -1
  334. package/packages/mcp-server/dist/session-manager.js +1 -1
  335. package/packages/mcp-server/dist/session-manager.js.map +1 -1
  336. package/packages/mcp-server/package.json +4 -4
  337. package/packages/native/package.json +1 -1
  338. package/packages/pi-agent-core/dist/agent-loop.d.ts.map +1 -1
  339. package/packages/pi-agent-core/dist/agent-loop.js +14 -9
  340. package/packages/pi-agent-core/dist/agent-loop.js.map +1 -1
  341. package/packages/pi-agent-core/package.json +1 -1
  342. package/packages/pi-ai/dist/env-api-keys.d.ts.map +1 -1
  343. package/packages/pi-ai/dist/env-api-keys.js +3 -0
  344. package/packages/pi-ai/dist/env-api-keys.js.map +1 -1
  345. package/packages/pi-ai/dist/index.d.ts +1 -0
  346. package/packages/pi-ai/dist/index.d.ts.map +1 -1
  347. package/packages/pi-ai/dist/index.js +1 -0
  348. package/packages/pi-ai/dist/index.js.map +1 -1
  349. package/packages/pi-ai/dist/providers/transform-messages.d.ts.map +1 -1
  350. package/packages/pi-ai/dist/providers/transform-messages.js +7 -3
  351. package/packages/pi-ai/dist/providers/transform-messages.js.map +1 -1
  352. package/packages/pi-ai/dist/tool-result-content.d.ts +3 -0
  353. package/packages/pi-ai/dist/tool-result-content.d.ts.map +1 -0
  354. package/packages/pi-ai/dist/tool-result-content.js +62 -0
  355. package/packages/pi-ai/dist/tool-result-content.js.map +1 -0
  356. package/packages/pi-ai/dist/types.d.ts +10 -22
  357. package/packages/pi-ai/dist/types.d.ts.map +1 -1
  358. package/packages/pi-ai/dist/types.js.map +1 -1
  359. package/packages/pi-ai/package.json +1 -1
  360. package/packages/pi-coding-agent/dist/core/model-resolver.d.ts.map +1 -1
  361. package/packages/pi-coding-agent/dist/core/model-resolver.js +1 -0
  362. package/packages/pi-coding-agent/dist/core/model-resolver.js.map +1 -1
  363. package/packages/pi-coding-agent/dist/core/package-manager.d.ts +9 -0
  364. package/packages/pi-coding-agent/dist/core/package-manager.d.ts.map +1 -1
  365. package/packages/pi-coding-agent/dist/core/package-manager.js +74 -53
  366. package/packages/pi-coding-agent/dist/core/package-manager.js.map +1 -1
  367. package/packages/pi-coding-agent/dist/core/resource-loader.d.ts +6 -0
  368. package/packages/pi-coding-agent/dist/core/resource-loader.d.ts.map +1 -1
  369. package/packages/pi-coding-agent/dist/core/resource-loader.js +30 -2
  370. package/packages/pi-coding-agent/dist/core/resource-loader.js.map +1 -1
  371. package/packages/pi-coding-agent/dist/core/session-manager-types.d.ts +1 -0
  372. package/packages/pi-coding-agent/dist/core/session-manager-types.d.ts.map +1 -1
  373. package/packages/pi-coding-agent/dist/core/session-manager-types.js.map +1 -1
  374. package/packages/pi-coding-agent/dist/core/session-manager.d.ts.map +1 -1
  375. package/packages/pi-coding-agent/dist/core/session-manager.js +3 -0
  376. package/packages/pi-coding-agent/dist/core/session-manager.js.map +1 -1
  377. package/packages/pi-coding-agent/dist/core/skill-directories.d.ts +66 -0
  378. package/packages/pi-coding-agent/dist/core/skill-directories.d.ts.map +1 -0
  379. package/packages/pi-coding-agent/dist/core/skill-directories.js +138 -0
  380. package/packages/pi-coding-agent/dist/core/skill-directories.js.map +1 -0
  381. package/packages/pi-coding-agent/dist/core/skills.d.ts +4 -1
  382. package/packages/pi-coding-agent/dist/core/skills.d.ts.map +1 -1
  383. package/packages/pi-coding-agent/dist/core/skills.js +4 -1
  384. package/packages/pi-coding-agent/dist/core/skills.js.map +1 -1
  385. package/packages/pi-coding-agent/dist/index.d.ts +1 -0
  386. package/packages/pi-coding-agent/dist/index.d.ts.map +1 -1
  387. package/packages/pi-coding-agent/dist/index.js +1 -0
  388. package/packages/pi-coding-agent/dist/index.js.map +1 -1
  389. package/packages/pi-coding-agent/package.json +7 -7
  390. package/packages/pi-tui/package.json +2 -2
  391. package/packages/rpc-client/dist/rpc-client.js +1 -1
  392. package/packages/rpc-client/dist/rpc-client.js.map +1 -1
  393. package/packages/rpc-client/package.json +2 -2
  394. package/pkg/dist/core/export-html/template.js +53 -4
  395. package/pkg/package.json +1 -1
  396. package/scripts/link-workspace-packages.cjs +14 -4
  397. package/src/resources/GSD-WORKFLOW.md +20 -25
  398. package/src/resources/extensions/ask-user-questions.ts +1 -1
  399. package/src/resources/extensions/claude-code-cli/stream-adapter.ts +130 -51
  400. package/src/resources/extensions/claude-code-cli/tests/stream-adapter.test.ts +371 -39
  401. package/src/resources/extensions/cursor-cli/index.ts +18 -0
  402. package/src/resources/extensions/cursor-cli/models.ts +65 -0
  403. package/src/resources/extensions/cursor-cli/package.json +11 -0
  404. package/src/resources/extensions/cursor-cli/readiness.ts +143 -0
  405. package/src/resources/extensions/cursor-cli/stream-adapter.ts +440 -0
  406. package/src/resources/extensions/cursor-cli/tests/index.test.ts +54 -0
  407. package/src/resources/extensions/cursor-cli/tests/readiness.test.ts +29 -0
  408. package/src/resources/extensions/cursor-cli/tests/stream-adapter.test.ts +166 -0
  409. package/src/resources/extensions/gsd/activity-log.ts +4 -1
  410. package/src/resources/extensions/gsd/artifact-verification.ts +25 -9
  411. package/src/resources/extensions/gsd/auto/closeout.ts +163 -58
  412. package/src/resources/extensions/gsd/auto/finalize.ts +8 -0
  413. package/src/resources/extensions/gsd/auto/loop-deps.ts +1 -0
  414. package/src/resources/extensions/gsd/auto/orchestrator.ts +4 -3
  415. package/src/resources/extensions/gsd/auto/pre-dispatch.ts +6 -3
  416. package/src/resources/extensions/gsd/auto/run-unit.ts +5 -2
  417. package/src/resources/extensions/gsd/auto/schedule-wakeup.ts +8 -0
  418. package/src/resources/extensions/gsd/auto/unit-phase.ts +5 -9
  419. package/src/resources/extensions/gsd/auto-artifact-paths.ts +12 -3
  420. package/src/resources/extensions/gsd/auto-direct-dispatch.ts +13 -7
  421. package/src/resources/extensions/gsd/auto-dispatch.ts +35 -7
  422. package/src/resources/extensions/gsd/auto-model-selection.ts +49 -18
  423. package/src/resources/extensions/gsd/auto-prompts.ts +73 -2
  424. package/src/resources/extensions/gsd/auto-recovery.ts +50 -6
  425. package/src/resources/extensions/gsd/auto-start.ts +9 -6
  426. package/src/resources/extensions/gsd/auto-timeout-recovery.ts +4 -0
  427. package/src/resources/extensions/gsd/auto-worktree-branch-lifecycle.ts +237 -0
  428. package/src/resources/extensions/gsd/auto-worktree-cleanup.ts +166 -0
  429. package/src/resources/extensions/gsd/auto-worktree-conflict-auto-resolve.ts +37 -0
  430. package/src/resources/extensions/gsd/auto-worktree-creation.ts +171 -0
  431. package/src/resources/extensions/gsd/auto-worktree-entry.ts +154 -0
  432. package/src/resources/extensions/gsd/auto-worktree-merge-already-merged.ts +161 -0
  433. package/src/resources/extensions/gsd/auto-worktree-merge-branch-head.ts +83 -0
  434. package/src/resources/extensions/gsd/auto-worktree-merge-cleanup.ts +132 -0
  435. package/src/resources/extensions/gsd/auto-worktree-merge-code-changes.ts +71 -0
  436. package/src/resources/extensions/gsd/auto-worktree-merge-db-ready.ts +112 -0
  437. package/src/resources/extensions/gsd/auto-worktree-merge-integration-branch.ts +99 -0
  438. package/src/resources/extensions/gsd/auto-worktree-merge-message.ts +166 -0
  439. package/src/resources/extensions/gsd/auto-worktree-merge-pre-teardown.ts +93 -0
  440. package/src/resources/extensions/gsd/auto-worktree-merge-stash.ts +213 -0
  441. package/src/resources/extensions/gsd/auto-worktree-merge.ts +391 -0
  442. package/src/resources/extensions/gsd/auto-worktree-milestone-shelter.ts +159 -0
  443. package/src/resources/extensions/gsd/auto-worktree-path-resolution.ts +6 -0
  444. package/src/resources/extensions/gsd/auto-worktree-path-utils.ts +10 -0
  445. package/src/resources/extensions/gsd/auto-worktree-resource-version.ts +44 -0
  446. package/src/resources/extensions/gsd/auto-worktree-runtime-cleanup.ts +119 -0
  447. package/src/resources/extensions/gsd/auto-worktree-session-registry.ts +71 -0
  448. package/src/resources/extensions/gsd/auto-worktree-sync.ts +370 -0
  449. package/src/resources/extensions/gsd/auto-worktree-teardown.ts +161 -0
  450. package/src/resources/extensions/gsd/auto-worktree.ts +69 -2390
  451. package/src/resources/extensions/gsd/auto.ts +32 -19
  452. package/src/resources/extensions/gsd/bootstrap/db-tools.ts +3 -0
  453. package/src/resources/extensions/gsd/bootstrap/dynamic-tools.ts +1 -1
  454. package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +148 -7
  455. package/src/resources/extensions/gsd/bootstrap/schedule-wakeup-tool.ts +80 -12
  456. package/src/resources/extensions/gsd/bootstrap/system-context.ts +1 -1
  457. package/src/resources/extensions/gsd/bootstrap/tool-call-loop-guard.ts +229 -28
  458. package/src/resources/extensions/gsd/bootstrap/write-gate.ts +23 -1
  459. package/src/resources/extensions/gsd/codebase-generator.ts +186 -19
  460. package/src/resources/extensions/gsd/commands/handlers/core.ts +39 -3
  461. package/src/resources/extensions/gsd/commands-handlers.ts +1 -1
  462. package/src/resources/extensions/gsd/commands-prefs-wizard.ts +135 -1
  463. package/src/resources/extensions/gsd/commands-workflow-templates.ts +3 -3
  464. package/src/resources/extensions/gsd/commands-worktree.ts +13 -2
  465. package/src/resources/extensions/gsd/db/queries.ts +49 -9
  466. package/src/resources/extensions/gsd/db/writers/cascades.ts +23 -1
  467. package/src/resources/extensions/gsd/discussion-handoff.ts +10 -2
  468. package/src/resources/extensions/gsd/docs/preferences-reference.md +8 -2
  469. package/src/resources/extensions/gsd/doctor-engine-checks.ts +372 -22
  470. package/src/resources/extensions/gsd/doctor-providers.ts +39 -10
  471. package/src/resources/extensions/gsd/doctor-types.ts +5 -1
  472. package/src/resources/extensions/gsd/doctor.ts +95 -3
  473. package/src/resources/extensions/gsd/exec-sandbox.ts +6 -2
  474. package/src/resources/extensions/gsd/flat-phase-migration.ts +132 -25
  475. package/src/resources/extensions/gsd/forensics.ts +1 -1
  476. package/src/resources/extensions/gsd/git-conflict-resolve.ts +2 -2
  477. package/src/resources/extensions/gsd/git-service.ts +67 -17
  478. package/src/resources/extensions/gsd/gsd-db.ts +105 -11
  479. package/src/resources/extensions/gsd/guidance.ts +2 -0
  480. package/src/resources/extensions/gsd/guided-flow.ts +71 -20
  481. package/src/resources/extensions/gsd/key-manager.ts +1 -0
  482. package/src/resources/extensions/gsd/markdown-renderer.ts +40 -10
  483. package/src/resources/extensions/gsd/md-importer.ts +93 -22
  484. package/src/resources/extensions/gsd/migrate-external.ts +23 -6
  485. package/src/resources/extensions/gsd/migration-auto-check.ts +32 -3
  486. package/src/resources/extensions/gsd/milestone-merge-transaction.ts +19 -4
  487. package/src/resources/extensions/gsd/milestone-settlement.ts +1 -1
  488. package/src/resources/extensions/gsd/model-router.ts +4 -5
  489. package/src/resources/extensions/gsd/parallel-merge.ts +1 -1
  490. package/src/resources/extensions/gsd/parallel-orchestrator.ts +3 -1
  491. package/src/resources/extensions/gsd/paths.ts +21 -3
  492. package/src/resources/extensions/gsd/preferences-diagnostics.ts +24 -0
  493. package/src/resources/extensions/gsd/preferences-models.ts +6 -3
  494. package/src/resources/extensions/gsd/preferences-skills.ts +10 -16
  495. package/src/resources/extensions/gsd/preferences-types.ts +30 -0
  496. package/src/resources/extensions/gsd/preferences-validation.ts +97 -2
  497. package/src/resources/extensions/gsd/preferences.ts +58 -4
  498. package/src/resources/extensions/gsd/prompts/plan-slice.md +4 -2
  499. package/src/resources/extensions/gsd/prompts/system.md +6 -6
  500. package/src/resources/extensions/gsd/quick.ts +11 -3
  501. package/src/resources/extensions/gsd/redact-secrets.ts +40 -0
  502. package/src/resources/extensions/gsd/repo-identity.ts +17 -0
  503. package/src/resources/extensions/gsd/repository-registry.ts +7 -1
  504. package/src/resources/extensions/gsd/root-write-leak-guard.ts +3 -2
  505. package/src/resources/extensions/gsd/safe-fs.ts +22 -2
  506. package/src/resources/extensions/gsd/skill-discovery.ts +47 -23
  507. package/src/resources/extensions/gsd/skills/gsd-headless/SKILL.md +7 -9
  508. package/src/resources/extensions/gsd/skills/gsd-headless/references/commands.md +1 -0
  509. package/src/resources/extensions/gsd/slice-parallel-orchestrator.ts +3 -1
  510. package/src/resources/extensions/gsd/state/derive/from-db.ts +201 -157
  511. package/src/resources/extensions/gsd/tests/auto-artifact-paths.test.ts +169 -1
  512. package/src/resources/extensions/gsd/tests/auto-loop-no-copy-artifacts.test.ts +2 -1
  513. package/src/resources/extensions/gsd/tests/auto-loop.test.ts +131 -5
  514. package/src/resources/extensions/gsd/tests/auto-migrating-recovery.test.ts +18 -0
  515. package/src/resources/extensions/gsd/tests/auto-model-selection.test.ts +178 -0
  516. package/src/resources/extensions/gsd/tests/auto-phases-lifecycle.test.ts +43 -1
  517. package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +111 -0
  518. package/src/resources/extensions/gsd/tests/auto-remote-session-lock-cleanup.test.ts +41 -0
  519. package/src/resources/extensions/gsd/tests/auto-runtime-state.test.ts +41 -0
  520. package/src/resources/extensions/gsd/tests/auto-session-scope.test.ts +4 -4
  521. package/src/resources/extensions/gsd/tests/auto-start-bootstrap-await-3420.test.ts +3 -0
  522. package/src/resources/extensions/gsd/tests/auto-start-clean-runtime-db-gated.test.ts +1 -1
  523. package/src/resources/extensions/gsd/tests/auto-timeout-recovery-harness-abort.test.ts +55 -0
  524. package/src/resources/extensions/gsd/tests/auto-warning-noise-regression.test.ts +10 -1
  525. package/src/resources/extensions/gsd/tests/auto-worktree-auto-resolve.test.ts +1 -1
  526. package/src/resources/extensions/gsd/tests/auto-worktree-merge-already-merged.test.ts +177 -0
  527. package/src/resources/extensions/gsd/tests/auto-worktree-merge-branch-head.test.ts +118 -0
  528. package/src/resources/extensions/gsd/tests/auto-worktree-merge-cleanup.test.ts +115 -0
  529. package/src/resources/extensions/gsd/tests/auto-worktree-merge-code-changes.test.ts +76 -0
  530. package/src/resources/extensions/gsd/tests/auto-worktree-merge-db-ready.test.ts +140 -0
  531. package/src/resources/extensions/gsd/tests/auto-worktree-merge-integration-branch.test.ts +123 -0
  532. package/src/resources/extensions/gsd/tests/auto-worktree-merge-message.test.ts +114 -0
  533. package/src/resources/extensions/gsd/tests/auto-worktree-merge-pre-teardown.test.ts +84 -0
  534. package/src/resources/extensions/gsd/tests/auto-worktree-merge-stash.test.ts +70 -0
  535. package/src/resources/extensions/gsd/tests/auto-worktree-milestone-shelter.test.ts +52 -0
  536. package/src/resources/extensions/gsd/tests/auto-worktree-registry.test.ts +6 -6
  537. package/src/resources/extensions/gsd/tests/auto-worktree-resource-version.test.ts +59 -0
  538. package/src/resources/extensions/gsd/tests/auto-worktree-untracked-content.test.ts +3 -1
  539. package/src/resources/extensions/gsd/tests/batch-task-query.test.ts +85 -0
  540. package/src/resources/extensions/gsd/tests/check-auto-start-ready-guard.test.ts +29 -0
  541. package/src/resources/extensions/gsd/tests/codebase-generator.test.ts +387 -0
  542. package/src/resources/extensions/gsd/tests/complete-milestone-excerpt.test.ts +62 -1
  543. package/src/resources/extensions/gsd/tests/completed-units-metrics-sync.test.ts +1 -1
  544. package/src/resources/extensions/gsd/tests/derive-state-db.test.ts +4 -0
  545. package/src/resources/extensions/gsd/tests/doctor-providers.test.ts +138 -1
  546. package/src/resources/extensions/gsd/tests/doctor-scope-db-unavailable.test.ts +571 -5
  547. package/src/resources/extensions/gsd/tests/doctor-workspace.test.ts +207 -0
  548. package/src/resources/extensions/gsd/tests/fast-forward-reused-milestone-branch.test.ts +1 -1
  549. package/src/resources/extensions/gsd/tests/flat-phase-migration.test.ts +109 -2
  550. package/src/resources/extensions/gsd/tests/flat-phase-renderer.test.ts +25 -1
  551. package/src/resources/extensions/gsd/tests/flat-rate-routing-guard.test.ts +87 -19
  552. package/src/resources/extensions/gsd/tests/gate-1b-orphan-discrimination.test.ts +89 -0
  553. package/src/resources/extensions/gsd/tests/gsd-db.test.ts +40 -0
  554. package/src/resources/extensions/gsd/tests/guided-flow-session-isolation.test.ts +9 -0
  555. package/src/resources/extensions/gsd/tests/import-completion-lost-update.test.ts +196 -0
  556. package/src/resources/extensions/gsd/tests/integration/all-milestones-complete-merge.test.ts +4 -6
  557. package/src/resources/extensions/gsd/tests/integration/auto-stash-merge.test.ts +2 -1
  558. package/src/resources/extensions/gsd/tests/integration/auto-worktree-milestone-merge.test.ts +3 -3
  559. package/src/resources/extensions/gsd/tests/integration/auto-worktree.test.ts +7 -8
  560. package/src/resources/extensions/gsd/tests/integration/feature-branch-lifecycle-integration.test.ts +2 -5
  561. package/src/resources/extensions/gsd/tests/integration/git-service.test.ts +76 -0
  562. package/src/resources/extensions/gsd/tests/integration/merge-cwd-restore.test.ts +1 -1
  563. package/src/resources/extensions/gsd/tests/integration/merge-preserve-worktree-on-preteardown-error.test.ts +1 -1
  564. package/src/resources/extensions/gsd/tests/integration/merge-strategy-regular.test.ts +2 -1
  565. package/src/resources/extensions/gsd/tests/integration/milestone-transition-worktree.test.ts +5 -7
  566. package/src/resources/extensions/gsd/tests/integration/state-machine-edge-cases.test.ts +4 -2
  567. package/src/resources/extensions/gsd/tests/integration/workspace-collapse-integration.test.ts +2 -4
  568. package/src/resources/extensions/gsd/tests/journal-integration.test.ts +16 -15
  569. package/src/resources/extensions/gsd/tests/markdown-renderer.test.ts +122 -0
  570. package/src/resources/extensions/gsd/tests/merge-closeout-consistency-gate.test.ts +1 -1
  571. package/src/resources/extensions/gsd/tests/merge-conflict-stops-loop.test.ts +4 -4
  572. package/src/resources/extensions/gsd/tests/merge-db-cycle.test.ts +1 -1
  573. package/src/resources/extensions/gsd/tests/merge-self-branch-guard.test.ts +1 -1
  574. package/src/resources/extensions/gsd/tests/migrate-external-worktree.test.ts +116 -0
  575. package/src/resources/extensions/gsd/tests/migration-auto-check.test.ts +91 -0
  576. package/src/resources/extensions/gsd/tests/milestone-merge-stash-restore.test.ts +592 -23
  577. package/src/resources/extensions/gsd/tests/milestone-merge-transaction.test.ts +25 -1
  578. package/src/resources/extensions/gsd/tests/none-mode-gates.test.ts +1 -1
  579. package/src/resources/extensions/gsd/tests/originalbase-path-comparison.test.ts +3 -3
  580. package/src/resources/extensions/gsd/tests/parallel-worker-lock-contention.test.ts +1 -1
  581. package/src/resources/extensions/gsd/tests/pending-autostart-scope.test.ts +2 -2
  582. package/src/resources/extensions/gsd/tests/phases-merge-error-stops-auto.test.ts +50 -6
  583. package/src/resources/extensions/gsd/tests/plan-slice-prompt.test.ts +17 -0
  584. package/src/resources/extensions/gsd/tests/plan-task.test.ts +264 -1
  585. package/src/resources/extensions/gsd/tests/preferences-worktree-sync.test.ts +1 -4
  586. package/src/resources/extensions/gsd/tests/preferences.test.ts +169 -0
  587. package/src/resources/extensions/gsd/tests/prefs-wizard-coverage.test.ts +147 -0
  588. package/src/resources/extensions/gsd/tests/recovery-verify-logs.test.ts +4 -4
  589. package/src/resources/extensions/gsd/tests/redact-secrets.test.ts +56 -0
  590. package/src/resources/extensions/gsd/tests/register-hooks-flat-phase-migration.test.ts +73 -0
  591. package/src/resources/extensions/gsd/tests/register-hooks-loop-guard-auto.test.ts +275 -0
  592. package/src/resources/extensions/gsd/tests/reopen-slice.test.ts +52 -0
  593. package/src/resources/extensions/gsd/tests/repository-registry.test.ts +41 -2
  594. package/src/resources/extensions/gsd/tests/require-slice-discussion-dispatch.test.ts +55 -0
  595. package/src/resources/extensions/gsd/tests/root-write-leak-guard.test.ts +31 -9
  596. package/src/resources/extensions/gsd/tests/runtime-invariant-modules.test.ts +20 -0
  597. package/src/resources/extensions/gsd/tests/schedule-wakeup-tool.test.ts +167 -0
  598. package/src/resources/extensions/gsd/tests/skill-discovery.test.ts +46 -0
  599. package/src/resources/extensions/gsd/tests/stale-worktree-cwd.test.ts +3 -5
  600. package/src/resources/extensions/gsd/tests/stalled-tool-recovery.test.ts +49 -0
  601. package/src/resources/extensions/gsd/tests/stash-pop-gsd-conflict.test.ts +2 -1
  602. package/src/resources/extensions/gsd/tests/stash-queued-context-files.test.ts +2 -1
  603. package/src/resources/extensions/gsd/tests/state-corruption-2945.test.ts +1 -1
  604. package/src/resources/extensions/gsd/tests/status-per-repo.test.ts +94 -0
  605. package/src/resources/extensions/gsd/tests/steer-worktree-path.test.ts +1 -1
  606. package/src/resources/extensions/gsd/tests/sync-worktree-skip-current.test.ts +1 -1
  607. package/src/resources/extensions/gsd/tests/system-flat-phase-layout.test.ts +33 -0
  608. package/src/resources/extensions/gsd/tests/teardown-chdir-failure-clears-registry.test.ts +4 -4
  609. package/src/resources/extensions/gsd/tests/teardown-cleanup-parity.test.ts +2 -1
  610. package/src/resources/extensions/gsd/tests/teardown-failure-clears-registry.test.ts +4 -4
  611. package/src/resources/extensions/gsd/tests/token-tool-gating.test.ts +35 -0
  612. package/src/resources/extensions/gsd/tests/tool-call-loop-guard.test.ts +259 -0
  613. package/src/resources/extensions/gsd/tests/uat-stuck-loop-orphaned-worktree.test.ts +1 -1
  614. package/src/resources/extensions/gsd/tests/unit-context-manifest.test.ts +66 -18
  615. package/src/resources/extensions/gsd/tests/unit-registry.test.ts +81 -0
  616. package/src/resources/extensions/gsd/tests/unit-runtime.test.ts +30 -0
  617. package/src/resources/extensions/gsd/tests/uok-gitops-turn-action.test.ts +52 -0
  618. package/src/resources/extensions/gsd/tests/validator-scope-parity.test.ts +53 -1
  619. package/src/resources/extensions/gsd/tests/workflow-tool-executors.test.ts +208 -1
  620. package/src/resources/extensions/gsd/tests/workspace.test.ts +18 -4
  621. package/src/resources/extensions/gsd/tests/worktree-db-integration.test.ts +1 -1
  622. package/src/resources/extensions/gsd/tests/worktree-db-respawn-truncation.test.ts +1 -1
  623. package/src/resources/extensions/gsd/tests/worktree-db-same-file.test.ts +1 -3
  624. package/src/resources/extensions/gsd/tests/worktree-expected-warnings.test.ts +1 -1
  625. package/src/resources/extensions/gsd/tests/worktree-git-pathspec.test.ts +1 -1
  626. package/src/resources/extensions/gsd/tests/worktree-journal-events.test.ts +4 -4
  627. package/src/resources/extensions/gsd/tests/worktree-lifecycle.test.ts +2 -2
  628. package/src/resources/extensions/gsd/tests/worktree-main-branch.test.ts +1 -1
  629. package/src/resources/extensions/gsd/tests/worktree-preferences-sync.test.ts +1 -1
  630. package/src/resources/extensions/gsd/tests/worktree-reentry.test.ts +2 -1
  631. package/src/resources/extensions/gsd/tests/worktree-sync-milestones.test.ts +36 -3
  632. package/src/resources/extensions/gsd/tests/worktree-sync-overwrite-loop.test.ts +1 -1
  633. package/src/resources/extensions/gsd/tests/worktree-sync-tasks.test.ts +1 -1
  634. package/src/resources/extensions/gsd/tests/worktree-teardown-safety.test.ts +32 -0
  635. package/src/resources/extensions/gsd/tool-contract.ts +29 -0
  636. package/src/resources/extensions/gsd/tools/plan-task.ts +107 -9
  637. package/src/resources/extensions/gsd/tools/reopen-slice.ts +5 -0
  638. package/src/resources/extensions/gsd/tools/reopen-task.ts +13 -5
  639. package/src/resources/extensions/gsd/tools/workflow-tool-executors.ts +58 -0
  640. package/src/resources/extensions/gsd/unit-context-manifest.ts +11 -5
  641. package/src/resources/extensions/gsd/unit-registry.ts +48 -2
  642. package/src/resources/extensions/gsd/unit-runtime.ts +42 -0
  643. package/src/resources/extensions/gsd/unmerged-milestone-guard.ts +1 -1
  644. package/src/resources/extensions/gsd/validation-block-guard.ts +2 -1
  645. package/src/resources/extensions/gsd/workspace-git-preflight.ts +2 -2
  646. package/src/resources/extensions/gsd/workspace.ts +42 -8
  647. package/src/resources/extensions/gsd/worktree-command.ts +1 -1
  648. package/src/resources/extensions/gsd/worktree-lifecycle.ts +154 -26
  649. package/src/resources/extensions/gsd/worktree-manager.ts +143 -5
  650. package/src/resources/extensions/gsd/worktree-reentry.ts +2 -1
  651. package/src/resources/extensions/shared/interview-ui.ts +58 -11
  652. package/src/resources/extensions/shared/tests/interview-ui-border.test.ts +32 -0
  653. package/dist/web/standalone/.next/static/chunks/app/_not-found/page-49f565245e1e4afe.js +0 -1
  654. package/dist/web/standalone/.next/static/chunks/app/page-bc4c723c6a19c6f0.js +0 -1
  655. package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/global-error-ec3eaffc9785ba48.js +0 -1
  656. /package/dist/web/standalone/.next/static/{zQLcXm0Za8lexoXtgDpMG → gXoWec4UNqcR0tkuHwYCr}/_buildManifest.js +0 -0
  657. /package/dist/web/standalone/.next/static/{zQLcXm0Za8lexoXtgDpMG → gXoWec4UNqcR0tkuHwYCr}/_ssgManifest.js +0 -0
@@ -454,6 +454,14 @@ export function insertTask(t: {
454
454
  fullSummaryMd?: string;
455
455
  sequence?: number;
456
456
  planning?: Partial<TaskPlanningRecord>;
457
+ // #1222 (metadata half): when re-importing from markdown, the caller only
458
+ // knows the plan/status — not the execution prose that gsd_task_complete
459
+ // wrote to the DB. Setting this preserves the existing row's execution
460
+ // columns (and completed_at) whenever the incoming value is empty/default,
461
+ // so a re-import cannot silently blank a completed task's summary metadata
462
+ // or refresh its completion timestamp. Off by default: callers that own the
463
+ // execution metadata (gsd_task_complete, planning) keep overwrite semantics.
464
+ preserveCompletionMetadata?: boolean;
457
465
  }): void {
458
466
  if (!getDbOrNull()!) throw new GSDError(GSD_STALE_STATE, "gsd-db: No database open");
459
467
  getDbOrNull()!.prepare(
@@ -473,17 +481,17 @@ export function insertTask(t: {
473
481
  ON CONFLICT(milestone_id, slice_id, id) DO UPDATE SET
474
482
  title = CASE WHEN NULLIF(:title, '') IS NOT NULL THEN :title ELSE tasks.title END,
475
483
  status = :status,
476
- one_liner = :one_liner,
477
- narrative = :narrative,
478
- verification_result = :verification_result,
479
- duration = :duration,
480
- completed_at = :completed_at,
481
- blocker_discovered = :blocker_discovered,
482
- deviations = :deviations,
483
- known_issues = :known_issues,
484
- key_files = :key_files,
485
- key_decisions = :key_decisions,
486
- full_summary_md = :full_summary_md,
484
+ one_liner = CASE WHEN :preserve_completion = 1 AND NULLIF(:one_liner, '') IS NULL THEN tasks.one_liner ELSE :one_liner END,
485
+ narrative = CASE WHEN :preserve_completion = 1 AND NULLIF(:narrative, '') IS NULL THEN tasks.narrative ELSE :narrative END,
486
+ verification_result = CASE WHEN :preserve_completion = 1 AND NULLIF(:verification_result, '') IS NULL THEN tasks.verification_result ELSE :verification_result END,
487
+ duration = CASE WHEN :preserve_completion = 1 AND NULLIF(:duration, '') IS NULL THEN tasks.duration ELSE :duration END,
488
+ completed_at = CASE WHEN :preserve_completion = 1 AND tasks.completed_at IS NOT NULL THEN tasks.completed_at ELSE :completed_at END,
489
+ blocker_discovered = CASE WHEN :preserve_completion = 1 AND :blocker_discovered = 0 THEN tasks.blocker_discovered ELSE :blocker_discovered END,
490
+ deviations = CASE WHEN :preserve_completion = 1 AND NULLIF(:deviations, '') IS NULL THEN tasks.deviations ELSE :deviations END,
491
+ known_issues = CASE WHEN :preserve_completion = 1 AND NULLIF(:known_issues, '') IS NULL THEN tasks.known_issues ELSE :known_issues END,
492
+ key_files = CASE WHEN :preserve_completion = 1 AND NULLIF(:key_files, '[]') IS NULL THEN tasks.key_files ELSE :key_files END,
493
+ key_decisions = CASE WHEN :preserve_completion = 1 AND NULLIF(:key_decisions, '[]') IS NULL THEN tasks.key_decisions ELSE :key_decisions END,
494
+ full_summary_md = CASE WHEN :preserve_completion = 1 AND NULLIF(:full_summary_md, '') IS NULL THEN tasks.full_summary_md ELSE :full_summary_md END,
487
495
  description = CASE WHEN NULLIF(:description, '') IS NOT NULL THEN :description ELSE tasks.description END,
488
496
  estimate = CASE WHEN NULLIF(:estimate, '') IS NOT NULL THEN :estimate ELSE tasks.estimate END,
489
497
  files = CASE WHEN NULLIF(:files, '[]') IS NOT NULL THEN :files ELSE tasks.files END,
@@ -523,6 +531,7 @@ export function insertTask(t: {
523
531
  ":observability_impact": t.planning?.observabilityImpact ?? "",
524
532
  ":full_plan_md": t.planning?.fullPlanMd ?? "",
525
533
  ":sequence": t.sequence ?? 0,
534
+ ":preserve_completion": t.preserveCompletionMetadata && (t.status === "complete" || t.status === "done") ? 1 : 0,
526
535
  ":target_repositories": JSON.stringify(t.planning?.targetRepositories ?? []),
527
536
  ":raw_target_repositories":
528
537
  t.planning && "targetRepositories" in t.planning
@@ -535,6 +544,78 @@ export function updateTaskStatus(milestoneId: string, sliceId: string, taskId: s
535
544
  applyStatusTransition({ entity: "task", milestoneId, sliceId, taskId, status, completedAt });
536
545
  }
537
546
 
547
+ export function repairTaskCompletionFromSummary(t: {
548
+ milestoneId: string;
549
+ sliceId: string;
550
+ taskId: string;
551
+ title?: string;
552
+ oneLiner?: string;
553
+ narrative?: string;
554
+ verificationResult: string;
555
+ duration?: string;
556
+ completedAt: string;
557
+ blockerDiscovered?: boolean;
558
+ deviations?: string;
559
+ knownIssues?: string;
560
+ keyFiles?: string[];
561
+ keyDecisions?: string[];
562
+ fullSummaryMd: string;
563
+ }): void {
564
+ const db = getDbOrNull();
565
+ if (!db) throw new GSDError(GSD_STALE_STATE, "gsd-db: No database open");
566
+ transaction(() => {
567
+ const seq = db.prepare(
568
+ `SELECT COALESCE(MAX(sequence), 0) + 1 AS next_sequence
569
+ FROM tasks
570
+ WHERE milestone_id = :mid AND slice_id = :sid`,
571
+ ).get({ ":mid": t.milestoneId, ":sid": t.sliceId }) as { next_sequence?: number } | undefined;
572
+ db.prepare(
573
+ `INSERT INTO tasks (
574
+ milestone_id, slice_id, id, title, status, one_liner, narrative,
575
+ verification_result, duration, completed_at, blocker_discovered,
576
+ deviations, known_issues, key_files, key_decisions, full_summary_md,
577
+ sequence
578
+ ) VALUES (
579
+ :milestone_id, :slice_id, :id, :title, 'complete', :one_liner, :narrative,
580
+ :verification_result, :duration, :completed_at, :blocker_discovered,
581
+ :deviations, :known_issues, :key_files, :key_decisions, :full_summary_md,
582
+ :sequence
583
+ )
584
+ ON CONFLICT(milestone_id, slice_id, id) DO UPDATE SET
585
+ title = CASE WHEN NULLIF(:title, '') IS NOT NULL THEN :title ELSE tasks.title END,
586
+ status = 'complete',
587
+ one_liner = CASE WHEN NULLIF(:one_liner, '') IS NOT NULL THEN :one_liner ELSE tasks.one_liner END,
588
+ narrative = CASE WHEN NULLIF(:narrative, '') IS NOT NULL THEN :narrative ELSE tasks.narrative END,
589
+ verification_result = :verification_result,
590
+ duration = CASE WHEN NULLIF(:duration, '') IS NOT NULL THEN :duration ELSE tasks.duration END,
591
+ completed_at = :completed_at,
592
+ blocker_discovered = :blocker_discovered,
593
+ deviations = CASE WHEN NULLIF(:deviations, '') IS NOT NULL THEN :deviations ELSE tasks.deviations END,
594
+ known_issues = CASE WHEN NULLIF(:known_issues, '') IS NOT NULL THEN :known_issues ELSE tasks.known_issues END,
595
+ key_files = :key_files,
596
+ key_decisions = :key_decisions,
597
+ full_summary_md = :full_summary_md`,
598
+ ).run({
599
+ ":milestone_id": t.milestoneId,
600
+ ":slice_id": t.sliceId,
601
+ ":id": t.taskId,
602
+ ":title": t.title ?? "",
603
+ ":one_liner": t.oneLiner ?? "",
604
+ ":narrative": t.narrative ?? "",
605
+ ":verification_result": t.verificationResult,
606
+ ":duration": t.duration ?? "",
607
+ ":completed_at": t.completedAt,
608
+ ":blocker_discovered": t.blockerDiscovered ? 1 : 0,
609
+ ":deviations": t.deviations ?? "",
610
+ ":known_issues": t.knownIssues ?? "",
611
+ ":key_files": JSON.stringify(t.keyFiles ?? []),
612
+ ":key_decisions": JSON.stringify(t.keyDecisions ?? []),
613
+ ":full_summary_md": t.fullSummaryMd,
614
+ ":sequence": seq?.next_sequence ?? 1,
615
+ });
616
+ });
617
+ }
618
+
538
619
  export function setTaskBlockerDiscovered(milestoneId: string, sliceId: string, taskId: string, discovered: boolean): void {
539
620
  if (!getDbOrNull()!) return;
540
621
  getDbOrNull()!.prepare(
@@ -1325,6 +1406,19 @@ export function deleteArtifactByPath(path: string): void {
1325
1406
  getDbOrNull()!.prepare("DELETE FROM artifacts WHERE path = :path").run({ ":path": path });
1326
1407
  }
1327
1408
 
1409
+ /** Delete artifact rows whose paths share a DB-relative prefix. */
1410
+ export function deleteArtifactsByPathPrefix(prefix: string): number {
1411
+ if (!getDbOrNull()!) throw new GSDError(GSD_STALE_STATE, "gsd-db: No database open");
1412
+ return transaction(() => {
1413
+ const likePrefix = `${prefix}%`;
1414
+ const countRow = getDbOrNull()!.prepare(
1415
+ "SELECT COUNT(*) AS count FROM artifacts WHERE path LIKE :prefix",
1416
+ ).get({ ":prefix": likePrefix });
1417
+ getDbOrNull()!.prepare("DELETE FROM artifacts WHERE path LIKE :prefix").run({ ":prefix": likePrefix });
1418
+ return Number(countRow?.["count"] ?? 0);
1419
+ });
1420
+ }
1421
+
1328
1422
  /**
1329
1423
  * Drop hierarchy rows in dependency order inside a transaction. Used by
1330
1424
  * `gsd recover --confirm` to rebuild engine state from markdown.
@@ -209,6 +209,8 @@ const DOCTOR_FIX_HINTS: Partial<Record<DoctorIssueCode, string>> = {
209
209
  state_file_stale: "Run `/gsd doctor fix` to rebuild the projection from the database.",
210
210
  state_file_missing: "Run `/gsd doctor fix` to rebuild the projection from the database.",
211
211
  projection_drift: "Run `/gsd doctor fix` to rebuild markdown projections from the database (DB is the source of truth).",
212
+ artifact_user_content_missing:
213
+ "Doctor cannot recreate user-authored content from the database. Re-run `/gsd discuss` for CONTEXT artifacts or `/gsd auto` for RESEARCH artifacts in that milestone.",
212
214
  uat_retry_exhausted: "Review the failing UAT criteria via `/gsd status`, fix the issue, then re-run `/gsd auto`.",
213
215
  };
214
216
 
@@ -42,7 +42,7 @@ import { gsdHome } from "./gsd-home.js";
42
42
  import {
43
43
  gsdRoot, milestonesDir, legacyMilestonesDir, resolveMilestoneFile,
44
44
  resolveSliceFile, resolveSlicePath, resolveGsdRootFile, relGsdRootFile,
45
- relMilestoneFile, relSliceFile,
45
+ relMilestoneFile, relSliceFile, clearPathCache,
46
46
  } from "./paths.js";
47
47
  import { join } from "node:path";
48
48
  import { readFileSync, existsSync, mkdirSync, readdirSync, rmSync } from "node:fs";
@@ -50,8 +50,8 @@ import { readSessionLockData, isSessionLockProcessAlive } from "./session-lock.j
50
50
  import { nativeAddAll, nativeCommit, nativeHasCommittedHead, nativeIsRepo, nativeInit } from "./native-git-bridge.js";
51
51
  import { isInheritedRepo } from "./repo-identity.js";
52
52
  import { ensureGitignore, ensurePreferences, untrackRuntimeFiles } from "./gitignore.js";
53
- import { getIsolationMode, loadEffectiveGSDPreferences } from "./preferences.js";
54
- import { getAutoWorktreePath } from "./auto-worktree.js";
53
+ import { getIsolationMode, loadEffectiveGSDPreferences, renderLanguageDirectiveForPrompt } from "./preferences.js";
54
+ import { getAutoWorktreePath } from "./auto-worktree-path-resolution.js";
55
55
  import { resolveUokFlags } from "./uok/flags.js";
56
56
  import { ensurePlanV2Graph, isMissingFinalizedContextResult } from "./uok/plan-v2.js";
57
57
  import { detectProjectState, hasGsdBootstrapArtifacts } from "./detection.js";
@@ -94,13 +94,14 @@ import {
94
94
  import { probeCoversRequiredWorkflowTools } from "./tool-surface-readiness.js";
95
95
  import { getRequiredWorkflowToolsForUnit } from "./unit-tool-contracts.js";
96
96
  import { isWorkflowToolSurfaceName } from "./workflow-tool-surface.js";
97
- import { getUnitWorkflowDispatchReadinessError } from "./tool-contract.js";
97
+ import { getUnitWorkflowDispatchReadinessErrorForModel } from "./tool-contract.js";
98
98
  import {
99
99
  runPreparation,
100
100
  formatCodebaseBrief,
101
101
  formatPriorContextBrief,
102
102
  } from "./preparation.js";
103
103
  import { verifyExpectedArtifact } from "./auto-recovery.js";
104
+ import { countPlanMilestoneRoadmapSlices } from "./artifact-verification.js";
104
105
  import type { MilestoneScope } from "./workspace.js";
105
106
  import { clearPendingGate, extractDepthVerificationMilestoneId, getPendingGate } from "./bootstrap/write-gate.js";
106
107
  import {
@@ -164,7 +165,7 @@ export const _scheduleAutoStartAfterIdleForTest = scheduleAutoStartAfterIdle;
164
165
  // These thin wrappers accept a MilestoneScope so callers that already hold a
165
166
  // pinned scope never have to re-derive (basePath, milestoneId) separately.
166
167
  // The underlying implementations in auto-recovery.ts / auto-artifact-paths.ts /
167
- // state.ts are unchanged — only the call surface in guided-flow.ts is migrated.
168
+ // state.ts remain the default for non-scope-specific units.
168
169
 
169
170
  /**
170
171
  * Scope-based overload of verifyExpectedArtifact.
@@ -176,9 +177,47 @@ export function verifyExpectedArtifactForScope(
176
177
  unitType: string,
177
178
  unitId: string,
178
179
  ): boolean {
180
+ if (
181
+ unitId === scope.milestoneId &&
182
+ (unitType === "discuss-milestone" || unitType === "plan-milestone")
183
+ ) {
184
+ // Layout-aware scope paths use resolveMilestoneFile; clear stale dir listings
185
+ // primed before discuss/plan wrote CONTEXT.md or ROADMAP.md (see checkAutoStartAfterDiscuss).
186
+ clearPathCache();
187
+ }
188
+ if (
189
+ unitId === scope.milestoneId &&
190
+ unitType === "discuss-milestone"
191
+ ) {
192
+ const path = resolveExpectedArtifactPathForScope(scope, unitType, unitId);
193
+ return path ? existsSync(path) : false;
194
+ }
195
+ if (unitId === scope.milestoneId && unitType === "plan-milestone") {
196
+ const path = resolveExpectedArtifactPathForScope(scope, unitType, unitId);
197
+ return verifyScopedPlanMilestoneArtifact(path, unitType, unitId);
198
+ }
179
199
  return verifyExpectedArtifact(unitType, unitId, scope.workspace.projectRoot);
180
200
  }
181
201
 
202
+ function verifyScopedPlanMilestoneArtifact(
203
+ path: string | null,
204
+ unitType: string,
205
+ unitId: string,
206
+ ): boolean {
207
+ if (!path || !existsSync(path)) return false;
208
+ try {
209
+ const roadmapContent = readFileSync(path, "utf-8");
210
+ if (countPlanMilestoneRoadmapSlices(roadmapContent) === 0) {
211
+ logWarning("recovery", `verify-fail ${unitType} ${unitId}: roadmap has zero slices at ${path}`);
212
+ return false;
213
+ }
214
+ return true;
215
+ } catch (err) {
216
+ logWarning("recovery", `plan-milestone roadmap verification failed: ${err instanceof Error ? err.message : String(err)}`);
217
+ return false;
218
+ }
219
+ }
220
+
182
221
  /**
183
222
  * Scope-based overload of resolveExpectedArtifactPath.
184
223
  * Returns the canonical absolute path (or null) using the scope's projectRoot.
@@ -188,6 +227,10 @@ export function resolveExpectedArtifactPathForScope(
188
227
  unitType: string,
189
228
  unitId: string,
190
229
  ): string | null {
230
+ if (unitId === scope.milestoneId) {
231
+ if (unitType === "discuss-milestone") return scope.contextFile();
232
+ if (unitType === "plan-milestone") return scope.roadmapFile();
233
+ }
191
234
  return resolveExpectedArtifactPath(unitType, unitId, scope.workspace.projectRoot);
192
235
  }
193
236
 
@@ -570,7 +613,7 @@ interface DispatchWorkflowOptions {
570
613
  deps?: {
571
614
  loadPreferences?: typeof loadEffectiveGSDPreferences;
572
615
  selectModel?: typeof selectAndApplyModel;
573
- getDispatchReadinessError?: typeof getUnitWorkflowDispatchReadinessError;
616
+ getDispatchReadinessError?: typeof getUnitWorkflowDispatchReadinessErrorForModel;
574
617
  };
575
618
  }
576
619
 
@@ -687,7 +730,7 @@ async function dispatchWorkflow(
687
730
  const loadPreferences = resolvedOptions.deps?.loadPreferences ?? loadEffectiveGSDPreferences;
688
731
  const selectModel = resolvedOptions.deps?.selectModel ?? selectAndApplyModel;
689
732
  const getDispatchReadinessError = resolvedOptions.deps?.getDispatchReadinessError
690
- ?? getUnitWorkflowDispatchReadinessError;
733
+ ?? getUnitWorkflowDispatchReadinessErrorForModel;
691
734
 
692
735
  // Route through the dynamic routing pipeline (complexity classification,
693
736
  // tier downgrade, fallback chains) — same path as auto-mode dispatches (#2958).
@@ -707,16 +750,12 @@ async function dispatchWorkflow(
707
750
  }
708
751
 
709
752
  const compatibilityError = getDispatchReadinessError({
710
- provider: result.appliedModel?.provider ?? ctx.model?.provider,
753
+ model: result.appliedModel,
754
+ fallbackModel: ctx.model,
755
+ getProviderAuthMode: (provider) => ctx.modelRegistry.getProviderAuthMode(provider),
711
756
  projectRoot,
712
757
  surface: "guided flow",
713
758
  unitType,
714
- authMode: result.appliedModel?.provider
715
- ? ctx.modelRegistry.getProviderAuthMode(result.appliedModel.provider)
716
- : ctx.model?.provider
717
- ? ctx.modelRegistry.getProviderAuthMode(ctx.model.provider)
718
- : undefined,
719
- baseUrl: result.appliedModel?.baseUrl ?? ctx.model?.baseUrl,
720
759
  // Guided flow starts the MCP workflow server as part of dispatch, so the
721
760
  // parent session's activeTools doesn't include MCP tools yet. The MCP
722
761
  // launch config check (detectWorkflowMcpLaunchConfig) is the right gate
@@ -882,7 +921,7 @@ function resolveAvailableModel<T extends { id: string; provider: string }>(
882
921
  * Build the discuss-and-plan prompt for a new milestone.
883
922
  * Used by all three "new milestone" paths (first ever, no active, all complete).
884
923
  */
885
- function buildDiscussPrompt(nextId: string, preamble: string, _basePath: string, pi: ExtensionAPI, ctx: ExtensionCommandContext, preparationContext?: string): string {
924
+ function buildDiscussPrompt(nextId: string, preamble: string, basePath: string, pi: ExtensionAPI, ctx: ExtensionCommandContext, preparationContext?: string): string {
886
925
  const milestoneRel = `.gsd/milestones/${nextId}`;
887
926
  const structuredQuestionsAvailable = getStructuredQuestionsAvailability(pi, ctx);
888
927
  const inlinedTemplates = [
@@ -892,7 +931,7 @@ function buildDiscussPrompt(nextId: string, preamble: string, _basePath: string,
892
931
  inlineTemplate("roadmap", "Roadmap"),
893
932
  inlineTemplate("decisions", "Decisions"),
894
933
  ].join("\n\n---\n\n");
895
- return loadPrompt("discuss", {
934
+ return prependLanguageDirective(basePath, loadPrompt("discuss", {
896
935
  milestoneId: nextId,
897
936
  preamble,
898
937
  preparationContext: preparationContext ?? "",
@@ -902,14 +941,26 @@ function buildDiscussPrompt(nextId: string, preamble: string, _basePath: string,
902
941
  inlinedTemplates,
903
942
  commitInstruction: buildDocsCommitInstruction(`docs(${nextId}): context, requirements, and roadmap`),
904
943
  multiMilestoneCommitInstruction: buildDocsCommitInstruction("docs: project plan — N milestones"),
905
- });
944
+ }));
945
+ }
946
+
947
+ /**
948
+ * Prepend the configured response-language directive to a dispatched discuss
949
+ * prompt so the discuss/QA conversation is held in the language set in
950
+ * PREFERENCES.md (#1210). No-op when no language is configured.
951
+ */
952
+ function prependLanguageDirective(basePath: string, prompt: string): string {
953
+ const directive = renderLanguageDirectiveForPrompt(
954
+ loadEffectiveGSDPreferences(basePath)?.preferences,
955
+ );
956
+ return directive ? `${directive}\n\n${prompt}` : prompt;
906
957
  }
907
958
 
908
959
  /**
909
960
  * Build the discuss prompt for headless milestone creation.
910
961
  * Uses the discuss-headless prompt template with seed context injected.
911
962
  */
912
- function buildHeadlessDiscussPrompt(nextId: string, seedContext: string, _basePath: string): string {
963
+ function buildHeadlessDiscussPrompt(nextId: string, seedContext: string, basePath: string): string {
913
964
  const milestoneRel = `.gsd/milestones/${nextId}`;
914
965
  const inlinedTemplates = [
915
966
  inlineTemplate("project", "Project"),
@@ -918,7 +969,7 @@ function buildHeadlessDiscussPrompt(nextId: string, seedContext: string, _basePa
918
969
  inlineTemplate("roadmap", "Roadmap"),
919
970
  inlineTemplate("decisions", "Decisions"),
920
971
  ].join("\n\n---\n\n");
921
- return loadPrompt("discuss-headless", {
972
+ return prependLanguageDirective(basePath, loadPrompt("discuss-headless", {
922
973
  milestoneId: nextId,
923
974
  seedContext,
924
975
  contextPath: `${milestoneRel}/${nextId}-CONTEXT.md`,
@@ -926,7 +977,7 @@ function buildHeadlessDiscussPrompt(nextId: string, seedContext: string, _basePa
926
977
  inlinedTemplates,
927
978
  commitInstruction: buildDocsCommitInstruction(`docs(${nextId}): context, requirements, and roadmap`),
928
979
  multiMilestoneCommitInstruction: buildDocsCommitInstruction("docs: project plan — N milestones"),
929
- });
980
+ }));
930
981
  }
931
982
 
932
983
  /**
@@ -43,6 +43,7 @@ export const PROVIDER_REGISTRY: ProviderInfo[] = [
43
43
  // must be in the canonical registry so all consumers see the same catalog.
44
44
  // See: https://github.com/open-gsd/gsd-pi/issues/4541
45
45
  { id: "claude-code", label: "Claude Code CLI", category: "llm", authMode: "externalCli" },
46
+ { id: "cursor-agent", label: "Cursor Agent", category: "llm", envVar: "CURSOR_API_KEY", authMode: "externalCli" },
46
47
  { id: "openai", label: "OpenAI", category: "llm", envVar: "OPENAI_API_KEY", prefixes: ["sk-"], dashboardUrl: "platform.openai.com/api-keys" },
47
48
  { id: "github-copilot", label: "GitHub Copilot", category: "llm", envVar: "GITHUB_TOKEN", authMode: "browserOAuth" },
48
49
  { id: "openai-codex", label: "ChatGPT Plus/Pro (Codex)",category: "llm", authMode: "browserOAuth" },
@@ -20,6 +20,7 @@ import {
20
20
  getSliceScopedArtifacts,
21
21
  getMilestoneSlices,
22
22
  getSliceTasks,
23
+ getTasksBySliceIds,
23
24
  getTask,
24
25
  getSlice,
25
26
  insertArtifact,
@@ -136,6 +137,12 @@ function meaningfulSection(value: string | null | undefined): string {
136
137
  return trimmed;
137
138
  }
138
139
 
140
+ function renderGateFindings(gate: GateRow): string {
141
+ const findings = gate.findings.trim() || `- **Verdict:** ${gate.verdict}\n- **Rationale:** ${gate.rationale}`;
142
+ if (gate.verdict !== "flag") return findings;
143
+ return `> **Warning:** Verdict: flag - concerns recorded below\n\n${findings}`;
144
+ }
145
+
139
146
  function pushIndented(lines: string[], value: string, indent = " "): void {
140
147
  for (const line of value.split("\n")) {
141
148
  lines.push(`${indent}${line}`);
@@ -356,7 +363,7 @@ function renderTaskPlanMarkdown(task: TaskRow, taskGates: GateRow[] = []): strin
356
363
  if (gate && gate.verdict !== "omitted") {
357
364
  lines.push(`## ${label}`);
358
365
  lines.push("");
359
- lines.push(gate.findings.trim() || `- **Verdict:** ${gate.verdict}\n- **Rationale:** ${gate.rationale}`);
366
+ lines.push(renderGateFindings(gate));
360
367
  lines.push("");
361
368
  }
362
369
  }
@@ -390,7 +397,7 @@ function renderSlicePlanMarkdown(slice: SliceRow, tasks: TaskRow[], gates: GateR
390
397
  if (q3 && q3.verdict !== "omitted") {
391
398
  lines.push("## Threat Surface");
392
399
  lines.push("");
393
- lines.push(q3.findings.trim() || `- **Verdict:** ${q3.verdict}\n- **Rationale:** ${q3.rationale}`);
400
+ lines.push(renderGateFindings(q3));
394
401
  lines.push("");
395
402
  }
396
403
 
@@ -398,7 +405,7 @@ function renderSlicePlanMarkdown(slice: SliceRow, tasks: TaskRow[], gates: GateR
398
405
  if (q4 && q4.verdict !== "omitted") {
399
406
  lines.push("## Requirement Impact");
400
407
  lines.push("");
401
- lines.push(q4.findings.trim() || `- **Verdict:** ${q4.verdict}\n- **Rationale:** ${q4.rationale}`);
408
+ lines.push(renderGateFindings(q4));
402
409
  lines.push("");
403
410
  }
404
411
 
@@ -876,6 +883,17 @@ export async function renderAllFromDb(basePath: string): Promise<RenderAllResult
876
883
  const result: RenderAllResult = { rendered: 0, skipped: 0, errors: [] };
877
884
  const milestones = getAllMilestones();
878
885
 
886
+ // Pre-fetch slices once per milestone and batch-load all tasks in one query
887
+ // family, avoiding an N+1 (previously one task query per slice).
888
+ const slicesByMilestone = new Map<string, SliceRow[]>();
889
+ const slicePairs: Array<{ milestoneId: string; sliceId: string }> = [];
890
+ for (const milestone of milestones) {
891
+ const slices = getMilestoneSlices(milestone.id);
892
+ slicesByMilestone.set(milestone.id, slices);
893
+ for (const slice of slices) slicePairs.push({ milestoneId: milestone.id, sliceId: slice.id });
894
+ }
895
+ const tasksBySlice = getTasksBySliceIds(slicePairs);
896
+
879
897
  for (const milestone of milestones) {
880
898
  // Render roadmap checkboxes
881
899
  try {
@@ -894,8 +912,8 @@ export async function renderAllFromDb(basePath: string): Promise<RenderAllResult
894
912
  result.errors.push(`milestone artifacts ${milestone.id}: ${(err as Error).message}`);
895
913
  }
896
914
 
897
- // Iterate slices
898
- const slices = getMilestoneSlices(milestone.id);
915
+ // Iterate slices (pre-fetched above)
916
+ const slices = slicesByMilestone.get(milestone.id) ?? [];
899
917
  for (const slice of slices) {
900
918
  // Preserve slice-scoped artifacts imported from disk, including real PLAN
901
919
  // fallback content when task rows cannot regenerate it.
@@ -931,8 +949,8 @@ export async function renderAllFromDb(basePath: string): Promise<RenderAllResult
931
949
  );
932
950
  }
933
951
 
934
- // Iterate tasks
935
- const tasks = getSliceTasks(milestone.id, slice.id);
952
+ // Iterate tasks (batched above)
953
+ const tasks = tasksBySlice.get(`${milestone.id}\0${slice.id}`) ?? [];
936
954
  for (const task of tasks) {
937
955
  try {
938
956
  const ok = await renderTaskSummary(
@@ -1281,9 +1299,21 @@ export async function renderAssessmentFromDb(
1281
1299
  sliceId: string,
1282
1300
  assessmentData: AssessmentData,
1283
1301
  ): Promise<{ assessmentPath: string; content: string }> {
1284
- // Flat-phase: assessment file lives in the phase dir
1285
- const slicePath = resolveSlicePath(basePath, milestoneId, sliceId)
1286
- ?? join(milestonesDir(basePath), canonicalPhaseDirName(milestoneId, getMilestone(milestoneId)?.title));
1302
+ // Flat-phase: the assessment file lives in the phase dir, NOT in a slices/SID/
1303
+ // subdir. resolveSlicePath() detects a slices/SID/ dir unconditionally, so a
1304
+ // stray slices/SID/ created by an earlier planning step would send this write
1305
+ // to a hybrid path (wrong dir, flat filename) that verification cannot find.
1306
+ // Guard with the same legacy-base check relSlicePath() uses so flat-phase
1307
+ // milestones always target the phase dir.
1308
+ const mDir = resolveMilestonePath(basePath, milestoneId);
1309
+ const legacyBase = legacyMilestonesDir(basePath);
1310
+ const isLegacyLayout = mDir
1311
+ ? mDir.startsWith(legacyBase + "/") || mDir.startsWith(legacyBase + "\\")
1312
+ : false;
1313
+ const fallbackDir = join(milestonesDir(basePath), canonicalPhaseDirName(milestoneId, getMilestone(milestoneId)?.title));
1314
+ const slicePath = isLegacyLayout
1315
+ ? (resolveSlicePath(basePath, milestoneId, sliceId) ?? fallbackDir)
1316
+ : (mDir ?? fallbackDir);
1287
1317
  const phaseNum = milestoneIdToPhaseNum(milestoneId);
1288
1318
  const planNum = sliceIdToPlanNum(sliceId);
1289
1319
  const absPath = join(slicePath, planFileName(phaseNum, planNum, "ASSESSMENT"));
@@ -5,7 +5,7 @@
5
5
  // Exports: parseDecisionsTable, parseRequirementsSections, migrateFromMarkdown
6
6
 
7
7
  import { readFileSync, readdirSync, existsSync, statSync } from 'node:fs';
8
- import { join, relative, basename } from 'node:path';
8
+ import { join, relative, basename, dirname } from 'node:path';
9
9
  import type { Decision, Requirement } from './types.js';
10
10
  import {
11
11
  upsertDecision,
@@ -24,6 +24,7 @@ import {
24
24
  resolveGsdRootFile,
25
25
  resolveMilestoneFile,
26
26
  resolveSliceFile,
27
+ resolveSlicePath,
27
28
  resolveTasksDir,
28
29
  legacyMilestonesDir,
29
30
  gsdRoot,
@@ -33,7 +34,7 @@ import {
33
34
  import { findMilestoneIds } from './guided-flow.js';
34
35
  import { milestoneIdToPhaseNum } from './layout-policy.js';
35
36
  import { parseRoadmap, parsePlan } from './parsers-legacy.js';
36
- import { parseContextDependsOn } from './files.js';
37
+ import { parseContextDependsOn, parseSummary } from './files.js';
37
38
  import { logWarning } from './workflow-logger.js';
38
39
 
39
40
  // ─── DECISIONS.md Parser ───────────────────────────────────────────────────
@@ -816,23 +817,68 @@ export function migrateHierarchyToDb(basePath: string): {
816
817
  // Per K002: use 'complete' not 'done'
817
818
  let taskStatus: string = taskEntry.done ? 'complete' : 'pending';
818
819
 
819
- // Pre-migration consistency (legacy layout only): if a task is marked
820
- // done but has no per-task SUMMARY.md, import it as pending so it gets
821
- // re-executed rather than silently entering the DB as complete.
822
- // Flat-phase has no per-task summary files by design the checkbox
823
- // state is the authoritative completion signal and is imported as-is.
824
- if (taskStatus === 'complete') {
825
- const tDir = resolveTasksDir(basePath, milestoneId, sliceEntry.id);
826
- if (tDir) {
827
- const summaryFile = join(tDir, `${taskEntry.id}-SUMMARY.md`);
828
- if (!existsSync(summaryFile)) {
829
- taskStatus = 'pending';
830
- process.stderr.write(
831
- `gsd-migrate: ${milestoneId}/${sliceEntry.id}/${taskEntry.id} marked done but missing summary importing as pending\n`,
832
- );
833
- }
820
+ // Resolve the per-task SUMMARY.md. Legacy layout keeps summaries under
821
+ // a tasks/ subdir; flat-phase writes TID-SUMMARY.md directly in the
822
+ // phase dir (execute-task's gsd_task_complete writes it there). A tasks/
823
+ // subdir may still exist in flat-phase for auxiliary artifactsits
824
+ // mere existence must NOT redirect summary resolution into tasks/ (#1208).
825
+ const slicePath = resolveSlicePath(basePath, milestoneId, sliceEntry.id);
826
+ let taskSummaryFile: string | null = null;
827
+ let isLegacySlice = false;
828
+ // Legacy layout keeps per-task summaries under a tasks/ subdir. Its
829
+ // presence — not merely "is this a legacy slice" — is what makes a
830
+ // missing summary a downgrade signal. resolveTasksDir returns null when
831
+ // no such dir exists, so a legacy slice whose checkbox is the only
832
+ // completion signal (no tasks/ dir at all) is left complete on import.
833
+ let legacyTasksDir: string | null = null;
834
+ if (slicePath) {
835
+ isLegacySlice = basename(dirname(slicePath)) === 'slices';
836
+ legacyTasksDir = isLegacySlice
837
+ ? resolveTasksDir(basePath, milestoneId, sliceEntry.id)
838
+ : null;
839
+ const summaryDir = legacyTasksDir ?? slicePath;
840
+ taskSummaryFile = join(summaryDir, `${taskEntry.id}-SUMMARY.md`);
841
+ }
842
+ const hasTaskSummary = taskSummaryFile !== null && existsSync(taskSummaryFile);
843
+
844
+ // Pre-migration consistency (legacy tasks/ layout only): if a task is
845
+ // marked done but its tasks/ dir has no per-task SUMMARY.md, import it
846
+ // as pending so it gets re-executed rather than silently entering the DB
847
+ // as complete. A legacy slice with no tasks/ dir (checkbox-only
848
+ // completion) and flat-phase layout are both left as-is here.
849
+ if (taskStatus === 'complete' && legacyTasksDir !== null && !hasTaskSummary) {
850
+ taskStatus = 'pending';
851
+ process.stderr.write(
852
+ `gsd-migrate: ${milestoneId}/${sliceEntry.id}/${taskEntry.id} marked done but missing summary — importing as pending\n`,
853
+ );
854
+ }
855
+
856
+ // Lost-update guard (#1222): a per-task SUMMARY.md is the durable
857
+ // completion attestation written by gsd_task_complete. When the plan
858
+ // checkbox is stale-unchecked but the SUMMARY exists on disk, a
859
+ // re-import must NOT downgrade the completed task back to pending — that
860
+ // silent revert is the lost-update that hard-stopped auto-mode after the
861
+ // first execute-task. The surviving SUMMARY wins over a stale checkbox.
862
+ // reopen-task removes the SUMMARY, so this never re-completes an
863
+ // intentionally reopened task.
864
+ // Flat-phase summaries are phase-scoped (T01-SUMMARY.md); when a milestone
865
+ // has multiple slices, require the summary parent frontmatter to match so
866
+ // one slice's completion does not attest a sibling's same-named task.
867
+ let summaryAttestsCompletion = hasTaskSummary;
868
+ if (summaryAttestsCompletion && !isLegacySlice && roadmap.slices.length > 1 && taskSummaryFile) {
869
+ try {
870
+ const summaryContent = readFileSync(taskSummaryFile, 'utf-8');
871
+ summaryAttestsCompletion = parseSummary(summaryContent).frontmatter.parent === sliceEntry.id;
872
+ } catch {
873
+ summaryAttestsCompletion = false;
834
874
  }
835
875
  }
876
+ if (taskStatus === 'pending' && summaryAttestsCompletion) {
877
+ taskStatus = 'complete';
878
+ process.stderr.write(
879
+ `gsd-migrate: ${milestoneId}/${sliceEntry.id}/${taskEntry.id} unchecked in plan but SUMMARY.md present — importing as complete (#1222)\n`,
880
+ );
881
+ }
836
882
 
837
883
  insertTask({
838
884
  id: taskEntry.id,
@@ -844,6 +890,12 @@ export function migrateHierarchyToDb(basePath: string): {
844
890
  files: taskEntry.files ?? [],
845
891
  verify: taskEntry.verify ?? '',
846
892
  },
893
+ // #1222 (metadata half): re-import derives status from the plan/summary
894
+ // but has none of the execution prose gsd_task_complete wrote to the DB.
895
+ // Preserve the existing row's execution columns and completed_at so a
896
+ // re-import cannot blank a completed task's summary metadata or refresh
897
+ // its completion timestamp — the DB row is strictly richer than the plan.
898
+ preserveCompletionMetadata: true,
847
899
  });
848
900
  counts.tasks++;
849
901
  }
@@ -857,12 +909,31 @@ export function migrateHierarchyToDb(basePath: string): {
857
909
  if (!sliceEntry.done) {
858
910
  const sliceSummaryPath = resolveSliceFile(basePath, milestoneId, sliceEntry.id, 'SUMMARY');
859
911
  const hasSliceSummary = sliceSummaryPath !== null && existsSync(sliceSummaryPath);
912
+ const slicePathForTasks = resolveSlicePath(basePath, milestoneId, sliceEntry.id);
913
+ const isLegacySliceLayout = slicePathForTasks !== null
914
+ && basename(dirname(slicePathForTasks)) === 'slices';
915
+ const taskSummaryDir = slicePathForTasks
916
+ ? (isLegacySliceLayout
917
+ ? (resolveTasksDir(basePath, milestoneId, sliceEntry.id) ?? slicePathForTasks)
918
+ : slicePathForTasks)
919
+ : null;
860
920
  const allTasksDone = plan.tasks.length > 0 && plan.tasks.every(t => {
861
- if (!t.done) return false;
862
- const tDir = resolveTasksDir(basePath, milestoneId, sliceEntry.id);
863
- // Flat-phase has no per-task summary files — checkbox state is authoritative.
864
- if (!tDir) return true;
865
- return existsSync(join(tDir, `${t.id}-SUMMARY.md`));
921
+ const taskSummaryFile = taskSummaryDir !== null
922
+ ? join(taskSummaryDir, `${t.id}-SUMMARY.md`)
923
+ : null;
924
+ const hasTaskSummary = taskSummaryFile !== null && existsSync(taskSummaryFile);
925
+ let summaryAttestsCompletion = hasTaskSummary;
926
+ if (summaryAttestsCompletion && !isLegacySliceLayout && roadmap.slices.length > 1 && taskSummaryFile) {
927
+ try {
928
+ const summaryContent = readFileSync(taskSummaryFile, 'utf-8');
929
+ summaryAttestsCompletion = parseSummary(summaryContent).frontmatter.parent === sliceEntry.id;
930
+ } catch {
931
+ summaryAttestsCompletion = false;
932
+ }
933
+ }
934
+ // Match per-task import rules above: SUMMARY attestation wins over a stale
935
+ // checkbox (#1222); flat-phase checkboxes are authoritative without summary.
936
+ return summaryAttestsCompletion || (t.done && !isLegacySliceLayout);
866
937
  });
867
938
  if (allTasksDone && hasSliceSummary) {
868
939
  if (_getAdapter()) {