@opengsd/gsd-core 1.13.0 → 1.15.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/README.ja-JP.md +3 -3
- package/README.ko-KR.md +3 -3
- package/README.pt-BR.md +3 -3
- package/README.zh-CN.md +3 -3
- package/agents/gsd-advisor-researcher.compact.md +85 -0
- package/agents/gsd-ai-researcher.compact.md +96 -0
- package/agents/gsd-assumptions-analyzer.compact.md +81 -0
- package/agents/gsd-code-fixer.compact.md +459 -0
- package/agents/gsd-code-fixer.md +9 -8
- package/agents/gsd-code-reviewer.compact.md +269 -0
- package/agents/gsd-code-reviewer.md +15 -3
- package/agents/gsd-codebase-mapper.compact.md +760 -0
- package/agents/gsd-debug-session-manager.compact.md +360 -0
- package/agents/gsd-debug-session-manager.md +17 -2
- package/agents/gsd-debugger.md +2 -2
- package/agents/gsd-doc-classifier.compact.md +192 -0
- package/agents/gsd-doc-synthesizer.compact.md +200 -0
- package/agents/gsd-doc-verifier.compact.md +143 -0
- package/agents/gsd-doc-writer.compact.md +440 -0
- package/agents/gsd-dom-verifier.compact.md +138 -0
- package/agents/gsd-domain-researcher.compact.md +141 -0
- package/agents/gsd-eval-auditor.compact.md +160 -0
- package/agents/gsd-eval-auditor.md +1 -1
- package/agents/gsd-eval-planner.compact.md +137 -0
- package/agents/gsd-executor.md +13 -8
- package/agents/gsd-framework-selector.compact.md +82 -0
- package/agents/gsd-integration-checker.compact.md +245 -0
- package/agents/gsd-intel-updater.compact.md +226 -0
- package/agents/gsd-intel-updater.md +1 -1
- package/agents/gsd-mempalace-curator.compact.md +45 -0
- package/agents/gsd-nyquist-auditor.compact.md +179 -0
- package/agents/gsd-pattern-mapper.compact.md +275 -0
- package/agents/gsd-phase-researcher.md +19 -11
- package/agents/gsd-plan-checker.md +8 -7
- package/agents/gsd-planner.md +12 -8
- package/agents/gsd-project-researcher.compact.md +587 -0
- package/agents/gsd-project-researcher.md +1 -1
- package/agents/gsd-research-synthesizer.compact.md +212 -0
- package/agents/gsd-research-synthesizer.md +1 -1
- package/agents/gsd-roadmapper.compact.md +454 -0
- package/agents/gsd-roadmapper.md +13 -0
- package/agents/gsd-security-auditor.compact.md +162 -0
- package/agents/gsd-ui-auditor.compact.md +404 -0
- package/agents/gsd-ui-auditor.md +155 -17
- package/agents/gsd-ui-checker.compact.md +277 -0
- package/agents/gsd-ui-researcher.compact.md +282 -0
- package/agents/gsd-ui-researcher.md +1 -1
- package/agents/gsd-user-profiler.compact.md +108 -0
- package/agents/gsd-verifier.md +10 -9
- package/bin/install.js +848 -163
- package/commands/gsd/autonomous.md +2 -2
- package/commands/gsd/capture.md +1 -1
- package/commands/gsd/cleanup.md +1 -0
- package/commands/gsd/code-review.md +2 -1
- package/commands/gsd/complete-milestone.md +1 -0
- package/commands/gsd/config.md +1 -0
- package/commands/gsd/debug.md +1 -0
- package/commands/gsd/graphify.md +1 -0
- package/commands/gsd/health.md +1 -0
- package/commands/gsd/mempalace-capture.md +8 -3
- package/commands/gsd/mempalace-recall.md +1 -0
- package/commands/gsd/new-milestone.md +1 -0
- package/commands/gsd/new-project.md +1 -0
- package/commands/gsd/next.md +1 -0
- package/commands/gsd/pause-work.md +1 -0
- package/commands/gsd/phase.md +1 -0
- package/commands/gsd/plan-review-convergence.md +6 -6
- package/commands/gsd/pr-branch.md +1 -0
- package/commands/gsd/progress.md +1 -1
- package/commands/gsd/quick-batch.md +1 -1
- package/commands/gsd/resume-work.md +1 -0
- package/commands/gsd/review-backlog.md +1 -0
- package/commands/gsd/review.md +2 -3
- package/commands/gsd/settings.md +2 -1
- package/commands/gsd/stats.md +1 -0
- package/commands/gsd/thread.md +1 -0
- package/commands/gsd/workspace.md +1 -0
- package/commands/gsd/workstreams.md +1 -0
- package/gsd-core/bin/check-latest-version.cjs +8 -3
- package/gsd-core/bin/gsd-tools.cjs +672 -146
- package/gsd-core/bin/lib/adr-parser.cjs +4 -2
- package/gsd-core/bin/lib/artifacts.cjs +2 -1
- package/gsd-core/bin/lib/audit.cjs +119 -34
- package/gsd-core/bin/lib/broken-windows.cjs +168 -49
- package/gsd-core/bin/lib/capability-lifecycle.cjs +10 -6
- package/gsd-core/bin/lib/capability-loader.cjs +135 -1
- package/gsd-core/bin/lib/capability-registry.cjs +96 -189
- package/gsd-core/bin/lib/capability-source.cjs +19 -2
- package/gsd-core/bin/lib/capability-validator.cjs +14 -2
- package/gsd-core/bin/lib/check-command-router.cjs +213 -49
- package/gsd-core/bin/lib/code-review-depth.cjs +2 -2
- package/gsd-core/bin/lib/codex-agent-toml.cjs +21 -25
- package/gsd-core/bin/lib/commands.cjs +823 -112
- package/gsd-core/bin/lib/config-loader.cjs +66 -4
- package/gsd-core/bin/lib/config.cjs +186 -45
- package/gsd-core/bin/lib/coverage.cjs +1 -1
- package/gsd-core/bin/lib/decisions.cjs +164 -45
- package/gsd-core/bin/lib/external-descriptor-trust.cjs +29 -14
- package/gsd-core/bin/lib/frontmatter.cjs +13 -0
- package/gsd-core/bin/lib/graphify.cjs +10 -2
- package/gsd-core/bin/lib/gsd2-import.cjs +1 -2
- package/gsd-core/bin/lib/health-diagnostic-rules/state-consistency.cjs +12 -1
- package/gsd-core/bin/lib/health-diagnostic-rules/worktree-health.cjs +1 -1
- package/gsd-core/bin/lib/host-runtime-detection.cjs +9 -0
- package/gsd-core/bin/lib/init.cjs +614 -86
- package/gsd-core/bin/lib/install-engine.cjs +29 -3
- package/gsd-core/bin/lib/install-profiles.cjs +14 -0
- package/gsd-core/bin/lib/installer-migrations.cjs +41 -5
- package/gsd-core/bin/lib/loop-resolver.cjs +50 -31
- package/gsd-core/bin/lib/mcp-catalog.cjs +2 -2
- package/gsd-core/bin/lib/milestone.cjs +37 -13
- package/gsd-core/bin/lib/model-resolver.cjs +253 -53
- package/gsd-core/bin/lib/phase-command-router.cjs +16 -2
- package/gsd-core/bin/lib/phase-id-card.cjs +32 -0
- package/gsd-core/bin/lib/phase-id-display.cjs +78 -0
- package/gsd-core/bin/lib/phase-id.cjs +268 -27
- package/gsd-core/bin/lib/phase-lifecycle.cjs +61 -0
- package/gsd-core/bin/lib/phase-locator.cjs +29 -10
- package/gsd-core/bin/lib/phase.cjs +393 -88
- package/gsd-core/bin/lib/plan-document.cjs +49 -1
- package/gsd-core/bin/lib/planning-document.cjs +459 -0
- package/gsd-core/bin/lib/planning-inspect.cjs +52 -19
- package/gsd-core/bin/lib/planning-snapshot.cjs +61 -12
- package/gsd-core/bin/lib/planning-workspace.cjs +57 -3
- package/gsd-core/bin/lib/pr-branch-patterns.cjs +57 -0
- package/gsd-core/bin/lib/pristine-baseline.cjs +182 -0
- package/gsd-core/bin/lib/probe-core.cjs +7 -1
- package/gsd-core/bin/lib/prohibition-enforcement.cjs +91 -4
- package/gsd-core/bin/lib/project-root.cjs +41 -2
- package/gsd-core/bin/lib/quick-batch.cjs +1 -1
- package/gsd-core/bin/lib/refactor-trigger-command-router.cjs +61 -2
- package/gsd-core/bin/lib/research-store.cjs +11 -12
- package/gsd-core/bin/lib/review-lane-descriptor.cjs +10 -30
- package/gsd-core/bin/lib/review-lane-invocation.cjs +23 -0
- package/gsd-core/bin/lib/review-reviewer-selection.cjs +2 -2
- package/gsd-core/bin/lib/reviewer-step-dispatch.cjs +337 -0
- package/gsd-core/bin/lib/roadmap-command-router.cjs +12 -4
- package/gsd-core/bin/lib/roadmap-parser.cjs +219 -18
- package/gsd-core/bin/lib/roadmap-upgrade.cjs +1539 -13
- package/gsd-core/bin/lib/roadmap.cjs +356 -42
- package/gsd-core/bin/lib/runtime-artifact-conversion.cjs +310 -41
- package/gsd-core/bin/lib/runtime-artifact-install-plan.cjs +15 -4
- package/gsd-core/bin/lib/runtime-artifact-layout.cjs +13 -5
- package/gsd-core/bin/lib/runtime-homes.cjs +4 -0
- package/gsd-core/bin/lib/runtime-hooks-surface.cjs +408 -37
- package/gsd-core/bin/lib/runtime-name-policy.cjs +111 -1
- package/gsd-core/bin/lib/security.cjs +126 -7
- package/gsd-core/bin/lib/shell-command-projection.cjs +10 -6
- package/gsd-core/bin/lib/state-document.cjs +130 -28
- package/gsd-core/bin/lib/state-md-schema.cjs +21 -14
- package/gsd-core/bin/lib/state-transition.cjs +181 -30
- package/gsd-core/bin/lib/state.cjs +265 -27
- package/gsd-core/bin/lib/surface.cjs +77 -3
- package/gsd-core/bin/lib/task-command-router.cjs +12 -6
- package/gsd-core/bin/lib/tdd-red-evidence.cjs +78 -5
- package/gsd-core/bin/lib/uat-predicate.cjs +47 -4
- package/gsd-core/bin/lib/uat.cjs +9 -1
- package/gsd-core/bin/lib/ui-consideration-probe.cjs +15 -2
- package/gsd-core/bin/lib/ui-frontend-evidence.cjs +100 -9
- package/gsd-core/bin/lib/undo-commit-selection.cjs +131 -0
- package/gsd-core/bin/lib/update-context.cjs +30 -24
- package/gsd-core/bin/lib/vendor/js-yaml.cjs +11 -3
- package/gsd-core/bin/lib/verification.cjs +315 -30
- package/gsd-core/bin/lib/verify-command-grounding.cjs +47 -3
- package/gsd-core/bin/lib/verify.cjs +320 -48
- package/gsd-core/bin/lib/workstream-inventory.cjs +1 -0
- package/gsd-core/bin/lib/worktree-base-ref.cjs +482 -73
- package/gsd-core/bin/lib/worktree-safety.cjs +797 -58
- package/gsd-core/bin/shared/config-defaults.manifest.json +4 -0
- package/gsd-core/bin/shared/config-schema.manifest.json +6 -0
- package/gsd-core/bin/verify-reapply-patches.cjs +439 -80
- package/gsd-core/references/checkpoints.md +5 -3
- package/gsd-core/references/compact-content-gate.md +66 -0
- package/gsd-core/references/edge-probe-fixtures/01-round-half-even/expected-coverage.json +28 -3
- package/gsd-core/references/edge-probe-fixtures/02-merge-intervals/expected-coverage.json +37 -4
- package/gsd-core/references/edge-probe-fixtures/03-truncate-graphemes/expected-coverage.json +28 -3
- package/gsd-core/references/edge-probe-fixtures/04-money-rounding/expected-coverage.json +28 -3
- package/gsd-core/references/edge-probe-fixtures/05-list-dedupe/expected-coverage.json +37 -4
- package/gsd-core/references/edge-probe-fixtures/06-resolved-mixed/expected-coverage.json +37 -4
- package/gsd-core/references/edge-probe.md +195 -21
- package/gsd-core/references/execute-phase-between-wave-reset.md +7 -6
- package/gsd-core/references/execute-phase-wave-guard.md +22 -11
- package/gsd-core/references/gsd-run-resolver.md +1 -1
- package/gsd-core/references/loop-hook-dispatch.md +18 -0
- package/gsd-core/references/model-profiles.md +13 -4
- package/gsd-core/references/phase-argument-parsing.md +9 -7
- package/gsd-core/references/phase-id-convention.md +28 -0
- package/gsd-core/references/planner-gap-closure.md +2 -0
- package/gsd-core/references/planner-load-graph-context.md +24 -13
- package/gsd-core/references/planner-verify-command-grounding.md +14 -0
- package/gsd-core/references/planning-config.md +14 -2
- package/gsd-core/references/tdd.md +30 -4
- package/gsd-core/references/thinking-models-planning.md +18 -2
- package/gsd-core/references/ui-consideration-probe.md +10 -5
- package/gsd-core/references/verification-patterns.md +17 -4
- package/gsd-core/references/verify-command-path-resolvability.md +10 -2
- package/gsd-core/references/worktree-path-safety.md +433 -2
- package/gsd-core/templates/README.md +7 -1
- package/gsd-core/templates/state.md +6 -3
- package/gsd-core/templates/summary.compact.md +212 -0
- package/gsd-core/templates/user-setup.compact.md +199 -0
- package/gsd-core/templates/user-setup.md +0 -9
- package/gsd-core/templates/verification-report.md +1 -1
- package/gsd-core/workflows/_runtime-launcher.snippet.sh +1 -1
- package/gsd-core/workflows/add-backlog.md +1 -1
- package/gsd-core/workflows/add-phase.md +1 -1
- package/gsd-core/workflows/add-tests.md +2 -2
- package/gsd-core/workflows/add-todo.md +6 -5
- package/gsd-core/workflows/ai-integration-phase.md +11 -3
- package/gsd-core/workflows/audit-fix.md +1 -1
- package/gsd-core/workflows/audit-milestone.md +1 -1
- package/gsd-core/workflows/audit-uat.md +1 -1
- package/gsd-core/workflows/autonomous/steps/converge-fail-fast.md +9 -18
- package/gsd-core/workflows/autonomous.md +29 -16
- package/gsd-core/workflows/check-todos.md +6 -4
- package/gsd-core/workflows/cleanup.md +5 -3
- package/gsd-core/workflows/code-review/steps/dispatch-fix.md +4 -3
- package/gsd-core/workflows/code-review/steps/structural-pre-pass.md +8 -1
- package/gsd-core/workflows/code-review-fix.md +108 -22
- package/gsd-core/workflows/code-review.md +216 -73
- package/gsd-core/workflows/complete-milestone/detail/elaboration.md +274 -0
- package/gsd-core/workflows/complete-milestone.md +41 -264
- package/gsd-core/workflows/debug.md +3 -3
- package/gsd-core/workflows/diagnose-issues.md +1 -1
- package/gsd-core/workflows/discuss-phase/modes/advisor.md +1 -1
- package/gsd-core/workflows/discuss-phase/modes/chain.md +1 -1
- package/gsd-core/workflows/discuss-phase-assumptions.md +1 -1
- package/gsd-core/workflows/discuss-phase.md +1 -1
- package/gsd-core/workflows/do.md +2 -2
- package/gsd-core/workflows/docs-update/detail/elaboration.md +179 -0
- package/gsd-core/workflows/docs-update.md +17 -158
- package/gsd-core/workflows/edit-phase.md +1 -1
- package/gsd-core/workflows/eval-review.md +10 -3
- package/gsd-core/workflows/execute-phase/detail/elaboration.md +124 -0
- package/gsd-core/workflows/execute-phase/steps/code-review-disposition.md +1017 -0
- package/gsd-core/workflows/execute-phase/steps/codebase-drift-gate.md +19 -4
- package/gsd-core/workflows/execute-phase/steps/completion-reconciliation.md +56 -0
- package/gsd-core/workflows/execute-phase/steps/executor-isolation-dispatch.md +43 -4
- package/gsd-core/workflows/execute-phase/steps/executor-progress-policy.md +43 -0
- 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 +1 -1
- package/gsd-core/workflows/execute-phase/steps/post-merge-gate.md +46 -9
- package/gsd-core/workflows/execute-phase/steps/protected-branch.md +1 -1
- package/gsd-core/workflows/execute-phase/steps/ready-wave-gate.md +37 -0
- package/gsd-core/workflows/execute-phase/steps/regression-gate-run.md +1 -1
- package/gsd-core/workflows/execute-phase/steps/sequential-root-pin.md +35 -0
- package/gsd-core/workflows/execute-phase/steps/stale-reverification.md +24 -0
- package/gsd-core/workflows/execute-phase/steps/tdd-applicability-resolution.md +1 -1
- package/gsd-core/workflows/execute-phase/steps/threat-id-gate.md +28 -0
- package/gsd-core/workflows/execute-phase/steps/wave-post-gate-hooks.md +1 -1
- package/gsd-core/workflows/execute-phase/steps/worktree-base-check.md +25 -0
- package/gsd-core/workflows/execute-phase.md +83 -172
- package/gsd-core/workflows/execute-plan.md +24 -10
- package/gsd-core/workflows/explore.md +3 -3
- package/gsd-core/workflows/extract-learnings.md +2 -1
- package/gsd-core/workflows/fast.md +1 -1
- package/gsd-core/workflows/forensics.md +1 -1
- package/gsd-core/workflows/graduation.md +1 -1
- package/gsd-core/workflows/health.md +2 -2
- package/gsd-core/workflows/help/modes/full.compact.md +398 -0
- package/gsd-core/workflows/help/modes/full.md +5 -5
- package/gsd-core/workflows/help/modes/topic.md +15 -5
- package/gsd-core/workflows/help.md +1 -1
- package/gsd-core/workflows/import.md +2 -2
- package/gsd-core/workflows/inbox.md +2 -2
- package/gsd-core/workflows/ingest-docs.md +3 -3
- package/gsd-core/workflows/insert-phase.md +1 -1
- package/gsd-core/workflows/list-seeds.md +1 -1
- package/gsd-core/workflows/list-workspaces.md +1 -1
- package/gsd-core/workflows/manager.md +2 -2
- package/gsd-core/workflows/map-codebase.md +52 -5
- package/gsd-core/workflows/milestone-summary.md +1 -1
- package/gsd-core/workflows/mvp-phase.md +1 -1
- package/gsd-core/workflows/new-milestone.md +56 -14
- package/gsd-core/workflows/new-project/detail/elaboration.md +216 -0
- package/gsd-core/workflows/new-project/steps/auto-mode-config.md +3 -3
- package/gsd-core/workflows/new-project/steps/codebase-map-offer.md +1 -1
- package/gsd-core/workflows/new-project.md +39 -209
- package/gsd-core/workflows/new-workspace.md +2 -2
- package/gsd-core/workflows/next.md +1 -1
- package/gsd-core/workflows/note.md +1 -1
- package/gsd-core/workflows/onboard.md +1 -1
- package/gsd-core/workflows/pause-work.md +1 -1
- package/gsd-core/workflows/plan-phase/detail/elaboration.md +209 -0
- package/gsd-core/workflows/plan-phase/steps/chunked-planning-mode.md +17 -5
- package/gsd-core/workflows/plan-phase/steps/prd-express-path.md +1 -1
- package/gsd-core/workflows/plan-phase/steps/stall-detection-helpers.md +23 -5
- package/gsd-core/workflows/plan-phase.md +45 -187
- package/gsd-core/workflows/plan-review-convergence.md +21 -5
- package/gsd-core/workflows/plant-seed.md +62 -20
- package/gsd-core/workflows/pr-branch.md +132 -20
- package/gsd-core/workflows/profile-user.md +2 -2
- package/gsd-core/workflows/progress.md +1 -1
- package/gsd-core/workflows/quick/steps/plan-checker-loop.md +25 -0
- package/gsd-core/workflows/quick/steps/quick-verification.md +1 -1
- package/gsd-core/workflows/quick/steps/worktree-pre-dispatch-commit.md +1 -1
- package/gsd-core/workflows/quick-batch/steps/batch-init.md +1 -1
- package/gsd-core/workflows/quick-batch/steps/completion.md +1 -1
- package/gsd-core/workflows/quick-batch/steps/merge-wave.md +1 -1
- package/gsd-core/workflows/quick-batch/steps/planner-wave.md +1 -1
- package/gsd-core/workflows/quick-batch/steps/research-phase.md +1 -1
- package/gsd-core/workflows/quick-batch/steps/resume-mode.md +1 -1
- package/gsd-core/workflows/quick-batch/steps/verification-wave.md +1 -1
- package/gsd-core/workflows/quick-batch/steps/worktree-dispatch.md +1 -1
- package/gsd-core/workflows/quick-batch.md +1 -1
- package/gsd-core/workflows/quick.md +29 -10
- package/gsd-core/workflows/reapply-patches.md +86 -6
- package/gsd-core/workflows/remove-phase.md +1 -1
- package/gsd-core/workflows/remove-workspace.md +2 -2
- package/gsd-core/workflows/resume-project.md +1 -1
- package/gsd-core/workflows/review.md +31 -16
- package/gsd-core/workflows/scan.md +1 -1
- package/gsd-core/workflows/secure-phase.md +3 -2
- package/gsd-core/workflows/settings-advanced.md +30 -10
- package/gsd-core/workflows/settings-integrations.md +2 -3
- package/gsd-core/workflows/settings.md +22 -9
- package/gsd-core/workflows/ship.md +3 -2
- package/gsd-core/workflows/sketch-wrap-up.md +1 -1
- package/gsd-core/workflows/sketch.md +1 -1
- package/gsd-core/workflows/smart-entry.md +2 -2
- package/gsd-core/workflows/spec-phase.md +15 -5
- package/gsd-core/workflows/spike-wrap-up.md +1 -1
- package/gsd-core/workflows/spike.md +1 -1
- package/gsd-core/workflows/stats.md +1 -1
- package/gsd-core/workflows/sync-skills.md +5 -5
- package/gsd-core/workflows/thread.md +1 -1
- package/gsd-core/workflows/transition.md +1 -1
- package/gsd-core/workflows/ui-phase.md +44 -8
- package/gsd-core/workflows/ui-review.md +18 -4
- package/gsd-core/workflows/ultraplan-phase.md +1 -1
- package/gsd-core/workflows/undo.md +339 -20
- package/gsd-core/workflows/update.md +14 -12
- package/gsd-core/workflows/validate-phase.md +3 -2
- package/gsd-core/workflows/verify-work/detail/elaboration.md +230 -0
- package/gsd-core/workflows/verify-work/steps/automated-ui-verification.md +1 -1
- package/gsd-core/workflows/verify-work/steps/mvp-uat-framing.md +1 -1
- package/gsd-core/workflows/verify-work.md +101 -196
- package/hooks/dist/gsd-agent-isolation-guard.js +66 -16
- package/hooks/dist/gsd-context-monitor.js +88 -15
- package/hooks/dist/gsd-cursor-subagent-start.js +34 -14
- package/hooks/dist/gsd-secret-read-guard.js +71 -19
- package/hooks/dist/gsd-statusline.js +81 -20
- package/hooks/dist/gsd-validate-commit.sh +97 -8
- package/hooks/dist/gsd-worktree-path-guard.js +25 -14
- package/hooks/dist/gsd-write-guard.js +46 -1
- package/hooks/dist/lib/dispatch-identity.js +187 -0
- package/hooks/dist/lib/filename-classification.js +64 -0
- package/hooks/dist/lib/isolation-deny-reason.js +53 -1
- package/hooks/dist/lib/isolation-sentinel.js +58 -19
- package/hooks/gsd-agent-isolation-guard.js +66 -16
- package/hooks/gsd-context-monitor.js +88 -15
- package/hooks/gsd-cursor-subagent-start.js +34 -14
- package/hooks/gsd-secret-read-guard.js +71 -19
- package/hooks/gsd-statusline.js +81 -20
- package/hooks/gsd-validate-commit.sh +97 -8
- package/hooks/gsd-worktree-path-guard.js +25 -14
- package/hooks/gsd-write-guard.js +46 -1
- package/hooks/lib/dispatch-identity.js +187 -0
- package/hooks/lib/filename-classification.js +64 -0
- package/hooks/lib/isolation-deny-reason.js +53 -1
- package/hooks/lib/isolation-sentinel.js +58 -19
- package/package.json +11 -6
- package/scripts/benchmark-compact-content-variants.cjs +298 -0
- package/scripts/benchmark-compact-content.cjs +368 -0
- package/scripts/build-hooks.js +15 -6
- package/scripts/check-contract-drift.cjs +131 -12
- package/scripts/check-env.cjs +36 -8
- package/scripts/check-glossary-refs.cjs +25 -21
- package/scripts/ci-next-health.cjs +271 -0
- package/scripts/ci-prepare-test-scope.cjs +7 -7
- package/scripts/ci-test-scope.cjs +126 -20
- package/scripts/ci-timeout-report.cjs +1 -1
- package/scripts/command-contract-helpers.cjs +3 -0
- package/scripts/diff-touches-shipped-paths.cjs +1 -1
- package/scripts/docs-guard-registry.cjs +35 -2
- package/scripts/gen-adr-index.cjs +8 -2
- package/scripts/gen-inventory-manifest.cjs +12 -0
- package/scripts/gen-loop-host-contract.cjs +69 -0
- package/scripts/gen-platform-conformance-tier.cjs +557 -0
- package/scripts/lib/drift-scan.cjs +1 -1
- package/scripts/lib/macos-conformance-tier.generated.cjs +224 -0
- package/scripts/lib/ndjson-reporter.cjs +3 -2
- package/scripts/lib/npm-version-check-diagnosis.cjs +59 -0
- package/scripts/lib/platform-conformance-tier.generated.cjs +287 -0
- package/scripts/lib/suite-detection.cjs +32 -0
- package/scripts/lint-allowed-tools-parity.cjs +221 -0
- package/scripts/lint-docs-guard-registration.exempt-baseline.cjs +47 -3
- package/scripts/lint-phase-arg-assignment.cjs +257 -0
- package/scripts/lint-phase-id-drift.cjs +623 -13
- package/scripts/lint-pr-branch-pattern-drift.cjs +148 -0
- package/scripts/lint-response-language-coverage.cjs +9 -3
- package/scripts/lint-retired-runtime-name.cjs +619 -0
- package/scripts/lint-source-test-name-collision.cjs +1 -1
- package/scripts/lint-state-write-path-drift.cjs +93 -0
- package/scripts/lint-test-file-count.allowlist.json +29 -9
- package/scripts/lint-vendored-deps.cjs +128 -17
- package/scripts/lint-workflow-shellcheck-baseline.json +100 -0
- package/scripts/prompt-injection-scan.sh +18 -0
- package/scripts/release-tarball-smoke.cjs +194 -1
- package/scripts/workflow-size.cjs +139 -0
- package/skills/gsd-autonomous/SKILL.md +2 -2
- package/skills/gsd-capture/SKILL.md +1 -1
- package/skills/gsd-cleanup/SKILL.md +1 -0
- package/skills/gsd-code-review/SKILL.md +2 -1
- package/skills/gsd-complete-milestone/SKILL.md +1 -0
- package/skills/gsd-config/SKILL.md +1 -0
- package/skills/gsd-debug/SKILL.md +1 -0
- package/skills/gsd-graphify/SKILL.md +1 -0
- package/skills/gsd-health/SKILL.md +1 -0
- package/skills/gsd-mempalace-capture/SKILL.md +8 -3
- package/skills/gsd-mempalace-recall/SKILL.md +1 -0
- package/skills/gsd-new-milestone/SKILL.md +1 -0
- package/skills/gsd-new-project/SKILL.md +1 -0
- package/skills/gsd-next/SKILL.md +1 -0
- package/skills/gsd-pause-work/SKILL.md +1 -0
- package/skills/gsd-phase/SKILL.md +1 -0
- package/skills/gsd-plan-review-convergence/SKILL.md +5 -5
- package/skills/gsd-pr-branch/SKILL.md +1 -0
- package/skills/gsd-progress/SKILL.md +1 -1
- package/skills/gsd-quick-batch/SKILL.md +1 -1
- package/skills/gsd-resume-work/SKILL.md +1 -0
- package/skills/gsd-review/SKILL.md +2 -3
- package/skills/gsd-review-backlog/SKILL.md +1 -0
- package/skills/gsd-settings/SKILL.md +2 -1
- package/skills/gsd-stats/SKILL.md +1 -0
- package/skills/gsd-thread/SKILL.md +1 -0
- package/skills/gsd-workspace/SKILL.md +1 -0
- package/skills/gsd-workstreams/SKILL.md +1 -0
- package/vscode/package.json +1 -1
- package/gsd-core/templates/claude-md.md +0 -145
- package/gsd-core/templates/codebase/concerns.md +0 -310
- package/gsd-core/templates/codebase/conventions.md +0 -307
- package/gsd-core/templates/codebase/integrations.md +0 -280
- package/gsd-core/templates/codebase/structure.md +0 -285
- package/gsd-core/templates/codebase/testing.md +0 -480
- package/gsd-core/templates/debug-subagent-prompt.md +0 -91
- package/gsd-core/templates/discovery.md +0 -146
|
@@ -32,6 +32,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
32
32
|
const node_fs_1 = __importDefault(require("node:fs"));
|
|
33
33
|
const node_path_1 = __importDefault(require("node:path"));
|
|
34
34
|
const markdown_sectionizer_cjs_1 = require("./markdown-sectionizer.cjs");
|
|
35
|
+
const security_cjs_1 = require("./security.cjs");
|
|
35
36
|
// eslint-disable-next-line @typescript-eslint/no-require-imports -- phase-id.cjs is an export= CommonJS module
|
|
36
37
|
const phaseIdMod = require("./phase-id.cjs");
|
|
37
38
|
const { stripProjectCodePrefix, extractPhaseToken, comparePhaseNum } = phaseIdMod;
|
|
@@ -380,6 +381,25 @@ function splitSegments(cmd) {
|
|
|
380
381
|
.map(s => s.trim())
|
|
381
382
|
.filter(s => s.length > 0);
|
|
382
383
|
}
|
|
384
|
+
/**
|
|
385
|
+
* Decode entity-escaped ampersands (`&` → `&`) — #4730, the grounding
|
|
386
|
+
* gate's share of the #3611 defect. Planners emit `<automated>` bodies with
|
|
387
|
+
* `&&` as the chain operator, and the executing agent reads the
|
|
388
|
+
* decoded (rendered) form. Without this decode, `splitSegments` cuts
|
|
389
|
+
* `&&` at its semicolons and a `cd` target absorbs the trailing
|
|
390
|
+
* `&` fragment (`rawTarget: "src &"`), reporting an existing directory
|
|
391
|
+
* as a `missing_dir` blocker. Applied to the command text inside
|
|
392
|
+
* `resolveVerifyCommandTarget` — before any segment splitting or target
|
|
393
|
+
* resolution, after `result.command` has captured the text verbatim — so the
|
|
394
|
+
* escaped and literal forms of the same command produce identical verdicts.
|
|
395
|
+
* Kept module-private beside `splitSegments`, mirroring the sibling
|
|
396
|
+
* `src/verify.cts`'s own private `decodeEntityAmps` (#3611): the two gates
|
|
397
|
+
* are separate modules that independently parse `<automated>` text, and
|
|
398
|
+
* neither imports the other.
|
|
399
|
+
*/
|
|
400
|
+
function decodeEntityAmps(s) {
|
|
401
|
+
return s.replace(/&/g, '&');
|
|
402
|
+
}
|
|
383
403
|
/** Strip a single matching pair of surrounding quotes, if present. */
|
|
384
404
|
function stripQuotes(s) {
|
|
385
405
|
if (s.length >= 2) {
|
|
@@ -438,6 +458,16 @@ function stripLeadingDotSlash(s) {
|
|
|
438
458
|
* without touching the filesystem. A climb that names a concrete sibling (e.g.
|
|
439
459
|
* `cd ../../frontend`, the exact #2401 shape) still names something checkable
|
|
440
460
|
* and falls through to the normal filesystem probe below.
|
|
461
|
+
*
|
|
462
|
+
* An ABSOLUTE target outside the project root takes the same `outside_root`
|
|
463
|
+
* exit (#4767). It is more ambiguous across worktrees, not less: it is pinned
|
|
464
|
+
* to exactly one checkout, and when a planner copies the orchestrator's cwd
|
|
465
|
+
* into `<automated>` that checkout is the main tree — so under worktree
|
|
466
|
+
* isolation the command exists, runs, and passes against code the worktree
|
|
467
|
+
* changed and the main tree did not. Existence is therefore not evidence for
|
|
468
|
+
* an absolute target outside the root, and the filesystem is not consulted.
|
|
469
|
+
* Containment goes through `tryWithinRootLexical` (#4636) — lexical because the
|
|
470
|
+
* probe is read-only and must not depend on the target existing.
|
|
441
471
|
*/
|
|
442
472
|
function isPureAncestorClimb(rel) {
|
|
443
473
|
if (rel.length === 0)
|
|
@@ -453,7 +483,7 @@ function declaredPathCovers(declaredPaths, norm) {
|
|
|
453
483
|
if (typeof p !== 'string')
|
|
454
484
|
return false;
|
|
455
485
|
const dp = stripLeadingDotSlash(toSlash(p));
|
|
456
|
-
return dp === target || dp.startsWith(target + '/');
|
|
486
|
+
return dp === target || dp.startsWith(target + '/'); // allow-handrolled-containment: declared-path coverage for pending-creation detection, not containment
|
|
457
487
|
});
|
|
458
488
|
}
|
|
459
489
|
/**
|
|
@@ -501,7 +531,10 @@ function resolveVerifyCommandTarget(command, options) {
|
|
|
501
531
|
if (typeof command !== 'string')
|
|
502
532
|
return result;
|
|
503
533
|
result.command = command;
|
|
504
|
-
|
|
534
|
+
// #4730: decode entity-escaped ampersands BEFORE segment splitting (see
|
|
535
|
+
// decodeEntityAmps) so the chain operator is visible to the splitter and
|
|
536
|
+
// the verdict matches what the executing agent's decoded form grounds to.
|
|
537
|
+
const trimmed = decodeEntityAmps(command.trim());
|
|
505
538
|
if (trimmed === '')
|
|
506
539
|
return result;
|
|
507
540
|
// Nyquist "MISSING — Wave 0 must create …" sentinel; Dimension 8 owns it.
|
|
@@ -550,7 +583,18 @@ function resolveVerifyCommandTarget(command, options) {
|
|
|
550
583
|
result.form = form;
|
|
551
584
|
result.rawTarget = rawTarget;
|
|
552
585
|
result.target = target;
|
|
553
|
-
if (
|
|
586
|
+
if (isAbs) {
|
|
587
|
+
// #4767: an absolute target outside projectRoot is `outside_root`, same
|
|
588
|
+
// as the bare climb — see isPureAncestorClimb's doc for why existence is
|
|
589
|
+
// not evidence here and the filesystem is deliberately not consulted.
|
|
590
|
+
if ((0, security_cjs_1.tryWithinRootLexical)(target, base) === null) {
|
|
591
|
+
result.status = 'ok';
|
|
592
|
+
result.severity = 'warning';
|
|
593
|
+
result.reason = 'outside_root';
|
|
594
|
+
return result;
|
|
595
|
+
}
|
|
596
|
+
}
|
|
597
|
+
else {
|
|
554
598
|
const rel = node_path_1.default.relative(base, target);
|
|
555
599
|
if (isPureAncestorClimb(rel)) {
|
|
556
600
|
result.status = 'ok';
|
|
@@ -13,6 +13,7 @@ const node_fs_1 = __importDefault(require("node:fs"));
|
|
|
13
13
|
const node_path_1 = __importDefault(require("node:path"));
|
|
14
14
|
const node_os_1 = __importDefault(require("node:os"));
|
|
15
15
|
const validate_cjs_1 = require("./validate.cjs");
|
|
16
|
+
const security_cjs_1 = require("./security.cjs");
|
|
16
17
|
// eslint-disable-next-line @typescript-eslint/no-require-imports -- planning-workspace.cjs is an export= CommonJS module
|
|
17
18
|
const planningWorkspace = require("./planning-workspace.cjs");
|
|
18
19
|
// eslint-disable-next-line @typescript-eslint/no-require-imports -- frontmatter.cjs is an export= CommonJS module
|
|
@@ -37,7 +38,7 @@ const worktreeSafetyMod = require("./worktree-safety.cjs");
|
|
|
37
38
|
// codebase-drift --name-status parse loop).
|
|
38
39
|
const { decodeGitQuotedPath } = worktreeSafetyMod;
|
|
39
40
|
const shell_command_projection_cjs_1 = require("./shell-command-projection.cjs");
|
|
40
|
-
const
|
|
41
|
+
const security_cjs_2 = require("./security.cjs");
|
|
41
42
|
const runtime_slash_cjs_1 = require("./runtime-slash.cjs");
|
|
42
43
|
const schema_detect_cjs_1 = require("./schema-detect.cjs");
|
|
43
44
|
const markdown_sectionizer_cjs_1 = require("./markdown-sectionizer.cjs");
|
|
@@ -63,7 +64,11 @@ const { SEVERITY: HEALTH_SEVERITY, REMEDY_ACTION, REMEDY_RISK, evaluateRules, ev
|
|
|
63
64
|
// eslint-disable-next-line @typescript-eslint/no-require-imports -- planning-snapshot.cjs is an export= CommonJS module
|
|
64
65
|
const planningSnapshotMod = require("./planning-snapshot.cjs");
|
|
65
66
|
const { buildPlanningSnapshot } = planningSnapshotMod;
|
|
66
|
-
|
|
67
|
+
// eslint-disable-next-line @typescript-eslint/no-require-imports -- onboard-projection.cjs is an export= CommonJS module
|
|
68
|
+
const onboardProjectionMod = require("./onboard-projection.cjs");
|
|
69
|
+
const { REQUIRED_CODEBASE_MAP_FILES } = onboardProjectionMod;
|
|
70
|
+
const clock_cjs_1 = require("./clock.cjs");
|
|
71
|
+
const { planningDir, planningRoot, withPlanningLock } = planningWorkspace;
|
|
67
72
|
const { defaultPhaseCleanCommitTimesMs } = verificationMod;
|
|
68
73
|
const { extractFrontmatter, parseMustHavesBlock } = frontmatterMod;
|
|
69
74
|
const { readStateHeadFreshness } = stateMod;
|
|
@@ -152,9 +157,12 @@ function verifySummaryCore(cwd, summaryPath, checkFileCount, opts) {
|
|
|
152
157
|
if (firstSegment.indexOf('.') > 0)
|
|
153
158
|
return false;
|
|
154
159
|
// Containment guard: a `../`-bearing reference must not turn this advisory
|
|
155
|
-
// into a filesystem existence probe outside the project.
|
|
156
|
-
|
|
157
|
-
|
|
160
|
+
// into a filesystem existence probe outside the project. Lexical (ADR-4650
|
|
161
|
+
// decision 6): the candidate is a string pulled from a SUMMARY document and
|
|
162
|
+
// by construction may not exist yet — existence is what gets probed
|
|
163
|
+
// downstream — and this is a pure string-heuristic filter with no other fs
|
|
164
|
+
// access, so a realpath call would also change its cost profile.
|
|
165
|
+
if ((0, security_cjs_1.tryWithinRootLexical)(candidate, projectRoot) === null)
|
|
158
166
|
return false;
|
|
159
167
|
return true;
|
|
160
168
|
};
|
|
@@ -846,8 +854,15 @@ function scanQuantitativeCriteria(content) {
|
|
|
846
854
|
// Not a markdown table: the negated-pipe class matches a SHELL pipeline
|
|
847
855
|
// stage boundary (git before the next `|`), the same shape the
|
|
848
856
|
// #429/#968 scanners use; there is no table row to parse.
|
|
857
|
+
// #4774: the lookahead keeps `||` — a logical OR, the construct that
|
|
858
|
+
// HANDLES the failure (e.g. the `git cat-file -e <sha> || echo missing`
|
|
859
|
+
// ghost-control idiom, reachable here when prose apostrophes leave the
|
|
860
|
+
// segment's quote state unclosed) — quiet, while `|` and `|&` (a real
|
|
861
|
+
// pipeline stage, stderr-merged or not) still warn. Accepted trade-off:
|
|
862
|
+
// a QUOTED `||` literal ahead of a real pipe (``git grep 'a||b' f | wc -l``)
|
|
863
|
+
// also goes quiet — the lookahead cannot reach past the doubled pipe.
|
|
849
864
|
// allow-adhoc-markdown: shell pipeline stage boundary, not a table cell (#4024)
|
|
850
|
-
if (/\bgit\s+[a-z][^\n|]
|
|
865
|
+
if (/\bgit\s+[a-z][^\n|]*\|(?!\|)/.test(seg)) {
|
|
851
866
|
record(warnings, 'R4', '[plan-criteria R4] A fallible `git` in a non-final pipeline stage is swallowed — the pipeline reports ' +
|
|
852
867
|
'the last stage\'s status, so a broken command reads as clean. Capture the status first.', seenWarn);
|
|
853
868
|
}
|
|
@@ -918,6 +933,13 @@ function extractPlanTaskInfos(content) {
|
|
|
918
933
|
const nameArr = (0, markdown_sectionizer_cjs_1.extractTaggedBlocks)(body, 'name');
|
|
919
934
|
const hasName = nameArr.length > 0;
|
|
920
935
|
const name = hasName ? nameArr[0].trim() : '';
|
|
936
|
+
// `(?:^|\s)` (not `\b`) so a hyphenated attribute ending in `auto_select`
|
|
937
|
+
// can never be mistaken for the real attribute — the same defensive
|
|
938
|
+
// anchor as extractOptionIds' `id` match below (#4095).
|
|
939
|
+
const autoSelectMatch = attrs.match(/(?:^|\s)auto_select\s*=\s*["']([^"']*)["']/);
|
|
940
|
+
const autoSelect = autoSelectMatch ? autoSelectMatch[1] : null;
|
|
941
|
+
const optionsArr = (0, markdown_sectionizer_cjs_1.extractTaggedBlocks)(body, 'options');
|
|
942
|
+
const optionIds = optionsArr.length > 0 ? extractOptionIds(optionsArr[0]) : [];
|
|
921
943
|
infos.push({
|
|
922
944
|
name,
|
|
923
945
|
type,
|
|
@@ -935,6 +957,8 @@ function extractPlanTaskInfos(content) {
|
|
|
935
957
|
hasHowToVerify: /<how-to-verify[\s>]/.test(body),
|
|
936
958
|
hasDecision: /<decision[\s>]/.test(body),
|
|
937
959
|
hasOptions: /<options[\s>]/.test(body),
|
|
960
|
+
autoSelect,
|
|
961
|
+
optionIds,
|
|
938
962
|
hasInstructions: /<instructions[\s>]/.test(body),
|
|
939
963
|
hasVerification: /<verification[\s>]/.test(body),
|
|
940
964
|
hasResumeSignal: /<resume-signal[\s>]/.test(body),
|
|
@@ -946,6 +970,35 @@ function extractPlanTaskInfos(content) {
|
|
|
946
970
|
}
|
|
947
971
|
return infos;
|
|
948
972
|
}
|
|
973
|
+
/**
|
|
974
|
+
* Extract the `id` attribute of every `<option id="…">` opening tag found in
|
|
975
|
+
* `optionsBody` (the inner text of one `<options>…</options>` block), in
|
|
976
|
+
* document order. Bounded attribute scan (`[^>]{0,500}`), mirroring the same
|
|
977
|
+
* ReDoS-safe idiom `extractPlanTaskInfos` uses for the `<task type="…">`
|
|
978
|
+
* attribute string — this file's established pattern for reading an
|
|
979
|
+
* attribute value without a general XML parser (#4095).
|
|
980
|
+
*/
|
|
981
|
+
function extractOptionIds(optionsBody) {
|
|
982
|
+
const ids = [];
|
|
983
|
+
if (typeof optionsBody !== 'string' || optionsBody.length === 0)
|
|
984
|
+
return ids;
|
|
985
|
+
const OPTION_OPEN_RE = /<option(\s[^>]{0,500})?>/g;
|
|
986
|
+
let match;
|
|
987
|
+
while ((match = OPTION_OPEN_RE.exec(optionsBody)) !== null) {
|
|
988
|
+
const attrs = match[1] ?? '';
|
|
989
|
+
// `(?:^|\s)` (not `\b`) so a decoy attribute like `data-id="…"` inside
|
|
990
|
+
// the same opening tag cannot be mistaken for the real `id` — `\b`
|
|
991
|
+
// matches at the `-`→`i` boundary too, which `.match()`'s
|
|
992
|
+
// first-hit-wins semantics would then silently prefer (#4095).
|
|
993
|
+
const idMatch = attrs.match(/(?:^|\s)id\s*=\s*["']([^"']{1,200})["']/);
|
|
994
|
+
if (idMatch)
|
|
995
|
+
ids.push(idMatch[1]);
|
|
996
|
+
if (match.index === OPTION_OPEN_RE.lastIndex) {
|
|
997
|
+
OPTION_OPEN_RE.lastIndex++;
|
|
998
|
+
}
|
|
999
|
+
}
|
|
1000
|
+
return ids;
|
|
1001
|
+
}
|
|
949
1002
|
function isCheckpointType(type) {
|
|
950
1003
|
return type.startsWith('checkpoint:');
|
|
951
1004
|
}
|
|
@@ -988,6 +1041,15 @@ function validatePlanTaskStructure(task) {
|
|
|
988
1041
|
errors.push(`Task '${taskName}' missing <decision>`);
|
|
989
1042
|
if (!task.hasOptions)
|
|
990
1043
|
errors.push(`Task '${taskName}' missing <options>`);
|
|
1044
|
+
if (task.autoSelect !== null) {
|
|
1045
|
+
if (task.autoSelect.length === 0) {
|
|
1046
|
+
errors.push(`Task '${taskName}' auto_select is empty — name an <option id="…">`);
|
|
1047
|
+
}
|
|
1048
|
+
else if (task.hasOptions && !task.optionIds.includes(task.autoSelect)) {
|
|
1049
|
+
errors.push(`Task '${taskName}' auto_select="${task.autoSelect}" does not match any `
|
|
1050
|
+
+ `<option id="…"> (available: ${task.optionIds.join(', ') || 'none'})`);
|
|
1051
|
+
}
|
|
1052
|
+
}
|
|
991
1053
|
break;
|
|
992
1054
|
case 'checkpoint:human-action':
|
|
993
1055
|
if (!task.hasAction)
|
|
@@ -1157,6 +1219,11 @@ function cmdVerifyPhaseCompleteness(cwd, phase, raw) {
|
|
|
1157
1219
|
warnings,
|
|
1158
1220
|
}, raw, errors.length === 0 ? 'complete' : 'incomplete');
|
|
1159
1221
|
}
|
|
1222
|
+
// #4678: citations may carry a trailing line suffix (":42", ":1-20") that
|
|
1223
|
+
// describes a location inside the file, not part of the path itself.
|
|
1224
|
+
function stripLineSuffix(ref) {
|
|
1225
|
+
return ref.replace(/:\d+(?:-\d+)?$/, '');
|
|
1226
|
+
}
|
|
1160
1227
|
function cmdVerifyReferences(cwd, filePath, raw) {
|
|
1161
1228
|
if (!filePath) {
|
|
1162
1229
|
error('file path required');
|
|
@@ -1172,9 +1239,10 @@ function cmdVerifyReferences(cwd, filePath, raw) {
|
|
|
1172
1239
|
const atRefs = content.match(/@([^\s\n,)]+\/[^\s\n,)]+)/g) || [];
|
|
1173
1240
|
for (const ref of atRefs) {
|
|
1174
1241
|
const cleanRef = ref.slice(1);
|
|
1175
|
-
const
|
|
1176
|
-
|
|
1177
|
-
|
|
1242
|
+
const fsRef = stripLineSuffix(cleanRef);
|
|
1243
|
+
const resolved = fsRef.startsWith('~/')
|
|
1244
|
+
? node_path_1.default.join(process.env['HOME'] || '', fsRef.slice(2))
|
|
1245
|
+
: node_path_1.default.join(cwd, fsRef);
|
|
1178
1246
|
if (node_fs_1.default.existsSync(resolved)) {
|
|
1179
1247
|
found.push(cleanRef);
|
|
1180
1248
|
}
|
|
@@ -1182,14 +1250,14 @@ function cmdVerifyReferences(cwd, filePath, raw) {
|
|
|
1182
1250
|
missing.push(cleanRef);
|
|
1183
1251
|
}
|
|
1184
1252
|
}
|
|
1185
|
-
const backtickRefs = content.match(/`([^`]+\/[^`]+\.[a-zA-Z]{1,10})`/g) || [];
|
|
1253
|
+
const backtickRefs = content.match(/`([^`]+\/[^`]+\.[a-zA-Z]{1,10}(?::\d+(?:-\d+)?)?)`/g) || [];
|
|
1186
1254
|
for (const ref of backtickRefs) {
|
|
1187
1255
|
const cleanRef = ref.slice(1, -1);
|
|
1188
1256
|
if (cleanRef.startsWith('http') || cleanRef.includes('${') || cleanRef.includes('{{'))
|
|
1189
1257
|
continue;
|
|
1190
1258
|
if (found.includes(cleanRef) || missing.includes(cleanRef))
|
|
1191
1259
|
continue;
|
|
1192
|
-
const resolved = node_path_1.default.join(cwd, cleanRef);
|
|
1260
|
+
const resolved = node_path_1.default.join(cwd, stripLineSuffix(cleanRef));
|
|
1193
1261
|
if (node_fs_1.default.existsSync(resolved)) {
|
|
1194
1262
|
found.push(cleanRef);
|
|
1195
1263
|
}
|
|
@@ -1251,28 +1319,75 @@ function cmdVerifyArtifacts(cwd, planFilePath, raw) {
|
|
|
1251
1319
|
const artFullPath = node_path_1.default.join(cwd, artPath);
|
|
1252
1320
|
const exists = node_fs_1.default.existsSync(artFullPath);
|
|
1253
1321
|
const check = { path: artPath, exists, issues: [], passed: false };
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1322
|
+
// #4685: one artifact's I/O problem is that artifact's failure, never the
|
|
1323
|
+
// whole plan's. `safeReadFile` rethrows every errno except ENOENT, so before
|
|
1324
|
+
// this an unreadable entry — a directory most commonly, but equally an EACCES
|
|
1325
|
+
// file or a dangling mount — threw out of the loop and the command reported
|
|
1326
|
+
// NOTHING: not the offending entry, and not the plan's other, perfectly good
|
|
1327
|
+
// artifacts either. A check that disappears is worse than a check that fails,
|
|
1328
|
+
// because a failure is visible.
|
|
1329
|
+
//
|
|
1330
|
+
// Scope of this guard, stated precisely (review nit): the `try` encloses the
|
|
1331
|
+
// whole per-artifact body, but the only statements in it that can throw are the
|
|
1332
|
+
// `statSync` and the read — the `min_lines`/`contains`/`exports` checks below
|
|
1333
|
+
// are pure string operations. So this catches I/O, and nothing here is a
|
|
1334
|
+
// deliberate guard around those criteria checks. A path `fs.existsSync` already
|
|
1335
|
+
// rejected never reaches here either (that is the `File not found` branch), so
|
|
1336
|
+
// this is not a claim to catch every way a path can be unusable.
|
|
1337
|
+
try {
|
|
1338
|
+
if (exists) {
|
|
1339
|
+
// A directory is reported as its own kind of failure, distinct from
|
|
1340
|
+
// `File not found`: the path resolved, it simply is not the thing an
|
|
1341
|
+
// artifact entry can be checked against. Verifying a directory (matching
|
|
1342
|
+
// `contains:`/`min_lines:`/`exports:` across the files inside it) is a
|
|
1343
|
+
// feature decision, deliberately not made here.
|
|
1344
|
+
if (node_fs_1.default.statSync(artFullPath).isDirectory()) {
|
|
1345
|
+
check['issues'].push('Not a file: path is a directory');
|
|
1346
|
+
}
|
|
1347
|
+
else {
|
|
1348
|
+
// `safeReadFile` returns null on ENOENT, and `|| ''` would turn that
|
|
1349
|
+
// into an empty file — which an entry carrying only `path`/`provides`
|
|
1350
|
+
// would then PASS, having checked nothing. `statSync` just succeeded, so
|
|
1351
|
+
// a null here means the artifact went away mid-check. Report that rather
|
|
1352
|
+
// than inheriting a pass from it. (Pre-existing above this fix, reachable
|
|
1353
|
+
// through the same race after `existsSync`; found in review.)
|
|
1354
|
+
const rawContent = (0, shell_command_projection_cjs_1.platformReadSync)(artFullPath);
|
|
1355
|
+
if (rawContent === null) {
|
|
1356
|
+
check['issues'].push('Unreadable: disappeared during check');
|
|
1357
|
+
results.push(check);
|
|
1358
|
+
continue;
|
|
1359
|
+
}
|
|
1360
|
+
const fileContent = rawContent;
|
|
1361
|
+
const lineCount = fileContent.split('\n').length;
|
|
1362
|
+
if (artifact['min_lines'] && lineCount < artifact['min_lines']) {
|
|
1363
|
+
check['issues'].push(`Only ${lineCount} lines, need ${artifact['min_lines']}`);
|
|
1364
|
+
}
|
|
1365
|
+
if (artifact['contains'] && !fileContent.includes(artifact['contains'])) {
|
|
1366
|
+
check['issues'].push(`Missing pattern: ${artifact['contains']}`);
|
|
1367
|
+
}
|
|
1368
|
+
if (artifact['exports']) {
|
|
1369
|
+
const exports = Array.isArray(artifact['exports'])
|
|
1370
|
+
? artifact['exports']
|
|
1371
|
+
: [artifact['exports']];
|
|
1372
|
+
for (const exp of exports) {
|
|
1373
|
+
if (!fileContent.includes(exp))
|
|
1374
|
+
check['issues'].push(`Missing export: ${exp}`);
|
|
1375
|
+
}
|
|
1376
|
+
}
|
|
1377
|
+
check['passed'] = check['issues'].length === 0;
|
|
1270
1378
|
}
|
|
1271
1379
|
}
|
|
1272
|
-
|
|
1380
|
+
else {
|
|
1381
|
+
check['issues'].push('File not found');
|
|
1382
|
+
}
|
|
1273
1383
|
}
|
|
1274
|
-
|
|
1275
|
-
|
|
1384
|
+
catch (err) {
|
|
1385
|
+
// Unreadable for some other reason. Record the errno rather than a generic
|
|
1386
|
+
// message — an operator seeing EACCES acts differently from one seeing EIO —
|
|
1387
|
+
// and leave `passed` false.
|
|
1388
|
+
const e = err;
|
|
1389
|
+
check['issues'].push(`Unreadable: ${e.code || (e.message ?? String(err))}`);
|
|
1390
|
+
check['passed'] = false;
|
|
1276
1391
|
}
|
|
1277
1392
|
results.push(check);
|
|
1278
1393
|
}
|
|
@@ -1378,11 +1493,11 @@ function cmdVerifyKeyLinks(cwd, planFilePath, raw) {
|
|
|
1378
1493
|
// project. Leave sourceContent as null so the existing not-found /
|
|
1379
1494
|
// pending classification below runs unchanged. Note this guard is
|
|
1380
1495
|
// narrower than it may look: `from: "."` is a non-empty string, so it
|
|
1381
|
-
// still reaches
|
|
1496
|
+
// still reaches tryWithinRoot and safeReadFile below, and DOES read the
|
|
1382
1497
|
// cwd directory (yielding "Source read failed: EISDIR") — this branch
|
|
1383
1498
|
// only short-circuits the true empty-string case.
|
|
1384
|
-
const
|
|
1385
|
-
if (
|
|
1499
|
+
const fromContained = (0, security_cjs_2.tryWithinRoot)(fromPath, cwd);
|
|
1500
|
+
if (fromContained === null) {
|
|
1386
1501
|
// Do not echo result.error — it embeds absolute host paths.
|
|
1387
1502
|
check['path_rejected'] = 'from';
|
|
1388
1503
|
check['detail'] = 'Source path rejected — resolves outside the project directory';
|
|
@@ -1390,7 +1505,7 @@ function cmdVerifyKeyLinks(cwd, planFilePath, raw) {
|
|
|
1390
1505
|
continue;
|
|
1391
1506
|
}
|
|
1392
1507
|
try {
|
|
1393
|
-
sourceContent = (0, shell_command_projection_cjs_1.platformReadSync)(
|
|
1508
|
+
sourceContent = (0, shell_command_projection_cjs_1.platformReadSync)(fromContained);
|
|
1394
1509
|
}
|
|
1395
1510
|
catch (err) {
|
|
1396
1511
|
// Report the errno only — never the message or path (untrusted `from:`
|
|
@@ -1458,8 +1573,8 @@ function cmdVerifyKeyLinks(cwd, planFilePath, raw) {
|
|
|
1458
1573
|
// An empty/missing `to:` is a malformed plan, not a
|
|
1459
1574
|
// path-confinement violation — only a non-empty path that
|
|
1460
1575
|
// actually resolves outside the project is path_rejected.
|
|
1461
|
-
const
|
|
1462
|
-
if (
|
|
1576
|
+
const toContained = (0, security_cjs_2.tryWithinRoot)(toPath, cwd);
|
|
1577
|
+
if (toContained === null) {
|
|
1463
1578
|
// Do not read a rejected `to:` — treat as no target content
|
|
1464
1579
|
// and do not echo result.error, which embeds absolute host
|
|
1465
1580
|
// paths.
|
|
@@ -1467,7 +1582,7 @@ function cmdVerifyKeyLinks(cwd, planFilePath, raw) {
|
|
|
1467
1582
|
check['detail'] = `Pattern "${link['pattern']}" not found in source; target path rejected — resolves outside the project directory`;
|
|
1468
1583
|
}
|
|
1469
1584
|
else {
|
|
1470
|
-
targetContent = (0, shell_command_projection_cjs_1.platformReadSync)(
|
|
1585
|
+
targetContent = (0, shell_command_projection_cjs_1.platformReadSync)(toContained);
|
|
1471
1586
|
}
|
|
1472
1587
|
}
|
|
1473
1588
|
if (targetContent && pat.test(targetContent)) {
|
|
@@ -1823,9 +1938,9 @@ function resolvePhaseDirByToken(phasesDir, phaseArg) {
|
|
|
1823
1938
|
const matched = matchPhaseDirs(dirNames, normalizedPhase).matches[0];
|
|
1824
1939
|
if (matched)
|
|
1825
1940
|
return node_path_1.default.join(phasesDir, matched);
|
|
1826
|
-
const
|
|
1827
|
-
if (
|
|
1828
|
-
return
|
|
1941
|
+
const contained = (0, security_cjs_2.tryWithinRoot)(phaseArg, phasesDir);
|
|
1942
|
+
if (contained !== null && node_fs_1.default.existsSync(contained))
|
|
1943
|
+
return contained;
|
|
1829
1944
|
return null;
|
|
1830
1945
|
}
|
|
1831
1946
|
/**
|
|
@@ -1986,6 +2101,110 @@ function cmdVerifySchemaDrift(cwd, phaseArg, skipFlag, raw) {
|
|
|
1986
2101
|
skipped: isSkipped,
|
|
1987
2102
|
}, raw);
|
|
1988
2103
|
}
|
|
2104
|
+
/**
|
|
2105
|
+
* Stamp `last_mapped_commit` (plus `last_mapped_at`) into the frontmatter of
|
|
2106
|
+
* every codebase-map document that exists on disk, using the current HEAD sha.
|
|
2107
|
+
*
|
|
2108
|
+
* #3418: `drift.cjs` shipped a correct `writeMappedCommit` with no production
|
|
2109
|
+
* caller, so no full `/gsd:map-codebase` run ever wrote the machine-readable
|
|
2110
|
+
* baseline that `cmdVerifyCodebaseDrift` reads. The stamp lives in CODE rather
|
|
2111
|
+
* than in a prose instruction to the mapper agent on purpose: an agent that
|
|
2112
|
+
* decides its work is already done skips a prose step silently, which is the
|
|
2113
|
+
* exact class of failure the stamp exists to detect.
|
|
2114
|
+
*
|
|
2115
|
+
* Only documents that already exist are stamped -- a `--fast` map produces four
|
|
2116
|
+
* of the seven, and this must not conjure the missing three as frontmatter-only
|
|
2117
|
+
* stubs that would then satisfy the seven-file completeness probe. `only`
|
|
2118
|
+
* (`--files a.md,b.md`) narrows further, for a caller that refreshed a subset.
|
|
2119
|
+
*
|
|
2120
|
+
* Non-blocking by contract, like every other drift surface: any failure emits
|
|
2121
|
+
* `skipped` with a reason and exits 0.
|
|
2122
|
+
*/
|
|
2123
|
+
function cmdStampCodebaseMap(cwd, raw, only) {
|
|
2124
|
+
// Non-hoisted: load-order matters for circular dep guard
|
|
2125
|
+
// eslint-disable-next-line @typescript-eslint/no-require-imports -- drift.cjs is an export= CommonJS module
|
|
2126
|
+
const drift = require('./drift.cjs');
|
|
2127
|
+
const emit = (payload) => output(payload, raw);
|
|
2128
|
+
const skip = (reason) => ({
|
|
2129
|
+
stamped: [],
|
|
2130
|
+
commit: null,
|
|
2131
|
+
stamped_at: null,
|
|
2132
|
+
skipped: true,
|
|
2133
|
+
reason,
|
|
2134
|
+
});
|
|
2135
|
+
try {
|
|
2136
|
+
// Probed outside the lock on purpose: taking the lock creates `.planning/`
|
|
2137
|
+
// if absent, and a stamp against a project that has no codebase map at all
|
|
2138
|
+
// must not conjure the directory. The per-document existence check inside
|
|
2139
|
+
// the lock is the one that matters -- a map deleted after this probe lands
|
|
2140
|
+
// on `no-codebase-map` there rather than being recreated as stubs.
|
|
2141
|
+
const codebaseDir = node_path_1.default.join(planningDir(cwd), 'codebase');
|
|
2142
|
+
if (!node_fs_1.default.existsSync(codebaseDir)) {
|
|
2143
|
+
emit(skip('no-codebase-dir'));
|
|
2144
|
+
return;
|
|
2145
|
+
}
|
|
2146
|
+
// `--files` restricts the stamp to the documents a caller actually
|
|
2147
|
+
// refreshed. The execute-phase auto-remap path rewrites STRUCTURE.md and
|
|
2148
|
+
// ARCHITECTURE.md only; stamping the other five at HEAD there would claim a
|
|
2149
|
+
// currency they do not have. Membership is checked against the closed
|
|
2150
|
+
// seven-document set, so an unknown name is a fail-loud non-answer rather
|
|
2151
|
+
// than a path this function tries to resolve. An empty value is refused
|
|
2152
|
+
// rather than read as "no filter": a caller that meant to narrow the scope
|
|
2153
|
+
// must not silently widen it to all seven.
|
|
2154
|
+
let candidates = REQUIRED_CODEBASE_MAP_FILES;
|
|
2155
|
+
if (only) {
|
|
2156
|
+
if (only.length === 0) {
|
|
2157
|
+
emit(skip('empty-codebase-map-file-filter'));
|
|
2158
|
+
return;
|
|
2159
|
+
}
|
|
2160
|
+
const unknown = only.filter((file) => !candidates.includes(file));
|
|
2161
|
+
if (unknown.length > 0) {
|
|
2162
|
+
emit(skip('unknown-codebase-map-file: ' + unknown.join(',')));
|
|
2163
|
+
return;
|
|
2164
|
+
}
|
|
2165
|
+
candidates = candidates.filter((file) => only.includes(file));
|
|
2166
|
+
}
|
|
2167
|
+
// Everything the stamp reads is read under the lock it writes under, the
|
|
2168
|
+
// same lock the rest of the .planning/ writers take. Two stampers can run
|
|
2169
|
+
// at once (the full map-codebase run and the execute-phase auto-remap);
|
|
2170
|
+
// one that resolved HEAD or listed the present documents before waiting on
|
|
2171
|
+
// the lock would write its now-stale sha over the newer one, or recreate a
|
|
2172
|
+
// document deleted while it waited as a frontmatter-only stub.
|
|
2173
|
+
const result = withPlanningLock(cwd, () => {
|
|
2174
|
+
const revProbe = (0, shell_command_projection_cjs_1.execGit)(['rev-parse', 'HEAD'], { cwd });
|
|
2175
|
+
if (revProbe.exitCode !== 0)
|
|
2176
|
+
return skip('not-a-git-repo');
|
|
2177
|
+
const commit = revProbe.stdout.trim();
|
|
2178
|
+
if (!/^[0-9a-f]{7,40}$/.test(commit))
|
|
2179
|
+
return skip('unreadable-head');
|
|
2180
|
+
const present = candidates.filter((file) => node_fs_1.default.existsSync(node_path_1.default.join(codebaseDir, file)));
|
|
2181
|
+
if (present.length === 0)
|
|
2182
|
+
return skip('no-codebase-map');
|
|
2183
|
+
// Host-local calendar day, matching the `**Analysis Date:**` line the
|
|
2184
|
+
// mapper agent writes -- the two freshness markers must not disagree by
|
|
2185
|
+
// a timezone.
|
|
2186
|
+
const stampedAt = clock_cjs_1.realClock.localToday();
|
|
2187
|
+
const write = drift['writeMappedCommit'];
|
|
2188
|
+
const stamped = [];
|
|
2189
|
+
const failed = [];
|
|
2190
|
+
for (const file of present) {
|
|
2191
|
+
try {
|
|
2192
|
+
write(node_path_1.default.join(codebaseDir, file), commit, stampedAt);
|
|
2193
|
+
stamped.push(file);
|
|
2194
|
+
}
|
|
2195
|
+
catch (err) {
|
|
2196
|
+
// One unwritable document must not cost the stamp on the other six.
|
|
2197
|
+
failed.push({ file, reason: err instanceof Error ? err.message : String(err) });
|
|
2198
|
+
}
|
|
2199
|
+
}
|
|
2200
|
+
return { stamped, failed, commit, stamped_at: stampedAt, skipped: false, reason: null };
|
|
2201
|
+
});
|
|
2202
|
+
emit(result);
|
|
2203
|
+
}
|
|
2204
|
+
catch (err) {
|
|
2205
|
+
emit(skip('exception: ' + (err instanceof Error ? err.message : String(err))));
|
|
2206
|
+
}
|
|
2207
|
+
}
|
|
1989
2208
|
function cmdVerifyCodebaseDrift(cwd, raw) {
|
|
1990
2209
|
// Non-hoisted: load-order matters for circular dep guard
|
|
1991
2210
|
// eslint-disable-next-line @typescript-eslint/no-require-imports -- drift.cjs is an export= CommonJS module
|
|
@@ -2034,16 +2253,45 @@ function cmdVerifyCodebaseDrift(cwd, raw) {
|
|
|
2034
2253
|
});
|
|
2035
2254
|
return;
|
|
2036
2255
|
}
|
|
2037
|
-
|
|
2038
|
-
|
|
2039
|
-
|
|
2040
|
-
|
|
2256
|
+
// #3418: an absent or unresolvable baseline means NO COMPARISON IS POSSIBLE.
|
|
2257
|
+
// It is neither zero drift nor total drift, and reporting it as either is a
|
|
2258
|
+
// lie the consumer cannot detect. The former fallback diffed HEAD against
|
|
2259
|
+
// the empty tree, so every tracked file read as newly added and the gate
|
|
2260
|
+
// reported maximum drift identically on every run -- which made a genuinely
|
|
2261
|
+
// stale map indistinguishable from a fresh one, and let `spawn_mapper` fire
|
|
2262
|
+
// a whole-repo remap while presenting itself as an incremental one.
|
|
2263
|
+
if (!lastMapped) {
|
|
2264
|
+
emit({
|
|
2265
|
+
block: false,
|
|
2266
|
+
skipped: true,
|
|
2267
|
+
reason: 'no-mapped-commit',
|
|
2268
|
+
action_required: false,
|
|
2269
|
+
directive: 'none',
|
|
2270
|
+
elements: [],
|
|
2271
|
+
last_mapped_commit: null,
|
|
2272
|
+
});
|
|
2273
|
+
return;
|
|
2041
2274
|
}
|
|
2042
|
-
|
|
2043
|
-
|
|
2044
|
-
|
|
2045
|
-
|
|
2275
|
+
const baseProbe = (0, shell_command_projection_cjs_1.execGit)(['cat-file', '-t', lastMapped], { cwd });
|
|
2276
|
+
if (baseProbe.exitCode !== 0 || baseProbe.stdout.trim() !== 'commit') {
|
|
2277
|
+
// A stamp git cannot resolve: history rewrite, GC, or a shallow clone.
|
|
2278
|
+
// Distinct reason from 'no-mapped-commit' -- the map claims a baseline,
|
|
2279
|
+
// this repository just cannot see it, which is an operator-actionable
|
|
2280
|
+
// difference (re-map vs. unshallow). A resolvable non-commit (a tree or
|
|
2281
|
+
// blob sha, a ref name) is the same class of bad baseline: git would
|
|
2282
|
+
// happily diff against it and report drift against the wrong object.
|
|
2283
|
+
emit({
|
|
2284
|
+
block: false,
|
|
2285
|
+
skipped: true,
|
|
2286
|
+
reason: 'unresolvable-mapped-commit',
|
|
2287
|
+
action_required: false,
|
|
2288
|
+
directive: 'none',
|
|
2289
|
+
elements: [],
|
|
2290
|
+
last_mapped_commit: lastMapped,
|
|
2291
|
+
});
|
|
2292
|
+
return;
|
|
2046
2293
|
}
|
|
2294
|
+
const base = lastMapped;
|
|
2047
2295
|
const diff = (0, shell_command_projection_cjs_1.execGit)(['diff', '--name-status', base, 'HEAD'], { cwd });
|
|
2048
2296
|
if (diff.exitCode !== 0) {
|
|
2049
2297
|
emit({
|
|
@@ -2056,6 +2304,27 @@ function cmdVerifyCodebaseDrift(cwd, raw) {
|
|
|
2056
2304
|
});
|
|
2057
2305
|
return;
|
|
2058
2306
|
}
|
|
2307
|
+
// #3418: GSD's own planning artifacts are not codebase structure. A
|
|
2308
|
+
// map-codebase run commits `.planning/codebase/*.md`, so a correctly
|
|
2309
|
+
// stamped baseline would be re-poisoned by the very commit that carries
|
|
2310
|
+
// the stamp -- the next gate invocation would report the map's own seven
|
|
2311
|
+
// documents as seven new directories, back over the default threshold of
|
|
2312
|
+
// three. Derived from planningRoot() rather than a hardcoded literal so a
|
|
2313
|
+
// repoint of the planning root cannot leave this filter behind.
|
|
2314
|
+
//
|
|
2315
|
+
// `git diff --name-status` always prints repo-root-relative paths, so a cwd
|
|
2316
|
+
// below the root needs the `sub/` prefix or the filter matches nothing.
|
|
2317
|
+
// That prefix comes from git (`--show-prefix`: root-relative, forward
|
|
2318
|
+
// slashes, trailing slash, empty at the root). The rejected alternative was
|
|
2319
|
+
// path.relative(`--show-toplevel`, cwd), which mixes two path producers: on
|
|
2320
|
+
// Windows os.tmpdir() hands back the 8.3 short form while git resolves the
|
|
2321
|
+
// long one, so relative() between them yields a `../..` chain that matches
|
|
2322
|
+
// nothing. The `.planning` half below is safe to compute with relative()
|
|
2323
|
+
// because both of its sides are the same cwd string.
|
|
2324
|
+
const prefixProbe = (0, shell_command_projection_cjs_1.execGit)(['rev-parse', '--show-prefix'], { cwd });
|
|
2325
|
+
const repoPrefix = prefixProbe.exitCode === 0 ? prefixProbe.stdout.trim() : '';
|
|
2326
|
+
const planningPrefix = repoPrefix + node_path_1.default.relative(cwd, planningRoot(cwd)).split(node_path_1.default.sep).join('/') + '/';
|
|
2327
|
+
const isPlanningArtifact = (file) => file.split('\\').join('/').startsWith(planningPrefix);
|
|
2059
2328
|
const added = [];
|
|
2060
2329
|
const modified = [];
|
|
2061
2330
|
const deleted = [];
|
|
@@ -2076,6 +2345,8 @@ function cmdVerifyCodebaseDrift(cwd, raw) {
|
|
|
2076
2345
|
// ASCII common case — passes through untouched. Both capture groups are
|
|
2077
2346
|
// decoded: R/C lines carry old AND new paths, either may be quoted.
|
|
2078
2347
|
const file = decodeGitQuotedPath(m[3] || m[2]);
|
|
2348
|
+
if (isPlanningArtifact(file))
|
|
2349
|
+
continue;
|
|
2079
2350
|
if (status === 'A' || status === 'R' || status === 'C')
|
|
2080
2351
|
added.push(file);
|
|
2081
2352
|
else if (status === 'M')
|
|
@@ -2154,5 +2425,6 @@ module.exports = {
|
|
|
2154
2425
|
cmdVerifyCodebaseDrift,
|
|
2155
2426
|
computeContextDrift,
|
|
2156
2427
|
cmdVerifyContextDrift,
|
|
2428
|
+
cmdStampCodebaseMap,
|
|
2157
2429
|
STATE_HEAD_ADVISORY_COMMITS,
|
|
2158
2430
|
};
|