@opengsd/gsd-core 1.11.0 → 1.13.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 +1 -1
- package/.opencode/plugins/gsd-core.js +12 -0
- package/agents/gsd-code-fixer.md +1 -1
- package/agents/gsd-debug-session-manager.md +1 -1
- package/agents/gsd-debugger.md +1 -1
- package/agents/gsd-dom-verifier.md +169 -0
- package/agents/gsd-eval-auditor.md +1 -1
- package/agents/gsd-executor.md +78 -42
- package/agents/gsd-framework-selector.md +1 -3
- package/agents/gsd-intel-updater.md +1 -1
- package/agents/gsd-mempalace-curator.md +0 -1
- package/agents/gsd-pattern-mapper.md +11 -0
- package/agents/gsd-phase-researcher.md +3 -1
- package/agents/gsd-plan-checker.md +91 -112
- package/agents/gsd-planner.md +20 -4
- package/agents/gsd-project-researcher.md +1 -1
- package/agents/gsd-research-synthesizer.md +2 -2
- package/agents/gsd-roadmapper.md +15 -11
- package/agents/gsd-ui-checker.md +82 -7
- package/agents/gsd-ui-researcher.md +70 -3
- package/agents/gsd-verifier.md +24 -2
- package/bin/install.js +847 -200
- package/commands/gsd/discuss-phase.md +1 -1
- package/commands/gsd/execute-phase.md +1 -1
- package/commands/gsd/import.md +1 -1
- package/commands/gsd/ns-workflow.md +2 -1
- package/commands/gsd/phase.md +1 -1
- package/commands/gsd/quick-batch.md +105 -0
- package/commands/gsd/quick.md +8 -4
- package/commands/gsd/surface.md +18 -8
- package/gsd-core/bin/gsd-tools.cjs +761 -100
- package/gsd-core/bin/lib/active-workstream-store.cjs +8 -0
- package/gsd-core/bin/lib/adr-parser.cjs +13 -7
- package/gsd-core/bin/lib/agent-install-check.cjs +162 -0
- package/gsd-core/bin/lib/api-coverage.cjs +30 -9
- package/gsd-core/bin/lib/artifacts.cjs +2 -0
- package/gsd-core/bin/lib/assumption-delta.cjs +30 -11
- package/gsd-core/bin/lib/audit.cjs +163 -41
- package/gsd-core/bin/lib/broken-windows.cjs +306 -28
- package/gsd-core/bin/lib/capability-activation.cjs +27 -0
- package/gsd-core/bin/lib/capability-lock.cjs +10 -4
- package/gsd-core/bin/lib/capability-registry.cjs +785 -144
- package/gsd-core/bin/lib/capability-state.cjs +25 -4
- package/gsd-core/bin/lib/capability-validator.cjs +321 -18
- package/gsd-core/bin/lib/capability-writer.cjs +14 -4
- package/gsd-core/bin/lib/check-command-router.cjs +229 -6
- package/gsd-core/bin/lib/claude-orchestration.cjs +10 -25
- package/gsd-core/bin/lib/cli-exit.cjs +496 -10
- package/gsd-core/bin/lib/clusters.cjs +1 -0
- package/gsd-core/bin/lib/code-review-depth.cjs +288 -0
- package/gsd-core/bin/lib/codex-agent-toml.cjs +410 -4
- package/gsd-core/bin/lib/command-aliases.cjs +16 -0
- package/gsd-core/bin/lib/command-arg-projection.cjs +144 -14
- package/gsd-core/bin/lib/command-routing-hub.cjs +31 -2
- package/gsd-core/bin/lib/commands.cjs +877 -54
- package/gsd-core/bin/lib/complexity-trigger.cjs +26 -6
- package/gsd-core/bin/lib/config-loader.cjs +121 -29
- package/gsd-core/bin/lib/config.cjs +92 -2
- package/gsd-core/bin/lib/configuration.cjs +129 -37
- package/gsd-core/bin/lib/core-utils.cjs +118 -14
- package/gsd-core/bin/lib/decisions.cjs +213 -1
- package/gsd-core/bin/lib/edge-probe.cjs +23 -2
- package/gsd-core/bin/lib/estimate-cli.cjs +55 -11
- package/gsd-core/bin/lib/exit-code-registry.cjs +98 -0
- package/gsd-core/bin/lib/file-overlap-partitioner.cjs +74 -0
- package/gsd-core/bin/lib/frontmatter.cjs +975 -326
- package/gsd-core/bin/lib/gap-checker.cjs +41 -8
- package/gsd-core/bin/lib/git-base-branch.cjs +182 -39
- package/gsd-core/bin/lib/health-diagnostic-rules/consistency.cjs +7 -3
- package/gsd-core/bin/lib/health-diagnostic-rules/phase-structure.cjs +8 -2
- package/gsd-core/bin/lib/health-diagnostic-rules/roadmap-disk-consistency.cjs +60 -14
- package/gsd-core/bin/lib/health-diagnostic-rules/state-consistency.cjs +75 -22
- package/gsd-core/bin/lib/health-diagnostic-rules/worktree-health.cjs +22 -8
- package/gsd-core/bin/lib/health-diagnostic.cjs +23 -3
- package/gsd-core/bin/lib/host-integration.cjs +96 -11
- package/gsd-core/bin/lib/init-command-router.cjs +132 -21
- package/gsd-core/bin/lib/init.cjs +252 -56
- package/gsd-core/bin/lib/install-engine.cjs +252 -15
- package/gsd-core/bin/lib/install-model-override-resolver.cjs +78 -1
- package/gsd-core/bin/lib/install-profiles.cjs +100 -18
- package/gsd-core/bin/lib/installer-migration-report.cjs +4 -0
- package/gsd-core/bin/lib/installer-migrations/010-antigravity-retire-confighome-artifacts.cjs +169 -0
- package/gsd-core/bin/lib/installer-migrations.cjs +10 -7
- package/gsd-core/bin/lib/intel.cjs +101 -26
- package/gsd-core/bin/lib/io.cjs +195 -15
- package/gsd-core/bin/lib/learnings.cjs +85 -14
- package/gsd-core/bin/lib/legacy-cleanup.cjs +8 -2
- package/gsd-core/bin/lib/loop-resolver.cjs +14 -8
- package/gsd-core/bin/lib/markdown-table.cjs +175 -4
- package/gsd-core/bin/lib/milestone.cjs +112 -7
- package/gsd-core/bin/lib/model-catalog.cjs +177 -19
- package/gsd-core/bin/lib/model-resolver.cjs +10 -28
- package/gsd-core/bin/lib/onboard-projection.cjs +5 -1
- package/gsd-core/bin/lib/phase-command-router.cjs +13 -6
- package/gsd-core/bin/lib/phase-estimation.cjs +17 -8
- package/gsd-core/bin/lib/phase-id.cjs +321 -13
- package/gsd-core/bin/lib/phase-lifecycle.cjs +24 -16
- package/gsd-core/bin/lib/phase-locator.cjs +138 -17
- package/gsd-core/bin/lib/phase.cjs +1175 -115
- package/gsd-core/bin/lib/plan-document.cjs +273 -0
- package/gsd-core/bin/lib/plan-scan.cjs +13 -2
- package/gsd-core/bin/lib/planning-command-router.cjs +61 -0
- package/gsd-core/bin/lib/planning-inspect.cjs +1168 -0
- package/gsd-core/bin/lib/planning-snapshot.cjs +165 -34
- package/gsd-core/bin/lib/planning-workspace.cjs +159 -28
- package/gsd-core/bin/lib/probe-core.cjs +4 -1
- package/gsd-core/bin/lib/profile-pipeline-command-router.cjs +50 -7
- package/gsd-core/bin/lib/profile-pipeline.cjs +6 -3
- package/gsd-core/bin/lib/quick-batch-command-router.cjs +285 -0
- package/gsd-core/bin/lib/quick-batch-dispatch.cjs +250 -0
- package/gsd-core/bin/lib/quick-batch.cjs +840 -0
- package/gsd-core/bin/lib/real-home-guard.cjs +419 -0
- package/gsd-core/bin/lib/refactor-trigger-command-router.cjs +71 -45
- package/gsd-core/bin/lib/review-lane-descriptor.cjs +62 -14
- package/gsd-core/bin/lib/review-lane-invocation.cjs +73 -1
- package/gsd-core/bin/lib/review-lane-runner.cjs +136 -10
- package/gsd-core/bin/lib/roadmap-command-router.cjs +45 -31
- package/gsd-core/bin/lib/roadmap-parser.cjs +577 -41
- package/gsd-core/bin/lib/roadmap.cjs +248 -64
- package/gsd-core/bin/lib/runtime-artifact-conversion.cjs +329 -41
- package/gsd-core/bin/lib/runtime-artifact-install-plan.cjs +16 -17
- package/gsd-core/bin/lib/runtime-artifact-layout.cjs +320 -109
- package/gsd-core/bin/lib/runtime-hooks-surface.cjs +487 -83
- package/gsd-core/bin/lib/runtime-identity.cjs +234 -0
- package/gsd-core/bin/lib/runtime-slash.cjs +72 -2
- package/gsd-core/bin/lib/shell-command-projection.cjs +75 -8
- package/gsd-core/bin/lib/smart-entry.cjs +19 -31
- package/gsd-core/bin/lib/spec-section.cjs +12 -7
- package/gsd-core/bin/lib/state-command-router.cjs +47 -18
- package/gsd-core/bin/lib/state-contract.cjs +359 -0
- package/gsd-core/bin/lib/state-document.cjs +216 -5
- package/gsd-core/bin/lib/state-md-schema.cjs +231 -0
- package/gsd-core/bin/lib/state-transition.cjs +850 -145
- package/gsd-core/bin/lib/state.cjs +1629 -287
- package/gsd-core/bin/lib/surface.cjs +33 -10
- package/gsd-core/bin/lib/task-command-router.cjs +111 -1
- package/gsd-core/bin/lib/task-content-resolution.cjs +368 -0
- package/gsd-core/bin/lib/tdd-red-evidence.cjs +133 -0
- package/gsd-core/bin/lib/teams-status.cjs +4 -1
- package/gsd-core/bin/lib/uat-predicate.cjs +58 -20
- package/gsd-core/bin/lib/uat.cjs +2542 -387
- package/gsd-core/bin/lib/ui-consideration-probe.cjs +9 -1
- package/gsd-core/bin/lib/ui-safety-gate.cjs +37 -7
- package/gsd-core/bin/lib/unusable-input.cjs +13 -0
- package/gsd-core/bin/lib/update-context.cjs +6 -2
- package/gsd-core/bin/lib/validate-command-router.cjs +2 -2
- package/gsd-core/bin/lib/validate.cjs +230 -12
- package/gsd-core/bin/lib/vendor/README.md +43 -5
- package/gsd-core/bin/lib/vendor/js-yaml.cjs +3014 -0
- package/gsd-core/bin/lib/verification-command-router.cjs +2 -1
- package/gsd-core/bin/lib/verification.cjs +287 -13
- package/gsd-core/bin/lib/verify-command-grounding.cjs +846 -0
- package/gsd-core/bin/lib/verify-command-router.cjs +1 -0
- package/gsd-core/bin/lib/verify.cjs +441 -56
- package/gsd-core/bin/lib/workstream-inventory.cjs +20 -2
- package/gsd-core/bin/lib/workstream-name-policy.cjs +25 -4
- package/gsd-core/bin/lib/worktree-base-ref.cjs +66 -12
- package/gsd-core/bin/lib/worktree-safety.cjs +185 -21
- package/gsd-core/bin/shared/config-defaults.manifest.json +7 -1
- package/gsd-core/bin/shared/config-schema.manifest.json +13 -0
- package/gsd-core/bin/shared/exit-codes.json +8 -0
- package/gsd-core/bin/shared/exit-codes.sh +20 -0
- package/gsd-core/bin/shared/model-catalog.json +8 -1
- package/gsd-core/bin/verify-reapply-patches.cjs +70 -3
- package/gsd-core/references/agent-contracts.md +6 -5
- package/gsd-core/references/api-coverage.md +24 -2
- package/gsd-core/references/autonomous-smart-discuss.md +3 -3
- package/gsd-core/references/checkpoints.md +37 -19
- package/gsd-core/references/decimal-phase-calculation.md +5 -5
- package/gsd-core/references/edge-probe.md +17 -5
- package/gsd-core/references/execute-mvp-tdd.md +18 -18
- package/gsd-core/references/execute-phase-between-wave-reset.md +9 -12
- package/gsd-core/references/execute-phase-response-language.md +6 -0
- package/gsd-core/references/execute-phase-wave-guard.md +11 -9
- package/gsd-core/references/executor-examples.md +42 -0
- package/gsd-core/references/failing-direction.md +78 -0
- package/gsd-core/references/few-shot-examples/plan-checker.md +15 -15
- package/gsd-core/references/gate-prompts.md +1 -1
- package/gsd-core/references/git-integration.md +5 -5
- package/gsd-core/references/git-planning-commit.md +3 -3
- package/gsd-core/references/gsd-run-resolver.md +1 -1
- package/gsd-core/references/loop-hook-dispatch.md +22 -0
- package/gsd-core/references/model-profiles.md +1 -1
- package/gsd-core/references/mvp-concepts.md +2 -2
- package/gsd-core/references/nyquist-compliance.md +74 -0
- package/gsd-core/references/offer-next.md +3 -5
- package/gsd-core/references/phase-argument-parsing.md +3 -3
- package/gsd-core/references/plan-checker-examples.md +41 -0
- package/gsd-core/references/planner-antipatterns.md +25 -0
- package/gsd-core/references/planner-chunked.md +5 -1
- package/gsd-core/references/planner-coupling.md +42 -0
- package/gsd-core/references/planner-failing-direction.md +53 -0
- package/gsd-core/references/planner-human-verify-mode.md +15 -1
- package/gsd-core/references/planner-quick-batch.md +71 -0
- package/gsd-core/references/planner-reviews.md +47 -0
- package/gsd-core/references/planner-revision.md +76 -3
- package/gsd-core/references/planner-verify-command-grounding.md +17 -0
- package/gsd-core/references/planning-config.md +39 -9
- package/gsd-core/references/response-language-directive.md +9 -0
- package/gsd-core/references/reviewer-instances.md +31 -0
- package/gsd-core/references/revision-loop.md +118 -11
- package/gsd-core/references/runtime-aware-dispatch.md +1 -1
- package/gsd-core/references/tdd.md +15 -12
- package/gsd-core/references/ui-brand.md +65 -21
- package/gsd-core/references/ui-consideration-probe.md +1 -1
- package/gsd-core/references/universal-anti-patterns.md +2 -2
- package/gsd-core/references/verifier-evidence-gate.md +160 -0
- package/gsd-core/references/verify-command-path-resolvability.md +42 -0
- package/gsd-core/references/verify-mvp-mode.md +1 -1
- package/gsd-core/references/workstream-flag.md +11 -11
- package/gsd-core/templates/README.md +1 -1
- package/gsd-core/templates/SECURITY.md +3 -3
- package/gsd-core/templates/UI-SPEC.md +25 -3
- package/gsd-core/templates/VALIDATION.md +3 -3
- package/gsd-core/templates/phase-prompt.md +7 -0
- package/gsd-core/templates/state.md +7 -0
- package/gsd-core/templates/verification-report.md +5 -0
- package/gsd-core/workflows/_runtime-launcher.snippet.sh +1 -1
- package/gsd-core/workflows/add-backlog.md +3 -1
- package/gsd-core/workflows/add-phase.md +5 -3
- package/gsd-core/workflows/add-tests.md +4 -9
- package/gsd-core/workflows/add-todo.md +2 -2
- package/gsd-core/workflows/ai-integration-phase.md +5 -10
- package/gsd-core/workflows/analyze-dependencies.md +2 -0
- package/gsd-core/workflows/audit-fix.md +14 -3
- package/gsd-core/workflows/audit-milestone.md +11 -9
- package/gsd-core/workflows/audit-uat.md +19 -2
- package/gsd-core/workflows/autonomous/steps/converge-fail-fast.md +2 -2
- package/gsd-core/workflows/autonomous.md +12 -26
- package/gsd-core/workflows/check-todos.md +2 -2
- package/gsd-core/workflows/cleanup.md +3 -3
- package/gsd-core/workflows/code-review/steps/structural-pre-pass.md +16 -14
- package/gsd-core/workflows/code-review-fix.md +3 -1
- package/gsd-core/workflows/code-review.md +192 -69
- package/gsd-core/workflows/complete-milestone.md +28 -14
- package/gsd-core/workflows/debug.md +6 -4
- package/gsd-core/workflows/diagnose-issues.md +17 -7
- package/gsd-core/workflows/discuss-phase/modes/advisor.md +3 -1
- package/gsd-core/workflows/discuss-phase/modes/all.md +2 -0
- package/gsd-core/workflows/discuss-phase/modes/analyze.md +2 -0
- package/gsd-core/workflows/discuss-phase/modes/auto.md +2 -0
- package/gsd-core/workflows/discuss-phase/modes/batch.md +2 -0
- package/gsd-core/workflows/discuss-phase/modes/chain.md +5 -7
- package/gsd-core/workflows/discuss-phase/modes/default.md +2 -0
- package/gsd-core/workflows/discuss-phase/modes/power.md +2 -0
- package/gsd-core/workflows/discuss-phase/modes/text.md +3 -1
- package/gsd-core/workflows/discuss-phase/templates/context.md +2 -0
- package/gsd-core/workflows/discuss-phase/templates/discussion-log.md +2 -0
- package/gsd-core/workflows/discuss-phase-assumptions/steps/auto-advance-dispatch.md +1 -3
- package/gsd-core/workflows/discuss-phase-assumptions.md +3 -3
- package/gsd-core/workflows/discuss-phase-power.md +2 -0
- package/gsd-core/workflows/discuss-phase.md +2 -2
- package/gsd-core/workflows/do.md +46 -19
- package/gsd-core/workflows/docs-update.md +6 -5
- package/gsd-core/workflows/edit-phase.md +3 -1
- package/gsd-core/workflows/eval-review.md +5 -10
- package/gsd-core/workflows/execute-phase/steps/codebase-drift-gate.md +3 -1
- package/gsd-core/workflows/execute-phase/steps/executor-isolation-dispatch.md +129 -11
- package/gsd-core/workflows/execute-phase/steps/gap-closure-artifacts.md +1 -1
- package/gsd-core/workflows/execute-phase/steps/partial-wave.md +1 -1
- package/gsd-core/workflows/execute-phase/steps/per-plan-executor-routing.md +1 -1
- package/gsd-core/workflows/execute-phase/steps/per-plan-worktree-gate.md +29 -5
- package/gsd-core/workflows/execute-phase/steps/post-merge-gate.md +2 -2
- package/gsd-core/workflows/execute-phase/steps/protected-branch.md +21 -0
- package/gsd-core/workflows/execute-phase/steps/regression-gate-run.md +4 -2
- package/gsd-core/workflows/execute-phase/steps/tdd-applicability-resolution.md +25 -0
- package/gsd-core/workflows/execute-phase/steps/wave-post-gate-hooks.md +39 -0
- package/gsd-core/workflows/execute-phase/steps/worktree-recovery-policy.md +2 -0
- package/gsd-core/workflows/execute-phase.md +68 -66
- package/gsd-core/workflows/execute-plan.md +25 -20
- package/gsd-core/workflows/explore.md +3 -1
- package/gsd-core/workflows/extract-learnings.md +3 -1
- package/gsd-core/workflows/fast.md +8 -2
- package/gsd-core/workflows/forensics.md +3 -1
- package/gsd-core/workflows/graduation.md +6 -6
- package/gsd-core/workflows/health.md +4 -7
- package/gsd-core/workflows/help/modes/brief.md +2 -0
- package/gsd-core/workflows/help/modes/default.md +2 -0
- package/gsd-core/workflows/help/modes/full.md +12 -0
- package/gsd-core/workflows/help/modes/topic.md +2 -0
- package/gsd-core/workflows/help.md +2 -0
- package/gsd-core/workflows/import.md +17 -14
- package/gsd-core/workflows/inbox.md +5 -6
- package/gsd-core/workflows/ingest-docs.md +45 -12
- package/gsd-core/workflows/insert-phase.md +7 -5
- package/gsd-core/workflows/list-phase-assumptions.md +2 -0
- package/gsd-core/workflows/list-seeds.md +7 -3
- package/gsd-core/workflows/list-workspaces.md +3 -1
- package/gsd-core/workflows/manager.md +15 -26
- package/gsd-core/workflows/map-codebase.md +3 -1
- package/gsd-core/workflows/milestone-summary.md +3 -1
- package/gsd-core/workflows/mvp-phase.md +3 -3
- package/gsd-core/workflows/new-milestone.md +10 -22
- package/gsd-core/workflows/new-project/steps/auto-mode-config.md +1 -1
- package/gsd-core/workflows/new-project.md +17 -29
- package/gsd-core/workflows/new-workspace.md +2 -2
- package/gsd-core/workflows/next.md +4 -2
- package/gsd-core/workflows/node-repair.md +2 -0
- package/gsd-core/workflows/note.md +2 -0
- package/gsd-core/workflows/onboard.md +1 -1
- package/gsd-core/workflows/pause-work.md +20 -5
- package/gsd-core/workflows/plan-phase/steps/adr-ingest-express-path.md +1 -1
- package/gsd-core/workflows/plan-phase/steps/chunked-planning-mode.md +100 -18
- package/gsd-core/workflows/plan-phase/steps/prd-express-path.md +4 -4
- package/gsd-core/workflows/plan-phase/steps/stall-detection-helpers.md +12 -3
- package/gsd-core/workflows/plan-phase.md +251 -54
- package/gsd-core/workflows/plan-review-convergence.md +148 -19
- package/gsd-core/workflows/plant-seed.md +3 -3
- package/gsd-core/workflows/pr-branch.md +195 -51
- package/gsd-core/workflows/profile-user.md +17 -15
- package/gsd-core/workflows/progress/steps/forensic-audit.md +1 -1
- package/gsd-core/workflows/progress.md +52 -15
- package/gsd-core/workflows/quick/steps/discussion-phase.md +1 -3
- package/gsd-core/workflows/quick/steps/plan-checker-loop.md +38 -5
- package/gsd-core/workflows/quick/steps/quick-verification.md +2 -4
- package/gsd-core/workflows/quick/steps/research-phase.md +5 -7
- package/gsd-core/workflows/quick/steps/worktree-pre-dispatch-commit.md +3 -3
- package/gsd-core/workflows/quick-batch/steps/batch-init.md +55 -0
- package/gsd-core/workflows/quick-batch/steps/completion.md +65 -0
- package/gsd-core/workflows/quick-batch/steps/merge-wave.md +100 -0
- package/gsd-core/workflows/quick-batch/steps/plan-checker-loop.md +147 -0
- package/gsd-core/workflows/quick-batch/steps/planner-wave.md +158 -0
- package/gsd-core/workflows/quick-batch/steps/research-phase.md +95 -0
- package/gsd-core/workflows/quick-batch/steps/resume-mode.md +49 -0
- package/gsd-core/workflows/quick-batch/steps/verification-wave.md +73 -0
- package/gsd-core/workflows/quick-batch/steps/worktree-dispatch.md +169 -0
- package/gsd-core/workflows/quick-batch.md +203 -0
- package/gsd-core/workflows/quick.md +33 -32
- package/gsd-core/workflows/reapply-patches.md +2 -0
- package/gsd-core/workflows/remove-phase.md +6 -4
- package/gsd-core/workflows/remove-workspace.md +3 -3
- package/gsd-core/workflows/resume-project.md +14 -14
- package/gsd-core/workflows/review.md +404 -21
- package/gsd-core/workflows/scan.md +3 -1
- package/gsd-core/workflows/section-manifest.json +12 -0
- package/gsd-core/workflows/secure-phase.md +3 -3
- package/gsd-core/workflows/session-report.md +2 -0
- package/gsd-core/workflows/settings-advanced.md +9 -9
- package/gsd-core/workflows/settings-integrations.md +66 -32
- package/gsd-core/workflows/settings.md +4 -6
- package/gsd-core/workflows/ship.md +22 -16
- package/gsd-core/workflows/sketch-wrap-up.md +13 -17
- package/gsd-core/workflows/sketch.md +13 -19
- package/gsd-core/workflows/smart-entry.md +4 -6
- package/gsd-core/workflows/spec-phase.md +31 -4
- package/gsd-core/workflows/spike-wrap-up.md +9 -11
- package/gsd-core/workflows/spike.md +21 -32
- package/gsd-core/workflows/stats.md +4 -2
- package/gsd-core/workflows/sync-skills.md +13 -5
- package/gsd-core/workflows/thread.md +13 -7
- package/gsd-core/workflows/transition.md +7 -5
- package/gsd-core/workflows/ui-phase.md +36 -21
- package/gsd-core/workflows/ui-review.md +7 -11
- package/gsd-core/workflows/ultraplan-phase.md +7 -13
- package/gsd-core/workflows/undo.md +9 -17
- package/gsd-core/workflows/update.md +47 -48
- package/gsd-core/workflows/validate-phase.md +3 -3
- package/gsd-core/workflows/verify-work/steps/automated-ui-verification.md +25 -1
- package/gsd-core/workflows/verify-work/steps/mvp-uat-framing.md +1 -1
- package/gsd-core/workflows/verify-work.md +106 -21
- package/hooks/dist/gsd-agent-isolation-guard.js +77 -38
- package/hooks/dist/gsd-check-update-worker.js +19 -2
- package/hooks/dist/gsd-config-reload.js +18 -12
- package/hooks/dist/gsd-context-monitor.js +302 -22
- package/hooks/dist/gsd-cursor-post-tool.js +3 -1
- package/hooks/dist/gsd-cursor-pre-tool.js +3 -1
- package/hooks/dist/gsd-cursor-session-start.js +2 -1
- package/hooks/dist/gsd-cursor-stop.js +2 -1
- package/hooks/dist/gsd-cursor-subagent-start.js +28 -23
- package/hooks/dist/gsd-cursor-subagent-stop.js +3 -1
- package/hooks/dist/gsd-ensure-canonical-path.js +2 -1
- package/hooks/dist/gsd-graphify-update.sh +22 -18
- package/hooks/dist/gsd-node-runner.sh +77 -0
- package/hooks/dist/gsd-phase-boundary.sh +1 -0
- package/hooks/dist/gsd-prompt-guard.js +46 -12
- package/hooks/dist/gsd-read-guard.js +18 -7
- package/hooks/dist/gsd-read-injection-scanner.js +22 -13
- package/hooks/dist/gsd-secret-read-guard.js +1079 -0
- package/hooks/dist/gsd-session-state.sh +1 -0
- package/hooks/dist/gsd-statusline.js +222 -29
- package/hooks/dist/gsd-validate-commit.sh +523 -12
- package/hooks/dist/gsd-windsurf-pre-command.js +16 -11
- package/hooks/dist/gsd-windsurf-pre-write.js +22 -13
- package/hooks/dist/gsd-workflow-guard.js +36 -17
- package/hooks/dist/gsd-worktree-path-guard.js +36 -21
- package/hooks/dist/gsd-write-guard.js +35 -25
- package/hooks/dist/lib/cli-exit.js +560 -0
- package/hooks/dist/lib/exit-code-registry.js +98 -0
- package/hooks/dist/lib/git-cmd.js +210 -1
- package/hooks/dist/lib/git-probe.js +84 -0
- package/hooks/dist/lib/hook-exit.js +81 -0
- package/hooks/dist/lib/injection-patterns.js +36 -6
- package/hooks/dist/managed-hooks-registry.cjs +4 -0
- package/hooks/gsd-agent-isolation-guard.js +77 -38
- package/hooks/gsd-check-update-worker.js +19 -2
- package/hooks/gsd-config-reload.js +18 -12
- package/hooks/gsd-context-monitor.js +302 -22
- package/hooks/gsd-cursor-post-tool.js +3 -1
- package/hooks/gsd-cursor-pre-tool.js +3 -1
- package/hooks/gsd-cursor-session-start.js +2 -1
- package/hooks/gsd-cursor-stop.js +2 -1
- package/hooks/gsd-cursor-subagent-start.js +28 -23
- package/hooks/gsd-cursor-subagent-stop.js +3 -1
- package/hooks/gsd-ensure-canonical-path.js +2 -1
- package/hooks/gsd-graphify-update.sh +22 -18
- package/hooks/gsd-node-runner.sh +77 -0
- package/hooks/gsd-phase-boundary.sh +1 -0
- package/hooks/gsd-prompt-guard.js +46 -12
- package/hooks/gsd-read-guard.js +18 -7
- package/hooks/gsd-read-injection-scanner.js +22 -13
- package/hooks/gsd-secret-read-guard.js +1079 -0
- package/hooks/gsd-session-state.sh +1 -0
- package/hooks/gsd-statusline.js +222 -29
- package/hooks/gsd-validate-commit.sh +523 -12
- package/hooks/gsd-windsurf-pre-command.js +16 -11
- package/hooks/gsd-windsurf-pre-write.js +22 -13
- package/hooks/gsd-workflow-guard.js +36 -17
- package/hooks/gsd-worktree-path-guard.js +36 -21
- package/hooks/gsd-write-guard.js +35 -25
- package/hooks/hooks.json +6 -0
- package/hooks/lib/cli-exit.js +560 -0
- package/hooks/lib/exit-code-registry.js +98 -0
- package/hooks/lib/git-cmd.js +210 -1
- package/hooks/lib/git-probe.js +84 -0
- package/hooks/lib/hook-exit.js +81 -0
- package/hooks/lib/injection-patterns.js +36 -6
- package/hooks/managed-hooks-registry.cjs +4 -0
- package/package.json +14 -9
- package/scripts/base64-scan.sh +74 -12
- package/scripts/build-hooks.js +12 -0
- package/scripts/check-glossary-refs.cjs +77 -15
- package/scripts/check-mutation-score-ratchet.cjs +156 -0
- package/scripts/ci-check-job-near-cap.cjs +49 -0
- package/scripts/ci-pr-mergeability.cjs +262 -0
- package/scripts/ci-test-scope.cjs +52 -12
- package/scripts/ci-timeout-report.cjs +230 -0
- package/scripts/docs-guard-registry.cjs +406 -0
- package/scripts/gen-capability-registry.cjs +8 -6
- package/scripts/gen-exit-code-docs.cjs +318 -0
- package/scripts/gen-exit-code-registry.cjs +891 -0
- package/scripts/gen-features.cjs +836 -0
- package/scripts/gen-hooks-cli-exit.cjs +239 -0
- package/scripts/gen-install-tree-fixtures.cjs +2 -2
- package/scripts/gen-loop-host-contract.cjs +189 -4
- package/scripts/gen-scripts-cli-exit.cjs +185 -0
- package/scripts/gen-state-md-docs.cjs +727 -0
- package/scripts/{test-failure-reasons.cjs → gsd-test-gate-reasons.cjs} +6 -0
- package/scripts/lib/ci-job-timing.cjs +72 -0
- package/scripts/lib/cli-exit.cjs +546 -44
- package/scripts/lib/drift-scan.cjs +32 -2
- package/scripts/lib/exit-code-registry.cjs +98 -0
- package/scripts/lib/ndjson-reporter.cjs +119 -0
- package/scripts/lib/shellcheck-fetch.cjs +247 -0
- package/scripts/lint-allow-test-rule-refs.allowlist.json +0 -6
- package/scripts/lint-allow-test-rule-refs.effective-ceiling.json +1 -1
- package/scripts/lint-allow-test-rule-refs.unverified-ceiling.json +1 -1
- package/scripts/lint-docs-guard-registration.cjs +495 -0
- package/scripts/lint-docs-guard-registration.exempt-baseline.cjs +198 -0
- package/scripts/lint-eslint-glob-coverage.allowlist.json +4 -0
- package/scripts/{lint-fix-has-regression-test.cjs → lint-fix-has-regression-tests.cjs} +12 -6
- package/scripts/lint-health-diagnostic-rule-table.cjs +65 -8
- package/scripts/lint-mutation-test-derivation-drift.cjs +86 -0
- package/scripts/lint-phase-enumeration-drift.cjs +45 -14
- package/scripts/lint-phase-id-drift.cjs +133 -8
- package/scripts/lint-planning-prompt-drift.cjs +38 -1
- package/scripts/lint-portable-grep.cjs +176 -0
- package/scripts/lint-removed-but-needed.cjs +184 -16
- package/scripts/lint-response-language-coverage.cjs +524 -0
- package/scripts/lint-seam-enforcement.cjs +182 -0
- package/scripts/lint-slug-derivation-drift.cjs +921 -0
- package/scripts/lint-source-test-name-collision.cjs +241 -0
- package/scripts/lint-state-write-path-drift.cjs +337 -432
- package/scripts/lint-test-file-count.allowlist.json +124 -4
- package/scripts/lint-test-file-count.cjs +25 -3
- package/scripts/lint-unreachable-guard-drift.cjs +51 -64
- package/scripts/lint-vendored-deps.cjs +208 -35
- package/scripts/lint-workflow-shellcheck-baseline.json +1027 -0
- package/scripts/lint-workflow-shellcheck.cjs +614 -0
- package/scripts/mutation-matrix.cjs +599 -50
- package/scripts/npm-audit-baseline.cjs +376 -0
- package/scripts/prompt-injection-scan.sh +83 -14
- package/scripts/require-issue-link-policy.cjs +16 -1
- package/scripts/secret-scan.sh +75 -13
- package/scripts/select-docs-guards.cjs +56 -0
- package/scripts/sync-runtime-launcher.cjs +22 -3
- package/skills/gsd-discuss-phase/SKILL.md +1 -1
- package/skills/gsd-execute-phase/SKILL.md +1 -1
- package/skills/gsd-import/SKILL.md +1 -1
- package/skills/gsd-ns-workflow/SKILL.md +1 -0
- package/skills/gsd-phase/SKILL.md +1 -1
- package/skills/gsd-quick/SKILL.md +8 -4
- package/skills/gsd-quick-batch/SKILL.md +105 -0
- package/skills/gsd-surface/SKILL.md +18 -8
- package/vscode/package.json +1 -1
- package/bin/lib/ui-safety-gate.cjs +0 -109
- package/scripts/lint-emitted-drift-ack.cjs +0 -344
- package/scripts/state-write-path-drift-baseline.json +0 -19
|
@@ -111,7 +111,13 @@ const RULE_W024 = {
|
|
|
111
111
|
function buildValidPhaseSet(snapshot) {
|
|
112
112
|
const valid = new Set();
|
|
113
113
|
for (const dir of snapshot.phaseDirs.value) {
|
|
114
|
-
|
|
114
|
+
// #612: the pre-migration source of this third was
|
|
115
|
+
// `collectDiskPhases(planBase, convention)`, whose keys came from the
|
|
116
|
+
// convention-aware extractor. Left convention-less here, a bracket repo's
|
|
117
|
+
// `GSD.02-05-slug` contributes `GSD.02` instead of `05`, so every STATE.md
|
|
118
|
+
// reference to a real phase falls outside the valid set and W002 fires on
|
|
119
|
+
// all of them.
|
|
120
|
+
const token = extractPhaseToken(dir, snapshot.phaseIdConvention);
|
|
115
121
|
if (token)
|
|
116
122
|
valid.add(token);
|
|
117
123
|
}
|
|
@@ -233,31 +239,71 @@ const RULE_W021 = {
|
|
|
233
239
|
description: "Phase's integer prefix implies a different milestone than its ROADMAP section (phase_id_convention: milestone-prefixed)",
|
|
234
240
|
repairable: false,
|
|
235
241
|
check: (snapshot) => {
|
|
236
|
-
const convention = snapshot.config.value?.['phase_id_convention'];
|
|
237
|
-
if (convention !== 'milestone-prefixed')
|
|
238
|
-
return [];
|
|
239
242
|
const diagnostics = [];
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
243
|
+
// Two INDEPENDENT gates, evaluated in the order the pre-migration
|
|
244
|
+
// `cmdValidateHealth` block emitted them (milestone-prefixed first, then
|
|
245
|
+
// bracket). They are deliberately NOT written as if/else: the two read
|
|
246
|
+
// DIFFERENT config bases and can both be true at once.
|
|
247
|
+
//
|
|
248
|
+
// milestone-prefixed — `snapshot.config` (ROOT config only), exactly as
|
|
249
|
+
// this gate has always read it. Federating THIS one silently moved a
|
|
250
|
+
// legacy convention's answer in BOTH directions on workstream repos: a
|
|
251
|
+
// W021 that fires at base vanishing, and one silent at base firing.
|
|
252
|
+
// bracket — `snapshot.phaseIdConvention` (federated workstream -> root),
|
|
253
|
+
// because the bracket reads this half reports on are themselves
|
|
254
|
+
// federated; gating it on the root answer would split the check against
|
|
255
|
+
// the reads it describes.
|
|
256
|
+
//
|
|
257
|
+
// A workstream that overrides a `milestone-prefixed` ROOT to `bracket` is
|
|
258
|
+
// the case that makes the distinction observable, and it is the reason an
|
|
259
|
+
// early `return` here would be a bug: the root-configured M-NN gate must
|
|
260
|
+
// still fire, or the repo looks healthier than it is.
|
|
261
|
+
const rootConvention = snapshot.config.value?.['phase_id_convention'];
|
|
262
|
+
if (rootConvention === 'milestone-prefixed') {
|
|
263
|
+
diagnostics.push(...checkMilestonePrefixW021(snapshot));
|
|
264
|
+
}
|
|
265
|
+
// #612: an ADDITIVE sibling branch — the milestone-prefixed gate above is
|
|
266
|
+
// untouched. Gated strictly on the ACTIVE convention, never on
|
|
267
|
+
// project_code presence: reads are selected per convention, and a CHECK
|
|
268
|
+
// that can fail a repo runs only for the convention that repo opted into.
|
|
269
|
+
if (snapshot.phaseIdConvention === 'bracket') {
|
|
270
|
+
for (const mm of snapshot.roadmapBracketIncoherences.value) {
|
|
271
|
+
diagnostics.push({
|
|
272
|
+
code: 'W021',
|
|
273
|
+
severity: SEVERITY.WARNING,
|
|
274
|
+
message: mm.kind === 'missing-bracket'
|
|
275
|
+
? `Phase ${mm.phaseId}: heading is not in bracket form under the 'bracket' convention (expected \`[CODE.${mm.sectionMilestone}] ${mm.phaseId}:\`)`
|
|
276
|
+
: `Phase ${mm.phaseId}: bracket milestone ${mm.phaseMilestone} does not match its section milestone ${mm.sectionMilestone}`,
|
|
277
|
+
remedy: adviseRemedy('Bracket migration lands with the #612 migrator (PR-3); until then, manually align the bracket milestone in this heading to match the enclosing section.'),
|
|
278
|
+
});
|
|
279
|
+
}
|
|
257
280
|
}
|
|
258
281
|
return diagnostics;
|
|
259
282
|
},
|
|
260
283
|
};
|
|
284
|
+
/** The milestone-prefixed half of W021, unchanged by #612. */
|
|
285
|
+
function checkMilestonePrefixW021(snapshot) {
|
|
286
|
+
const diagnostics = [];
|
|
287
|
+
for (const entry of snapshot.roadmapDeclaredPhases.value) {
|
|
288
|
+
// `entry.milestone === null` means the builder never found this phase
|
|
289
|
+
// heading inside any versioned (`v\d+\.\d+`) section — the original
|
|
290
|
+
// `checkMilestonePrefixMismatches` only ever iterates phases found
|
|
291
|
+
// WITHIN a section, so a phase outside any section is equivalently
|
|
292
|
+
// never checked here.
|
|
293
|
+
if (entry.milestone === null)
|
|
294
|
+
continue;
|
|
295
|
+
const expectedMilestone = getMilestoneFromPhaseId(entry.phaseId);
|
|
296
|
+
if (expectedMilestone === null || expectedMilestone === entry.milestone)
|
|
297
|
+
continue;
|
|
298
|
+
diagnostics.push({
|
|
299
|
+
code: 'W021',
|
|
300
|
+
severity: SEVERITY.WARNING,
|
|
301
|
+
message: `Phase ${entry.phaseId}: integer prefix implies ${expectedMilestone} but listed under ${entry.milestone}`,
|
|
302
|
+
remedy: adviseRemedy('gsd-tools roadmap upgrade --convention milestone-prefixed'),
|
|
303
|
+
});
|
|
304
|
+
}
|
|
305
|
+
return diagnostics;
|
|
306
|
+
}
|
|
261
307
|
// ─── W026 — STATE says milestone complete but ROADMAP lists unstarted phase ─
|
|
262
308
|
const RULE_W026 = {
|
|
263
309
|
code: 'W026',
|
|
@@ -282,7 +328,14 @@ const RULE_W026 = {
|
|
|
282
328
|
// unwindowed `phaseDirNames2` (`verify.cts:2372-2382`, a direct
|
|
283
329
|
// `readdirSync` of the phases dir), not the current-milestone-windowed
|
|
284
330
|
// `phaseDirs`.
|
|
285
|
-
|
|
331
|
+
// #612: the directory read widens with the heading read that produced
|
|
332
|
+
// `currentMilestoneRoadmapPhaseIds`, or every bracket phase resolves to
|
|
333
|
+
// nothing, reads as unstarted, and this UNGATED warning false-fires on
|
|
334
|
+
// any bracket repo whose STATE says the milestone is complete. #2528
|
|
335
|
+
// moved the read onto the shared selector; the convention rides along,
|
|
336
|
+
// since the selector's primary match IS the `phaseTokenMatches` call this
|
|
337
|
+
// line used to make directly.
|
|
338
|
+
const hasDirectory = matchPhaseDirs(snapshot.allPhaseDirNames.value, normalized, snapshot.phaseIdConvention).matches.length > 0;
|
|
286
339
|
if (!hasDirectory)
|
|
287
340
|
unstarted.push(phaseId);
|
|
288
341
|
}
|
|
@@ -35,10 +35,8 @@
|
|
|
35
35
|
* src/health-diagnostic-rules/worktree-health.cts, compiled to
|
|
36
36
|
* gsd-core/bin/lib/health-diagnostic-rules/worktree-health.cjs (gitignored).
|
|
37
37
|
*/
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
};
|
|
41
|
-
const node_path_1 = __importDefault(require("node:path"));
|
|
38
|
+
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
39
|
+
const shellCmdProjection = require("../shell-command-projection.cjs");
|
|
42
40
|
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
43
41
|
const healthDiagnosticMod = require("../health-diagnostic-types.cjs");
|
|
44
42
|
const { SEVERITY, adviseRemedy } = healthDiagnosticMod;
|
|
@@ -121,15 +119,31 @@ function checkW017(snapshot) {
|
|
|
121
119
|
// against `process.cwd()`. Per this batch's brief: the interpolated command
|
|
122
120
|
// (with the real path) lives in `message`; `remedy.args.command` stays a
|
|
123
121
|
// static `<path>` template, mirroring the split the brief specifies.
|
|
122
|
+
// ─── #3663 — path-comparison provenance helper ─────────────────────────────
|
|
123
|
+
//
|
|
124
|
+
// snapshot.cwd is raw process-cwd-derived — path.resolve() normalizes
|
|
125
|
+
// separators and relative segments but NOT casing, and a process launched via
|
|
126
|
+
// a differently-cased path echoes that spelling back. finding.path is
|
|
127
|
+
// `git worktree list`-derived, which self-normalizes to the canonical
|
|
128
|
+
// on-disk casing (forward slashes). Comparing those two spellings strictly
|
|
129
|
+
// misclassifies the ACTIVE worktree as stale on win32 — so the comparison
|
|
130
|
+
// folds case ONLY on win32 (case-insensitive filesystem, via the Shell
|
|
131
|
+
// Command Projection seam's toComparablePathKey — the platform-conditional
|
|
132
|
+
// fold policy lives there, not per call site) and stays case-sensitive on
|
|
133
|
+
// POSIX, where differently-cased paths are genuinely different directories.
|
|
134
|
+
// No realpath resolution — that would change symlink matching behavior.
|
|
135
|
+
function isActiveWorktreePath(activeCwd, worktreePath, platform = process.platform) {
|
|
136
|
+
const active = shellCmdProjection.toComparablePathKey(activeCwd, platform);
|
|
137
|
+
const worktree = shellCmdProjection.toComparablePathKey(worktreePath, platform);
|
|
138
|
+
return active === worktree || active.startsWith(worktree + '/');
|
|
139
|
+
}
|
|
124
140
|
function checkW027(snapshot) {
|
|
125
141
|
const diagnostics = [];
|
|
126
142
|
const activeCwd = snapshot.cwd;
|
|
127
143
|
for (const finding of snapshot.worktreeHealth.value) {
|
|
128
144
|
if (finding.kind !== 'stale')
|
|
129
145
|
continue;
|
|
130
|
-
|
|
131
|
-
const isActiveWorktree = activeCwd === normalizedWorktree || activeCwd.startsWith(normalizedWorktree + node_path_1.default.sep);
|
|
132
|
-
if (isActiveWorktree)
|
|
146
|
+
if (isActiveWorktreePath(activeCwd, finding.path))
|
|
133
147
|
continue;
|
|
134
148
|
diagnostics.push({
|
|
135
149
|
code: 'W027',
|
|
@@ -170,4 +184,4 @@ const RULES = [
|
|
|
170
184
|
check: checkW027,
|
|
171
185
|
},
|
|
172
186
|
];
|
|
173
|
-
module.exports = { RULES };
|
|
187
|
+
module.exports = { RULES, isActiveWorktreePath };
|
|
@@ -103,7 +103,7 @@ const CONSISTENCY_RULES = [
|
|
|
103
103
|
// (`verify.cts:2405-2553`) — ported verbatim, not reinvented.
|
|
104
104
|
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
105
105
|
const planningWorkspaceMod = require("./planning-workspace.cjs");
|
|
106
|
-
const {
|
|
106
|
+
const { planningDir } = planningWorkspaceMod;
|
|
107
107
|
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
108
108
|
const configLoaderMod = require("./config-loader.cjs");
|
|
109
109
|
const { CONFIG_DEFAULTS } = configLoaderMod;
|
|
@@ -113,6 +113,12 @@ const { getMilestoneInfo } = roadmapParserMod;
|
|
|
113
113
|
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
114
114
|
const stateMod = require("./state.cjs");
|
|
115
115
|
const { writeStateMd } = stateMod;
|
|
116
|
+
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
117
|
+
const frontmatter = require("./frontmatter.cjs");
|
|
118
|
+
const { extractFrontmatter } = frontmatter;
|
|
119
|
+
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
120
|
+
const stateTransitionMod = require("./state-transition.cjs");
|
|
121
|
+
const { rebuildStateTransaction } = stateTransitionMod;
|
|
116
122
|
const clock_cjs_1 = require("./clock.cjs");
|
|
117
123
|
const shell_command_projection_cjs_1 = require("./shell-command-projection.cjs");
|
|
118
124
|
const runtime_slash_cjs_1 = require("./runtime-slash.cjs");
|
|
@@ -160,7 +166,13 @@ function evaluateConsistencyRules(snapshot) {
|
|
|
160
166
|
* document for the read side.
|
|
161
167
|
*/
|
|
162
168
|
function repairPaths(cwd) {
|
|
163
|
-
|
|
169
|
+
// #3749: the project root is PROJECT-aware but deliberately NOT workstream-
|
|
170
|
+
// scoped — under GSD_PROJECT, config.json/MILESTONES.md/milestones belong to
|
|
171
|
+
// `.planning/<project>/` (the same base init.new-project's config_path
|
|
172
|
+
// names); under GSD_WORKSTREAM they stay at the workstream PARENT, keeping
|
|
173
|
+
// the documented root-vs-workstream split. planningDir(cwd, null) is exactly
|
|
174
|
+
// that base: project env honored, ws env suppressed.
|
|
175
|
+
const rootBase = planningDir(cwd, null);
|
|
164
176
|
const wsBase = planningDir(cwd);
|
|
165
177
|
return {
|
|
166
178
|
rootBase,
|
|
@@ -268,7 +280,15 @@ function runRepairAction(cwd, action, paths) {
|
|
|
268
280
|
stateContent += `**Status:** Resuming\n\n`;
|
|
269
281
|
stateContent += `## Session Log\n\n`;
|
|
270
282
|
stateContent += `- ${clock_cjs_1.realClock.localToday()}: STATE.md regenerated by ${slash('health')} --repair\n`;
|
|
271
|
-
|
|
283
|
+
// ADR-3473 §8.6: `/gsd-health --repair` is a factory reset, so
|
|
284
|
+
// preservation must not run; the snapshot of the file being replaced is
|
|
285
|
+
// still captured, and `{}` is the correct, legal snapshot of a
|
|
286
|
+
// STATE.md that had no parseable frontmatter — which is the usual
|
|
287
|
+
// reason this repair fires.
|
|
288
|
+
const priorState = node_fs_1.default.existsSync(statePath) ? ((0, shell_command_projection_cjs_1.platformReadSync)(statePath) ?? '') : '';
|
|
289
|
+
writeStateMd(statePath, stateContent, rebuildStateTransaction({
|
|
290
|
+
snapshot: extractFrontmatter(priorState, statePath),
|
|
291
|
+
}), cwd);
|
|
272
292
|
return { success: true, path: 'STATE.md', extraDetails };
|
|
273
293
|
}
|
|
274
294
|
case REMEDY_ACTION.ADD_NYQUIST_KEY:
|
|
@@ -72,7 +72,7 @@ const INTERFACE_POINTS = Object.freeze(['command', 'dispatch', 'model', 'hooks',
|
|
|
72
72
|
const SAFE_DEFAULTS = {
|
|
73
73
|
embeddingMode: 'declarative',
|
|
74
74
|
commandSurface: 'prose-only',
|
|
75
|
-
dispatch: { namedDispatch: false, nested: false, maxDepth: 0, background: false, subagentToolkit: 'read-only', backgroundDispatch: false, isolation: 'none' },
|
|
75
|
+
dispatch: { namedDispatch: false, nested: false, maxDepth: 0, background: false, subagentToolkit: 'read-only', backgroundDispatch: false, isolation: 'none', maxConcurrency: 1 },
|
|
76
76
|
modelMode: 'passive',
|
|
77
77
|
hookBus: 'none',
|
|
78
78
|
stateIO: 'session-log-append',
|
|
@@ -84,7 +84,7 @@ const PROFILE_BASELINES = Object.freeze({
|
|
|
84
84
|
'programmatic-cli': Object.freeze({
|
|
85
85
|
embeddingMode: 'imperative',
|
|
86
86
|
commandSurface: 'slash-file',
|
|
87
|
-
dispatch: Object.freeze({ namedDispatch: true, nested: true, maxDepth: -1, background: true, subagentToolkit: 'full', backgroundDispatch: true, isolation: 'none' }),
|
|
87
|
+
dispatch: Object.freeze({ namedDispatch: true, nested: true, maxDepth: -1, background: true, subagentToolkit: 'full', backgroundDispatch: true, isolation: 'none', maxConcurrency: 1 }),
|
|
88
88
|
modelMode: 'passive',
|
|
89
89
|
hookBus: 'host',
|
|
90
90
|
stateIO: 'filesystem',
|
|
@@ -95,7 +95,7 @@ const PROFILE_BASELINES = Object.freeze({
|
|
|
95
95
|
'declarative-cli': Object.freeze({
|
|
96
96
|
embeddingMode: 'declarative',
|
|
97
97
|
commandSurface: 'slash-file',
|
|
98
|
-
dispatch: Object.freeze({ namedDispatch: true, nested: false, maxDepth: 1, background: false, subagentToolkit: 'full', backgroundDispatch: false, isolation: 'none' }),
|
|
98
|
+
dispatch: Object.freeze({ namedDispatch: true, nested: false, maxDepth: 1, background: false, subagentToolkit: 'full', backgroundDispatch: false, isolation: 'none', maxConcurrency: 1 }),
|
|
99
99
|
modelMode: 'passive',
|
|
100
100
|
hookBus: 'host',
|
|
101
101
|
stateIO: 'filesystem',
|
|
@@ -106,7 +106,7 @@ const PROFILE_BASELINES = Object.freeze({
|
|
|
106
106
|
'ide': Object.freeze({
|
|
107
107
|
embeddingMode: 'imperative',
|
|
108
108
|
commandSurface: 'palette',
|
|
109
|
-
dispatch: Object.freeze({ namedDispatch: true, nested: true, maxDepth: 5, background: true, subagentToolkit: 'full', backgroundDispatch: true, isolation: 'none' }),
|
|
109
|
+
dispatch: Object.freeze({ namedDispatch: true, nested: true, maxDepth: 5, background: true, subagentToolkit: 'full', backgroundDispatch: true, isolation: 'none', maxConcurrency: 1 }),
|
|
110
110
|
modelMode: 'active',
|
|
111
111
|
hookBus: 'engine',
|
|
112
112
|
stateIO: 'sandboxed-storage',
|
|
@@ -235,7 +235,7 @@ const DEFAULT_ENGINE = {
|
|
|
235
235
|
axes: {
|
|
236
236
|
embeddingMode: 'imperative',
|
|
237
237
|
commandSurface: 'slash-file',
|
|
238
|
-
dispatch: { namedDispatch: true, nested: true, maxDepth: -1, background: true, subagentToolkit: 'full', backgroundDispatch: true, isolation: 'none' },
|
|
238
|
+
dispatch: { namedDispatch: true, nested: true, maxDepth: -1, background: true, subagentToolkit: 'full', backgroundDispatch: true, isolation: 'none', maxConcurrency: 1 },
|
|
239
239
|
modelMode: 'active',
|
|
240
240
|
hookBus: 'host',
|
|
241
241
|
stateIO: 'filesystem',
|
|
@@ -246,6 +246,19 @@ const DEFAULT_ENGINE = {
|
|
|
246
246
|
known: HOST_INTEGRATION_AXES,
|
|
247
247
|
};
|
|
248
248
|
// ---------------------------------------------------------------------------
|
|
249
|
+
// isPositiveSafeInteger — shared predicate (#3673)
|
|
250
|
+
// ---------------------------------------------------------------------------
|
|
251
|
+
/**
|
|
252
|
+
* True iff `v` is a positive (>0) JS safe integer. Single source of truth for
|
|
253
|
+
* the dispatch.maxConcurrency contract: used by negotiateHostCapabilities
|
|
254
|
+
* below, and by gsd-core/bin/gsd-tools.cjs's routeDispatchCapacity (which
|
|
255
|
+
* requires this module's compiled output rather than reimplementing the
|
|
256
|
+
* predicate), so the two consumers cannot silently diverge.
|
|
257
|
+
*/
|
|
258
|
+
function isPositiveSafeInteger(v) {
|
|
259
|
+
return typeof v === 'number' && Number.isSafeInteger(v) && v > 0;
|
|
260
|
+
}
|
|
261
|
+
// ---------------------------------------------------------------------------
|
|
249
262
|
// negotiateHostCapabilities
|
|
250
263
|
// ---------------------------------------------------------------------------
|
|
251
264
|
/**
|
|
@@ -335,6 +348,7 @@ function negotiateHostCapabilities(host, engine = DEFAULT_ENGINE) {
|
|
|
335
348
|
let effectiveSubagentToolkit;
|
|
336
349
|
let effectiveMaxDepth;
|
|
337
350
|
let effectiveIsolation;
|
|
351
|
+
let effectiveMaxConcurrency;
|
|
338
352
|
if (hostDispatch === null) {
|
|
339
353
|
// Host didn't declare dispatch at all — fail-closed to most-restrictive values
|
|
340
354
|
warnings.push(`host did not declare 'dispatch'`);
|
|
@@ -345,6 +359,7 @@ function negotiateHostCapabilities(host, engine = DEFAULT_ENGINE) {
|
|
|
345
359
|
effectiveSubagentToolkit = 'read-only';
|
|
346
360
|
effectiveMaxDepth = 0;
|
|
347
361
|
effectiveIsolation = 'none';
|
|
362
|
+
effectiveMaxConcurrency = 1;
|
|
348
363
|
}
|
|
349
364
|
else {
|
|
350
365
|
// N1: observability warnings for 'undocumented' sentinel on dispatch fields
|
|
@@ -408,6 +423,41 @@ function negotiateHostCapabilities(host, engine = DEFAULT_ENGINE) {
|
|
|
408
423
|
const eDepthNum = engineDispatch.maxDepth < 0 ? Infinity : engineDispatch.maxDepth;
|
|
409
424
|
const minDepth = Math.min(hDepthNum, eDepthNum);
|
|
410
425
|
effectiveMaxDepth = minDepth === Infinity ? -1 : minDepth;
|
|
426
|
+
// maxConcurrency (#3673, ADR-1239 Phase 1): a positive-safe-integer
|
|
427
|
+
// passthrough with a fail-closed floor of 1. UNLIKE maxDepth, there is no
|
|
428
|
+
// min(host, engine) reduction here — the design doc explicitly rejects an
|
|
429
|
+
// engine-side ceiling for this field (no competing intrinsic worker
|
|
430
|
+
// ceiling to cap against at the negotiation layer); a `--jobs N` cap is
|
|
431
|
+
// applied later, at the Phase 4 scheduler.
|
|
432
|
+
const hostMaxConcurrency = hostDispatch.maxConcurrency;
|
|
433
|
+
if (hostMaxConcurrency === UNDOCUMENTED) {
|
|
434
|
+
warnings.push(`dispatch.maxConcurrency is undocumented — degraded closed (1)`);
|
|
435
|
+
effectiveMaxConcurrency = 1;
|
|
436
|
+
}
|
|
437
|
+
else if (isPositiveSafeInteger(hostMaxConcurrency)) {
|
|
438
|
+
effectiveMaxConcurrency = hostMaxConcurrency;
|
|
439
|
+
}
|
|
440
|
+
else if (hostMaxConcurrency === undefined) {
|
|
441
|
+
warnings.push(`host did not declare 'dispatch.maxConcurrency' — treating as 1`);
|
|
442
|
+
effectiveMaxConcurrency = 1;
|
|
443
|
+
}
|
|
444
|
+
else if (typeof hostMaxConcurrency !== 'number') {
|
|
445
|
+
warnings.push(`host dispatch.maxConcurrency is not a number — treating as 1`);
|
|
446
|
+
effectiveMaxConcurrency = 1;
|
|
447
|
+
}
|
|
448
|
+
else if (!Number.isSafeInteger(hostMaxConcurrency)) {
|
|
449
|
+
if (Number.isInteger(hostMaxConcurrency)) {
|
|
450
|
+
warnings.push(`host dispatch.maxConcurrency is an unsafe integer — treating as 1`);
|
|
451
|
+
}
|
|
452
|
+
else {
|
|
453
|
+
warnings.push(`host dispatch.maxConcurrency is not an integer — treating as 1`);
|
|
454
|
+
}
|
|
455
|
+
effectiveMaxConcurrency = 1;
|
|
456
|
+
}
|
|
457
|
+
else {
|
|
458
|
+
warnings.push(`host dispatch.maxConcurrency is non-positive — treating as 1`);
|
|
459
|
+
effectiveMaxConcurrency = 1;
|
|
460
|
+
}
|
|
411
461
|
// If namedDispatch is false, cap maxDepth/nested/background/backgroundDispatch to 0/false/false/false (struct consistency)
|
|
412
462
|
if (!effectiveNamedDispatch) {
|
|
413
463
|
effectiveMaxDepth = 0;
|
|
@@ -424,6 +474,7 @@ function negotiateHostCapabilities(host, engine = DEFAULT_ENGINE) {
|
|
|
424
474
|
subagentToolkit: effectiveSubagentToolkit,
|
|
425
475
|
backgroundDispatch: effectiveBackgroundDispatch,
|
|
426
476
|
isolation: effectiveIsolation,
|
|
477
|
+
maxConcurrency: effectiveMaxConcurrency,
|
|
427
478
|
};
|
|
428
479
|
// ---------------------------------------------------------------------------
|
|
429
480
|
// Assemble effective axes
|
|
@@ -653,10 +704,25 @@ function extensionEventSurfaceFor(extensionEvents) {
|
|
|
653
704
|
* per-host branch ADR-1239 exists to remove. Omit `prompt` entirely and the
|
|
654
705
|
* resolution is byte-identical to Phase 2's (the unconsumed-resolver shape).
|
|
655
706
|
*
|
|
656
|
-
* Argv order is base args → cwd flag → prompt, so the prompt
|
|
657
|
-
* positional token for the hosts that read it that way.
|
|
707
|
+
* Argv order is base args → model flag → cwd flag → prompt, so the prompt
|
|
708
|
+
* stays the final positional token for the hosts that read it that way. The
|
|
709
|
+
* model flag is placed BEFORE the cwd flag (not after, and not appended at
|
|
710
|
+
* the very end) purely to keep it clear of that trailing positional — the
|
|
711
|
+
* model value itself is never the prompt-adjacent token a host might scan
|
|
712
|
+
* for last.
|
|
713
|
+
*
|
|
714
|
+
* `model` (Phase 4, #3714) is optional, descriptor-gated exactly like prompt:
|
|
715
|
+
* a `modelFlag` string on the descriptor names the flag that pins the
|
|
716
|
+
* spawned executor's model (codex: `--model`); `null`/absent means the host
|
|
717
|
+
* exposes no such override on this exec path, and `[modelFlag, model]` is
|
|
718
|
+
* appended ONLY when both the descriptor's `modelFlag` and the caller's
|
|
719
|
+
* `model` are non-empty strings. Omitting `model` entirely (or passing it to
|
|
720
|
+
* a host with no `modelFlag`) is byte-identical to the resolver's behavior
|
|
721
|
+
* before this parameter existed. This function decides no policy about WHICH
|
|
722
|
+
* model to pass or what 'inherit' means — that is entirely the caller's job;
|
|
723
|
+
* this seam only shapes descriptor + values into argv.
|
|
658
724
|
*/
|
|
659
|
-
function resolveOrchestratorExec(orchestratorExec, cwd, prompt) {
|
|
725
|
+
function resolveOrchestratorExec(orchestratorExec, cwd, prompt, model) {
|
|
660
726
|
if (!orchestratorExec || typeof orchestratorExec !== 'object' || Array.isArray(orchestratorExec)) {
|
|
661
727
|
return { ok: false, reason: 'missing_command' };
|
|
662
728
|
}
|
|
@@ -676,11 +742,22 @@ function resolveOrchestratorExec(orchestratorExec, cwd, prompt) {
|
|
|
676
742
|
if (oe.promptFlag !== undefined && oe.promptFlag !== null && typeof oe.promptFlag !== 'string') {
|
|
677
743
|
return { ok: false, reason: 'invalid_prompt_flag' };
|
|
678
744
|
}
|
|
745
|
+
if (oe.modelFlag !== undefined && oe.modelFlag !== null && typeof oe.modelFlag !== 'string') {
|
|
746
|
+
return { ok: false, reason: 'invalid_model_flag' };
|
|
747
|
+
}
|
|
679
748
|
// An executor spawned with no instruction is a hang, not a degraded run —
|
|
680
749
|
// fail closed rather than launching a prompt-less process.
|
|
681
750
|
if (prompt !== undefined && (typeof prompt !== 'string' || prompt.length === 0)) {
|
|
682
751
|
return { ok: false, reason: 'invalid_prompt' };
|
|
683
752
|
}
|
|
753
|
+
// Unlike `prompt` — where empty is a hang, not a degraded run, hence the
|
|
754
|
+
// fail-closed check above — an absent/null/empty model is simply "use the
|
|
755
|
+
// host default", the same benign degradation `cwdFlag: null` already
|
|
756
|
+
// expresses. Only a present-but-non-string value (number/bool/array/object)
|
|
757
|
+
// is a caller error; null/undefined/'' fall through to "omit the flag".
|
|
758
|
+
if (model !== undefined && model !== null && typeof model !== 'string') {
|
|
759
|
+
return { ok: false, reason: 'invalid_model' };
|
|
760
|
+
}
|
|
684
761
|
// Leading-dash guard, mirroring worktree-safety.cts's `unsafe_leading_dash`
|
|
685
762
|
// check on git arguments. A positional prompt (or a cwd) beginning with '-'
|
|
686
763
|
// is parsed by the spawned CLI as a FLAG, not a value — the same failure the
|
|
@@ -695,10 +772,17 @@ function resolveOrchestratorExec(orchestratorExec, cwd, prompt) {
|
|
|
695
772
|
if (cwd.startsWith('-')) {
|
|
696
773
|
return { ok: false, reason: 'unsafe_leading_dash_cwd' };
|
|
697
774
|
}
|
|
775
|
+
if (typeof model === 'string' && model.startsWith('-')) {
|
|
776
|
+
return { ok: false, reason: 'unsafe_leading_dash_model' };
|
|
777
|
+
}
|
|
698
778
|
const baseArgs = Array.isArray(oe.args) ? [...oe.args] : [];
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
779
|
+
let args = baseArgs;
|
|
780
|
+
if (typeof oe.modelFlag === 'string' && oe.modelFlag.length > 0 && typeof model === 'string' && model.length > 0) {
|
|
781
|
+
args = [...args, oe.modelFlag, model];
|
|
782
|
+
}
|
|
783
|
+
args = typeof oe.cwdFlag === 'string' && oe.cwdFlag.length > 0
|
|
784
|
+
? [...args, oe.cwdFlag, cwd]
|
|
785
|
+
: args;
|
|
702
786
|
if (typeof prompt === 'string') {
|
|
703
787
|
if (typeof oe.promptFlag === 'string' && oe.promptFlag.length > 0) {
|
|
704
788
|
args.push(oe.promptFlag, prompt);
|
|
@@ -720,6 +804,7 @@ module.exports = {
|
|
|
720
804
|
EXTENSION_EVENT_SURFACES,
|
|
721
805
|
degradationFor,
|
|
722
806
|
profileOf,
|
|
807
|
+
isPositiveSafeInteger,
|
|
723
808
|
negotiateHostCapabilities,
|
|
724
809
|
shouldFlattenDispatch,
|
|
725
810
|
resolveDispatchType,
|