@opengsd/gsd-core 1.18.0 → 1.20.0
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 +2 -1
- package/.opencode/plugins/gsd-core.js +2 -3
- package/agents/gsd-code-fixer.compact.md +7 -7
- package/agents/gsd-code-fixer.md +13 -7
- package/agents/gsd-code-reviewer.compact.md +49 -8
- package/agents/gsd-code-reviewer.md +53 -14
- package/agents/gsd-executor.md +8 -4
- package/agents/gsd-verifier.md +1 -1
- package/bin/install.js +422 -103
- package/commands/gsd/update.md +5 -2
- package/gsd-core/bin/gsd-tools.cjs +179 -30
- package/gsd-core/bin/lib/agent-install-check.cjs +29 -3
- package/gsd-core/bin/lib/args-terminator.cjs +114 -0
- package/gsd-core/bin/lib/broken-windows.cjs +59 -1
- package/gsd-core/bin/lib/capability-lifecycle.cjs +1 -12
- package/gsd-core/bin/lib/capability-lock.cjs +13 -2
- package/gsd-core/bin/lib/capability-registry.cjs +376 -103
- package/gsd-core/bin/lib/capability-state.cjs +14 -8
- package/gsd-core/bin/lib/capability-validator.cjs +32 -0
- package/gsd-core/bin/lib/commands.cjs +27 -17
- package/gsd-core/bin/lib/config-loader.cjs +13 -3
- package/gsd-core/bin/lib/config.cjs +256 -58
- package/gsd-core/bin/lib/core-utils.cjs +45 -0
- package/gsd-core/bin/lib/decision-coverage-support.cjs +74 -0
- package/gsd-core/bin/lib/frontmatter.cjs +21 -3
- package/gsd-core/bin/lib/gate-api-coverage-verify-pre.cjs +2 -2
- package/gsd-core/bin/lib/gate-context-drift.cjs +9 -4
- package/gsd-core/bin/lib/gate-decision-coverage-plan.cjs +6 -1
- package/gsd-core/bin/lib/gate-decision-coverage-verify.cjs +6 -1
- package/gsd-core/bin/lib/gate-evaluation-scope.cjs +134 -13
- package/gsd-core/bin/lib/gate-phase-context.cjs +7 -8
- package/gsd-core/bin/lib/gate-schema-drift.cjs +1 -1
- package/gsd-core/bin/lib/gate-tdd-review-checkpoint.cjs +63 -22
- package/gsd-core/bin/lib/gate-ui-safety.cjs +23 -5
- package/gsd-core/bin/lib/git-info-exclude.cjs +52 -0
- package/gsd-core/bin/lib/health-diagnostic-rules/phase-structure.cjs +31 -12
- package/gsd-core/bin/lib/health-diagnostic-rules/roadmap-disk-consistency.cjs +9 -7
- package/gsd-core/bin/lib/health-diagnostic-rules/state-consistency.cjs +3 -3
- package/gsd-core/bin/lib/health-diagnostic-types.cjs +4 -0
- package/gsd-core/bin/lib/health-diagnostic.cjs +52 -1
- package/gsd-core/bin/lib/host-integration.cjs +13 -6
- package/gsd-core/bin/lib/init.cjs +245 -68
- package/gsd-core/bin/lib/install-engine.cjs +246 -32
- package/gsd-core/bin/lib/install-profiles.cjs +9 -4
- package/gsd-core/bin/lib/installer-migration-report.cjs +2 -0
- package/gsd-core/bin/lib/io.cjs +6 -0
- package/gsd-core/bin/lib/markdown-line-diff.cjs +147 -0
- package/gsd-core/bin/lib/markdown-sectionizer.cjs +147 -1
- package/gsd-core/bin/lib/markdown-table.cjs +23 -0
- package/gsd-core/bin/lib/mcp-server.cjs +8 -5
- package/gsd-core/bin/lib/milestone-lock.cjs +8 -1
- package/gsd-core/bin/lib/milestone-release-map.cjs +244 -0
- package/gsd-core/bin/lib/milestone-release-tags.cjs +440 -0
- package/gsd-core/bin/lib/milestone.cjs +61 -51
- package/gsd-core/bin/lib/model-catalog.cjs +8 -0
- package/gsd-core/bin/lib/normalize-test-command.cjs +67 -0
- package/gsd-core/bin/lib/phase-entry-grammar.cjs +119 -0
- package/gsd-core/bin/lib/phase-id-display.cjs +2 -0
- package/gsd-core/bin/lib/phase-id.cjs +629 -38
- package/gsd-core/bin/lib/phase-lifecycle.cjs +12 -44
- package/gsd-core/bin/lib/phase-locator.cjs +328 -19
- package/gsd-core/bin/lib/phase.cjs +3066 -653
- package/gsd-core/bin/lib/planning-document.cjs +26 -5
- package/gsd-core/bin/lib/planning-inspect.cjs +27 -35
- package/gsd-core/bin/lib/planning-snapshot.cjs +15 -8
- package/gsd-core/bin/lib/planning-workspace.cjs +21 -3
- package/gsd-core/bin/lib/pristine-baseline.cjs +11 -3
- package/gsd-core/bin/lib/read-only-git-env.cjs +79 -0
- package/gsd-core/bin/lib/refactor-trigger-command-router.cjs +2 -2
- package/gsd-core/bin/lib/review-lane-descriptor.cjs +57 -2
- package/gsd-core/bin/lib/review-lane-invocation.cjs +125 -18
- package/gsd-core/bin/lib/review-lane-runner.cjs +33 -4
- package/gsd-core/bin/lib/reviewer-step-dispatch.cjs +11 -9
- package/gsd-core/bin/lib/roadmap-parser.cjs +735 -137
- package/gsd-core/bin/lib/roadmap-progress.cjs +136 -0
- package/gsd-core/bin/lib/roadmap-upgrade.cjs +47 -7
- package/gsd-core/bin/lib/roadmap.cjs +383 -123
- package/gsd-core/bin/lib/runtime-artifact-conversion.cjs +381 -14
- package/gsd-core/bin/lib/runtime-artifact-layout.cjs +8 -4
- package/gsd-core/bin/lib/runtime-hooks-surface.cjs +60 -16
- package/gsd-core/bin/lib/shell-command-projection.cjs +151 -19
- package/gsd-core/bin/lib/smart-entry.cjs +35 -11
- package/gsd-core/bin/lib/state-contract.cjs +39 -15
- package/gsd-core/bin/lib/state-document.cjs +344 -27
- package/gsd-core/bin/lib/state-transition.cjs +156 -32
- package/gsd-core/bin/lib/state.cjs +527 -186
- package/gsd-core/bin/lib/surface.cjs +9 -0
- package/gsd-core/bin/lib/task-command-router.cjs +5 -25
- package/gsd-core/bin/lib/task-content-resolution.cjs +46 -1
- package/gsd-core/bin/lib/template.cjs +2 -2
- package/gsd-core/bin/lib/validate.cjs +3 -2
- package/gsd-core/bin/lib/vendor/re2js.cjs +863 -577
- package/gsd-core/bin/lib/vendor/re2js.d.cts +284 -219
- package/gsd-core/bin/lib/verification.cjs +96 -9
- package/gsd-core/bin/lib/verify.cjs +4 -2
- package/gsd-core/bin/lib/workstream-inventory.cjs +26 -20
- package/gsd-core/bin/lib/worktree-safety.cjs +22 -1
- package/gsd-core/bin/shared/config-defaults.manifest.json +1 -0
- package/gsd-core/bin/shared/config-schema.manifest.json +1 -0
- package/gsd-core/bin/verify-reapply-patches.cjs +411 -10
- package/gsd-core/references/cicd-review-patterns.md +45 -0
- package/gsd-core/references/git-integration.md +11 -0
- package/gsd-core/references/loop-hook-dispatch.md +13 -6
- package/gsd-core/references/necessity-review.md +48 -0
- package/gsd-core/references/planning-config.md +2 -0
- package/gsd-core/references/tdd.md +2 -2
- package/gsd-core/templates/DEBUG.md +16 -0
- package/gsd-core/templates/config.json +2 -1
- package/gsd-core/templates/verification-report.md +1 -1
- package/gsd-core/workflows/audit-fix.md +2 -1
- package/gsd-core/workflows/code-review/steps/structural-pre-pass.md +10 -1
- package/gsd-core/workflows/code-review-fix.md +46 -5
- package/gsd-core/workflows/code-review.md +64 -7
- package/gsd-core/workflows/complete-milestone/steps/project-md-evolution-review.md +145 -0
- package/gsd-core/workflows/complete-milestone/steps/release-map.md +80 -0
- package/gsd-core/workflows/complete-milestone.md +37 -150
- package/gsd-core/workflows/diagnose-issues.md +29 -5
- package/gsd-core/workflows/discuss-phase/modes/power.md +1 -1
- package/gsd-core/workflows/discuss-phase-assumptions.md +33 -2
- package/gsd-core/workflows/discuss-phase-power.md +19 -2
- package/gsd-core/workflows/discuss-phase.md +6 -10
- package/gsd-core/workflows/execute-phase/steps/per-plan-worktree-gate.md +13 -7
- package/gsd-core/workflows/execute-phase/steps/post-merge-gate.md +7 -2
- package/gsd-core/workflows/execute-phase/steps/regression-gate-run.md +2 -1
- package/gsd-core/workflows/execute-phase/steps/verify-phase-goal.md +2 -2
- package/gsd-core/workflows/execute-phase/steps/wave-post-gate-hooks.md +11 -2
- package/gsd-core/workflows/execute-phase.md +10 -6
- package/gsd-core/workflows/execute-plan.md +1 -1
- package/gsd-core/workflows/health.md +2 -1
- package/gsd-core/workflows/import.md +1 -1
- package/gsd-core/workflows/plan-phase/steps/chunked-planning-mode.md +2 -2
- package/gsd-core/workflows/plan-phase/steps/stall-detection-helpers.md +13 -9
- package/gsd-core/workflows/plan-phase.md +14 -14
- package/gsd-core/workflows/pr-branch.md +2 -0
- package/gsd-core/workflows/quick/steps/plan-checker-loop.md +1 -1
- package/gsd-core/workflows/quick/steps/worktree-pre-dispatch-commit.md +8 -1
- package/gsd-core/workflows/quick-batch/steps/plan-checker-loop.md +2 -1
- package/gsd-core/workflows/quick.md +1 -1
- package/gsd-core/workflows/reapply-patches.md +104 -0
- package/gsd-core/workflows/review.md +70 -154
- package/gsd-core/workflows/section-manifest.json +5 -0
- package/gsd-core/workflows/secure-phase.md +1 -1
- package/gsd-core/workflows/settings-advanced.md +57 -9
- package/gsd-core/workflows/settings.md +1 -0
- package/gsd-core/workflows/ship.md +15 -4
- package/gsd-core/workflows/spec-phase.md +3 -6
- package/gsd-core/workflows/verify-work.md +4 -3
- package/hooks/dist/gsd-agent-isolation-guard.js +11 -1
- package/hooks/dist/gsd-cursor-subagent-start.js +6 -2
- package/hooks/dist/gsd-graphify-update.sh +6 -0
- package/hooks/dist/gsd-path-export.js +95 -0
- package/hooks/dist/gsd-secret-read-guard.js +172 -39
- package/hooks/dist/gsd-statusline.js +37 -3
- package/hooks/dist/gsd-windsurf-pre-write.js +29 -2
- package/hooks/dist/gsd-workflow-guard.js +3 -2
- package/hooks/dist/gsd-worktree-path-guard.js +29 -2
- package/hooks/dist/lib/git-probe.js +16 -0
- package/hooks/dist/lib/isolation-sentinel.js +44 -0
- package/hooks/dist/managed-hooks-registry.cjs +1 -0
- package/hooks/gsd-agent-isolation-guard.js +11 -1
- package/hooks/gsd-cursor-subagent-start.js +6 -2
- package/hooks/gsd-graphify-update.sh +6 -0
- package/hooks/gsd-path-export.js +95 -0
- package/hooks/gsd-secret-read-guard.js +172 -39
- package/hooks/gsd-statusline.js +37 -3
- package/hooks/gsd-windsurf-pre-write.js +29 -2
- package/hooks/gsd-workflow-guard.js +3 -2
- package/hooks/gsd-worktree-path-guard.js +29 -2
- package/hooks/hooks.json +1 -0
- package/hooks/lib/git-probe.js +16 -0
- package/hooks/lib/isolation-sentinel.js +44 -0
- package/hooks/managed-hooks-registry.cjs +1 -0
- package/package.json +15 -8
- package/pi/gsd.cjs +1047 -10
- package/pi/package-agents/gsd-advisor-researcher.md +113 -0
- package/pi/package-agents/gsd-ai-researcher.md +111 -0
- package/pi/package-agents/gsd-assumptions-analyzer.md +110 -0
- package/pi/package-agents/gsd-code-fixer.md +774 -0
- package/pi/package-agents/gsd-code-reviewer.md +441 -0
- package/pi/package-agents/gsd-codebase-mapper.md +850 -0
- package/pi/package-agents/gsd-debug-session-manager.md +416 -0
- package/pi/package-agents/gsd-debugger.md +1274 -0
- package/pi/package-agents/gsd-doc-classifier.md +269 -0
- package/pi/package-agents/gsd-doc-synthesizer.md +259 -0
- package/pi/package-agents/gsd-doc-verifier.md +212 -0
- package/pi/package-agents/gsd-doc-writer.md +626 -0
- package/pi/package-agents/gsd-dom-verifier.md +164 -0
- package/pi/package-agents/gsd-domain-researcher.md +144 -0
- package/pi/package-agents/gsd-eval-auditor.md +185 -0
- package/pi/package-agents/gsd-eval-planner.md +149 -0
- package/pi/package-agents/gsd-executor.md +898 -0
- package/pi/package-agents/gsd-framework-selector.md +159 -0
- package/pi/package-agents/gsd-integration-checker.md +476 -0
- package/pi/package-agents/gsd-intel-updater.md +338 -0
- package/pi/package-agents/gsd-mempalace-curator.md +49 -0
- package/pi/package-agents/gsd-nyquist-auditor.md +200 -0
- package/pi/package-agents/gsd-pattern-mapper.md +340 -0
- package/pi/package-agents/gsd-phase-researcher.md +897 -0
- package/pi/package-agents/gsd-plan-checker.md +1077 -0
- package/pi/package-agents/gsd-planner.md +1003 -0
- package/pi/package-agents/gsd-project-researcher.md +611 -0
- package/pi/package-agents/gsd-research-synthesizer.md +259 -0
- package/pi/package-agents/gsd-roadmapper.md +779 -0
- package/pi/package-agents/gsd-security-auditor.md +171 -0
- package/pi/package-agents/gsd-ui-auditor.md +581 -0
- package/pi/package-agents/gsd-ui-checker.md +417 -0
- package/pi/package-agents/gsd-ui-researcher.md +469 -0
- package/pi/package-agents/gsd-user-profiler.md +174 -0
- package/pi/package-agents/gsd-verifier.md +963 -0
- package/pi/package-agents/manifest.json +39 -0
- package/pi/package-skills/gsd-add-tests/SKILL.md +39 -0
- package/pi/package-skills/gsd-ai-integration-phase/SKILL.md +36 -0
- package/pi/package-skills/gsd-audit-fix/SKILL.md +34 -0
- package/pi/package-skills/gsd-audit-milestone/SKILL.md +40 -0
- package/pi/package-skills/gsd-audit-uat/SKILL.md +26 -0
- package/pi/package-skills/gsd-autonomous/SKILL.md +52 -0
- package/pi/package-skills/gsd-capture/SKILL.md +68 -0
- package/pi/package-skills/gsd-cleanup/SKILL.md +25 -0
- package/pi/package-skills/gsd-code-review/SKILL.md +71 -0
- package/pi/package-skills/gsd-complete-milestone/SKILL.md +147 -0
- package/pi/package-skills/gsd-config/SKILL.md +60 -0
- package/pi/package-skills/gsd-debug/SKILL.md +64 -0
- package/pi/package-skills/gsd-discuss-phase/SKILL.md +74 -0
- package/pi/package-skills/gsd-docs-update/SKILL.md +50 -0
- package/pi/package-skills/gsd-eval-review/SKILL.md +35 -0
- package/pi/package-skills/gsd-execute-phase/SKILL.md +62 -0
- package/pi/package-skills/gsd-explore/SKILL.md +26 -0
- package/pi/package-skills/gsd-extract-learnings/SKILL.md +25 -0
- package/pi/package-skills/gsd-fast/SKILL.md +33 -0
- package/pi/package-skills/gsd-forensics/SKILL.md +59 -0
- package/pi/package-skills/gsd-graphify/SKILL.md +210 -0
- package/pi/package-skills/gsd-health/SKILL.md +36 -0
- package/pi/package-skills/gsd-help/SKILL.md +37 -0
- package/pi/package-skills/gsd-import/SKILL.md +46 -0
- package/pi/package-skills/gsd-inbox/SKILL.md +42 -0
- package/pi/package-skills/gsd-ingest-docs/SKILL.md +43 -0
- package/pi/package-skills/gsd-manager/SKILL.md +46 -0
- package/pi/package-skills/gsd-map-codebase/SKILL.md +85 -0
- package/pi/package-skills/gsd-mempalace-capture/SKILL.md +111 -0
- package/pi/package-skills/gsd-mempalace-recall/SKILL.md +111 -0
- package/pi/package-skills/gsd-milestone-summary/SKILL.md +54 -0
- package/pi/package-skills/gsd-mvp-phase/SKILL.md +45 -0
- package/pi/package-skills/gsd-new-milestone/SKILL.md +49 -0
- package/pi/package-skills/gsd-new-project/SKILL.md +49 -0
- package/pi/package-skills/gsd-next/SKILL.md +34 -0
- package/pi/package-skills/gsd-ns-context/SKILL.md +31 -0
- package/pi/package-skills/gsd-ns-ideate/SKILL.md +30 -0
- package/pi/package-skills/gsd-ns-manage/SKILL.md +42 -0
- package/pi/package-skills/gsd-ns-project/SKILL.md +34 -0
- package/pi/package-skills/gsd-ns-review/SKILL.md +35 -0
- package/pi/package-skills/gsd-ns-workflow/SKILL.md +44 -0
- package/pi/package-skills/gsd-onboard/SKILL.md +46 -0
- package/pi/package-skills/gsd-pause-work/SKILL.md +48 -0
- package/pi/package-skills/gsd-phase/SKILL.md +61 -0
- package/pi/package-skills/gsd-plan-phase/SKILL.md +62 -0
- package/pi/package-skills/gsd-plan-review-convergence/SKILL.md +63 -0
- package/pi/package-skills/gsd-pr-branch/SKILL.md +31 -0
- package/pi/package-skills/gsd-profile-user/SKILL.md +48 -0
- package/pi/package-skills/gsd-progress/SKILL.md +51 -0
- package/pi/package-skills/gsd-quick/SKILL.md +179 -0
- package/pi/package-skills/gsd-quick-batch/SKILL.md +114 -0
- package/pi/package-skills/gsd-resume-work/SKILL.md +31 -0
- package/pi/package-skills/gsd-review/SKILL.md +50 -0
- package/pi/package-skills/gsd-review-backlog/SKILL.md +65 -0
- package/pi/package-skills/gsd-secure-phase/SKILL.md +37 -0
- package/pi/package-skills/gsd-settings/SKILL.md +30 -0
- package/pi/package-skills/gsd-ship/SKILL.md +27 -0
- package/pi/package-skills/gsd-sketch/SKILL.md +56 -0
- package/pi/package-skills/gsd-spec-phase/SKILL.md +63 -0
- package/pi/package-skills/gsd-spike/SKILL.md +53 -0
- package/pi/package-skills/gsd-stats/SKILL.md +22 -0
- package/pi/package-skills/gsd-surface/SKILL.md +177 -0
- package/pi/package-skills/gsd-thread/SKILL.md +29 -0
- package/pi/package-skills/gsd-ui-phase/SKILL.md +35 -0
- package/pi/package-skills/gsd-ui-review/SKILL.md +35 -0
- package/pi/package-skills/gsd-ultraplan-phase/SKILL.md +38 -0
- package/pi/package-skills/gsd-undo/SKILL.md +38 -0
- package/pi/package-skills/gsd-update/SKILL.md +54 -0
- package/pi/package-skills/gsd-validate-phase/SKILL.md +37 -0
- package/pi/package-skills/gsd-verify-work/SKILL.md +41 -0
- package/pi/package-skills/gsd-workspace/SKILL.md +57 -0
- package/pi/package-skills/gsd-workstreams/SKILL.md +73 -0
- package/scripts/build-hooks.js +4 -0
- package/scripts/ci-next-health.cjs +246 -23
- package/scripts/command-contract-helpers.cjs +1 -1
- package/scripts/docs-guard-registry.cjs +22 -7
- package/scripts/gen-features.cjs +14 -2
- package/scripts/gen-health-docs.cjs +13 -1
- package/scripts/gen-pi-package-skills.cjs +217 -0
- package/scripts/lib/drift-scan.cjs +27 -0
- package/scripts/lib/macos-conformance-tier.generated.cjs +17 -1
- package/scripts/lib/platform-conformance-tier.generated.cjs +37 -1
- package/scripts/lint-docs-guard-registration.exempt-baseline.cjs +3 -3
- package/scripts/lint-phase-enumeration-drift.cjs +8 -4
- package/scripts/lint-retired-runtime-name.cjs +5 -0
- package/scripts/lint-roadmap-progress-drift.cjs +421 -0
- package/scripts/mutation-matrix.cjs +23 -1
- package/scripts/npm-audit-baseline.cjs +41 -7
- package/scripts/reviewed-or-maintainer-policy.cjs +181 -0
- package/scripts/select-docs-guards.cjs +1 -1
- package/scripts/self-test-report-policy.cjs +350 -0
- package/scripts/sync-next-version.cjs +38 -6
- package/skills/gsd-update/SKILL.md +5 -2
- package/vscode/package.json +1 -1
- package/scripts/diagnose-validate-commit-in-tier.cjs +0 -270
- package/scripts/diagnose-validate-commit-phases.cjs +0 -348
- package/scripts/xtrace-phase-timing.cjs +0 -205
|
@@ -27,20 +27,11 @@ command -v cursor-agent >/dev/null 2>&1 && echo "cursor:available" || echo "curs
|
|
|
27
27
|
command -v agy >/dev/null 2>&1 && echo "antigravity:available" || echo "antigravity:missing"
|
|
28
28
|
command -v kimi >/dev/null 2>&1 && echo "kimi-code:available" || echo "kimi-code:missing"
|
|
29
29
|
|
|
30
|
-
# Check local model servers (OpenAI-compatible HTTP API — no CLI binary required)
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
curl -s --max-time 2 "${OLLAMA_HOST}/v1/models" >/dev/null 2>&1 && echo "ollama:available" || echo "ollama:missing"
|
|
30
|
+
# Check local model servers (OpenAI-compatible HTTP API — no CLI binary required);
|
|
31
|
+
# hosts and defaults come from each lane's descriptor
|
|
32
|
+
gsd_run review-lane availability || { echo "WARNING: review-lane availability failed or is unsupported by this gsd-tools; treating local lanes as missing" >&2; printf 'ollama:missing\nlm_studio:missing\nllama_cpp:missing\n'; }
|
|
34
33
|
|
|
35
|
-
|
|
36
|
-
if [ -z "$LM_STUDIO_HOST" ] || [ "$LM_STUDIO_HOST" = "null" ]; then LM_STUDIO_HOST="http://localhost:1234"; fi
|
|
37
|
-
curl -s --max-time 2 "${LM_STUDIO_HOST}/v1/models" >/dev/null 2>&1 && echo "lm_studio:available" || echo "lm_studio:missing"
|
|
38
|
-
|
|
39
|
-
LLAMA_CPP_HOST=$(gsd_run query config-get review.llama_cpp_host --raw 2>/dev/null || echo "")
|
|
40
|
-
if [ -z "$LLAMA_CPP_HOST" ] || [ "$LLAMA_CPP_HOST" = "null" ]; then LLAMA_CPP_HOST="http://localhost:8080"; fi
|
|
41
|
-
curl -s --max-time 2 "${LLAMA_CPP_HOST}/v1/models" >/dev/null 2>&1 && echo "llama_cpp:available" || echo "llama_cpp:missing"
|
|
42
|
-
|
|
43
|
-
# jq prerequisite (#2589). The config/model/budget lookups in this workflow no
|
|
34
|
+
# jq prerequisite (#2589). The config/model lookups in this workflow no
|
|
44
35
|
# longer need jq — they use the native --raw/--pick flags. But the lanes listed
|
|
45
36
|
# under "jq-dependent reviewer lanes" below parse structured JSON that gsd-tools
|
|
46
37
|
# does not emit (OpenAI-compatible /v1/chat/completions responses, opencode's
|
|
@@ -254,7 +245,7 @@ Output your review in markdown format.
|
|
|
254
245
|
|
|
255
246
|
Write to a temp file: `{run_dir}/gsd-review-prompt.md`
|
|
256
247
|
|
|
257
|
-
|
|
248
|
+
Append the plan coverage manifest to the prompt:
|
|
258
249
|
|
|
259
250
|
```bash
|
|
260
251
|
# #2962: zsh aborts the block on an unmatched for-list glob (nomatch); bash passes it through. nullglob both.
|
|
@@ -262,38 +253,21 @@ shopt -s nullglob 2>/dev/null; setopt NULL_GLOB 2>/dev/null
|
|
|
262
253
|
|
|
263
254
|
RUN_DIR="{run_dir}" # from gather_context
|
|
264
255
|
|
|
265
|
-
# Write individual section files for per-reviewer budget trimming
|
|
266
|
-
# These are always written so reviewers with a budget can invoke prompt-budget
|
|
267
|
-
cp "$INSTRUCTIONS_BLOCK_FILE" "${RUN_DIR}/gsd-review-instructions.md"
|
|
268
|
-
cp "$ROADMAP_SECTION_FILE" "${RUN_DIR}/gsd-review-roadmap.md"
|
|
269
|
-
|
|
270
|
-
# Plan files: copy each PLAN.md to a predictable path named after its source
|
|
271
|
-
# plan id (#3959: a bare padded index discards provenance — the budget tool's
|
|
272
|
-
# per-plan `### <file>` header then renders a run-dir artifact name no reviewer
|
|
273
|
-
# or consensus step can resolve. The plan id keeps the gsd-review-plan-*.md glob
|
|
274
|
-
# prepare_trimmed_prompt_for_reviewer consumes.)
|
|
275
|
-
for PLAN_FILE in "${PHASE_DIR}"/*-PLAN.md; do
|
|
276
|
-
PLAN_BASENAME=$(basename "$PLAN_FILE")
|
|
277
|
-
PLAN_ID="${PLAN_BASENAME%-PLAN.md}"
|
|
278
|
-
cp "$PLAN_FILE" "${RUN_DIR}/gsd-review-plan-${PLAN_ID}.md"
|
|
279
|
-
done
|
|
280
|
-
|
|
281
256
|
# #3301: plan coverage manifest — tell reviewers exactly which plan ids exist and
|
|
282
257
|
# how many there are, so a review that silently covers 6 of 7 plans is no longer
|
|
283
258
|
# indistinguishable from one that covers all 7. The id is the plan file's own
|
|
284
259
|
# basename with the `-PLAN.md` suffix stripped (e.g. `12.6-01-PLAN.md` ->
|
|
285
260
|
# `12.6-01`) — NOT the `plan:` frontmatter key, which holds only the bare
|
|
286
261
|
# in-phase sequence number ("01") and can never reconstruct the phase-qualified
|
|
287
|
-
# id reviewers need to cite. The filename is guaranteed present for every
|
|
288
|
-
#
|
|
262
|
+
# id reviewers need to cite. The filename is guaranteed present for every plan,
|
|
263
|
+
# so no plan is ever dropped from the manifest for lacking a key.
|
|
289
264
|
# Count and bullets are both derived directly from the glob loop below, never
|
|
290
265
|
# from re-splitting an accumulated string: bash word-splits an unquoted `$VAR`
|
|
291
266
|
# on IFS by default, but zsh does not (no `setopt SH_WORD_SPLIT` here), so a
|
|
292
267
|
# prior `PLAN_IDS="$PLAN_IDS $id"` + `for x in $PLAN_IDS` round-trip silently
|
|
293
268
|
# collapsed every id onto one iteration under zsh whenever there were 2+ plans
|
|
294
|
-
# (gsd-core#4099). Direct glob iteration (`for f in "${PHASE_DIR}"/*-PLAN.md
|
|
295
|
-
#
|
|
296
|
-
# never needs word-splitting at all.
|
|
269
|
+
# (gsd-core#4099). Direct glob iteration (`for f in "${PHASE_DIR}"/*-PLAN.md`)
|
|
270
|
+
# is identical under both shells, so this never needs word-splitting at all.
|
|
297
271
|
PLAN_COUNT=0
|
|
298
272
|
PLAN_ID_BULLETS=""
|
|
299
273
|
for PLAN_FILE in "${PHASE_DIR}"/*-PLAN.md; do
|
|
@@ -304,10 +278,8 @@ for PLAN_FILE in "${PHASE_DIR}"/*-PLAN.md; do
|
|
|
304
278
|
"
|
|
305
279
|
done
|
|
306
280
|
|
|
307
|
-
#
|
|
308
|
-
#
|
|
309
|
-
# above) — a manifest matching either would be picked up as a report or as a
|
|
310
|
-
# plan to review.
|
|
281
|
+
# Dot-prefixed so the `gsd-review-*.md` glob over RUN_DIR (reviewer reports,
|
|
282
|
+
# invoke_reviewers) can never pick it up as a report.
|
|
311
283
|
{
|
|
312
284
|
echo ""
|
|
313
285
|
echo "## Plan Coverage Manifest"
|
|
@@ -318,33 +290,11 @@ done
|
|
|
318
290
|
printf '%s' "$PLAN_ID_BULLETS"
|
|
319
291
|
} > "${RUN_DIR}/.plans-manifest.md"
|
|
320
292
|
|
|
321
|
-
#
|
|
322
|
-
if [ -f ".planning/PROJECT.md" ]; then
|
|
323
|
-
cp .planning/PROJECT.md "${RUN_DIR}/gsd-review-project.md"
|
|
324
|
-
fi
|
|
325
|
-
_CTX=( "${PHASE_DIR}"/*-CONTEXT.md )
|
|
326
|
-
if [ ${#_CTX[@]} -gt 0 ]; then
|
|
327
|
-
cat "${_CTX[@]}" > "${RUN_DIR}/gsd-review-context.md"
|
|
328
|
-
fi
|
|
329
|
-
_RESEARCH=( "${PHASE_DIR}"/*-RESEARCH.md )
|
|
330
|
-
if [ ${#_RESEARCH[@]} -gt 0 ]; then
|
|
331
|
-
cat "${_RESEARCH[@]}" > "${RUN_DIR}/gsd-review-research.md"
|
|
332
|
-
fi
|
|
333
|
-
if [ -f ".planning/REQUIREMENTS.md" ]; then
|
|
334
|
-
cp .planning/REQUIREMENTS.md "${RUN_DIR}/gsd-review-requirements.md"
|
|
335
|
-
fi
|
|
336
|
-
|
|
337
|
-
# #3301: append the manifest to BOTH files reviewers actually read — the
|
|
338
|
-
# per-lane budget-trimmed instructions file (descriptor lanes get
|
|
339
|
-
# `--instructions-file`) and the full combined prompt (combined-prompt lanes
|
|
340
|
-
# read the whole file). The `instructions` fragment is in prompt-budget's
|
|
341
|
-
# `minimumFor` floor set and is never trimmed, so this survives per-lane
|
|
342
|
-
# budget trimming intact.
|
|
343
|
-
cat "${RUN_DIR}/.plans-manifest.md" >> "${RUN_DIR}/gsd-review-instructions.md"
|
|
293
|
+
# #3301: append the manifest to the one prompt file every lane reads.
|
|
344
294
|
cat "${RUN_DIR}/.plans-manifest.md" >> "${RUN_DIR}/gsd-review-prompt.md"
|
|
345
295
|
```
|
|
346
296
|
|
|
347
|
-
Note: `
|
|
297
|
+
Note: `PHASE_DIR` comes from prompt assembly; `RUN_DIR` is the run-scoped dir from `gather_context` (#2358) re-assigned from `{run_dir}` above. Every lane receives `gsd-review-prompt.md` whole — it is never trimmed per lane (#4559). A lane whose prompt exceeds its cap is refused in `invoke_reviewers`, not shortened.
|
|
348
298
|
</step>
|
|
349
299
|
|
|
350
300
|
<step name="invoke_reviewers">
|
|
@@ -417,35 +367,6 @@ REPO_ROOT="$(git rev-parse --show-toplevel 2>/dev/null || pwd)"
|
|
|
417
367
|
# user's intent; here it would fire exactly the requests the default exists to prevent.
|
|
418
368
|
PARALLEL_LANES=$(gsd_run query config-get review.parallel_lanes --raw 2>/dev/null || echo "false")
|
|
419
369
|
|
|
420
|
-
# Shared budget-trim helper. Was defined inside the Ollama leg; it is lane-agnostic, so it is
|
|
421
|
-
# hoisted here now that any lane may declare a promptBudgetKey. Returns non-zero when the budget
|
|
422
|
-
# is too small for the minimum review set (prompt-budget exit 2 / 11).
|
|
423
|
-
prepare_trimmed_prompt_for_reviewer() {
|
|
424
|
-
REVIEWER_KEY="$1"; REVIEWER_BUDGET="$2"; OUTPUT_PROMPT="$3"; OUTPUT_META="$4"
|
|
425
|
-
|
|
426
|
-
PLAN_FILE_ARGS=""
|
|
427
|
-
for p in "$RUN_DIR"/gsd-review-plan-*.md; do
|
|
428
|
-
[ -f "$p" ] && PLAN_FILE_ARGS="$PLAN_FILE_ARGS --plan-file $p"
|
|
429
|
-
done
|
|
430
|
-
PROJECT_ARG=""
|
|
431
|
-
[ -f "$RUN_DIR/gsd-review-project.md" ] && PROJECT_ARG="--project-file $RUN_DIR/gsd-review-project.md"
|
|
432
|
-
CONTEXT_ARG=""
|
|
433
|
-
[ -f "$RUN_DIR/gsd-review-context.md" ] && CONTEXT_ARG="--context-file $RUN_DIR/gsd-review-context.md"
|
|
434
|
-
RESEARCH_ARG=""
|
|
435
|
-
[ -f "$RUN_DIR/gsd-review-research.md" ] && RESEARCH_ARG="--research-file $RUN_DIR/gsd-review-research.md"
|
|
436
|
-
REQUIREMENTS_ARG=""
|
|
437
|
-
[ -f "$RUN_DIR/gsd-review-requirements.md" ] && REQUIREMENTS_ARG="--requirements-file $RUN_DIR/gsd-review-requirements.md"
|
|
438
|
-
|
|
439
|
-
gsd_run query prompt-budget \
|
|
440
|
-
--budget "$REVIEWER_BUDGET" \
|
|
441
|
-
--instructions-file "$RUN_DIR/gsd-review-instructions.md" \
|
|
442
|
-
--roadmap-file "$RUN_DIR/gsd-review-roadmap.md" \
|
|
443
|
-
$PLAN_FILE_ARGS $PROJECT_ARG $CONTEXT_ARG $RESEARCH_ARG $REQUIREMENTS_ARG \
|
|
444
|
-
--output-prompt "$OUTPUT_PROMPT" \
|
|
445
|
-
--output-metadata "$OUTPUT_META"
|
|
446
|
-
return $?
|
|
447
|
-
}
|
|
448
|
-
|
|
449
370
|
gsd_run query review-lane plan \
|
|
450
371
|
--selected "$SELECTED_REVIEWERS" --run-dir "$RUN_DIR" --repo-root "$REPO_ROOT" --json \
|
|
451
372
|
> "$RUN_DIR/gsd-review-lanes.json"
|
|
@@ -462,36 +383,18 @@ run_review_lane() {
|
|
|
462
383
|
# `local` is hygiene, not a live fix: each `&`-dispatched call already forks its own subshell, so
|
|
463
384
|
# concurrent lanes cannot share these today. Scoped anyway so the isolation is a property of this
|
|
464
385
|
# function rather than of the dispatch mechanism happening to fork.
|
|
465
|
-
local SLUG
|
|
386
|
+
local SLUG
|
|
466
387
|
SLUG="$1"
|
|
467
|
-
#
|
|
468
|
-
#
|
|
469
|
-
#
|
|
470
|
-
|
|
471
|
-
--repo-root "$REPO_ROOT" --json 2>/dev/null \
|
|
472
|
-
| sed -n 's/.*"promptBudget": *\([0-9-]*\).*/\1/p' | head -1)
|
|
473
|
-
PROMPT_ARG=""
|
|
474
|
-
if [ -n "$LANE_BUDGET" ] && [ "$LANE_BUDGET" != "null" ] && [ "$LANE_BUDGET" -gt 0 ] 2>/dev/null; then
|
|
475
|
-
TRIMMED="$RUN_DIR/gsd-review-prompt-$SLUG.md"
|
|
476
|
-
if prepare_trimmed_prompt_for_reviewer "$SLUG" "$LANE_BUDGET" "$TRIMMED" \
|
|
477
|
-
"$RUN_DIR/gsd-review-prompt-$SLUG.metadata.json"; then
|
|
478
|
-
PROMPT_ARG="--prompt-file $TRIMMED"
|
|
479
|
-
else
|
|
480
|
-
# A budget too small for the minimum review set drops the lane just as silently as an empty
|
|
481
|
-
# response used to (#2605), so leave the skip visible in the review output, not only on stderr.
|
|
482
|
-
echo "$SLUG review skipped: prompt budget (${LANE_BUDGET} tokens) too small for the minimum review set." \
|
|
483
|
-
> "$RUN_DIR/gsd-review-$SLUG.md"
|
|
484
|
-
# Was `continue` when this was a loop body. Inside a function that keyword is not the loop
|
|
485
|
-
# control it looks like — `return 0` is what skips this lane and leaves it with no result line.
|
|
486
|
-
return 0
|
|
487
|
-
fi
|
|
488
|
-
fi
|
|
388
|
+
# #4559: no per-lane trimming. Every lane receives the whole prompt; `review-lane invoke` measures it
|
|
389
|
+
# against the lane's cap (its own `promptBudgetKey`, the global `review.max_prompt_tokens`, or the
|
|
390
|
+
# default derived from its declared context window) and REFUSES a lane that is over, writing a
|
|
391
|
+
# `review did not run: prompt exceeds` stub. A trimmed prompt reviewed something other than the plans.
|
|
489
392
|
|
|
490
393
|
# One invocation, whatever the lane's transport, prompt channel, output channel or handler.
|
|
491
394
|
# `--explicit` marks a lane the user NAMED: ADR-2782 D4 — not finding a lane nobody asked for is
|
|
492
395
|
# normal, failing to run one somebody asked for is an error.
|
|
493
396
|
gsd_run query review-lane invoke --slug "$SLUG" \
|
|
494
|
-
--run-dir "$RUN_DIR" --repo-root "$REPO_ROOT" $
|
|
397
|
+
--run-dir "$RUN_DIR" --repo-root "$REPO_ROOT" $EXPLICIT_FLAG --json \
|
|
495
398
|
> "$RUN_DIR/gsd-review-lane-result-$SLUG.json"
|
|
496
399
|
}
|
|
497
400
|
|
|
@@ -536,13 +439,17 @@ wait
|
|
|
536
439
|
|
|
537
440
|
# Aggregate in SELECTED_REVIEWERS order, NOT completion order, so the JSONL a concurrent run
|
|
538
441
|
# produces is byte-identical to the one a sequential run produces. This is post-join and therefore
|
|
539
|
-
# single-threaded, so `>>` here is safe. A lane that
|
|
540
|
-
#
|
|
442
|
+
# single-threaded, so `>>` here is safe. A lane that never started leaves no result file, and a lane
|
|
443
|
+
# REFUSED for its prompt cap (#4559: reason `prompt_exceeds_context`) is deliberately left out of the
|
|
444
|
+
# aggregate — it did not run, so it must not count as a lane result or feed models:/model_sources:.
|
|
445
|
+
# Its own result file stays in RUN_DIR for the `refused_reviewers` frontmatter.
|
|
541
446
|
# Rewrapped through unquoted command substitution (gsd-core#4109) — see the
|
|
542
447
|
# dispatch loop above for why a bare `$DISPATCH_SLUGS` collapses under zsh.
|
|
543
448
|
for SLUG in $(printf '%s' "$DISPATCH_SLUGS"); do
|
|
544
449
|
LANE_RESULT="$RUN_DIR/gsd-review-lane-result-$SLUG.json"
|
|
545
|
-
|
|
450
|
+
# The refusal is the PARSED `reason` field — a failed lane whose `detail` merely mentions the
|
|
451
|
+
# string is a real lane result and must stay in the aggregate.
|
|
452
|
+
if [ -f "$LANE_RESULT" ] && ! node -e 'try{process.exit(JSON.parse(require("fs").readFileSync(process.argv[1],"utf8")).reason==="prompt_exceeds_context"?0:1)}catch{process.exit(1)}' "$LANE_RESULT"; then
|
|
546
453
|
cat "$LANE_RESULT" >> "$RUN_DIR/gsd-review-lane-results.jsonl"
|
|
547
454
|
fi
|
|
548
455
|
done
|
|
@@ -555,7 +462,9 @@ review: it keeps its "failed or returned empty output" header (#2494/#2605/#2794
|
|
|
555
462
|
|
|
556
463
|
A lane that will not run reports a typed reason rather than an empty file — `missing_binary`,
|
|
557
464
|
`probe_failed`, `probe_timeout`, `missing_required_binary`, `host_unreachable`,
|
|
558
|
-
`egress_host_changed`, `unknown_handler`, `
|
|
465
|
+
`egress_host_changed`, `unknown_handler`, `prompt_exceeds_context` (the prompt is over
|
|
466
|
+
the lane's cap — refused, never trimmed; its review file carries a `review did not run: prompt exceeds` stub).
|
|
467
|
+
**`egress_host_changed` means the lane
|
|
559
468
|
was consented to send plans to one destination and `.planning/config.json` now names another; it is
|
|
560
469
|
blocked, not silently redirected** (ADR-2782 D5).
|
|
561
470
|
|
|
@@ -572,7 +481,7 @@ Display progress:
|
|
|
572
481
|
**#3352 (ADR-3473 §8.5): no artifact from failed inputs.** Before rendering anything, gate on
|
|
573
482
|
whether any lane actually produced a result — "every lane failed" is exactly "the aggregate
|
|
574
483
|
JSONL has zero lines" (§`invoke_reviewers`'s aggregation loop already builds this file as a
|
|
575
|
-
byproduct; a lane that never started or was
|
|
484
|
+
byproduct; a lane that never started or was refused for its prompt cap contributes no line either way).
|
|
576
485
|
|
|
577
486
|
```bash
|
|
578
487
|
RUN_DIR="{run_dir}"
|
|
@@ -584,7 +493,7 @@ TOTAL_LANE_FAILURE="false"
|
|
|
584
493
|
ALL_LANES_SKIPPED="false"
|
|
585
494
|
if [ "${LANE_LINES:-0}" -eq 0 ]; then
|
|
586
495
|
# Zero lines means every dispatched lane left no result JSON — either every one
|
|
587
|
-
# was
|
|
496
|
+
# was refused for its prompt cap (N5: a refusal is not a failure) or every one actually failed
|
|
588
497
|
# to run. Re-derive the dispatched-slug set the same way invoke_reviewers did
|
|
589
498
|
# (SELECTED_REVIEWERS is a shell block boundary — recompute, do not assume the
|
|
590
499
|
# earlier step's local DISPATCH_SLUGS variable survived into this block).
|
|
@@ -595,10 +504,10 @@ if [ "${LANE_LINES:-0}" -eq 0 ]; then
|
|
|
595
504
|
esac
|
|
596
505
|
DISPATCH_SLUGS="$DISPATCH_SLUGS $SLUG"
|
|
597
506
|
done
|
|
598
|
-
# Distinguish by whether every dispatched slug's stub markdown
|
|
599
|
-
#
|
|
600
|
-
#
|
|
601
|
-
#
|
|
507
|
+
# Distinguish by whether every dispatched slug's stub markdown carries the refusal marker:
|
|
508
|
+
# `review-lane invoke` writes `review did not run: prompt exceeds ...` (#4559) before returning
|
|
509
|
+
# without ever probing or spawning the lane; a real failure stub does not. If a slug has no
|
|
510
|
+
# stub at all, it is not a refusal.
|
|
602
511
|
DISPATCHED_COUNT=0
|
|
603
512
|
SKIPPED_COUNT=0
|
|
604
513
|
# Rewrapped through unquoted command substitution (gsd-core#4109): a bare
|
|
@@ -607,7 +516,7 @@ if [ "${LANE_LINES:-0}" -eq 0 ]; then
|
|
|
607
516
|
for SLUG in $(printf '%s' "$DISPATCH_SLUGS"); do
|
|
608
517
|
DISPATCHED_COUNT=$((DISPATCHED_COUNT + 1))
|
|
609
518
|
STUB="$RUN_DIR/gsd-review-$SLUG.md"
|
|
610
|
-
if [ -f "$STUB" ] && grep -q "review
|
|
519
|
+
if [ -f "$STUB" ] && grep -q "review did not run: prompt exceeds" "$STUB" 2>/dev/null; then
|
|
611
520
|
SKIPPED_COUNT=$((SKIPPED_COUNT + 1))
|
|
612
521
|
fi
|
|
613
522
|
done
|
|
@@ -620,15 +529,16 @@ fi
|
|
|
620
529
|
```
|
|
621
530
|
|
|
622
531
|
- **If `ALL_LANES_SKIPPED=true`:** do NOT write `REVIEWS.md` and do NOT run the commit below —
|
|
623
|
-
there is nothing to review. Report to the user that every selected lane
|
|
624
|
-
(not a failure
|
|
532
|
+
there is nothing to review. Report to the user that every selected lane refused its prompt cap
|
|
533
|
+
(not a failure; name the cap and the `review.context_window_tokens.<slug>` /
|
|
534
|
+
`review.max_prompt_tokens_per_reviewer.<slug>` keys that raise it) and stop; do not proceed to `present_results`' summary claiming a review ran.
|
|
625
535
|
- **If `TOTAL_LANE_FAILURE=true`:** do NOT write `REVIEWS.md` and do NOT run the commit below.
|
|
626
536
|
Report the total lane failure to the user (name the lanes that were dispatched and point at
|
|
627
537
|
their `.err`/stub files preserved under `.review-diagnostics/` by `present_results`) and stop.
|
|
628
538
|
- **Otherwise** (at least one lane produced a result — R1, unchanged): proceed exactly as below.
|
|
629
539
|
|
|
630
540
|
**#3301: plan coverage check.** For each dispatched lane that produced a *real* review (not a
|
|
631
|
-
stub, not
|
|
541
|
+
stub, not refused for its prompt cap, not empty), check whether its output mentions every plan id from
|
|
632
542
|
`.plans-manifest.md` — the same manifest `build_prompt` gave the reviewer, so the expected-id list
|
|
633
543
|
here can never diverge from what the reviewer was actually told. This is diagnostic only: it never
|
|
634
544
|
blocks the workflow, never fails a lane, and never changes the `TOTAL_LANE_FAILURE`/
|
|
@@ -665,17 +575,29 @@ done
|
|
|
665
575
|
# Rewrapped through unquoted command substitution (gsd-core#4109): a bare
|
|
666
576
|
# `$DISPATCH_SLUGS` word-splits under bash but not zsh, collapsing every
|
|
667
577
|
# slug onto one iteration there whenever 2+ reviewers were selected.
|
|
578
|
+
# gsd-resolve-lib begin pattern.cjs (#5640): load helpers from the installed runtime, not the cwd
|
|
579
|
+
_gsd_lib_probe="pattern.cjs"
|
|
580
|
+
_gsd_rt="${RUNTIME_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}"
|
|
581
|
+
_gsd_gr="$(command -v gsd_run 2>/dev/null || true)"
|
|
582
|
+
case "$_gsd_gr" in /*) ;; *) _gsd_gr="" ;; esac # a gsd_run shell function prints its bare name: not a path
|
|
583
|
+
[ -n "$_gsd_gr" ] && _gsd_gr="$(dirname "$(node -p "require('fs').realpathSync(process.argv[1])" "$_gsd_gr" 2>/dev/null || echo "$_gsd_gr")")/lib"
|
|
584
|
+
GSD_LIB_DIR=""
|
|
585
|
+
_gsd_pick() { for _gsd_d; do if [ -n "$_gsd_d" ] && [ -f "$_gsd_d/$_gsd_lib_probe" ]; then GSD_LIB_DIR="$_gsd_d"; return 0; fi; done; return 1; }
|
|
586
|
+
_gsd_pick "${GSD_TOOLS:+${GSD_TOOLS%/*}/lib}" "$_gsd_rt/gsd-core/bin/lib" "$_gsd_rt/.claude/gsd-core/bin/lib" "$_gsd_rt/.codex/gsd-core/bin/lib" "$_gsd_gr" "${CLAUDE_CONFIG_DIR:-$HOME/.claude}/gsd-core/bin/lib" "${CODEX_HOME:-$HOME/.codex}/gsd-core/bin/lib" || true
|
|
587
|
+
if [ -z "$GSD_LIB_DIR" ]; then echo "ERROR: pattern.cjs not found in the GSD runtime. Looked in: ${GSD_TOOLS:+${GSD_TOOLS%/*}/lib, }${_gsd_rt}/gsd-core/bin/lib (and its .claude and .codex forms), ${_gsd_gr:-next to gsd_run (not on PATH)}, ${CLAUDE_CONFIG_DIR:-$HOME/.claude}/gsd-core/bin/lib, ${CODEX_HOME:-$HOME/.codex}/gsd-core/bin/lib. Reinstall: npx -y @opengsd/gsd-core@latest --claude --local" >&2; exit 1; fi
|
|
588
|
+
export GSD_LIB_DIR
|
|
589
|
+
# gsd-resolve-lib end
|
|
668
590
|
for SLUG in $(printf '%s' "$DISPATCH_SLUGS"); do
|
|
669
591
|
[ "$SLUG" = "coderabbit" ] && continue
|
|
670
592
|
REVIEW_FILE="$RUN_DIR/gsd-review-$SLUG.md"
|
|
671
593
|
[ -f "$REVIEW_FILE" ] || continue
|
|
672
594
|
[ -s "$REVIEW_FILE" ] || continue
|
|
673
|
-
grep -q "review
|
|
595
|
+
grep -q "review did not run: prompt exceeds" "$REVIEW_FILE" 2>/dev/null && continue
|
|
674
596
|
grep -q "failed or returned empty output" "$REVIEW_FILE" 2>/dev/null && continue
|
|
675
597
|
|
|
676
598
|
node -e '
|
|
677
599
|
const fs = require("fs");
|
|
678
|
-
const { escapeRegex } = require("
|
|
600
|
+
const { escapeRegex } = require(require("path").join(process.env.GSD_LIB_DIR, "pattern.cjs"));
|
|
679
601
|
const manifest = fs.readFileSync(process.argv[1], "utf8");
|
|
680
602
|
const review = fs.readFileSync(process.argv[2], "utf8");
|
|
681
603
|
const ids = manifest.split("\n")
|
|
@@ -693,7 +615,7 @@ done
|
|
|
693
615
|
|
|
694
616
|
Each `${RUN_DIR}/.plan-coverage-<slug>.json` carries `{complete, missing_ids, total}` for one
|
|
695
617
|
graded lane. Collect these into a `plan_coverage` frontmatter block — **only** when at least one
|
|
696
|
-
graded lane has `complete: false` (mirrors the
|
|
618
|
+
graded lane has `complete: false` (mirrors the `refused_reviewers` precedent: present
|
|
697
619
|
only when there is something to report):
|
|
698
620
|
|
|
699
621
|
```yaml
|
|
@@ -711,7 +633,7 @@ heading and before the end of the first exact `<!-- gsd:plan-revision-conflicts:
|
|
|
711
633
|
as `{preserved_plan_revision_conflict_entries}`. Ignore identical headings or delimiters in reviewer
|
|
712
634
|
output: reviewers do not own blocking state. Restore the captured bytes at the explicit slot below.
|
|
713
635
|
|
|
714
|
-
After all reviewers complete, collect
|
|
636
|
+
After all reviewers complete, collect the lanes that were refused for their prompt cap (#4559): each dispatched lane whose `${RUN_DIR}/gsd-review-lane-result-<slug>.json` has `"reason": "prompt_exceeds_context"`. For each, include a `refused_reviewers` entry in the frontmatter with `estimated_tokens`, `cap` and `cap_source` copied from that file's `refusal` object (`estimatedTokens`, `cap`, `capSource`). Omit the key entirely if no lane was refused. A refused lane's section in the body renders its `review did not run: prompt exceeds` stub, never an empty section.
|
|
715
637
|
|
|
716
638
|
**Reviewer instances (#1517, optional):** when instances ran, frontmatter records their
|
|
717
639
|
names, each gets its own `## <Adapter> Review (<instance>)` section, and ≥2 same-cli
|
|
@@ -743,16 +665,11 @@ models: # resolved model per reviewer; `unknown` when not reco
|
|
|
743
665
|
model_sources: # how each value above was determined
|
|
744
666
|
codex: "banner"
|
|
745
667
|
antigravity: "unknown"
|
|
746
|
-
|
|
668
|
+
refused_reviewers: # only present if at least one lane was refused for its prompt cap (#4559)
|
|
747
669
|
ollama:
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
omitted: [context, research]
|
|
752
|
-
project_md_shrunk: true
|
|
753
|
-
plan_truncation_pct: 22
|
|
754
|
-
hard_failed: false
|
|
755
|
-
note_injected: true
|
|
670
|
+
estimated_tokens: 61000
|
|
671
|
+
cap: 6000
|
|
672
|
+
cap_source: lane # lane | global | context-window
|
|
756
673
|
plan_coverage: # only present if at least one graded lane is incomplete (#3301)
|
|
757
674
|
ollama:
|
|
758
675
|
total: 7
|
|
@@ -816,7 +733,7 @@ present as complete. Report instead:
|
|
|
816
733
|
```
|
|
817
734
|
### GSD ► REVIEW FAILED
|
|
818
735
|
|
|
819
|
-
Phase {N}: every selected reviewer lane {failed to produce a result|
|
|
736
|
+
Phase {N}: every selected reviewer lane {failed to produce a result|refused its prompt cap} — no
|
|
820
737
|
REVIEWS.md was written.
|
|
821
738
|
|
|
822
739
|
{If the preserve+cleanup block below reports success: "Diagnostics preserved:
|
|
@@ -849,11 +766,9 @@ step names only `{padded_phase}-REVIEWS.md` explicitly, never a directory glob,
|
|
|
849
766
|
`.review-diagnostics/` is never swept into it.
|
|
850
767
|
|
|
851
768
|
**#4097: preserve lane OUTPUT, never the run's own input copies.** `RUN_DIR` holds not only
|
|
852
|
-
lane outputs — prompt assembly
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
requirements sections, and the per-lane trimmed prompts. Those are byte-identical duplicates of
|
|
856
|
-
files already committed under `.planning/`; sweeping them into `.review-diagnostics/` buries
|
|
769
|
+
lane outputs — prompt assembly also writes the run's assembled INPUT there under the same
|
|
770
|
+
`gsd-review-` prefix: the combined prompt (`gsd-review-prompt.md`). It duplicates files already
|
|
771
|
+
committed under `.planning/`; sweeping them into `.review-diagnostics/` buries
|
|
857
772
|
the actual evidence under plan duplicates and grows the phase directory on every run. The
|
|
858
773
|
exclusion list below is CLOSED and owned here: this workflow itself writes every input
|
|
859
774
|
basename at prompt-assembly time, so a future input file CANNOT silently join the evidence
|
|
@@ -879,8 +794,10 @@ DIAG_DIR="{phase_dir}/.review-diagnostics"
|
|
|
879
794
|
# the closed input set this workflow itself writes — direct glob iteration with a `case`
|
|
880
795
|
# filter, no string accumulator, identical under bash and zsh (#4099/#4109), and the
|
|
881
796
|
# `nullglob` set at the top of this fence keeps an empty RUN_DIR an empty array (#2962).
|
|
882
|
-
# `gsd-review-prompt*`
|
|
883
|
-
#
|
|
797
|
+
# `gsd-review-prompt*` is the one input file this workflow now writes (#4559 removed the
|
|
798
|
+
# per-lane trimmed prompts and the section copies). The section-copy names stay excluded:
|
|
799
|
+
# a run dir reused from an earlier GSD version can still hold them, and they are inputs,
|
|
800
|
+
# not lane evidence.
|
|
884
801
|
_DIAG_MD=()
|
|
885
802
|
for f in "$RUN_DIR"/gsd-review-*.md; do
|
|
886
803
|
case "$(basename "$f")" in
|
|
@@ -905,9 +822,8 @@ if [ ${#_DIAG_MD[@]} -gt 0 ] || [ ${#_DIAG_ERR[@]} -gt 0 ]; then
|
|
|
905
822
|
# unique per run BY CONSTRUCTION — uniqueness never depends on the clock. The
|
|
906
823
|
# UTC stamp is only a sort key in front of it, and is omitted entirely if `date`
|
|
907
824
|
# fails. Lane basenames are unchanged INSIDE the subdirectory, so evidence still
|
|
908
|
-
# correlates back to its lane, and nothing inside $RUN_DIR is renamed (
|
|
909
|
-
#
|
|
910
|
-
# on those exact basenames).
|
|
825
|
+
# correlates back to its lane, and nothing inside $RUN_DIR is renamed (the
|
|
826
|
+
# lane invocation resolver depends on those exact basenames).
|
|
911
827
|
_DIAG_STAMP="$(date -u +%Y%m%dT%H%M%SZ 2>/dev/null || true)"
|
|
912
828
|
_DIAG_RUN_DIR="$DIAG_DIR/${_DIAG_STAMP:+${_DIAG_STAMP}-}$(basename "$RUN_DIR")"
|
|
913
829
|
# `mkdir -p` still creates $DIAG_DIR itself, so a plain FILE sitting at
|
|
@@ -40,6 +40,11 @@
|
|
|
40
40
|
}
|
|
41
41
|
],
|
|
42
42
|
"complete-milestone": [
|
|
43
|
+
{
|
|
44
|
+
"id": "project-md-evolution-review",
|
|
45
|
+
"when": "state:flat-mode",
|
|
46
|
+
"read": "gsd-core/workflows/complete-milestone/steps/project-md-evolution-review.md"
|
|
47
|
+
},
|
|
43
48
|
{
|
|
44
49
|
"id": "git-tag",
|
|
45
50
|
"when": "state:git-create-tag",
|
|
@@ -181,7 +181,7 @@ gsd_run query commit "docs(phase-${PHASE}): add/update security threat verificat
|
|
|
181
181
|
GSD > PHASE {N} THREAT-SECURE
|
|
182
182
|
threats_open: 0 — no blocking threats remain (threats_open: 0).
|
|
183
183
|
▶ /gsd:validate-phase {N} validate test coverage
|
|
184
|
-
▶ /gsd:verify-work {N} run UAT
|
|
184
|
+
▶ /gsd:verify-work {N} run UAT; once UAT and verification pass it marks the phase complete (ROADMAP + STATE); if it refuses on stale verification, re-run /gsd:execute-phase {N} then verify again
|
|
185
185
|
```
|
|
186
186
|
|
|
187
187
|
Display `/clear` reminder.
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
Apply response_language to all user-facing prose — narration between tool calls, status updates, progress notes, and findings included; preserve code, paths, and identifiers.
|
|
2
2
|
|
|
3
3
|
<purpose>
|
|
4
|
-
Interactive configuration of GSD power-user knobs — plan bounce, planner stall detection, node
|
|
5
|
-
repair, subagent timeouts, inline plan threshold, cross-AI execution, base branch, branch templates, response language,
|
|
4
|
+
Interactive configuration of GSD power-user knobs — plan bounce, planner stall detection and timing, node repair, subagent timeouts, inline plan threshold, cross-AI execution, base branch, branch templates, response language,
|
|
6
5
|
context window, gitignored search, graphify build timeout, runtime model tier overrides, and
|
|
7
6
|
model policy configuration (provider + budget → canonical tier mapping, or manual model ID
|
|
8
7
|
assignment per cost tier).
|
|
@@ -50,6 +49,8 @@ shown in parentheses:
|
|
|
50
49
|
|
|
51
50
|
Planning Tuning:
|
|
52
51
|
- `planner.stall_detection_enabled` (default: `true`)
|
|
52
|
+
- `planner.stall_threshold_minutes` (default: `10`)
|
|
53
|
+
- `planner.stall_detect_interval_minutes` (default: `5`)
|
|
53
54
|
- `workflow.plan_bounce` (default: `false`)
|
|
54
55
|
- `workflow.plan_bounce_passes` (default: `2`)
|
|
55
56
|
- `workflow.plan_bounce_script` (default: `null`)
|
|
@@ -106,10 +107,10 @@ in `$ARGUMENTS` OR `text_mode` is true in config. When `TEXT_MODE=true`, replace
|
|
|
106
107
|
choice number or free-text value.
|
|
107
108
|
|
|
108
109
|
**Numeric-input validation.** For any numeric field (`*_passes`, `*_budget`, `*_timeout`,
|
|
109
|
-
`*_threshold`, `context_window`, `graphify.build_timeout`), if the user types a value that
|
|
110
|
+
`*_threshold`, `*_minutes`, `context_window`, `graphify.build_timeout`), if the user types a value that
|
|
110
111
|
is not a non-negative integer, the workflow MUST reject it, state which value was invalid,
|
|
111
112
|
and re-prompt that single field. The minimum accepted value is field-specific and is stated
|
|
112
|
-
in each field's prompt below — `
|
|
113
|
+
in each field's prompt below — the `*_passes` fields and the `planner.stall_*_minutes` fields
|
|
113
114
|
require `>= 1`; all other numeric fields accept `>= 0`. An empty input means "keep current"
|
|
114
115
|
— the existing value is retained. Non-numeric input is never silently coerced.
|
|
115
116
|
|
|
@@ -127,7 +128,9 @@ stored verbatim as a string.
|
|
|
127
128
|
|
|
128
129
|
### Section 1 — Planning Tuning
|
|
129
130
|
|
|
130
|
-
|
|
131
|
+
Asked as four calls, 1a–1d (`AskUserQuestion` takes at most 4 questions per call).
|
|
132
|
+
|
|
133
|
+
**1a — Planner watchdog.** Before offering the disabled choice, display this warning verbatim:
|
|
131
134
|
|
|
132
135
|
`Warning: disabling planner stall detection gives up bounded automatic recovery if the runtime loses an agent completion handoff. Planning still waits through the runtime-native completion mechanism, but you may need to interrupt and use the filesystem fallback.`
|
|
133
136
|
|
|
@@ -141,7 +144,40 @@ AskUserQuestion([
|
|
|
141
144
|
{ label: "Yes (default: true)", description: "Poll for completion markers and plan-file activity, with bounded recovery." },
|
|
142
145
|
{ label: "No (false)", description: "Await runtime-native completion without polling. Gives up bounded automatic recovery if completion handoff is lost." }
|
|
143
146
|
]
|
|
147
|
+
}
|
|
148
|
+
])
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
**1b — Stall timing.** Ask only when `planner.stall_detection_enabled` is effectively `true` after 1a (anything but boolean `false`); otherwise skip 1b.
|
|
152
|
+
`planner.stall_threshold_minutes`: idle time before plan-phase offers recovery; raise it for slow models. `planner.stall_detect_interval_minutes`: check cadence. Both integer `>= 1`.
|
|
153
|
+
|
|
154
|
+
```text
|
|
155
|
+
AskUserQuestion([
|
|
156
|
+
{
|
|
157
|
+
question: "Planner stall threshold (minutes)? (current: <value or 10>)",
|
|
158
|
+
header: "Stall Threshold",
|
|
159
|
+
multiSelect: false,
|
|
160
|
+
options: [
|
|
161
|
+
{ label: "Keep current", description: "Leave the threshold unchanged." },
|
|
162
|
+
{ label: "Enter minutes", description: "Integer >= 1. Default: 10." }
|
|
163
|
+
]
|
|
144
164
|
},
|
|
165
|
+
{
|
|
166
|
+
question: "Planner stall check interval (minutes)? (current: <value or 5>)",
|
|
167
|
+
header: "Stall Interval",
|
|
168
|
+
multiSelect: false,
|
|
169
|
+
options: [
|
|
170
|
+
{ label: "Keep current", description: "Leave the interval unchanged." },
|
|
171
|
+
{ label: "Enter minutes", description: "Integer >= 1. Default: 5." }
|
|
172
|
+
]
|
|
173
|
+
}
|
|
174
|
+
])
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
**1c — Plan bounce.**
|
|
178
|
+
|
|
179
|
+
```text
|
|
180
|
+
AskUserQuestion([
|
|
145
181
|
{
|
|
146
182
|
question: "Run external plan-bounce validator against generated PLAN.md? (current: <value or false>)",
|
|
147
183
|
header: "Plan Bounce",
|
|
@@ -169,7 +205,14 @@ AskUserQuestion([
|
|
|
169
205
|
{ label: "Clear (null)", description: "Unset the script path." },
|
|
170
206
|
{ label: "Enter path", description: "Type an absolute or repo-relative path. Receives PLAN.md path as first argument." }
|
|
171
207
|
]
|
|
172
|
-
}
|
|
208
|
+
}
|
|
209
|
+
])
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
**1d — Timeouts.**
|
|
213
|
+
|
|
214
|
+
```text
|
|
215
|
+
AskUserQuestion([
|
|
173
216
|
{
|
|
174
217
|
question: "Subagent timeout (milliseconds)? (current: <value or 300000>)",
|
|
175
218
|
header: "Subagent Timeout",
|
|
@@ -180,12 +223,12 @@ AskUserQuestion([
|
|
|
180
223
|
]
|
|
181
224
|
},
|
|
182
225
|
{
|
|
183
|
-
question: "Inline plan threshold — tasks
|
|
226
|
+
question: "Inline plan threshold — plans with this many tasks or fewer execute inline instead of spawning a subagent? (current: <value or 2>)",
|
|
184
227
|
header: "Inline Plan Threshold",
|
|
185
228
|
multiSelect: false,
|
|
186
229
|
options: [
|
|
187
230
|
{ label: "Keep current", description: "Leave threshold unchanged." },
|
|
188
|
-
{ label: "Enter number", description: "Integer
|
|
231
|
+
{ label: "Enter number", description: "Integer >= 0. Non-numeric rejected. Default: 2. Set 0 to always spawn a subagent." }
|
|
189
232
|
]
|
|
190
233
|
}
|
|
191
234
|
])
|
|
@@ -535,7 +578,9 @@ anything not listed in Sections 1–8 MUST survive the update):
|
|
|
535
578
|
...existing_config,
|
|
536
579
|
"planner": {
|
|
537
580
|
...existing_planner,
|
|
538
|
-
"stall_detection_enabled": <new|existing
|
|
581
|
+
"stall_detection_enabled": <new|existing>,
|
|
582
|
+
"stall_threshold_minutes": <new|existing>,
|
|
583
|
+
"stall_detect_interval_minutes": <new|existing>
|
|
539
584
|
},
|
|
540
585
|
"workflow": {
|
|
541
586
|
...existing_workflow,
|
|
@@ -772,6 +817,8 @@ Display:
|
|
|
772
817
|
| Setting | Value |
|
|
773
818
|
|--------------------------------------------|-------|
|
|
774
819
|
| planner.stall_detection_enabled | {true/false} |
|
|
820
|
+
| planner.stall_threshold_minutes | {minutes} |
|
|
821
|
+
| planner.stall_detect_interval_minutes | {minutes} |
|
|
775
822
|
| workflow.plan_bounce | {on/off} |
|
|
776
823
|
| workflow.plan_bounce_passes | {n} |
|
|
777
824
|
| workflow.plan_bounce_script | {path/null} |
|
|
@@ -826,6 +873,7 @@ UI/AI phase gates), use /gsd:settings.
|
|
|
826
873
|
- [ ] Eight sections rendered (Planning, Execution, Discussion, Cross-AI, Git, Runtime/Output, Runtime Model Tiers, Model Policy)
|
|
827
874
|
- [ ] Every field pre-selected to its current value (or documented default if absent)
|
|
828
875
|
- [ ] Disabling planner stall detection shows the bounded-recovery warning before writing `false`
|
|
876
|
+
- [ ] Stall threshold/interval asked only while stall detection is on; no call exceeds 4 questions
|
|
829
877
|
- [ ] Numeric inputs validated — non-numeric rejected and re-prompted
|
|
830
878
|
- [ ] Branch-template inputs validated — non-default must contain a placeholder
|
|
831
879
|
- [ ] Null-allowed fields accept an empty input as a clear
|
|
@@ -59,6 +59,7 @@ Parse current values (default to `true` if not present):
|
|
|
59
59
|
- `graphify.auto_update` — opt-in: auto-rebuild graph after main HEAD advances (#3347) (default: `false`)
|
|
60
60
|
- `model_profile` — which model each agent uses (default: `balanced`)
|
|
61
61
|
- `git.branching_strategy` — branching approach (default: `"none"`)
|
|
62
|
+
- `git.repo_tagging` — milestone tagging mode: `"single"` (one `v[X.Y]` tag, default) or `"per_repo"` (record a release map and tag each `planning.sub_repos` repository separately; set via `gsd_run query config-set git.repo_tagging per_repo`, #3628)
|
|
62
63
|
- `workflow.use_worktrees` — whether parallel executor agents run in worktree isolation (honored when the runtime declares a `dispatch.isolation` primitive — `harness-worktree` or `orchestrator-worktree`; runtimes declaring `none` default it to `false` and fail closed on an explicit `true` — #1521, #2486, #2584)
|
|
63
64
|
- `workflow.compact_content` — load token-minimized instruction variants where they exist, trading rarely-needed elaboration for a smaller always-loaded instruction window (default: false if absent; #4139)
|
|
64
65
|
- `model_policy.provider` — provider slug for model policy (default: `null`; known values: anthropic, openai, google, qwen; set via /gsd:config --advanced)
|