gsd-pi 2.82.0-dev.dfbc5f58f → 2.82.0-dev.e7a7f1ed5

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 (182) hide show
  1. package/README.md +1 -1
  2. package/dist/resources/.managed-resources-content-hash +1 -1
  3. package/dist/resources/extensions/claude-code-cli/stream-adapter.js +1 -1
  4. package/dist/resources/extensions/gsd/auto/phases.js +73 -30
  5. package/dist/resources/extensions/gsd/auto-dashboard.js +66 -1
  6. package/dist/resources/extensions/gsd/auto-direct-dispatch.js +1 -0
  7. package/dist/resources/extensions/gsd/auto-dispatch.js +10 -16
  8. package/dist/resources/extensions/gsd/auto-recovery.js +40 -13
  9. package/dist/resources/extensions/gsd/auto-start.js +3 -3
  10. package/dist/resources/extensions/gsd/auto-verification.js +17 -4
  11. package/dist/resources/extensions/gsd/auto-worktree.js +65 -9
  12. package/dist/resources/extensions/gsd/auto.js +7 -2
  13. package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +27 -6
  14. package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +4 -2
  15. package/dist/resources/extensions/gsd/commands-prefs-wizard.js +7 -2
  16. package/dist/resources/extensions/gsd/crash-recovery.js +16 -4
  17. package/dist/resources/extensions/gsd/db/milestone-leases.js +24 -0
  18. package/dist/resources/extensions/gsd/doctor-git-checks.js +46 -1
  19. package/dist/resources/extensions/gsd/git-service.js +6 -2
  20. package/dist/resources/extensions/gsd/gsd-db.js +20 -6
  21. package/dist/resources/extensions/gsd/guided-flow-queue.js +4 -3
  22. package/dist/resources/extensions/gsd/guided-flow.js +95 -116
  23. package/dist/resources/extensions/gsd/guided-unit-context.js +23 -0
  24. package/dist/resources/extensions/gsd/migration-auto-check.js +12 -17
  25. package/dist/resources/extensions/gsd/pending-auto-start.js +52 -0
  26. package/dist/resources/extensions/gsd/prompts/complete-milestone.md +1 -1
  27. package/dist/resources/extensions/gsd/prompts/complete-slice.md +1 -1
  28. package/dist/resources/extensions/gsd/prompts/discuss-headless.md +8 -8
  29. package/dist/resources/extensions/gsd/prompts/discuss.md +9 -9
  30. package/dist/resources/extensions/gsd/prompts/guided-discuss-project.md +4 -4
  31. package/dist/resources/extensions/gsd/prompts/guided-discuss-requirements.md +3 -3
  32. package/dist/resources/extensions/gsd/prompts/plan-slice.md +1 -1
  33. package/dist/resources/extensions/gsd/prompts/queue.md +4 -4
  34. package/dist/resources/extensions/gsd/prompts/refine-slice.md +1 -1
  35. package/dist/resources/extensions/gsd/prompts/rewrite-docs.md +1 -1
  36. package/dist/resources/extensions/gsd/queue-reorder-ui.js +30 -13
  37. package/dist/resources/extensions/gsd/smart-entry-routing.js +36 -0
  38. package/dist/resources/extensions/gsd/state-reconciliation/drift/project-md.js +9 -14
  39. package/dist/resources/extensions/gsd/state-reconciliation/drift/roadmap.js +19 -24
  40. package/dist/resources/extensions/gsd/status-guards.js +7 -0
  41. package/dist/resources/extensions/gsd/workflow-mcp.js +17 -1
  42. package/dist/tsconfig.extensions.tsbuildinfo +1 -1
  43. package/dist/web/standalone/.next/BUILD_ID +1 -1
  44. package/dist/web/standalone/.next/app-path-routes-manifest.json +9 -9
  45. package/dist/web/standalone/.next/build-manifest.json +2 -2
  46. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  47. package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
  48. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  49. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  50. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  51. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  52. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  53. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  54. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  55. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  56. package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
  57. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
  58. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  59. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
  60. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  61. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  62. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  63. package/dist/web/standalone/.next/server/app/api/browse-directories/route.js +1 -1
  64. package/dist/web/standalone/.next/server/app/index.html +1 -1
  65. package/dist/web/standalone/.next/server/app/index.rsc +1 -1
  66. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
  67. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +1 -1
  68. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  69. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
  70. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  71. package/dist/web/standalone/.next/server/app-paths-manifest.json +9 -9
  72. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  73. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  74. package/dist/web/standalone/.next/server/pages/500.html +1 -1
  75. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  76. package/package.json +1 -1
  77. package/packages/pi-ai/dist/providers/google-gemini-cli.d.ts.map +1 -1
  78. package/packages/pi-ai/dist/providers/google-gemini-cli.js +5 -0
  79. package/packages/pi-ai/dist/providers/google-gemini-cli.js.map +1 -1
  80. package/packages/pi-ai/dist/providers/google-gemini-cli.test.d.ts +2 -0
  81. package/packages/pi-ai/dist/providers/google-gemini-cli.test.d.ts.map +1 -0
  82. package/packages/pi-ai/dist/providers/google-gemini-cli.test.js +41 -0
  83. package/packages/pi-ai/dist/providers/google-gemini-cli.test.js.map +1 -0
  84. package/packages/pi-ai/src/providers/google-gemini-cli.test.ts +49 -0
  85. package/packages/pi-ai/src/providers/google-gemini-cli.ts +7 -0
  86. package/packages/pi-ai/tsconfig.tsbuildinfo +1 -1
  87. package/packages/pi-coding-agent/dist/modes/interactive/components/footer.d.ts.map +1 -1
  88. package/packages/pi-coding-agent/dist/modes/interactive/components/footer.js +24 -6
  89. package/packages/pi-coding-agent/dist/modes/interactive/components/footer.js.map +1 -1
  90. package/packages/pi-coding-agent/src/modes/interactive/components/footer.ts +23 -7
  91. package/packages/pi-coding-agent/tsconfig.tsbuildinfo +1 -1
  92. package/packages/pi-tui/dist/__tests__/terminal.test.d.ts +2 -0
  93. package/packages/pi-tui/dist/__tests__/terminal.test.d.ts.map +1 -0
  94. package/packages/pi-tui/dist/__tests__/terminal.test.js +103 -0
  95. package/packages/pi-tui/dist/__tests__/terminal.test.js.map +1 -0
  96. package/packages/pi-tui/dist/terminal.d.ts +2 -0
  97. package/packages/pi-tui/dist/terminal.d.ts.map +1 -1
  98. package/packages/pi-tui/dist/terminal.js +12 -0
  99. package/packages/pi-tui/dist/terminal.js.map +1 -1
  100. package/packages/pi-tui/src/__tests__/terminal.test.ts +121 -0
  101. package/packages/pi-tui/src/terminal.ts +11 -0
  102. package/packages/pi-tui/tsconfig.tsbuildinfo +1 -1
  103. package/src/resources/extensions/claude-code-cli/stream-adapter.ts +1 -1
  104. package/src/resources/extensions/claude-code-cli/tests/stream-adapter.test.ts +9 -0
  105. package/src/resources/extensions/gsd/auto/phases.ts +83 -37
  106. package/src/resources/extensions/gsd/auto-dashboard.ts +72 -1
  107. package/src/resources/extensions/gsd/auto-direct-dispatch.ts +1 -0
  108. package/src/resources/extensions/gsd/auto-dispatch.ts +10 -16
  109. package/src/resources/extensions/gsd/auto-recovery.ts +45 -11
  110. package/src/resources/extensions/gsd/auto-start.ts +2 -3
  111. package/src/resources/extensions/gsd/auto-verification.ts +22 -2
  112. package/src/resources/extensions/gsd/auto-worktree.ts +74 -9
  113. package/src/resources/extensions/gsd/auto.ts +8 -2
  114. package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +36 -6
  115. package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +4 -2
  116. package/src/resources/extensions/gsd/commands-prefs-wizard.ts +8 -3
  117. package/src/resources/extensions/gsd/crash-recovery.ts +16 -2
  118. package/src/resources/extensions/gsd/db/milestone-leases.ts +26 -0
  119. package/src/resources/extensions/gsd/doctor-git-checks.ts +45 -1
  120. package/src/resources/extensions/gsd/doctor-types.ts +1 -0
  121. package/src/resources/extensions/gsd/git-service.ts +6 -3
  122. package/src/resources/extensions/gsd/gsd-db.ts +18 -6
  123. package/src/resources/extensions/gsd/guided-flow-queue.ts +4 -3
  124. package/src/resources/extensions/gsd/guided-flow.ts +128 -133
  125. package/src/resources/extensions/gsd/guided-unit-context.ts +30 -0
  126. package/src/resources/extensions/gsd/migration-auto-check.ts +15 -23
  127. package/src/resources/extensions/gsd/pending-auto-start.ts +79 -0
  128. package/src/resources/extensions/gsd/prompts/complete-milestone.md +1 -1
  129. package/src/resources/extensions/gsd/prompts/complete-slice.md +1 -1
  130. package/src/resources/extensions/gsd/prompts/discuss-headless.md +8 -8
  131. package/src/resources/extensions/gsd/prompts/discuss.md +9 -9
  132. package/src/resources/extensions/gsd/prompts/guided-discuss-project.md +4 -4
  133. package/src/resources/extensions/gsd/prompts/guided-discuss-requirements.md +3 -3
  134. package/src/resources/extensions/gsd/prompts/plan-slice.md +1 -1
  135. package/src/resources/extensions/gsd/prompts/queue.md +4 -4
  136. package/src/resources/extensions/gsd/prompts/refine-slice.md +1 -1
  137. package/src/resources/extensions/gsd/prompts/rewrite-docs.md +1 -1
  138. package/src/resources/extensions/gsd/queue-reorder-ui.ts +31 -13
  139. package/src/resources/extensions/gsd/smart-entry-routing.ts +77 -0
  140. package/src/resources/extensions/gsd/state-reconciliation/drift/project-md.ts +12 -15
  141. package/src/resources/extensions/gsd/state-reconciliation/drift/roadmap.ts +17 -25
  142. package/src/resources/extensions/gsd/status-guards.ts +8 -0
  143. package/src/resources/extensions/gsd/tests/auto-dashboard.test.ts +71 -0
  144. package/src/resources/extensions/gsd/tests/auto-loop.test.ts +2 -0
  145. package/src/resources/extensions/gsd/tests/auto-paused-ui-cleanup.test.ts +29 -1
  146. package/src/resources/extensions/gsd/tests/auto-phases-lifecycle.test.ts +53 -2
  147. package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +76 -5
  148. package/src/resources/extensions/gsd/tests/auto-stop-notification.test.ts +20 -0
  149. package/src/resources/extensions/gsd/tests/checkout-branch-stash-guard.test.ts +87 -0
  150. package/src/resources/extensions/gsd/tests/clear-stale-autostart.test.ts +11 -2
  151. package/src/resources/extensions/gsd/tests/complete-slice.test.ts +5 -9
  152. package/src/resources/extensions/gsd/tests/crash-recovery-via-db.test.ts +43 -0
  153. package/src/resources/extensions/gsd/tests/custom-engine-loop-integration.test.ts +2 -0
  154. package/src/resources/extensions/gsd/tests/db-authority-regression.test.ts +208 -0
  155. package/src/resources/extensions/gsd/tests/dispatch-complete-milestone-guard.test.ts +27 -0
  156. package/src/resources/extensions/gsd/tests/doctor-empty-worktree.test.ts +65 -0
  157. package/src/resources/extensions/gsd/tests/gsd-db.test.ts +11 -0
  158. package/src/resources/extensions/gsd/tests/guided-discuss-project-prompt-rendering.test.ts +2 -0
  159. package/src/resources/extensions/gsd/tests/guided-dispatch-root.test.ts +106 -0
  160. package/src/resources/extensions/gsd/tests/guided-flow-session-isolation.test.ts +59 -11
  161. package/src/resources/extensions/gsd/tests/guided-tool-contract.test.ts +65 -0
  162. package/src/resources/extensions/gsd/tests/headless-milestone-parity.test.ts +7 -7
  163. package/src/resources/extensions/gsd/tests/integration/git-service.test.ts +9 -0
  164. package/src/resources/extensions/gsd/tests/journal-integration.test.ts +46 -0
  165. package/src/resources/extensions/gsd/tests/merge-db-cycle.test.ts +179 -0
  166. package/src/resources/extensions/gsd/tests/migration-auto-check.test.ts +26 -18
  167. package/src/resources/extensions/gsd/tests/pending-autostart-scope.test.ts +29 -5
  168. package/src/resources/extensions/gsd/tests/plan-slice-prompt.test.ts +2 -0
  169. package/src/resources/extensions/gsd/tests/prefs-wizard-coverage.test.ts +59 -0
  170. package/src/resources/extensions/gsd/tests/provider-errors.test.ts +37 -1
  171. package/src/resources/extensions/gsd/tests/queue-reorder-ui.test.ts +54 -0
  172. package/src/resources/extensions/gsd/tests/remediation-completion-guard.test.ts +43 -0
  173. package/src/resources/extensions/gsd/tests/run-uat-replay-cap.test.ts +2 -3
  174. package/src/resources/extensions/gsd/tests/smart-entry-routing.test.ts +113 -0
  175. package/src/resources/extensions/gsd/tests/start-auto-detached.test.ts +22 -1
  176. package/src/resources/extensions/gsd/tests/state-reconciliation-drift.test.ts +119 -23
  177. package/src/resources/extensions/gsd/tests/status-guards.test.ts +13 -1
  178. package/src/resources/extensions/gsd/tests/validate-milestone-stuck-guard.test.ts +29 -2
  179. package/src/resources/extensions/gsd/tests/workflow-mcp.test.ts +18 -0
  180. package/src/resources/extensions/gsd/workflow-mcp.ts +18 -1
  181. /package/dist/web/standalone/.next/static/{q0WYuDVbHeFFYbdd-fei2 → 4dSwdrs__8NwCZggxP9KF}/_buildManifest.js +0 -0
  182. /package/dist/web/standalone/.next/static/{q0WYuDVbHeFFYbdd-fei2 → 4dSwdrs__8NwCZggxP9KF}/_ssgManifest.js +0 -0
@@ -0,0 +1,52 @@
1
+ // GSD-2 — Pending auto-start handoff state.
2
+ // Stores discuss-to-auto handoff entries keyed by project root.
3
+ import { createWorkspace, scopeMilestone } from "./workspace.js";
4
+ const pendingAutoStartMap = new Map();
5
+ export function getPendingAutoStart(basePath) {
6
+ if (basePath)
7
+ return pendingAutoStartMap.get(basePath) ?? null;
8
+ if (pendingAutoStartMap.size === 1)
9
+ return pendingAutoStartMap.values().next().value;
10
+ return null;
11
+ }
12
+ export const _getPendingAutoStart = getPendingAutoStart;
13
+ export function hasPendingAutoStart(basePath) {
14
+ if (basePath)
15
+ return pendingAutoStartMap.has(basePath);
16
+ return pendingAutoStartMap.size > 0;
17
+ }
18
+ export function setPendingAutoStart(basePath, entry) {
19
+ if (!entry.ctx || !entry.pi) {
20
+ throw new Error("setPendingAutoStart requires ctx and pi");
21
+ }
22
+ const ws = createWorkspace(entry.basePath);
23
+ const scope = scopeMilestone(ws, entry.milestoneId);
24
+ pendingAutoStartMap.set(basePath, {
25
+ createdAt: Date.now(),
26
+ planBlockedRecoveryCount: 0,
27
+ ...entry,
28
+ scope,
29
+ ctx: entry.ctx,
30
+ pi: entry.pi,
31
+ });
32
+ }
33
+ export function deletePendingAutoStart(basePath) {
34
+ pendingAutoStartMap.delete(basePath);
35
+ }
36
+ export function clearPendingAutoStart(basePath) {
37
+ if (basePath) {
38
+ pendingAutoStartMap.delete(basePath);
39
+ }
40
+ else {
41
+ pendingAutoStartMap.clear();
42
+ }
43
+ }
44
+ export function getDiscussionMilestoneId(basePath) {
45
+ if (basePath) {
46
+ return pendingAutoStartMap.get(basePath)?.milestoneId ?? null;
47
+ }
48
+ if (pendingAutoStartMap.size === 1) {
49
+ return pendingAutoStartMap.values().next().value.milestoneId;
50
+ }
51
+ return null;
52
+ }
@@ -57,7 +57,7 @@ Subagents report only; they do not write user source. Fold any findings into Dec
57
57
  **Success path** (all verifications passed):
58
58
 
59
59
  10. For each requirement whose status changed in step 9, call `gsd_requirement_update` with the requirement ID and updated `status` and `validation` fields — the tool regenerates `.gsd/REQUIREMENTS.md` automatically. Do this BEFORE completing the milestone so requirement updates are persisted.
60
- 11. Update `.gsd/PROJECT.md`: use the `write` tool with `path: ".gsd/PROJECT.md"` and `content` containing the full updated document reflecting milestone completion and current project state. Do NOT use the `edit` tool for this PROJECT.md is a full-document refresh.
60
+ 11. Refresh the project state through `gsd_summary_save` with `artifact_type: "PROJECT"` and the full updated project markdown as `content`; omit `milestone_id`. The tool persists the DB-backed PROJECT artifact and renders `.gsd/PROJECT.md`. Do not write or edit `.gsd/PROJECT.md` directly.
61
61
  12. Extract structured learnings from this milestone and persist them to the GSD memory store. Follow the procedure block immediately below — it writes `{{milestoneId}}-LEARNINGS.md` as the audit trail and persists Patterns, Lessons, and Decisions via `capture_thought` (categories: pattern, gotcha/convention, architecture). The memory store is the single source of truth for cross-session durable knowledge (ADR-013).
62
62
 
63
63
  {{extractLearningsSteps}}
@@ -34,7 +34,7 @@ Use `subagent` only for fresh-context review when useful: reviewer for cross-cut
34
34
  12. Review the inlined task-summary excerpts for DECISIONS.md and KNOWLEDGE.md-worthy decisions, patterns, and gotchas. Read full `*-SUMMARY.md` files only when an excerpt is absent, truncated, or lacks the specific evidence needed for the slice narrative. Capture significant items with `capture_thought`; do not append knowledge files directly.
35
35
  13. When verification passes, call `gsd_slice_complete`. The DB-backed tool is the canonical write path. Do **not** manually write `{{sliceSummaryPath}}`. Do **not** manually write `{{sliceUatPath}}`. Do not edit roadmap checkboxes; the tool renders files and updates projections.
36
36
  14. Do not run git commands.
37
- 15. Update `.gsd/PROJECT.md` with a full `write` only if the current project state needs refresh.
37
+ 15. If the current project state needs refresh, call `gsd_summary_save` with `artifact_type: "PROJECT"` and the full updated project markdown as `content`; omit `milestone_id`. Do not write or edit `.gsd/PROJECT.md` directly.
38
38
 
39
39
  **Autonomous execution:** no human is available. Do not call `ask_user_questions` or `secure_env_collect`; make reasonable assumptions and document them.
40
40
 
@@ -106,8 +106,8 @@ Directories use bare IDs. Files use ID-SUFFIX format. Titles live inside content
106
106
 
107
107
  In a single pass:
108
108
  1. `mkdir -p .gsd/milestones/{{milestoneId}}/slices`
109
- 2. Write or update `.gsd/PROJECT.md` use the **Project** output template below. Describe what the project is, its current state, and list the milestone sequence.
110
- 3. Write or update `.gsd/REQUIREMENTS.md` use the **Requirements** output template below. Confirm states, ownership, and traceability before roadmap creation.
109
+ 2. Call `gsd_summary_save` with `artifact_type: "PROJECT"` and full Project template content. The tool persists the DB-backed PROJECT artifact and renders `.gsd/PROJECT.md`. Describe what the project is, its current state, and list the milestone sequence.
110
+ 3. Persist requirements with `gsd_requirement_save` or `gsd_requirement_update`, then call `gsd_summary_save` with `artifact_type: "REQUIREMENTS"` so the tool renders `.gsd/REQUIREMENTS.md` from DB rows. Confirm states, ownership, and traceability before roadmap creation.
111
111
 
112
112
  **Depth-Preservation Guidance for context.md:** Preserve the specification's exact terminology, emphasis, and framing. Do not flatten domain-specific language into generics. CONTEXT.md is downstream agents' only window into this spec.
113
113
 
@@ -120,8 +120,8 @@ In a single pass:
120
120
 
121
121
  Before emitting the ready phrase, verify in the CURRENT turn that you have:
122
122
 
123
- - [ ] Written `.gsd/PROJECT.md` (step 2)
124
- - [ ] Written `.gsd/REQUIREMENTS.md` (step 3)
123
+ - [ ] Called `gsd_summary_save` for the PROJECT artifact (step 2)
124
+ - [ ] Persisted requirements and called `gsd_summary_save` for the REQUIREMENTS artifact (step 3)
125
125
  - [ ] Written `{{contextPath}}` (step 4)
126
126
  - [ ] Called `gsd_plan_milestone` (step 5)
127
127
 
@@ -145,8 +145,8 @@ Next steps:
145
145
  #### Phase 1: Shared artifacts
146
146
 
147
147
  1. For each milestone, call `gsd_milestone_generate_id`; never invent IDs. Then `mkdir -p .gsd/milestones/<ID>/slices`.
148
- 2. Write `.gsd/PROJECT.md` use the **Project** output template below.
149
- 3. Write `.gsd/REQUIREMENTS.md` use the **Requirements** output template below. Capture Active, Deferred, Out of Scope, and any already Validated requirements. Later milestones may have provisional ownership where slice plans do not exist yet.
148
+ 2. Call `gsd_summary_save` with `artifact_type: "PROJECT"` and full Project template content so the tool persists the DB-backed PROJECT artifact and renders `.gsd/PROJECT.md`.
149
+ 3. Persist requirements with `gsd_requirement_save` or `gsd_requirement_update`, then call `gsd_summary_save` with `artifact_type: "REQUIREMENTS"` so the tool renders `.gsd/REQUIREMENTS.md` from DB rows. Capture Active, Deferred, Out of Scope, and any already Validated requirements. Later milestones may have provisional ownership where slice plans do not exist yet.
150
150
  4. For any architectural or pattern decisions, call `gsd_decision_save` — the tool auto-assigns IDs and regenerates `.gsd/DECISIONS.md` automatically.
151
151
 
152
152
  #### Phase 2: Primary milestone
@@ -214,8 +214,8 @@ For single-milestone projects, do NOT write this file.
214
214
 
215
215
  Before emitting the ready phrase, verify in the CURRENT turn that you have:
216
216
 
217
- - [ ] Written `.gsd/PROJECT.md`
218
- - [ ] Written `.gsd/REQUIREMENTS.md`
217
+ - [ ] Called `gsd_summary_save` for the PROJECT artifact
218
+ - [ ] Persisted requirements and called `gsd_summary_save` for the REQUIREMENTS artifact
219
219
  - [ ] Written the primary milestone `CONTEXT.md`
220
220
  - [ ] Called `gsd_plan_milestone` for the primary milestone
221
221
  - [ ] Written `.gsd/DISCUSSION-MANIFEST.json` with `gates_completed === total`
@@ -186,7 +186,7 @@ Research is advisory, not auto-binding. Use discussion output to identify table
186
186
 
187
187
  ## Capability Contract
188
188
 
189
- Before writing a roadmap, produce or update `.gsd/REQUIREMENTS.md`.
189
+ Before writing a roadmap, persist requirements with `gsd_requirement_save` or `gsd_requirement_update`, then render `.gsd/REQUIREMENTS.md` through `gsd_summary_save` with `artifact_type: "REQUIREMENTS"`.
190
190
 
191
191
  Use it as the project's explicit capability contract.
192
192
 
@@ -226,8 +226,8 @@ Directories use bare IDs. Files use ID-SUFFIX format. Titles live inside file co
226
226
 
227
227
  Once the user is satisfied, in a single pass:
228
228
  1. `mkdir -p .gsd/milestones/{{milestoneId}}/slices`
229
- 2. Write or update `.gsd/PROJECT.md` use the **Project** output template below. Describe what the project is, its current state, and list the milestone sequence.
230
- 3. Write or update `.gsd/REQUIREMENTS.md` use the **Requirements** output template below. Confirm requirement states, ownership, and traceability before roadmap creation.
229
+ 2. Call `gsd_summary_save` with `artifact_type: "PROJECT"` and full Project template content. The tool persists the DB-backed PROJECT artifact and renders `.gsd/PROJECT.md`. Describe what the project is, its current state, and list the milestone sequence.
230
+ 3. Persist requirements with `gsd_requirement_save` or `gsd_requirement_update`, then call `gsd_summary_save` with `artifact_type: "REQUIREMENTS"` so the tool renders `.gsd/REQUIREMENTS.md` from DB rows. Confirm requirement states, ownership, and traceability before roadmap creation.
231
231
  **Depth-Preservation Guidance for context.md:**
232
232
  When writing context.md, preserve the user's exact terminology, emphasis, and framing. Do not flatten nuance into generic summaries. If the user said "craft feel," write "craft feel," not "high-quality user experience." CONTEXT.md is downstream agents' only window into this conversation.
233
233
 
@@ -243,8 +243,8 @@ When writing CONTEXT.md, include discussion-layer sections: **Scope**, **Archite
243
243
 
244
244
  Before emitting the ready phrase, verify in the CURRENT turn that you have:
245
245
 
246
- - [ ] Written `.gsd/PROJECT.md` (step 2)
247
- - [ ] Written `.gsd/REQUIREMENTS.md` (step 3)
246
+ - [ ] Called `gsd_summary_save` for the PROJECT artifact (step 2)
247
+ - [ ] Persisted requirements and called `gsd_summary_save` for the REQUIREMENTS artifact (step 3)
248
248
  - [ ] Written `{{contextPath}}` (step 4)
249
249
  - [ ] Called `gsd_plan_milestone` (step 5)
250
250
 
@@ -270,8 +270,8 @@ Once the user confirms the milestone split:
270
270
  #### Phase 1: Shared artifacts
271
271
 
272
272
  1. For each milestone, call `gsd_milestone_generate_id`; never invent IDs. Then `mkdir -p .gsd/milestones/<ID>/slices`.
273
- 2. Write `.gsd/PROJECT.md` use the **Project** output template below.
274
- 3. Write `.gsd/REQUIREMENTS.md` use the **Requirements** output template below. Capture Active, Deferred, Out of Scope, and any already Validated requirements. Later milestones may have provisional ownership where slice plans do not exist yet.
273
+ 2. Call `gsd_summary_save` with `artifact_type: "PROJECT"` and full Project template content so the tool persists the DB-backed PROJECT artifact and renders `.gsd/PROJECT.md`.
274
+ 3. Persist requirements with `gsd_requirement_save` or `gsd_requirement_update`, then call `gsd_summary_save` with `artifact_type: "REQUIREMENTS"` so the tool renders `.gsd/REQUIREMENTS.md` from DB rows. Capture Active, Deferred, Out of Scope, and any already Validated requirements. Later milestones may have provisional ownership where slice plans do not exist yet.
275
275
  4. For any architectural or pattern decisions made during discussion, call `gsd_decision_save` — the tool auto-assigns IDs and regenerates `.gsd/DECISIONS.md` automatically.
276
276
 
277
277
  #### Phase 2: Primary milestone
@@ -344,8 +344,8 @@ For single-milestone projects, do NOT write this file.
344
344
 
345
345
  Before emitting the ready phrase, verify in the CURRENT turn that you have:
346
346
 
347
- - [ ] Written `.gsd/PROJECT.md` (Phase 1)
348
- - [ ] Written `.gsd/REQUIREMENTS.md` (Phase 1)
347
+ - [ ] Called `gsd_summary_save` for the PROJECT artifact (Phase 1)
348
+ - [ ] Persisted requirements and called `gsd_summary_save` for the REQUIREMENTS artifact (Phase 1)
349
349
  - [ ] Written primary-milestone `CONTEXT.md` (Phase 2)
350
350
  - [ ] Called `gsd_plan_milestone` for the primary milestone (Phase 2)
351
351
  - [ ] Written `.gsd/DISCUSSION-MANIFEST.json` with `gates_completed === total` (Phase 3)
@@ -1,6 +1,6 @@
1
1
  **Working directory:** `{{workingDirectory}}`. All file reads, writes, and shell commands MUST operate relative to this directory. Do NOT `cd` elsewhere. For `.gsd` files, use absolute paths rooted at `{{workingDirectory}}`, not `Glob`.
2
2
 
3
- Discuss the **project** as a whole: vision, users, anti-goals, constraints, and rough milestone sequence. Ask only real gray areas, then write `.gsd/PROJECT.md` with the **Project** template below. If a `GSD Skill Preferences` block exists, use it; artifact rules still apply.
3
+ Discuss the **project** as a whole: vision, users, anti-goals, constraints, and rough milestone sequence. Ask only real gray areas, then persist the final Project template through `gsd_summary_save` with `artifact_type: "PROJECT"`. The tool renders `.gsd/PROJECT.md`; do not write the projection directly. If a `GSD Skill Preferences` block exists, use it; artifact rules still apply.
4
4
 
5
5
  This runs once before milestone discussion. Later milestones, requirements, and roadmaps depend on it.
6
6
 
@@ -34,7 +34,7 @@ After the opening answer, classify project shape as **`simple`** or **`complex`*
34
34
 
35
35
  **Default to `complex` when uncertain.** The user can override the verdict in plain text; if they do, accept it and proceed.
36
36
 
37
- Persist the verdict to PROJECT.md -> `## Project Shape`; downstream `discuss-requirements`, `discuss-milestone`, and `discuss-slice` read it from there.
37
+ Persist the verdict through `gsd_summary_save` with `artifact_type: "PROJECT"` into `## Project Shape`; downstream `discuss-requirements`, `discuss-milestone`, and `discuss-slice` read the rendered projection.
38
38
 
39
39
  ### Before deeper rounds
40
40
 
@@ -95,7 +95,7 @@ If they clarify, absorb the correction and re-verify.
95
95
 
96
96
  The depth verification is the only required confirmation gate. Do not add a second "ready to proceed?" gate after it.
97
97
 
98
- **CRITICAL — Confirmation gate:** Do not write final PROJECT.md until the user selects the "(Recommended)" option (structured path) or explicitly confirms (plain-text path). If the user declines, cancels, does not respond, or the tool fails, re-ask.
98
+ **CRITICAL — Confirmation gate:** Do not persist final PROJECT content until the user selects the "(Recommended)" option (structured path) or explicitly confirms (plain-text path). If the user declines, cancels, does not respond, or the tool fails, re-ask.
99
99
 
100
100
  ---
101
101
 
@@ -104,7 +104,7 @@ The depth verification is the only required confirmation gate. Do not add a seco
104
104
  Once the user confirms depth:
105
105
 
106
106
  1. Use the **Project** output template (inlined above).
107
- 2. Call `gsd_summary_save` with `artifact_type: "PROJECT"` and full project markdown as `content`; omit `milestone_id`. The tool writes `.gsd/PROJECT.md` and persists to DB. Preserve the user's terms and framing.
107
+ 2. Call `gsd_summary_save` with `artifact_type: "PROJECT"` and full project markdown as `content`; omit `milestone_id`. The tool persists the DB-backed PROJECT artifact and renders `.gsd/PROJECT.md`. Preserve the user's terms and framing.
108
108
  3. The `## Project Shape` section MUST contain `**Complexity:** simple` or `**Complexity:** complex` (matching the verdict you announced) plus a one-line `**Why:**` rationale. Downstream stages read this line.
109
109
  4. The `## Capability Contract` section MUST reference `.gsd/REQUIREMENTS.md` — that file does not yet exist; the next stage (`discuss-requirements`) will produce it.
110
110
  5. The `## Milestone Sequence` MUST list at least M001 with title and one-liner. Subsequent milestones may be listed as known intents; they will be elaborated in their own discuss-milestone stages.
@@ -1,6 +1,6 @@
1
1
  **Working directory:** `{{workingDirectory}}`. All file reads, writes, and shell commands MUST operate relative to this directory. Do NOT `cd` elsewhere. For `.gsd` files, use absolute paths rooted at `{{workingDirectory}}`, not `Glob`.
2
2
 
3
- Discuss **project-level requirements**. Read `.gsd/PROJECT.md` first; it is authoritative for vision, core value, anti-goals, and milestone sequence. Requirements must trace to it. Ask capability gray areas, then write `.gsd/REQUIREMENTS.md` using v2 `R###` format and the **Requirements** template.
3
+ Discuss **project-level requirements**. Read `.gsd/PROJECT.md` first; it is the rendered project artifact for vision, core value, anti-goals, and milestone sequence. Requirements must trace to it. Ask capability gray areas, then persist requirements with `gsd_requirement_save` and render `.gsd/REQUIREMENTS.md` through `gsd_summary_save` using v2 `R###` format and the **Requirements** template.
4
4
 
5
5
  This runs once after `discuss-project` and before milestone work, creating the capability contract for milestones, slices, and verification.
6
6
 
@@ -25,7 +25,7 @@ Before your first action, print this banner verbatim in chat:
25
25
  3. If `.gsd/REQUIREMENTS.md` exists, read it as the working set.
26
26
 
27
27
  **Shape-dependent cadence:**
28
- - **`simple`**: one fast pass. Extract from PROJECT.md, ask 1-2 plain-text clarifiers only when class/status is ambiguous, then write REQUIREMENTS.md.
28
+ - **`simple`**: one fast pass. Extract from PROJECT.md, ask 1-2 plain-text clarifiers only when class/status is ambiguous, then persist requirements through the DB-backed tools.
29
29
  - **`complex`**: multi-round questioning with structured 3-4-option questions where alternatives matter.
30
30
 
31
31
  ---
@@ -81,7 +81,7 @@ Before the wrap-up gate, verify: every milestone has an Active requirement; Core
81
81
 
82
82
  If they adjust, absorb and re-verify.
83
83
 
84
- **CRITICAL — Confirmation gate:** Do not write final REQUIREMENTS.md until explicit confirmation. Never rationalize past it.
84
+ **CRITICAL — Confirmation gate:** Do not persist final REQUIREMENTS content until explicit confirmation. Never rationalize past it.
85
85
 
86
86
  ---
87
87
 
@@ -42,7 +42,7 @@ If slice research is inlined, trust its architectural findings, but verify every
42
42
  8. Each task needs the exact `gsd_plan_slice.tasks[]` shape: `taskId`, `title`, `description`, `estimate`, `files`, `verify`, `inputs`, `expectedOutput`, and optional `observabilityImpact`. `description` should contain the Why / Do / Done-when narrative. `files`, `inputs`, and `expectedOutput` must be JSON arrays of strings, even when there is only one path (for example, `"inputs": ["src/index.ts"]`, never `"inputs": "src/index.ts"`). Use paths relative to `{{workingDirectory}}`; do not put absolute paths to the original checkout or any directory outside `{{workingDirectory}}` in `files`, `inputs`, `expectedOutput`, or verification commands. **`expectedOutput` must only list files the task actually creates or overwrites on disk.** Do NOT include files the task merely reads, verifies, or tests — those belong only in `inputs`. If a task is a pure verification or test task that produces no new files, `expectedOutput` may be `[]` or limited to test-result artifacts (e.g. a log or assertion output). A file that does not yet exist on disk and is needed as an `input` must be produced by an earlier task's `expectedOutput` — if no prior task creates it, add a task before this one that does.
43
43
  9. Persist with `gsd_plan_slice` using `milestoneId`, `sliceId`, `goal`, optional `successCriteria`/`proofLevel`/`integrationClosure`/`observabilityImpact`, and `tasks`. `gsd_plan_slice` handles task persistence transactionally and renders `{{outputPath}}` plus task plans; do not call `gsd_plan_task`. The DB-backed tool is the canonical write path. Do **not** rely on direct `PLAN.md` writes as the source of truth.
44
44
  10. Self-audit before finishing: goal/demo closure, requirement coverage, locked decisions, concrete paths, dependency order, wiring, scope size, proof truthfulness, feature completeness, and quality gates. Quality gates: non-trivial slices/tasks include specific Q3-Q7 coverage where applicable.
45
- 11. If planning creates structural decisions, append them to `.gsd/DECISIONS.md`.
45
+ 11. If planning creates structural decisions, call `gsd_decision_save` for each; the tool persists the decision and regenerates `.gsd/DECISIONS.md`.
46
46
  12. {{commitInstruction}}
47
47
 
48
48
  The slice directory already exists. Do not mkdir.
@@ -114,10 +114,10 @@ Once the user is satisfied, in one pass for **each** new milestone:
114
114
 
115
115
  After all milestone directories and context files are written:
116
116
 
117
- 3. Update `.gsd/PROJECT.md` by adding new milestones to the Milestone Sequence. Keep existing entries exactly as-is; only add new lines.
118
- 4. If `.gsd/REQUIREMENTS.md` exists and the queued work introduces new in-scope capabilities or promotes Deferred items, update it.
119
- 5. If discussion produced decisions relevant to existing work, append to `.gsd/DECISIONS.md`.
120
- 6. Append to `.gsd/QUEUE.md`.
117
+ 3. Refresh project state through `gsd_summary_save` with `artifact_type: "PROJECT"` and full PROJECT content that includes the new milestones in the Milestone Sequence; omit `milestone_id`.
118
+ 4. If the queued work introduces new in-scope capabilities or promotes Deferred items, persist those changes with `gsd_requirement_save` or `gsd_requirement_update`, then call `gsd_summary_save` with `artifact_type: "REQUIREMENTS"` so `.gsd/REQUIREMENTS.md` renders from DB rows.
119
+ 5. If discussion produced decisions relevant to existing work, call `gsd_decision_save` for each decision; the tool regenerates `.gsd/DECISIONS.md`.
120
+ 6. If `.gsd/QUEUE.md` is maintained, update it only as an audit projection of queued intent. Runtime queue state must come from the DB-backed milestone/context tool calls above.
121
121
  7. {{commitInstruction}}
122
122
 
123
123
  **Do NOT write roadmaps for queued milestones.**
@@ -67,7 +67,7 @@ Then:
67
67
  5. Decompose the slice into tasks that fit one context window each. Every task passed to `gsd_plan_slice` must use the exact keys `taskId`, `title`, `description`, `estimate`, `files`, `verify`, `inputs`, `expectedOutput`, and optional `observabilityImpact`. Put Why / Do / Done-when detail in `description`. `files`, `inputs`, and `expectedOutput` must be JSON arrays of strings, even for one path (for example, `"expectedOutput": ["src/index.ts"]`, never `"expectedOutput": "src/index.ts"`).
68
68
  6. **Persist planning state through `gsd_plan_slice`.** Call it with the full payload. The tool writes to the DB and renders `{{outputPath}}` and `{{slicePath}}/tasks/T##-PLAN.md` automatically. Do NOT rely on direct `PLAN.md` writes.
69
69
  7. **Self-audit the plan.** If every task were completed exactly as written, the slice goal/demo should be true. Every must-have maps to a task. Inputs and Expected Output are backtick-wrapped file paths.
70
- 8. If refinement produced structural decisions that diverge from the sketch, append them to `.gsd/DECISIONS.md`.
70
+ 8. If refinement produced structural decisions that diverge from the sketch, call `gsd_decision_save` for each; the tool persists the decision and regenerates `.gsd/DECISIONS.md`.
71
71
  9. {{commitInstruction}}
72
72
 
73
73
  The slice directory and tasks/ subdirectory already exist. Do NOT mkdir.
@@ -23,7 +23,7 @@ An override was issued by the user that changes a fundamental decision or approa
23
23
  - For DECISIONS.md: append a new decision entry documenting the override and why. Do NOT delete prior decisions — mark them as superseded with a note.
24
24
  - For slice plans (S##-PLAN.md): update Goal, Demo, and Verification sections if affected. Update Files Likely Touched if the override changes scope. Do NOT modify completed task entries.
25
25
  - For REQUIREMENTS.md: update requirement descriptions if the override changes what "done" means, but do not remove requirements.
26
- - For PROJECT.md: update if the override changes project-level facts.
26
+ - For PROJECT.md: do not edit the projection directly. If the override changes project-level facts, persist the revised Project content through `gsd_summary_save` with `artifact_type: "PROJECT"` so the DB remains authoritative.
27
27
  - Milestone context files are reference only — do not modify them.
28
28
  4. Mark all active overrides as resolved: change `**Scope:** active` to `**Scope:** resolved` in `{{overridesPath}}`
29
29
  5. Do not commit manually — the system auto-commits your changes after this unit completes.
@@ -24,6 +24,7 @@ export async function showQueueReorder(ctx, completed, pending) {
24
24
  const items = [...pending];
25
25
  let cursor = 0;
26
26
  let grabbed = false;
27
+ let scrollOffset = 0;
27
28
  let cachedLines;
28
29
  let validation;
29
30
  // Mutable deps map — tracks removals during this session
@@ -128,9 +129,11 @@ export async function showQueueReorder(ctx, completed, pending) {
128
129
  return cachedLines;
129
130
  const ui = makeUI(theme, width);
130
131
  const lines = [];
132
+ const queueRows = [];
131
133
  const push = (...rows) => { for (const r of rows)
132
134
  lines.push(...r); };
133
135
  const add = (s) => truncateToWidth(s, width);
136
+ let cursorQueueRow = 0;
134
137
  const headerText = grabbed ? " Queue Reorder — Moving Item" : " Queue Reorder";
135
138
  push(ui.bar(), ui.blank(), ui.header(headerText), ui.blank());
136
139
  // Completed milestones (dimmed)
@@ -153,13 +156,15 @@ export async function showQueueReorder(ctx, completed, pending) {
153
156
  const num = i + 1;
154
157
  const label = item.title && item.title !== item.id ? `${item.id} ${item.title}` : item.id;
155
158
  if (isCursor && grabbed) {
156
- lines.push(add(` ${theme.fg("warning", `▸▸ ${num}. ${label}`)}`));
159
+ cursorQueueRow = queueRows.length;
160
+ queueRows.push(add(` ${theme.fg("warning", `▸▸ ${num}. ${label}`)}`));
157
161
  }
158
162
  else if (isCursor) {
159
- lines.push(add(` ${theme.fg("accent", `${GLYPH.cursor} ${num}. ${label}`)}`));
163
+ cursorQueueRow = queueRows.length;
164
+ queueRows.push(add(` ${theme.fg("accent", `${GLYPH.cursor} ${num}. ${label}`)}`));
160
165
  }
161
166
  else {
162
- lines.push(add(` ${theme.fg("text", `${num}. ${label}`)}`));
167
+ queueRows.push(add(` ${theme.fg("text", `${num}. ${label}`)}`));
163
168
  }
164
169
  // depends_on annotations
165
170
  const deps = liveDeps.get(item.id) ?? [];
@@ -168,34 +173,35 @@ export async function showQueueReorder(ctx, completed, pending) {
168
173
  continue;
169
174
  const pairKey = `${item.id}:${dep}`;
170
175
  if (violatedPairs.has(pairKey)) {
171
- lines.push(add(` ${theme.fg("warning", `${GLYPH.statusWarning} depends_on: ${dep} — auto-removed on confirm`)}`));
176
+ queueRows.push(add(` ${theme.fg("warning", `${GLYPH.statusWarning} depends_on: ${dep} — auto-removed on confirm`)}`));
172
177
  }
173
178
  else if (redundantPairs.has(pairKey)) {
174
- lines.push(add(` ${theme.fg("dim", `↳ depends_on: ${dep} (redundant)`)}`));
179
+ queueRows.push(add(` ${theme.fg("dim", `↳ depends_on: ${dep} (redundant)`)}`));
175
180
  }
176
181
  else {
177
- lines.push(add(` ${theme.fg("dim", `↳ depends_on: ${dep}`)}`));
182
+ queueRows.push(add(` ${theme.fg("dim", `↳ depends_on: ${dep}`)}`));
178
183
  }
179
184
  }
180
185
  // Missing deps
181
186
  for (const v of validation.violations.filter(v => v.milestone === item.id && v.type === 'missing_dep')) {
182
- lines.push(add(` ${theme.fg("error", `${GLYPH.statusWarning} depends_on: ${v.dependsOn} (does not exist)`)}`));
187
+ queueRows.push(add(` ${theme.fg("error", `${GLYPH.statusWarning} depends_on: ${v.dependsOn} (does not exist)`)}`));
183
188
  }
184
189
  }
185
190
  // Removed deps feedback
191
+ const trailingLines = [];
186
192
  if (removedDeps.length > 0) {
187
- push(ui.blank());
193
+ trailingLines.push(...ui.blank());
188
194
  for (const r of removedDeps) {
189
- lines.push(add(` ${theme.fg("success", `${GLYPH.statusDone} Removed: ${r.milestone} depends_on ${r.dep}`)}`));
195
+ trailingLines.push(add(` ${theme.fg("success", `${GLYPH.statusDone} Removed: ${r.milestone} depends_on ${r.dep}`)}`));
190
196
  }
191
197
  }
192
198
  // Circular warning
193
199
  const circ = validation.violations.find(v => v.type === 'circular');
194
200
  if (circ) {
195
- push(ui.blank());
196
- lines.push(add(` ${theme.fg("error", `${GLYPH.statusWarning} ${circ.message}`)}`));
201
+ trailingLines.push(...ui.blank());
202
+ trailingLines.push(add(` ${theme.fg("error", `${GLYPH.statusWarning} ${circ.message}`)}`));
197
203
  }
198
- push(ui.blank());
204
+ trailingLines.push(...ui.blank());
199
205
  // Hints — context-sensitive based on grab state
200
206
  const hints = [];
201
207
  if (grabbed) {
@@ -215,7 +221,18 @@ export async function showQueueReorder(ctx, completed, pending) {
215
221
  hints.push("enter ok");
216
222
  }
217
223
  hints.push("esc");
218
- push(ui.hints(hints), ui.bar());
224
+ trailingLines.push(...ui.hints(hints), ...ui.bar());
225
+ const maxOverlayRows = Math.max(10, process.stdout.rows ? Math.floor(process.stdout.rows * 0.8) : 24);
226
+ const availableQueueRows = Math.max(1, maxOverlayRows - lines.length - trailingLines.length);
227
+ const maxScroll = Math.max(0, queueRows.length - availableQueueRows);
228
+ if (cursorQueueRow < scrollOffset) {
229
+ scrollOffset = cursorQueueRow;
230
+ }
231
+ else if (cursorQueueRow >= scrollOffset + availableQueueRows) {
232
+ scrollOffset = cursorQueueRow - availableQueueRows + 1;
233
+ }
234
+ scrollOffset = Math.min(Math.max(scrollOffset, 0), maxScroll);
235
+ lines.push(...queueRows.slice(scrollOffset, scrollOffset + availableQueueRows), ...trailingLines);
219
236
  cachedLines = lines;
220
237
  return lines;
221
238
  }
@@ -0,0 +1,36 @@
1
+ // GSD-2 — Smart entry routing decisions.
2
+ // Pure route selection for /gsd guided wizard choices.
3
+ export function resolveGuidedExecuteLaunchMode(isolationMode) {
4
+ return isolationMode === "worktree" ? "auto-step" : "guided-dispatch";
5
+ }
6
+ export function resolveActiveTaskChoiceRoute(input) {
7
+ if (input.choice === "auto") {
8
+ return {
9
+ kind: "auto-bootstrap",
10
+ verboseMode: false,
11
+ };
12
+ }
13
+ if (input.choice === "execute") {
14
+ if (resolveGuidedExecuteLaunchMode(input.isolationMode) === "auto-step") {
15
+ return {
16
+ kind: "auto-bootstrap",
17
+ verboseMode: false,
18
+ options: {
19
+ step: true,
20
+ milestoneLock: input.milestoneId,
21
+ },
22
+ };
23
+ }
24
+ return {
25
+ kind: "guided-dispatch",
26
+ unitType: "execute-task",
27
+ };
28
+ }
29
+ if (input.choice === "status") {
30
+ return { kind: "status" };
31
+ }
32
+ if (input.choice === "milestone_actions") {
33
+ return { kind: "milestone-actions" };
34
+ }
35
+ throw new Error(`Invalid ActiveTaskChoice: ${input.choice}`);
36
+ }
@@ -1,12 +1,11 @@
1
1
  // Project/App: GSD-2
2
2
  // File Purpose: ADR-017 unregistered-milestone drift handler. Detects
3
3
  // milestones whose on-disk directory has meaningful content (ROADMAP/
4
- // CONTEXT/SUMMARY) but no DB row, then runs the markdown importer to
5
- // reconcile. PROJECT.md is the human-facing index the importer's source
6
- // of truth is the .gsd/milestones/ directory tree.
4
+ // CONTEXT/SUMMARY) but no DB row, then fails closed with an explicit recovery
5
+ // instruction. Markdown hierarchy import is reserved for operator-controlled
6
+ // migration/recovery commands, not automatic runtime reconciliation.
7
7
  import { existsSync } from "node:fs";
8
8
  import { getMilestone, isDbAvailable } from "../../gsd-db.js";
9
- import { migrateHierarchyToDb } from "../../md-importer.js";
10
9
  import { findMilestoneIds } from "../../milestone-ids.js";
11
10
  import { resolveMilestoneFile } from "../../paths.js";
12
11
  function milestoneHasContent(basePath, milestoneId) {
@@ -31,17 +30,13 @@ export function detectUnregisteredMilestoneDrift(_state, ctx) {
31
30
  return drifts;
32
31
  }
33
32
  /**
34
- * Repair: invoke the markdown importer. migrateHierarchyToDb walks the same
35
- * findMilestoneIds list the detector uses and INSERTs OR IGNOREs every
36
- * missing milestone (and its slices/tasks) idempotent under cap=2 retry.
37
- *
38
- * Note: even though we receive one record at a time, the importer is a
39
- * project-wide operation. Repeated invocation across multiple drift records
40
- * in the same pass is wasteful but safe; a future optimization could
41
- * coalesce by checking whether the importer has already run this pass.
33
+ * Repair intentionally fails closed. The project-root DB is authoritative at
34
+ * runtime; markdown-only milestones must be imported through an explicit
35
+ * migration/recovery command so operators opt into changing canonical state.
42
36
  */
43
- export function repairUnregisteredMilestone(_record, ctx) {
44
- migrateHierarchyToDb(ctx.basePath);
37
+ export function repairUnregisteredMilestone(record, _ctx) {
38
+ throw new Error(`Milestone ${record.milestoneId} exists only as markdown projection. ` +
39
+ "Runtime reconciliation will not import markdown into the authoritative DB; run explicit GSD recovery/migration if this markdown should repopulate the database.");
45
40
  }
46
41
  export const unregisteredMilestoneHandler = {
47
42
  kind: "unregistered-milestone",
@@ -1,14 +1,15 @@
1
1
  // Project/App: GSD-2
2
2
  // File Purpose: ADR-017 roadmap-divergence drift handler. Detects mismatches
3
- // between ROADMAP.md (parsed slice sequence + depends declarations) and the
4
- // DB slice rows for that milestone, then reconciles via the markdown
5
- // importer plus an explicit junction-table sync.
3
+ // between ROADMAP.md (parsed slice sequence, depends declarations, and
4
+ // checkboxes) and the DB slice rows for that milestone, then re-renders the
5
+ // ROADMAP projection from the authoritative DB rows.
6
6
  import { existsSync, readFileSync } from "node:fs";
7
- import { getMilestone, getMilestoneSlices, isDbAvailable, syncSliceDependencies, } from "../../gsd-db.js";
8
- import { migrateHierarchyToDb } from "../../md-importer.js";
7
+ import { getMilestone, getMilestoneSlices, isDbAvailable, } from "../../gsd-db.js";
8
+ import { renderRoadmapFromDb } from "../../markdown-renderer.js";
9
9
  import { findMilestoneIds } from "../../milestone-ids.js";
10
10
  import { parseRoadmap } from "../../parsers-legacy.js";
11
11
  import { resolveMilestoneFile } from "../../paths.js";
12
+ import { isClosedStatus } from "../../status-guards.js";
12
13
  function arraysEqual(a, b) {
13
14
  if (a.length !== b.length)
14
15
  return false;
@@ -30,8 +31,10 @@ function milestoneHasDivergence(basePath, milestoneId) {
30
31
  }
31
32
  const dbSlices = getMilestoneSlices(milestoneId);
32
33
  const dbSliceMap = new Map(dbSlices.map((s) => [s.id, s]));
34
+ const roadmapSliceIds = new Set();
33
35
  for (let i = 0; i < roadmap.slices.length; i++) {
34
36
  const roadmapSlice = roadmap.slices[i];
37
+ roadmapSliceIds.add(roadmapSlice.id);
35
38
  const expectedSequence = i + 1;
36
39
  const dbSlice = dbSliceMap.get(roadmapSlice.id);
37
40
  if (!dbSlice)
@@ -40,6 +43,12 @@ function milestoneHasDivergence(basePath, milestoneId) {
40
43
  return true;
41
44
  if (!arraysEqual(dbSlice.depends, roadmapSlice.depends))
42
45
  return true;
46
+ if (isClosedStatus(dbSlice.status) !== roadmapSlice.done)
47
+ return true;
48
+ }
49
+ for (const dbSlice of dbSlices) {
50
+ if (!roadmapSliceIds.has(dbSlice.id))
51
+ return true;
43
52
  }
44
53
  return false;
45
54
  }
@@ -59,26 +68,12 @@ export function detectRoadmapDivergenceDrift(_state, ctx) {
59
68
  return drifts;
60
69
  }
61
70
  /**
62
- * Repair a milestone's roadmap divergence:
63
- * 1. migrateHierarchyToDb upserts slice rows (sequence + depends JSON
64
- * update via ON CONFLICT DO UPDATE).
65
- * 2. syncSliceDependencies updates the junction table per slice — the
66
- * importer only writes the JSON column, not the relational view.
71
+ * Repair a milestone's roadmap divergence by regenerating the projection from
72
+ * DB rows. ROADMAP.md is a projection; runtime reconciliation must not import
73
+ * slice presence, sequence, dependencies, or checkbox state from markdown.
67
74
  */
68
- export function repairRoadmapDivergence(record, ctx) {
69
- migrateHierarchyToDb(ctx.basePath);
70
- const roadmapPath = resolveMilestoneFile(ctx.basePath, record.milestoneId, "ROADMAP");
71
- if (!roadmapPath || !existsSync(roadmapPath))
72
- return;
73
- try {
74
- const roadmap = parseRoadmap(readFileSync(roadmapPath, "utf-8"));
75
- for (const slice of roadmap.slices) {
76
- syncSliceDependencies(record.milestoneId, slice.id, slice.depends);
77
- }
78
- }
79
- catch {
80
- /* parse failure: detector will fire again next pass */
81
- }
75
+ export async function repairRoadmapDivergence(record, ctx) {
76
+ await renderRoadmapFromDb(ctx.basePath, record.milestoneId);
82
77
  }
83
78
  export const roadmapDivergenceHandler = {
84
79
  kind: "roadmap-divergence",
@@ -26,3 +26,10 @@ export function isInactiveStatus(status) {
26
26
  export function isSkippedForDispatch(status) {
27
27
  return isClosedStatus(status) || status === "parked" || isDeferredStatus(status);
28
28
  }
29
+ /**
30
+ * Returns true when a milestone is future/backlog work (not currently executing).
31
+ * Includes legacy/project-specific alias "planned" for compatibility.
32
+ */
33
+ export function isFutureMilestoneStatus(status) {
34
+ return status === "pending" || status === "queued" || status === "planned";
35
+ }
@@ -322,6 +322,16 @@ function hasAskUserQuestionsTool(activeTools) {
322
322
  return toolSeparator >= 0 && toolName.slice(toolSeparator + 2) === "ask_user_questions";
323
323
  });
324
324
  }
325
+ function hasRequiredTool(requiredTool, activeTools) {
326
+ return activeTools.some((toolName) => {
327
+ if (toolName === requiredTool)
328
+ return true;
329
+ if (!toolName.startsWith("mcp__"))
330
+ return false;
331
+ const toolSeparator = toolName.indexOf("__", "mcp__".length);
332
+ return toolSeparator >= 0 && toolName.slice(toolSeparator + 2) === requiredTool;
333
+ });
334
+ }
325
335
  function workflowMcpStructuredQuestionsOptIn(env = process.env) {
326
336
  const value = env.GSD_WORKFLOW_MCP_STRUCTURED_QUESTIONS;
327
337
  return value === "1" || value === "true";
@@ -352,8 +362,14 @@ export function getWorkflowTransportSupportError(provider, requiredTools, option
352
362
  if (!launch) {
353
363
  return `Provider ${providerLabel} cannot run ${surface}${unitLabel}: the GSD workflow MCP server is not configured or discoverable. Detected Claude Code model but no workflow MCP. Please run /gsd mcp init . from your project root. You can also configure GSD_WORKFLOW_MCP_COMMAND, build packages/mcp-server/dist/cli.js, or install gsd-mcp-server on PATH.`;
354
364
  }
355
- const missing = [...new Set(requiredTools)].filter((tool) => !MCP_WORKFLOW_TOOL_SURFACE.has(tool));
365
+ const uniqueRequired = [...new Set(requiredTools)];
366
+ const missing = (options.activeTools && options.activeTools.length > 0)
367
+ ? uniqueRequired.filter((tool) => !hasRequiredTool(tool, options.activeTools))
368
+ : uniqueRequired.filter((tool) => !MCP_WORKFLOW_TOOL_SURFACE.has(tool));
356
369
  if (missing.length === 0)
357
370
  return null;
371
+ if (options.activeTools && options.activeTools.length > 0) {
372
+ return `Provider ${providerLabel} cannot run ${surface}${unitLabel}: this unit requires ${missing.join(", ")}, but the active runtime toolset currently exposes only ${options.activeTools.slice().sort().join(", ")}.`;
373
+ }
358
374
  return `Provider ${providerLabel} cannot run ${surface}${unitLabel}: this unit requires ${missing.join(", ")}, but the workflow MCP transport currently exposes only ${Array.from(MCP_WORKFLOW_TOOL_SURFACE).sort().join(", ")}.`;
359
375
  }