@opengsd/gsd-core 1.17.0 → 1.19.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-advisor-researcher.compact.md +1 -1
- package/agents/gsd-advisor-researcher.md +1 -1
- package/agents/gsd-assumptions-analyzer.compact.md +1 -1
- package/agents/gsd-assumptions-analyzer.md +1 -1
- package/agents/gsd-code-fixer.compact.md +3 -3
- package/agents/gsd-code-fixer.md +5 -4
- package/agents/gsd-code-reviewer.compact.md +1 -1
- package/agents/gsd-code-reviewer.md +1 -1
- package/agents/gsd-codebase-mapper.compact.md +1 -1
- package/agents/gsd-codebase-mapper.md +1 -1
- package/agents/gsd-debugger.md +1 -1
- package/agents/gsd-doc-verifier.compact.md +4 -4
- package/agents/gsd-doc-verifier.md +4 -3
- package/agents/gsd-doc-writer.compact.md +23 -5
- package/agents/gsd-doc-writer.md +19 -6
- package/agents/gsd-eval-auditor.compact.md +1 -1
- package/agents/gsd-eval-auditor.md +1 -1
- package/agents/gsd-executor.md +7 -3
- package/agents/gsd-integration-checker.compact.md +1 -1
- package/agents/gsd-integration-checker.md +1 -1
- package/agents/gsd-nyquist-auditor.compact.md +1 -1
- package/agents/gsd-nyquist-auditor.md +1 -1
- package/agents/gsd-phase-researcher.md +1 -1
- package/agents/gsd-plan-checker.md +2 -1
- package/agents/gsd-planner.md +5 -4
- package/agents/gsd-project-researcher.compact.md +1 -1
- package/agents/gsd-project-researcher.md +1 -1
- package/agents/gsd-research-synthesizer.compact.md +5 -5
- package/agents/gsd-research-synthesizer.md +5 -5
- package/agents/gsd-roadmapper.compact.md +1 -1
- package/agents/gsd-roadmapper.md +1 -1
- package/agents/gsd-security-auditor.compact.md +1 -1
- package/agents/gsd-security-auditor.md +1 -1
- package/agents/gsd-ui-auditor.compact.md +1 -1
- package/agents/gsd-ui-auditor.md +1 -1
- package/agents/gsd-ui-checker.compact.md +1 -1
- package/agents/gsd-ui-checker.md +1 -1
- package/agents/gsd-ui-researcher.compact.md +13 -1
- package/agents/gsd-ui-researcher.md +28 -1
- package/agents/gsd-verifier.md +2 -2
- package/bin/install.js +460 -105
- package/commands/gsd/code-review.md +8 -0
- package/commands/gsd/pause-work.md +1 -1
- package/gsd-core/bin/gsd-tools.cjs +124 -18
- 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-ledger.cjs +25 -0
- package/gsd-core/bin/lib/capability-lock.cjs +41 -8
- package/gsd-core/bin/lib/capability-registry.cjs +162 -74
- package/gsd-core/bin/lib/capability-source.cjs +3 -1
- package/gsd-core/bin/lib/capability-state.cjs +20 -11
- package/gsd-core/bin/lib/capability-validator.cjs +23 -4
- package/gsd-core/bin/lib/commands.cjs +5 -1
- 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 +34 -0
- package/gsd-core/bin/lib/decision-coverage-support.cjs +93 -0
- package/gsd-core/bin/lib/gate-context-drift.cjs +8 -3
- package/gsd-core/bin/lib/gate-decision-coverage-plan.cjs +21 -1
- package/gsd-core/bin/lib/gate-decision-coverage-verify.cjs +19 -1
- package/gsd-core/bin/lib/gate-evaluation-scope.cjs +134 -13
- package/gsd-core/bin/lib/gate-predicate-evaluator.cjs +23 -3
- package/gsd-core/bin/lib/gate-predicate.cjs +8 -12
- package/gsd-core/bin/lib/gate-tdd-review-checkpoint.cjs +114 -18
- package/gsd-core/bin/lib/gate-ui-safety.cjs +23 -5
- package/gsd-core/bin/lib/git-info-exclude.cjs +57 -0
- package/gsd-core/bin/lib/health-diagnostic-rules/phase-structure.cjs +18 -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 +76 -5
- package/gsd-core/bin/lib/install-effort-resolver.cjs +2 -2
- package/gsd-core/bin/lib/install-engine.cjs +246 -32
- package/gsd-core/bin/lib/install-model-override-resolver.cjs +4 -3
- package/gsd-core/bin/lib/install-profiles.cjs +14 -7
- package/gsd-core/bin/lib/installer-migration-report.cjs +2 -0
- package/gsd-core/bin/lib/markdown-line-diff.cjs +147 -0
- package/gsd-core/bin/lib/markdown-sectionizer.cjs +113 -0
- 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 +43 -1
- 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-id.cjs +21 -4
- package/gsd-core/bin/lib/phase-lifecycle.cjs +37 -4
- package/gsd-core/bin/lib/phase.cjs +235 -37
- package/gsd-core/bin/lib/planning-snapshot.cjs +3 -1
- package/gsd-core/bin/lib/planning-workspace.cjs +18 -0
- package/gsd-core/bin/lib/pristine-baseline.cjs +11 -3
- package/gsd-core/bin/lib/read-only-git-env.cjs +58 -0
- package/gsd-core/bin/lib/report-parser.cjs +57 -1
- package/gsd-core/bin/lib/review-lane-descriptor.cjs +35 -2
- package/gsd-core/bin/lib/review-lane-invocation.cjs +40 -0
- package/gsd-core/bin/lib/review-lane-runner.cjs +33 -4
- package/gsd-core/bin/lib/review-reviewer-selection.cjs +20 -1
- package/gsd-core/bin/lib/roadmap-parser.cjs +12 -0
- package/gsd-core/bin/lib/roadmap-upgrade.cjs +39 -2
- package/gsd-core/bin/lib/roadmap.cjs +89 -30
- package/gsd-core/bin/lib/runtime-artifact-conversion.cjs +428 -16
- package/gsd-core/bin/lib/runtime-artifact-layout.cjs +8 -4
- package/gsd-core/bin/lib/runtime-homes.cjs +18 -0
- package/gsd-core/bin/lib/runtime-hooks-surface.cjs +60 -16
- package/gsd-core/bin/lib/shell-command-projection.cjs +123 -16
- package/gsd-core/bin/lib/smart-entry.cjs +37 -16
- package/gsd-core/bin/lib/state-contract.cjs +29 -9
- package/gsd-core/bin/lib/state-document.cjs +47 -5
- package/gsd-core/bin/lib/state-transition.cjs +150 -34
- package/gsd-core/bin/lib/state.cjs +140 -88
- package/gsd-core/bin/lib/surface.cjs +9 -0
- package/gsd-core/bin/lib/task-command-router.cjs +7 -28
- package/gsd-core/bin/lib/task-content-resolution.cjs +46 -1
- package/gsd-core/bin/lib/tdd-red-evidence.cjs +5 -0
- package/gsd-core/bin/lib/tdd-test-files.cjs +42 -0
- package/gsd-core/bin/lib/verification.cjs +96 -9
- package/gsd-core/bin/lib/verify.cjs +38 -1
- 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/references/agent-contracts.md +1 -1
- package/gsd-core/references/agent-skills-bootstrap.md +26 -7
- package/gsd-core/references/git-integration.md +14 -3
- package/gsd-core/references/loop-hook-dispatch.md +13 -6
- package/gsd-core/references/planner-reversibility.md +18 -4
- package/gsd-core/references/planner-verify-command-grounding.md +18 -0
- package/gsd-core/references/planning-config.md +2 -0
- package/gsd-core/references/tdd.md +5 -4
- package/gsd-core/references/verifier-phase-gates.md +8 -1
- 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/add-backlog.md +10 -2
- package/gsd-core/workflows/add-phase.md +5 -1
- package/gsd-core/workflows/add-tests.md +5 -1
- package/gsd-core/workflows/add-todo.md +5 -1
- package/gsd-core/workflows/ai-integration-phase.md +5 -1
- package/gsd-core/workflows/audit-fix.md +2 -1
- package/gsd-core/workflows/audit-milestone.md +21 -9
- package/gsd-core/workflows/autonomous/templates/minimal-context.md +41 -0
- package/gsd-core/workflows/autonomous.md +52 -64
- package/gsd-core/workflows/check-todos.md +5 -1
- package/gsd-core/workflows/code-review/steps/structural-pre-pass.md +10 -1
- package/gsd-core/workflows/code-review-fix.md +5 -1
- package/gsd-core/workflows/code-review.md +66 -8
- package/gsd-core/workflows/complete-milestone/detail/elaboration.md +5 -1
- 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 +64 -157
- package/gsd-core/workflows/debug.md +5 -1
- package/gsd-core/workflows/diagnose-issues.md +34 -6
- package/gsd-core/workflows/discuss-phase/modes/chain.md +5 -1
- package/gsd-core/workflows/discuss-phase/modes/power.md +1 -1
- package/gsd-core/workflows/discuss-phase-assumptions.md +44 -5
- package/gsd-core/workflows/discuss-phase-power.md +19 -2
- package/gsd-core/workflows/discuss-phase.md +11 -11
- package/gsd-core/workflows/docs-update/detail/elaboration.md +7 -6
- package/gsd-core/workflows/docs-update.md +27 -5
- package/gsd-core/workflows/edit-phase.md +5 -1
- package/gsd-core/workflows/eval-review.md +11 -3
- package/gsd-core/workflows/execute-phase/steps/codebase-drift-gate.md +5 -1
- 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 +19 -8
- package/gsd-core/workflows/execute-phase/steps/regression-gate-run.md +21 -3
- package/gsd-core/workflows/execute-phase/steps/regression-gate.md +18 -1
- package/gsd-core/workflows/execute-phase/steps/verify-phase-goal.md +7 -3
- package/gsd-core/workflows/execute-phase/steps/wave-post-gate-hooks.md +11 -2
- package/gsd-core/workflows/execute-phase.md +46 -11
- package/gsd-core/workflows/execute-plan.md +8 -4
- package/gsd-core/workflows/extract-learnings.md +6 -2
- package/gsd-core/workflows/forensics.md +5 -1
- package/gsd-core/workflows/health.md +2 -1
- package/gsd-core/workflows/import.md +6 -2
- package/gsd-core/workflows/insert-phase.md +5 -1
- package/gsd-core/workflows/manager.md +10 -2
- package/gsd-core/workflows/map-codebase.md +5 -1
- package/gsd-core/workflows/milestone-summary.md +10 -2
- package/gsd-core/workflows/new-milestone.md +13 -5
- package/gsd-core/workflows/new-project.md +9 -5
- package/gsd-core/workflows/next.md +8 -4
- package/gsd-core/workflows/pause-work.md +3 -3
- package/gsd-core/workflows/plan-phase/steps/auto-advance-check.md +70 -0
- package/gsd-core/workflows/plan-phase/steps/chunked-planning-mode.md +7 -3
- package/gsd-core/workflows/plan-phase/steps/closed-phase-gate.md +6 -2
- package/gsd-core/workflows/plan-phase.md +54 -86
- package/gsd-core/workflows/plan-review-convergence.md +17 -5
- package/gsd-core/workflows/plant-seed.md +8 -4
- package/gsd-core/workflows/progress.md +6 -2
- 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-batch.md +5 -1
- package/gsd-core/workflows/quick.md +23 -8
- package/gsd-core/workflows/remove-phase.md +5 -1
- package/gsd-core/workflows/resume-project.md +5 -1
- package/gsd-core/workflows/review.md +22 -15
- package/gsd-core/workflows/scan.md +5 -1
- package/gsd-core/workflows/section-manifest.json +5 -0
- package/gsd-core/workflows/secure-phase.md +6 -2
- package/gsd-core/workflows/settings.md +4 -3
- package/gsd-core/workflows/ship.md +16 -14
- package/gsd-core/workflows/spec-phase.md +3 -6
- package/gsd-core/workflows/thread.md +10 -2
- package/gsd-core/workflows/transition.md +5 -1
- package/gsd-core/workflows/ui-phase.md +5 -1
- package/gsd-core/workflows/ui-review.md +6 -2
- package/gsd-core/workflows/ultraplan-phase.md +5 -1
- package/gsd-core/workflows/update.md +5 -1
- package/gsd-core/workflows/validate-phase.md +6 -2
- package/gsd-core/workflows/verify-work/detail/elaboration.md +1 -1
- package/gsd-core/workflows/verify-work/steps/mvp-uat-framing.md +5 -1
- package/gsd-core/workflows/verify-work.md +15 -6
- package/hooks/dist/gsd-agent-isolation-guard.js +14 -2
- package/hooks/dist/gsd-cursor-subagent-start.js +8 -3
- package/hooks/dist/gsd-path-export.js +95 -0
- package/hooks/dist/gsd-secret-read-guard.js +244 -53
- package/hooks/dist/gsd-statusline.js +35 -2
- package/hooks/dist/gsd-validate-commit.sh +27 -5
- package/hooks/dist/gsd-windsurf-pre-write.js +28 -1
- package/hooks/dist/gsd-workflow-guard.js +1 -1
- package/hooks/dist/gsd-worktree-path-guard.js +28 -1
- 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 +14 -2
- package/hooks/gsd-cursor-subagent-start.js +8 -3
- package/hooks/gsd-path-export.js +95 -0
- package/hooks/gsd-secret-read-guard.js +244 -53
- package/hooks/gsd-statusline.js +35 -2
- package/hooks/gsd-validate-commit.sh +27 -5
- package/hooks/gsd-windsurf-pre-write.js +28 -1
- package/hooks/gsd-workflow-guard.js +1 -1
- package/hooks/gsd-worktree-path-guard.js +28 -1
- package/hooks/hooks.json +1 -0
- package/hooks/lib/isolation-sentinel.js +44 -0
- package/hooks/managed-hooks-registry.cjs +1 -0
- package/package.json +13 -6
- 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 +769 -0
- package/pi/package-agents/gsd-code-reviewer.md +402 -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 +894 -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 +51 -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/audit-workflow-script-paths.cjs +1 -1
- package/scripts/build-hooks.js +4 -0
- package/scripts/command-contract-helpers.cjs +1 -1
- package/scripts/diagnose-windows-spawn-watcher.cjs +317 -0
- package/scripts/docs-guard-registry.cjs +22 -7
- package/scripts/gen-health-docs.cjs +13 -1
- package/scripts/gen-pi-package-skills.cjs +217 -0
- package/scripts/lib/macos-conformance-tier.generated.cjs +19 -0
- package/scripts/lib/platform-conformance-tier.generated.cjs +41 -0
- package/scripts/lint-docs-guard-registration.exempt-baseline.cjs +3 -3
- package/scripts/lint-phase-arg-assignment.cjs +2 -2
- package/scripts/lint-retired-runtime-name.cjs +5 -0
- package/scripts/lint-workflow-shellcheck-baseline.json +16 -16
- package/scripts/npm-audit-baseline.cjs +41 -7
- package/scripts/release-tarball-smoke.cjs +1 -0
- 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/skills/gsd-code-review/SKILL.md +8 -0
- package/skills/gsd-pause-work/SKILL.md +1 -1
- package/vscode/package.json +1 -1
|
@@ -48,6 +48,14 @@ Optional flags parsed from the `<arguments>` block:
|
|
|
48
48
|
- `--files=file1,file2,...` — Explicit file list override. Has highest precedence for file scoping per D-08. When provided, workflow skips SUMMARY.md extraction and git diff fallback entirely.
|
|
49
49
|
|
|
50
50
|
Context files (CLAUDE.md, SUMMARY.md, phase state) are resolved inside the workflow via `gsd-tools query init.phase-op` and delegated to agent via `<required_reading>` blocks.
|
|
51
|
+
|
|
52
|
+
## Outside a phase
|
|
53
|
+
|
|
54
|
+
Reviewer lanes run without a phase (`gsd_run` is defined by the runtime-launcher preamble inside workflow fences; in a plain shell call `node <install>/gsd-core/bin/gsd-tools.cjs` instead): pipe canonical repo-relative file paths (one per line) to stdin of
|
|
55
|
+
`gsd_run review-lane dispatch-step --repo-root <root> --depth <quick|standard|deep> --base-sha <sha> --run-dir "$(mktemp -d)" --cap-id code-review --point execute:post --explicit <slugs> --raw`.
|
|
56
|
+
`review-lane` flags are space-separated (`--depth quick`), never `--flag=value`. `--explicit` (omitted, nothing dispatches yet the call exits ok), `--depth`, `--base-sha` (lane reviews changes relative to it; commit them first) and stdin paths are required; `--run-dir` should be a fresh temp dir (default `.` writes the prompt file into the current directory); read each lane's output path (`results[].reviewPath`) from the JSON before removing it. `--cap-id`/`--point` select the `code-review` capability, which must be enabled (`workflow.code_review`) and active at `--point` — `execute:post`, or `execute:wave:post` when `workflow.code_review_point` selects it; otherwise nothing dispatches.
|
|
57
|
+
`--explicit` takes comma-separated canonical slugs, no spaces (`codex,antigravity`), not flag aliases (`antigravity`, not `agy`); slugs: first column of `gsd_run review-lane sections` (`review-lane flags` lists flags/aliases).
|
|
58
|
+
Each lane declares its own model key, which is not always its slug (antigravity's is `review.models.agy`); see the `review.models.*` table in `docs/CONFIGURATION.md`. Unset = lane default model.
|
|
51
59
|
</context>
|
|
52
60
|
|
|
53
61
|
<process>
|
|
@@ -21,7 +21,7 @@ Routes to the pause-work workflow which handles:
|
|
|
21
21
|
- Current phase detection from recent files
|
|
22
22
|
- Complete state gathering (position, completed work, remaining work, decisions, blockers)
|
|
23
23
|
- Handoff file creation with all context sections
|
|
24
|
-
- Git commit
|
|
24
|
+
- Git commit handoff
|
|
25
25
|
- Resume instructions
|
|
26
26
|
</objective>
|
|
27
27
|
|
|
@@ -85,6 +85,14 @@
|
|
|
85
85
|
* [--no-archive-phases] Skip moving phase dirs to milestones/vX.Y-phases/ (archived by default)
|
|
86
86
|
* [--archive-quick] Move .planning/quick/* dirs to milestones/vX.Y-quick/ + reset the
|
|
87
87
|
* Quick Tasks Completed table (#2142; opt-in, default OFF)
|
|
88
|
+
* [--release-map <file>] Archive a per-repository release map (JSON array of
|
|
89
|
+
* {repo, release, reference, environment, status, tag}) as
|
|
90
|
+
* milestones/vX.Y-RELEASE-MAP.json and record it in MILESTONES.md
|
|
91
|
+
* (#5706; validated before any write, absent = unchanged)
|
|
92
|
+
*
|
|
93
|
+
* milestone release-tags --map <file.json> [--dry-run]
|
|
94
|
+
* Preflight, then create annotated tags per sub-repo from a JSON array of
|
|
95
|
+
* {repo, tag, ref?, message?, skip?}; never pushes, never overwrites (#5705)
|
|
88
96
|
*
|
|
89
97
|
* milestone archive-quick <version> Move .planning/quick/* dirs to milestones/vX.Y-quick/ + reset the
|
|
90
98
|
* Quick Tasks Completed table, WITHOUT the milestone complete close-out
|
|
@@ -312,6 +320,7 @@ try {
|
|
|
312
320
|
} catch { /* advisory — never block */ }
|
|
313
321
|
|
|
314
322
|
const { resolveActiveWorkstream, applyResolvedWorkstreamEnv, peekActiveWorkstream } = require('./lib/active-workstream-store.cjs');
|
|
323
|
+
const { planningDir, planningRoot } = require('./lib/planning-workspace.cjs');
|
|
315
324
|
const state = require('./lib/state.cjs');
|
|
316
325
|
const phase = require('./lib/phase.cjs');
|
|
317
326
|
const roadmap = require('./lib/roadmap.cjs');
|
|
@@ -325,6 +334,7 @@ const config = require('./lib/config.cjs');
|
|
|
325
334
|
const estimateCli = require('./lib/estimate-cli.cjs');
|
|
326
335
|
const template = require('./lib/template.cjs');
|
|
327
336
|
const milestone = require('./lib/milestone.cjs');
|
|
337
|
+
const milestoneReleaseTags = require('./lib/milestone-release-tags.cjs');
|
|
328
338
|
const commands = require('./lib/commands.cjs');
|
|
329
339
|
const runtimeIdentity = require('./lib/runtime-identity.cjs');
|
|
330
340
|
const init = require('./lib/init.cjs');
|
|
@@ -847,7 +857,31 @@ function dispatchOverlayCapabilityCommand({ command, args, cwd, raw, error, load
|
|
|
847
857
|
error,
|
|
848
858
|
output: output,
|
|
849
859
|
});
|
|
850
|
-
if (
|
|
860
|
+
if (handled) return;
|
|
861
|
+
// #5268: this verb's flag surface is closed, as `todo complete`'s is
|
|
862
|
+
// (#4096). `--dry-run` is parsed and plumbed, and any OTHER flag fails loudly
|
|
863
|
+
// instead of being silently ignored: an accepted-but-ignored `--dry-run`
|
|
864
|
+
// wrote the config it was meant to preview. (`--raw` is spliced by the
|
|
865
|
+
// dispatcher before routing; it stays in the set as a guard against that
|
|
866
|
+
// splice ever moving.) The choices JSON is the one positional argument,
|
|
867
|
+
// wherever the flag sits, and a second one is refused for the same reason.
|
|
868
|
+
// A flag is a dash followed by a letter: `-1` is a (negative-number) JSON
|
|
869
|
+
// argument, refused below as choices that are not an object, not a flag.
|
|
870
|
+
const CONFIG_NEW_PROJECT_KNOWN_FLAGS = new Set(['--dry-run', '--raw']);
|
|
871
|
+
const positionals = [];
|
|
872
|
+
for (const a of args.slice(1)) {
|
|
873
|
+
if (typeof a === 'string' && /^--?[A-Za-z]/.test(a)) {
|
|
874
|
+
if (!CONFIG_NEW_PROJECT_KNOWN_FLAGS.has(a)) {
|
|
875
|
+
error(`Unknown flag for config-new-project: ${a}`, ERROR_REASON.USAGE);
|
|
876
|
+
}
|
|
877
|
+
continue;
|
|
878
|
+
}
|
|
879
|
+
positionals.push(a);
|
|
880
|
+
}
|
|
881
|
+
if (positionals.length > 1) {
|
|
882
|
+
error(`Unexpected argument for config-new-project: ${positionals[1]}. Usage: config-new-project [choices-json] [--dry-run]`, ERROR_REASON.USAGE);
|
|
883
|
+
}
|
|
884
|
+
config.cmdConfigNewProject(cwd, positionals[0], raw, { dryRun: args.includes('--dry-run') });
|
|
851
885
|
}
|
|
852
886
|
|
|
853
887
|
function routeConfigPath({ cwd, raw, workstreamContext }) {
|
|
@@ -1445,8 +1479,12 @@ function dispatchOverlayCapabilityCommand({ command, args, cwd, raw, error, load
|
|
|
1445
1479
|
// Silent no-op when the section is absent or the table is already canonical
|
|
1446
1480
|
// — the quick/fast workflows call this before their first append, so the
|
|
1447
1481
|
// migration runs exactly once, on the first quick run, unprompted otherwise.
|
|
1448
|
-
const
|
|
1482
|
+
const planningPath = planningDir(cwd);
|
|
1483
|
+
const statePath = path.join(planningPath, 'STATE.md');
|
|
1449
1484
|
if (!fs.existsSync(statePath)) {
|
|
1485
|
+
if (planningPath !== planningRoot(cwd)) {
|
|
1486
|
+
throw new ExitError(1, `quick-tasks-migrate: STATE.md not found at ${statePath}`);
|
|
1487
|
+
}
|
|
1450
1488
|
output({ ok: true, migrated: false, reason: `STATE.md not found at ${statePath}` }, raw);
|
|
1451
1489
|
return;
|
|
1452
1490
|
}
|
|
@@ -1519,7 +1557,7 @@ function dispatchOverlayCapabilityCommand({ command, args, cwd, raw, error, load
|
|
|
1519
1557
|
|| (qtaQuickId && qtaSlug ? `[${qtaQuickId}-${qtaSlug}](./quick/${qtaQuickId}-${qtaSlug}/)` : undefined);
|
|
1520
1558
|
const qtaStatus = qtaParsed['status'] || undefined;
|
|
1521
1559
|
|
|
1522
|
-
const statePath = path.join(cwd, '
|
|
1560
|
+
const statePath = path.join(planningDir(cwd), 'STATE.md');
|
|
1523
1561
|
if (!fs.existsSync(statePath)) {
|
|
1524
1562
|
error(`quick-tasks-append: STATE.md not found at ${statePath}`, ERROR_REASON.USAGE);
|
|
1525
1563
|
}
|
|
@@ -1593,7 +1631,7 @@ function dispatchOverlayCapabilityCommand({ command, args, cwd, raw, error, load
|
|
|
1593
1631
|
const fsx = require('node:fs');
|
|
1594
1632
|
const os = require('node:os');
|
|
1595
1633
|
const { REVIEWER_LANES, mergeReviewerLanes } = require('./lib/review-lane-descriptor.cjs');
|
|
1596
|
-
const { resolveLanePlan: resolveLanePlanBase, resolveLaneEffort, resolveLaneBudget } = require('./lib/review-lane-invocation.cjs');
|
|
1634
|
+
const { resolveLanePlan: resolveLanePlanBase, resolveLaneEffort, resolveLaneBudget, applyPromptOverride } = require('./lib/review-lane-invocation.cjs');
|
|
1597
1635
|
// OpenCode 2.x argv differs from 1.x (no --variant; effort rides on the model as `#variant`;
|
|
1598
1636
|
// ADR-5331 D5/D8). The generation is probed lazily, only when the opencode lane is resolved.
|
|
1599
1637
|
const resolveLanePlan = (laneInput) => {
|
|
@@ -1627,8 +1665,9 @@ function dispatchOverlayCapabilityCommand({ command, args, cwd, raw, error, load
|
|
|
1627
1665
|
// `plan`/`invoke` are the only subs that need the expensive plan-building path
|
|
1628
1666
|
// below; `sections`/`flags` return earlier still. Anything else errors here, before
|
|
1629
1667
|
// any of that work starts.
|
|
1630
|
-
|
|
1631
|
-
|
|
1668
|
+
const REVIEW_LANE_USAGE = 'Usage: review-lane <plan|invoke|sections|flags|availability|dispatch-step|explicit-from-argv> [--selected a,b] [--run-dir D] [--repo-root R]';
|
|
1669
|
+
if (!['plan', 'invoke', 'sections', 'flags', 'availability', 'dispatch-step', 'explicit-from-argv'].includes(sub)) {
|
|
1670
|
+
error(REVIEW_LANE_USAGE);
|
|
1632
1671
|
return;
|
|
1633
1672
|
}
|
|
1634
1673
|
const runDir = flag('--run-dir') || '.';
|
|
@@ -1704,8 +1743,34 @@ function dispatchOverlayCapabilityCommand({ command, args, cwd, raw, error, load
|
|
|
1704
1743
|
method: opts.method,
|
|
1705
1744
|
headers: opts.body ? { 'Content-Type': 'application/json' } : undefined,
|
|
1706
1745
|
body: opts.body,
|
|
1746
|
+
// Never follow a redirect: the egress check compares the CONFIGURED host, so a
|
|
1747
|
+
// followed redirect would send the review prompt to a host the user never named (#5433).
|
|
1748
|
+
redirect: 'manual',
|
|
1707
1749
|
signal: AbortSignal.timeout(opts.timeoutMs),
|
|
1708
1750
|
});
|
|
1751
|
+
// probe:true marks a reachability probe (returns status only, body ''): the status line is the answer, so do not
|
|
1752
|
+
// let a stalled body turn a replying server into `missing`.
|
|
1753
|
+
if (opts.probe) {
|
|
1754
|
+
res.body?.cancel().catch(() => {});
|
|
1755
|
+
return { ok: res.ok, status: res.status, body: '' };
|
|
1756
|
+
}
|
|
1757
|
+
if (res.status >= 300 && res.status < 400) {
|
|
1758
|
+
res.body?.cancel().catch(() => {});
|
|
1759
|
+
const location = res.headers.get('location');
|
|
1760
|
+
let target = 'without a Location header';
|
|
1761
|
+
if (location) {
|
|
1762
|
+
target = 'to an unparseable Location';
|
|
1763
|
+
try { target = `to ${new URL(location, url).host}`; } catch { /* keep the unparseable wording */ }
|
|
1764
|
+
}
|
|
1765
|
+
// Host and path only: a configured URL may carry credentials that must not reach a review file.
|
|
1766
|
+
const asked = (() => { try { const u = new URL(url); return `${u.host}${u.pathname}`; } catch { return 'the configured URL'; } })();
|
|
1767
|
+
return {
|
|
1768
|
+
ok: false,
|
|
1769
|
+
status: res.status,
|
|
1770
|
+
body: '',
|
|
1771
|
+
error: `${asked} answered HTTP ${res.status}, redirecting ${target}. The lane does not follow redirects; configure the final URL as the lane's host.`,
|
|
1772
|
+
};
|
|
1773
|
+
}
|
|
1709
1774
|
return { ok: res.ok, status: res.status, body: await res.text() };
|
|
1710
1775
|
} catch (e) {
|
|
1711
1776
|
return { ok: false, status: 0, body: '', error: e && e.message ? e.message : String(e) };
|
|
@@ -1732,6 +1797,23 @@ function dispatchOverlayCapabilityCommand({ command, args, cwd, raw, error, load
|
|
|
1732
1797
|
|
|
1733
1798
|
const selected = (flag('--selected') || '')
|
|
1734
1799
|
.split(',').map((s) => s.trim()).filter(Boolean);
|
|
1800
|
+
// #5266: `<slug>:available|missing` per openai-http lane. Host + default come from the lane
|
|
1801
|
+
// descriptor (resolveLanePlan), probing is runner.probeLane — review.md keeps no host table.
|
|
1802
|
+
// Prerequisite binaries (jq) are reported separately by the workflow, not folded in here.
|
|
1803
|
+
// First-party lanes only: ADR-2782 D5 requires egress/consent before a third-party lane's host is
|
|
1804
|
+
// contacted; detection has no such check, so installed third-party lanes are never probed here.
|
|
1805
|
+
if (sub === 'availability') {
|
|
1806
|
+
const { rows, warnings } = await runner.probeHttpLanes(
|
|
1807
|
+
REVIEWER_LANES,
|
|
1808
|
+
selected,
|
|
1809
|
+
(lane) => resolveLanePlan({ lane, configGet, runDir, repoRoot }),
|
|
1810
|
+
buildLaneRunnerDeps(),
|
|
1811
|
+
);
|
|
1812
|
+
for (const w of warnings) process.stderr.write(`review-lane availability: ${w}\n`);
|
|
1813
|
+
process.stdout.write(rows.join('\n') + (rows.length ? '\n' : ''));
|
|
1814
|
+
return;
|
|
1815
|
+
}
|
|
1816
|
+
|
|
1735
1817
|
// ADR-2782 D8 (#2927): the lane map is first-party ∪ INSTALLED overlay
|
|
1736
1818
|
// `reviewer` bodies, first-party winning on slug collision. Before this merge
|
|
1737
1819
|
// the map was built from the frozen REVIEWER_LANES array alone, so an installed,
|
|
@@ -1945,7 +2027,7 @@ function dispatchOverlayCapabilityCommand({ command, args, cwd, raw, error, load
|
|
|
1945
2027
|
const dispatchResult = await dispatchReviewerLanes(
|
|
1946
2028
|
{
|
|
1947
2029
|
trait,
|
|
1948
|
-
selection: { explicitFlags, detected: rosterSlugs },
|
|
2030
|
+
selection: { explicitFlags, detected: rosterSlugs, lanes: mergedLanes },
|
|
1949
2031
|
repoRoot,
|
|
1950
2032
|
paths,
|
|
1951
2033
|
depth,
|
|
@@ -1996,7 +2078,7 @@ function dispatchOverlayCapabilityCommand({ command, args, cwd, raw, error, load
|
|
|
1996
2078
|
}
|
|
1997
2079
|
|
|
1998
2080
|
if (sub !== 'invoke') {
|
|
1999
|
-
error(
|
|
2081
|
+
error(REVIEW_LANE_USAGE);
|
|
2000
2082
|
return;
|
|
2001
2083
|
}
|
|
2002
2084
|
|
|
@@ -2097,14 +2179,11 @@ function dispatchOverlayCapabilityCommand({ command, args, cwd, raw, error, load
|
|
|
2097
2179
|
}
|
|
2098
2180
|
|
|
2099
2181
|
// `--prompt-file` lets the caller substitute a budget-trimmed prompt. Applied to whichever
|
|
2100
|
-
// channel this lane actually reads from,
|
|
2182
|
+
// channel this lane actually reads from (stdin, argv, an argv-embedded file reference, or the
|
|
2183
|
+
// http promptPath), so one flag serves every lane (#5049).
|
|
2101
2184
|
const promptOverride = flag('--prompt-file');
|
|
2102
2185
|
if (promptOverride) {
|
|
2103
|
-
|
|
2104
|
-
if (entry.plan.stdin) entry.plan.stdin = promptOverride;
|
|
2105
|
-
} else {
|
|
2106
|
-
entry.plan.promptPath = promptOverride;
|
|
2107
|
-
}
|
|
2186
|
+
entry.plan = applyPromptOverride(entry.plan, promptOverride, repoRoot);
|
|
2108
2187
|
}
|
|
2109
2188
|
|
|
2110
2189
|
// ADR-2782 D5 rule 4: re-resolve the consented destination at INVOCATION. `undefined` (no
|
|
@@ -2139,6 +2218,13 @@ function dispatchOverlayCapabilityCommand({ command, args, cwd, raw, error, load
|
|
|
2139
2218
|
testCommandNormalizer.cmdNormalizeTestCommand(cwd, args[1]);
|
|
2140
2219
|
}
|
|
2141
2220
|
|
|
2221
|
+
function routeResolvePackageManager({ args, cwd }) {
|
|
2222
|
+
// #5346: the gates' no-configured-command fallback asks here for the
|
|
2223
|
+
// project's package manager (packageManager field, then lockfile, else npm).
|
|
2224
|
+
// args[1] is the script name; --cwd (already parsed into `cwd`) locates package.json.
|
|
2225
|
+
require('./lib/normalize-test-command.cjs').cmdResolvePackageManager(cwd, args[1]);
|
|
2226
|
+
}
|
|
2227
|
+
|
|
2142
2228
|
function routeDispatchShouldFlatten({ args, cwd, raw, error }) {
|
|
2143
2229
|
// #1708 / #853: typed query replacing the `RUNTIME === 'codex'` prose rule.
|
|
2144
2230
|
//
|
|
@@ -3022,7 +3108,12 @@ function dispatchOverlayCapabilityCommand({ command, args, cwd, raw, error, load
|
|
|
3022
3108
|
const jsonIdx = args.indexOf('--json');
|
|
3023
3109
|
const agentSkillsJsonMode = jsonIdx !== -1;
|
|
3024
3110
|
if (agentSkillsJsonMode) args.splice(jsonIdx, 1);
|
|
3025
|
-
|
|
3111
|
+
// #5122: the agent's own self-load asks for configured skills only,
|
|
3112
|
+
// never the persona fallback served to orchestrator-side injection.
|
|
3113
|
+
const skillsOnlyIdx = args.indexOf('--skills-only');
|
|
3114
|
+
const agentSkillsOnly = skillsOnlyIdx !== -1;
|
|
3115
|
+
if (agentSkillsOnly) args.splice(skillsOnlyIdx, 1);
|
|
3116
|
+
init.cmdAgentSkills(cwd, args[1], raw, agentSkillsJsonMode, agentSkillsOnly);
|
|
3026
3117
|
}
|
|
3027
3118
|
|
|
3028
3119
|
function routeSkillManifest({ args, cwd, raw, error }) {
|
|
@@ -3135,7 +3226,18 @@ function dispatchOverlayCapabilityCommand({ command, args, cwd, raw, error, load
|
|
|
3135
3226
|
// --dry-run) the command refuses before touching anything. Distinct
|
|
3136
3227
|
// from --force, which bypasses the narrow scope guards only.
|
|
3137
3228
|
const confirm = args.includes('--confirm');
|
|
3138
|
-
|
|
3229
|
+
// #5706 (epic #3628): optional caller-supplied release map file.
|
|
3230
|
+
// A flag with no usable value fails loud rather than being dropped.
|
|
3231
|
+
let releaseMap = null;
|
|
3232
|
+
const releaseMapIdx = args.indexOf('--release-map');
|
|
3233
|
+
if (releaseMapIdx !== -1) {
|
|
3234
|
+
const releaseMapValue = args[releaseMapIdx + 1];
|
|
3235
|
+
if (typeof releaseMapValue !== 'string' || releaseMapValue.startsWith('--') || releaseMapValue.trim() === '') {
|
|
3236
|
+
error('--release-map requires a file path (a JSON array of release-map entries)');
|
|
3237
|
+
}
|
|
3238
|
+
releaseMap = releaseMapValue;
|
|
3239
|
+
}
|
|
3240
|
+
milestone.cmdMilestoneComplete(cwd, args[2], { name: milestoneName, archivePhases, force, dryRun, archiveQuick, confirm, releaseMap }, raw);
|
|
3139
3241
|
} else if (subcommand === 'archive-quick') {
|
|
3140
3242
|
// #2142 escalation: narrow archival-only entry point (does NOT
|
|
3141
3243
|
// touch ROADMAP/REQUIREMENTS/MILESTONES.md, runs no completion
|
|
@@ -3143,8 +3245,11 @@ function dispatchOverlayCapabilityCommand({ command, args, cwd, raw, error, load
|
|
|
3143
3245
|
// unlike `milestone complete --archive-quick`.
|
|
3144
3246
|
const dryRun = args.includes('--dry-run');
|
|
3145
3247
|
milestone.cmdQuickArchive(cwd, args[2], { dryRun }, raw);
|
|
3248
|
+
} else if (subcommand === 'release-tags') {
|
|
3249
|
+
// #5705 (epic #3628 Phase 1): repository-scoped annotated release tags.
|
|
3250
|
+
milestoneReleaseTags.cmdMilestoneReleaseTags(cwd, args, raw);
|
|
3146
3251
|
} else {
|
|
3147
|
-
error('Unknown milestone subcommand. Available: complete, archive-quick', ERROR_REASON.SDK_UNKNOWN_COMMAND);
|
|
3252
|
+
error('Unknown milestone subcommand. Available: complete, archive-quick, release-tags', ERROR_REASON.SDK_UNKNOWN_COMMAND);
|
|
3148
3253
|
}
|
|
3149
3254
|
}
|
|
3150
3255
|
|
|
@@ -4802,6 +4907,7 @@ const HOST_COMMAND_ROUTERS = {
|
|
|
4802
4907
|
// #3676 (Phase 4, epic #3344): quick-batch coordination verbs.
|
|
4803
4908
|
'quick-batch': routeQuickBatchCommand,
|
|
4804
4909
|
'normalize-test-command': routeNormalizeTestCommand,
|
|
4910
|
+
'resolve-package-manager': routeResolvePackageManager,
|
|
4805
4911
|
'dispatch-should-flatten': routeDispatchShouldFlatten,
|
|
4806
4912
|
'dispatch-isolation': routeDispatchIsolation,
|
|
4807
4913
|
'dispatch-capacity': routeDispatchCapacity,
|
|
@@ -5107,7 +5213,7 @@ function runWithTimeout(argv) {
|
|
|
5107
5213
|
// drifting apart when a query command was added to only one or two.
|
|
5108
5214
|
const TOP_LEVEL_USAGE = 'Usage: gsd-tools <command> [args] [--raw] [--pick <field>] [--cwd <path>] [--project-dir <path>] [--ws <name>] [--json-errors] [--exit-contract=<v>]\n' +
|
|
5109
5215
|
'Commands: agent, agent-skills, assumption-delta, audit-open, audit-uat, check, check-commit, commit, commit-docs-guard, commit-to-subrepo, pr-subrepo, ' +
|
|
5110
|
-
'config-ensure-section, config-get, config-new-project, config-path, config-set, migrate-config, normalize-test-command, ' +
|
|
5216
|
+
'config-ensure-section, config-get, config-new-project, config-path, config-set, migrate-config, normalize-test-command, resolve-package-manager, ' +
|
|
5111
5217
|
'context-predicates, current-timestamp, detect-custom-files, docs-init, drift-guard, effort, extract-messages, find-phase, ' +
|
|
5112
5218
|
'from-gsd2, frontmatter, gap-analysis, generate-claude-md, generate-claude-profile, ' +
|
|
5113
5219
|
'generate-dev-preferences, generate-slug, graphify, history-digest, init, intel, ' +
|
|
@@ -328,8 +328,33 @@ function checkCodexModelPosture(runtime, projectRoot) {
|
|
|
328
328
|
// derives its sandbox_mode from actually lives, in every install shape
|
|
329
329
|
// (repo-dev tree or npm-global package, where the package still ships its
|
|
330
330
|
// own agents/ alongside bin/ and gsd-core/).
|
|
331
|
-
|
|
332
|
-
|
|
331
|
+
//
|
|
332
|
+
// #5496: "install-relative" has three shapes. This module compiles to
|
|
333
|
+
// `<root>/gsd-core/bin/lib/`, so `<root>` is three parents up. In the repository
|
|
334
|
+
// and the npm package the canonical sources are `<root>/agents`. In an INSTALLED
|
|
335
|
+
// config dir `<root>/agents` holds the CONVERTED runtime copies (no `tools:`
|
|
336
|
+
// declaration — every role then derived `read-only`, 26 false violations on a
|
|
337
|
+
// clean Codex install) and the canonical sources are `<root>/gsd-core/agents`.
|
|
338
|
+
// Prefer the nested directory when it actually holds agent sources; fall back to
|
|
339
|
+
// `<root>/agents`. `root` is a parameter so each layout is testable.
|
|
340
|
+
//
|
|
341
|
+
// #5636: "holds agent sources" is a recognized agent file, `gsd-<name>.md` (every file in the shipped
|
|
342
|
+
// roster) that is not a `.compact.md` variant. Any markdown would let a stray README in the nested
|
|
343
|
+
// directory hide the real sources, so the posture check found no role's canonical file and skipped all.
|
|
344
|
+
const CANONICAL_AGENT_SOURCE_FILE = /^gsd-.+\.md$/;
|
|
345
|
+
function isCanonicalAgentSourceFile(entry) {
|
|
346
|
+
return CANONICAL_AGENT_SOURCE_FILE.test(entry) && !entry.endsWith('.compact.md');
|
|
347
|
+
}
|
|
348
|
+
function canonicalAgentSourceDir(root = node_path_1.default.join(__dirname, '..', '..', '..')) {
|
|
349
|
+
const nested = node_path_1.default.join(root, 'gsd-core', 'agents');
|
|
350
|
+
try {
|
|
351
|
+
if (node_fs_1.default.readdirSync(nested).some(isCanonicalAgentSourceFile))
|
|
352
|
+
return nested;
|
|
353
|
+
}
|
|
354
|
+
catch {
|
|
355
|
+
// Absent or unreadable: not this layout.
|
|
356
|
+
}
|
|
357
|
+
return node_path_1.default.join(root, 'agents');
|
|
333
358
|
}
|
|
334
359
|
/**
|
|
335
360
|
* Validate installed Codex `.toml` agents' `sandbox_mode` against what each
|
|
@@ -384,7 +409,7 @@ function checkCodexSandboxPosture(runtime, projectRoot) {
|
|
|
384
409
|
reason: POSTURE_REASON.AGENTS_DIR_MISSING,
|
|
385
410
|
};
|
|
386
411
|
}
|
|
387
|
-
const canonicalAgentsDir =
|
|
412
|
+
const canonicalAgentsDir = canonicalAgentSourceDir();
|
|
388
413
|
// Same symlink guard as checkCodexModelPosture, same reason (never follow
|
|
389
414
|
// an agents-dir symlink into an arbitrary file's content).
|
|
390
415
|
const tomlFiles = node_fs_1.default
|
|
@@ -533,6 +558,7 @@ module.exports = {
|
|
|
533
558
|
checkAgentsInstalled,
|
|
534
559
|
checkCodexModelPosture,
|
|
535
560
|
checkCodexSandboxPosture,
|
|
561
|
+
canonicalAgentSourceDir,
|
|
536
562
|
POSTURE_REASON,
|
|
537
563
|
resolveAgentHint,
|
|
538
564
|
};
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Per-install terminators for the typed-text capture heredocs (#5637).
|
|
4
|
+
*
|
|
5
|
+
* Every workflow that reads the typed text opens with
|
|
6
|
+
*
|
|
7
|
+
* IFS= read -rd '' GSD_ARGS <<'GSD_ARGS_END' || true
|
|
8
|
+
* $ARGUMENTS
|
|
9
|
+
* GSD_ARGS_END
|
|
10
|
+
*
|
|
11
|
+
* and `/gsd-quick-batch` feeds `parse-args` through the same shape with `GSD_QUICK_BATCH_ARGS_END`.
|
|
12
|
+
* The harness replaces `$ARGUMENTS` with the typed text before the shell parses the fence, so typed
|
|
13
|
+
* text with a terminator line of its own closes the heredoc early and the lines after it run as
|
|
14
|
+
* shell. A literal in a shipped file cannot be made unforgeable, so each install replaces it with
|
|
15
|
+
* `<TERMINATOR>_<nonce>`, a nonce the typed text has no way to know. The shipped source keeps the
|
|
16
|
+
* canonical tokens; only the files an install writes carry the nonce.
|
|
17
|
+
*/
|
|
18
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
19
|
+
exports.ARGS_NONCE_RE = exports.ARGS_TERMINATOR = exports.ARGS_TERMINATORS = void 0;
|
|
20
|
+
exports.generateArgsNonce = generateArgsNonce;
|
|
21
|
+
exports.stampArgsTerminator = stampArgsTerminator;
|
|
22
|
+
exports.readInstalledNonce = readInstalledNonce;
|
|
23
|
+
exports.armArgsNonce = armArgsNonce;
|
|
24
|
+
exports.disarmArgsNonce = disarmArgsNonce;
|
|
25
|
+
exports.stampInstalledContent = stampInstalledContent;
|
|
26
|
+
const node_crypto_1 = require("node:crypto");
|
|
27
|
+
const node_fs_1 = require("node:fs");
|
|
28
|
+
const node_path_1 = require("node:path");
|
|
29
|
+
/** The canonical terminators the shipped workflows and commands carry. */
|
|
30
|
+
exports.ARGS_TERMINATORS = Object.freeze(['GSD_ARGS_END', 'GSD_QUICK_BATCH_ARGS_END']);
|
|
31
|
+
/** The terminator every workflow carries. */
|
|
32
|
+
exports.ARGS_TERMINATOR = 'GSD_ARGS_END';
|
|
33
|
+
/** A nonce is 128 random bits as 32 lowercase hex characters. */
|
|
34
|
+
exports.ARGS_NONCE_RE = /^[0-9a-f]{32}$/;
|
|
35
|
+
const OPENER_RE = new RegExp(`<<'(${exports.ARGS_TERMINATORS.join('|')})'`, 'g');
|
|
36
|
+
const CLOSER_RE = new RegExp(`^(${exports.ARGS_TERMINATORS.join('|')})(?=\\r?$)`, 'gm');
|
|
37
|
+
/** A fresh nonce. `randomBytes` is a seam for tests. */
|
|
38
|
+
function generateArgsNonce(randomBytes = node_crypto_1.randomBytes) {
|
|
39
|
+
return randomBytes(16).toString('hex');
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* `content` with each canonical terminator replaced by the stamped one: the heredoc opener tag and
|
|
43
|
+
* the closing line. A terminator that is already stamped does not match and is left alone, and so
|
|
44
|
+
* is prose that names a token inside a line.
|
|
45
|
+
*
|
|
46
|
+
* @throws {TypeError} when `nonce` is not 32 lowercase hex characters
|
|
47
|
+
*/
|
|
48
|
+
function stampArgsTerminator(content, nonce) {
|
|
49
|
+
if (typeof nonce !== 'string' || !exports.ARGS_NONCE_RE.test(nonce)) {
|
|
50
|
+
throw new TypeError('stampArgsTerminator: nonce must be 32 lowercase hex characters');
|
|
51
|
+
}
|
|
52
|
+
return content
|
|
53
|
+
.replace(OPENER_RE, (_m, token) => `<<'${token}_${nonce}'`)
|
|
54
|
+
.replace(CLOSER_RE, (_m, token) => `${token}_${nonce}`);
|
|
55
|
+
}
|
|
56
|
+
let armedNonce = null;
|
|
57
|
+
const INSTALLED_NONCE_RE = /^GSD_ARGS_END_([0-9a-f]{32})\r?$/m;
|
|
58
|
+
/** A workflow is tens of KiB; anything near this is not one, and is not read. */
|
|
59
|
+
const MAX_WORKFLOW_BYTES = 2 * 1024 * 1024;
|
|
60
|
+
/**
|
|
61
|
+
* The nonce a previous install left in `configDir`, read from the first installed workflow that
|
|
62
|
+
* carries one; null when there is none. Entries that are not regular files (a directory, a FIFO,
|
|
63
|
+
* a symlink) and files over MAX_WORKFLOW_BYTES are skipped, and one unreadable entry does not end
|
|
64
|
+
* the scan.
|
|
65
|
+
*/
|
|
66
|
+
function readInstalledNonce(configDir) {
|
|
67
|
+
let dir;
|
|
68
|
+
let names;
|
|
69
|
+
try {
|
|
70
|
+
dir = (0, node_path_1.join)(configDir, 'gsd-core', 'workflows');
|
|
71
|
+
names = (0, node_fs_1.readdirSync)(dir).sort();
|
|
72
|
+
}
|
|
73
|
+
catch {
|
|
74
|
+
return null;
|
|
75
|
+
}
|
|
76
|
+
for (const name of names) {
|
|
77
|
+
if (!name.endsWith('.md'))
|
|
78
|
+
continue;
|
|
79
|
+
try {
|
|
80
|
+
const full = (0, node_path_1.join)(dir, name);
|
|
81
|
+
const stat = (0, node_fs_1.lstatSync)(full);
|
|
82
|
+
if (!stat.isFile() || stat.size > MAX_WORKFLOW_BYTES)
|
|
83
|
+
continue;
|
|
84
|
+
const match = INSTALLED_NONCE_RE.exec((0, node_fs_1.readFileSync)(full, 'utf8'));
|
|
85
|
+
if (match)
|
|
86
|
+
return match[1];
|
|
87
|
+
}
|
|
88
|
+
catch {
|
|
89
|
+
// This entry is unreadable; the next one may still carry the nonce.
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
return null;
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Arm stamping for the install into `configDir`, before it writes anything. When `reuse` is true
|
|
96
|
+
* the directory's installed nonce is kept, so a reinstall changes nothing; otherwise, or when
|
|
97
|
+
* there is none, a fresh one is minted. Only a global install (a directory under the user's home,
|
|
98
|
+
* which a cloned repository cannot seed) may reuse: a project-local directory is often committed,
|
|
99
|
+
* and a nonce planted there would be adopted. Generators never arm it, so the committed generated
|
|
100
|
+
* skills stay canonical and deterministic.
|
|
101
|
+
*/
|
|
102
|
+
function armArgsNonce(configDir, reuse = false) {
|
|
103
|
+
const prior = reuse && configDir !== undefined ? readInstalledNonce(configDir) : null;
|
|
104
|
+
armedNonce = prior ?? generateArgsNonce();
|
|
105
|
+
return armedNonce;
|
|
106
|
+
}
|
|
107
|
+
/** Stop stamping: the process is no longer writing for an install that has a nonce. */
|
|
108
|
+
function disarmArgsNonce() {
|
|
109
|
+
armedNonce = null;
|
|
110
|
+
}
|
|
111
|
+
/** `content` stamped with the armed nonce, or untouched when this process is not an installer. */
|
|
112
|
+
function stampInstalledContent(content) {
|
|
113
|
+
return armedNonce === null ? content : stampArgsTerminator(content, armedNonce);
|
|
114
|
+
}
|
|
@@ -504,6 +504,63 @@ function validateEntryShape(e, i) {
|
|
|
504
504
|
...('milestone' in o ? { milestone: typeof o.milestone === 'string' ? o.milestone : null } : {}),
|
|
505
505
|
};
|
|
506
506
|
}
|
|
507
|
+
/**
|
|
508
|
+
* #5418: when the frontmatter counts disagree with the parsed entries, the usual
|
|
509
|
+
* cause is a hand-edited table: a row added to the rendered table (and the counts
|
|
510
|
+
* bumped to match) while the fenced JSON block, the sole source of entries, was left
|
|
511
|
+
* behind. Names the row ids the table and the JSON block disagree about so the
|
|
512
|
+
* counts message does not point at the (correct) frontmatter. Returns '' when there
|
|
513
|
+
* is nothing to add. Best-effort by design: it runs while a WindowsError is already
|
|
514
|
+
* on its way out, so it must never throw and replace that error.
|
|
515
|
+
*/
|
|
516
|
+
/** Row ids spelled out in the divergence note; the rest are counted. */
|
|
517
|
+
const ROW_ID_LIST_LIMIT = 20;
|
|
518
|
+
function describeTableJsonDivergence(raw, entries) {
|
|
519
|
+
try {
|
|
520
|
+
// The hint is the PARSED entry count, not frontmatter total_count: the latter
|
|
521
|
+
// is the number that is wrong here.
|
|
522
|
+
const table = extractTableRegion(raw, entries.length);
|
|
523
|
+
if (table === null)
|
|
524
|
+
return '';
|
|
525
|
+
const rowId = (line) => (line.split('|')[1] ?? '').trim();
|
|
526
|
+
// Ids are positive integers (the JSON side enforces it), so a first cell that is
|
|
527
|
+
// not one — the `_(none)_` empty-ledger placeholder, a continuation line of a
|
|
528
|
+
// multi-line description, control characters — is not a row id and is never
|
|
529
|
+
// echoed into the message.
|
|
530
|
+
const tableIds = new Set();
|
|
531
|
+
const tableLines = table.split('\n');
|
|
532
|
+
for (let i = 2; i < tableLines.length; i++) {
|
|
533
|
+
if (!tableLines[i].startsWith('|'))
|
|
534
|
+
continue;
|
|
535
|
+
const id = rowId(tableLines[i]);
|
|
536
|
+
if (/^\d{1,15}$/.test(id))
|
|
537
|
+
tableIds.add(id);
|
|
538
|
+
}
|
|
539
|
+
const jsonIds = new Set(entries.map((e) => String(e.id)));
|
|
540
|
+
const byNumber = (a, b) => Number(a) - Number(b);
|
|
541
|
+
const list = (ids) => {
|
|
542
|
+
const shown = ids.slice(0, ROW_ID_LIST_LIMIT).join(', ');
|
|
543
|
+
return ids.length > ROW_ID_LIST_LIMIT ? `${shown} and ${ids.length - ROW_ID_LIST_LIMIT} more` : shown;
|
|
544
|
+
};
|
|
545
|
+
const tableOnly = [...tableIds].filter((id) => !jsonIds.has(id)).sort(byNumber);
|
|
546
|
+
const jsonOnly = [...jsonIds].filter((id) => !tableIds.has(id)).sort(byNumber);
|
|
547
|
+
const parts = [];
|
|
548
|
+
if (tableOnly.length > 0) {
|
|
549
|
+
parts.push(`row id(s) in the table but not in the fenced JSON block: ${list(tableOnly)}`);
|
|
550
|
+
}
|
|
551
|
+
if (jsonOnly.length > 0) {
|
|
552
|
+
parts.push(`row id(s) in the fenced JSON block but not in the table: ${list(jsonOnly)}`);
|
|
553
|
+
}
|
|
554
|
+
if (parts.length === 0)
|
|
555
|
+
return '';
|
|
556
|
+
return ` The table and the fenced JSON block disagree (${parts.join('; ')}). The JSON block is the ` +
|
|
557
|
+
'authoritative entries source: add the missing entries there (or remove the stray table rows) ' +
|
|
558
|
+
'and keep the frontmatter counts in step with it.';
|
|
559
|
+
}
|
|
560
|
+
catch {
|
|
561
|
+
return '';
|
|
562
|
+
}
|
|
563
|
+
}
|
|
507
564
|
function parseLedger(raw) {
|
|
508
565
|
const fm = parseFrontmatterStrict(raw);
|
|
509
566
|
if (fm.schema_version !== exports.SCHEMA_VERSION) {
|
|
@@ -537,7 +594,8 @@ function parseLedger(raw) {
|
|
|
537
594
|
recomputed.total_count !== ledger.total_count) {
|
|
538
595
|
throw new WindowsError(exports.REASON.WINDOWS_LEDGER_MALFORMED, `Ledger counts disagree with entries: frontmatter open/waived/fixed/total=` +
|
|
539
596
|
`${ledger.open_count}/${ledger.waived_count}/${ledger.fixed_count}/${ledger.total_count}` +
|
|
540
|
-
` but entries yield ${recomputed.open_count}/${recomputed.waived_count}/${recomputed.fixed_count}/${recomputed.total_count}.`
|
|
597
|
+
` but entries yield ${recomputed.open_count}/${recomputed.waived_count}/${recomputed.fixed_count}/${recomputed.total_count}.` +
|
|
598
|
+
describeTableJsonDivergence(raw, entries));
|
|
541
599
|
}
|
|
542
600
|
return ledger;
|
|
543
601
|
}
|
|
@@ -807,6 +807,28 @@ function reconcile(runtimeDir) {
|
|
|
807
807
|
}
|
|
808
808
|
return result;
|
|
809
809
|
}
|
|
810
|
+
/**
|
|
811
|
+
* #5121: the one bounded read for a SKILL.md found by walking a skill root. A skill file is untrusted
|
|
812
|
+
* repository (or installed-runtime) content: a symlink to /dev/zero exhausts memory and a FIFO blocks
|
|
813
|
+
* the process, because a bare readFileSync does neither a type nor a size check. Reuses the fd protocol
|
|
814
|
+
* of readSmallRegularFile and maps its fail-closed "unreadable" conditions (not a regular file after
|
|
815
|
+
* following symlinks, over the cap) to null, so a caller treats the file as it treats a missing one.
|
|
816
|
+
* Any other IO error still throws, as the unbounded read did.
|
|
817
|
+
*
|
|
818
|
+
* 256 KiB: the largest shipped SKILL.md is ~21 KB, so the cap is >10x headroom while still bounding the
|
|
819
|
+
* allocation a hostile repository can force.
|
|
820
|
+
*/
|
|
821
|
+
const SKILL_FILE_MAX_BYTES = 256 * 1024;
|
|
822
|
+
function readSkillFile(filePath) {
|
|
823
|
+
try {
|
|
824
|
+
return readSmallRegularFile(filePath, SKILL_FILE_MAX_BYTES);
|
|
825
|
+
}
|
|
826
|
+
catch (err) {
|
|
827
|
+
if (err instanceof LedgerIOError && (err.code === 'ENXIO' || err.code === 'EISDIR' || err.code === 'EFBIG'))
|
|
828
|
+
return null;
|
|
829
|
+
throw err;
|
|
830
|
+
}
|
|
831
|
+
}
|
|
810
832
|
module.exports = {
|
|
811
833
|
readLedger,
|
|
812
834
|
readLedgerStrict,
|
|
@@ -822,6 +844,9 @@ module.exports = {
|
|
|
822
844
|
// #1459 finding 1 (HIGH): the RAW-BYTES variant — the SOLE correct reader for the byte-exact,
|
|
823
845
|
// injective consent content-hash binding (a utf8 decode is lossy and could collide binary artifacts).
|
|
824
846
|
readSmallRegularFileBuffer,
|
|
847
|
+
// #5121: bounded SKILL.md read shared by skill discovery, the installed-runtime manifest and capability skills.
|
|
848
|
+
readSkillFile,
|
|
849
|
+
SKILL_FILE_MAX_BYTES,
|
|
825
850
|
// Exported for testing / introspection
|
|
826
851
|
LEDGER_FILE_NAME,
|
|
827
852
|
CorruptLedgerError,
|