@opengsd/gsd-pi 1.1.1-dev.9f86580 → 1.1.1-dev.b2556262

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 (261) hide show
  1. package/dist/headless-recover.js +56 -1
  2. package/dist/resources/.managed-resources-content-hash +1 -1
  3. package/dist/resources/extensions/browser-tools/index.js +39 -22
  4. package/dist/resources/extensions/browser-tools/state.js +12 -0
  5. package/dist/resources/extensions/browser-tools/tools/session.js +3 -2
  6. package/dist/resources/extensions/browser-tools/utils.js +3 -3
  7. package/dist/resources/extensions/gsd/auto/loop.js +4 -2
  8. package/dist/resources/extensions/gsd/auto/phases.js +43 -10
  9. package/dist/resources/extensions/gsd/auto/session.js +20 -1
  10. package/dist/resources/extensions/gsd/auto/workflow-kernel.js +1 -0
  11. package/dist/resources/extensions/gsd/auto-dispatch.js +72 -12
  12. package/dist/resources/extensions/gsd/auto-model-selection.js +128 -9
  13. package/dist/resources/extensions/gsd/auto-post-unit.js +19 -2
  14. package/dist/resources/extensions/gsd/auto-prompts.js +24 -19
  15. package/dist/resources/extensions/gsd/auto-recovery.js +4 -2
  16. package/dist/resources/extensions/gsd/auto-runtime-state.js +3 -0
  17. package/dist/resources/extensions/gsd/auto-start.js +1 -1
  18. package/dist/resources/extensions/gsd/auto.js +14 -11
  19. package/dist/resources/extensions/gsd/bootstrap/db-tools.js +3 -3
  20. package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +172 -65
  21. package/dist/resources/extensions/gsd/closeout-wizard.js +32 -9
  22. package/dist/resources/extensions/gsd/commands/handlers/ops.js +2 -9
  23. package/dist/resources/extensions/gsd/commands-maintenance.js +93 -15
  24. package/dist/resources/extensions/gsd/commands-prefs-wizard.js +2 -2
  25. package/dist/resources/extensions/gsd/db-writer.js +35 -0
  26. package/dist/resources/extensions/gsd/docs/preferences-reference.md +50 -1
  27. package/dist/resources/extensions/gsd/gsd-db.js +480 -172
  28. package/dist/resources/extensions/gsd/markdown-renderer.js +37 -53
  29. package/dist/resources/extensions/gsd/md-importer.js +38 -3
  30. package/dist/resources/extensions/gsd/migration-auto-check.js +126 -31
  31. package/dist/resources/extensions/gsd/parsers-legacy.js +23 -0
  32. package/dist/resources/extensions/gsd/planning-path-scope.js +22 -4
  33. package/dist/resources/extensions/gsd/pre-execution-checks.js +10 -2
  34. package/dist/resources/extensions/gsd/preferences-models.js +110 -43
  35. package/dist/resources/extensions/gsd/preferences-types.js +13 -0
  36. package/dist/resources/extensions/gsd/preferences-validation.js +68 -3
  37. package/dist/resources/extensions/gsd/preferences.js +4 -1
  38. package/dist/resources/extensions/gsd/prompts/gate-evaluate.md +1 -1
  39. package/dist/resources/extensions/gsd/prompts/plan-slice.md +1 -1
  40. package/dist/resources/extensions/gsd/prompts/refine-slice.md +1 -1
  41. package/dist/resources/extensions/gsd/roadmap-slices.js +5 -1
  42. package/dist/resources/extensions/gsd/safety/content-validator.js +6 -4
  43. package/dist/resources/extensions/gsd/source-observations.js +306 -0
  44. package/dist/resources/extensions/gsd/state-reconciliation/drift/completion.js +15 -8
  45. package/dist/resources/extensions/gsd/state-reconciliation/drift/stale-render.js +33 -5
  46. package/dist/resources/extensions/gsd/state-reconciliation/drift/stale-worker.js +34 -13
  47. package/dist/resources/extensions/gsd/state-reconciliation/index.js +39 -14
  48. package/dist/resources/extensions/gsd/state-reconciliation/spawn-gate.js +4 -4
  49. package/dist/resources/extensions/gsd/state.js +7 -3
  50. package/dist/resources/extensions/gsd/tool-contract.js +14 -0
  51. package/dist/resources/extensions/gsd/tool-presentation-plan.js +1 -9
  52. package/dist/resources/extensions/gsd/tools/complete-slice.js +7 -6
  53. package/dist/resources/extensions/gsd/tools/plan-slice.js +42 -11
  54. package/dist/resources/extensions/gsd/tools/plan-task.js +7 -1
  55. package/dist/resources/extensions/gsd/tools/workflow-tool-executors.js +57 -429
  56. package/dist/resources/extensions/gsd/uat-policy.js +130 -0
  57. package/dist/resources/extensions/gsd/uat-run.js +414 -0
  58. package/dist/resources/extensions/gsd/unit-context-manifest.js +3 -4
  59. package/dist/resources/extensions/gsd/verdict-parser.js +3 -8
  60. package/dist/resources/extensions/gsd/workflow-manifest.js +132 -5
  61. package/dist/resources/extensions/gsd/workflow-projections.js +8 -0
  62. package/dist/resources/extensions/gsd/worktree-state-projection.js +18 -17
  63. package/dist/resources/extensions/subagent/agents.js +1 -0
  64. package/dist/resources/extensions/subagent/index.js +27 -12
  65. package/dist/resources/extensions/subagent/launch.js +7 -2
  66. package/dist/web/standalone/.next/BUILD_ID +1 -1
  67. package/dist/web/standalone/.next/app-path-routes-manifest.json +8 -8
  68. package/dist/web/standalone/.next/build-manifest.json +2 -2
  69. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  70. package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
  71. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  72. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  73. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  74. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  75. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  76. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  77. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  78. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  79. package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
  80. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
  81. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  82. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
  83. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  84. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  85. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  86. package/dist/web/standalone/.next/server/app/index.html +1 -1
  87. package/dist/web/standalone/.next/server/app/index.rsc +1 -1
  88. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
  89. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +1 -1
  90. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  91. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
  92. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  93. package/dist/web/standalone/.next/server/app-paths-manifest.json +8 -8
  94. package/dist/web/standalone/.next/server/chunks/8357.js +1 -1
  95. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  96. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  97. package/dist/web/standalone/.next/server/pages/500.html +1 -1
  98. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  99. package/dist/web/standalone/node_modules/@gsd/native/dist/native.js +22 -0
  100. package/dist/web/standalone/node_modules/node-pty/build/Makefile +1 -1
  101. package/package.json +4 -4
  102. package/packages/cloud-mcp-gateway/package.json +2 -2
  103. package/packages/contracts/package.json +1 -1
  104. package/packages/daemon/package.json +4 -4
  105. package/packages/gsd-agent-core/package.json +5 -5
  106. package/packages/gsd-agent-modes/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
  107. package/packages/gsd-agent-modes/dist/modes/interactive/components/assistant-message.js +21 -23
  108. package/packages/gsd-agent-modes/dist/modes/interactive/components/assistant-message.js.map +1 -1
  109. package/packages/gsd-agent-modes/dist/modes/interactive/components/tool-execution.d.ts +3 -0
  110. package/packages/gsd-agent-modes/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  111. package/packages/gsd-agent-modes/dist/modes/interactive/components/tool-execution.js +25 -0
  112. package/packages/gsd-agent-modes/dist/modes/interactive/components/tool-execution.js.map +1 -1
  113. package/packages/gsd-agent-modes/dist/modes/interactive/components/transcript-design.d.ts +1 -0
  114. package/packages/gsd-agent-modes/dist/modes/interactive/components/transcript-design.d.ts.map +1 -1
  115. package/packages/gsd-agent-modes/dist/modes/interactive/components/transcript-design.js +66 -12
  116. package/packages/gsd-agent-modes/dist/modes/interactive/components/transcript-design.js.map +1 -1
  117. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.d.ts.map +1 -1
  118. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.js +18 -11
  119. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.js.map +1 -1
  120. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-chat-render.d.ts.map +1 -1
  121. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-chat-render.js +16 -0
  122. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-chat-render.js.map +1 -1
  123. package/packages/gsd-agent-modes/package.json +7 -7
  124. package/packages/mcp-server/dist/workflow-tools.js +1 -1
  125. package/packages/mcp-server/dist/workflow-tools.js.map +1 -1
  126. package/packages/mcp-server/package.json +3 -3
  127. package/packages/native/dist/native.js +22 -0
  128. package/packages/native/package.json +1 -1
  129. package/packages/pi-agent-core/package.json +1 -1
  130. package/packages/pi-ai/dist/image-models.generated.d.ts +30 -0
  131. package/packages/pi-ai/dist/image-models.generated.d.ts.map +1 -1
  132. package/packages/pi-ai/dist/image-models.generated.js +30 -0
  133. package/packages/pi-ai/dist/image-models.generated.js.map +1 -1
  134. package/packages/pi-ai/dist/models.generated.d.ts +23 -17
  135. package/packages/pi-ai/dist/models.generated.d.ts.map +1 -1
  136. package/packages/pi-ai/dist/models.generated.js +25 -24
  137. package/packages/pi-ai/dist/models.generated.js.map +1 -1
  138. package/packages/pi-ai/package.json +1 -1
  139. package/packages/pi-coding-agent/dist/core/settings-manager.js +1 -1
  140. package/packages/pi-coding-agent/dist/core/settings-manager.js.map +1 -1
  141. package/packages/pi-coding-agent/dist/theme/themes.js +1 -1
  142. package/packages/pi-coding-agent/dist/theme/themes.js.map +1 -1
  143. package/packages/pi-coding-agent/package.json +7 -7
  144. package/packages/pi-tui/dist/utils.d.ts +11 -0
  145. package/packages/pi-tui/dist/utils.d.ts.map +1 -1
  146. package/packages/pi-tui/dist/utils.js +119 -6
  147. package/packages/pi-tui/dist/utils.js.map +1 -1
  148. package/packages/pi-tui/package.json +2 -1
  149. package/packages/rpc-client/package.json +2 -2
  150. package/pkg/dist/theme/themes.js +1 -1
  151. package/pkg/dist/theme/themes.js.map +1 -1
  152. package/pkg/package.json +1 -1
  153. package/src/resources/extensions/browser-tools/index.ts +39 -22
  154. package/src/resources/extensions/browser-tools/state.ts +13 -0
  155. package/src/resources/extensions/browser-tools/tests/browser-tools-unit.test.cjs +57 -0
  156. package/src/resources/extensions/browser-tools/tools/session.ts +4 -2
  157. package/src/resources/extensions/browser-tools/utils.ts +3 -3
  158. package/src/resources/extensions/gsd/auto/loop-deps.ts +1 -0
  159. package/src/resources/extensions/gsd/auto/loop.ts +4 -2
  160. package/src/resources/extensions/gsd/auto/phases.ts +42 -10
  161. package/src/resources/extensions/gsd/auto/session.ts +22 -1
  162. package/src/resources/extensions/gsd/auto/workflow-kernel.ts +1 -0
  163. package/src/resources/extensions/gsd/auto-dispatch.ts +85 -12
  164. package/src/resources/extensions/gsd/auto-model-selection.ts +164 -12
  165. package/src/resources/extensions/gsd/auto-post-unit.ts +20 -2
  166. package/src/resources/extensions/gsd/auto-prompts.ts +23 -20
  167. package/src/resources/extensions/gsd/auto-recovery.ts +22 -3
  168. package/src/resources/extensions/gsd/auto-runtime-state.ts +5 -0
  169. package/src/resources/extensions/gsd/auto-start.ts +1 -1
  170. package/src/resources/extensions/gsd/auto.ts +13 -10
  171. package/src/resources/extensions/gsd/bootstrap/db-tools.ts +3 -3
  172. package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +225 -72
  173. package/src/resources/extensions/gsd/closeout-wizard.ts +47 -13
  174. package/src/resources/extensions/gsd/commands/handlers/ops.ts +2 -17
  175. package/src/resources/extensions/gsd/commands-maintenance.ts +124 -13
  176. package/src/resources/extensions/gsd/commands-prefs-wizard.ts +2 -2
  177. package/src/resources/extensions/gsd/db-writer.ts +38 -0
  178. package/src/resources/extensions/gsd/docs/preferences-reference.md +50 -1
  179. package/src/resources/extensions/gsd/gsd-db.ts +564 -186
  180. package/src/resources/extensions/gsd/markdown-renderer.ts +44 -66
  181. package/src/resources/extensions/gsd/md-importer.ts +49 -2
  182. package/src/resources/extensions/gsd/migration-auto-check.ts +154 -34
  183. package/src/resources/extensions/gsd/parsers-legacy.ts +20 -0
  184. package/src/resources/extensions/gsd/planning-path-scope.ts +22 -4
  185. package/src/resources/extensions/gsd/pre-execution-checks.ts +9 -2
  186. package/src/resources/extensions/gsd/preferences-models.ts +112 -43
  187. package/src/resources/extensions/gsd/preferences-types.ts +39 -0
  188. package/src/resources/extensions/gsd/preferences-validation.ts +76 -2
  189. package/src/resources/extensions/gsd/preferences.ts +5 -0
  190. package/src/resources/extensions/gsd/prompts/gate-evaluate.md +1 -1
  191. package/src/resources/extensions/gsd/prompts/plan-slice.md +1 -1
  192. package/src/resources/extensions/gsd/prompts/refine-slice.md +1 -1
  193. package/src/resources/extensions/gsd/roadmap-slices.ts +6 -1
  194. package/src/resources/extensions/gsd/safety/content-validator.ts +8 -5
  195. package/src/resources/extensions/gsd/source-observations.ts +402 -0
  196. package/src/resources/extensions/gsd/state-reconciliation/drift/completion.ts +20 -8
  197. package/src/resources/extensions/gsd/state-reconciliation/drift/stale-render.ts +44 -5
  198. package/src/resources/extensions/gsd/state-reconciliation/drift/stale-worker.ts +39 -11
  199. package/src/resources/extensions/gsd/state-reconciliation/index.ts +45 -15
  200. package/src/resources/extensions/gsd/state-reconciliation/spawn-gate.ts +4 -4
  201. package/src/resources/extensions/gsd/state.ts +7 -4
  202. package/src/resources/extensions/gsd/tests/auto-loop.test.ts +15 -0
  203. package/src/resources/extensions/gsd/tests/auto-model-selection.test.ts +299 -1
  204. package/src/resources/extensions/gsd/tests/auto-paused-ui-cleanup.test.ts +32 -0
  205. package/src/resources/extensions/gsd/tests/auto-phases-lifecycle.test.ts +75 -3
  206. package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +22 -1
  207. package/src/resources/extensions/gsd/tests/before-provider-context-management.test.ts +145 -0
  208. package/src/resources/extensions/gsd/tests/closeout-wizard.test.ts +44 -0
  209. package/src/resources/extensions/gsd/tests/commands-dispatcher-unmerged-milestone.test.ts +26 -1
  210. package/src/resources/extensions/gsd/tests/content-validator.test.ts +74 -0
  211. package/src/resources/extensions/gsd/tests/custom-engine-loop-integration.test.ts +16 -2
  212. package/src/resources/extensions/gsd/tests/doctor-scope-db-unavailable.test.ts +1 -11
  213. package/src/resources/extensions/gsd/tests/gate-dispatch.test.ts +64 -0
  214. package/src/resources/extensions/gsd/tests/gate-storage.test.ts +15 -0
  215. package/src/resources/extensions/gsd/tests/gsd-recover.test.ts +62 -1
  216. package/src/resources/extensions/gsd/tests/journal-integration.test.ts +15 -0
  217. package/src/resources/extensions/gsd/tests/markdown-renderer.test.ts +42 -0
  218. package/src/resources/extensions/gsd/tests/migration-auto-check.test.ts +99 -0
  219. package/src/resources/extensions/gsd/tests/plan-slice.test.ts +99 -2
  220. package/src/resources/extensions/gsd/tests/plan-task.test.ts +19 -0
  221. package/src/resources/extensions/gsd/tests/preferences.test.ts +14 -0
  222. package/src/resources/extensions/gsd/tests/prefs-wizard-coverage.test.ts +1 -0
  223. package/src/resources/extensions/gsd/tests/prompt-contracts.test.ts +9 -0
  224. package/src/resources/extensions/gsd/tests/register-hooks-depth-verification.test.ts +101 -1
  225. package/src/resources/extensions/gsd/tests/repository-registry.test.ts +2 -2
  226. package/src/resources/extensions/gsd/tests/runtime-invariant-modules.test.ts +8 -0
  227. package/src/resources/extensions/gsd/tests/schema-v21-sequence.test.ts +5 -3
  228. package/src/resources/extensions/gsd/tests/schema-v27-v28-sequence.test.ts +162 -18
  229. package/src/resources/extensions/gsd/tests/skipped-validation-db-atomicity.test.ts +8 -0
  230. package/src/resources/extensions/gsd/tests/source-observations.test.ts +275 -0
  231. package/src/resources/extensions/gsd/tests/stale-queued-milestone.test.ts +43 -0
  232. package/src/resources/extensions/gsd/tests/state-reconciliation-drift.test.ts +76 -21
  233. package/src/resources/extensions/gsd/tests/thinking-level-resolution.test.ts +203 -0
  234. package/src/resources/extensions/gsd/tests/uat-policy.test.ts +170 -0
  235. package/src/resources/extensions/gsd/tests/unit-context-manifest.test.ts +7 -1
  236. package/src/resources/extensions/gsd/tests/workflow-kernel.test.ts +7 -0
  237. package/src/resources/extensions/gsd/tests/workflow-manifest.test.ts +306 -1
  238. package/src/resources/extensions/gsd/tests/workflow-tool-executors.test.ts +73 -6
  239. package/src/resources/extensions/gsd/tests/worktree-db.test.ts +511 -1
  240. package/src/resources/extensions/gsd/tests/worktree-state-projection.test.ts +44 -0
  241. package/src/resources/extensions/gsd/tool-contract.ts +28 -0
  242. package/src/resources/extensions/gsd/tool-presentation-plan.ts +1 -11
  243. package/src/resources/extensions/gsd/tools/complete-slice.ts +7 -6
  244. package/src/resources/extensions/gsd/tools/plan-slice.ts +54 -12
  245. package/src/resources/extensions/gsd/tools/plan-task.ts +8 -1
  246. package/src/resources/extensions/gsd/tools/workflow-tool-executors.ts +66 -526
  247. package/src/resources/extensions/gsd/types.ts +1 -0
  248. package/src/resources/extensions/gsd/uat-policy.ts +191 -0
  249. package/src/resources/extensions/gsd/uat-run.ts +550 -0
  250. package/src/resources/extensions/gsd/unit-context-manifest.ts +3 -4
  251. package/src/resources/extensions/gsd/verdict-parser.ts +3 -10
  252. package/src/resources/extensions/gsd/workflow-manifest.ts +193 -7
  253. package/src/resources/extensions/gsd/workflow-projections.ts +9 -0
  254. package/src/resources/extensions/gsd/worktree-state-projection.ts +22 -22
  255. package/src/resources/extensions/shared/tests/format-utils.test.ts +8 -3
  256. package/src/resources/extensions/subagent/agents.ts +4 -0
  257. package/src/resources/extensions/subagent/index.ts +28 -3
  258. package/src/resources/extensions/subagent/launch.ts +8 -0
  259. package/src/resources/extensions/subagent/tests/model-override.test.ts +31 -0
  260. /package/dist/web/standalone/.next/static/{zzYMrKpPGfRQRxSFO32Jr → tJOKQbQRO-9MiFDO8DIDS}/_buildManifest.js +0 -0
  261. /package/dist/web/standalone/.next/static/{zzYMrKpPGfRQRxSFO32Jr → tJOKQbQRO-9MiFDO8DIDS}/_ssgManifest.js +0 -0
@@ -481,6 +481,8 @@ export async function handleCleanupProjects(args: string, ctx: ExtensionCommandC
481
481
  ctx.ui.notify(lines.join("\n"), "info");
482
482
  }
483
483
 
484
+ type HierarchyCounts = { milestones: number; slices: number; tasks: number };
485
+
484
486
  function recoverConfirmed(args: string): boolean {
485
487
  return args
486
488
  .split(/\s+/)
@@ -488,27 +490,82 @@ function recoverConfirmed(args: string): boolean {
488
490
  .some((part) => part === "--confirm" || part === "--yes" || part === "confirm");
489
491
  }
490
492
 
491
- async function confirmRecover(ctx: ExtensionCommandContext, args: string): Promise<boolean> {
492
- if (recoverConfirmed(args)) return true;
493
+ function recoverAllowsDataLoss(args: string): boolean {
494
+ return args
495
+ .split(/\s+/)
496
+ .map((part) => part.trim().toLowerCase())
497
+ .some((part) => part === "--allow-data-loss" || part === "--force");
498
+ }
493
499
 
500
+ async function confirmRecover(
501
+ ctx: ExtensionCommandContext,
502
+ args: string,
503
+ markdown: HierarchyCounts,
504
+ beforeDb: HierarchyCounts,
505
+ dataLoss: boolean,
506
+ ): Promise<boolean> {
494
507
  const warning = [
495
508
  "gsd recover imports markdown into the database.",
496
509
  "It clears and reconstructs milestone, slice, and task hierarchy rows from rendered markdown.",
497
510
  "Use /gsd rebuild markdown for normal DB-to-markdown realignment.",
498
- ].join("\n");
511
+ "",
512
+ ` Markdown on disk: ${markdown.milestones}M/${markdown.slices}S/${markdown.tasks}T`,
513
+ ` Current DB: ${beforeDb.milestones}M/${beforeDb.slices}S/${beforeDb.tasks}T`,
514
+ ];
515
+ if (dataLoss) {
516
+ warning.push(
517
+ "",
518
+ "⚠ The DB holds rows the markdown lacks. Recover will permanently DELETE",
519
+ " those rows. A snapshot is written to .gsd/backups/ first, but if the DB",
520
+ " is the source of truth you almost certainly want /gsd rebuild markdown.",
521
+ );
522
+ }
523
+ const warningText = warning.join("\n");
524
+
525
+ if (recoverConfirmed(args)) {
526
+ // Non-interactive --confirm still refuses a data-loss recover unless the
527
+ // caller explicitly opts in with --allow-data-loss / --force.
528
+ if (dataLoss && !recoverAllowsDataLoss(args)) {
529
+ ctx.ui.notify(
530
+ `${warningText}\n\nRefusing: this would delete authoritative DB rows. Re-run with ` +
531
+ `/gsd recover --confirm --allow-data-loss to proceed, or use /gsd rebuild markdown ` +
532
+ `to re-project markdown from the DB instead.`,
533
+ "error",
534
+ );
535
+ return false;
536
+ }
537
+ return true;
538
+ }
499
539
 
500
540
  if (typeof ctx.ui.confirm === "function") {
501
541
  const confirmed = await ctx.ui.confirm(
502
542
  "Import markdown into the DB?",
503
- `${warning}\n\nContinue only if the DB is lost or corrupt and markdown is the source you intend to import.`,
543
+ `${warningText}\n\nContinue only if the DB is lost or corrupt and markdown is the source you intend to import.`,
504
544
  );
505
- if (confirmed) return true;
506
- ctx.ui.notify("gsd recover cancelled. No database changes made.", "info");
507
- return false;
545
+ if (!confirmed) {
546
+ ctx.ui.notify("gsd recover cancelled. No database changes made.", "info");
547
+ return false;
548
+ }
549
+ // Data loss requires a second, explicit acknowledgement — the interactive
550
+ // equivalent of the --allow-data-loss opt-in the non-interactive paths
551
+ // demand. A single generic "yes" must not silently delete DB rows.
552
+ if (dataLoss) {
553
+ const acknowledged = await ctx.ui.confirm(
554
+ "Permanently delete DB rows the markdown lacks?",
555
+ "This recover will DELETE authoritative DB rows the markdown does not contain. " +
556
+ "A snapshot is saved to .gsd/backups/ first, but /gsd rebuild markdown is usually " +
557
+ "what you want. Proceed with the deletion?",
558
+ );
559
+ if (!acknowledged) {
560
+ ctx.ui.notify("gsd recover cancelled. No database changes made.", "info");
561
+ return false;
562
+ }
563
+ }
564
+ return true;
508
565
  }
509
566
 
510
567
  ctx.ui.notify(
511
- `${warning}\n\nNo database changes made. Re-run /gsd recover --confirm to proceed.`,
568
+ `${warningText}\n\nNo database changes made. Re-run /gsd recover --confirm to proceed.`,
512
569
  "warning",
513
570
  );
514
571
  return false;
@@ -524,18 +581,31 @@ async function confirmRecover(ctx: ExtensionCommandContext, args: string): Promi
524
581
  * Prints counts of recovered items and the resulting project phase.
525
582
  */
526
583
  export async function handleRecover(ctx: ExtensionCommandContext, basePath: string, args = ""): Promise<void> {
527
- const { isDbAvailable: dbAvailable, clearEngineHierarchy, transaction: dbTransaction } = await import("./gsd-db.js");
584
+ const { isDbAvailable: dbAvailable, clearEngineHierarchy, transaction: dbTransaction, backupDatabaseSnapshot } = await import("./gsd-db.js");
528
585
  const { migrateHierarchyToDb } = await import("./md-importer.js");
529
586
  const { invalidateStateCache } = await import("./state.js");
587
+ const { countDbHierarchy, countMarkdownHierarchy, recoverWouldDeleteDbRows } = await import("./migration-auto-check.js");
588
+ const { renderAllFromDb } = await import("./markdown-renderer.js");
530
589
 
531
590
  if (!dbAvailable()) {
532
591
  ctx.ui.notify("gsd recover: No database open. Run a GSD command first to initialize the DB.", "error");
533
592
  return;
534
593
  }
535
594
 
536
- if (!(await confirmRecover(ctx, args))) return;
595
+ // Compare markdown-on-disk against the live DB so the confirmation prompt can
596
+ // surface exactly what recover will overwrite (and refuse silent data loss).
597
+ // The data-loss check is identity-based, not count-based: it flags any DB row
598
+ // markdown lacks, including equal-count divergence (DB S99 vs markdown S01).
599
+ const markdown = countMarkdownHierarchy(basePath);
600
+ const beforeDb = countDbHierarchy();
601
+ const dataLoss = recoverWouldDeleteDbRows(basePath);
602
+
603
+ if (!(await confirmRecover(ctx, args, markdown, beforeDb, dataLoss))) return;
537
604
 
538
605
  try {
606
+ // 0. Snapshot the DB before the destructive clear so recover is reversible.
607
+ const backupPath = backupDatabaseSnapshot("pre-recover");
608
+
539
609
  // 1. Delete + re-populate inside a single transaction for atomicity.
540
610
  // clearEngineHierarchy() uses transaction() internally but transaction()
541
611
  // is re-entrant, so wrapping in dbTransaction() keeps the whole
@@ -545,9 +615,16 @@ export async function handleRecover(ctx: ExtensionCommandContext, basePath: stri
545
615
  return migrateHierarchyToDb(basePath);
546
616
  });
547
617
 
548
- // 3. Invalidate state cache so deriveState() picks up fresh DB data
618
+ // 2. Invalidate state cache so deriveState() picks up fresh DB data
549
619
  invalidateStateCache();
550
620
 
621
+ // 3. Re-project markdown from the freshly imported DB so disk and DB agree
622
+ // immediately (otherwise the markdown still reflects the pre-import state
623
+ // and the next startup check would flag fresh drift). renderAllFromDb
624
+ // swallows per-artifact failures into its result, so inspect them — a
625
+ // silent projection failure must not be reported as a clean success.
626
+ const renderResult = await renderAllFromDb(basePath);
627
+
551
628
  // 4. Derive state to verify sanity
552
629
  const state = await deriveState(basePath);
553
630
 
@@ -560,6 +637,23 @@ export async function handleRecover(ctx: ExtensionCommandContext, basePath: stri
560
637
  ``,
561
638
  ` Phase: ${state.phase}`,
562
639
  ];
640
+ // Post-import verification: markdown that failed to parse imports as fewer
641
+ // rows than countMarkdownHierarchy saw on disk. Surface the shortfall.
642
+ if (
643
+ counts.milestones < markdown.milestones ||
644
+ counts.slices < markdown.slices ||
645
+ counts.tasks < markdown.tasks
646
+ ) {
647
+ lines.push(
648
+ ``,
649
+ ` ⚠ Imported fewer rows than markdown contained ` +
650
+ `(${markdown.milestones}M/${markdown.slices}S/${markdown.tasks}T on disk). ` +
651
+ `Some markdown may have failed to parse — review before continuing.`,
652
+ );
653
+ }
654
+ if (backupPath) {
655
+ lines.push(``, ` Backup: ${backupPath}`);
656
+ }
563
657
  if (state.activeMilestone) {
564
658
  lines.push(` Active: ${state.activeMilestone.id}: ${state.activeMilestone.title}`);
565
659
  }
@@ -570,10 +664,27 @@ export async function handleRecover(ctx: ExtensionCommandContext, basePath: stri
570
664
  lines.push(` Task: ${state.activeTask.id}: ${state.activeTask.title}`);
571
665
  }
572
666
 
667
+ // Surface markdown projection failures: renderAllFromDb resolves even when
668
+ // individual artifacts fail to render, so a clean exit here would otherwise
669
+ // hide a stale/partial projection.
670
+ const renderFailed = renderResult.errors.length > 0;
671
+ if (renderFailed) {
672
+ lines.push(
673
+ ``,
674
+ ` ⚠ ${renderResult.errors.length} markdown projection(s) failed to render — ` +
675
+ `markdown may be stale. Re-run /gsd rebuild markdown.`,
676
+ );
677
+ for (const e of renderResult.errors.slice(0, 5)) lines.push(` - ${e}`);
678
+ if (renderResult.errors.length > 5) {
679
+ lines.push(` …and ${renderResult.errors.length - 5} more`);
680
+ }
681
+ }
682
+
573
683
  process.stderr.write(
574
- `gsd-recover: recovered ${counts.milestones}M/${counts.slices}S/${counts.tasks}T hierarchy\n`,
684
+ `gsd-recover: recovered ${counts.milestones}M/${counts.slices}S/${counts.tasks}T hierarchy` +
685
+ `${renderFailed ? ` (${renderResult.errors.length} projection errors)` : ""}\n`,
575
686
  );
576
- ctx.ui.notify(lines.join("\n"), "success");
687
+ ctx.ui.notify(lines.join("\n"), renderFailed ? "warning" : "success");
577
688
  } catch (err) {
578
689
  const msg = err instanceof Error ? err.message : String(err);
579
690
  logWarning("command", `recover failed: ${msg}`);
@@ -1285,7 +1285,7 @@ async function configureHooks(ctx: ExtensionCommandContext, prefs: Record<string
1285
1285
  if (geEnabled !== undefined) ge.enabled = geEnabled;
1286
1286
  const currentSliceGates = Array.isArray(ge.slice_gates) ? ge.slice_gates as string[] : [];
1287
1287
  const sgInput = await ctx.ui.input(
1288
- `Slice gates to evaluate (comma-separated, blank keeps)${currentSliceGates.length ? ` (current: ${currentSliceGates.join(", ")})` : " (default: Q3,Q4)"}:`,
1288
+ `Gate-evaluate slice gates (Q3,Q4; comma-separated, blank keeps)${currentSliceGates.length ? ` (current: ${currentSliceGates.join(", ")})` : " (default: Q3,Q4)"}:`,
1289
1289
  currentSliceGates.join(", "),
1290
1290
  );
1291
1291
  if (sgInput !== null && sgInput !== undefined) {
@@ -1751,7 +1751,7 @@ export function serializePreferencesToFrontmatter(prefs: Record<string, unknown>
1751
1751
  // Ordered keys for consistent output
1752
1752
  const orderedKeys = [
1753
1753
  "version", "mode", "always_use_skills", "prefer_skills", "avoid_skills",
1754
- "skill_rules", "custom_instructions", "models", "skill_discovery",
1754
+ "skill_rules", "custom_instructions", "models", "thinking", "skill_discovery",
1755
1755
  "skill_staleness_days", "auto_supervisor", "uat_dispatch", "unique_milestone_ids",
1756
1756
  "budget_ceiling", "budget_enforcement", "context_pause_threshold",
1757
1757
  "notifications", "cmux", "remote_questions", "git",
@@ -452,6 +452,44 @@ export function _resetDecisionSaveLock(): void {
452
452
  _decisionSaveLock = Promise.resolve();
453
453
  }
454
454
 
455
+ /**
456
+ * Re-project root DECISIONS.md from the authoritative decision records, with no
457
+ * new decision being added. Mirrors the projection saveDecisionToDb performs
458
+ * after a save, but over the full set — so a DB → markdown re-projection
459
+ * (recover, rebuild, reconcile) re-derives DECISIONS.md and never leaves it
460
+ * showing a stale subset (e.g. after a worktree merge that accepted one
461
+ * branch's DECISIONS.md while the DB holds the union of both branches'
462
+ * decisions). DB stays the single source of truth; this only writes markdown.
463
+ */
464
+ export async function regenerateDecisionsMarkdown(basePath: string): Promise<void> {
465
+ const { getAllDecisionsFromMemories } = await import('./context-store.js');
466
+ const allDecisions: Decision[] = getAllDecisionsFromMemories();
467
+
468
+ const filePath = resolveGsdRootFile(basePath, 'DECISIONS');
469
+ let existingContent: string | null = null;
470
+ if (existsSync(filePath)) {
471
+ existingContent = readFileSync(filePath, 'utf-8');
472
+ }
473
+
474
+ // Nothing to project: no decisions in the DB and no file to normalize.
475
+ if (allDecisions.length === 0 && existingContent === null) return;
476
+
477
+ let md: string;
478
+ if (existingContent && !isDecisionsTableFormat(existingContent)) {
479
+ // Preserve freeform content; refresh only the appended decisions table.
480
+ const marker = '---\n\n## Decisions Table';
481
+ const markerIdx = existingContent.indexOf(marker);
482
+ const freeformPart = markerIdx >= 0
483
+ ? existingContent.substring(0, markerIdx).trimEnd()
484
+ : existingContent.trimEnd();
485
+ md = freeformPart + '\n' + generateDecisionsAppendBlock(allDecisions);
486
+ } else {
487
+ md = generateDecisionsMd(allDecisions);
488
+ }
489
+
490
+ await saveFile(filePath, md);
491
+ }
492
+
455
493
  // ─── Save Decision to DB + Regenerate Markdown ────────────────────────────
456
494
 
457
495
  export interface SaveDecisionFields {
@@ -104,14 +104,22 @@ Setting `prefer_skills: []` does **not** disable skill discovery — it just mea
104
104
 
105
105
  - `language`: preferred response language for all GSD interactions. Accepts any language name or code — `"Chinese"`, `"zh"`, `"German"`, `"de"`, `"日本語"`, etc. When set, GSD injects "Always respond in \<language\>" into every agent's system prompt, including after `/clear`. Quickest way to set it: `/gsd language <name>`. To clear: `/gsd language off`.
106
106
 
107
- - `models`: per-stage model selection (applies to both auto-mode and guided-flow dispatches). Keys: `research`, `planning`, `discuss`, `execution`, `execution_simple`, `completion`, `validation`, `subagent`. Values can be:
107
+ - `models`: per-stage model selection (applies to both auto-mode and guided-flow dispatches). Keys: `research`, `planning`, `discuss`, `execution`, `execution_simple`, `completion`, `validation`, `subagent`, `uat`. Values can be:
108
108
  - Simple string: `"claude-sonnet-4-6"` — single model, no fallbacks
109
109
  - Provider-qualified string: `"bedrock/claude-sonnet-4-6"` — targets a specific provider when the same model ID exists across multiple providers
110
110
  - Object with fallbacks: `{ model: "claude-opus-4-6", fallbacks: ["glm-5", "minimax-m2.5"] }` — tries fallbacks in order if primary fails
111
111
  - Object with provider: `{ model: "claude-opus-4-6", provider: "bedrock" }` — explicit provider targeting in object format
112
+ - Object with thinking: `{ model: "claude-opus-4-6", thinking: "xhigh" }` — pins the reasoning effort for that phase (see `thinking` below)
112
113
  - Omit a key to use whatever model is currently active (except `discuss` and `validation` which fall back to `planning` when unset). Fallbacks are tried when model switching fails (provider unavailable, rate limited, etc.).
113
114
  - `discuss` — used for milestone/slice discussion (interactive context gathering). Falls back to `planning` if unset.
114
115
  - `validation` — used for gate evaluation, roadmap reassessment, milestone validation, and doc rewrites. Falls back to `planning` if unset.
116
+ - `uat` — used for UAT runs. Falls back to `completion` if unset.
117
+
118
+ - `thinking`: per-phase reasoning effort (ADR-026), separate from `models`. Same phase keys as `models`. Values: `off`, `minimal`, `low`, `medium`, `high`, `xhigh`. Thinking travels with the model — model choice and reasoning effort are independent controls, so you can run one model across phases at different reasoning levels.
119
+ - Two equivalent ways to set it: inline as `models.<phase>.thinking`, or as a separate `thinking:` block keyed by phase. For the same phase, the inline value wins over the block; project preferences win over global; a phase that's unset inherits via the same sibling chain as `models` (e.g. `discuss → planning`).
120
+ - If no thinking is configured for a phase, the session level (set via `/model`) is used, exactly as before — this is fully backward-compatible.
121
+ - `execute-task` (code-writing) has a measured reasoning floor of `medium`: at lower levels models stop planning edits and thrash on file re-reads. The floor applies to the session/default path. An **explicit** `execution` thinking level bypasses the floor and is honored verbatim (with a one-time advisory) — set `execution: low` deliberately if you want it.
122
+ - Levels a model can't support are clamped to the nearest supported level at dispatch and never sent to the provider, so a model/level mismatch never fails a unit mid-run. `xhigh` is only honored by select model families.
115
123
 
116
124
  - `skill_staleness_days`: number — skills unused for this many days get deprioritized during discovery. Set to `0` to disable staleness tracking. Default: `60`.
117
125
 
@@ -448,6 +456,47 @@ models:
448
456
  ---
449
457
  ```
450
458
 
459
+ ## Per-Phase Thinking Level Example
460
+
461
+ Model choice and reasoning effort are independent controls (ADR-026). You can use one model across phases at different reasoning levels, or mix per-phase models with per-phase thinking.
462
+
463
+ Inline form — thinking pinned alongside the model:
464
+
465
+ ```yaml
466
+ ---
467
+ version: 1
468
+ models:
469
+ planning:
470
+ model: openai-codex/gpt-5.4
471
+ thinking: xhigh
472
+ execution:
473
+ model: openai-codex/gpt-5.4
474
+ thinking: low # explicit → bypasses the execute-task medium floor
475
+ validation:
476
+ model: openai-codex/gpt-5.4
477
+ thinking: high
478
+ ---
479
+ ```
480
+
481
+ Separate-block form — set thinking without pinning a model (the session model is used):
482
+
483
+ ```yaml
484
+ ---
485
+ version: 1
486
+ thinking:
487
+ research: medium
488
+ planning: xhigh
489
+ discuss: high
490
+ execution: low
491
+ execution_simple: low
492
+ completion: medium
493
+ validation: high
494
+ uat: medium
495
+ ---
496
+ ```
497
+
498
+ For a single phase, an inline `models.<phase>.thinking` value wins over the same phase in the `thinking:` block; project preferences win over global. Unsupported levels are clamped to the nearest level the resolved model supports.
499
+
451
500
  When a model fails to switch (provider unavailable, rate limited, credits exhausted), GSD automatically tries the next model in the `fallbacks` list. This ensures auto-mode continues even when your preferred provider hits limits.
452
501
 
453
502
  ## Provider Targeting