@opengsd/gsd-core 1.14.0 → 1.16.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 +85 -5
- 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-code-fixer.compact.md +7 -6
- package/agents/gsd-code-fixer.md +9 -8
- package/agents/gsd-code-reviewer.compact.md +5 -3
- package/agents/gsd-code-reviewer.md +8 -6
- package/agents/gsd-debug-session-manager.compact.md +17 -2
- package/agents/gsd-debug-session-manager.md +17 -2
- package/agents/gsd-debugger.md +3 -3
- package/agents/gsd-eval-auditor.compact.md +1 -1
- package/agents/gsd-eval-auditor.md +1 -1
- package/agents/gsd-executor.md +17 -12
- package/agents/gsd-intel-updater.compact.md +1 -1
- package/agents/gsd-intel-updater.md +1 -1
- package/agents/gsd-mempalace-curator.md +2 -2
- package/agents/gsd-phase-researcher.md +19 -11
- package/agents/gsd-plan-checker.md +15 -9
- package/agents/gsd-planner.md +15 -11
- package/agents/gsd-project-researcher.compact.md +1 -1
- package/agents/gsd-project-researcher.md +1 -1
- package/agents/gsd-research-synthesizer.compact.md +1 -1
- package/agents/gsd-research-synthesizer.md +1 -1
- package/agents/gsd-ui-auditor.compact.md +21 -30
- package/agents/gsd-ui-auditor.md +166 -37
- package/agents/gsd-ui-researcher.compact.md +1 -1
- package/agents/gsd-ui-researcher.md +1 -1
- package/agents/gsd-verifier.md +37 -14
- package/bin/install.js +764 -287
- package/commands/gsd/add-tests.md +6 -1
- package/commands/gsd/ai-integration-phase.md +6 -1
- package/commands/gsd/audit-fix.md +5 -0
- package/commands/gsd/audit-milestone.md +6 -1
- package/commands/gsd/autonomous.md +7 -2
- package/commands/gsd/capture.md +9 -5
- package/commands/gsd/code-review.md +7 -2
- package/commands/gsd/complete-milestone.md +4 -0
- package/commands/gsd/config.md +7 -3
- package/commands/gsd/debug.md +11 -7
- package/commands/gsd/discuss-phase.md +7 -3
- package/commands/gsd/docs-update.md +12 -7
- package/commands/gsd/eval-review.md +6 -1
- package/commands/gsd/execute-phase.md +12 -7
- package/commands/gsd/extract-learnings.md +5 -0
- package/commands/gsd/fast.md +4 -0
- package/commands/gsd/forensics.md +5 -1
- package/commands/gsd/graphify.md +10 -6
- package/commands/gsd/health.md +5 -0
- package/commands/gsd/help.md +7 -2
- package/commands/gsd/import.md +7 -3
- package/commands/gsd/inbox.md +5 -0
- package/commands/gsd/ingest-docs.md +5 -1
- package/commands/gsd/manager.md +6 -1
- package/commands/gsd/map-codebase.md +7 -3
- package/commands/gsd/mempalace-capture.md +12 -4
- package/commands/gsd/mempalace-recall.md +5 -1
- package/commands/gsd/milestone-summary.md +5 -1
- package/commands/gsd/mvp-phase.md +8 -3
- package/commands/gsd/new-milestone.md +6 -1
- package/commands/gsd/new-project.md +5 -0
- package/commands/gsd/next.md +6 -1
- package/commands/gsd/ns-context.md +4 -0
- package/commands/gsd/ns-ideate.md +4 -0
- package/commands/gsd/ns-manage.md +4 -0
- package/commands/gsd/ns-project.md +4 -0
- package/commands/gsd/ns-review.md +4 -0
- package/commands/gsd/ns-workflow.md +4 -0
- package/commands/gsd/onboard.md +6 -1
- package/commands/gsd/pause-work.md +5 -1
- package/commands/gsd/phase.md +8 -4
- package/commands/gsd/plan-phase.md +6 -1
- package/commands/gsd/plan-review-convergence.md +11 -7
- package/commands/gsd/pr-branch.md +4 -0
- package/commands/gsd/profile-user.md +5 -1
- package/commands/gsd/progress.md +7 -2
- package/commands/gsd/quick-batch.md +21 -9
- package/commands/gsd/quick.md +12 -7
- package/commands/gsd/review.md +7 -4
- package/commands/gsd/secure-phase.md +6 -1
- package/commands/gsd/ship.md +5 -0
- package/commands/gsd/sketch.md +7 -2
- package/commands/gsd/spec-phase.md +5 -1
- package/commands/gsd/spike.md +8 -3
- package/commands/gsd/surface.md +5 -1
- package/commands/gsd/thread.md +4 -0
- package/commands/gsd/ui-phase.md +6 -1
- package/commands/gsd/ui-review.md +6 -1
- package/commands/gsd/ultraplan-phase.md +5 -1
- package/commands/gsd/undo.md +5 -1
- package/commands/gsd/update.md +6 -2
- package/commands/gsd/validate-phase.md +6 -1
- package/commands/gsd/verify-work.md +6 -1
- package/commands/gsd/workspace.md +7 -3
- package/gsd-core/bin/gsd-tools.cjs +477 -78
- package/gsd-core/bin/lib/active-workstream-store.cjs +15 -0
- package/gsd-core/bin/lib/adr-parser.cjs +3 -1
- package/gsd-core/bin/lib/agent-install-check.cjs +4 -1
- package/gsd-core/bin/lib/audit.cjs +144 -42
- package/gsd-core/bin/lib/broken-windows.cjs +13 -13
- package/gsd-core/bin/lib/capability-activation.cjs +9 -4
- package/gsd-core/bin/lib/capability-registry.cjs +197 -222
- package/gsd-core/bin/lib/capability-validator.cjs +16 -1
- package/gsd-core/bin/lib/check-auto-mode.cjs +35 -0
- package/gsd-core/bin/lib/check-command-router.cjs +164 -1625
- package/gsd-core/bin/lib/cjs-command-router-adapter.cjs +13 -2
- package/gsd-core/bin/lib/cli-exit.cjs +12 -0
- package/gsd-core/bin/lib/codex-agent-toml.cjs +32 -33
- package/gsd-core/bin/lib/command-aliases.cjs +7 -0
- package/gsd-core/bin/lib/command-routing-hub.cjs +48 -1
- package/gsd-core/bin/lib/commands.cjs +343 -207
- package/gsd-core/bin/lib/complexity-trigger.cjs +8 -7
- package/gsd-core/bin/lib/config-loader.cjs +65 -4
- package/gsd-core/bin/lib/config.cjs +76 -19
- package/gsd-core/bin/lib/core-utils.cjs +6 -1
- package/gsd-core/bin/lib/coverage.cjs +4 -8
- package/gsd-core/bin/lib/decision-coverage-support.cjs +259 -0
- package/gsd-core/bin/lib/decisions.cjs +30 -14
- package/gsd-core/bin/lib/drift.cjs +177 -42
- package/gsd-core/bin/lib/frontmatter-fence.cjs +90 -0
- package/gsd-core/bin/lib/frontmatter-splice.cjs +494 -0
- package/gsd-core/bin/lib/frontmatter.cjs +426 -234
- package/gsd-core/bin/lib/gap-checker.cjs +72 -29
- package/gsd-core/bin/lib/gate-api-coverage-verify-pre.cjs +381 -0
- package/gsd-core/bin/lib/gate-args.cjs +53 -0
- package/gsd-core/bin/lib/gate-codebase-drift.cjs +285 -0
- package/gsd-core/bin/lib/gate-config.cjs +46 -0
- package/gsd-core/bin/lib/gate-context-drift.cjs +141 -0
- package/gsd-core/bin/lib/gate-decision-coverage-plan.cjs +169 -0
- package/gsd-core/bin/lib/gate-decision-coverage-verify.cjs +126 -0
- package/gsd-core/bin/lib/gate-evaluation-scope.cjs +555 -0
- package/gsd-core/bin/lib/gate-evidence.cjs +138 -0
- package/gsd-core/bin/lib/gate-exit.cjs +27 -0
- package/gsd-core/bin/lib/gate-gap-analysis-plan-post.cjs +61 -0
- package/gsd-core/bin/lib/gate-phase-context.cjs +170 -0
- package/gsd-core/bin/lib/gate-predicate-evaluator.cjs +1 -1
- package/gsd-core/bin/lib/gate-predicate.cjs +165 -0
- package/gsd-core/bin/lib/gate-prohibition-enforcement.cjs +94 -0
- package/gsd-core/bin/lib/gate-schema-drift.cjs +165 -0
- package/gsd-core/bin/lib/gate-tdd-red-evidence.cjs +100 -0
- package/gsd-core/bin/lib/gate-tdd-review-checkpoint.cjs +182 -0
- package/gsd-core/bin/lib/gate-ui-plan.cjs +86 -0
- package/gsd-core/bin/lib/gate-ui-safety.cjs +80 -0
- package/gsd-core/bin/lib/gate-verdict.cjs +64 -0
- package/gsd-core/bin/lib/gate-verify-command-paths.cjs +78 -0
- package/gsd-core/bin/lib/gate-verify-failure-directions.cjs +41 -0
- package/gsd-core/bin/lib/graphify.cjs +10 -2
- package/gsd-core/bin/lib/health-diagnostic-rules/phase-structure.cjs +43 -47
- package/gsd-core/bin/lib/health-diagnostic.cjs +45 -8
- package/gsd-core/bin/lib/host-runtime-detection.cjs +9 -0
- package/gsd-core/bin/lib/init.cjs +364 -132
- package/gsd-core/bin/lib/install-engine.cjs +30 -33
- package/gsd-core/bin/lib/install-profiles.cjs +7 -4
- package/gsd-core/bin/lib/installer-migrations.cjs +8 -1
- package/gsd-core/bin/lib/io.cjs +122 -3
- package/gsd-core/bin/lib/loop-resolver.cjs +95 -0
- package/gsd-core/bin/lib/markdown-sectionizer.cjs +75 -1
- package/gsd-core/bin/lib/milestone.cjs +37 -6
- package/gsd-core/bin/lib/model-resolver.cjs +171 -62
- package/gsd-core/bin/lib/observability/event.cjs +1 -1
- package/gsd-core/bin/lib/observability/logger.cjs +46 -1
- package/gsd-core/bin/lib/pattern.cjs +10 -0
- package/gsd-core/bin/lib/phase-command-router.cjs +20 -5
- package/gsd-core/bin/lib/phase-estimation.cjs +5 -4
- 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 +110 -8
- package/gsd-core/bin/lib/phase-lifecycle.cjs +9 -2
- package/gsd-core/bin/lib/phase-locator.cjs +29 -10
- package/gsd-core/bin/lib/phase-status.cjs +360 -0
- package/gsd-core/bin/lib/phase.cjs +489 -88
- package/gsd-core/bin/lib/plan-document.cjs +142 -20
- package/gsd-core/bin/lib/plan-drift-guard.cjs +5 -0
- package/gsd-core/bin/lib/planning-document.cjs +692 -0
- package/gsd-core/bin/lib/planning-inspect.cjs +60 -9
- package/gsd-core/bin/lib/planning-snapshot.cjs +18 -0
- package/gsd-core/bin/lib/planning-workspace.cjs +83 -55
- package/gsd-core/bin/lib/pr-branch-patterns.cjs +57 -0
- package/gsd-core/bin/lib/pristine-baseline.cjs +10 -0
- package/gsd-core/bin/lib/probe-core.cjs +7 -1
- package/gsd-core/bin/lib/profile-output.cjs +6 -3
- package/gsd-core/bin/lib/prohibition-enforcement.cjs +0 -55
- package/gsd-core/bin/lib/project-root.cjs +41 -2
- package/gsd-core/bin/lib/quick-batch-command-router.cjs +35 -9
- package/gsd-core/bin/lib/quick-batch-dispatch.cjs +11 -8
- package/gsd-core/bin/lib/real-home-guard.cjs +9 -1
- package/gsd-core/bin/lib/report-parser.cjs +269 -0
- package/gsd-core/bin/lib/review-lane-descriptor.cjs +10 -30
- package/gsd-core/bin/lib/review-reviewer-selection.cjs +2 -2
- package/gsd-core/bin/lib/roadmap-command-router.cjs +25 -19
- package/gsd-core/bin/lib/roadmap-parser.cjs +242 -15
- package/gsd-core/bin/lib/roadmap-upgrade.cjs +1653 -65
- package/gsd-core/bin/lib/roadmap.cjs +405 -88
- package/gsd-core/bin/lib/runtime-artifact-conversion.cjs +373 -187
- package/gsd-core/bin/lib/runtime-artifact-install-plan.cjs +5 -2
- package/gsd-core/bin/lib/runtime-artifact-layout.cjs +57 -1
- package/gsd-core/bin/lib/runtime-homes.cjs +14 -7
- package/gsd-core/bin/lib/runtime-hooks-surface.cjs +522 -624
- package/gsd-core/bin/lib/runtime-name-policy.cjs +246 -21
- package/gsd-core/bin/lib/runtime-slash.cjs +47 -30
- package/gsd-core/bin/lib/shell-command-projection.cjs +47 -8
- package/gsd-core/bin/lib/smart-entry.cjs +19 -3
- package/gsd-core/bin/lib/stale-bake-guard.cjs +32 -48
- package/gsd-core/bin/lib/state-contract.cjs +15 -18
- package/gsd-core/bin/lib/state-document.cjs +100 -22
- package/gsd-core/bin/lib/state-transition.cjs +39 -2
- package/gsd-core/bin/lib/state.cjs +256 -105
- package/gsd-core/bin/lib/surface.cjs +19 -2
- package/gsd-core/bin/lib/tdd-red-evidence.cjs +48 -79
- package/gsd-core/bin/lib/uat-predicate.cjs +359 -38
- package/gsd-core/bin/lib/uat.cjs +432 -7
- package/gsd-core/bin/lib/ui-consideration-probe.cjs +15 -2
- package/gsd-core/bin/lib/ui-frontend-evidence.cjs +167 -40
- package/gsd-core/bin/lib/undo-commit-selection.cjs +131 -0
- package/gsd-core/bin/lib/vendor/README.md +31 -9
- package/gsd-core/bin/lib/vendor/saxes.cjs +1934 -0
- package/gsd-core/bin/lib/vendor/saxes.cjs.LICENSE.txt +92 -0
- package/gsd-core/bin/lib/vendor/tap-parser.cjs +8927 -0
- package/gsd-core/bin/lib/vendor/tap-parser.cjs.LICENSE.txt +152 -0
- package/gsd-core/bin/lib/verification-command-router.cjs +2 -1
- package/gsd-core/bin/lib/verification.cjs +1378 -274
- package/gsd-core/bin/lib/verify-command-grounding.cjs +46 -2
- package/gsd-core/bin/lib/verify-command-router.cjs +18 -7
- package/gsd-core/bin/lib/verify.cjs +357 -531
- package/gsd-core/bin/lib/workstream-inventory-builder.cjs +14 -6
- package/gsd-core/bin/lib/workstream-inventory.cjs +31 -21
- package/gsd-core/bin/lib/workstream-name-policy.cjs +31 -1
- package/gsd-core/bin/lib/workstream.cjs +11 -2
- package/gsd-core/bin/lib/worktree-base-ref.cjs +482 -73
- package/gsd-core/bin/lib/worktree-safety.cjs +784 -51
- package/gsd-core/bin/shared/config-defaults.manifest.json +8 -0
- package/gsd-core/bin/shared/config-schema.manifest.json +5 -0
- package/gsd-core/references/autonomous-smart-discuss.md +2 -1
- package/gsd-core/references/autonomous-ui-design-contract.md +3 -3
- package/gsd-core/references/checkpoints.md +5 -3
- 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-mvp-tdd.md +5 -10
- package/gsd-core/references/execute-phase-between-wave-reset.md +10 -6
- package/gsd-core/references/execute-phase-response-language.md +1 -1
- 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 +7 -1
- package/gsd-core/references/model-profiles.md +1 -1
- package/gsd-core/references/offer-next.md +1 -1
- 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 +12 -3
- package/gsd-core/references/spidr-splitting.md +1 -1
- package/gsd-core/references/tdd.md +37 -8
- package/gsd-core/references/ui-consideration-probe.md +10 -5
- package/gsd-core/references/verifier-phase-gates.md +5 -2
- package/gsd-core/references/verify-command-path-resolvability.md +10 -2
- package/gsd-core/references/verify-mvp-mode.md +2 -2
- package/gsd-core/references/workstream-flag.md +33 -3
- package/gsd-core/references/worktree-path-safety.md +321 -0
- package/gsd-core/templates/README.md +1 -1
- package/gsd-core/templates/UAT.md +17 -1
- package/gsd-core/templates/config.json +2 -11
- 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 +8 -7
- package/gsd-core/workflows/add-tests.md +4 -3
- package/gsd-core/workflows/add-todo.md +6 -5
- package/gsd-core/workflows/ai-integration-phase.md +13 -4
- package/gsd-core/workflows/audit-fix.md +1 -1
- package/gsd-core/workflows/audit-milestone.md +4 -3
- 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 +43 -23
- package/gsd-core/workflows/check-todos.md +7 -6
- package/gsd-core/workflows/cleanup.md +2 -2
- package/gsd-core/workflows/code-review/steps/dispatch-fix.md +4 -3
- package/gsd-core/workflows/code-review/steps/structural-pre-pass.md +20 -13
- package/gsd-core/workflows/code-review-fix.md +112 -25
- package/gsd-core/workflows/code-review.md +146 -135
- package/gsd-core/workflows/complete-milestone/detail/elaboration.md +4 -3
- package/gsd-core/workflows/complete-milestone.md +13 -8
- package/gsd-core/workflows/debug.md +32 -7
- package/gsd-core/workflows/diagnose-issues.md +3 -2
- 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 +4 -3
- package/gsd-core/workflows/discuss-phase.md +4 -3
- package/gsd-core/workflows/do.md +2 -2
- package/gsd-core/workflows/docs-update.md +6 -5
- package/gsd-core/workflows/edit-phase.md +4 -3
- package/gsd-core/workflows/eval-review.md +14 -5
- package/gsd-core/workflows/execute-phase/detail/elaboration.md +2 -2
- package/gsd-core/workflows/execute-phase/steps/code-review-disposition.md +1019 -0
- package/gsd-core/workflows/execute-phase/steps/codebase-drift-gate.md +15 -4
- package/gsd-core/workflows/execute-phase/steps/completion-reconciliation.md +10 -7
- package/gsd-core/workflows/execute-phase/steps/executor-isolation-dispatch.md +37 -3
- package/gsd-core/workflows/execute-phase/steps/gap-closure-artifacts.md +3 -1
- package/gsd-core/workflows/execute-phase/steps/partial-wave.md +2 -2
- 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/regression-gate.md +2 -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/verify-phase-goal.md +187 -0
- package/gsd-core/workflows/execute-phase/steps/wave-post-gate-hooks.md +2 -3
- package/gsd-core/workflows/execute-phase/steps/worktree-base-check.md +25 -0
- package/gsd-core/workflows/execute-phase.md +96 -178
- package/gsd-core/workflows/execute-plan.md +18 -23
- package/gsd-core/workflows/explore.md +4 -4
- package/gsd-core/workflows/extract-learnings.md +4 -2
- 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 +3 -2
- package/gsd-core/workflows/help/modes/full.compact.md +3 -3
- package/gsd-core/workflows/help/modes/full.md +5 -5
- package/gsd-core/workflows/help/modes/topic.md +15 -5
- package/gsd-core/workflows/import.md +4 -3
- package/gsd-core/workflows/inbox.md +2 -2
- package/gsd-core/workflows/ingest-docs.md +3 -3
- package/gsd-core/workflows/insert-phase.md +4 -3
- package/gsd-core/workflows/list-seeds.md +1 -1
- package/gsd-core/workflows/list-workspaces.md +1 -1
- package/gsd-core/workflows/manager.md +6 -4
- package/gsd-core/workflows/map-codebase.md +5 -4
- package/gsd-core/workflows/milestone-summary.md +3 -2
- package/gsd-core/workflows/mvp-phase.md +14 -14
- package/gsd-core/workflows/new-milestone.md +11 -11
- 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 +7 -7
- 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 +2 -2
- package/gsd-core/workflows/plan-phase/detail/elaboration.md +1 -1
- package/gsd-core/workflows/plan-phase/steps/chunked-planning-mode.md +17 -5
- package/gsd-core/workflows/plan-phase/steps/closed-phase-gate.md +1 -1
- 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 +50 -24
- 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 +113 -13
- package/gsd-core/workflows/profile-user.md +2 -2
- package/gsd-core/workflows/progress.md +19 -49
- package/gsd-core/workflows/quick/steps/plan-checker-loop.md +27 -0
- package/gsd-core/workflows/quick/steps/quick-verification.md +4 -4
- package/gsd-core/workflows/quick/steps/worktree-pre-dispatch-commit.md +30 -11
- 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 +9 -3
- package/gsd-core/workflows/quick-batch/steps/worktree-dispatch.md +1 -1
- package/gsd-core/workflows/quick-batch.md +15 -10
- package/gsd-core/workflows/quick.md +62 -39
- package/gsd-core/workflows/reapply-patches.md +9 -3
- package/gsd-core/workflows/remove-phase.md +3 -2
- package/gsd-core/workflows/remove-workspace.md +2 -2
- package/gsd-core/workflows/resume-project.md +3 -2
- package/gsd-core/workflows/review.md +33 -17
- package/gsd-core/workflows/scan.md +3 -2
- package/gsd-core/workflows/secure-phase.md +13 -13
- package/gsd-core/workflows/settings-advanced.md +30 -10
- package/gsd-core/workflows/settings-integrations.md +2 -3
- package/gsd-core/workflows/settings.md +4 -4
- package/gsd-core/workflows/ship.md +14 -13
- 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 +2 -2
- package/gsd-core/workflows/transition.md +13 -23
- package/gsd-core/workflows/ui-phase.md +48 -11
- package/gsd-core/workflows/ui-review.md +21 -6
- package/gsd-core/workflows/ultraplan-phase.md +3 -2
- package/gsd-core/workflows/undo.md +339 -20
- package/gsd-core/workflows/update.md +7 -7
- package/gsd-core/workflows/validate-phase.md +12 -13
- package/gsd-core/workflows/verify-work/detail/elaboration.md +43 -3
- package/gsd-core/workflows/verify-work/steps/automated-ui-verification.md +1 -1
- package/gsd-core/workflows/verify-work/steps/mvp-uat-framing.md +5 -3
- package/gsd-core/workflows/verify-work.md +129 -55
- package/hooks/dist/gsd-agent-isolation-guard.js +32 -0
- package/hooks/dist/gsd-check-update-worker.js +8 -0
- package/hooks/dist/gsd-check-update.js +8 -0
- package/hooks/dist/gsd-context-monitor.js +31 -8
- package/hooks/dist/gsd-cursor-subagent-start.js +8 -0
- package/hooks/dist/gsd-secret-read-guard.js +161 -4
- package/hooks/dist/gsd-statusline.js +85 -20
- package/hooks/dist/gsd-update-banner.js +8 -0
- package/hooks/dist/gsd-validate-commit.sh +63 -4
- package/hooks/dist/gsd-windsurf-pre-write.js +11 -2
- package/hooks/dist/gsd-workflow-guard.js +5 -4
- package/hooks/dist/gsd-worktree-path-guard.js +6 -2
- package/hooks/dist/lib/cli-exit.js +12 -0
- package/hooks/dist/lib/git-probe.js +17 -1
- package/hooks/dist/lib/isolation-sentinel.js +2 -2
- package/hooks/gsd-agent-isolation-guard.js +32 -0
- package/hooks/gsd-check-update-worker.js +8 -0
- package/hooks/gsd-check-update.js +8 -0
- package/hooks/gsd-context-monitor.js +31 -8
- package/hooks/gsd-cursor-subagent-start.js +8 -0
- package/hooks/gsd-secret-read-guard.js +161 -4
- package/hooks/gsd-statusline.js +85 -20
- package/hooks/gsd-update-banner.js +8 -0
- package/hooks/gsd-validate-commit.sh +63 -4
- package/hooks/gsd-windsurf-pre-write.js +11 -2
- package/hooks/gsd-workflow-guard.js +5 -4
- package/hooks/gsd-worktree-path-guard.js +6 -2
- package/hooks/hooks.json +5 -5
- package/hooks/lib/cli-exit.js +12 -0
- package/hooks/lib/git-probe.js +17 -1
- package/hooks/lib/isolation-sentinel.js +2 -2
- package/package.json +22 -4
- package/scripts/build-hooks.js +15 -6
- package/scripts/changeset/parse.cjs +52 -4
- package/scripts/check-contract-drift.cjs +127 -11
- package/scripts/ci-timeout-report.cjs +770 -4
- package/scripts/command-contract-helpers.cjs +15 -8
- package/scripts/docs-guard-registry.cjs +34 -0
- package/scripts/gen-features.cjs +13 -8
- package/scripts/gen-hooks-cli-exit.cjs +12 -28
- package/scripts/gen-loop-host-contract.cjs +79 -1
- package/scripts/gen-platform-conformance-tier.cjs +187 -1
- package/scripts/gen-plugin-skills.cjs +87 -1
- package/scripts/gen-research-agents.cjs +24 -31
- package/scripts/gen-scripts-cli-exit.cjs +30 -3
- package/scripts/gen-test-timings.cjs +32 -7
- package/scripts/lib/cli-exit.cjs +12 -0
- package/scripts/lib/macos-conformance-tier.generated.cjs +34 -2
- package/scripts/lib/ndjson-reporter.cjs +31 -5
- package/scripts/lib/platform-conformance-tier.generated.cjs +45 -5
- package/scripts/lib/registration-ledger-preload.cjs +155 -0
- package/scripts/lib/vendor-bundle.cjs +59 -0
- package/scripts/lib/vendor-licenses/saxes-6.0.0.txt +64 -0
- 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-completion-predicate-drift.cjs +18 -19
- package/scripts/lint-descriptions.cjs +7 -3
- package/scripts/lint-docs-guard-registration.exempt-baseline.cjs +38 -1
- package/scripts/lint-eslint-glob-coverage.allowlist.json +20 -0
- package/scripts/lint-frontmatter-fence-drift.cjs +313 -0
- package/scripts/lint-frontmatter-scalar-broad-grep.cjs +122 -16
- package/scripts/lint-phase-arg-assignment.cjs +257 -0
- package/scripts/lint-phase-enumeration-drift.cjs +12 -8
- package/scripts/lint-phase-id-drift.cjs +319 -5
- package/scripts/lint-planning-document-positive-control.cjs +329 -0
- package/scripts/lint-pr-branch-pattern-drift.cjs +148 -0
- package/scripts/lint-response-language-coverage.cjs +3 -0
- package/scripts/lint-retired-runtime-name.cjs +619 -0
- package/scripts/lint-skill-deps.cjs +7 -3
- package/scripts/lint-state-write-path-drift.cjs +93 -0
- package/scripts/lint-test-file-count.allowlist.json +38 -9
- package/scripts/lint-test-file-count.cjs +34 -1
- package/scripts/lint-vendored-deps.cjs +41 -5
- package/scripts/lint-workflow-shellcheck-baseline.json +25 -10
- package/scripts/mutation-matrix.cjs +50 -5
- package/scripts/prompt-injection-scan.sh +4 -0
- package/scripts/release-tarball-smoke.cjs +194 -1
- package/scripts/require-issue-link-policy.cjs +6 -2
- package/scripts/sync-runtime-launcher.cjs +184 -2
- package/scripts/verify-npm-publish.cjs +76 -20
- package/skills/gsd-add-tests/SKILL.md +6 -1
- package/skills/gsd-ai-integration-phase/SKILL.md +6 -1
- package/skills/gsd-audit-fix/SKILL.md +5 -0
- package/skills/gsd-audit-milestone/SKILL.md +6 -1
- package/skills/gsd-autonomous/SKILL.md +7 -2
- package/skills/gsd-capture/SKILL.md +9 -5
- package/skills/gsd-code-review/SKILL.md +7 -2
- package/skills/gsd-complete-milestone/SKILL.md +4 -0
- package/skills/gsd-config/SKILL.md +8 -4
- package/skills/gsd-debug/SKILL.md +11 -7
- package/skills/gsd-discuss-phase/SKILL.md +7 -3
- package/skills/gsd-docs-update/SKILL.md +12 -7
- package/skills/gsd-eval-review/SKILL.md +6 -1
- package/skills/gsd-execute-phase/SKILL.md +12 -7
- package/skills/gsd-extract-learnings/SKILL.md +5 -0
- package/skills/gsd-fast/SKILL.md +4 -0
- package/skills/gsd-forensics/SKILL.md +5 -1
- package/skills/gsd-graphify/SKILL.md +10 -6
- package/skills/gsd-health/SKILL.md +5 -0
- package/skills/gsd-help/SKILL.md +7 -2
- package/skills/gsd-import/SKILL.md +7 -3
- package/skills/gsd-inbox/SKILL.md +5 -0
- package/skills/gsd-ingest-docs/SKILL.md +5 -1
- package/skills/gsd-manager/SKILL.md +6 -1
- package/skills/gsd-map-codebase/SKILL.md +7 -3
- package/skills/gsd-mempalace-capture/SKILL.md +12 -4
- package/skills/gsd-mempalace-recall/SKILL.md +5 -1
- package/skills/gsd-milestone-summary/SKILL.md +5 -1
- package/skills/gsd-mvp-phase/SKILL.md +8 -3
- package/skills/gsd-new-milestone/SKILL.md +6 -1
- package/skills/gsd-new-project/SKILL.md +5 -0
- package/skills/gsd-next/SKILL.md +6 -1
- package/skills/gsd-ns-context/SKILL.md +4 -0
- package/skills/gsd-ns-ideate/SKILL.md +4 -0
- package/skills/gsd-ns-manage/SKILL.md +4 -0
- package/skills/gsd-ns-project/SKILL.md +4 -0
- package/skills/gsd-ns-review/SKILL.md +4 -0
- package/skills/gsd-ns-workflow/SKILL.md +4 -0
- package/skills/gsd-onboard/SKILL.md +6 -1
- package/skills/gsd-pause-work/SKILL.md +5 -1
- package/skills/gsd-phase/SKILL.md +8 -4
- package/skills/gsd-plan-phase/SKILL.md +6 -1
- package/skills/gsd-plan-review-convergence/SKILL.md +10 -6
- package/skills/gsd-pr-branch/SKILL.md +4 -0
- package/skills/gsd-profile-user/SKILL.md +5 -1
- package/skills/gsd-progress/SKILL.md +7 -2
- package/skills/gsd-quick/SKILL.md +16 -10
- package/skills/gsd-quick-batch/SKILL.md +21 -9
- package/skills/gsd-review/SKILL.md +7 -4
- package/skills/gsd-review-backlog/SKILL.md +3 -2
- package/skills/gsd-secure-phase/SKILL.md +6 -1
- package/skills/gsd-ship/SKILL.md +5 -0
- package/skills/gsd-sketch/SKILL.md +7 -2
- package/skills/gsd-spec-phase/SKILL.md +5 -1
- package/skills/gsd-spike/SKILL.md +8 -3
- package/skills/gsd-surface/SKILL.md +5 -1
- package/skills/gsd-thread/SKILL.md +4 -0
- package/skills/gsd-ui-phase/SKILL.md +6 -1
- package/skills/gsd-ui-review/SKILL.md +6 -1
- package/skills/gsd-ultraplan-phase/SKILL.md +5 -1
- package/skills/gsd-undo/SKILL.md +5 -1
- package/skills/gsd-update/SKILL.md +6 -2
- package/skills/gsd-validate-phase/SKILL.md +6 -1
- package/skills/gsd-verify-work/SKILL.md +6 -1
- package/skills/gsd-workspace/SKILL.md +7 -3
- package/skills/gsd-workstreams/SKILL.md +6 -6
- package/vscode/package.json +1 -1
|
@@ -71,7 +71,7 @@ const planningScopeMod = require("./planning-scope.cjs");
|
|
|
71
71
|
const { SCOPE } = planningScopeMod;
|
|
72
72
|
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
73
73
|
const verificationMod = require("./verification.cjs");
|
|
74
|
-
const { readVerificationStatus } = verificationMod;
|
|
74
|
+
const { readVerificationStatus, VerificationStatusError, failOnVerificationStatusError } = verificationMod;
|
|
75
75
|
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
76
76
|
const phaseIdMod = require("./phase-id.cjs");
|
|
77
77
|
const { phaseKeyFromDir, phaseKeyFromToken, phaseMarkdownRegexSource } = phaseIdMod;
|
|
@@ -304,6 +304,8 @@ function containmentEnforcingVerificationFs(planningRoot) {
|
|
|
304
304
|
return node_fs_1.default.readFileSync(filePath, encoding);
|
|
305
305
|
},
|
|
306
306
|
statSync(filePath) {
|
|
307
|
+
// #5118: a code-less containment throw here is NOT "phase directory
|
|
308
|
+
// not found" — readVerificationStatus falls through to `missing`.
|
|
307
309
|
assertContained(filePath);
|
|
308
310
|
return node_fs_1.default.statSync(filePath);
|
|
309
311
|
},
|
|
@@ -917,7 +919,24 @@ function extractDependencyTokens(sectionBody) {
|
|
|
917
919
|
const m = DEPENDS_ON_LINE_RE.exec(sectionBody);
|
|
918
920
|
if (!m)
|
|
919
921
|
return [];
|
|
920
|
-
|
|
922
|
+
// #4764: phase REFERENCES, not digit runs — the same prose-anchored grammar
|
|
923
|
+
// init.manager's dep_phases extraction uses (owner: phase-id.cts's
|
|
924
|
+
// PHASE_DEP_REF_SOURCE). The whole-field token scrape this replaces pulled
|
|
925
|
+
// calendar dates, git shas and ledger ids in as dependencies. The grammar's
|
|
926
|
+
// capture group 1 already excludes the "Phase(s)" anchor word, so no
|
|
927
|
+
// prefix-strip literal is needed here. Self-exclusion (init.manager drops
|
|
928
|
+
// the row's own number) is deliberately NOT applied: this reader has no row
|
|
929
|
+
// context at the extraction site and reports informationally, it does not
|
|
930
|
+
// gate.
|
|
931
|
+
const refRe = new RegExp(phaseIdMod.PHASE_DEP_REF_SOURCE, 'gi');
|
|
932
|
+
const tokenRe = new RegExp(phaseIdMod.PHASE_NUMBER_TOKEN_SOURCE, 'g');
|
|
933
|
+
const tokens = [];
|
|
934
|
+
let refMatch;
|
|
935
|
+
while ((refMatch = refRe.exec(m[1])) !== null) {
|
|
936
|
+
for (const t of refMatch[1].matchAll(tokenRe))
|
|
937
|
+
tokens.push(t[0]);
|
|
938
|
+
}
|
|
939
|
+
return sortedUnique(tokens);
|
|
921
940
|
}
|
|
922
941
|
/**
|
|
923
942
|
* This phase's own ROADMAP.md section body — milestone-scoped via the SAME
|
|
@@ -999,6 +1018,17 @@ function buildPhaseGoalAndDependencies(cwd, roadmapDoc, phaseId, phaseDirLabel,
|
|
|
999
1018
|
}
|
|
1000
1019
|
// ─── Entry points ─────────────────────────────────────────────────────────────
|
|
1001
1020
|
function buildPlanningInspect(cwd) {
|
|
1021
|
+
return buildPlanningInspectResult(cwd).payload;
|
|
1022
|
+
}
|
|
1023
|
+
/**
|
|
1024
|
+
* #5118: the inspect payload plus the first verification report whose
|
|
1025
|
+
* `status` is outside the closed set (`statusError`, or `null`) — the
|
|
1026
|
+
* aggregate CARRIES the owner's error in its own result, and `planning
|
|
1027
|
+
* inspect` fails with it instead of printing an answer computed over a
|
|
1028
|
+
* report the owner refused.
|
|
1029
|
+
*/
|
|
1030
|
+
function buildPlanningInspectResult(cwd) {
|
|
1031
|
+
let statusError = null;
|
|
1002
1032
|
const diagnostics = [];
|
|
1003
1033
|
const paths = planningPaths(cwd);
|
|
1004
1034
|
const planningExists = node_fs_1.default.existsSync(paths.planning);
|
|
@@ -1061,8 +1091,8 @@ function buildPlanningInspect(cwd) {
|
|
|
1061
1091
|
// GAP 2 (#2790 follow-up security review): `readVerificationStatus`
|
|
1062
1092
|
// (`src/verification.cts`) is a shared owner with its own unguarded
|
|
1063
1093
|
// `readFileSync` — a `*-VERIFICATION.md` symlinked outside the planning
|
|
1064
|
-
// root would leak
|
|
1065
|
-
//
|
|
1094
|
+
// root would leak its unrecognized `status:` value verbatim (today via
|
|
1095
|
+
// the VerificationStatusError message, #5118). Fixed
|
|
1066
1096
|
// from THIS consumer's side via the injectable `opts.fs` seam that
|
|
1067
1097
|
// function already exposes, never by touching its signature — see
|
|
1068
1098
|
// `containmentEnforcingVerificationFs`'s doc comment. This same seam's
|
|
@@ -1077,9 +1107,22 @@ function buildPlanningInspect(cwd) {
|
|
|
1077
1107
|
// (`superseded`) rather than document text, and GAP 1's directory
|
|
1078
1108
|
// containment check already covers the escaped-DIRECTORY case for it —
|
|
1079
1109
|
// so it needs no fix of its own.
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1110
|
+
// #5118: an out-of-set report status is carried, not thrown past the
|
|
1111
|
+
// other phases — the row reads `status: null` and the command fails with
|
|
1112
|
+
// the first such error once the payload is built.
|
|
1113
|
+
let verification;
|
|
1114
|
+
try {
|
|
1115
|
+
verification = readVerificationStatus(phaseDir, {
|
|
1116
|
+
fs: containmentEnforcingVerificationFs(paths.planning),
|
|
1117
|
+
});
|
|
1118
|
+
}
|
|
1119
|
+
catch (err) {
|
|
1120
|
+
if (!(err instanceof VerificationStatusError))
|
|
1121
|
+
throw err;
|
|
1122
|
+
if (statusError === null)
|
|
1123
|
+
statusError = err;
|
|
1124
|
+
verification = { status: null, next_action: err.message, route: '' };
|
|
1125
|
+
}
|
|
1083
1126
|
const token = /^(\d+(?:\.\d+)*)/.exec(phase.dir);
|
|
1084
1127
|
const phaseId = token ? token[1] : null;
|
|
1085
1128
|
const { goal, dependencies } = buildPhaseGoalAndDependencies(cwd, roadmapDoc, phaseId, phase.dir, diagnostics);
|
|
@@ -1112,6 +1155,8 @@ function buildPlanningInspect(cwd) {
|
|
|
1112
1155
|
verification: {
|
|
1113
1156
|
status: verification.status,
|
|
1114
1157
|
next_action: verification.next_action ?? null,
|
|
1158
|
+
// #5118: additive — the bare command the owner routes this status to.
|
|
1159
|
+
route: verification.route,
|
|
1115
1160
|
},
|
|
1116
1161
|
roadmap_acceptance: {
|
|
1117
1162
|
checkbox: checkboxByPhaseKey.has(phaseKeyFromDir(phase.dir))
|
|
@@ -1133,7 +1178,7 @@ function buildPlanningInspect(cwd) {
|
|
|
1133
1178
|
const phaseScope = worstScope(snapshot.phaseDirs.scope, snapshot.phases.scope, ...phaseRows.map((p) => p.scope));
|
|
1134
1179
|
const acceptedPhases = makeFraction(phaseRows.filter((p) => p.complete).length, phaseRows.length, phaseScope, 'progress.accepted_phases', diagnostics);
|
|
1135
1180
|
const completedPlans = makeFraction(phaseRows.reduce((sum, p) => sum + p.summary_count, 0), phaseRows.reduce((sum, p) => sum + p.plan_count, 0), phaseScope, 'progress.completed_plans', diagnostics);
|
|
1136
|
-
|
|
1181
|
+
const payload = {
|
|
1137
1182
|
schema_version: PLANNING_INSPECT_SCHEMA_VERSION,
|
|
1138
1183
|
generated_from: {
|
|
1139
1184
|
cwd: toPosix(cwd),
|
|
@@ -1161,6 +1206,7 @@ function buildPlanningInspect(cwd) {
|
|
|
1161
1206
|
},
|
|
1162
1207
|
diagnostics,
|
|
1163
1208
|
};
|
|
1209
|
+
return { payload, statusError };
|
|
1164
1210
|
}
|
|
1165
1211
|
/**
|
|
1166
1212
|
* `planning inspect` — emit the schema-v1 snapshot.
|
|
@@ -1170,7 +1216,12 @@ function buildPlanningInspect(cwd) {
|
|
|
1170
1216
|
* transparently on stdout. Bypassing `output()` would lose that for free.
|
|
1171
1217
|
*/
|
|
1172
1218
|
function cmdPlanningInspect(cwd, raw) {
|
|
1173
|
-
|
|
1219
|
+
const { payload, statusError } = buildPlanningInspectResult(cwd);
|
|
1220
|
+
// #5118: a read-only aggregate over a refused report prints nothing and
|
|
1221
|
+
// fails with the error's own reason (`verification_status_invalid`).
|
|
1222
|
+
if (statusError)
|
|
1223
|
+
failOnVerificationStatusError(statusError);
|
|
1224
|
+
output(payload, raw);
|
|
1174
1225
|
}
|
|
1175
1226
|
const planningInspect = {
|
|
1176
1227
|
PLANNING_INSPECT_SCHEMA_VERSION,
|
|
@@ -124,10 +124,12 @@ function buildPhaseSnapshot(phasesDir, dir, convention) {
|
|
|
124
124
|
// report exactly like its legacy twin.
|
|
125
125
|
const completionResult = isPhaseComplete(fullPhaseDir, { convention });
|
|
126
126
|
const scanResult = scanPhasePlans(fullPhaseDir);
|
|
127
|
+
const statusError = completionResult.value.statusError;
|
|
127
128
|
return {
|
|
128
129
|
dir,
|
|
129
130
|
complete: completionResult.value.complete,
|
|
130
131
|
verificationStatus: completionResult.value.verification.status,
|
|
132
|
+
verificationStatusError: statusError ? { file: statusError.file, message: statusError.message } : null,
|
|
131
133
|
planCount: scanResult.planCount,
|
|
132
134
|
summaryCount: scanResult.summaryCount,
|
|
133
135
|
scope: worstScope(completionResult.scope, scanResult.scope),
|
|
@@ -882,6 +884,22 @@ function buildCurrentMilestoneRoadmapPhaseIdsField(cwd, roadmapPath, convention)
|
|
|
882
884
|
// and `bracketGroup` is 0. Inferring the convention from a matched bracket's
|
|
883
885
|
// shape would run a repo-failing check against a repo that never opted in.
|
|
884
886
|
const bracketGroup = convention === 'bracket' ? 1 : 0;
|
|
887
|
+
// #5007 (Phase 6 / ADR-4910 §8): already composed from `phaseHeadingPrefixSrcFor`
|
|
888
|
+
// directly, not a hand-rolled literal — the site's only marked defect was
|
|
889
|
+
// this doc comment's own prose quoting the pattern verbatim (fixed above),
|
|
890
|
+
// which is exactly what the drift detector matched. Audited against the
|
|
891
|
+
// design doc's suggested further swap onto `buildPhaseHeadingScanRegex`
|
|
892
|
+
// (the same owner `bracketGroup`/`phaseNumGroup` above hand-derives) and
|
|
893
|
+
// deliberately did NOT make that swap: the owner's regex requires a title
|
|
894
|
+
// (`${OPTIONAL_PHASE_TAG_SOURCE}\s*:\s*([^\n]+)` — at least one non-newline
|
|
895
|
+
// character after the colon), while this site's own tail is bare `:` with
|
|
896
|
+
// no title requirement. A live probe against this function (a `### Phase 3:`
|
|
897
|
+
// heading with no title text) confirms the current, pre-migration behavior
|
|
898
|
+
// DOES count that phase — swapping to the owner would silently drop it from
|
|
899
|
+
// W026's scan, and no existing test (including the ADR-612 census test
|
|
900
|
+
// pinned to this site by name) would catch that narrowing, since the census
|
|
901
|
+
// only pins `phaseHeadingPrefixSrcFor`'s own output, not this regex's tail.
|
|
902
|
+
// Kept as its own composition to preserve this exact byte-for-behavior.
|
|
885
903
|
const phasePattern = new RegExp(`#{2,4}\\s*${phaseHeadingPrefixSrcFor(PHASE_HEADING_BASELINE.LABEL_ONLY, convention, Boolean(bracketGroup))}(${PHASE_NUMBER_TOKEN_SOURCE})(?:\\s*\\([^)\\n]{0,200}\\))?\\s*:`, 'gi');
|
|
886
904
|
const value = [];
|
|
887
905
|
for (const m of scoped.matchAll(phasePattern)) {
|
|
@@ -114,13 +114,18 @@ const PLANNING_LOCK_RETRY_ERRNOS = new Set([
|
|
|
114
114
|
* two-readers-two-bases lesson).
|
|
115
115
|
*/
|
|
116
116
|
function resolveEnvWorkstream() {
|
|
117
|
-
|
|
117
|
+
const value = process.env['GSD_WORKSTREAM']?.trim();
|
|
118
|
+
return value || null;
|
|
118
119
|
}
|
|
119
120
|
function planningDir(cwd, ws, project) {
|
|
120
121
|
if (project === undefined)
|
|
121
|
-
project = process.env['GSD_PROJECT']
|
|
122
|
+
project = process.env['GSD_PROJECT']?.trim() || null;
|
|
123
|
+
else if (typeof project === 'string')
|
|
124
|
+
project = project.trim() || null;
|
|
122
125
|
if (ws === undefined)
|
|
123
126
|
ws = resolveEnvWorkstream();
|
|
127
|
+
else if (typeof ws === 'string')
|
|
128
|
+
ws = ws.trim() || null;
|
|
124
129
|
// Reject path separators and traversal components in project/workstream names
|
|
125
130
|
const BAD_SEGMENT = /[/\\]|\.\./;
|
|
126
131
|
if (project && BAD_SEGMENT.test(project)) {
|
|
@@ -139,60 +144,73 @@ function planningDir(cwd, ws, project) {
|
|
|
139
144
|
function planningRoot(cwd) {
|
|
140
145
|
return node_path_1.default.join(cwd, '.planning');
|
|
141
146
|
}
|
|
147
|
+
const CONFIG_VALUE_ABSENT = Object.freeze({ present: false, value: undefined });
|
|
142
148
|
/**
|
|
143
|
-
*
|
|
144
|
-
*
|
|
145
|
-
*
|
|
146
|
-
*
|
|
147
|
-
* project- and workstream-aware); otherwise the flat root's key, but only
|
|
148
|
-
* under the GSD_WORKSTREAM env gate — config-get deliberately does NOT
|
|
149
|
-
* inherit root under GSD_PROJECT alone, and this read must not diverge
|
|
150
|
-
* (#3963). Strict `=== false` (never coerced); any read failure degrades to
|
|
151
|
-
* "not opted out" (worktrees on — the fail-safe direction: the guard keeps
|
|
152
|
-
* enforcing). Direct file reads only — never loadConfig, which normalizes
|
|
153
|
-
* and rewrites config on paths that back sentinel writes.
|
|
149
|
+
* The value one config file sets at `keyPath`, if it sets one at all. Every
|
|
150
|
+
* segment must be an OWN property of a plain (non-null, non-array) object, so
|
|
151
|
+
* an absent, unreadable, or unparseable file — or a non-object anywhere on the
|
|
152
|
+
* path — does not set the key.
|
|
154
153
|
*/
|
|
155
|
-
function
|
|
156
|
-
|
|
157
|
-
// themselves throw on a GSD_PROJECT/GSD_WORKSTREAM value containing path
|
|
158
|
-
// separators or `..`, and this contract ("any failure degrades to not
|
|
159
|
-
// opted out — worktrees on, keep enforcing") must hold for that shape too.
|
|
154
|
+
function ownConfigValue(configPath, keyPath) {
|
|
155
|
+
let node;
|
|
160
156
|
try {
|
|
161
|
-
|
|
157
|
+
node = JSON.parse(String(node_fs_1.default.readFileSync(configPath, 'utf8')));
|
|
162
158
|
}
|
|
163
159
|
catch {
|
|
164
|
-
return
|
|
160
|
+
return CONFIG_VALUE_ABSENT;
|
|
161
|
+
}
|
|
162
|
+
for (const key of keyPath) {
|
|
163
|
+
if (node === null || typeof node !== 'object' || Array.isArray(node))
|
|
164
|
+
return CONFIG_VALUE_ABSENT;
|
|
165
|
+
if (!Object.prototype.hasOwnProperty.call(node, key))
|
|
166
|
+
return CONFIG_VALUE_ABSENT;
|
|
167
|
+
node = node[key];
|
|
165
168
|
}
|
|
169
|
+
return { present: true, value: node };
|
|
166
170
|
}
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
171
|
+
/**
|
|
172
|
+
* #3972/#4975: the ONE scope-aware config read for surfaces that must answer
|
|
173
|
+
* with the value `config-get <keyPath>` reports but may not call loadConfig
|
|
174
|
+
* (it normalizes and rewrites config.json, spawns git, and prints warnings).
|
|
175
|
+
* Ladder: the scoped config's OWN key wins (planningDir is project- and
|
|
176
|
+
* workstream-aware); otherwise the flat root's key, but only under the
|
|
177
|
+
* GSD_WORKSTREAM env gate — config-get deliberately does NOT inherit root
|
|
178
|
+
* under GSD_PROJECT alone, and no reader of this ladder may diverge (#3963).
|
|
179
|
+
* An unreadable or unparseable file sets nothing, so the ladder moves on:
|
|
180
|
+
* under GSD_WORKSTREAM a broken workstream config inherits the root's key.
|
|
181
|
+
* That is the one place this read and config-get part ways — for a scoped
|
|
182
|
+
* config.json that exists but cannot be read or parsed, config-get fails
|
|
183
|
+
* with CONFIG_PARSE_FAILED instead of reporting a value.
|
|
184
|
+
* The value is returned uncoerced; each caller applies its own strict
|
|
185
|
+
* comparison. Never throws: planningDir/planningRoot reject a
|
|
186
|
+
* GSD_PROJECT/GSD_WORKSTREAM value containing path separators or `..`, and
|
|
187
|
+
* that shape resolves to "not present".
|
|
188
|
+
*/
|
|
189
|
+
function readScopedConfigValue(cwd, keyPath) {
|
|
190
|
+
try {
|
|
191
|
+
const scoped = ownConfigValue(node_path_1.default.join(planningDir(cwd), 'config.json'), keyPath);
|
|
192
|
+
if (scoped.present)
|
|
193
|
+
return scoped;
|
|
194
|
+
if (resolveEnvWorkstream() !== null) {
|
|
195
|
+
return ownConfigValue(node_path_1.default.join(planningRoot(cwd), 'config.json'), keyPath);
|
|
174
196
|
}
|
|
175
|
-
};
|
|
176
|
-
const ownKey = (cfg) => {
|
|
177
|
-
if (cfg === null || typeof cfg !== 'object')
|
|
178
|
-
return { present: false, value: undefined };
|
|
179
|
-
const wf = cfg.workflow;
|
|
180
|
-
if (wf === null || typeof wf !== 'object' || Array.isArray(wf))
|
|
181
|
-
return { present: false, value: undefined };
|
|
182
|
-
const wfRec = wf;
|
|
183
|
-
return Object.prototype.hasOwnProperty.call(wfRec, 'use_worktrees')
|
|
184
|
-
? { present: true, value: wfRec['use_worktrees'] }
|
|
185
|
-
: { present: false, value: undefined };
|
|
186
|
-
};
|
|
187
|
-
const scoped = ownKey(readCfg(node_path_1.default.join(planningDir(cwd), 'config.json')));
|
|
188
|
-
if (scoped.present)
|
|
189
|
-
return scoped.value === false;
|
|
190
|
-
if (process.env['GSD_WORKSTREAM']) {
|
|
191
|
-
const root = ownKey(readCfg(node_path_1.default.join(planningRoot(cwd), 'config.json')));
|
|
192
|
-
if (root.present)
|
|
193
|
-
return root.value === false;
|
|
194
197
|
}
|
|
195
|
-
|
|
198
|
+
catch {
|
|
199
|
+
// Degrade to "not present" — see the contract above.
|
|
200
|
+
}
|
|
201
|
+
return CONFIG_VALUE_ABSENT;
|
|
202
|
+
}
|
|
203
|
+
/**
|
|
204
|
+
* #3972: the ONE owner of "is this planning scope opted out of worktrees?" —
|
|
205
|
+
* the effective `workflow.use_worktrees === false` read every
|
|
206
|
+
* isolation-deciding surface must share (config-get's merged view is the
|
|
207
|
+
* contract), resolved on the readScopedConfigValue ladder. Strict `=== false`
|
|
208
|
+
* (never coerced); a config that cannot be read never opts out by itself
|
|
209
|
+
* (worktrees on — the fail-safe direction: the guard keeps enforcing).
|
|
210
|
+
*/
|
|
211
|
+
function worktreesOptedOut(cwd) {
|
|
212
|
+
const { present, value } = readScopedConfigValue(cwd, ['workflow', 'use_worktrees']);
|
|
213
|
+
return present && value === false;
|
|
196
214
|
}
|
|
197
215
|
/**
|
|
198
216
|
* #612: resolve `phase_id_convention` with the SAME workstream->root federation
|
|
@@ -300,8 +318,8 @@ function listAvailableWorkstreams(cwd) {
|
|
|
300
318
|
function quickDirFrom(planningBase) {
|
|
301
319
|
return node_path_1.default.join(planningBase, 'quick');
|
|
302
320
|
}
|
|
303
|
-
// #4256: the todos directory — deliberately ROOT-SCOPED,
|
|
304
|
-
//
|
|
321
|
+
// #4256: the todos directory — deliberately ROOT-SCOPED, like debug (#5042).
|
|
322
|
+
// Todos are shared project state by construction: the
|
|
305
323
|
// migrateToWorkstreams contract keeps them among the shared files that "stay
|
|
306
324
|
// in place" at .planning/todos/ (workstream.cts), and every workflow writer
|
|
307
325
|
// writes that literal cwd-relative root path. The six todos readers
|
|
@@ -325,6 +343,14 @@ function todosDirFrom(planningBase) {
|
|
|
325
343
|
function todosDir(cwd) {
|
|
326
344
|
return todosDirFrom(planningRoot(cwd));
|
|
327
345
|
}
|
|
346
|
+
// Debug sessions are shared project state: the workflow and debugger agent
|
|
347
|
+
// write them under the root .planning/debug directory in every workstream.
|
|
348
|
+
function debugDirFrom(planningBase) {
|
|
349
|
+
return node_path_1.default.join(planningBase, 'debug');
|
|
350
|
+
}
|
|
351
|
+
function debugDir(cwd) {
|
|
352
|
+
return debugDirFrom(planningRoot(cwd));
|
|
353
|
+
}
|
|
328
354
|
function planningPaths(cwd, ws) {
|
|
329
355
|
const base = planningDir(cwd, ws);
|
|
330
356
|
return {
|
|
@@ -335,14 +361,13 @@ function planningPaths(cwd, ws) {
|
|
|
335
361
|
config: node_path_1.default.join(base, 'config.json'),
|
|
336
362
|
phases: node_path_1.default.join(base, 'phases'),
|
|
337
363
|
requirements: node_path_1.default.join(base, 'REQUIREMENTS.md'),
|
|
338
|
-
// #3149: the debug-session directory
|
|
339
|
-
//
|
|
340
|
-
|
|
341
|
-
debug: node_path_1.default.join(base, 'debug'),
|
|
364
|
+
// #3149/#5042: the debug-session directory shared by state.load,
|
|
365
|
+
// init.debug, and the root-scoped writers.
|
|
366
|
+
debug: debugDir(cwd),
|
|
342
367
|
// #2142: quick-task directory, composed via the shared quickDirFrom helper.
|
|
343
368
|
quick: quickDirFrom(base),
|
|
344
|
-
// #4256: todos directory — deliberately ROOT-scoped
|
|
345
|
-
//
|
|
369
|
+
// #4256: todos directory — deliberately ROOT-scoped like debug, while
|
|
370
|
+
// most other keys follow the active workstream/project (todos are shared
|
|
346
371
|
// project state per the migrateToWorkstreams contract), composed via the
|
|
347
372
|
// shared todosDir helper so this key and every direct caller agree.
|
|
348
373
|
todos: todosDir(cwd),
|
|
@@ -607,6 +632,7 @@ function findContextMdIn(absDirOrFiles) {
|
|
|
607
632
|
}
|
|
608
633
|
module.exports = {
|
|
609
634
|
worktreesOptedOut,
|
|
635
|
+
readScopedConfigValue,
|
|
610
636
|
createPlanningWorkspace,
|
|
611
637
|
createSharedPointerAdapter,
|
|
612
638
|
createSessionScopedPointerAdapter,
|
|
@@ -618,6 +644,8 @@ module.exports = {
|
|
|
618
644
|
listAvailableWorkstreams,
|
|
619
645
|
planningPaths,
|
|
620
646
|
quickDirFrom,
|
|
647
|
+
debugDirFrom,
|
|
648
|
+
debugDir,
|
|
621
649
|
todosDirFrom,
|
|
622
650
|
todosDir,
|
|
623
651
|
withPlanningLock,
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* PR-branch `.planning/` path classification patterns — single source of
|
|
4
|
+
* truth (ADR-4910 §8, epic #4906 Phase 5; issues #4605, #4606).
|
|
5
|
+
*
|
|
6
|
+
* `gsd-core/workflows/pr-branch.md` cannot `require()` this module at
|
|
7
|
+
* runtime — a workflow markdown file has no module system, and its bash
|
|
8
|
+
* steps are copy-pasted text executed by whatever shell interprets the
|
|
9
|
+
* workflow. So the three exported constants below are mirrored VERBATIM
|
|
10
|
+
* into that file's `TRANSIENT_DIRS=`, `STRUCTURAL_RE=`, and
|
|
11
|
+
* `MILESTONE_PHASES_RE=` bash variable assignments, and
|
|
12
|
+
* `scripts/lint-pr-branch-pattern-drift.cjs` asserts the mirror never
|
|
13
|
+
* drifts from this file (compiled to `gsd-core/bin/lib/pr-branch-patterns.cjs`)
|
|
14
|
+
* as part of `npm run lint:ci`. Change a value here, then update
|
|
15
|
+
* `gsd-core/workflows/pr-branch.md` to match, or the drift guard fails.
|
|
16
|
+
*
|
|
17
|
+
* This module does not read the filesystem and has no dependencies (a leaf
|
|
18
|
+
* module, mirroring `src/secrets.cts` / `src/planning-scope.cts`).
|
|
19
|
+
*/
|
|
20
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
21
|
+
exports.MILESTONE_PHASES_RE_SRC = exports.STRUCTURAL_RE_SRC = exports.TRANSIENT_DIRS_SRC = void 0;
|
|
22
|
+
/**
|
|
23
|
+
* Space-separated list of `.planning/` subdirectory names that are reviewer
|
|
24
|
+
* noise (PLAN.md, SUMMARY.md, CONTEXT.md, RESEARCH.md, and friends) —
|
|
25
|
+
* filtered out of a PR branch in BOTH default and strict mode.
|
|
26
|
+
*
|
|
27
|
+
* Mirrored verbatim into `gsd-core/workflows/pr-branch.md`'s
|
|
28
|
+
* `TRANSIENT_DIRS="..."` assignment.
|
|
29
|
+
*/
|
|
30
|
+
exports.TRANSIENT_DIRS_SRC = 'phases quick research threads todos debug seeds codebase ui-reviews';
|
|
31
|
+
/**
|
|
32
|
+
* Structural planning files — repository planning state, preserved in
|
|
33
|
+
* default mode and filtered out in strict mode. Anchored on both
|
|
34
|
+
* alternatives so `.planning/STATEX.md` and `.planning/STATE.md.bak` are
|
|
35
|
+
* NOT treated as structural. The `milestones` alternative matches only
|
|
36
|
+
* FILES directly under `.planning/milestones/` (e.g. `v1.0-ROADMAP.md`) —
|
|
37
|
+
* not a `<milestone>-phases/` subdirectory nested there. That subdirectory
|
|
38
|
+
* is reviewer noise, not structural state (#4605); it falls through to
|
|
39
|
+
* `MILESTONE_PHASES_RE_SRC` below instead.
|
|
40
|
+
*
|
|
41
|
+
* Mirrored verbatim into `gsd-core/workflows/pr-branch.md`'s
|
|
42
|
+
* `STRUCTURAL_RE="..."` assignment.
|
|
43
|
+
*/
|
|
44
|
+
exports.STRUCTURAL_RE_SRC = '^\\.planning/(STATE|ROADMAP|MILESTONES|PROJECT|REQUIREMENTS)\\.md$|^\\.planning/milestones/[^/]+\\.md$';
|
|
45
|
+
/**
|
|
46
|
+
* Milestone-scoped phase-plan directories — the same reviewer noise as
|
|
47
|
+
* `TRANSIENT_DIRS_SRC`'s `phases` entry, but nested per-milestone once a
|
|
48
|
+
* project has passed at least one milestone:
|
|
49
|
+
* `.planning/milestones/<milestone>-phases/`. The milestone slug (`v1.0`,
|
|
50
|
+
* `m2`, ...) varies per project, so this is declared as a shape, not a
|
|
51
|
+
* literal path — a single path segment standing in for the slug, anchored
|
|
52
|
+
* the same way `STRUCTURAL_RE_SRC`'s alternatives are (#4605).
|
|
53
|
+
*
|
|
54
|
+
* Mirrored verbatim into `gsd-core/workflows/pr-branch.md`'s
|
|
55
|
+
* `MILESTONE_PHASES_RE="..."` assignment.
|
|
56
|
+
*/
|
|
57
|
+
exports.MILESTONE_PHASES_RE_SRC = '^\\.planning/milestones/[^/]+-phases/';
|
|
@@ -27,6 +27,8 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
27
27
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
28
28
|
exports.sha256File = sha256File;
|
|
29
29
|
exports.findPristineByHash = findPristineByHash;
|
|
30
|
+
exports.isCleanRelativePosixPath = isCleanRelativePosixPath;
|
|
31
|
+
exports.gitExec = gitExec;
|
|
30
32
|
exports.findPristineInGit = findPristineInGit;
|
|
31
33
|
const node_fs_1 = __importDefault(require("node:fs"));
|
|
32
34
|
const node_path_1 = __importDefault(require("node:path"));
|
|
@@ -125,6 +127,14 @@ const GIT_MAX_COMMITS_PER_FILE = 100;
|
|
|
125
127
|
const GIT_SUBPROCESS_TIMEOUT_MS = 10_000;
|
|
126
128
|
/** git log --format=%H output cap; 100 full shas are ~4 KB, this is headroom. */
|
|
127
129
|
const GIT_MAX_BUFFER_BYTES = 16 * 1024 * 1024;
|
|
130
|
+
/**
|
|
131
|
+
* #5105 review finding 1/4: shared containment guard AND the shared
|
|
132
|
+
* non-trimming `git` subprocess runner, exported so `uat.cts`'s
|
|
133
|
+
* `readBaselineAtHead` (byte-exact `git show HEAD:<path>` read) can route
|
|
134
|
+
* through the same bounded, `windowsHide`d, stderr-discarding call this
|
|
135
|
+
* module already uses, rather than maintaining a second private
|
|
136
|
+
* `execFileSync` wrapper that can drift from this one's timeout/maxBuffer.
|
|
137
|
+
*/
|
|
128
138
|
function isCleanRelativePosixPath(relPath) {
|
|
129
139
|
if (!relPath || relPath.startsWith('/') || relPath.includes('\\') || relPath.includes('\0')) {
|
|
130
140
|
return false;
|
|
@@ -234,6 +234,12 @@ function analyzeCoverage(items, resolutions = [], validators) {
|
|
|
234
234
|
const unresolved = merged.filter((i) => i.status === 'unresolved').length;
|
|
235
235
|
const applicable = merged.length;
|
|
236
236
|
const resolved = applicable - unresolved; // closed set: resolved-status + dismissed
|
|
237
|
+
// #4656: the unclassified soft-signal rows count toward `applicable` (the
|
|
238
|
+
// rollup is count-preserving and `resolved = applicable - unresolved` is a
|
|
239
|
+
// documented identity), so the count is exposed as a SIBLING field — the
|
|
240
|
+
// zero-applicable guards can then also fire when EVERY requirement is
|
|
241
|
+
// unclassified, the case the spec-phase/ui-phase docs promise to catch.
|
|
242
|
+
const unclassified = merged.filter((i) => i.category === 'unclassified').length;
|
|
237
243
|
const byVerification = {};
|
|
238
244
|
for (const tier of validators.verification)
|
|
239
245
|
byVerification[tier] = 0;
|
|
@@ -242,7 +248,7 @@ function analyzeCoverage(items, resolutions = [], validators) {
|
|
|
242
248
|
byVerification[i.verification] = (byVerification[i.verification] ?? 0) + 1;
|
|
243
249
|
}
|
|
244
250
|
}
|
|
245
|
-
return { items: merged, coverage: { applicable, resolved, unresolved, byVerification } };
|
|
251
|
+
return { items: merged, coverage: { applicable, resolved, unresolved, unclassified, byVerification } };
|
|
246
252
|
}
|
|
247
253
|
/**
|
|
248
254
|
* The prohibition adapter's injected runtime validators (ADR-550 #5). There is no closed
|
|
@@ -29,6 +29,7 @@ const shell_command_projection_cjs_1 = require("./shell-command-projection.cjs")
|
|
|
29
29
|
const runtime_homes_cjs_1 = require("./runtime-homes.cjs");
|
|
30
30
|
const runtime_slash_cjs_1 = require("./runtime-slash.cjs");
|
|
31
31
|
const runtime_name_policy_cjs_1 = require("./runtime-name-policy.cjs");
|
|
32
|
+
const frontmatter_fence_cjs_1 = require("./frontmatter-fence.cjs");
|
|
32
33
|
// ─── Constants ────────────────────────────────────────────────────────────────
|
|
33
34
|
const DIMENSION_KEYS = [
|
|
34
35
|
'communication_style', 'decision_speed', 'explanation_depth',
|
|
@@ -203,6 +204,7 @@ function buildClaudeMdWorkflowEnforcement(runtime) {
|
|
|
203
204
|
'Before using Edit, Write, or other file-changing tools, start work through a GSD command so planning artifacts and execution context stay in sync.',
|
|
204
205
|
'',
|
|
205
206
|
'Use these entry points:',
|
|
207
|
+
`- \`${String((0, runtime_slash_cjs_1.formatGsdSlash)('fast', runtime))}\` for a trivial task inline, with no subagents and no PLAN.md`,
|
|
206
208
|
`- \`${String((0, runtime_slash_cjs_1.formatGsdSlash)('quick', runtime))}\` for small fixes, doc updates, and ad-hoc tasks`,
|
|
207
209
|
`- \`${String((0, runtime_slash_cjs_1.formatGsdSlash)('debug', runtime))}\` for investigation and bug fixing`,
|
|
208
210
|
`- \`${String((0, runtime_slash_cjs_1.formatGsdSlash)('execute-phase', runtime))}\` for planned phase work`,
|
|
@@ -477,10 +479,11 @@ function generateSkillsSection(cwd) {
|
|
|
477
479
|
*/
|
|
478
480
|
function extractSkillFrontmatter(content) {
|
|
479
481
|
const result = { name: '', description: '' };
|
|
480
|
-
|
|
481
|
-
|
|
482
|
+
// The block is the one the one fence owner (`locateFrontmatterFence`) finds.
|
|
483
|
+
const fence = (0, frontmatter_fence_cjs_1.locateFrontmatterFence)(content);
|
|
484
|
+
if (!fence?.closed)
|
|
482
485
|
return result;
|
|
483
|
-
const fmBlock =
|
|
486
|
+
const fmBlock = content.slice(fence.openEnd, fence.bodyEnd);
|
|
484
487
|
const lines = fmBlock.split('\n');
|
|
485
488
|
let currentKey = '';
|
|
486
489
|
for (const line of lines) {
|
|
@@ -58,14 +58,9 @@ exports.eslintHasFatalError = eslintHasFatalError;
|
|
|
58
58
|
exports.eslintJsonHasRule = eslintJsonHasRule;
|
|
59
59
|
exports.defaultProveFailFirst = defaultProveFailFirst;
|
|
60
60
|
exports.runProhibitionEnforcement = runProhibitionEnforcement;
|
|
61
|
-
exports.routeProhibitionEnforcement = routeProhibitionEnforcement;
|
|
62
61
|
const node_fs_1 = __importDefault(require("node:fs"));
|
|
63
62
|
const node_path_1 = __importDefault(require("node:path"));
|
|
64
63
|
const node_child_process_1 = require("node:child_process");
|
|
65
|
-
// Import the leaf I/O module directly (core.cjs re-export spine retired in epic #1267).
|
|
66
|
-
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
67
|
-
const io = require("./io.cjs");
|
|
68
|
-
const { output, error, ERROR_REASON } = io;
|
|
69
64
|
const probe_core_cjs_1 = require("./probe-core.cjs");
|
|
70
65
|
/**
|
|
71
66
|
* READ-BACK ADAPTER (#1278, plan 01-03): reconstruct a `CheckDescriptor` from the flat scalar keys
|
|
@@ -730,53 +725,3 @@ function runProhibitionEnforcement(prohibition, check, options = {}) {
|
|
|
730
725
|
...(mode ? { mode } : {}),
|
|
731
726
|
};
|
|
732
727
|
}
|
|
733
|
-
/**
|
|
734
|
-
* Parse a `{ prohibition, check, mode }` request from a JSON file path or inline `--json` string.
|
|
735
|
-
* Returns null on any parse failure (the caller surfaces a structured error, never a throw).
|
|
736
|
-
*/
|
|
737
|
-
function parseRequest(args) {
|
|
738
|
-
// args[0] = 'check', args[1] = 'prohibition-enforcement', args[2] = <json-file-path | --json>
|
|
739
|
-
const jsonFlagIdx = args.indexOf('--json');
|
|
740
|
-
let payload = '';
|
|
741
|
-
if (jsonFlagIdx !== -1 && typeof args[jsonFlagIdx + 1] === 'string') {
|
|
742
|
-
payload = args[jsonFlagIdx + 1];
|
|
743
|
-
}
|
|
744
|
-
else if (typeof args[2] === 'string' && args[2]) {
|
|
745
|
-
try {
|
|
746
|
-
payload = node_fs_1.default.readFileSync(args[2], 'utf-8');
|
|
747
|
-
}
|
|
748
|
-
catch {
|
|
749
|
-
return null;
|
|
750
|
-
}
|
|
751
|
-
}
|
|
752
|
-
else {
|
|
753
|
-
return null;
|
|
754
|
-
}
|
|
755
|
-
try {
|
|
756
|
-
const parsed = JSON.parse(payload);
|
|
757
|
-
const checkRaw = parsed['check'];
|
|
758
|
-
const check = (checkRaw && typeof checkRaw === 'object')
|
|
759
|
-
? checkRaw
|
|
760
|
-
: null;
|
|
761
|
-
const modeRaw = parsed['mode'];
|
|
762
|
-
const mode = typeof modeRaw === 'string' ? modeRaw : undefined;
|
|
763
|
-
return { prohibition: parsed['prohibition'] ?? null, check, ...(mode ? { mode } : {}) };
|
|
764
|
-
}
|
|
765
|
-
catch {
|
|
766
|
-
return null;
|
|
767
|
-
}
|
|
768
|
-
}
|
|
769
|
-
/**
|
|
770
|
-
* CLI surface: `gsd_run check prohibition-enforcement <request.json>` (or `--json '<inline>'`).
|
|
771
|
-
* Parses the request, runs the producer, and emits the result as JSON. Honors the no-throw
|
|
772
|
-
* contract: malformed input -> structured `error(...)`, never an uncaught throw.
|
|
773
|
-
*/
|
|
774
|
-
function routeProhibitionEnforcement(args, raw) {
|
|
775
|
-
const req = parseRequest(args);
|
|
776
|
-
if (!req) {
|
|
777
|
-
error('prohibition-enforcement requires a JSON request: check prohibition-enforcement <request.json> | --json \'{"prohibition":{...},"check":{...}}\'', ERROR_REASON.SDK_MISSING_ARG);
|
|
778
|
-
return;
|
|
779
|
-
}
|
|
780
|
-
const result = runProhibitionEnforcement(req.prohibition, req.check, req.mode ? { mode: req.mode } : {});
|
|
781
|
-
output(result, raw, undefined);
|
|
782
|
-
}
|
|
@@ -17,12 +17,28 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
17
17
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
18
18
|
};
|
|
19
19
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
20
|
+
exports.setExplicitProjectRoot = setExplicitProjectRoot;
|
|
21
|
+
exports.resolveProjectRoot = resolveProjectRoot;
|
|
20
22
|
exports.findProjectRoot = findProjectRoot;
|
|
21
23
|
exports.consentProjectRoot = consentProjectRoot;
|
|
22
24
|
const node_fs_1 = __importDefault(require("node:fs"));
|
|
23
25
|
const node_path_1 = __importDefault(require("node:path"));
|
|
24
26
|
const node_os_1 = __importDefault(require("node:os"));
|
|
25
27
|
const FIND_PROJECT_ROOT_MAX_DEPTH = 10;
|
|
28
|
+
// #4894: an operator-supplied `--project-dir` IS the project root — the
|
|
29
|
+
// dispatcher validates it and skips the ancestor walk-up for `cwd`, but code
|
|
30
|
+
// that derives a root from a PHASE DIRECTORY (verification) never sees `cwd`.
|
|
31
|
+
// The dispatcher records the validated root here, once per process, and those
|
|
32
|
+
// callers resolve through `resolveProjectRoot`. `null` (the default, and what
|
|
33
|
+
// the dispatcher sets when the flag is absent) leaves `findProjectRoot`'s
|
|
34
|
+
// walk-up as the only source of truth, so no-flag behavior is unchanged.
|
|
35
|
+
let explicitProjectRoot = null;
|
|
36
|
+
function setExplicitProjectRoot(root) {
|
|
37
|
+
explicitProjectRoot = root;
|
|
38
|
+
}
|
|
39
|
+
function resolveProjectRoot(startDir) {
|
|
40
|
+
return explicitProjectRoot ?? findProjectRoot(startDir);
|
|
41
|
+
}
|
|
26
42
|
function findProjectRoot(startDir) {
|
|
27
43
|
let resolvedStart;
|
|
28
44
|
try {
|
|
@@ -43,12 +59,35 @@ function findProjectRoot(startDir) {
|
|
|
43
59
|
catch {
|
|
44
60
|
// fall through
|
|
45
61
|
}
|
|
62
|
+
// A `.planning` that is itself a symlink is a deliberate hop into a separate
|
|
63
|
+
// tree (the documented "keep planning content out of the tracked repo"
|
|
64
|
+
// convention: `.planning -> ~/.gsd-external-planning/<project>/`, its own git
|
|
65
|
+
// repo). `fs.existsSync(d + '/.git')` DEREFERENCES `d`, so at `d ===
|
|
66
|
+
// <the .planning symlink path>` it finds the EXTERNAL store's `.git`, and
|
|
67
|
+
// both isInsideGitRepo/nearestGitRoot misread it as a crossed nested-child-
|
|
68
|
+
// repo boundary (#2843's guard). `fs.lstatSync` does not dereference its
|
|
69
|
+
// final path component, so it answers "is `d` ITSELF a symlink" (#4815).
|
|
70
|
+
//
|
|
71
|
+
// Deliberately scoped to a symlink named `.planning`, NOT any symlinked
|
|
72
|
+
// directory: a nested child repo reached through some other symlinked
|
|
73
|
+
// ancestor is still a real repo boundary, and skipping it would reopen
|
|
74
|
+
// #2843 through a different trigger.
|
|
75
|
+
function isSymlinkedPlanningDir(d) {
|
|
76
|
+
if (node_path_1.default.basename(d) !== '.planning')
|
|
77
|
+
return false;
|
|
78
|
+
try {
|
|
79
|
+
return node_fs_1.default.lstatSync(d).isSymbolicLink();
|
|
80
|
+
}
|
|
81
|
+
catch {
|
|
82
|
+
return false;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
46
85
|
// Walk upward, mirroring isInsideGitRepo from the CJS reference.
|
|
47
86
|
function isInsideGitRepo(candidateParent) {
|
|
48
87
|
let d = resolvedStart;
|
|
49
88
|
while (d !== fsRoot) {
|
|
50
89
|
try {
|
|
51
|
-
if (node_fs_1.default.existsSync(d + node_path_1.default.sep + '.git'))
|
|
90
|
+
if (!isSymlinkedPlanningDir(d) && node_fs_1.default.existsSync(d + node_path_1.default.sep + '.git'))
|
|
52
91
|
return true;
|
|
53
92
|
}
|
|
54
93
|
catch {
|
|
@@ -77,7 +116,7 @@ function findProjectRoot(startDir) {
|
|
|
77
116
|
if (d === upTo)
|
|
78
117
|
break;
|
|
79
118
|
try {
|
|
80
|
-
if (node_fs_1.default.existsSync(d + node_path_1.default.sep + '.git'))
|
|
119
|
+
if (!isSymlinkedPlanningDir(d) && node_fs_1.default.existsSync(d + node_path_1.default.sep + '.git'))
|
|
81
120
|
return d;
|
|
82
121
|
}
|
|
83
122
|
catch {
|