@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
|
@@ -63,7 +63,19 @@ function countRoadmapPhases(roadmapPath, fallbackCount, cwd, ws, versionOverride
|
|
|
63
63
|
return fallbackCount;
|
|
64
64
|
if (!cwd)
|
|
65
65
|
return fallbackCount;
|
|
66
|
-
|
|
66
|
+
// #2761 B1 (trek-e review): `undefined`, NOT `null`. The third argument
|
|
67
|
+
// discriminates "not resolved yet — resolve it from this workstream's
|
|
68
|
+
// config" (`undefined`) from "resolved, and it is not bracket" (`null`).
|
|
69
|
+
// This site meant the former and spelled the latter, so a workstream that
|
|
70
|
+
// opted into `phase_id_convention: "bracket"` had its ROADMAP scanned with
|
|
71
|
+
// the LEGACY grammar: the heading set came back empty, `phaseCount` was 0,
|
|
72
|
+
// and the count silently fell back to the on-disk directory count — the
|
|
73
|
+
// very degrade the #3185 rewrite of this function existed to remove.
|
|
74
|
+
// Measured on a bracket workstream whose milestone declares 3 phases:
|
|
75
|
+
// `null` -> 0 (fallback), `undefined` -> 3. A non-bracket workstream
|
|
76
|
+
// resolves to a value that compiles the same base grammar `null` did, so
|
|
77
|
+
// its count is unchanged (verified against a legacy control).
|
|
78
|
+
const filter = getMilestonePhaseFilter(cwd, versionOverride ?? null, undefined, ws ?? null);
|
|
67
79
|
// A pass-all degrade (phaseCount 0) means the window declared no phases —
|
|
68
80
|
// fall back rather than reporting a confident zero.
|
|
69
81
|
return filter.phaseCount > 0 ? filter.phaseCount : fallbackCount;
|
|
@@ -437,7 +449,13 @@ function inspectWorkstream(cwd, name, options = {}) {
|
|
|
437
449
|
// filtering. Consulted only when it is genuinely scoped to a single milestone
|
|
438
450
|
// (`versionScoped`); the unversioned whole-roadmap shape spans the project's
|
|
439
451
|
// lifetime and would re-admit prior-milestone phases — the very defect here.
|
|
440
|
-
|
|
452
|
+
//
|
|
453
|
+
// #2761 B1 (trek-e review): `undefined`, not `null` — same discriminator fix
|
|
454
|
+
// as `countRoadmapPhases` above. This site iterates workstreams by NAME, so
|
|
455
|
+
// it is exactly the caller that cannot set `GSD_WORKSTREAM`; spelling `null`
|
|
456
|
+
// pinned every workstream to the legacy grammar and made `headingScoped`
|
|
457
|
+
// unreachable (`phaseCount > 0` never held) on a bracket workstream.
|
|
458
|
+
const headingFilter = getMilestonePhaseFilter(cwd, currentVersion, undefined, name);
|
|
441
459
|
const headingScoped = headingFilter.versionScoped && headingFilter.phaseCount > 0;
|
|
442
460
|
// Phase keys the ROADMAP attributes to some OTHER milestone. A row carrying an
|
|
443
461
|
// explicit version that is not the current one is a positive claim by a prior
|
|
@@ -6,6 +6,24 @@
|
|
|
6
6
|
* byte-for-behaviour from the prior hand-written .cjs; only types are added.
|
|
7
7
|
*
|
|
8
8
|
* Used by active-workstream-store.cjs, planning-workspace.cjs, workstream.cjs.
|
|
9
|
+
*
|
|
10
|
+
* #3883 (ADR-3473 §8.3): toWorkstreamSlug delegates to core-utils.cjs's
|
|
11
|
+
* generateSlugInternal (the canonical slug formula), passing `maxLen: null`
|
|
12
|
+
* to preserve this site's pre-migration untruncated contract — the 60-char
|
|
13
|
+
* default collided distinct >60-char workstream names onto the same slug
|
|
14
|
+
* (verified: `"a".repeat(60)+"alpha"` and `"a".repeat(60)+"beta"` truncated
|
|
15
|
+
* identically). core-utils.cjs already
|
|
16
|
+
* requires (transitively, at module-init time) THIS module:
|
|
17
|
+
* core-utils.cjs -> planning-workspace.cjs -> active-workstream-store.cjs ->
|
|
18
|
+
* workstream-name-policy.cjs. A top-level require of core-utils.cjs here
|
|
19
|
+
* would therefore close that cycle and — per this codebase's compiled-.cjs
|
|
20
|
+
* convention of a single `module.exports = {...}` reassignment at the bottom
|
|
21
|
+
* of core-utils.cjs — capture a stale, still-empty exports object forever
|
|
22
|
+
* (verified live: "generateSlugInternal is not a function" whichever module
|
|
23
|
+
* loads first). The require is deferred (lazy, inside toWorkstreamSlug's
|
|
24
|
+
* body) instead, mirroring the same cycle-break already used by
|
|
25
|
+
* core-utils.cts's own getPhaseFileStats/plan-scan.cjs seam and by
|
|
26
|
+
* phase-id.cts's toDir/getPhaseDirFromPhaseId.
|
|
9
27
|
*/
|
|
10
28
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
11
29
|
exports.INVALID_ACTIVE_WORKSTREAM_NAME_MESSAGE = void 0;
|
|
@@ -68,10 +86,13 @@ function validateWorkstreamName(name) {
|
|
|
68
86
|
* Lowercases, collapses non-alphanumeric runs to hyphens, strips leading/trailing hyphens.
|
|
69
87
|
*/
|
|
70
88
|
function toWorkstreamSlug(name) {
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
89
|
+
// #3883 (ADR-3473 §8.3): delegate to the canonical slug formula
|
|
90
|
+
// (generateSlugInternal, core-utils.cts) rather than re-implementing it —
|
|
91
|
+
// this call site previously diverged from it (no transliteration, no
|
|
92
|
+
// 60-char truncation). Lazy require to break the core-utils.cjs cycle
|
|
93
|
+
// (see the module dependency doc comment above).
|
|
94
|
+
// eslint-disable-next-line @typescript-eslint/no-require-imports, @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-call
|
|
95
|
+
return require('./core-utils.cjs').generateSlugInternal(String(name ?? ''), null) ?? '';
|
|
75
96
|
}
|
|
76
97
|
/**
|
|
77
98
|
* Returns true when `name` is a valid active workstream name:
|
|
@@ -94,10 +94,13 @@ function parseJsonc(text) {
|
|
|
94
94
|
}
|
|
95
95
|
// ─── Message constants (verbatim — downstream docs/tests depend on these) ─────
|
|
96
96
|
function buildMsgDiverged(headSha, forkRef, forkSha) {
|
|
97
|
-
return `⚠ Worktree base mismatch: HEAD (${shortSha(headSha)}) differs from ${forkRef} (${shortSha(forkSha)}). Running this phase sequentially on the main working tree.
|
|
97
|
+
return `⚠ Worktree base mismatch: HEAD (${shortSha(headSha)}) differs from ${forkRef} (${shortSha(forkSha)}). Running this phase sequentially on the main working tree. Parallel worktrees return once HEAD is merged/pushed so ${forkRef} matches it. (worktree.baseRef:"head" applies only where GSD itself creates the worktree — the runtime harness does not read it; #48, #3659.)`;
|
|
98
98
|
}
|
|
99
|
-
const MSG_UNKNOWN = `⚠ Cannot determine the worktree fork base (origin/HEAD unresolved). Running this phase sequentially on the main working tree to avoid a base mismatch.
|
|
100
|
-
|
|
99
|
+
const MSG_UNKNOWN = `⚠ Cannot determine the worktree fork base (origin/HEAD unresolved). Running this phase sequentially on the main working tree to avoid a base mismatch. Parallel worktrees return once origin/HEAD resolves and matches HEAD. See #683, #3659.`;
|
|
100
|
+
function buildMsgBaserefHeadIgnored(headSha, forkRef, forkSha) {
|
|
101
|
+
return `⚠ Worktree base mismatch: worktree.baseRef:"head" is set, but the runtime harness does not honor it for isolated dispatch — the fork base stays ${forkRef} (${shortSha(forkSha)}) while HEAD is ${shortSha(headSha)} (#48; upstream claude-code#44965). Running this phase sequentially on the main working tree. Parallel worktrees return once HEAD is merged/pushed so ${forkRef} matches it, or on runtimes where GSD itself manages worktree creation. See #3659.`;
|
|
102
|
+
}
|
|
103
|
+
const MSG_HEAD_UNRESOLVABLE = `⚠ Cannot determine the worktree base (git rev-parse HEAD did not return a definitive answer). Running this phase sequentially on the main working tree to avoid an unverified base mismatch. Note: worktree.baseRef:"head" silences this check only where GSD itself creates the worktree (orchestrator-managed runtimes) — in harness mode it never applied (#48, #3659). Retry; if it persists, check for a stalled filesystem mount or a stale git index lock (.git/index.lock). See #683, #3050.`;
|
|
101
104
|
/**
|
|
102
105
|
* Returns true when an execGit result indicates the subprocess was killed by
|
|
103
106
|
* a timeout. A timeout means the command genuinely could not complete — it
|
|
@@ -228,7 +231,20 @@ function resolveEffectiveBaseRef(claudeDir, deps, userClaudeDir) {
|
|
|
228
231
|
* deps.userClaudeDir overrides the user/global config directory resolution
|
|
229
232
|
* (default: getGlobalConfigDir('claude'), which honours CLAUDE_CONFIG_DIR).
|
|
230
233
|
*/
|
|
231
|
-
function cmdWorktreeBaseCheck(cwd,
|
|
234
|
+
function cmdWorktreeBaseCheck(cwd, args, deps) {
|
|
235
|
+
// --mode threads the dispatch isolation mode through to the evaluation
|
|
236
|
+
// (#3659): 'harness-worktree' (default) or 'orchestrator-worktree'. Invalid
|
|
237
|
+
// or missing values after --mode fail closed — a silently defaulted typo
|
|
238
|
+
// would re-open the hole the flag exists to close.
|
|
239
|
+
let isolationMode = 'harness-worktree';
|
|
240
|
+
const modeIdx = args.indexOf('--mode');
|
|
241
|
+
if (modeIdx !== -1) {
|
|
242
|
+
const value = args[modeIdx + 1];
|
|
243
|
+
if (value !== 'harness-worktree' && value !== 'orchestrator-worktree') {
|
|
244
|
+
throw new Error(`worktree base-check: --mode must be harness-worktree or orchestrator-worktree, got ${JSON.stringify(value ?? null)}`);
|
|
245
|
+
}
|
|
246
|
+
isolationMode = value;
|
|
247
|
+
}
|
|
232
248
|
const claudeDir = node_path_1.default.join(cwd, '.claude');
|
|
233
249
|
const userClaudeDir = Object.prototype.hasOwnProperty.call(deps ?? {}, 'userClaudeDir')
|
|
234
250
|
? deps.userClaudeDir
|
|
@@ -238,8 +254,22 @@ function cmdWorktreeBaseCheck(cwd, _args, deps) {
|
|
|
238
254
|
cwd,
|
|
239
255
|
effectiveBaseRef,
|
|
240
256
|
execGit: deps?.execGit,
|
|
257
|
+
isolationMode,
|
|
258
|
+
});
|
|
259
|
+
// Default emit goes through fs.writeSync(1, …), NOT process.stdout.write:
|
|
260
|
+
// the CLI's --pick capture intercepts writeSync, and command substitution
|
|
261
|
+
// is a pipe — via process.stdout.write a `$(gsd-tools … --pick x)` capture
|
|
262
|
+
// received the full JSON instead of the picked field, so the workflow
|
|
263
|
+
// auto-degrade guards never matched (#3659 review). Short-count loop per
|
|
264
|
+
// io.cjs writeAllSync's rationale (a non-blocking pipe can accept partial
|
|
265
|
+
// writes).
|
|
266
|
+
const write = deps?.write ?? ((s) => {
|
|
267
|
+
const buf = Buffer.from(s, 'utf8');
|
|
268
|
+
let offset = 0;
|
|
269
|
+
while (offset < buf.length) {
|
|
270
|
+
offset += node_fs_1.default.writeSync(1, buf, offset, buf.length - offset);
|
|
271
|
+
}
|
|
241
272
|
});
|
|
242
|
-
const write = deps?.write ?? ((s) => process.stdout.write(s));
|
|
243
273
|
write(JSON.stringify(result, null, 2) + '\n');
|
|
244
274
|
return result;
|
|
245
275
|
}
|
|
@@ -295,7 +325,20 @@ function cmdWorktreeSetBaseRef(cwd, _args, deps) {
|
|
|
295
325
|
baseRef: 'head',
|
|
296
326
|
file,
|
|
297
327
|
};
|
|
298
|
-
|
|
328
|
+
// Default emit goes through fs.writeSync(1, …), NOT process.stdout.write:
|
|
329
|
+
// the CLI's --pick capture intercepts writeSync, and command substitution
|
|
330
|
+
// is a pipe — via process.stdout.write a `$(gsd-tools … --pick x)` capture
|
|
331
|
+
// received the full JSON instead of the picked field, so the workflow
|
|
332
|
+
// auto-degrade guards never matched (#3659 review). Short-count loop per
|
|
333
|
+
// io.cjs writeAllSync's rationale (a non-blocking pipe can accept partial
|
|
334
|
+
// writes).
|
|
335
|
+
const write = deps?.write ?? ((s) => {
|
|
336
|
+
const buf = Buffer.from(s, 'utf8');
|
|
337
|
+
let offset = 0;
|
|
338
|
+
while (offset < buf.length) {
|
|
339
|
+
offset += node_fs_1.default.writeSync(1, buf, offset, buf.length - offset);
|
|
340
|
+
}
|
|
341
|
+
});
|
|
299
342
|
write(JSON.stringify(output, null, 2) + '\n');
|
|
300
343
|
return output;
|
|
301
344
|
}
|
|
@@ -311,12 +354,19 @@ function evaluateWorktreeBaseDegrade(deps) {
|
|
|
311
354
|
const execGit = deps?.execGit ?? shell_command_projection_cjs_1.execGit;
|
|
312
355
|
const cwd = deps?.cwd;
|
|
313
356
|
const cwdOpts = cwd ? { cwd } : {};
|
|
314
|
-
// a.
|
|
315
|
-
//
|
|
316
|
-
//
|
|
317
|
-
//
|
|
318
|
-
//
|
|
319
|
-
|
|
357
|
+
// a. baseRef 'head' suppresses ONLY where GSD controls the fork start-point
|
|
358
|
+
// (#3659). The former unconditional suppress trusted the harness to honor the
|
|
359
|
+
// setting; #48 verified 5/5 that the Agent-isolation dispatch path never
|
|
360
|
+
// routes through project settings (upstream claude-code#44965), so in
|
|
361
|
+
// harness mode the fork base is always origin/HEAD and 'head' must fall
|
|
362
|
+
// through to the same comparison the fresh path runs. In
|
|
363
|
+
// orchestrator-worktree mode GSD itself runs `git worktree add <path>
|
|
364
|
+
// <start-point>` with the orchestrator HEAD — 'head' is honored by
|
|
365
|
+
// construction there and the suppress is correct. Any non-"head" value
|
|
366
|
+
// (including "fresh" and absent/null) has fresh/origin-HEAD semantics and is
|
|
367
|
+
// evaluated against origin/HEAD as before. (Reference: #683, #48, #3659.)
|
|
368
|
+
const headIgnoredByHarness = deps?.effectiveBaseRef === 'head';
|
|
369
|
+
if (headIgnoredByHarness && (deps?.isolationMode ?? 'harness-worktree') === 'orchestrator-worktree') {
|
|
320
370
|
return { shouldDegrade: false, reason: 'baseref-head', message: null, headSha: null, forkRef: null, forkSha: null, headAbsenceVerified: null };
|
|
321
371
|
}
|
|
322
372
|
// b. Resolve HEAD sha.
|
|
@@ -389,6 +439,10 @@ function evaluateWorktreeBaseDegrade(deps) {
|
|
|
389
439
|
if (forkSha === headSha) {
|
|
390
440
|
return { shouldDegrade: false, reason: 'head-matches-fork', message: null, headSha, forkRef, forkSha, headAbsenceVerified: null };
|
|
391
441
|
}
|
|
442
|
+
if (headIgnoredByHarness) {
|
|
443
|
+
const message = buildMsgBaserefHeadIgnored(headSha, forkRef, forkSha);
|
|
444
|
+
return { shouldDegrade: true, reason: 'baseref-head-ignored-by-harness', message, headSha, forkRef, forkSha, headAbsenceVerified: null };
|
|
445
|
+
}
|
|
392
446
|
const message = buildMsgDiverged(headSha, forkRef, forkSha);
|
|
393
447
|
return { shouldDegrade: true, reason: 'head-diverged-from-fork', message, headSha, forkRef, forkSha, headAbsenceVerified: null };
|
|
394
448
|
}
|
|
@@ -374,6 +374,12 @@ function normalizeCleanupManifestEntry(entry) {
|
|
|
374
374
|
// would make an unrecorded plan look 100% out of scope.
|
|
375
375
|
const filesModified = (Array.isArray(e.files_modified) ? e.files_modified : [])
|
|
376
376
|
.filter((f) => typeof f === 'string' && f.trim().length > 0);
|
|
377
|
+
// #3003: same liberal-in-what-we-accept rule as `files_modified` above — non-array,
|
|
378
|
+
// or non-string / empty elements, are dropped rather than coerced, and an EMPTY
|
|
379
|
+
// result omits the field entirely so "declares nothing" stays indistinguishable
|
|
380
|
+
// from "not recorded" (the guard's own absence-check already treats both as unknown).
|
|
381
|
+
const declaredDeletions = (Array.isArray(e.declared_deletions) ? e.declared_deletions : [])
|
|
382
|
+
.filter((f) => typeof f === 'string' && f.trim().length > 0);
|
|
377
383
|
const normalized = {
|
|
378
384
|
agent_id: typeof e.agent_id === 'string' ? e.agent_id : null,
|
|
379
385
|
worktree_path: worktreePath,
|
|
@@ -383,6 +389,8 @@ function normalizeCleanupManifestEntry(entry) {
|
|
|
383
389
|
};
|
|
384
390
|
if (filesModified.length > 0)
|
|
385
391
|
normalized.files_modified = filesModified;
|
|
392
|
+
if (declaredDeletions.length > 0)
|
|
393
|
+
normalized.declared_deletions = declaredDeletions;
|
|
386
394
|
return normalized;
|
|
387
395
|
}
|
|
388
396
|
function normalizeCleanupManifest(manifest) {
|
|
@@ -480,16 +488,84 @@ function repoRootStillMidMerge(execGit, repoRoot) {
|
|
|
480
488
|
// advisory fire on essentially every wave.
|
|
481
489
|
const SUMMARY_ARTIFACT_DIR = '.planning';
|
|
482
490
|
const SUMMARY_ARTIFACT_SUFFIX = 'SUMMARY.md';
|
|
491
|
+
/**
|
|
492
|
+
* Decode a git-quoted path. With `core.quotepath` left at its default (`true`)
|
|
493
|
+
* git wraps any path containing non-ASCII or special bytes in double quotes
|
|
494
|
+
* and C-escapes it — e.g. `tests/é.ts` is emitted as the literal
|
|
495
|
+
* `"tests/\303\251.ts"`. Both sides of the deletion/scope comparison
|
|
496
|
+
* (a declared path and a git-reported path) must agree on the same decoded
|
|
497
|
+
* shape, and decoding it here — rather than passing `-c core.quotepath=false`
|
|
498
|
+
* on the `execGit` call — keeps the git argv, and therefore every existing
|
|
499
|
+
* test fixture that asserts on exact argv, unchanged. It also works
|
|
500
|
+
* regardless of the user's own `core.quotepath` config.
|
|
501
|
+
*
|
|
502
|
+
* A value that is not wrapped in a leading and trailing `"` is returned
|
|
503
|
+
* completely untouched — this is the overwhelmingly common (plain ASCII)
|
|
504
|
+
* case and must not be altered in any way.
|
|
505
|
+
*
|
|
506
|
+
* Escapes decode to BYTES, collected into a Buffer and decoded as UTF-8 only
|
|
507
|
+
* at the end: `\303\251` is two bytes that together form one character (é),
|
|
508
|
+
* so decoding them one at a time would produce mojibake. Malformed input
|
|
509
|
+
* (a trailing lone backslash, or an octal escape with fewer than three
|
|
510
|
+
* digits) never throws — it degrades to treating the character literally, so
|
|
511
|
+
* a single bad path can never take down the whole cleanup wave.
|
|
512
|
+
*
|
|
513
|
+
* Exported (#4081) so the codebase-drift gate's `--name-status` parser can
|
|
514
|
+
* decode the identical C-quoted form before classifying paths — the gate's
|
|
515
|
+
* `execGit` call sets no `core.quotepath` config, so it receives the same
|
|
516
|
+
* quoting and must decode it with the same single owner of this seam.
|
|
517
|
+
*/
|
|
518
|
+
function decodeGitQuotedPath(raw) {
|
|
519
|
+
if (raw.length < 2 || !raw.startsWith('"') || !raw.endsWith('"'))
|
|
520
|
+
return raw;
|
|
521
|
+
const body = raw.slice(1, -1);
|
|
522
|
+
const bytes = [];
|
|
523
|
+
for (let i = 0; i < body.length; i++) {
|
|
524
|
+
const ch = body[i];
|
|
525
|
+
if (ch !== '\\' || i === body.length - 1) {
|
|
526
|
+
// UTF-8 bytes, not the code unit: a DECLARED path may be quoted while
|
|
527
|
+
// still holding a literal `é`, and pushing 0xE9 alone is invalid UTF-8.
|
|
528
|
+
// codePointAt keeps a surrogate pair together.
|
|
529
|
+
const codePoint = body.codePointAt(i);
|
|
530
|
+
const char = codePoint === undefined ? ch : String.fromCodePoint(codePoint);
|
|
531
|
+
bytes.push(...Buffer.from(char, 'utf8'));
|
|
532
|
+
i += char.length - 1;
|
|
533
|
+
continue;
|
|
534
|
+
}
|
|
535
|
+
const rest = body.slice(i + 1);
|
|
536
|
+
const octalMatch = /^([0-3][0-7][0-7])/.exec(rest);
|
|
537
|
+
if (octalMatch) {
|
|
538
|
+
bytes.push(parseInt(octalMatch[1], 8));
|
|
539
|
+
i += 3;
|
|
540
|
+
continue;
|
|
541
|
+
}
|
|
542
|
+
const next = body[i + 1];
|
|
543
|
+
const CONTROL_ESCAPES = {
|
|
544
|
+
a: 0x07, b: 0x08, f: 0x0c, n: 0x0a, r: 0x0d, t: 0x09, v: 0x0b,
|
|
545
|
+
'\\': 0x5c, '"': 0x22,
|
|
546
|
+
};
|
|
547
|
+
if (Object.prototype.hasOwnProperty.call(CONTROL_ESCAPES, next)) {
|
|
548
|
+
bytes.push(CONTROL_ESCAPES[next]);
|
|
549
|
+
}
|
|
550
|
+
else {
|
|
551
|
+
bytes.push(next.charCodeAt(0));
|
|
552
|
+
}
|
|
553
|
+
i += 1;
|
|
554
|
+
}
|
|
555
|
+
return Buffer.from(bytes).toString('utf8');
|
|
556
|
+
}
|
|
483
557
|
/**
|
|
484
558
|
* Normalize one path for scope comparison. Applied to BOTH sides so a declared
|
|
485
|
-
* path and a git-reported path meet in the same shape:
|
|
486
|
-
*
|
|
487
|
-
*
|
|
488
|
-
*
|
|
489
|
-
*
|
|
559
|
+
* path and a git-reported path meet in the same shape: any git C-quoting is
|
|
560
|
+
* decoded first (order matters — the backslash-to-slash conversion below
|
|
561
|
+
* would destroy the escape sequences if it ran first), then backslashes
|
|
562
|
+
* become slashes unconditionally (a backslash path is not a Windows-only
|
|
563
|
+
* input), and a leading `./` and any trailing `/` are stripped. This is the
|
|
564
|
+
* single normalizer shared by the SUMMARY-artifact predicate and the scope
|
|
565
|
+
* advisory, so the two can never disagree about what `./a\b/` means.
|
|
490
566
|
*/
|
|
491
567
|
function normalizeScopePath(raw) {
|
|
492
|
-
return String(raw || '')
|
|
568
|
+
return decodeGitQuotedPath(String(raw || '').trim())
|
|
493
569
|
.replace(/\\/g, '/')
|
|
494
570
|
.trim()
|
|
495
571
|
.replace(/^\.\//, '')
|
|
@@ -703,6 +779,42 @@ function planWaveScopeConformance(changedPaths, declaredFiles, branch) {
|
|
|
703
779
|
}
|
|
704
780
|
return warnings;
|
|
705
781
|
}
|
|
782
|
+
/**
|
|
783
|
+
* #3003: split git's reported deletions into declared and undeclared.
|
|
784
|
+
*
|
|
785
|
+
* EXACT match after `normalizeScopePath` — the same normalizer both other path
|
|
786
|
+
* comparisons in this file use, so a declared path and a git-reported path meet in the
|
|
787
|
+
* same shape (`a\b` and `./a/b/` both become `a/b`).
|
|
788
|
+
*
|
|
789
|
+
* Deliberately NOT `declaredScopePrefix`. That helper returns `null` for a glob-leading
|
|
790
|
+
* pattern meaning "matches everything", which is right for the ADVISORY it serves — a
|
|
791
|
+
* false alarm there costs more than a miss — and exactly wrong for a GATE, where it would
|
|
792
|
+
* let `["*.ts"]` disarm the guard. A glob here is simply a literal path that matches
|
|
793
|
+
* nothing. Prefix matching is likewise refused: `["tests"]` must not authorize deleting
|
|
794
|
+
* everything under tests/.
|
|
795
|
+
*
|
|
796
|
+
* Pure — no git, no IO. Returns the undeclared residue in the order git reported it.
|
|
797
|
+
*/
|
|
798
|
+
function partitionDeclaredDeletions(deletedPaths, declared) {
|
|
799
|
+
const allowed = new Set((Array.isArray(declared) ? declared : [])
|
|
800
|
+
.filter((p) => typeof p === 'string')
|
|
801
|
+
.map((p) => normalizeScopePath(p))
|
|
802
|
+
.filter((p) => p.length > 0));
|
|
803
|
+
const undeclared = [];
|
|
804
|
+
const seen = new Set();
|
|
805
|
+
for (const raw of Array.isArray(deletedPaths) ? deletedPaths : []) {
|
|
806
|
+
if (typeof raw !== 'string')
|
|
807
|
+
continue;
|
|
808
|
+
const normalized = normalizeScopePath(raw);
|
|
809
|
+
if (!normalized || seen.has(normalized))
|
|
810
|
+
continue;
|
|
811
|
+
seen.add(normalized);
|
|
812
|
+
if (allowed.has(normalized))
|
|
813
|
+
continue;
|
|
814
|
+
undeclared.push(normalized);
|
|
815
|
+
}
|
|
816
|
+
return undeclared;
|
|
817
|
+
}
|
|
706
818
|
function executeWorktreeWaveCleanupPlan(plan, deps = {}) {
|
|
707
819
|
const execGit = deps.execGit || execGitDefault;
|
|
708
820
|
const entries = Array.isArray(plan?.entries) ? plan.entries : [];
|
|
@@ -762,13 +874,17 @@ function executeWorktreeWaveCleanupPlan(plan, deps = {}) {
|
|
|
762
874
|
continue; // #2852: isolate
|
|
763
875
|
}
|
|
764
876
|
if (deletions.stdout) {
|
|
765
|
-
//
|
|
766
|
-
//
|
|
767
|
-
//
|
|
768
|
-
//
|
|
769
|
-
//
|
|
770
|
-
|
|
771
|
-
|
|
877
|
+
// #3003: a deletion the PLAN declared is authorized; anything else still blocks.
|
|
878
|
+
// Only a SUCCESSFUL check reaches here — a failed one blocked above on its own
|
|
879
|
+
// reason, so a broken check can never be filtered into a pass.
|
|
880
|
+
//
|
|
881
|
+
// The block detail carries ONLY the undeclared residue. Listing declared paths
|
|
882
|
+
// there would misdirect the operator toward paths that were fine.
|
|
883
|
+
const undeclaredDeletions = partitionDeclaredDeletions(deletions.stdout.split('\n'), entry.declared_deletions);
|
|
884
|
+
if (undeclaredDeletions.length > 0) {
|
|
885
|
+
blockEntry(result, 'branch_contains_deletions', undeclaredDeletions.join('\n'));
|
|
886
|
+
continue; // #2852: isolate
|
|
887
|
+
}
|
|
772
888
|
}
|
|
773
889
|
// #2596: advisory scope conformance — does the branch's ACTUAL committed
|
|
774
890
|
// diff stay inside the scope the plan declared? Gated on a declared scope
|
|
@@ -779,13 +895,34 @@ function executeWorktreeWaveCleanupPlan(plan, deps = {}) {
|
|
|
779
895
|
// ADVISORY ONLY. Unlike the deletions check above, a finding here does NOT
|
|
780
896
|
// call blockEntry and does NOT touch `ok` — the merge proceeds. Promotion
|
|
781
897
|
// to a hard gate is a separate, disclosed change.
|
|
782
|
-
|
|
898
|
+
// #3003: a declared deletion is in scope by construction — `git diff --name-only`
|
|
899
|
+
// includes deleted paths, so without accounting for the declaration, authorizing a
|
|
900
|
+
// deletion would immediately warn that the same path is out of declared scope.
|
|
901
|
+
//
|
|
902
|
+
// It is SUBTRACTED from the findings rather than UNIONED into the declared scope,
|
|
903
|
+
// and the difference is not cosmetic. `planWaveScopeConformance` reads its scope
|
|
904
|
+
// list with prefix-and-glob semantics, so unioning would silently hand
|
|
905
|
+
// `declared_deletions` a second, WIDER matching rule than the gate gives it:
|
|
906
|
+
// `["*.md"]` (inert at the gate) would yield a null prefix meaning "matches
|
|
907
|
+
// everything" and mute the advisory entirely, and `["src"]` would mute all of
|
|
908
|
+
// `src/`. One field with two matching rules is a trap. Subtracting keeps the
|
|
909
|
+
// field exact-match-only on every surface it touches.
|
|
910
|
+
//
|
|
911
|
+
// Gating stays on `files_modified` alone for the same reason: a plan that declares
|
|
912
|
+
// only deletions has still declared no modification scope, so the advisory stays
|
|
913
|
+
// exactly as silent as it was before this change instead of warning on every
|
|
914
|
+
// modified path.
|
|
915
|
+
const declaredFiles = Array.isArray(entry.files_modified) ? entry.files_modified : [];
|
|
916
|
+
if (declaredFiles.length > 0) {
|
|
783
917
|
const scopeDiff = execGit(['diff', '--name-only', `HEAD...${entry.branch}`], { cwd: plan.repoRoot });
|
|
784
918
|
const scopeWarnings = !gitResultOk(scopeDiff)
|
|
785
919
|
// A broken advisory must never become a gate: record that conformance
|
|
786
920
|
// is unknown rather than blocking (or, worse, silently passing).
|
|
787
921
|
? [{ code: WAVE_CLEANUP_WARNING.SCOPE_CHECK_UNAVAILABLE, branch: entry.branch, path: null }]
|
|
788
|
-
: planWaveScopeConformance((scopeDiff.stdout || '').split('\n'),
|
|
922
|
+
: planWaveScopeConformance((scopeDiff.stdout || '').split('\n'), declaredFiles, entry.branch)
|
|
923
|
+
// A path-less warning (SCOPE_CHECK_UNAVAILABLE) is never subtracted.
|
|
924
|
+
.filter((w) => w.path === null
|
|
925
|
+
|| partitionDeclaredDeletions([w.path], entry.declared_deletions).length > 0);
|
|
789
926
|
result.warnings.push(...scopeWarnings);
|
|
790
927
|
allWarnings.push(...scopeWarnings);
|
|
791
928
|
}
|
|
@@ -973,12 +1110,16 @@ function planWorktreeRecordAgent(manifestRaw, fields) {
|
|
|
973
1110
|
// 2. Shared validation: run the candidate through the reader's normalizer.
|
|
974
1111
|
// If it returns null the reader would drop this entry on read — reject now.
|
|
975
1112
|
const declaredScope = parseDeclaredScopeFlag(fields.files);
|
|
1113
|
+
// #3003: reuse parseDeclaredScopeFlag — a blank/absent --deletions leaves the
|
|
1114
|
+
// entry shape untouched, mirroring the --files rule directly above.
|
|
1115
|
+
const declaredDeletions = parseDeclaredScopeFlag(fields.deletions);
|
|
976
1116
|
const candidate = {
|
|
977
1117
|
agent_id: agentId,
|
|
978
1118
|
worktree_path: worktreePath,
|
|
979
1119
|
branch,
|
|
980
1120
|
expected_base: base,
|
|
981
1121
|
...(declaredScope.length > 0 ? { files_modified: declaredScope } : {}),
|
|
1122
|
+
...(declaredDeletions.length > 0 ? { declared_deletions: declaredDeletions } : {}),
|
|
982
1123
|
};
|
|
983
1124
|
const entry = normalizeCleanupManifestEntry(candidate);
|
|
984
1125
|
if (!entry) {
|
|
@@ -1072,6 +1213,11 @@ function planWorktreeRecordAgent(manifestRaw, fields) {
|
|
|
1072
1213
|
if (entry.files_modified && entry.files_modified.length > 0) {
|
|
1073
1214
|
recorded.files_modified = entry.files_modified;
|
|
1074
1215
|
}
|
|
1216
|
+
// #3003: same conservative rule as --files above — a blank --deletions
|
|
1217
|
+
// leaves the entry shape untouched.
|
|
1218
|
+
if (entry.declared_deletions && entry.declared_deletions.length > 0) {
|
|
1219
|
+
recorded.declared_deletions = entry.declared_deletions;
|
|
1220
|
+
}
|
|
1075
1221
|
worktrees.push(recorded);
|
|
1076
1222
|
return {
|
|
1077
1223
|
ok: true,
|
|
@@ -1083,7 +1229,7 @@ function planWorktreeRecordAgent(manifestRaw, fields) {
|
|
|
1083
1229
|
/**
|
|
1084
1230
|
* CLI command: append a validated per-agent entry to a wave cleanup manifest.
|
|
1085
1231
|
*
|
|
1086
|
-
* Usage: worktree record-agent --manifest <path> --agent-id <id> --path <worktree> --branch <branch> --base <sha> [--files "<space-separated paths>"]
|
|
1232
|
+
* Usage: worktree record-agent --manifest <path> --agent-id <id> --path <worktree> --branch <branch> --base <sha> [--files "<space-separated paths>"] [--deletions "<space-separated paths>"]
|
|
1087
1233
|
*
|
|
1088
1234
|
* Fails loudly (non-zero exit + recovery hint on stderr) when a field is
|
|
1089
1235
|
* missing/garbled or the manifest is absent/malformed, rather than appending an
|
|
@@ -1092,13 +1238,15 @@ function planWorktreeRecordAgent(manifestRaw, fields) {
|
|
|
1092
1238
|
function cmdWorktreeRecordAgent(cwd, args = [], deps = {}) {
|
|
1093
1239
|
const flag = (name) => {
|
|
1094
1240
|
const i = args.indexOf(name);
|
|
1095
|
-
|
|
1241
|
+
if (i < 0 || i + 1 >= args.length)
|
|
1242
|
+
return '';
|
|
1243
|
+
return args[i + 1];
|
|
1096
1244
|
};
|
|
1097
1245
|
const write = deps.write || ((s) => process.stdout.write(s));
|
|
1098
1246
|
const writeErr = deps.writeErr || ((s) => process.stderr.write(s));
|
|
1099
1247
|
const manifestPath = flag('--manifest');
|
|
1100
1248
|
if (!manifestPath) {
|
|
1101
|
-
writeErr('Usage: worktree record-agent --manifest <path> --agent-id <id> --path <worktree> --branch <branch> --base <sha> [--files "<space-separated paths>"]\n');
|
|
1249
|
+
writeErr('Usage: worktree record-agent --manifest <path> --agent-id <id> --path <worktree> --branch <branch> --base <sha> [--files "<space-separated paths>"] [--deletions "<space-separated paths>"]\n');
|
|
1102
1250
|
process.exitCode = 2;
|
|
1103
1251
|
return { ok: false, reason: 'usage', entry: null };
|
|
1104
1252
|
}
|
|
@@ -1121,6 +1269,7 @@ function cmdWorktreeRecordAgent(cwd, args = [], deps = {}) {
|
|
|
1121
1269
|
branch: flag('--branch'),
|
|
1122
1270
|
base: flag('--base'),
|
|
1123
1271
|
files: flag('--files'),
|
|
1272
|
+
deletions: flag('--deletions'),
|
|
1124
1273
|
});
|
|
1125
1274
|
if (!plan.ok || plan.manifest === null) {
|
|
1126
1275
|
writeErr(`[gsd] worktree.record-agent: ${plan.reason} — ${plan.hint || ''}\n`);
|
|
@@ -1165,12 +1314,16 @@ function planWorktreeCreate(fields) {
|
|
|
1165
1314
|
};
|
|
1166
1315
|
}
|
|
1167
1316
|
const declaredScope = parseDeclaredScopeFlag(fields.files);
|
|
1317
|
+
// #3003: reuse parseDeclaredScopeFlag — a blank/absent --deletions leaves the
|
|
1318
|
+
// entry shape untouched, mirroring the --files rule directly above.
|
|
1319
|
+
const declaredDeletions = parseDeclaredScopeFlag(fields.deletions);
|
|
1168
1320
|
const candidate = {
|
|
1169
1321
|
agent_id: agentId,
|
|
1170
1322
|
worktree_path: worktreePath,
|
|
1171
1323
|
branch,
|
|
1172
1324
|
expected_base: base,
|
|
1173
1325
|
...(declaredScope.length > 0 ? { files_modified: declaredScope } : {}),
|
|
1326
|
+
...(declaredDeletions.length > 0 ? { declared_deletions: declaredDeletions } : {}),
|
|
1174
1327
|
};
|
|
1175
1328
|
const entry = normalizeCleanupManifestEntry(candidate);
|
|
1176
1329
|
if (!entry) {
|
|
@@ -1298,7 +1451,7 @@ function executeWorktreeCreatePlan(plan, repoRoot, deps = {}) {
|
|
|
1298
1451
|
* validated manifest entry so the worktree is immediately manageable by
|
|
1299
1452
|
* `worktree cleanup-wave` / `worktree reap-orphans`.
|
|
1300
1453
|
*
|
|
1301
|
-
* Usage: worktree create --manifest <path> --agent-id <id> --path <worktree> --branch <branch> --base <sha> --root <dir> [--files "<space-separated paths>"]
|
|
1454
|
+
* Usage: worktree create --manifest <path> --agent-id <id> --path <worktree> --branch <branch> --base <sha> --root <dir> [--files "<space-separated paths>"] [--deletions "<space-separated paths>"]
|
|
1302
1455
|
*
|
|
1303
1456
|
* #2584 FIX 1 — ORDERING CONTRACT: every manifest read/parse/shape-validate/
|
|
1304
1457
|
* plan step runs BEFORE the git side effect (step 5). The ONLY manifest
|
|
@@ -1312,13 +1465,15 @@ function executeWorktreeCreatePlan(plan, repoRoot, deps = {}) {
|
|
|
1312
1465
|
function cmdWorktreeCreate(cwd, args = [], deps = {}) {
|
|
1313
1466
|
const flag = (name) => {
|
|
1314
1467
|
const i = args.indexOf(name);
|
|
1315
|
-
|
|
1468
|
+
if (i < 0 || i + 1 >= args.length)
|
|
1469
|
+
return '';
|
|
1470
|
+
return args[i + 1];
|
|
1316
1471
|
};
|
|
1317
1472
|
const write = deps.write || ((s) => process.stdout.write(s));
|
|
1318
1473
|
const writeErr = deps.writeErr || ((s) => process.stderr.write(s));
|
|
1319
1474
|
const manifestPath = flag('--manifest');
|
|
1320
1475
|
if (!manifestPath) {
|
|
1321
|
-
writeErr('Usage: worktree create --manifest <path> --agent-id <id> --path <worktree> --branch <branch> --base <sha> --root <dir> [--files "<space-separated paths>"]\n');
|
|
1476
|
+
writeErr('Usage: worktree create --manifest <path> --agent-id <id> --path <worktree> --branch <branch> --base <sha> --root <dir> [--files "<space-separated paths>"] [--deletions "<space-separated paths>"]\n');
|
|
1322
1477
|
process.exitCode = 2;
|
|
1323
1478
|
return { ok: false, reason: 'usage' };
|
|
1324
1479
|
}
|
|
@@ -1384,6 +1539,7 @@ function cmdWorktreeCreate(cwd, args = [], deps = {}) {
|
|
|
1384
1539
|
branch: flag('--branch'),
|
|
1385
1540
|
base: flag('--base'),
|
|
1386
1541
|
files: flag('--files'),
|
|
1542
|
+
deletions: flag('--deletions'),
|
|
1387
1543
|
});
|
|
1388
1544
|
if (!plan.ok || !plan.entry) {
|
|
1389
1545
|
writeErr(`[gsd] worktree.create: ${plan.reason} — ${plan.hint || ''}\n`);
|
|
@@ -1455,6 +1611,11 @@ function cmdWorktreeCreate(cwd, args = [], deps = {}) {
|
|
|
1455
1611
|
if (Array.isArray(plan.entry.files_modified) && plan.entry.files_modified.length > 0) {
|
|
1456
1612
|
recorded.files_modified = plan.entry.files_modified;
|
|
1457
1613
|
}
|
|
1614
|
+
// #3003: same conservative rule as --files above — a blank --deletions
|
|
1615
|
+
// leaves the entry shape untouched.
|
|
1616
|
+
if (Array.isArray(plan.entry.declared_deletions) && plan.entry.declared_deletions.length > 0) {
|
|
1617
|
+
recorded.declared_deletions = plan.entry.declared_deletions;
|
|
1618
|
+
}
|
|
1458
1619
|
const dedupeKey = `${recorded.worktree_path}\0${recorded.branch}`;
|
|
1459
1620
|
const alreadyPresent = worktrees.some((existing) => {
|
|
1460
1621
|
const normalized = normalizeCleanupManifestEntry(existing);
|
|
@@ -1830,6 +1991,9 @@ function pruneOrphanedWorktrees(repoRoot, deps = {}) {
|
|
|
1830
1991
|
return [];
|
|
1831
1992
|
}
|
|
1832
1993
|
module.exports = {
|
|
1994
|
+
// Re-exported for the codebase-drift gate's --name-status parser (#4081):
|
|
1995
|
+
// single owner of git C-quoted-path decoding.
|
|
1996
|
+
decodeGitQuotedPath,
|
|
1833
1997
|
resolveWorktreeContext,
|
|
1834
1998
|
resolveWorktreeLinkage,
|
|
1835
1999
|
parseWorktreePorcelain,
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"_comment": "Canonical CONFIG_DEFAULTS for the Configuration Module. Nested shape is canonical. CJS flat projection (branching_strategy, sub_repos, etc.) is handled by consumers at the boundary. Security keys (security_enforcement, security_asvs_level, security_block_on) and post_planning_gaps live in workflow.* as their canonical location. resolve_model_ids, context_window, phase_naming are CJS-originated top-level keys included here. brave_search, firecrawl, exa_search default to false in the manifest; at runtime buildNewProjectConfig detects API keys. The plan_checker (CJS flat)
|
|
2
|
+
"_comment": "Canonical CONFIG_DEFAULTS for the Configuration Module. Nested shape is canonical. CJS flat projection (branching_strategy, sub_repos, etc.) is handled by consumers at the boundary. Security keys (security_enforcement, security_asvs_level, security_block_on) and post_planning_gaps live in workflow.* as their canonical location. resolve_model_ids, context_window, phase_naming are CJS-originated top-level keys included here. brave_search, firecrawl, exa_search default to false in the manifest; at runtime buildNewProjectConfig detects API keys. The plan_checker (CJS flat) \u2192 workflow.plan_check (canonical nested) divergence is resolved: canonical name is workflow.plan_check. _auto_chain_active is a runtime-state field included for completeness.",
|
|
3
3
|
"model_profile": "balanced",
|
|
4
4
|
"commit_docs": true,
|
|
5
5
|
"parallelization": true,
|
|
@@ -46,11 +46,13 @@
|
|
|
46
46
|
"context_coverage_gate": true,
|
|
47
47
|
"code_review": true,
|
|
48
48
|
"code_review_depth": "standard",
|
|
49
|
+
"code_review_depth_overrides": [],
|
|
49
50
|
"code_review_command": null,
|
|
50
51
|
"pattern_mapper": true,
|
|
51
52
|
"plan_bounce": false,
|
|
52
53
|
"plan_bounce_script": null,
|
|
53
54
|
"plan_bounce_passes": 2,
|
|
55
|
+
"inline_plan_threshold": 2,
|
|
54
56
|
"auto_prune_state": false,
|
|
55
57
|
"post_planning_gaps": true,
|
|
56
58
|
"security_enforcement": true,
|
|
@@ -60,6 +62,7 @@
|
|
|
60
62
|
},
|
|
61
63
|
"planning": {
|
|
62
64
|
"commit_docs": true,
|
|
65
|
+
"pr_strict": false,
|
|
63
66
|
"search_gitignored": false,
|
|
64
67
|
"sub_repos": [],
|
|
65
68
|
"granularity": "standard"
|
|
@@ -97,6 +100,9 @@
|
|
|
97
100
|
"source_grounding": true,
|
|
98
101
|
"source_grounding_authority": "grep"
|
|
99
102
|
},
|
|
103
|
+
"review": {
|
|
104
|
+
"max_prompt_tokens": null
|
|
105
|
+
},
|
|
100
106
|
"capabilities": {
|
|
101
107
|
"strict_known_registries": null,
|
|
102
108
|
"auto_update": false
|