@opengsd/gsd-core 1.8.0 → 1.9.1
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.
- package/.claude-plugin/marketplace.json +1 -1
- package/.claude-plugin/plugin.json +1 -1
- package/.opencode/plugins/gsd-core.js +31 -1
- package/agents/gsd-code-fixer.md +107 -34
- package/agents/gsd-codebase-mapper.md +1 -1
- package/agents/gsd-debug-session-manager.md +36 -0
- package/agents/gsd-executor.md +20 -7
- package/agents/gsd-intel-updater.md +3 -3
- package/agents/gsd-phase-researcher.md +4 -2
- package/agents/gsd-plan-checker.md +20 -0
- package/agents/gsd-planner.md +15 -23
- package/agents/gsd-project-researcher.md +2 -2
- package/agents/gsd-ui-auditor.md +0 -40
- package/bin/install.js +236 -107
- package/commands/gsd/plan-review-convergence.md +5 -1
- package/gsd-core/bin/gsd-tools.cjs +882 -4
- package/gsd-core/bin/lib/api-coverage.cjs +22 -8
- package/gsd-core/bin/lib/audit.cjs +8 -8
- package/gsd-core/bin/lib/capability-consent.cjs +40 -1
- package/gsd-core/bin/lib/capability-lifecycle.cjs +58 -0
- package/gsd-core/bin/lib/capability-loader.cjs +23 -1
- package/gsd-core/bin/lib/capability-registry.cjs +1353 -132
- package/gsd-core/bin/lib/capability-trust.cjs +468 -33
- package/gsd-core/bin/lib/capability-validator.cjs +882 -6
- package/gsd-core/bin/lib/check-command-router.cjs +12 -2
- package/gsd-core/bin/lib/cjs-command-router-adapter.cjs +15 -0
- package/gsd-core/bin/lib/claude-orchestration-command-router.cjs +102 -12
- package/gsd-core/bin/lib/claude-orchestration.cjs +125 -22
- package/gsd-core/bin/lib/commands.cjs +246 -18
- package/gsd-core/bin/lib/config-loader.cjs +200 -28
- package/gsd-core/bin/lib/config.cjs +90 -5
- package/gsd-core/bin/lib/estimate-cli.cjs +336 -0
- package/gsd-core/bin/lib/frontmatter.cjs +125 -15
- package/gsd-core/bin/lib/host-integration.cjs +215 -8
- package/gsd-core/bin/lib/init.cjs +44 -19
- package/gsd-core/bin/lib/install-engine.cjs +1 -0
- package/gsd-core/bin/lib/milestone.cjs +36 -9
- package/gsd-core/bin/lib/model-catalog.cjs +51 -1
- package/gsd-core/bin/lib/observability/logger.cjs +7 -2
- package/gsd-core/bin/lib/phase-command-router.cjs +10 -1
- package/gsd-core/bin/lib/phase-estimation.cjs +398 -0
- package/gsd-core/bin/lib/phase-id.cjs +278 -5
- package/gsd-core/bin/lib/phase.cjs +61 -6
- package/gsd-core/bin/lib/plan-drift-guard.cjs +1 -1
- package/gsd-core/bin/lib/plan-scan.cjs +1 -1
- package/gsd-core/bin/lib/planning-workspace.cjs +9 -2
- package/gsd-core/bin/lib/profile-output.cjs +34 -8
- package/gsd-core/bin/lib/project-root.cjs +48 -0
- package/gsd-core/bin/lib/review-lane-descriptor.cjs +927 -0
- package/gsd-core/bin/lib/review-lane-invocation.cjs +348 -0
- package/gsd-core/bin/lib/review-lane-runner.cjs +594 -0
- package/gsd-core/bin/lib/review-reviewer-selection.cjs +114 -32
- package/gsd-core/bin/lib/roadmap-parser.cjs +54 -6
- package/gsd-core/bin/lib/roadmap.cjs +10 -4
- package/gsd-core/bin/lib/runtime-artifact-conversion.cjs +31 -4
- package/gsd-core/bin/lib/runtime-artifact-layout.cjs +1 -1
- package/gsd-core/bin/lib/runtime-hooks-surface.cjs +140 -0
- package/gsd-core/bin/lib/runtime-name-policy.cjs +15 -2
- package/gsd-core/bin/lib/smart-entry.cjs +1 -1
- package/gsd-core/bin/lib/state-document.cjs +164 -20
- package/gsd-core/bin/lib/state-transition.cjs +28 -10
- package/gsd-core/bin/lib/state.cjs +141 -21
- package/gsd-core/bin/lib/uat-predicate.cjs +6 -4
- package/gsd-core/bin/lib/uat.cjs +9 -7
- package/gsd-core/bin/lib/ui-consideration-probe.cjs +2 -2
- package/gsd-core/bin/lib/unusable-input.cjs +216 -0
- package/gsd-core/bin/lib/validate.cjs +32 -0
- package/gsd-core/bin/lib/verification.cjs +51 -14
- package/gsd-core/bin/lib/verify.cjs +146 -22
- package/gsd-core/bin/lib/worktree-safety.cjs +360 -15
- package/gsd-core/bin/shared/config-defaults.manifest.json +1 -0
- package/gsd-core/bin/shared/config-schema.manifest.json +1 -13
- package/gsd-core/bin/shared/model-catalog.json +5 -0
- package/gsd-core/bin/shared/runtime-aliases.manifest.json +5 -0
- package/gsd-core/references/context-budget.md +40 -0
- package/gsd-core/references/gate-prompts.md +6 -3
- package/gsd-core/references/model-profile-resolution.md +64 -13
- package/gsd-core/references/offer-next.md +88 -0
- package/gsd-core/references/planning-config.md +2 -1
- package/gsd-core/references/reviewer-instances.md +28 -21
- package/gsd-core/references/runtime-aware-dispatch.md +42 -0
- package/gsd-core/references/ui-consideration-probe.md +2 -2
- package/gsd-core/references/worktree-branch-check.md +4 -4
- package/gsd-core/templates/summary-minimal.md +4 -0
- package/gsd-core/templates/summary-standard.md +4 -0
- package/gsd-core/templates/summary.md +7 -0
- package/gsd-core/workflows/ai-integration-phase.md +4 -4
- package/gsd-core/workflows/audit-fix.md +4 -0
- package/gsd-core/workflows/audit-milestone.md +8 -0
- package/gsd-core/workflows/autonomous.md +19 -15
- package/gsd-core/workflows/check-todos.md +2 -2
- package/gsd-core/workflows/code-review-fix.md +14 -6
- package/gsd-core/workflows/code-review.md +93 -21
- package/gsd-core/workflows/debug.md +10 -2
- package/gsd-core/workflows/diagnose-issues.md +4 -0
- package/gsd-core/workflows/discuss-phase/modes/advisor.md +2 -4
- package/gsd-core/workflows/discuss-phase/modes/auto.md +0 -6
- package/gsd-core/workflows/discuss-phase-assumptions.md +15 -9
- package/gsd-core/workflows/discuss-phase.md +2 -2
- package/gsd-core/workflows/docs-update.md +8 -0
- package/gsd-core/workflows/eval-review.md +1 -1
- package/gsd-core/workflows/execute-phase/steps/codebase-drift-gate.md +4 -0
- package/gsd-core/workflows/execute-phase/steps/executor-isolation-dispatch.md +160 -0
- package/gsd-core/workflows/execute-phase.md +85 -115
- package/gsd-core/workflows/execute-plan.md +5 -4
- package/gsd-core/workflows/explore.md +4 -0
- package/gsd-core/workflows/extract-learnings.md +21 -0
- package/gsd-core/workflows/help/modes/full.md +3 -3
- package/gsd-core/workflows/import.md +4 -1
- package/gsd-core/workflows/ingest-docs.md +4 -0
- package/gsd-core/workflows/map-codebase.md +13 -6
- package/gsd-core/workflows/new-milestone.md +10 -2
- package/gsd-core/workflows/new-project.md +11 -4
- package/gsd-core/workflows/next.md +5 -2
- package/gsd-core/workflows/plan-phase.md +42 -46
- package/gsd-core/workflows/plan-review-convergence.md +18 -14
- package/gsd-core/workflows/progress.md +1 -1
- package/gsd-core/workflows/quick.md +14 -3
- package/gsd-core/workflows/review.md +146 -575
- package/gsd-core/workflows/scan.md +9 -1
- package/gsd-core/workflows/secure-phase.md +10 -2
- package/gsd-core/workflows/ship.md +41 -11
- package/gsd-core/workflows/smart-entry.md +1 -1
- package/gsd-core/workflows/ui-phase.md +8 -1
- package/gsd-core/workflows/ui-review.md +8 -1
- package/gsd-core/workflows/update.md +104 -5
- package/gsd-core/workflows/validate-phase.md +10 -2
- package/gsd-core/workflows/verify-work.md +8 -1
- package/hooks/dist/gsd-cursor-session-start.js +6 -2
- package/hooks/dist/gsd-cursor-stop.js +6 -2
- package/hooks/dist/gsd-cursor-subagent-start.js +6 -2
- package/hooks/dist/gsd-graphify-update.sh +9 -0
- package/hooks/dist/gsd-phase-boundary.sh +14 -2
- package/hooks/dist/gsd-prompt-guard.js +101 -2
- package/hooks/dist/gsd-read-guard.js +100 -2
- package/hooks/dist/gsd-read-injection-scanner.js +109 -2
- package/hooks/dist/gsd-statusline.js +9 -6
- package/hooks/dist/gsd-workflow-guard.js +110 -6
- package/hooks/dist/gsd-worktree-path-guard.js +132 -8
- package/hooks/dist/lib/cursor-workspace.js +74 -0
- package/hooks/gsd-cursor-session-start.js +6 -2
- package/hooks/gsd-cursor-stop.js +6 -2
- package/hooks/gsd-cursor-subagent-start.js +6 -2
- package/hooks/gsd-graphify-update.sh +9 -0
- package/hooks/gsd-phase-boundary.sh +14 -2
- package/hooks/gsd-prompt-guard.js +101 -2
- package/hooks/gsd-read-guard.js +100 -2
- package/hooks/gsd-read-injection-scanner.js +109 -2
- package/hooks/gsd-statusline.js +9 -6
- package/hooks/gsd-workflow-guard.js +110 -6
- package/hooks/gsd-worktree-path-guard.js +132 -8
- package/hooks/lib/cursor-workspace.js +74 -0
- package/package.json +7 -7
- package/pi/gsd.cjs +26 -1
- package/scripts/check-coverage-gate.cjs +51 -0
- package/scripts/check-glossary-refs.cjs +24 -0
- package/scripts/ci-test-scope.cjs +67 -17
- package/scripts/gen-adr-index.cjs +6 -4
- package/scripts/gen-capability-matrix.cjs +26 -2
- package/scripts/gen-capability-registry.cjs +132 -34
- package/scripts/gen-emitted-baseline.cjs +145 -0
- package/scripts/gen-registry.cjs +39 -15
- package/scripts/lint-compiled-artifact-sync.cjs +146 -0
- package/scripts/lint-emitted-drift-ack.cjs +149 -0
- package/scripts/lint-fix-has-regression-test.cjs +131 -0
- package/scripts/lint-resolution-provenance.cjs +9 -0
- package/scripts/mutation-matrix.cjs +4 -0
- package/scripts/prompt-injection-scan.sh +6 -0
- package/scripts/registry-schema.cjs +372 -94
- package/scripts/release-notes/conventional-title.cjs +19 -1
- package/scripts/release-notes/format-github-release-notes.cjs +7 -3
- package/scripts/validate-registry.cjs +10 -6
- package/scripts/workflow-size.cjs +16 -8
- package/skills/gsd-plan-review-convergence/SKILL.md +5 -1
- package/vscode/package.json +1 -1
- package/scripts/gen-golden-install-parity-zcode.cjs +0 -77
- package/scripts/update-size-baseline.cjs +0 -68
|
@@ -239,6 +239,32 @@ function runHook(hookFile, payload, opts = {}) {
|
|
|
239
239
|
return { stdout, exitCode, timedOut: result.signal === "SIGTERM" };
|
|
240
240
|
}
|
|
241
241
|
|
|
242
|
+
/**
|
|
243
|
+
* In-process check for whether context-usage warnings are disabled in project
|
|
244
|
+
* config. Mirrors the exact semantics of the same check inside
|
|
245
|
+
* hooks/gsd-context-monitor.js (introduced by #1073): an explicit
|
|
246
|
+
* `config.hooks.context_warnings === false` disables them; a missing or
|
|
247
|
+
* unparseable .planning/config.json keeps them enabled (the default).
|
|
248
|
+
*
|
|
249
|
+
* #2697: hoisting this check in-process lets the adapter SKIP the context-monitor
|
|
250
|
+
* spawn entirely when the user has opted out, instead of paying a full Node boot
|
|
251
|
+
* inside the child only to read the boolean and exit. Missing/unparseable config
|
|
252
|
+
* MUST behave identically to the hook (enabled) so the default path is unchanged.
|
|
253
|
+
*
|
|
254
|
+
* @param {string} cwd project working directory (the plugin's currentCwd)
|
|
255
|
+
* @returns {boolean} true when context warnings are explicitly disabled
|
|
256
|
+
*/
|
|
257
|
+
function contextWarningsDisabled(cwd) {
|
|
258
|
+
try {
|
|
259
|
+
const configPath = path.join(cwd, '.planning', 'config.json');
|
|
260
|
+
const config = JSON.parse(fs.readFileSync(configPath, 'utf8'));
|
|
261
|
+
return config.hooks?.context_warnings === false;
|
|
262
|
+
} catch {
|
|
263
|
+
// Missing or unparseable config → proceed with defaults (context warnings enabled).
|
|
264
|
+
return false;
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
|
|
242
268
|
// ---------------------------------------------------------------------------
|
|
243
269
|
// Hook output translation → OpenCode semantics
|
|
244
270
|
// ---------------------------------------------------------------------------
|
|
@@ -587,7 +613,11 @@ const GsdCorePlugin = async ({ directory } = {}) => {
|
|
|
587
613
|
|
|
588
614
|
// gsd-context-monitor.js — context usage warnings (Bash/Edit/Write/Task/...)
|
|
589
615
|
// Only meaningful when a session_id is tracked (writes metrics sentinel).
|
|
590
|
-
|
|
616
|
+
// #2697: skip the subprocess spawn entirely when context warnings are
|
|
617
|
+
// explicitly disabled in project config — the hook would exit early anyway,
|
|
618
|
+
// so hoisting the check in-process avoids paying a Node boot per tool call.
|
|
619
|
+
// Missing/unparseable config = enabled (default), so the spawn still runs.
|
|
620
|
+
if (currentSessionId && !contextWarningsDisabled(cwd)) {
|
|
591
621
|
const payload = {
|
|
592
622
|
hook_event_name: "PostToolUse",
|
|
593
623
|
tool_name: claudeTool,
|
package/agents/gsd-code-fixer.md
CHANGED
|
@@ -216,9 +216,36 @@ If a finding references multiple files (in Fix section or Issue section):
|
|
|
216
216
|
|
|
217
217
|
This agent runs as a background process that makes commits. Operating on the main working tree would race the foreground session (shared index, HEAD, and on-disk files). Instead, every instance runs in its own isolated worktree.
|
|
218
218
|
|
|
219
|
+
**#2825: honor `workflow.use_worktrees`.** This is the ONLY writer that hand-rolls a git worktree
|
|
220
|
+
inside the agent prompt; every other writer path (`/gsd:execute-phase`, `/gsd:execute-plan`,
|
|
221
|
+
`/gsd:quick`, `/gsd:diagnose-issues`) reads `workflow.use_worktrees` and skips isolation when it is
|
|
222
|
+
`false`. Read the same flag here and, when it is `false`, edit and commit in the main checkout
|
|
223
|
+
directly (set `wt="."`, no `reviewfix_branch`, no recovery sentinel, no `git worktree add`, and skip
|
|
224
|
+
the cleanup tail — there is no worktree to remove). When the flag is not `false`, the transactional
|
|
225
|
+
worktree path below runs unchanged. A user who explicitly opted out of worktrees must never have a
|
|
226
|
+
worktree created; the hand-rolled worktree also cannot run the project's gates safely (no
|
|
227
|
+
`node_modules`), so the opt-out is also the safe path.
|
|
228
|
+
|
|
219
229
|
The cleanup tail (commit fixes -> remove worktree -> drop recovery sentinel) MUST be **transactional**: either all of (worktree, branch advance, sentinel) end in a clean state, or — if the process is interrupted (system restart, OOM kill) between the last commit and `git worktree remove` — a discoverable recovery sentinel is left behind so a future run, `/gsd:resume-work`, or `/gsd:progress` can complete the cleanup. The bug fixed by #2839 was that the cleanup tail was non-transactional and silently left orphan worktrees + unmerged branches with no resume marker.
|
|
220
230
|
|
|
221
231
|
```bash
|
|
232
|
+
# #2825: honor workflow.use_worktrees — the documented opt-out. When false,
|
|
233
|
+
# edit/commit in the main checkout (wt=".", no temp branch, no sentinel, no
|
|
234
|
+
# cleanup tail). Read the flag the same way the four sibling writer workflows
|
|
235
|
+
# do. NOTE: this read parses .planning/config.json directly via `node` rather
|
|
236
|
+
# than the gsd-tools CLI, because setup_worktree runs BEFORE the canonical
|
|
237
|
+
# launcher preamble is sourced — invoking the CLI here would be undefined at
|
|
238
|
+
# runtime and violates the runtime-launcher-parity preamble-ordering rule.
|
|
239
|
+
# Once the preamble is sourced (later steps), the CLI is available.
|
|
240
|
+
USE_WORKTREES=$(node -e '
|
|
241
|
+
try {
|
|
242
|
+
const fs = require("fs");
|
|
243
|
+
const p = (process.env.GSD_PROJECT_DIR || process.cwd()) + "/.planning/config.json";
|
|
244
|
+
const cfg = JSON.parse(fs.readFileSync(p, "utf8"));
|
|
245
|
+
process.stdout.write(String((cfg.workflow && cfg.workflow.use_worktrees) ?? true));
|
|
246
|
+
} catch { process.stdout.write("true"); }
|
|
247
|
+
')
|
|
248
|
+
|
|
222
249
|
# Derive worktree path from padded_phase (parsed from config in next step,
|
|
223
250
|
# but the shell snippet below is illustrative — adapt once config is parsed).
|
|
224
251
|
# In practice: parse padded_phase from config first, then run:
|
|
@@ -264,34 +291,47 @@ if [ -f "$sentinel" ]; then
|
|
|
264
291
|
rm -f "$sentinel"
|
|
265
292
|
fi
|
|
266
293
|
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
#
|
|
270
|
-
#
|
|
271
|
-
#
|
|
272
|
-
#
|
|
273
|
-
#
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
reviewfix_branch="
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
#
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
294
|
+
# #2825: when the user opted out of worktrees, edit/commit in the main
|
|
295
|
+
# checkout directly — no temp branch, no sentinel, no cleanup tail. This is
|
|
296
|
+
# the safe path: the hand-rolled worktree has no node_modules, so it cannot
|
|
297
|
+
# run the project's gates, and an improvised teardown can destroy the real
|
|
298
|
+
# node_modules on Windows (a junction followed by rm -rf). wt="." means every
|
|
299
|
+
# downstream read/edit/commit lands in the main working tree, and the cleanup
|
|
300
|
+
# tail below is a no-op (nothing to fast-forward, no worktree to remove).
|
|
301
|
+
if [ "$USE_WORKTREES" = "false" ]; then
|
|
302
|
+
wt="."
|
|
303
|
+
reviewfix_branch="$branch"
|
|
304
|
+
echo "workflow.use_worktrees=false — editing/committing in the main checkout (no worktree)."
|
|
305
|
+
else
|
|
306
|
+
wt=$(mktemp -d "/tmp/sv-${padded_phase}-reviewfix-XXXXXX")
|
|
307
|
+
|
|
308
|
+
# Create a temp branch from the current branch tip so the worktree
|
|
309
|
+
# attaches to that NEW branch rather than the user's currently-checked-out
|
|
310
|
+
# branch (#2990: git refuses to check out the same branch in two
|
|
311
|
+
# worktrees by default; the original `git worktree add "$wt" "$branch"`
|
|
312
|
+
# failed before the agent could do any work). The temp branch shares
|
|
313
|
+
# history with $branch up to the moment of creation, so commits made
|
|
314
|
+
# inside the worktree fast-forward $branch on cleanup.
|
|
315
|
+
reviewfix_branch="gsd-reviewfix/${padded_phase}-$$"
|
|
316
|
+
git worktree add -b "$reviewfix_branch" "$wt" "$branch"
|
|
317
|
+
|
|
318
|
+
# Write the recovery sentinel ONLY AFTER `git worktree add` succeeds.
|
|
319
|
+
# Writing it before would leave a sentinel pointing at a worktree that does
|
|
320
|
+
# not exist if `git worktree add` itself failed.
|
|
321
|
+
node -e '
|
|
322
|
+
const fs = require("fs");
|
|
323
|
+
const [sentinelPath, worktree_path, branch, reviewfix_branch, padded_phase] = process.argv.slice(1);
|
|
324
|
+
fs.writeFileSync(sentinelPath, JSON.stringify({
|
|
325
|
+
worktree_path,
|
|
326
|
+
branch,
|
|
327
|
+
reviewfix_branch,
|
|
328
|
+
padded_phase,
|
|
329
|
+
started_at: new Date().toISOString()
|
|
330
|
+
}, null, 2));
|
|
331
|
+
' "$sentinel" "$wt" "$branch" "$reviewfix_branch" "$padded_phase"
|
|
332
|
+
|
|
333
|
+
cd "$wt"
|
|
334
|
+
fi
|
|
295
335
|
```
|
|
296
336
|
|
|
297
337
|
Concrete steps:
|
|
@@ -305,9 +345,18 @@ Concrete steps:
|
|
|
305
345
|
|
|
306
346
|
**If `git worktree add` fails**, surface the error and exit — do not force-remove the path, as another concurrent run may be holding it. Do not write the sentinel (the worktree does not exist). Do not delete `$reviewfix_branch` either; if `-b` failed, no temp branch was created.
|
|
307
347
|
|
|
308
|
-
**Cleanup tail (transactional, ALWAYS — even on failure):** After writing REVIEW-FIX.md and before returning to the orchestrator, run the cleanup in this exact order
|
|
348
|
+
**Cleanup tail (transactional, ALWAYS — even on failure — when a worktree was created):** After writing REVIEW-FIX.md and before returning to the orchestrator, run the cleanup in this exact order. (When `workflow.use_worktrees` is `false`, no worktree was created — the cleanup is a no-op and the bash below early-exits.)
|
|
309
349
|
|
|
310
350
|
```bash
|
|
351
|
+
# #2825: when worktrees were disabled, there is nothing to clean up — the
|
|
352
|
+
# agent edited/committed on $branch directly in the main checkout (wt=".",
|
|
353
|
+
# reviewfix_branch==$branch, no sentinel, no temp worktree). Skip the whole
|
|
354
|
+
# tail; the four steps below are all no-ops or harmful (e.g. `git worktree
|
|
355
|
+
# remove "."` ) in that mode.
|
|
356
|
+
if [ "$USE_WORKTREES" = "false" ]; then
|
|
357
|
+
exit 0
|
|
358
|
+
fi
|
|
359
|
+
|
|
311
360
|
# Step 1 (#2990): fast-forward $branch to capture the commits the agent
|
|
312
361
|
# made on $reviewfix_branch. Run from the main repo (not $wt) — the user's
|
|
313
362
|
# checkout owns $branch. --ff-only ensures we never silently drop or
|
|
@@ -354,7 +403,7 @@ fi
|
|
|
354
403
|
rm -f "$sentinel"
|
|
355
404
|
```
|
|
356
405
|
|
|
357
|
-
This cleanup is unconditional — register it mentally as a finally-block obligation. If the agent exits early (config error, no findings, etc.), still run the cleanup tail in order (fast-forward → worktree remove → temp branch delete → sentinel rm) before exit. The sentinel must NEVER be removed before `git worktree remove` succeeds. The temp branch must NEVER be deleted while the fast-forward is in a diverged state.
|
|
406
|
+
This cleanup is unconditional when a worktree was created — register it mentally as a finally-block obligation. If the agent exits early (config error, no findings, etc.), still run the cleanup tail in order (fast-forward → worktree remove → temp branch delete → sentinel rm) before exit. (When `workflow.use_worktrees` is `false`, no worktree exists and the bash above early-exits before these steps.) The sentinel must NEVER be removed before `git worktree remove` succeeds. The temp branch must NEVER be deleted while the fast-forward is in a diverged state.
|
|
358
407
|
</step>
|
|
359
408
|
|
|
360
409
|
<step name="load_context">
|
|
@@ -456,7 +505,7 @@ For each finding in sorted order:
|
|
|
456
505
|
|
|
457
506
|
**If verification passed:**
|
|
458
507
|
|
|
459
|
-
Use `
|
|
508
|
+
Use `gsd_run query commit` with conventional format (message first, then every staged file path):
|
|
460
509
|
```bash
|
|
461
510
|
_GSD_SHIM_NAME="gsd-tools.cjs"; _GSD_RUNTIME_ROOT="${RUNTIME_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}"; GSD_TOOLS="${_GSD_RUNTIME_ROOT}/gsd-core/bin/${_GSD_SHIM_NAME}"; if [ -f "$GSD_TOOLS" ]; then gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${_GSD_RUNTIME_ROOT}/.claude/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${_GSD_RUNTIME_ROOT}/.claude/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${_GSD_RUNTIME_ROOT}/.codex/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${_GSD_RUNTIME_ROOT}/.codex/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif command -v gsd-tools >/dev/null 2>&1; then GSD_TOOLS="$(command -v gsd-tools)"; gsd_run() { "$GSD_TOOLS" "$@"; }; elif [ -f "${CLAUDE_CONFIG_DIR:-$HOME/.claude}/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${CLAUDE_CONFIG_DIR:-$HOME/.claude}/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${HERMES_HOME:-$HOME/.hermes}/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${HERMES_HOME:-$HOME/.hermes}/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${CURSOR_CONFIG_DIR:-$HOME/.cursor}/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${CURSOR_CONFIG_DIR:-$HOME/.cursor}/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${CODEX_HOME:-$HOME/.codex}/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${CODEX_HOME:-$HOME/.codex}/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${GEMINI_CONFIG_DIR:-$HOME/.gemini}/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${GEMINI_CONFIG_DIR:-$HOME/.gemini}/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${COPILOT_CONFIG_DIR:-$HOME/.copilot}/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${COPILOT_CONFIG_DIR:-$HOME/.copilot}/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${WINDSURF_CONFIG_DIR:-$HOME/.codeium/windsurf}/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${WINDSURF_CONFIG_DIR:-$HOME/.codeium/windsurf}/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${AUGMENT_CONFIG_DIR:-$HOME/.augment}/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${AUGMENT_CONFIG_DIR:-$HOME/.augment}/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${TRAE_CONFIG_DIR:-$HOME/.trae}/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${TRAE_CONFIG_DIR:-$HOME/.trae}/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${QWEN_CONFIG_DIR:-$HOME/.qwen}/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${QWEN_CONFIG_DIR:-$HOME/.qwen}/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${CODEBUDDY_CONFIG_DIR:-$HOME/.codebuddy}/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${CODEBUDDY_CONFIG_DIR:-$HOME/.codebuddy}/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${CLINE_CONFIG_DIR:-$HOME/.cline}/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${CLINE_CONFIG_DIR:-$HOME/.cline}/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${GROK_AGENTS_HOME:-$HOME/.agents}/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${GROK_AGENTS_HOME:-$HOME/.agents}/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${ANTIGRAVITY_CONFIG_DIR:-$HOME/.gemini/antigravity}/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${ANTIGRAVITY_CONFIG_DIR:-$HOME/.gemini/antigravity}/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${OPENCODE_CONFIG_DIR:-${XDG_CONFIG_HOME:-$HOME/.config}/opencode}/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${OPENCODE_CONFIG_DIR:-${XDG_CONFIG_HOME:-$HOME/.config}/opencode}/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${KILO_CONFIG_DIR:-${XDG_CONFIG_HOME:-$HOME/.config}/kilo}/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${KILO_CONFIG_DIR:-${XDG_CONFIG_HOME:-$HOME/.config}/kilo}/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; else echo "ERROR: gsd-tools.cjs not found at $GSD_TOOLS and gsd-tools is not on PATH. Run: npx -y @opengsd/gsd-core@latest --claude --local" >&2; exit 1; fi; if [ -n "${CLAUDE_ENV_FILE:-}" ] && [ -n "${GSD_TOOLS:-}" ]; then printf "export PATH='%s':\"\$PATH\"\n" "${GSD_TOOLS%/*}" >> "$CLAUDE_ENV_FILE" 2>/dev/null || true; fi
|
|
462
511
|
gsd_run query commit \
|
|
@@ -587,9 +636,33 @@ _Iteration: {N}_
|
|
|
587
636
|
|
|
588
637
|
<critical_rules>
|
|
589
638
|
|
|
590
|
-
**ALWAYS run inside the isolated worktree** — set up via `branch=$(git branch --show-current)` + `wt=$(mktemp -d "/tmp/sv-${padded_phase}-reviewfix-XXXXXX")` + `git worktree add -b "$reviewfix_branch" "$wt" "$branch"` at the very start (see `setup_worktree` step). Using `mktemp` ensures concurrent runs do not collide. Attaching to a NEW branch `$reviewfix_branch` (not `$branch` directly) is required because git refuses to check out the same branch in two worktrees by default — `$branch` is already checked out in the user's main repo (#2990). Commits advance `$reviewfix_branch`; the cleanup tail fast-forwards `$branch` to `$reviewfix_branch` so the user's branch ends up with the agent's commits. Every file read, edit, and commit must happen inside `$wt`. Run the four-step cleanup tail
|
|
591
|
-
|
|
592
|
-
|
|
639
|
+
**ALWAYS run inside the isolated worktree** — set up via `branch=$(git branch --show-current)` + `wt=$(mktemp -d "/tmp/sv-${padded_phase}-reviewfix-XXXXXX")` + `git worktree add -b "$reviewfix_branch" "$wt" "$branch"` at the very start (see `setup_worktree` step). Using `mktemp` ensures concurrent runs do not collide. Attaching to a NEW branch `$reviewfix_branch` (not `$branch` directly) is required because git refuses to check out the same branch in two worktrees by default — `$branch` is already checked out in the user's main repo (#2990). Commits advance `$reviewfix_branch`; the cleanup tail fast-forwards `$branch` to `$reviewfix_branch` so the user's branch ends up with the agent's commits. Every file read, edit, and commit must happen inside `$wt`. Run the four-step cleanup tail when done (treat it as a finally block) — but only when a worktree was actually created; when `workflow.use_worktrees` is `false` the cleanup early-exits (no worktree to remove). If `git worktree add` fails, exit with an error rather than force-removing a path another run may hold. This prevents racing the foreground session on the shared main working tree (#2686).
|
|
640
|
+
|
|
641
|
+
**#2825 — honor `workflow.use_worktrees`.** Before creating a worktree, read the
|
|
642
|
+
`workflow.use_worktrees` config flag (the documented opt-out — same key the four sibling writer
|
|
643
|
+
workflows honor). `setup_worktree` reads it via `node` directly from `.planning/config.json`
|
|
644
|
+
(because that step runs BEFORE the canonical gsd_run launcher preamble is sourced; later steps may
|
|
645
|
+
use `gsd_run query config-get workflow.use_worktrees`). When it is `false`, do NOT create a worktree
|
|
646
|
+
— edit and commit in the main checkout directly (`wt="."`, no temp branch, no sentinel, no cleanup
|
|
647
|
+
tail). A user who opted out of worktrees must
|
|
648
|
+
never have one created. See the `setup_worktree` step for the gated bash.
|
|
649
|
+
|
|
650
|
+
**NEVER `rm -rf` a possible reparse point** (#2825). On Windows, `node_modules` inside the worktree
|
|
651
|
+
may be a junction/reparse point whose target is the REAL `node_modules` in the main checkout — and
|
|
652
|
+
`rm -rf` follows the link and deletes the target's contents (silent, misdiagnosable data loss). Do
|
|
653
|
+
NOT improvise a `node_modules` teardown. The worktree has no `node_modules` by design; if you need
|
|
654
|
+
the project's gates, run them in the main checkout after the fast-forward, OR leave the worktree's
|
|
655
|
+
dependency handling to `git worktree remove` (which does not recurse into a separately-managed
|
|
656
|
+
link). Never use `rm -rf` (or `2>/dev/null || rm -rf || true`) as a fallback for removing a path
|
|
657
|
+
that might be a reparse point — on failure, STOP and surface the error rather than falling through
|
|
658
|
+
to a destructive remove.
|
|
659
|
+
|
|
660
|
+
**Record where verification ran** (#2825). The REVIEW-FIX.md verification section must state whether
|
|
661
|
+
the gates ran in the main checkout or the isolated worktree, so a reader can tell whether the numbers
|
|
662
|
+
are reproducible from the tree they are looking at (a worktree-env run is not reproducible from the
|
|
663
|
+
main checkout after teardown).
|
|
664
|
+
|
|
665
|
+
**ALWAYS run the transactional cleanup tail in order when a worktree was created** (#2839, #2990; skipped — bash early-exits — when `workflow.use_worktrees` is `false`): the cleanup is four steps with strict ordering. (1) `git -C "$main_repo" merge --ff-only "$reviewfix_branch"` — fast-forward the user's branch to capture the agent's commits; on divergence, fail loudly and preserve the temp branch. (2) `git worktree remove "$wt" --force`. (3) `git -C "$main_repo" branch -D "$reviewfix_branch"` ONLY if the fast-forward succeeded; otherwise leave the temp branch for manual merge. (4) `rm -f "$sentinel"` (the recovery sentinel at `${phase_dir}/.review-fix-recovery-pending.json`). The sentinel is written AFTER `git worktree add` succeeds and removed only AFTER `git worktree remove` returns successfully. The temp branch is deleted only when the fast-forward succeeded. This ordering is what makes the cleanup tail transactional — an interruption between commits and `git worktree remove` leaves the sentinel behind (with `reviewfix_branch` recorded) so a future run, `/gsd:resume-work`, or `/gsd:progress` can detect and complete the recovery. Reversing the order recreates the orphan-worktree bug.
|
|
593
666
|
|
|
594
667
|
**ALWAYS use the Write tool to create files** — never use `Bash(cat << 'EOF')` or heredoc commands for file creation.
|
|
595
668
|
|
|
@@ -175,7 +175,7 @@ Write document(s) to `.planning/codebase/` using the templates below.
|
|
|
175
175
|
**Document naming:** UPPERCASE.md (e.g., STACK.md, ARCHITECTURE.md)
|
|
176
176
|
|
|
177
177
|
**Template filling:**
|
|
178
|
-
1.
|
|
178
|
+
1. Set the `**Analysis Date:**` line, the `*... analysis: ...*` footer, and any `<!-- refreshed: ... -->` header to the date provided in your prompt (the `Today's date:` line), overwriting whatever date is already there. NEVER guess or infer the date — always use the exact date from the prompt.
|
|
179
179
|
2. Replace `[Placeholder text]` with findings from exploration
|
|
180
180
|
3. If something is not found, use "Not detected" or "Not applicable"
|
|
181
181
|
4. Always include file paths with backticks
|
|
@@ -310,6 +310,41 @@ If user selects 3: proceed to Step 4 with fix = "not applied (guardrail rejected
|
|
|
310
310
|
|
|
311
311
|
Read the resolved (or current) debug file to extract final Resolution values.
|
|
312
312
|
|
|
313
|
+
**Commit before returning a terminal summary (#2568).** This agent owns the terminal path —
|
|
314
|
+
it applies fixes, archives to `resolved/`, and returns the summary — but carried no commit
|
|
315
|
+
step, so `commit_docs` was never consulted on the normal `/gsd:debug` flow and session docs
|
|
316
|
+
were left untracked. Do this for **both** terminal shapes below, and **NOT** for
|
|
317
|
+
`CONTINUE_REQUIRED` above: that shape is non-terminal, and committing there would strand a
|
|
318
|
+
half-finished session looking done, exactly as fabricating a terminal summary would.
|
|
319
|
+
`CHECKPOINT REACHED` (Step 3d) likewise does not commit — it pauses for user input and loops
|
|
320
|
+
back to Step 3.
|
|
321
|
+
|
|
322
|
+
1. **In-session fix code.** If a fix was applied during this session and its code changes are
|
|
323
|
+
still uncommitted, commit them first. Stage **specific files only** — the files the fix
|
|
324
|
+
touched. Do this rather than `git add -A`, which would sweep unrelated working-tree
|
|
325
|
+
changes into a debug commit. Guard on staged content: `gsd-debugger.md`'s
|
|
326
|
+
`archive_session` step may already have committed this fix on the confirmed-checkpoint
|
|
327
|
+
path, and a bare `git commit` with nothing staged exits non-zero and would abort this
|
|
328
|
+
step before the summary is returned:
|
|
329
|
+
```bash
|
|
330
|
+
git add <files the fix touched>
|
|
331
|
+
git diff --cached --quiet || git commit -m "fix: {brief description}"
|
|
332
|
+
```
|
|
333
|
+
2. **Session doc.** Commit via the CLI, which already gates on `commit_docs` and returns
|
|
334
|
+
`skipped_commit_docs_false` when disabled — call it unconditionally rather than
|
|
335
|
+
re-checking the config here, so the policy lives in one place. `query commit` treats an
|
|
336
|
+
empty diff as `nothing_to_commit` and exits 0, so a second call after
|
|
337
|
+
`archive_session` already committed the doc is a safe no-op. The canonical `gsd_run` preamble is
|
|
338
|
+
established once in Step 2 and is the single definition this agent carries (repo
|
|
339
|
+
invariant: exactly one preamble per agent file, before its first call):
|
|
340
|
+
```bash
|
|
341
|
+
# resolved session — path spelled literally; this agent receives `slug` and
|
|
342
|
+
# `debug_file_path`, NOT a `debug_dir` variable (see <session_parameters>).
|
|
343
|
+
gsd_run query commit "docs(debug): resolve {slug} session" --files .planning/debug/resolved/{slug}.md
|
|
344
|
+
# abandoned session (checkpoint retained for `/gsd:debug continue {slug}`)
|
|
345
|
+
gsd_run query commit "docs(debug): checkpoint {slug} session" --files {debug_file_path}
|
|
346
|
+
```
|
|
347
|
+
|
|
313
348
|
Return compact summary (terminal — investigation resolved):
|
|
314
349
|
|
|
315
350
|
```markdown
|
|
@@ -349,5 +384,6 @@ If the session was abandoned by user choice, return (terminal — user stopped):
|
|
|
349
384
|
- [ ] TDD gate applied when tdd_mode=true and ROOT CAUSE FOUND
|
|
350
385
|
- [ ] Loop continues until DEBUG COMPLETE, ABANDONED, or user stops
|
|
351
386
|
- [ ] Non-terminal `CONTINUE_REQUIRED` (not a fabricated terminal summary) returned when the manager's own turn/context budget is exhausted mid-investigation
|
|
387
|
+
- [ ] Session doc (and any uncommitted fix code from this session) committed before a terminal summary, respecting `commit_docs` — and NOT committed on the non-terminal `CONTINUE_REQUIRED` path
|
|
352
388
|
- [ ] Compact summary returned (at most 2K tokens)
|
|
353
389
|
</success_criteria>
|
package/agents/gsd-executor.md
CHANGED
|
@@ -495,11 +495,11 @@ if [ -f .git ]; then # worktree
|
|
|
495
495
|
echo "DO NOT use 'git update-ref' to rewind the protected branch — surface as blocker (#2924)." >&2
|
|
496
496
|
exit 1
|
|
497
497
|
fi
|
|
498
|
-
# Positive allow-list: HEAD must be on
|
|
499
|
-
#
|
|
500
|
-
# arbitrary branch that the deny-list would silently allow (#2924).
|
|
501
|
-
if ! echo "$ACTUAL_BRANCH" | grep -Eq '^worktree-agent-[A-Za-z0-9._/-]+$'; then
|
|
502
|
-
echo "FATAL: refusing to commit — worktree HEAD '$ACTUAL_BRANCH' is not in the worktree-agent-* namespace." >&2
|
|
498
|
+
# Positive allow-list: HEAD must be on a per-agent branch (`agent-<id>` or
|
|
499
|
+
# legacy `worktree-agent-<id>`). This catches feature/* and any other
|
|
500
|
+
# arbitrary branch that the deny-list would silently allow (#2924, #1995).
|
|
501
|
+
if ! echo "$ACTUAL_BRANCH" | grep -Eq '^(worktree-)?agent-[A-Za-z0-9._/-]+$'; then
|
|
502
|
+
echo "FATAL: refusing to commit — worktree HEAD '$ACTUAL_BRANCH' is not in the agent-* / worktree-agent-* namespace." >&2
|
|
503
503
|
echo "Agent commits must live on per-agent branches; surface as blocker (#2924)." >&2
|
|
504
504
|
exit 1
|
|
505
505
|
fi
|
|
@@ -638,7 +638,16 @@ This file is the canonical output of this step. The orchestrator reads `.plannin
|
|
|
638
638
|
|
|
639
639
|
**Use template:** @~/.claude/gsd-core/templates/summary.md
|
|
640
640
|
|
|
641
|
-
**Frontmatter:** phase, plan, subsystem, tags, dependency graph (requires/provides/affects), tech-stack (added/patterns), key-files (created/modified), decisions, metrics (duration, completed date), status (`status: complete` — required so the audit-open scanner recognises the summary as done).
|
|
641
|
+
**Frontmatter:** phase, plan, subsystem, tags, dependency graph (requires/provides/affects), tech-stack (added/patterns), key-files (created/modified), decisions, metrics (duration, completed date), status (`status: complete` — required so the audit-open scanner recognises the summary as done), and `actuals` (#2632).
|
|
642
|
+
|
|
643
|
+
**`actuals` (required when the plan carried an `estimate`):** record what the phase ACTUALLY cost, on the SAME scale the estimate used — `estimateTokens` (chars/4) over the realized diff, NOT a harness token count. Mixing scales measures the measurement methods, not the miss.
|
|
644
|
+
```yaml
|
|
645
|
+
actuals:
|
|
646
|
+
tokens: 74000 # chars/4 over the files you actually changed
|
|
647
|
+
tasks: 5 # tasks completed
|
|
648
|
+
commits: 7 # commits made
|
|
649
|
+
```
|
|
650
|
+
These pair with the plan's `estimate` to calibrate future estimates (ADR-2629). Do not round to look closer to the estimate — a flattering number corrupts every later projection.
|
|
642
651
|
|
|
643
652
|
**Title:** `# Phase [X] Plan [Y]: [Name] Summary`
|
|
644
653
|
|
|
@@ -780,7 +789,7 @@ gsd_run query commit "docs({phase}-{plan}): complete [plan-name] plan" --files \
|
|
|
780
789
|
Separate from per-task commits — captures execution results only.
|
|
781
790
|
|
|
782
791
|
**Handling the SDK return envelope (#3678):** `gsd-tools query commit` returns
|
|
783
|
-
one of
|
|
792
|
+
one of these shapes:
|
|
784
793
|
|
|
785
794
|
- `{committed: true, hash, reason: 'committed'}` — commit succeeded; record
|
|
786
795
|
the hash in the completion format.
|
|
@@ -793,6 +802,10 @@ one of three shapes:
|
|
|
793
802
|
success path.** Record "skipped (.planning gitignored)" and move on.
|
|
794
803
|
- `{committed: false, reason: 'nothing_to_commit' | 'commit_failed', ...}` —
|
|
795
804
|
no-op / genuine failure; surface in the completion notes.
|
|
805
|
+
- `{committed: false, reason: 'staging_failed' | 'staging_timeout', file, error}` —
|
|
806
|
+
`git add` itself failed (#2608), e.g. an unwritable index. Nothing committed,
|
|
807
|
+
index rolled back. Surface `file` + `error` (git's stderr); do not retry — a
|
|
808
|
+
retry hits the same cause.
|
|
796
809
|
|
|
797
810
|
**Do not fall back to raw `git add` / `git commit` / `git add -f`** when the
|
|
798
811
|
SDK returns `skipped: true`. The SDK's skip is the user's deliberate choice
|
|
@@ -123,7 +123,7 @@ All JSON files include a `_meta` object with `updated_at` (ISO timestamp) and `v
|
|
|
123
123
|
}
|
|
124
124
|
```
|
|
125
125
|
|
|
126
|
-
**exports constraint:** Array of ACTUAL exported symbol names extracted from `module.exports` or `export` statements. MUST be real identifiers (e.g., `"configLoad"`, `"stateUpdate"`), NOT descriptions (e.g., `"config operations"`). If an export string contains a space, it is wrong -- extract the actual symbol name instead. Use `
|
|
126
|
+
**exports constraint:** Array of ACTUAL exported symbol names extracted from `module.exports` or `export` statements. MUST be real identifiers (e.g., `"configLoad"`, `"stateUpdate"`), NOT descriptions (e.g., `"config operations"`). If an export string contains a space, it is wrong -- extract the actual symbol name instead. Use `gsd_run intel extract-exports <file>` to get accurate exports.
|
|
127
127
|
|
|
128
128
|
Types: `entry-point`, `module`, `config`, `test`, `script`, `type-def`, `style`, `template`, `data`.
|
|
129
129
|
|
|
@@ -255,7 +255,7 @@ gsd_run intel patch-meta .planning/intel/arch-decisions.json
|
|
|
255
255
|
|
|
256
256
|
### Step 6.5: Self-Check
|
|
257
257
|
|
|
258
|
-
Run: `
|
|
258
|
+
Run: `gsd_run intel validate`
|
|
259
259
|
|
|
260
260
|
Review the output:
|
|
261
261
|
|
|
@@ -267,7 +267,7 @@ This step is MANDATORY -- do not skip it.
|
|
|
267
267
|
|
|
268
268
|
### Step 7: Snapshot
|
|
269
269
|
|
|
270
|
-
Run: `
|
|
270
|
+
Run: `gsd_run intel snapshot`
|
|
271
271
|
|
|
272
272
|
This writes `.last-refresh.json` with accurate timestamps and hashes. Do NOT write `.last-refresh.json` manually.
|
|
273
273
|
</execution_flow>
|
|
@@ -32,6 +32,8 @@ Spawned by `/gsd:plan-phase` (integrated) or `/gsd:plan-phase --research-phase <
|
|
|
32
32
|
|
|
33
33
|
**Package name provenance rule:** A package name discovered via WebSearch, training data, or any non-authoritative source must be tagged `[ASSUMED]` regardless of whether `npm view` confirms it exists on the registry. Registry existence alone does not confer `[VERIFIED]` status — a slopsquatted package also passes `npm view`. Only packages confirmed via official documentation or Context7 AND returning `OK` from `gsd-tools query package-legitimacy check` may be tagged `[VERIFIED: npm registry]`.
|
|
34
34
|
|
|
35
|
+
**In-repo value provenance rule:** A claim about an in-repo *discrete value* — an enum, a schema or type union, an error code, a status constant, or a filesystem path — may be tagged `[VERIFIED: …]` only if you opened the source-of-truth file with `Read` **this session**. A codebase `grep` is not sufficient on its own: it confirms a string occurs, not that you read the definition. Cite the path **and line range** (`[VERIFIED: src/types/order.ts:14-22]`), and quote the values **verbatim** in RESEARCH.md beside the claim — paraphrase is forbidden. The quote is what makes the tag checkable — a citation with no quote beside it does not earn `[VERIFIED]`, however precise the line range looks. Every value appearing in a code example or skeleton must also appear in that verbatim quote; a value that does not is `[ASSUMED]`. For a filesystem path, cite the line in the script that creates it, not the location you expect it to occupy. Training memory and a web search are not substitutes for reading the file — a discrete value that merely looks right fails at the executor's `parse()`/typecheck, the most expensive place to discover it.
|
|
36
|
+
|
|
35
37
|
Claims tagged `[ASSUMED]` signal to the planner and discuss-phase that the information needs user confirmation before becoming a locked decision. Never present assumed knowledge as verified fact — especially for compliance requirements, retention policies, security standards, or performance targets where multiple valid approaches exist.
|
|
36
38
|
</role>
|
|
37
39
|
|
|
@@ -136,7 +138,7 @@ For each item where `fetch` is present, invoke the MCP tool matching `fetch.prov
|
|
|
136
138
|
| `exa` | `mcp__exa__web_search_exa` with `fetch.query` |
|
|
137
139
|
| `tavily` | `mcp__tavily__search` with `fetch.query` |
|
|
138
140
|
| `perplexity` | `mcp__perplexity__*` (use the appropriate perplexity MCP tool for the query) |
|
|
139
|
-
| `brave` | `
|
|
141
|
+
| `brave` | `gsd_run query websearch "<fetch.query>"` (Brave-backed) or built-in `WebSearch` |
|
|
140
142
|
| `firecrawl` | `mcp__firecrawl__scrape` with url (scrape kind) or `mcp__firecrawl__search` |
|
|
141
143
|
| `websearch` | built-in `WebSearch` tool |
|
|
142
144
|
| `webfetch` | built-in `WebFetch` tool |
|
|
@@ -707,7 +709,7 @@ docker info 2>/dev/null | head -3
|
|
|
707
709
|
|
|
708
710
|
## Step 3: Execute Research Protocol
|
|
709
711
|
|
|
710
|
-
For each domain, use the `<tool_strategy>` seam (Steps A–D): build questions JSON, call `
|
|
712
|
+
For each domain, use the `<tool_strategy>` seam (Steps A–D): build questions JSON, call `gsd_run query research-plan`, run the indicated provider per item, then cache each digest. Document findings with confidence levels as you go (use `gsd_run query classify-confidence --provider <id>` to obtain the tier).
|
|
711
713
|
|
|
712
714
|
## Step 4: Validation Architecture Research (if nyquist_validation enabled)
|
|
713
715
|
|
|
@@ -252,6 +252,19 @@ issue:
|
|
|
252
252
|
1. Count tasks per plan
|
|
253
253
|
2. Estimate files modified per plan
|
|
254
254
|
3. Check against thresholds
|
|
255
|
+
4. **Smart-zone estimate check (#2631, ADR-2629).** For each plan carrying an `estimate` block, run the
|
|
256
|
+
`estimate-check --calibrated` verb against its `estimate.tokens` (the `--calibrated` flag is required —
|
|
257
|
+
the plan's figure already has the factor applied, and omitting it would square the correction) (invoked in Step 1 below, after the launcher
|
|
258
|
+
preamble). The verb reads `workflow.smart_zone_tokens` and applies the project's calibration. Report
|
|
259
|
+
one line per plan: plan id, estimated tokens, the budget, and — when `over_budget` is true — the
|
|
260
|
+
returned `recommendation`, which names how many slices the phase should become.
|
|
261
|
+
|
|
262
|
+
**Over budget is a WARNING, never a blocker** (ADR-2629 Decision 5). Recommend re-slicing into a tracer
|
|
263
|
+
plus expansion slices; never fail the check on it. Report `estimate.confidence` alongside: `low` means
|
|
264
|
+
fewer than 3 completed phases carry actuals, so the figure is not yet calibrated for this project — say
|
|
265
|
+
so rather than presenting it as precise, and weigh the task/file thresholds above more heavily.
|
|
266
|
+
|
|
267
|
+
A plan with no `estimate` block is not a defect; the field is optional and additive.
|
|
255
268
|
|
|
256
269
|
**Thresholds:**
|
|
257
270
|
| Metric | Target | Warning | Blocker |
|
|
@@ -706,6 +719,13 @@ gsd_run query phase.list-plans "$phase_number"
|
|
|
706
719
|
gsd_run query phase.list-artifacts "$phase_number" --type research
|
|
707
720
|
gsd_run query roadmap.get-phase "$phase_number"
|
|
708
721
|
gsd_run query phase.list-artifacts "$phase_number" --type summary
|
|
722
|
+
|
|
723
|
+
# Smart-zone estimate check (#2631) — advisory, never fails the check.
|
|
724
|
+
for plan in "${phase_dir:-$PHASE_DIR}"/*-PLAN.md; do
|
|
725
|
+
[ -f "$plan" ] || continue # unmatched glob leaves the literal pattern — skip it
|
|
726
|
+
EST=$(sed -n '/^estimate:/,/^[a-z_]*:/p' "$plan" | grep -o 'tokens: *[0-9]*' | head -1 | grep -o '[0-9]*')
|
|
727
|
+
[ -n "$EST" ] && gsd_run query estimate-check --tokens "$EST" --calibrated 2>/dev/null || true
|
|
728
|
+
done
|
|
709
729
|
```
|
|
710
730
|
|
|
711
731
|
**Extract:** Phase goal, requirements (decompose goal), locked decisions, deferred ideas.
|
package/agents/gsd-planner.md
CHANGED
|
@@ -288,30 +288,15 @@ See @~/.claude/gsd-core/references/planner-guidance.md for dependency graph buil
|
|
|
288
288
|
|
|
289
289
|
<scope_estimation>
|
|
290
290
|
|
|
291
|
-
##
|
|
291
|
+
## Sizing and the Estimate Block
|
|
292
292
|
|
|
293
|
-
|
|
293
|
+
Full rules: @~/.claude/gsd-core/references/context-budget.md (Phase Sizing). Read before sizing.
|
|
294
294
|
|
|
295
|
-
**
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
| Medium (auth, payments) | 2 | ~20-30% | ~40-50% |
|
|
301
|
-
| Heavy (migrations, multi-subsystem) | 1-2 | ~30-40% | ~30-50% |
|
|
302
|
-
|
|
303
|
-
## Split Signals
|
|
304
|
-
|
|
305
|
-
**ALWAYS split if:**
|
|
306
|
-
- More than 3 tasks
|
|
307
|
-
- Multiple subsystems (DB + API + UI = separate plans)
|
|
308
|
-
- Any task with >5 file modifications
|
|
309
|
-
- Checkpoint + implementation in same plan
|
|
310
|
-
- Discovery + implementation in same plan
|
|
311
|
-
|
|
312
|
-
**CONSIDER splitting:** >5 files total, natural semantic boundaries, context cost estimate exceeds 40% for a single plan. See `<planner_authority_limits>` for prohibited split reasons.
|
|
313
|
-
|
|
314
|
-
See @~/.claude/gsd-core/references/planner-guidance.md for Granularity Calibration table (Coarse/Standard/Fine plans-per-phase).
|
|
295
|
+
- **2-3 tasks per plan.** **ALWAYS split if:** >3 tasks, multiple subsystems, or any task touching >5 files.
|
|
296
|
+
- **Emit `estimate`**: run `estimate-calibration`; `tokens` = raw projection x factor, `raw_tokens` = that
|
|
297
|
+
projection before the factor (calibration measures actual/raw), `confidence` verbatim — derived from
|
|
298
|
+
sample count, never self-rated.
|
|
299
|
+
- **Over the smart-zone budget?** Re-slice: tracer + expansion slices. Advisory, never a block.
|
|
315
300
|
|
|
316
301
|
</scope_estimation>
|
|
317
302
|
|
|
@@ -331,6 +316,12 @@ autonomous: true # false if plan has checkpoints
|
|
|
331
316
|
requirements: [] # REQUIRED — Requirement IDs from ROADMAP this plan addresses. MUST NOT be empty.
|
|
332
317
|
user_setup: [] # Human-required setup (omit if empty)
|
|
333
318
|
|
|
319
|
+
estimate: # Projected execution cost (see Estimate Emission)
|
|
320
|
+
tokens: 60000 # calibrated projection
|
|
321
|
+
raw_tokens: 30000 # pre-factor projection
|
|
322
|
+
tasks: 3 # task count the projection assumes
|
|
323
|
+
confidence: low # low | med | high — DERIVED from sample count, never self-rated
|
|
324
|
+
|
|
334
325
|
must_haves:
|
|
335
326
|
truths: [] # Observable behaviors
|
|
336
327
|
artifacts: [] # Files that must exist
|
|
@@ -412,6 +403,7 @@ Create `.planning/phases/XX-name/{padded_phase}-{plan}-SUMMARY.md` when done
|
|
|
412
403
|
| `autonomous` | Yes | `true` if no checkpoints |
|
|
413
404
|
| `requirements` | Yes | **MUST** list requirement IDs from ROADMAP. Every roadmap requirement ID MUST appear in at least one plan. |
|
|
414
405
|
| `user_setup` | No | Human-required setup items |
|
|
406
|
+
| `estimate` | No | Projected cost `{tokens, tasks, confidence}`. See Estimate Emission. |
|
|
415
407
|
| `must_haves` | Yes | Goal-backward verification criteria |
|
|
416
408
|
|
|
417
409
|
Wave numbers are pre-computed during planning. Execute-phase reads `wave` directly from frontmatter.
|
|
@@ -734,7 +726,7 @@ Read the most recent milestone retrospective and cross-milestone trends. Extract
|
|
|
734
726
|
</step>
|
|
735
727
|
|
|
736
728
|
<step name="inject_global_learnings">
|
|
737
|
-
If `features.global_learnings` is `true`: run `
|
|
729
|
+
If `features.global_learnings` is `true`: run `gsd_run query learnings.query --tag <tag> --limit 5` once per tag from PLAN.md frontmatter `tags` (or use the single most specific keyword). The handler matches one `--tag` at a time. Prefix matches with `[Prior learning from <project>]` as weak priors. Project-local decisions take precedence. Skip silently if disabled or no matches.
|
|
738
730
|
</step>
|
|
739
731
|
|
|
740
732
|
<step name="gather_phase_context">
|
|
@@ -102,7 +102,7 @@ For each item where `fetch` is present, invoke the MCP tool matching `fetch.prov
|
|
|
102
102
|
| `exa` | `mcp__exa__web_search_exa` with `fetch.query` |
|
|
103
103
|
| `tavily` | `mcp__tavily__search` with `fetch.query` |
|
|
104
104
|
| `perplexity` | `mcp__perplexity__*` (use the appropriate perplexity MCP tool for the query) |
|
|
105
|
-
| `brave` | `
|
|
105
|
+
| `brave` | `gsd_run query websearch "<fetch.query>"` (Brave-backed) or built-in `WebSearch` |
|
|
106
106
|
| `firecrawl` | `mcp__firecrawl__scrape` with url (scrape kind) or `mcp__firecrawl__search` |
|
|
107
107
|
| `websearch` | built-in `WebSearch` tool |
|
|
108
108
|
| `webfetch` | built-in `WebFetch` tool |
|
|
@@ -490,7 +490,7 @@ Orchestrator provides: project name/description, research mode, project context,
|
|
|
490
490
|
|
|
491
491
|
## Step 3: Execute Research
|
|
492
492
|
|
|
493
|
-
For each domain, use the `<tool_strategy>` seam (Steps A–D): build questions JSON, call `
|
|
493
|
+
For each domain, use the `<tool_strategy>` seam (Steps A–D): build questions JSON, call `gsd_run query research-plan`, run the indicated provider per item, then cache each digest. Document findings with confidence levels as you go (use `gsd_run query classify-confidence --provider <id>` to obtain the tier).
|
|
494
494
|
|
|
495
495
|
## Step 4: Quality Check
|
|
496
496
|
|
package/agents/gsd-ui-auditor.md
CHANGED
|
@@ -104,46 +104,6 @@ This gate runs unconditionally on every audit. The .gitignore ensures screenshot
|
|
|
104
104
|
|
|
105
105
|
</gitignore_gate>
|
|
106
106
|
|
|
107
|
-
<playwright_mcp_approach>
|
|
108
|
-
|
|
109
|
-
## Automated Screenshot Capture via Playwright-MCP (preferred when available)
|
|
110
|
-
|
|
111
|
-
Before attempting the CLI screenshot approach, check whether `mcp__playwright__*`
|
|
112
|
-
tools are available in this session. If they are, use them instead of the CLI approach:
|
|
113
|
-
|
|
114
|
-
```
|
|
115
|
-
# Preferred: Playwright-MCP automated verification
|
|
116
|
-
# 1. Navigate to the component URL
|
|
117
|
-
mcp__playwright__navigate(url="http://localhost:3000")
|
|
118
|
-
|
|
119
|
-
# 2. Take desktop screenshot
|
|
120
|
-
mcp__playwright__screenshot(name="desktop", width=1440, height=900)
|
|
121
|
-
|
|
122
|
-
# 3. Take mobile screenshot
|
|
123
|
-
mcp__playwright__screenshot(name="mobile", width=375, height=812)
|
|
124
|
-
|
|
125
|
-
# 4. For specific components listed in UI-SPEC.md, navigate to each
|
|
126
|
-
# component route and capture targeted screenshots for comparison
|
|
127
|
-
# against the spec's stated dimensions, colors, and layout.
|
|
128
|
-
|
|
129
|
-
# 5. Compare screenshots against UI-SPEC.md requirements:
|
|
130
|
-
# - Dimensions: Is component X width 70vw as specified?
|
|
131
|
-
# - Color: Is the accent color applied only on declared elements?
|
|
132
|
-
# - Layout: Are spacing values within the declared spacing scale?
|
|
133
|
-
# Report any visual discrepancies as automated findings.
|
|
134
|
-
```
|
|
135
|
-
|
|
136
|
-
**When Playwright-MCP is available:**
|
|
137
|
-
- Use it for all screenshot capture (skip the CLI approach below)
|
|
138
|
-
- Each UI checkpoint from UI-SPEC.md can be verified automatically
|
|
139
|
-
- Discrepancies are reported as pillar findings with screenshot evidence
|
|
140
|
-
- Items requiring subjective judgment are flagged as `needs_human_review: true`
|
|
141
|
-
|
|
142
|
-
**When Playwright-MCP is NOT available:** fall back to the CLI screenshot approach
|
|
143
|
-
below. Behavior is unchanged from the standard code-only audit path.
|
|
144
|
-
|
|
145
|
-
</playwright_mcp_approach>
|
|
146
|
-
|
|
147
107
|
<screenshot_approach>
|
|
148
108
|
|
|
149
109
|
## Screenshot Capture (CLI only — no MCP, no persistent browser)
|