gsd-pi 2.82.0-dev.3709f22a5 → 2.82.0-dev.4285182e8

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 (193) hide show
  1. package/README.md +2 -2
  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/loop.js +14 -1
  5. package/dist/resources/extensions/gsd/auto/phases.js +53 -29
  6. package/dist/resources/extensions/gsd/auto/session.js +4 -0
  7. package/dist/resources/extensions/gsd/auto/workflow-kernel.js +3 -0
  8. package/dist/resources/extensions/gsd/auto-direct-dispatch.js +1 -0
  9. package/dist/resources/extensions/gsd/auto-dispatch.js +13 -19
  10. package/dist/resources/extensions/gsd/auto-post-unit.js +13 -6
  11. package/dist/resources/extensions/gsd/auto-recovery.js +40 -13
  12. package/dist/resources/extensions/gsd/auto-start.js +3 -3
  13. package/dist/resources/extensions/gsd/auto-verification.js +17 -4
  14. package/dist/resources/extensions/gsd/auto-worktree.js +65 -9
  15. package/dist/resources/extensions/gsd/auto.js +14 -8
  16. package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +6 -1
  17. package/dist/resources/extensions/gsd/bootstrap/db-tools.js +1 -1
  18. package/dist/resources/extensions/gsd/bootstrap/write-gate.js +1 -1
  19. package/dist/resources/extensions/gsd/commands/catalog.js +7 -1
  20. package/dist/resources/extensions/gsd/commands/handlers/core.js +1 -0
  21. package/dist/resources/extensions/gsd/commands/handlers/ops.js +5 -0
  22. package/dist/resources/extensions/gsd/commands-prefs-wizard.js +7 -2
  23. package/dist/resources/extensions/gsd/commands-verdict.js +139 -0
  24. package/dist/resources/extensions/gsd/crash-recovery.js +16 -4
  25. package/dist/resources/extensions/gsd/db/milestone-leases.js +24 -0
  26. package/dist/resources/extensions/gsd/forensics.js +3 -3
  27. package/dist/resources/extensions/gsd/git-service.js +6 -2
  28. package/dist/resources/extensions/gsd/gsd-db.js +20 -6
  29. package/dist/resources/extensions/gsd/guided-flow-queue.js +4 -3
  30. package/dist/resources/extensions/gsd/guided-flow.js +8 -5
  31. package/dist/resources/extensions/gsd/markdown-renderer.js +10 -8
  32. package/dist/resources/extensions/gsd/paths.js +4 -0
  33. package/dist/resources/extensions/gsd/queue-reorder-ui.js +30 -13
  34. package/dist/resources/extensions/gsd/state.js +3 -3
  35. package/dist/resources/extensions/gsd/status-guards.js +7 -0
  36. package/dist/resources/extensions/gsd/templates/plan.md +1 -0
  37. package/dist/resources/extensions/gsd/templates/task-plan.md +6 -0
  38. package/dist/resources/extensions/gsd/tools/plan-slice.js +3 -5
  39. package/dist/resources/extensions/gsd/workflow-mcp.js +17 -1
  40. package/dist/resources/extensions/gsd/worktree-manager.js +1 -1
  41. package/dist/resources/extensions/ttsr/ttsr-manager.js +3 -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 +11 -11
  45. package/dist/web/standalone/.next/build-manifest.json +3 -3
  46. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  47. package/dist/web/standalone/.next/react-loadable-manifest.json +3 -3
  48. package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
  49. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  50. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  51. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  52. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  53. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  54. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  55. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  56. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  57. package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
  58. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
  59. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  60. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
  61. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  62. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  63. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  64. package/dist/web/standalone/.next/server/app/api/browse-directories/route.js +1 -1
  65. package/dist/web/standalone/.next/server/app/index.html +1 -1
  66. package/dist/web/standalone/.next/server/app/index.rsc +1 -1
  67. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
  68. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +1 -1
  69. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  70. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
  71. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  72. package/dist/web/standalone/.next/server/app-paths-manifest.json +11 -11
  73. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  74. package/dist/web/standalone/.next/server/middleware-react-loadable-manifest.js +1 -1
  75. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  76. package/dist/web/standalone/.next/server/pages/500.html +1 -1
  77. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  78. package/dist/web/standalone/.next/static/chunks/8359.65b24fac92188a6b.js +10 -0
  79. package/dist/web/standalone/.next/static/chunks/9441.ff70bb53f6835771.js +1 -0
  80. package/dist/web/standalone/.next/static/chunks/{webpack-9a4db269f9ed63ad.js → webpack-855d616060cb6e59.js} +1 -1
  81. package/package.json +1 -1
  82. package/packages/pi-ai/dist/providers/google-gemini-cli.d.ts.map +1 -1
  83. package/packages/pi-ai/dist/providers/google-gemini-cli.js +5 -0
  84. package/packages/pi-ai/dist/providers/google-gemini-cli.js.map +1 -1
  85. package/packages/pi-ai/dist/providers/google-gemini-cli.test.d.ts +2 -0
  86. package/packages/pi-ai/dist/providers/google-gemini-cli.test.d.ts.map +1 -0
  87. package/packages/pi-ai/dist/providers/google-gemini-cli.test.js +41 -0
  88. package/packages/pi-ai/dist/providers/google-gemini-cli.test.js.map +1 -0
  89. package/packages/pi-ai/src/providers/google-gemini-cli.test.ts +49 -0
  90. package/packages/pi-ai/src/providers/google-gemini-cli.ts +7 -0
  91. package/packages/pi-ai/tsconfig.tsbuildinfo +1 -1
  92. package/packages/pi-coding-agent/dist/core/chat-controller-ordering.test.js +44 -3
  93. package/packages/pi-coding-agent/dist/core/chat-controller-ordering.test.js.map +1 -1
  94. package/packages/pi-coding-agent/dist/core/sdk.js +1 -1
  95. package/packages/pi-coding-agent/dist/core/sdk.js.map +1 -1
  96. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.d.ts.map +1 -1
  97. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js +71 -97
  98. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js.map +1 -1
  99. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-ordering.test.js +25 -1
  100. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-ordering.test.js.map +1 -1
  101. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts +2 -0
  102. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  103. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js +24 -10
  104. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
  105. package/packages/pi-coding-agent/src/core/chat-controller-ordering.test.ts +53 -3
  106. package/packages/pi-coding-agent/src/core/sdk.ts +1 -1
  107. package/packages/pi-coding-agent/src/modes/interactive/controllers/chat-controller.ts +75 -102
  108. package/packages/pi-coding-agent/src/modes/interactive/interactive-mode-ordering.test.ts +30 -1
  109. package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +29 -10
  110. package/packages/pi-coding-agent/tsconfig.tsbuildinfo +1 -1
  111. package/packages/pi-tui/dist/__tests__/terminal.test.d.ts +2 -0
  112. package/packages/pi-tui/dist/__tests__/terminal.test.d.ts.map +1 -0
  113. package/packages/pi-tui/dist/__tests__/terminal.test.js +103 -0
  114. package/packages/pi-tui/dist/__tests__/terminal.test.js.map +1 -0
  115. package/packages/pi-tui/dist/terminal.d.ts +2 -0
  116. package/packages/pi-tui/dist/terminal.d.ts.map +1 -1
  117. package/packages/pi-tui/dist/terminal.js +12 -0
  118. package/packages/pi-tui/dist/terminal.js.map +1 -1
  119. package/packages/pi-tui/src/__tests__/terminal.test.ts +121 -0
  120. package/packages/pi-tui/src/terminal.ts +11 -0
  121. package/packages/pi-tui/tsconfig.tsbuildinfo +1 -1
  122. package/src/resources/extensions/claude-code-cli/stream-adapter.ts +1 -1
  123. package/src/resources/extensions/claude-code-cli/tests/stream-adapter.test.ts +9 -0
  124. package/src/resources/extensions/gsd/auto/loop.ts +14 -1
  125. package/src/resources/extensions/gsd/auto/phases.ts +60 -36
  126. package/src/resources/extensions/gsd/auto/session.ts +4 -0
  127. package/src/resources/extensions/gsd/auto/workflow-kernel.ts +5 -1
  128. package/src/resources/extensions/gsd/auto-direct-dispatch.ts +1 -0
  129. package/src/resources/extensions/gsd/auto-dispatch.ts +13 -19
  130. package/src/resources/extensions/gsd/auto-post-unit.ts +14 -6
  131. package/src/resources/extensions/gsd/auto-recovery.ts +45 -11
  132. package/src/resources/extensions/gsd/auto-start.ts +2 -3
  133. package/src/resources/extensions/gsd/auto-verification.ts +22 -2
  134. package/src/resources/extensions/gsd/auto-worktree.ts +74 -9
  135. package/src/resources/extensions/gsd/auto.ts +13 -8
  136. package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +9 -1
  137. package/src/resources/extensions/gsd/bootstrap/db-tools.ts +1 -1
  138. package/src/resources/extensions/gsd/bootstrap/write-gate.ts +1 -1
  139. package/src/resources/extensions/gsd/commands/catalog.ts +7 -1
  140. package/src/resources/extensions/gsd/commands/handlers/core.ts +1 -0
  141. package/src/resources/extensions/gsd/commands/handlers/ops.ts +5 -0
  142. package/src/resources/extensions/gsd/commands-prefs-wizard.ts +8 -3
  143. package/src/resources/extensions/gsd/commands-verdict.ts +202 -0
  144. package/src/resources/extensions/gsd/crash-recovery.ts +16 -2
  145. package/src/resources/extensions/gsd/db/milestone-leases.ts +26 -0
  146. package/src/resources/extensions/gsd/forensics.ts +3 -3
  147. package/src/resources/extensions/gsd/git-service.ts +6 -3
  148. package/src/resources/extensions/gsd/gsd-db.ts +18 -6
  149. package/src/resources/extensions/gsd/guided-flow-queue.ts +4 -3
  150. package/src/resources/extensions/gsd/guided-flow.ts +8 -5
  151. package/src/resources/extensions/gsd/markdown-renderer.ts +10 -8
  152. package/src/resources/extensions/gsd/paths.ts +5 -0
  153. package/src/resources/extensions/gsd/queue-reorder-ui.ts +31 -13
  154. package/src/resources/extensions/gsd/state.ts +3 -3
  155. package/src/resources/extensions/gsd/status-guards.ts +8 -0
  156. package/src/resources/extensions/gsd/templates/plan.md +1 -0
  157. package/src/resources/extensions/gsd/templates/task-plan.md +6 -0
  158. package/src/resources/extensions/gsd/tests/auto-loop.test.ts +2 -0
  159. package/src/resources/extensions/gsd/tests/auto-paused-ui-cleanup.test.ts +139 -1
  160. package/src/resources/extensions/gsd/tests/auto-post-unit-step-message.test.ts +6 -5
  161. package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +76 -5
  162. package/src/resources/extensions/gsd/tests/checkout-branch-stash-guard.test.ts +87 -0
  163. package/src/resources/extensions/gsd/tests/commands-verdict.test.ts +378 -0
  164. package/src/resources/extensions/gsd/tests/crash-recovery-via-db.test.ts +43 -0
  165. package/src/resources/extensions/gsd/tests/custom-engine-loop-integration.test.ts +2 -0
  166. package/src/resources/extensions/gsd/tests/dispatch-complete-milestone-guard.test.ts +27 -0
  167. package/src/resources/extensions/gsd/tests/gsd-db.test.ts +11 -0
  168. package/src/resources/extensions/gsd/tests/gsdroot-worktree-detection.test.ts +5 -2
  169. package/src/resources/extensions/gsd/tests/integration/git-service.test.ts +9 -0
  170. package/src/resources/extensions/gsd/tests/journal-integration.test.ts +46 -0
  171. package/src/resources/extensions/gsd/tests/merge-db-cycle.test.ts +179 -0
  172. package/src/resources/extensions/gsd/tests/pipeline-variant-dispatch.test.ts +2 -1
  173. package/src/resources/extensions/gsd/tests/plan-slice.test.ts +26 -1
  174. package/src/resources/extensions/gsd/tests/post-unit-state-rebuild.test.ts +84 -0
  175. package/src/resources/extensions/gsd/tests/prefs-wizard-coverage.test.ts +59 -0
  176. package/src/resources/extensions/gsd/tests/provider-errors.test.ts +18 -1
  177. package/src/resources/extensions/gsd/tests/quality-gates.test.ts +6 -0
  178. package/src/resources/extensions/gsd/tests/queue-reorder-ui.test.ts +54 -0
  179. package/src/resources/extensions/gsd/tests/remediation-completion-guard.test.ts +43 -0
  180. package/src/resources/extensions/gsd/tests/run-uat-replay-cap.test.ts +2 -3
  181. package/src/resources/extensions/gsd/tests/status-guards.test.ts +13 -1
  182. package/src/resources/extensions/gsd/tests/unit-context-manifest.test.ts +17 -0
  183. package/src/resources/extensions/gsd/tests/validate-milestone-stuck-guard.test.ts +29 -2
  184. package/src/resources/extensions/gsd/tests/workflow-kernel.test.ts +7 -0
  185. package/src/resources/extensions/gsd/tests/workflow-mcp.test.ts +18 -0
  186. package/src/resources/extensions/gsd/tools/plan-slice.ts +3 -4
  187. package/src/resources/extensions/gsd/workflow-mcp.ts +18 -1
  188. package/src/resources/extensions/gsd/worktree-manager.ts +1 -1
  189. package/src/resources/extensions/ttsr/ttsr-manager.ts +5 -1
  190. package/dist/web/standalone/.next/static/chunks/8359.7eb3bb8f8ecf4c01.js +0 -10
  191. package/dist/web/standalone/.next/static/chunks/9441.1081da1125d1764f.js +0 -1
  192. /package/dist/web/standalone/.next/static/{kkGf3_VaPFkiDNV_D7Dtl → 78uanrILNOKG-Jpi4itAE}/_buildManifest.js +0 -0
  193. /package/dist/web/standalone/.next/static/{kkGf3_VaPFkiDNV_D7Dtl → 78uanrILNOKG-Jpi4itAE}/_ssgManifest.js +0 -0
@@ -320,6 +320,10 @@ export function resolveGsdPathContract(workRoot, originalProjectRoot) {
320
320
  isWorktree,
321
321
  };
322
322
  }
323
+ export function gsdProjectionRoot(basePath) {
324
+ const contract = resolveGsdPathContract(basePath);
325
+ return normalizeRealPath(contract.worktreeGsd ?? contract.projectGsd);
326
+ }
323
327
  /**
324
328
  * Invalidate the gsdRoot cache.
325
329
  * Use ONLY at session-reset boundaries: workspace switch, process exit, or
@@ -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
  }
@@ -460,7 +460,7 @@ async function handleAllSlicesDone(basePath, activeMilestone, registry, requirem
460
460
  recentDecisions: [],
461
461
  blockers: [
462
462
  `Milestone ${activeMilestone.id} validation verdict is needs-remediation but all slices are complete. ` +
463
- `Add remediation slices via gsd_reassess_roadmap or override the verdict manually.`,
463
+ `Add remediation slices via gsd_reassess_roadmap, or run \`/gsd verdict pass --rationale "..."\` to override.`,
464
464
  ],
465
465
  nextAction: `Resolve ${activeMilestone.id} remediation before proceeding.`,
466
466
  registry, requirements,
@@ -1132,7 +1132,7 @@ export async function _deriveStateImpl(basePath, opts) {
1132
1132
  recentDecisions: [],
1133
1133
  blockers: [
1134
1134
  `Milestone ${activeMilestone.id} validation verdict is needs-remediation but all slices are complete. ` +
1135
- `Add remediation slices via gsd_reassess_roadmap or override the verdict manually.`,
1135
+ `Add remediation slices via gsd_reassess_roadmap, or run \`/gsd verdict pass --rationale "..."\` to override.`,
1136
1136
  ],
1137
1137
  nextAction: `Resolve ${activeMilestone.id} remediation before proceeding.`,
1138
1138
  registry,
@@ -1253,7 +1253,7 @@ export async function _deriveStateImpl(basePath, opts) {
1253
1253
  const summaryPath = resolveTaskFile(basePath, activeMilestone.id, activeSlice.id, t.id, "SUMMARY");
1254
1254
  if (summaryPath && existsSync(summaryPath)) {
1255
1255
  t.done = true;
1256
- logWarning("reconcile", `task ${activeMilestone.id}/${activeSlice.id}/${t.id} reconciled via SUMMARY on disk (#2514)`, { mid: activeMilestone.id, sid: activeSlice.id, tid: t.id });
1256
+ logWarning("reconcile", `task ${activeMilestone.id}/${activeSlice.id}/${t.id} reconciled via SUMMARY on disk`, { mid: activeMilestone.id, sid: activeSlice.id, tid: t.id });
1257
1257
  }
1258
1258
  }
1259
1259
  const taskProgress = {
@@ -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
+ }
@@ -132,6 +132,7 @@
132
132
  Verify field rules:
133
133
  - MUST be a mechanically executable command: `npm test`, `grep -q "pattern" file`, `test -f path`
134
134
  - MUST NOT use shell pipes, redirects, semicolons, backticks, command substitution, or output trimming
135
+ - MUST NOT use inline `node -e` assertions for verification; put assertions in a real test file and run it with `node --test` or a package test script
135
136
  - For content/document tasks: verify file existence, section count, YAML validity, or word count
136
137
  NOT exact phrasing, specific formulas, or "zero TBD" aspirational criteria
137
138
  - If no command can verify the output, write: "Manual review — file exists and is non-empty"
@@ -57,6 +57,12 @@ skills_used:
57
57
  - {{howToVerifyThisTaskIsActuallyDone}}
58
58
  - {{commandToRun_OR_behaviorToCheck}}
59
59
 
60
+ ## Verify Rules
61
+
62
+ - Use a real executable check, not prose.
63
+ - If the check needs file-content assertions, write a `node:test` file and run it with `node --test` or a package test script.
64
+ - Do not use inline `node -e` assertions for verification.
65
+
60
66
  ## Observability Impact
61
67
 
62
68
  <!-- OMIT THIS SECTION ENTIRELY for simple tasks that don't touch runtime boundaries,
@@ -12,7 +12,7 @@ import { appendEvent } from "../workflow-events.js";
12
12
  import { logWarning } from "../workflow-logger.js";
13
13
  import { validatePlanningPathScope } from "../planning-path-scope.js";
14
14
  import { checkFilePathConsistency, checkTaskOrdering } from "../pre-execution-checks.js";
15
- import { buildTaskFileName, gsdRoot, resolveTasksDir } from "../paths.js";
15
+ import { buildTaskFileName, gsdProjectionRoot } from "../paths.js";
16
16
  function validateTasks(value) {
17
17
  if (!Array.isArray(value) || value.length === 0) {
18
18
  throw new Error("tasks must be a non-empty array");
@@ -241,14 +241,12 @@ export async function handlePlanSlice(rawParams, basePath) {
241
241
  return { error: guardError };
242
242
  }
243
243
  try {
244
- const tasksDir = resolveTasksDir(basePath, params.milestoneId, params.sliceId);
244
+ const tasksDir = join(gsdProjectionRoot(basePath), "milestones", params.milestoneId, "slices", params.sliceId, "tasks");
245
245
  for (const taskId of omittedTaskIds) {
246
- if (!tasksDir)
247
- continue;
248
246
  const taskPlanPath = join(tasksDir, buildTaskFileName(taskId, "PLAN"));
249
247
  if (existsSync(taskPlanPath))
250
248
  rmSync(taskPlanPath, { force: true });
251
- const artifactPath = relative(gsdRoot(basePath), taskPlanPath).replace(/\\/g, "/");
249
+ const artifactPath = relative(gsdProjectionRoot(basePath), taskPlanPath).replace(/\\/g, "/");
252
250
  deleteArtifactByPath(artifactPath);
253
251
  }
254
252
  const renderResult = await renderPlanFromDb(basePath, params.milestoneId, params.sliceId);
@@ -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
  }
@@ -491,7 +491,7 @@ export function removeWorktree(basePath, name, opts = {}) {
491
491
  const nestedGitPath = join(nestedDir, ".git");
492
492
  try {
493
493
  rmSync(nestedGitPath, { recursive: true, force: true });
494
- logWarning("reconcile", `Removed nested .git directory from scaffolded project to prevent data loss (#2616)`, { worktree: name, nestedRepo: nestedDir });
494
+ logWarning("reconcile", `Removed nested .git directory from scaffolded project to prevent data loss`, { worktree: name, nestedRepo: nestedDir });
495
495
  }
496
496
  catch {
497
497
  logWarning("reconcile", `Failed to remove nested .git directory — files may be lost as orphaned gitlink`, { worktree: name, nestedRepo: nestedDir });
@@ -43,6 +43,7 @@ const MAX_BUFFER_BYTES = 512 * 1024;
43
43
  * Prevents CPU spinning when deltas arrive faster than regex evaluation (#468).
44
44
  */
45
45
  const JS_FALLBACK_CHECK_INTERVAL_MS = 50;
46
+ const JS_FALLBACK_THROTTLE_MIN_BUFFER_BYTES = 4 * 1024;
46
47
  const DEFAULT_SCOPE = {
47
48
  allowText: true,
48
49
  allowThinking: false,
@@ -308,7 +309,8 @@ export class TtsrManager {
308
309
  // streams — regex on a growing buffer is O(rules × buffer_size) (#468).
309
310
  const now = Date.now();
310
311
  const lastCheck = this.#lastJsCheckAt.get(bufferKey) ?? 0;
311
- if (now - lastCheck < JS_FALLBACK_CHECK_INTERVAL_MS) {
312
+ if (nextBuffer.length >= JS_FALLBACK_THROTTLE_MIN_BUFFER_BYTES &&
313
+ now - lastCheck < JS_FALLBACK_CHECK_INTERVAL_MS) {
312
314
  stopTimer({ bufferSize: nextBuffer.length, throttled: true });
313
315
  return [];
314
316
  }