@opengsd/gsd-pi 1.1.1-dev.b2556262 → 1.2.0-dev.844675c9

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 (211) hide show
  1. package/dist/project-sessions.js +4 -2
  2. package/dist/resources/.managed-resources-content-hash +1 -1
  3. package/dist/resources/extensions/claude-code-cli/stream-adapter.js +17 -9
  4. package/dist/resources/extensions/gsd/auto/contracts.js +8 -1
  5. package/dist/resources/extensions/gsd/auto/orchestrator.js +659 -57
  6. package/dist/resources/extensions/gsd/auto-prompts.js +110 -1
  7. package/dist/resources/extensions/gsd/auto-runtime-state.js +3 -0
  8. package/dist/resources/extensions/gsd/auto-tool-tracking.js +5 -0
  9. package/dist/resources/extensions/gsd/auto-unit-tool-scope.js +29 -0
  10. package/dist/resources/extensions/gsd/auto-worktree.js +24 -17
  11. package/dist/resources/extensions/gsd/auto.js +62 -464
  12. package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +4 -1
  13. package/dist/resources/extensions/gsd/debug-logger.js +10 -0
  14. package/dist/resources/extensions/gsd/doctor-proactive.js +7 -2
  15. package/dist/resources/extensions/gsd/guided-flow.js +2 -2
  16. package/dist/resources/extensions/gsd/markdown-renderer.js +31 -32
  17. package/dist/resources/extensions/gsd/mcp-filter.js +6 -0
  18. package/dist/resources/extensions/gsd/native-git-bridge.js +45 -0
  19. package/dist/resources/extensions/gsd/prompts/discuss.md +6 -7
  20. package/dist/resources/extensions/gsd/prompts/guided-discuss-milestone.md +5 -7
  21. package/dist/resources/extensions/gsd/prompts/guided-discuss-project.md +3 -5
  22. package/dist/resources/extensions/gsd/prompts/guided-discuss-requirements.md +1 -2
  23. package/dist/resources/extensions/gsd/prompts/guided-discuss-slice.md +5 -6
  24. package/dist/resources/extensions/gsd/prompts/plan-slice.md +1 -1
  25. package/dist/resources/extensions/gsd/prompts/research-milestone.md +2 -2
  26. package/dist/resources/extensions/gsd/prompts/validate-milestone.md +5 -3
  27. package/dist/resources/extensions/gsd/schemas/parsers.js +6 -1
  28. package/dist/resources/extensions/gsd/state-reconciliation/drift/artifact-db.js +21 -1
  29. package/dist/resources/extensions/gsd/tools/workflow-tool-executors.js +169 -20
  30. package/dist/resources/extensions/gsd/user-input-boundary.js +42 -4
  31. package/dist/tsconfig.extensions.tsbuildinfo +1 -0
  32. package/dist/web/standalone/.next/BUILD_ID +1 -1
  33. package/dist/web/standalone/.next/app-path-routes-manifest.json +8 -8
  34. package/dist/web/standalone/.next/build-manifest.json +2 -2
  35. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  36. package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
  37. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  38. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  39. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  40. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  41. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  42. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  43. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  44. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  45. package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
  46. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
  47. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  48. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
  49. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  50. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  51. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  52. package/dist/web/standalone/.next/server/app/api/boot/route.js.nft.json +1 -1
  53. package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route.js.nft.json +1 -1
  54. package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route.js.nft.json +1 -1
  55. package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route.js.nft.json +1 -1
  56. package/dist/web/standalone/.next/server/app/api/captures/route.js.nft.json +1 -1
  57. package/dist/web/standalone/.next/server/app/api/cleanup/route.js.nft.json +1 -1
  58. package/dist/web/standalone/.next/server/app/api/doctor/route.js.nft.json +1 -1
  59. package/dist/web/standalone/.next/server/app/api/export-data/route.js.nft.json +1 -1
  60. package/dist/web/standalone/.next/server/app/api/files/route.js.nft.json +1 -1
  61. package/dist/web/standalone/.next/server/app/api/forensics/route.js.nft.json +1 -1
  62. package/dist/web/standalone/.next/server/app/api/git/route.js +1 -1
  63. package/dist/web/standalone/.next/server/app/api/git/route.js.nft.json +1 -1
  64. package/dist/web/standalone/.next/server/app/api/history/route.js.nft.json +1 -1
  65. package/dist/web/standalone/.next/server/app/api/hooks/route.js.nft.json +1 -1
  66. package/dist/web/standalone/.next/server/app/api/inspect/route.js.nft.json +1 -1
  67. package/dist/web/standalone/.next/server/app/api/knowledge/route.js.nft.json +1 -1
  68. package/dist/web/standalone/.next/server/app/api/live-state/route.js.nft.json +1 -1
  69. package/dist/web/standalone/.next/server/app/api/mcp-connections/route.js.nft.json +1 -1
  70. package/dist/web/standalone/.next/server/app/api/notifications/route.js.nft.json +1 -1
  71. package/dist/web/standalone/.next/server/app/api/onboarding/route.js.nft.json +1 -1
  72. package/dist/web/standalone/.next/server/app/api/projects/route.js.nft.json +1 -1
  73. package/dist/web/standalone/.next/server/app/api/recovery/route.js.nft.json +1 -1
  74. package/dist/web/standalone/.next/server/app/api/session/browser/route.js.nft.json +1 -1
  75. package/dist/web/standalone/.next/server/app/api/session/command/route.js.nft.json +1 -1
  76. package/dist/web/standalone/.next/server/app/api/session/events/route.js.nft.json +1 -1
  77. package/dist/web/standalone/.next/server/app/api/session/manage/route.js.nft.json +1 -1
  78. package/dist/web/standalone/.next/server/app/api/settings-data/route.js.nft.json +1 -1
  79. package/dist/web/standalone/.next/server/app/api/shutdown/route.js.nft.json +1 -1
  80. package/dist/web/standalone/.next/server/app/api/skill-health/route.js.nft.json +1 -1
  81. package/dist/web/standalone/.next/server/app/api/steer/route.js.nft.json +1 -1
  82. package/dist/web/standalone/.next/server/app/api/switch-root/route.js.nft.json +1 -1
  83. package/dist/web/standalone/.next/server/app/api/terminal/sessions/route.js.nft.json +1 -1
  84. package/dist/web/standalone/.next/server/app/api/terminal/stream/route.js.nft.json +1 -1
  85. package/dist/web/standalone/.next/server/app/api/undo/route.js.nft.json +1 -1
  86. package/dist/web/standalone/.next/server/app/api/visualizer/route.js.nft.json +1 -1
  87. package/dist/web/standalone/.next/server/app/index.html +1 -1
  88. package/dist/web/standalone/.next/server/app/index.rsc +1 -1
  89. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
  90. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +1 -1
  91. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  92. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
  93. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  94. package/dist/web/standalone/.next/server/app-paths-manifest.json +8 -8
  95. package/dist/web/standalone/.next/server/chunks/5047.js +2 -0
  96. package/dist/web/standalone/.next/server/chunks/5124.js +1 -0
  97. package/dist/web/standalone/.next/server/chunks/8357.js +2 -2
  98. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  99. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  100. package/dist/web/standalone/.next/server/pages/500.html +1 -1
  101. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  102. package/dist/web/standalone/node_modules/@gsd/native/package.json +1 -1
  103. package/dist/web/standalone/node_modules/node-pty/build/Makefile +1 -1
  104. package/dist/web/standalone/node_modules/postcss/lib/container.js +26 -18
  105. package/dist/web/standalone/node_modules/postcss/lib/css-syntax-error.js +47 -14
  106. package/dist/web/standalone/node_modules/postcss/lib/declaration.js +4 -4
  107. package/dist/web/standalone/node_modules/postcss/lib/fromJSON.js +3 -3
  108. package/dist/web/standalone/node_modules/postcss/lib/input.js +54 -29
  109. package/dist/web/standalone/node_modules/postcss/lib/lazy-result.js +47 -37
  110. package/dist/web/standalone/node_modules/postcss/lib/map-generator.js +26 -9
  111. package/dist/web/standalone/node_modules/postcss/lib/no-work-result.js +57 -55
  112. package/dist/web/standalone/node_modules/postcss/lib/node.js +99 -31
  113. package/dist/web/standalone/node_modules/postcss/lib/parse.js +1 -1
  114. package/dist/web/standalone/node_modules/postcss/lib/parser.js +10 -9
  115. package/dist/web/standalone/node_modules/postcss/lib/postcss.js +12 -12
  116. package/dist/web/standalone/node_modules/postcss/lib/previous-map.js +30 -11
  117. package/dist/web/standalone/node_modules/postcss/lib/processor.js +7 -7
  118. package/dist/web/standalone/node_modules/postcss/lib/result.js +5 -5
  119. package/dist/web/standalone/node_modules/postcss/lib/rule.js +6 -6
  120. package/dist/web/standalone/node_modules/postcss/lib/stringifier.js +69 -28
  121. package/dist/web/standalone/node_modules/postcss/lib/tokenize.js +6 -2
  122. package/dist/web/standalone/node_modules/postcss/package.json +48 -48
  123. package/package.json +16 -11
  124. package/packages/cloud-mcp-gateway/package.json +2 -2
  125. package/packages/contracts/package.json +1 -1
  126. package/packages/daemon/package.json +4 -4
  127. package/packages/gsd-agent-core/package.json +5 -5
  128. package/packages/gsd-agent-modes/dist/modes/interactive/components/transcript-design.js +1 -1
  129. package/packages/gsd-agent-modes/dist/modes/interactive/components/transcript-design.js.map +1 -1
  130. package/packages/gsd-agent-modes/package.json +7 -7
  131. package/packages/mcp-server/package.json +3 -3
  132. package/packages/native/package.json +1 -1
  133. package/packages/pi-agent-core/package.json +1 -1
  134. package/packages/pi-ai/dist/models.generated.d.ts +0 -34
  135. package/packages/pi-ai/dist/models.generated.d.ts.map +1 -1
  136. package/packages/pi-ai/dist/models.generated.js +12 -46
  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/auth-storage.d.ts.map +1 -1
  140. package/packages/pi-coding-agent/dist/core/auth-storage.js +11 -3
  141. package/packages/pi-coding-agent/dist/core/auth-storage.js.map +1 -1
  142. package/packages/pi-coding-agent/package.json +7 -7
  143. package/packages/pi-tui/package.json +2 -2
  144. package/packages/rpc-client/package.json +2 -2
  145. package/pkg/package.json +1 -1
  146. package/scripts/install/deps.js +10 -0
  147. package/scripts/link-workspace-packages.cjs +7 -40
  148. package/src/resources/extensions/claude-code-cli/stream-adapter.ts +18 -8
  149. package/src/resources/extensions/claude-code-cli/tests/stream-adapter.test.ts +2 -2
  150. package/src/resources/extensions/gsd/auto/contracts.ts +8 -119
  151. package/src/resources/extensions/gsd/auto/orchestrator.ts +794 -58
  152. package/src/resources/extensions/gsd/auto-prompts.ts +114 -1
  153. package/src/resources/extensions/gsd/auto-runtime-state.ts +4 -0
  154. package/src/resources/extensions/gsd/auto-tool-tracking.ts +5 -0
  155. package/src/resources/extensions/gsd/auto-unit-tool-scope.ts +33 -0
  156. package/src/resources/extensions/gsd/auto-worktree.ts +24 -16
  157. package/src/resources/extensions/gsd/auto.ts +81 -500
  158. package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +4 -0
  159. package/src/resources/extensions/gsd/debug-logger.ts +11 -0
  160. package/src/resources/extensions/gsd/doctor-proactive.ts +8 -2
  161. package/src/resources/extensions/gsd/guided-flow.ts +2 -2
  162. package/src/resources/extensions/gsd/markdown-renderer.ts +38 -19
  163. package/src/resources/extensions/gsd/mcp-filter.ts +7 -0
  164. package/src/resources/extensions/gsd/native-git-bridge.ts +48 -0
  165. package/src/resources/extensions/gsd/prompts/discuss.md +6 -7
  166. package/src/resources/extensions/gsd/prompts/guided-discuss-milestone.md +5 -7
  167. package/src/resources/extensions/gsd/prompts/guided-discuss-project.md +3 -5
  168. package/src/resources/extensions/gsd/prompts/guided-discuss-requirements.md +1 -2
  169. package/src/resources/extensions/gsd/prompts/guided-discuss-slice.md +5 -6
  170. package/src/resources/extensions/gsd/prompts/plan-slice.md +1 -1
  171. package/src/resources/extensions/gsd/prompts/research-milestone.md +2 -2
  172. package/src/resources/extensions/gsd/prompts/validate-milestone.md +5 -3
  173. package/src/resources/extensions/gsd/schemas/parsers.ts +6 -1
  174. package/src/resources/extensions/gsd/state-reconciliation/drift/artifact-db.ts +31 -10
  175. package/src/resources/extensions/gsd/tests/artifact-db-drift-memo.test.ts +66 -0
  176. package/src/resources/extensions/gsd/tests/auto-dispatch-baseline-harness.test.ts +53 -0
  177. package/src/resources/extensions/gsd/tests/auto-orchestrator.test.ts +590 -855
  178. package/src/resources/extensions/gsd/tests/auto-paused-ui-cleanup.test.ts +38 -10
  179. package/src/resources/extensions/gsd/tests/debug-logger.test.ts +15 -0
  180. package/src/resources/extensions/gsd/tests/execute-summary-save-empty-project.test.ts +64 -1
  181. package/src/resources/extensions/gsd/tests/integration/merge-strategy-regular.test.ts +157 -0
  182. package/src/resources/extensions/gsd/tests/markdown-renderer-parse-cache.test.ts +75 -0
  183. package/src/resources/extensions/gsd/tests/native-merge-regular.test.ts +139 -0
  184. package/src/resources/extensions/gsd/tests/orchestrator-legacy-parity.test.ts +127 -0
  185. package/src/resources/extensions/gsd/tests/parse-project-milestone-bridge.test.ts +77 -0
  186. package/src/resources/extensions/gsd/tests/plan-slice-prompt.test.ts +4 -2
  187. package/src/resources/extensions/gsd/tests/prompt-contracts.test.ts +29 -2
  188. package/src/resources/extensions/gsd/tests/research-milestone-composer.test.ts +65 -0
  189. package/src/resources/extensions/gsd/tests/start-auto-detached.test.ts +19 -5
  190. package/src/resources/extensions/gsd/tests/token-tool-gating.test.ts +38 -0
  191. package/src/resources/extensions/gsd/tests/user-input-boundary.test.ts +62 -0
  192. package/src/resources/extensions/gsd/tests/worktree-safety.test.ts +24 -0
  193. package/src/resources/extensions/gsd/tests/write-gate-planning-unit.test.ts +15 -3
  194. package/src/resources/extensions/gsd/tools/workflow-tool-executors.ts +183 -21
  195. package/src/resources/extensions/gsd/user-input-boundary.ts +37 -5
  196. package/dist/web/standalone/.next/server/chunks/678.js +0 -2
  197. package/packages/gsd-agent-modes/dist/modes/interactive/components/__prototype__/gsd-widget-prototype.d.ts +0 -21
  198. package/packages/gsd-agent-modes/dist/modes/interactive/components/__prototype__/gsd-widget-prototype.d.ts.map +0 -1
  199. package/packages/gsd-agent-modes/dist/modes/interactive/components/__prototype__/gsd-widget-prototype.js +0 -213
  200. package/packages/gsd-agent-modes/dist/modes/interactive/components/__prototype__/gsd-widget-prototype.js.map +0 -1
  201. package/packages/gsd-agent-modes/dist/modes/interactive/components/__prototype__/transcript-density-prototype.d.ts +0 -28
  202. package/packages/gsd-agent-modes/dist/modes/interactive/components/__prototype__/transcript-density-prototype.d.ts.map +0 -1
  203. package/packages/gsd-agent-modes/dist/modes/interactive/components/__prototype__/transcript-density-prototype.js +0 -249
  204. package/packages/gsd-agent-modes/dist/modes/interactive/components/__prototype__/transcript-density-prototype.js.map +0 -1
  205. package/packages/gsd-agent-modes/dist/modes/interactive/components/__prototype__/transcript-design-prototype.d.ts +0 -19
  206. package/packages/gsd-agent-modes/dist/modes/interactive/components/__prototype__/transcript-design-prototype.d.ts.map +0 -1
  207. package/packages/gsd-agent-modes/dist/modes/interactive/components/__prototype__/transcript-design-prototype.js +0 -797
  208. package/packages/gsd-agent-modes/dist/modes/interactive/components/__prototype__/transcript-design-prototype.js.map +0 -1
  209. package/scripts/ensure-workspace-builds.cjs +0 -129
  210. /package/dist/web/standalone/.next/static/{tJOKQbQRO-9MiFDO8DIDS → Qbr81pQ-pbQXP4bq2VXLv}/_buildManifest.js +0 -0
  211. /package/dist/web/standalone/.next/static/{tJOKQbQRO-9MiFDO8DIDS → Qbr81pQ-pbQXP4bq2VXLv}/_ssgManifest.js +0 -0
@@ -37,6 +37,7 @@ import {
37
37
  import { formatDecisionsCompact, formatRequirementsCompact } from "./structured-data-formatter.js";
38
38
  import { readPhaseAnchor, formatAnchorForPrompt } from "./phase-anchor.js";
39
39
  import { composeContextModeInstructions, composeInlinedContext, composeUnitContext, type ArtifactResolver, type ContextModeRenderMode, type ExcerptResolver } from "./unit-context-composer.js";
40
+ import { resolveManifest } from "./unit-context-manifest.js";
40
41
  import { readCompactionSnapshot } from "./compaction-snapshot.js";
41
42
  import { logWarning } from "./workflow-logger.js";
42
43
  import { inlineGraphSubgraph } from "./graph-context.js";
@@ -1674,6 +1675,70 @@ export async function buildDiscussRequirementsPrompt(
1674
1675
  }));
1675
1676
  }
1676
1677
 
1678
+ /**
1679
+ * Bounded codebase snapshot for research-milestone grounding (ADR-029).
1680
+ *
1681
+ * Reuses the in-process, ~millisecond `analyzeCodebase` / `formatCodebaseBrief`
1682
+ * machinery that powers the guided-discuss Preparation Snapshot, so research
1683
+ * grounds on current code reality instead of running an open-ended `rg`/`find`/
1684
+ * `scout` survey on every dispatch (the auto-mode counterpart to ADR-028).
1685
+ *
1686
+ * Gated on the manifest's `codebaseMap` flag (previously a dead policy flag)
1687
+ * and the `discuss_preparation` opt-out. Failures degrade silently — research
1688
+ * still runs, it just falls back to on-demand reads.
1689
+ */
1690
+ async function buildResearchCodebaseSnapshot(base: string): Promise<string | null> {
1691
+ const manifest = resolveManifest("research-milestone");
1692
+ if (!manifest?.codebaseMap) return null;
1693
+ const prefs = loadEffectiveGSDPreferences(base)?.preferences;
1694
+ if (prefs?.discuss_preparation === false) return null;
1695
+ try {
1696
+ const { analyzeCodebase, formatCodebaseBrief } = await import("./preparation.js");
1697
+ const brief = await analyzeCodebase(base);
1698
+ const formatted = formatCodebaseBrief(brief).trim();
1699
+ if (!formatted) return null;
1700
+ return [
1701
+ "### Codebase Snapshot (current code reality)",
1702
+ "Source: in-process bounded scan of the working tree.",
1703
+ "",
1704
+ "This snapshot describes what already exists. Treat it as authoritative for current code reality and do NOT re-survey the tree to rediscover it. Read a specific file only when a research question hinges on its exact contents.",
1705
+ "",
1706
+ formatted,
1707
+ ].join("\n");
1708
+ } catch (err) {
1709
+ logWarning("prompt", `buildResearchCodebaseSnapshot failed: ${err instanceof Error ? err.message : String(err)}`);
1710
+ return null;
1711
+ }
1712
+ }
1713
+
1714
+ /**
1715
+ * Lightweight research resume block (ADR-029).
1716
+ *
1717
+ * When a prior attempt for this milestone left durable output — a partial
1718
+ * RESEARCH artifact and/or a research phase anchor — inline it under a
1719
+ * "continue, do not redo" banner so a re-dispatched research unit extends
1720
+ * prior work instead of re-running every command from scratch (the
1721
+ * restart-from-scratch pattern observed in the 789 run trace). No new state
1722
+ * machine: the partial RESEARCH file and the existing phase anchor are the
1723
+ * durable signals. Returns null when there is nothing to resume.
1724
+ */
1725
+ async function buildResearchResumeBlock(base: string, mid: string): Promise<string | null> {
1726
+ const researchPath = resolveMilestoneFile(base, mid, "RESEARCH");
1727
+ const researchRel = relMilestoneFile(base, mid, "RESEARCH");
1728
+ const partial = await inlineFileOptional(researchPath, researchRel, "Prior Partial Research");
1729
+ const anchor = readPhaseAnchor(base, mid, "research-milestone");
1730
+ if (!partial && !anchor) return null;
1731
+ const lines: string[] = [
1732
+ "### Resume — Prior Partial Research (continue, do not redo)",
1733
+ "",
1734
+ "A previous research attempt for this milestone left the durable output below. **Build on it — do not restart from scratch.** Re-run a command only when its prior result is missing or stale, and persist progress incrementally with `gsd_summary_save` so any interruption keeps your findings.",
1735
+ "",
1736
+ ];
1737
+ if (anchor) lines.push(formatAnchorForPrompt(anchor), "");
1738
+ if (partial) lines.push(partial);
1739
+ return lines.join("\n").trimEnd();
1740
+ }
1741
+
1677
1742
  export async function buildResearchMilestonePrompt(mid: string, midTitle: string, base: string): Promise<string> {
1678
1743
  const contextTelemetry: PromptContextTelemetryEntry[] = [];
1679
1744
 
@@ -1715,6 +1780,34 @@ export async function buildResearchMilestonePrompt(mid: string, midTitle: string
1715
1780
  const knowledgeInlineRM = await inlineKnowledgeBudgeted(base, extractKeywords(midTitle));
1716
1781
  const parts: string[] = [];
1717
1782
  if (composed.prepend) parts.push(composed.prepend);
1783
+
1784
+ // Resume grounding (ADR-029): if a prior attempt left partial research or a
1785
+ // phase anchor, inline it prominently so a re-dispatched unit continues
1786
+ // rather than re-running every command from scratch.
1787
+ const resumeBlock = await buildResearchResumeBlock(base, mid);
1788
+ if (resumeBlock) {
1789
+ parts.push(resumeBlock);
1790
+ trackPromptContext(contextTelemetry, "research-resume", "inline", resumeBlock);
1791
+ } else {
1792
+ trackPromptContext(contextTelemetry, "research-resume", "skipped", null, "no prior partial research");
1793
+ }
1794
+
1795
+ // Project-size signal (ADR-029): same classification plan-milestone gets, so
1796
+ // research right-sizes effort on tiny projects instead of over-researching.
1797
+ const classificationBlock = formatProjectClassificationForPlanning(classifyProject(base));
1798
+ parts.push(classificationBlock);
1799
+ trackPromptContext(contextTelemetry, "project-classification", "inline", classificationBlock);
1800
+
1801
+ // Codebase snapshot (ADR-029): bounded, in-process code-reality grounding so
1802
+ // research does not open-endedly survey the tree (auto-mode ADR-028).
1803
+ const codebaseSnapshot = await buildResearchCodebaseSnapshot(base);
1804
+ if (codebaseSnapshot) {
1805
+ parts.push(codebaseSnapshot);
1806
+ trackPromptContext(contextTelemetry, "codebase-snapshot", "inline", codebaseSnapshot);
1807
+ } else {
1808
+ trackPromptContext(contextTelemetry, "codebase-snapshot", "skipped", null, "disabled, empty, or scan failed");
1809
+ }
1810
+
1718
1811
  if (knowledgeInlineRM && composed.inline) {
1719
1812
  const idx = composed.inline.lastIndexOf("### Output Template:");
1720
1813
  if (idx > 0) {
@@ -3679,6 +3772,22 @@ export async function buildReactiveExecutePrompt(
3679
3772
  // derivation, and tool handlers all consult the same source of truth.
3680
3773
  // See gate-registry.ts for the full ownership map.
3681
3774
 
3775
+ /**
3776
+ * Adapt gate-registry guidance for section-close phases.
3777
+ *
3778
+ * Gate-registry text is shared with the gate-evaluate subagent, where
3779
+ * "Return verdict ..." is literal. Section-close units write artifact sections
3780
+ * instead, so translate that wording at render time without mutating the
3781
+ * canonical guidance.
3782
+ */
3783
+ function sectionModeGuidance(guidance: string): string {
3784
+ return guidance.replace(
3785
+ /Return verdict '([^']+)'/g,
3786
+ (_match, verdict: string) =>
3787
+ verdict === "omitted" ? "Leave the section empty" : `Record a \`${verdict}\``,
3788
+ );
3789
+ }
3790
+
3682
3791
  /**
3683
3792
  * Render a "Gates to Close" block for turns like `complete-slice` and
3684
3793
  * `validate-milestone` that own gates which are closed as a side-effect
@@ -3702,12 +3811,16 @@ function renderGatesToCloseBlock(
3702
3811
  "These quality gates are still pending for this unit. You MUST address every one before calling the closing tool — the handler closes the DB row based on whether the corresponding artifact section is present.",
3703
3812
  );
3704
3813
  lines.push("");
3814
+ lines.push(
3815
+ "**Do NOT call `gsd_save_gate_result` (or any gate-result tool) for these gates** — that tool belongs to a different phase and the call will be blocked. You close each gate purely by writing its named section: a populated section records `pass`, an empty section records `omitted`, and the completion handler persists the verdict for you. Treat any \"return verdict\" wording in the guidance below as describing that section outcome, not as an instruction to call a tool.",
3816
+ );
3817
+ lines.push("");
3705
3818
  for (const def of applicable) {
3706
3819
  lines.push(`### ${def.id} — ${def.promptSection}`);
3707
3820
  lines.push("");
3708
3821
  lines.push(`**Question:** ${def.question}`);
3709
3822
  lines.push("");
3710
- lines.push(def.guidance);
3823
+ lines.push(sectionModeGuidance(def.guidance));
3711
3824
  if (opts.allowOmit) {
3712
3825
  lines.push("");
3713
3826
  lines.push(
@@ -47,6 +47,10 @@ export function isAutoCompletionStopInProgress(): boolean {
47
47
  return autoSession.completionStopInProgress;
48
48
  }
49
49
 
50
+ export function clearAutoCompletionStopInProgress(): void {
51
+ autoSession.completionStopInProgress = false;
52
+ }
53
+
50
54
  export function markToolStart(toolCallId: string, toolName?: string): void {
51
55
  markTrackedToolStart(toolCallId, autoSession.active, toolName);
52
56
  }
@@ -136,6 +136,11 @@ export const DETERMINISTIC_POLICY_ERROR_STRINGS = [
136
136
  // "Cannot write to milestone CONTEXT.md without depth verification." for direct
137
137
  // write tool calls to *-CONTEXT.md paths (different code path than gsd_summary_save).
138
138
  "CONTEXT.md without depth verification",
139
+ // Section-close gate units (execute-task, complete-slice, validate-milestone) that
140
+ // reach for gsd_save_gate_result get the calm redirect from softGateToolRedirect
141
+ // (auto-unit-tool-scope.ts) instead of a HARD BLOCK. Still deterministic — those
142
+ // phases never own that tool, so a retry hits the same redirect every time.
143
+ "closes its quality gates by writing summary sections",
139
144
  ] as const;
140
145
 
141
146
  /**
@@ -35,6 +35,17 @@ const EXECUTE_TASK_UNIT_TYPES = new Set([
35
35
  "reactive-execute",
36
36
  ]);
37
37
 
38
+ // These units own quality gates, but their completion handlers persist verdicts
39
+ // from artifact sections. gsd_save_gate_result belongs to gate-evaluate, so keep
40
+ // blocking it here with a calm redirect to the section-write path.
41
+ const SECTION_CLOSE_GATE_UNIT_TYPES = new Set([
42
+ "execute-task",
43
+ "execute-task-simple",
44
+ "reactive-execute",
45
+ "complete-slice",
46
+ "validate-milestone",
47
+ ]);
48
+
38
49
  const EXTRA_SCOPED_GSD_LIFECYCLE_TOOLS = [
39
50
  "gsd_skip_slice",
40
51
  "gsd_slice_reopen",
@@ -52,6 +63,8 @@ const SCOPED_GSD_LIFECYCLE_TOOLS = new Set(
52
63
  );
53
64
 
54
65
  export const GSD_PHASE_SCOPE_DISPLAY_REASON = "This GSD phase only allows its scoped workflow tools.";
66
+ export const GSD_SECTION_CLOSE_GATE_DISPLAY_REASON =
67
+ "Gates here close by writing summary sections — gsd_save_gate_result isn't needed.";
55
68
 
56
69
  type AutoUnitToolScopeResult = {
57
70
  block: boolean;
@@ -90,6 +103,22 @@ function hardBlock(unitType: string, what: string): AutoUnitToolScopeResult {
90
103
  };
91
104
  }
92
105
 
106
+ // This stable marker is registered in auto-tool-tracking.ts so auto-mode treats
107
+ // the redirect as deterministic policy, not a retryable execution failure.
108
+ function softGateToolRedirect(unitType: string): AutoUnitToolScopeResult {
109
+ return {
110
+ block: true,
111
+ reason: [
112
+ `Skip this call — the "${unitType}" phase closes its quality gates by writing summary sections,`,
113
+ "not by calling gsd_save_gate_result (that tool belongs to the gate-evaluate phase).",
114
+ "Record each gate by filling its named section in your summary: a populated section records `pass`,",
115
+ "an empty one records `omitted`. Then call your completion tool and the handler persists every verdict.",
116
+ "This is expected, not an error — continue without gsd_save_gate_result.",
117
+ ].join(" "),
118
+ displayReason: GSD_SECTION_CLOSE_GATE_DISPLAY_REASON,
119
+ };
120
+ }
121
+
93
122
  function allowedGsdToolsForUnit(unitType: string): string[] {
94
123
  return [...new Set(
95
124
  (AUTO_UNIT_SCOPED_TOOLS[unitType] ?? [])
@@ -171,6 +200,10 @@ export function shouldBlockAutoUnitToolCall(
171
200
  );
172
201
  }
173
202
 
203
+ if (canonicalTool === "gsd_save_gate_result" && SECTION_CLOSE_GATE_UNIT_TYPES.has(unitType)) {
204
+ return softGateToolRedirect(unitType);
205
+ }
206
+
174
207
  return hardBlock(
175
208
  unitType,
176
209
  `GSD lifecycle tool "${canonicalTool}" is not permitted; allowed GSD tools: ${allowedTools.length > 0 ? allowedTools.join(", ") : "(none)"}`,
@@ -69,6 +69,7 @@ import {
69
69
  nativeCommit,
70
70
  nativeCheckoutBranch,
71
71
  nativeMergeSquash,
72
+ nativeMergeRegular,
72
73
  nativeConflictFiles,
73
74
  nativeCheckoutTheirs,
74
75
  nativeAddPaths,
@@ -538,15 +539,16 @@ function removeMergeStateFiles(basePath: string, contextLabel: string): void {
538
539
  }
539
540
  }
540
541
 
541
- function cleanupSquashConflictState(basePath: string): void {
542
- // `git merge --squash` conflicts can leave unmerged index entries without
543
- // MERGE_HEAD, so merge-abort alone is not enough. Reset the merge index, then
544
- // remove merge message files that native/libgit2 paths may have created.
542
+ function cleanupConflictState(basePath: string): void {
543
+ // Merge conflicts can leave unmerged index entries; merge-abort alone is not
544
+ // enough for squash merges (MERGE_HEAD is never written). Reset the merge
545
+ // index, then remove merge message files that native/libgit2 paths may have
546
+ // created.
545
547
  try {
546
548
  nativeMergeAbort(basePath);
547
549
  } catch (err) {
548
- // Expected for squash conflicts when MERGE_HEAD was never written.
549
- debugLog("squash-conflict-cleanup:merge-abort-skipped", {
550
+ // MERGE_HEAD absent (squash merge path) abort is a no-op, which is fine.
551
+ debugLog("conflict-cleanup:merge-abort-skipped", {
550
552
  error: err instanceof Error ? err.message : String(err),
551
553
  });
552
554
  }
@@ -557,9 +559,9 @@ function cleanupSquashConflictState(basePath: string): void {
557
559
  encoding: "utf-8",
558
560
  });
559
561
  } catch (err) {
560
- logError("worktree", `git reset --merge failed after squash conflict: ${err instanceof Error ? err.message : String(err)}`);
562
+ logError("worktree", `git reset --merge failed after merge conflict: ${err instanceof Error ? err.message : String(err)}`);
561
563
  }
562
- removeMergeStateFiles(basePath, "squash conflict");
564
+ removeMergeStateFiles(basePath, "conflict");
563
565
  }
564
566
 
565
567
  // ─── Dispatch-Level Sync (project root ↔ worktree) ──────────────────────────
@@ -2161,15 +2163,21 @@ export function mergeMilestoneToMain(
2161
2163
  logWarning("worktree", `git stash failed: ${err instanceof Error ? err.message : String(err)}`);
2162
2164
  }
2163
2165
 
2164
- // 7b. Clean up stale merge state before attempting squash merge (#2912).
2166
+ // 7b. Clean up stale merge state before attempting the merge (#2912).
2165
2167
  // A leftover MERGE_HEAD (from a previous failed merge, libgit2 native path,
2166
- // or interrupted operation) causes `git merge --squash` to refuse with
2168
+ // or interrupted operation) causes git merge to refuse with
2167
2169
  // "fatal: You have not concluded your merge (MERGE_HEAD exists)".
2168
2170
  // Defensively remove merge artifacts before starting.
2169
2171
  removeMergeStateFiles(originalBasePath_, "pre-merge");
2170
2172
 
2171
- // 8. Squash merge auto-resolve .gsd/ state file conflicts (#530)
2172
- const mergeResult = nativeMergeSquash(originalBasePath_, milestoneBranch);
2173
+ // 8. Mergerespect merge_strategy preference (#549).
2174
+ // "squash" (default): stages changes without a merge commit; caller commits.
2175
+ // "merge": --no-ff --no-commit so caller can supply the commit message while
2176
+ // git records a real merge commit (MERGE_HEAD present when nativeCommit runs).
2177
+ const effectiveStrategy = prefs.merge_strategy === "merge" ? "merge" : "squash";
2178
+ const mergeResult = effectiveStrategy === "merge"
2179
+ ? nativeMergeRegular(originalBasePath_, milestoneBranch)
2180
+ : nativeMergeSquash(originalBasePath_, milestoneBranch);
2173
2181
  if (needsDbCycle && dbPathToReopen) {
2174
2182
  try {
2175
2183
  openDatabase(dbPathToReopen);
@@ -2205,7 +2213,7 @@ export function mergeMilestoneToMain(
2205
2213
  : `Check \`git status\` in the project root for details.`;
2206
2214
  throw new GSDError(
2207
2215
  GSD_GIT_ERROR,
2208
- `Squash merge of ${milestoneBranch} rejected: working tree has dirty or untracked files ` +
2216
+ `${effectiveStrategy === "merge" ? "Merge" : "Squash merge"} of ${milestoneBranch} rejected: working tree has dirty or untracked files ` +
2209
2217
  `that conflict with the merge. ${fileList}`,
2210
2218
  );
2211
2219
  }
@@ -2231,7 +2239,7 @@ export function mergeMilestoneToMain(
2231
2239
 
2232
2240
  // If there are still real code conflicts, escalate
2233
2241
  if (codeConflicts.length > 0) {
2234
- cleanupSquashConflictState(originalBasePath_);
2242
+ cleanupConflictState(originalBasePath_);
2235
2243
 
2236
2244
  // Pop stash before throwing so local work is not lost (#2151).
2237
2245
  if (stashed) {
@@ -2250,7 +2258,7 @@ export function mergeMilestoneToMain(
2250
2258
  process.chdir(previousCwd);
2251
2259
  throw new MergeConflictError(
2252
2260
  codeConflicts,
2253
- "squash",
2261
+ effectiveStrategy,
2254
2262
  milestoneBranch,
2255
2263
  mainBranch,
2256
2264
  );
@@ -2416,7 +2424,7 @@ export function mergeMilestoneToMain(
2416
2424
  process.chdir(previousCwd);
2417
2425
  throw new GSDError(
2418
2426
  GSD_GIT_ERROR,
2419
- `Squash merge produced nothing to commit but milestone branch "${milestoneBranch}" ` +
2427
+ `${effectiveStrategy === "merge" ? "Merge" : "Squash merge"} produced nothing to commit but milestone branch "${milestoneBranch}" ` +
2420
2428
  `has ${codeChanges.length} code file(s) not on "${mainBranch}". ` +
2421
2429
  `Aborting worktree teardown to prevent data loss.`,
2422
2430
  );