@opengsd/gsd-core 1.10.0 → 1.12.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/agents/gsd-code-fixer.md +1 -1
- package/agents/gsd-debug-session-manager.md +12 -1
- package/agents/gsd-debugger.md +1 -1
- package/agents/gsd-doc-synthesizer.md +2 -4
- package/agents/gsd-dom-verifier.md +169 -0
- package/agents/gsd-eval-auditor.md +1 -1
- package/agents/gsd-executor.md +22 -14
- package/agents/gsd-framework-selector.md +1 -3
- package/agents/gsd-intel-updater.md +1 -1
- package/agents/gsd-mempalace-curator.md +5 -3
- package/agents/gsd-pattern-mapper.md +11 -0
- package/agents/gsd-phase-researcher.md +23 -2
- package/agents/gsd-plan-checker.md +50 -53
- package/agents/gsd-planner.md +50 -50
- package/agents/gsd-project-researcher.md +1 -1
- package/agents/gsd-research-synthesizer.md +2 -2
- package/agents/gsd-roadmapper.md +15 -11
- package/agents/gsd-ui-checker.md +63 -4
- package/agents/gsd-ui-researcher.md +41 -3
- package/agents/gsd-user-profiler.md +3 -0
- package/agents/gsd-verifier.md +13 -4
- package/bin/install.js +1448 -1103
- package/commands/gsd/code-review.md +1 -1
- package/commands/gsd/discuss-phase.md +1 -1
- package/commands/gsd/execute-phase.md +1 -1
- package/commands/gsd/import.md +1 -1
- package/commands/gsd/map-codebase.md +1 -1
- package/commands/gsd/mempalace-capture.md +1 -1
- package/commands/gsd/mempalace-recall.md +1 -1
- package/commands/gsd/new-milestone.md +1 -1
- package/commands/gsd/quick.md +9 -5
- package/commands/gsd/review-backlog.md +2 -1
- package/commands/gsd/verify-work.md +1 -1
- package/gsd-core/bin/gsd-tools.cjs +1035 -138
- package/gsd-core/bin/lib/active-workstream-store.cjs +146 -22
- package/gsd-core/bin/lib/adr-parser.cjs +13 -7
- package/gsd-core/bin/lib/agent-install-check.cjs +392 -32
- package/gsd-core/bin/lib/api-coverage.cjs +33 -14
- package/gsd-core/bin/lib/artifacts.cjs +5 -0
- package/gsd-core/bin/lib/assumption-delta.cjs +32 -15
- package/gsd-core/bin/lib/audit-command-router.cjs +9 -2
- package/gsd-core/bin/lib/audit.cjs +1026 -268
- package/gsd-core/bin/lib/broken-windows.cjs +306 -28
- package/gsd-core/bin/lib/capability-consent.cjs +149 -15
- package/gsd-core/bin/lib/capability-lifecycle.cjs +45 -0
- package/gsd-core/bin/lib/capability-lock.cjs +10 -4
- package/gsd-core/bin/lib/capability-registry.cjs +845 -130
- package/gsd-core/bin/lib/capability-source.cjs +92 -0
- package/gsd-core/bin/lib/capability-state.cjs +18 -3
- package/gsd-core/bin/lib/capability-trust.cjs +444 -25
- package/gsd-core/bin/lib/capability-validator.cjs +700 -40
- package/gsd-core/bin/lib/capability-writer.cjs +3 -2
- package/gsd-core/bin/lib/check-command-router.cjs +216 -42
- package/gsd-core/bin/lib/claude-orchestration.cjs +56 -3
- package/gsd-core/bin/lib/cli-exit.cjs +496 -10
- package/gsd-core/bin/lib/code-review-depth.cjs +288 -0
- package/gsd-core/bin/lib/codex-agent-toml.cjs +735 -0
- package/gsd-core/bin/lib/command-aliases.cjs +22 -0
- package/gsd-core/bin/lib/command-arg-projection.cjs +144 -14
- package/gsd-core/bin/lib/command-roster.cjs +44 -1
- package/gsd-core/bin/lib/command-routing-hub.cjs +31 -2
- package/gsd-core/bin/lib/commands.cjs +1172 -108
- package/gsd-core/bin/lib/commonjs-marker.cjs +12 -6
- package/gsd-core/bin/lib/complexity-trigger.cjs +1192 -0
- package/gsd-core/bin/lib/config-loader.cjs +187 -23
- package/gsd-core/bin/lib/config.cjs +102 -3
- package/gsd-core/bin/lib/configuration.cjs +129 -37
- package/gsd-core/bin/lib/core-utils.cjs +208 -33
- package/gsd-core/bin/lib/decisions.cjs +23 -0
- package/gsd-core/bin/lib/edge-probe.cjs +9 -1
- package/gsd-core/bin/lib/estimate-cli.cjs +55 -11
- package/gsd-core/bin/lib/exit-code-registry.cjs +98 -0
- package/gsd-core/bin/lib/fallow-runner.cjs +20 -44
- package/gsd-core/bin/lib/frontmatter.cjs +899 -229
- package/gsd-core/bin/lib/gap-checker.cjs +95 -10
- package/gsd-core/bin/lib/git-base-branch.cjs +276 -39
- package/gsd-core/bin/lib/gsd2-import.cjs +10 -1
- package/gsd-core/bin/lib/health-diagnostic-rules/agent-install.cjs +101 -0
- package/gsd-core/bin/lib/health-diagnostic-rules/config-validation.cjs +348 -0
- package/gsd-core/bin/lib/health-diagnostic-rules/consistency.cjs +149 -0
- package/gsd-core/bin/lib/health-diagnostic-rules/install-surface-shadowing.cjs +98 -0
- package/gsd-core/bin/lib/health-diagnostic-rules/milestone-archive-hygiene.cjs +100 -0
- package/gsd-core/bin/lib/health-diagnostic-rules/phase-structure.cjs +222 -0
- package/gsd-core/bin/lib/health-diagnostic-rules/roadmap-disk-consistency.cjs +268 -0
- package/gsd-core/bin/lib/health-diagnostic-rules/root-existence.cjs +161 -0
- package/gsd-core/bin/lib/health-diagnostic-rules/state-consistency.cjs +303 -0
- package/gsd-core/bin/lib/health-diagnostic-rules/worktree-health.cjs +187 -0
- package/gsd-core/bin/lib/health-diagnostic-types.cjs +68 -0
- package/gsd-core/bin/lib/health-diagnostic.cjs +451 -0
- package/gsd-core/bin/lib/host-integration.cjs +39 -6
- package/gsd-core/bin/lib/host-runtime-detection.cjs +134 -0
- package/gsd-core/bin/lib/init-command-router.cjs +118 -21
- package/gsd-core/bin/lib/init.cjs +439 -168
- package/gsd-core/bin/lib/install-effort-resolver.cjs +73 -30
- package/gsd-core/bin/lib/install-engine.cjs +811 -259
- package/gsd-core/bin/lib/install-fs-adapter.cjs +262 -0
- package/gsd-core/bin/lib/install-model-override-resolver.cjs +235 -0
- package/gsd-core/bin/lib/install-profiles.cjs +212 -61
- package/gsd-core/bin/lib/install-scope.cjs +270 -0
- package/gsd-core/bin/lib/install-shadow-report.cjs +385 -0
- package/gsd-core/bin/lib/installed-surface-resolver.cjs +381 -0
- package/gsd-core/bin/lib/installer-migration-report.cjs +3 -0
- package/gsd-core/bin/lib/installer-migrations/010-antigravity-retire-confighome-artifacts.cjs +169 -0
- package/gsd-core/bin/lib/installer-migrations.cjs +148 -38
- package/gsd-core/bin/lib/intel.cjs +101 -26
- package/gsd-core/bin/lib/io.cjs +170 -15
- package/gsd-core/bin/lib/learnings.cjs +85 -14
- package/gsd-core/bin/lib/legacy-cleanup.cjs +8 -2
- package/gsd-core/bin/lib/markdown-sectionizer.cjs +2 -1
- package/gsd-core/bin/lib/markdown-table.cjs +183 -22
- package/gsd-core/bin/lib/milestone-lock.cjs +248 -0
- package/gsd-core/bin/lib/milestone.cjs +842 -73
- package/gsd-core/bin/lib/model-catalog.cjs +232 -16
- package/gsd-core/bin/lib/model-resolver.cjs +193 -68
- package/gsd-core/bin/lib/normalize-test-command.cjs +1 -1
- package/gsd-core/bin/lib/onboard-projection.cjs +5 -1
- package/gsd-core/bin/lib/pattern.cjs +122 -0
- package/gsd-core/bin/lib/phase-estimation.cjs +18 -9
- package/gsd-core/bin/lib/phase-id.cjs +514 -40
- package/gsd-core/bin/lib/phase-lifecycle.cjs +52 -19
- package/gsd-core/bin/lib/phase-locator.cjs +262 -34
- package/gsd-core/bin/lib/phase.cjs +1038 -214
- package/gsd-core/bin/lib/plan-dependency-graph.cjs +72 -1
- package/gsd-core/bin/lib/plan-document.cjs +263 -0
- package/gsd-core/bin/lib/plan-drift-guard.cjs +120 -0
- package/gsd-core/bin/lib/plan-scan.cjs +98 -3
- package/gsd-core/bin/lib/planning-command-router.cjs +61 -0
- package/gsd-core/bin/lib/planning-inspect.cjs +1168 -0
- package/gsd-core/bin/lib/planning-scope.cjs +31 -0
- package/gsd-core/bin/lib/planning-snapshot.cjs +894 -0
- package/gsd-core/bin/lib/planning-workspace.cjs +112 -6
- package/gsd-core/bin/lib/probe-core.cjs +5 -2
- package/gsd-core/bin/lib/profile-output.cjs +1 -1
- package/gsd-core/bin/lib/profile-pipeline-command-router.cjs +50 -7
- package/gsd-core/bin/lib/profile-pipeline.cjs +6 -3
- package/gsd-core/bin/lib/real-home-guard.cjs +419 -0
- package/gsd-core/bin/lib/refactor-trigger-command-router.cjs +766 -0
- package/gsd-core/bin/lib/retired-artifact-cleanup.cjs +11 -6
- package/gsd-core/bin/lib/review-lane-descriptor.cjs +22 -13
- package/gsd-core/bin/lib/review-lane-invocation.cjs +30 -0
- package/gsd-core/bin/lib/review-lane-runner.cjs +421 -66
- package/gsd-core/bin/lib/review-reviewer-selection.cjs +13 -18
- package/gsd-core/bin/lib/roadmap-command-router.cjs +59 -11
- package/gsd-core/bin/lib/roadmap-parser.cjs +1006 -184
- package/gsd-core/bin/lib/roadmap-upgrade.cjs +37 -10
- package/gsd-core/bin/lib/roadmap.cjs +442 -96
- package/gsd-core/bin/lib/runtime-artifact-conversion.cjs +702 -52
- package/gsd-core/bin/lib/runtime-artifact-install-plan.cjs +14 -2
- package/gsd-core/bin/lib/runtime-artifact-layout.cjs +459 -55
- package/gsd-core/bin/lib/runtime-config-adapter-registry.cjs +3 -2
- package/gsd-core/bin/lib/runtime-homes.cjs +69 -3
- package/gsd-core/bin/lib/runtime-hooks-surface.cjs +402 -58
- package/gsd-core/bin/lib/runtime-identity.cjs +234 -0
- package/gsd-core/bin/lib/runtime-name-policy.cjs +3 -1
- package/gsd-core/bin/lib/runtime-slash.cjs +96 -8
- package/gsd-core/bin/lib/security.cjs +104 -5
- package/gsd-core/bin/lib/shell-command-projection.cjs +342 -7
- package/gsd-core/bin/lib/smart-entry.cjs +133 -23
- package/gsd-core/bin/lib/spec-section.cjs +12 -7
- package/gsd-core/bin/lib/state-command-router.cjs +52 -19
- package/gsd-core/bin/lib/state-contract.cjs +359 -0
- package/gsd-core/bin/lib/state-document.cjs +338 -8
- package/gsd-core/bin/lib/state-md-schema.cjs +221 -0
- package/gsd-core/bin/lib/state-transition.cjs +846 -176
- package/gsd-core/bin/lib/state.cjs +2589 -369
- package/gsd-core/bin/lib/surface.cjs +33 -11
- package/gsd-core/bin/lib/task-command-router.cjs +111 -1
- package/gsd-core/bin/lib/task-content-resolution.cjs +368 -0
- package/gsd-core/bin/lib/teams-status.cjs +4 -1
- package/gsd-core/bin/lib/text-lines.cjs +80 -0
- package/gsd-core/bin/lib/token-scanner.cjs +76 -0
- package/gsd-core/bin/lib/uat-predicate.cjs +67 -23
- package/gsd-core/bin/lib/uat.cjs +1761 -167
- package/gsd-core/bin/lib/ui-consideration-probe.cjs +9 -1
- package/gsd-core/bin/lib/ui-frontend-evidence.cjs +157 -0
- package/gsd-core/bin/lib/ui-safety-gate.cjs +51 -12
- package/gsd-core/bin/lib/unusable-input.cjs +37 -0
- package/gsd-core/bin/lib/update-context.cjs +8 -2
- package/gsd-core/bin/lib/user-artifact-staging.cjs +705 -0
- package/gsd-core/bin/lib/validate-command-router.cjs +2 -2
- package/gsd-core/bin/lib/validate.cjs +20 -6
- package/gsd-core/bin/lib/vendor/README.md +75 -0
- package/gsd-core/bin/lib/vendor/js-yaml.cjs +3014 -0
- package/gsd-core/bin/lib/vendor/re2js.cjs +6480 -0
- package/gsd-core/bin/lib/vendor/re2js.d.cts +938 -0
- package/gsd-core/bin/lib/verification-command-router.cjs +2 -1
- package/gsd-core/bin/lib/verification.cjs +272 -9
- package/gsd-core/bin/lib/verify-command-grounding.cjs +846 -0
- package/gsd-core/bin/lib/verify.cjs +453 -918
- package/gsd-core/bin/lib/workstream-inventory-builder.cjs +53 -32
- package/gsd-core/bin/lib/workstream-inventory.cjs +63 -10
- package/gsd-core/bin/lib/workstream-name-policy.cjs +25 -4
- package/gsd-core/bin/lib/workstream.cjs +2 -2
- package/gsd-core/bin/lib/worktree-base-ref.cjs +66 -12
- package/gsd-core/bin/lib/worktree-safety.cjs +341 -18
- package/gsd-core/bin/shared/config-defaults.manifest.json +8 -1
- package/gsd-core/bin/shared/config-schema.manifest.json +12 -1
- package/gsd-core/bin/shared/exit-codes.json +8 -0
- package/gsd-core/bin/shared/exit-codes.sh +20 -0
- package/gsd-core/bin/shared/model-catalog.json +8 -1
- package/gsd-core/references/agent-contracts.md +44 -26
- package/gsd-core/references/api-coverage.md +24 -2
- package/gsd-core/references/autonomous-smart-discuss.md +3 -3
- package/gsd-core/references/checkpoints.md +39 -21
- package/gsd-core/references/context-budget.md +1 -1
- package/gsd-core/references/decimal-phase-calculation.md +5 -5
- package/gsd-core/references/dispatch-isolation-gate.md +138 -0
- package/gsd-core/references/doc-conflict-engine.md +1 -1
- package/gsd-core/references/edge-probe.md +8 -0
- package/gsd-core/references/execute-mvp-tdd.md +4 -6
- package/gsd-core/references/execute-phase-between-wave-reset.md +15 -14
- package/gsd-core/references/execute-phase-context-guard.md +1 -1
- package/gsd-core/references/execute-phase-response-language.md +1 -1
- package/gsd-core/references/execute-phase-wave-guard.md +17 -11
- package/gsd-core/references/failing-direction.md +78 -0
- package/gsd-core/references/gate-prompts.md +1 -1
- package/gsd-core/references/git-integration.md +5 -5
- package/gsd-core/references/git-planning-commit.md +5 -4
- package/gsd-core/references/gsd-run-resolver.md +1 -1
- package/gsd-core/references/loop-hook-dispatch.md +61 -2
- package/gsd-core/references/model-profiles.md +12 -4
- package/gsd-core/references/mvp-concepts.md +9 -9
- package/gsd-core/references/nyquist-compliance.md +74 -0
- package/gsd-core/references/offer-next.md +3 -5
- package/gsd-core/references/phase-argument-parsing.md +3 -3
- package/gsd-core/references/planner-failing-direction.md +53 -0
- package/gsd-core/references/planner-guidance.md +3 -9
- package/gsd-core/references/planner-human-verify-mode.md +15 -1
- package/gsd-core/references/planner-preconditions.md +1 -1
- package/gsd-core/references/planner-reviews.md +1 -1
- package/gsd-core/references/planner-revision.md +1 -1
- package/gsd-core/references/planner-verify-command-grounding.md +17 -0
- package/gsd-core/references/planning-config.md +44 -13
- package/gsd-core/references/reviewer-instances.md +31 -0
- package/gsd-core/references/revision-loop.md +1 -1
- package/gsd-core/references/runtime-aware-dispatch.md +1 -1
- package/gsd-core/references/specless-probe-fallback.md +1 -1
- package/gsd-core/references/tdd.md +1 -3
- package/gsd-core/references/ui-brand.md +65 -21
- package/gsd-core/references/ui-consideration-probe.md +1 -1
- package/gsd-core/references/universal-anti-patterns.md +5 -5
- package/gsd-core/references/verifier-phase-gates.md +192 -0
- package/gsd-core/references/verify-command-path-resolvability.md +42 -0
- package/gsd-core/references/verify-mvp-mode.md +2 -2
- package/gsd-core/references/workstream-flag.md +33 -17
- package/gsd-core/templates/README.md +1 -1
- package/gsd-core/templates/SECURITY.md +3 -3
- package/gsd-core/templates/UI-SPEC.md +25 -3
- package/gsd-core/templates/VALIDATION.md +3 -3
- package/gsd-core/templates/discussion-log.md +1 -1
- package/gsd-core/templates/phase-prompt.md +5 -4
- package/gsd-core/templates/state.md +11 -4
- package/gsd-core/templates/verification-report.md +9 -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 +3 -3
- package/gsd-core/workflows/add-tests.md +3 -8
- package/gsd-core/workflows/add-todo.md +1 -1
- package/gsd-core/workflows/ai-integration-phase.md +13 -20
- package/gsd-core/workflows/audit-fix.md +12 -3
- package/gsd-core/workflows/audit-milestone.md +9 -9
- package/gsd-core/workflows/audit-uat.md +17 -2
- package/gsd-core/workflows/autonomous/steps/converge-fail-fast.md +2 -2
- package/gsd-core/workflows/autonomous.md +11 -27
- package/gsd-core/workflows/check-todos.md +1 -1
- package/gsd-core/workflows/cleanup.md +64 -5
- package/gsd-core/workflows/code-review/steps/structural-pre-pass.md +14 -4
- package/gsd-core/workflows/code-review-fix.md +38 -11
- package/gsd-core/workflows/code-review.md +159 -52
- package/gsd-core/workflows/complete-milestone.md +151 -23
- package/gsd-core/workflows/debug.md +12 -8
- package/gsd-core/workflows/diagnose-issues.md +47 -15
- package/gsd-core/workflows/discuss-phase/modes/advisor.md +1 -1
- package/gsd-core/workflows/discuss-phase/modes/chain.md +5 -8
- package/gsd-core/workflows/discuss-phase/modes/default.md +1 -1
- package/gsd-core/workflows/discuss-phase/modes/text.md +1 -1
- package/gsd-core/workflows/discuss-phase-assumptions/steps/auto-advance-dispatch.md +1 -3
- package/gsd-core/workflows/discuss-phase-assumptions.md +4 -3
- package/gsd-core/workflows/discuss-phase.md +1 -1
- package/gsd-core/workflows/do.md +3 -6
- package/gsd-core/workflows/docs-update.md +5 -4
- package/gsd-core/workflows/edit-phase.md +27 -2
- package/gsd-core/workflows/eval-review.md +7 -14
- package/gsd-core/workflows/execute-phase/steps/codebase-drift-gate.md +1 -1
- package/gsd-core/workflows/execute-phase/steps/executor-isolation-dispatch.md +142 -15
- 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 +77 -0
- package/gsd-core/workflows/execute-phase/steps/per-plan-worktree-gate.md +24 -4
- package/gsd-core/workflows/execute-phase/steps/post-merge-gate.md +2 -2
- package/gsd-core/workflows/execute-phase/steps/protected-branch.md +21 -0
- package/gsd-core/workflows/execute-phase/steps/regression-gate-run.md +2 -2
- package/gsd-core/workflows/execute-phase/steps/wave-post-gate-hooks.md +39 -0
- package/gsd-core/workflows/execute-phase.md +72 -100
- package/gsd-core/workflows/execute-plan.md +52 -15
- package/gsd-core/workflows/explore.md +131 -4
- package/gsd-core/workflows/extract-learnings.md +1 -1
- package/gsd-core/workflows/fast.md +10 -2
- package/gsd-core/workflows/forensics.md +1 -1
- package/gsd-core/workflows/graduation.md +5 -5
- package/gsd-core/workflows/health.md +76 -10
- package/gsd-core/workflows/import.md +18 -15
- package/gsd-core/workflows/inbox.md +4 -5
- package/gsd-core/workflows/ingest-docs.md +49 -16
- package/gsd-core/workflows/insert-phase.md +5 -5
- package/gsd-core/workflows/list-seeds.md +5 -3
- package/gsd-core/workflows/list-workspaces.md +1 -1
- package/gsd-core/workflows/manager.md +12 -23
- package/gsd-core/workflows/map-codebase.md +1 -1
- package/gsd-core/workflows/milestone-summary.md +1 -1
- package/gsd-core/workflows/mvp-phase.md +8 -5
- package/gsd-core/workflows/new-milestone.md +22 -29
- package/gsd-core/workflows/new-project/steps/auto-mode-config.md +1 -1
- package/gsd-core/workflows/new-project.md +26 -40
- package/gsd-core/workflows/new-workspace.md +1 -1
- package/gsd-core/workflows/next.md +14 -2
- package/gsd-core/workflows/pause-work.md +1 -1
- package/gsd-core/workflows/plan-phase/steps/adr-ingest-express-path.md +1 -1
- package/gsd-core/workflows/plan-phase/steps/chunked-planning-mode.md +1 -1
- package/gsd-core/workflows/plan-phase/steps/prd-express-path.md +2 -4
- package/gsd-core/workflows/plan-phase/steps/stall-detection-helpers.md +3 -3
- package/gsd-core/workflows/plan-phase.md +162 -59
- package/gsd-core/workflows/plan-review-convergence.md +96 -11
- package/gsd-core/workflows/plant-seed.md +2 -2
- package/gsd-core/workflows/pr-branch.md +187 -51
- package/gsd-core/workflows/profile-user.md +16 -14
- package/gsd-core/workflows/progress.md +61 -18
- package/gsd-core/workflows/quick/steps/discussion-phase.md +1 -3
- package/gsd-core/workflows/quick/steps/plan-checker-loop.md +5 -7
- package/gsd-core/workflows/quick/steps/quick-verification.md +28 -9
- package/gsd-core/workflows/quick/steps/research-phase.md +4 -6
- package/gsd-core/workflows/quick/steps/worktree-pre-dispatch-commit.md +3 -3
- package/gsd-core/workflows/quick.md +55 -44
- package/gsd-core/workflows/remove-phase.md +4 -4
- package/gsd-core/workflows/remove-workspace.md +2 -2
- package/gsd-core/workflows/resume-project.md +8 -12
- package/gsd-core/workflows/review.md +219 -20
- package/gsd-core/workflows/scan.md +1 -1
- package/gsd-core/workflows/secure-phase.md +3 -3
- package/gsd-core/workflows/session-report.md +2 -1
- package/gsd-core/workflows/settings-advanced.md +7 -9
- package/gsd-core/workflows/settings-integrations.md +64 -31
- package/gsd-core/workflows/settings.md +69 -7
- package/gsd-core/workflows/ship.md +116 -50
- package/gsd-core/workflows/sketch-wrap-up.md +11 -17
- package/gsd-core/workflows/sketch.md +12 -18
- package/gsd-core/workflows/smart-entry.md +3 -5
- package/gsd-core/workflows/spec-phase.md +53 -13
- package/gsd-core/workflows/spike-wrap-up.md +7 -11
- package/gsd-core/workflows/spike.md +20 -31
- package/gsd-core/workflows/stats.md +2 -2
- package/gsd-core/workflows/sync-skills.md +64 -9
- package/gsd-core/workflows/thread.md +11 -7
- package/gsd-core/workflows/transition.md +49 -14
- package/gsd-core/workflows/ui-phase.md +15 -21
- package/gsd-core/workflows/ui-review.md +8 -12
- package/gsd-core/workflows/ultraplan-phase.md +5 -13
- package/gsd-core/workflows/undo.md +8 -16
- package/gsd-core/workflows/update.md +7 -11
- package/gsd-core/workflows/validate-phase.md +3 -3
- package/gsd-core/workflows/verify-work/steps/automated-ui-verification.md +25 -1
- package/gsd-core/workflows/verify-work/steps/mvp-uat-framing.md +1 -1
- package/gsd-core/workflows/verify-work.md +66 -25
- package/hooks/dist/gsd-agent-isolation-guard.js +158 -30
- package/hooks/dist/gsd-check-update-worker.js +56 -13
- package/hooks/dist/gsd-check-update.js +19 -1
- package/hooks/dist/gsd-config-reload.js +18 -12
- package/hooks/dist/gsd-context-monitor.js +19 -10
- package/hooks/dist/gsd-cursor-post-tool.js +3 -1
- package/hooks/dist/gsd-cursor-pre-tool.js +2 -3
- package/hooks/dist/gsd-cursor-session-start.js +2 -1
- package/hooks/dist/gsd-cursor-stop.js +2 -1
- package/hooks/dist/gsd-cursor-subagent-start.js +83 -3
- package/hooks/dist/gsd-cursor-subagent-stop.js +6 -3
- package/hooks/dist/gsd-ensure-canonical-path.js +2 -1
- package/hooks/dist/gsd-graphify-update.sh +22 -18
- package/hooks/dist/gsd-node-runner.sh +76 -0
- package/hooks/dist/gsd-phase-boundary.sh +1 -0
- package/hooks/dist/gsd-prompt-guard.js +37 -27
- package/hooks/dist/gsd-read-guard.js +16 -7
- package/hooks/dist/gsd-read-injection-scanner.js +55 -32
- package/hooks/dist/gsd-session-state.sh +1 -0
- package/hooks/dist/gsd-statusline.js +231 -24
- package/hooks/dist/gsd-update-banner.js +22 -1
- package/hooks/dist/gsd-validate-commit.sh +80 -6
- package/hooks/dist/gsd-windsurf-pre-command.js +16 -11
- package/hooks/dist/gsd-windsurf-pre-write.js +22 -13
- package/hooks/dist/gsd-workflow-guard.js +162 -46
- package/hooks/dist/gsd-worktree-path-guard.js +36 -21
- package/hooks/dist/gsd-write-guard.js +35 -25
- package/hooks/dist/lib/cli-exit.js +560 -0
- package/hooks/dist/lib/exit-code-registry.js +98 -0
- package/hooks/dist/lib/git-cmd.js +92 -59
- package/hooks/dist/lib/git-probe.js +84 -0
- package/hooks/dist/lib/hook-exit.js +81 -0
- package/hooks/dist/lib/injection-patterns.js +45 -0
- package/hooks/dist/lib/isolation-deny-reason.js +39 -0
- package/hooks/dist/lib/isolation-sentinel.js +9 -0
- package/hooks/dist/managed-hooks-registry.cjs +3 -0
- package/hooks/gsd-agent-isolation-guard.js +158 -30
- package/hooks/gsd-check-update-worker.js +56 -13
- package/hooks/gsd-check-update.js +19 -1
- package/hooks/gsd-config-reload.js +18 -12
- package/hooks/gsd-context-monitor.js +19 -10
- package/hooks/gsd-cursor-post-tool.js +3 -1
- package/hooks/gsd-cursor-pre-tool.js +2 -3
- package/hooks/gsd-cursor-session-start.js +2 -1
- package/hooks/gsd-cursor-stop.js +2 -1
- package/hooks/gsd-cursor-subagent-start.js +83 -3
- package/hooks/gsd-cursor-subagent-stop.js +6 -3
- package/hooks/gsd-ensure-canonical-path.js +2 -1
- package/hooks/gsd-graphify-update.sh +22 -18
- package/hooks/gsd-node-runner.sh +76 -0
- package/hooks/gsd-phase-boundary.sh +1 -0
- package/hooks/gsd-prompt-guard.js +37 -27
- package/hooks/gsd-read-guard.js +16 -7
- package/hooks/gsd-read-injection-scanner.js +55 -32
- package/hooks/gsd-session-state.sh +1 -0
- package/hooks/gsd-statusline.js +231 -24
- package/hooks/gsd-update-banner.js +22 -1
- package/hooks/gsd-validate-commit.sh +80 -6
- package/hooks/gsd-windsurf-pre-command.js +16 -11
- package/hooks/gsd-windsurf-pre-write.js +22 -13
- package/hooks/gsd-workflow-guard.js +162 -46
- package/hooks/gsd-worktree-path-guard.js +36 -21
- package/hooks/gsd-write-guard.js +35 -25
- package/hooks/lib/cli-exit.js +560 -0
- package/hooks/lib/exit-code-registry.js +98 -0
- package/hooks/lib/git-cmd.js +92 -59
- package/hooks/lib/git-probe.js +84 -0
- package/hooks/lib/hook-exit.js +81 -0
- package/hooks/lib/injection-patterns.js +45 -0
- package/hooks/lib/isolation-deny-reason.js +39 -0
- package/hooks/lib/isolation-sentinel.js +9 -0
- package/hooks/managed-hooks-registry.cjs +3 -0
- package/package.json +28 -11
- package/pi/gsd.cjs +19 -5
- package/scripts/base64-scan.sh +74 -12
- package/scripts/baselines/planning-prompt-drift-baseline.json +4 -0
- package/scripts/baselines/planning-snapshot-bypass-baseline.json +12 -0
- package/scripts/baselines/unreachable-guard-drift-baseline.json +4 -0
- package/scripts/build-hooks.js +5 -0
- package/scripts/changeset/lint.cjs +60 -5
- package/scripts/check-alias-drift.cjs +7 -43
- package/scripts/check-contract-drift.cjs +297 -0
- package/scripts/check-glossary-refs.cjs +77 -15
- package/scripts/check-mutation-score-ratchet.cjs +156 -0
- package/scripts/ci-check-job-near-cap.cjs +49 -0
- package/scripts/ci-pr-mergeability.cjs +262 -0
- package/scripts/ci-test-scope.cjs +64 -14
- package/scripts/ci-timeout-report.cjs +230 -0
- package/scripts/command-contract-helpers.cjs +903 -1
- package/scripts/docs-guard-registry.cjs +396 -0
- package/scripts/gen-adr-index.cjs +728 -38
- package/scripts/gen-capability-registry.cjs +11 -21
- package/scripts/gen-context-index.cjs +2 -11
- package/scripts/gen-exit-code-docs.cjs +318 -0
- package/scripts/gen-exit-code-registry.cjs +891 -0
- package/scripts/gen-features.cjs +836 -0
- package/scripts/gen-health-docs.cjs +390 -0
- package/scripts/gen-hooks-cli-exit.cjs +239 -0
- package/scripts/gen-install-tree-fixtures.cjs +2 -2
- package/scripts/gen-inventory-manifest.cjs +50 -4
- package/scripts/gen-loop-host-contract.cjs +138 -25
- package/scripts/gen-registry.cjs +3 -14
- package/scripts/gen-scripts-cli-exit.cjs +185 -0
- package/scripts/gen-state-md-docs.cjs +727 -0
- package/scripts/{test-failure-reasons.cjs → gsd-test-gate-reasons.cjs} +6 -0
- package/scripts/lib/alias-drift-families.cjs +46 -0
- package/scripts/lib/ci-job-timing.cjs +72 -0
- package/scripts/lib/cli-exit.cjs +546 -44
- package/scripts/lib/drift-scan.cjs +308 -0
- package/scripts/lib/exit-code-registry.cjs +98 -0
- package/scripts/lib/ndjson-reporter.cjs +119 -0
- package/scripts/lint-allow-test-rule-refs.allowlist.json +1 -26
- package/scripts/lint-allow-test-rule-refs.effective-ceiling.json +4 -0
- package/scripts/lint-allow-test-rule-refs.unverified-ceiling.json +3 -0
- package/scripts/lint-canary-version-leak.cjs +73 -0
- package/scripts/lint-command-contract.cjs +96 -13
- package/scripts/lint-completion-predicate-drift.cjs +933 -0
- package/scripts/lint-completion-ratio-drift.cjs +214 -0
- package/scripts/lint-default-flip-documentation.cjs +193 -0
- package/scripts/lint-docs-guard-registration.cjs +495 -0
- package/scripts/lint-docs-guard-registration.exempt-baseline.cjs +193 -0
- package/scripts/lint-eslint-glob-coverage.allowlist.json +38 -0
- package/scripts/lint-eslint-glob-coverage.cjs +340 -0
- package/scripts/{lint-fix-has-regression-test.cjs → lint-fix-has-regression-tests.cjs} +12 -6
- package/scripts/lint-frontmatter-scalar-broad-grep.cjs +237 -0
- package/scripts/lint-health-diagnostic-rule-table.cjs +461 -0
- package/scripts/lint-hooks-runtime-build-seam.cjs +262 -0
- package/scripts/lint-milestone-window-drift.cjs +468 -0
- package/scripts/lint-mutation-test-derivation-drift.cjs +86 -0
- package/scripts/lint-phase-enumeration-drift.cjs +492 -0
- package/scripts/lint-plan-count-drift.cjs +318 -0
- package/scripts/lint-planning-artifact-writer-drift.cjs +398 -0
- package/scripts/lint-planning-prompt-drift.cjs +471 -0
- package/scripts/lint-planning-snapshot-bypass-drift.cjs +544 -0
- package/scripts/lint-regression-test-names.cjs +15 -13
- package/scripts/lint-removed-but-needed.cjs +488 -0
- package/scripts/lint-seam-enforcement.cjs +182 -0
- package/scripts/lint-slug-derivation-drift.cjs +921 -0
- package/scripts/lint-source-test-name-collision.cjs +241 -0
- package/scripts/lint-state-field-drift.cjs +805 -0
- package/scripts/lint-state-write-path-drift.cjs +950 -0
- package/scripts/lint-test-file-count.allowlist.json +137 -8
- package/scripts/lint-test-file-count.cjs +25 -3
- package/scripts/lint-unreachable-guard-drift.cjs +830 -0
- package/scripts/lint-vendored-deps.cjs +297 -0
- package/scripts/mutation-matrix.cjs +599 -50
- package/scripts/pr-changed-files.cjs +63 -0
- package/scripts/pr-template-policy.cjs +14 -4
- package/scripts/prompt-injection-scan.sh +100 -14
- package/scripts/require-issue-link-policy.cjs +192 -0
- package/scripts/secret-scan.sh +75 -13
- package/scripts/select-docs-guards.cjs +56 -0
- package/scripts/sync-runtime-launcher.cjs +24 -7
- package/skills/gsd-autonomous/SKILL.md +0 -1
- package/skills/gsd-code-review/SKILL.md +1 -1
- package/skills/gsd-discuss-phase/SKILL.md +1 -1
- package/skills/gsd-execute-phase/SKILL.md +1 -2
- package/skills/gsd-import/SKILL.md +1 -1
- package/skills/gsd-map-codebase/SKILL.md +1 -1
- package/skills/gsd-mempalace-capture/SKILL.md +1 -1
- package/skills/gsd-mempalace-recall/SKILL.md +1 -1
- package/skills/gsd-new-milestone/SKILL.md +1 -1
- package/skills/gsd-next/SKILL.md +0 -1
- package/skills/gsd-plan-phase/SKILL.md +0 -1
- package/skills/gsd-progress/SKILL.md +0 -1
- package/skills/gsd-quick/SKILL.md +9 -5
- package/skills/gsd-review-backlog/SKILL.md +2 -1
- package/skills/gsd-stats/SKILL.md +0 -1
- package/skills/gsd-verify-work/SKILL.md +1 -1
- package/vscode/package.json +1 -1
- package/bin/lib/ui-safety-gate.cjs +0 -107
- package/gsd-core/workflows/discovery-phase.md +0 -298
- package/gsd-core/workflows/plan-milestone-gaps.md +0 -281
- package/gsd-core/workflows/verify-phase.md +0 -574
- package/scripts/affected-tests-lib.cjs +0 -554
- package/scripts/lint-allow-test-rule-refs.cjs +0 -162
- package/scripts/lint-emitted-drift-ack.cjs +0 -344
- package/scripts/run-affected-tests.cjs +0 -7
- package/scripts/run-tests.cjs +0 -1051
|
@@ -0,0 +1,398 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Registry-completeness guard for the `.planning/`-root artifact registry
|
|
6
|
+
* (epic #3180, ADR-3180 §8.4 deliverable C, Phase 12 #3310).
|
|
7
|
+
*
|
|
8
|
+
* `src/artifacts.cts`'s `isCanonicalPlanningFile` enumerates every file name
|
|
9
|
+
* gsd workflows officially write at the `.planning/` ROOT (used today by
|
|
10
|
+
* `validate.health`'s W019 to flag unrecognized files). Nothing previously
|
|
11
|
+
* checked the OTHER direction: that every actual writer of a `.planning/`
|
|
12
|
+
* root file is itself represented in that registry. This guard closes that
|
|
13
|
+
* gap statically — it does not run any code, it scans `src/*.cts` for a
|
|
14
|
+
* write whose target file name can be determined AT READ TIME and checks
|
|
15
|
+
* that name against the real (compiled) `isCanonicalPlanningFile`.
|
|
16
|
+
*
|
|
17
|
+
* ## What counts as a checkable write
|
|
18
|
+
*
|
|
19
|
+
* A call to `platformWriteSync(` or `fs.writeFileSync(` whose first argument
|
|
20
|
+
* resolves — through same-file, single-hop static tracing only — to a
|
|
21
|
+
* LITERAL `.md`/`.json` file name joined onto an UNAMBIGUOUS `.planning/`
|
|
22
|
+
* root expression. Three source shapes are recognized, all real patterns
|
|
23
|
+
* found in this codebase (`src/roadmap.cts`, `src/state.cts`,
|
|
24
|
+
* `src/config.cts`, `src/milestone.cts`, `src/health-diagnostic.cts`):
|
|
25
|
+
*
|
|
26
|
+
* 1. `path.join(<ROOT>, 'Literal.md')` — inline, or assigned first to a
|
|
27
|
+
* `const`/`let` binding or an object-literal property
|
|
28
|
+
* (`key: path.join(<ROOT>, 'Literal.md')`) that is later passed to the
|
|
29
|
+
* write call by name. Object-literal properties are traced by NAME
|
|
30
|
+
* only (no cross-function data-flow) — this matches the actual
|
|
31
|
+
* `RepairPaths`-style convention this repo already uses
|
|
32
|
+
* (`src/health-diagnostic.cts:209-218`), where a destructured
|
|
33
|
+
* parameter reuses the same identifier the property was defined with.
|
|
34
|
+
* 2. `planningPaths(cwd).<prop>` for `<prop>` in `state`, `roadmap`,
|
|
35
|
+
* `project`, `config`, `requirements` — the `PlanningPaths` interface's
|
|
36
|
+
* own file-valued properties (`src/planning-workspace.cts`), which are
|
|
37
|
+
* already a full path, not a directory to join further.
|
|
38
|
+
* 3. A `<ROOT>` in both forms above means EXACTLY `planningRoot(cwd)`,
|
|
39
|
+
* `planningDir(cwd)` (no second argument), or `planningPaths(cwd)`
|
|
40
|
+
* (no second argument) `.planning` — deliberately excluding any call
|
|
41
|
+
* that passes a workstream/project argument (`planningDir(cwd, ws)`),
|
|
42
|
+
* because that form can resolve UNDER `.planning/workstreams/<ws>/`
|
|
43
|
+
* instead of the `.planning/` root, and this guard cannot tell
|
|
44
|
+
* statically whether `ws` is truthy at runtime. Per this guard's own
|
|
45
|
+
* design brief: "false negatives are safer than false positives" — an
|
|
46
|
+
* ambiguous root expression is silently skipped, never reported either
|
|
47
|
+
* way.
|
|
48
|
+
*
|
|
49
|
+
* Anything else — a template-literal or otherwise runtime-computed target,
|
|
50
|
+
* a multi-segment join landing under `phases/`, `milestones/`, or
|
|
51
|
+
* `workstreams/`, a path built through an intermediate helper this guard
|
|
52
|
+
* does not recognize (e.g. `path.dirname(x)`, a ternary, a `.gsd/`
|
|
53
|
+
* fallback) — is silently skipped. This guard reports VIOLATIONS only; a
|
|
54
|
+
* skipped write is never counted as a pass either. See the module docblock
|
|
55
|
+
* above `src/artifacts.cts` for the registry's own stated scope
|
|
56
|
+
* (".planning/ root level" only) — this guard shares that scope.
|
|
57
|
+
*
|
|
58
|
+
* ## Caveat: same-file, name-based tracing (not a real data-flow analysis)
|
|
59
|
+
*
|
|
60
|
+
* Both the `const`/`let` and object-literal-property forms are tracked in a
|
|
61
|
+
* single flat, WHOLE-FILE, name -> file-name map (no per-function scoping).
|
|
62
|
+
* If the same identifier were reused in one file for two unrelated purposes
|
|
63
|
+
* — one a real `.planning/`-root join, the other something else entirely —
|
|
64
|
+
* this guard could mis-resolve the second one. No such collision exists in
|
|
65
|
+
* `src/*.cts` today (verified during implementation); this is a known,
|
|
66
|
+
* accepted heuristic limit, matching this guard's explicitly simpler
|
|
67
|
+
* (non-function-scoped) design versus its sibling
|
|
68
|
+
* `lint-planning-snapshot-bypass-drift.cjs`.
|
|
69
|
+
*
|
|
70
|
+
* ## No ratchet / no baseline
|
|
71
|
+
*
|
|
72
|
+
* Unlike its `lint-*-drift.cjs` siblings, this is a bare pass/fail check,
|
|
73
|
+
* not a shrinking-debt baseline: a ground-truth sweep of this codebase
|
|
74
|
+
* found every real `.planning/`-root writer already registered, so there is
|
|
75
|
+
* no inherited debt to grandfather. Any violation this guard reports is a
|
|
76
|
+
* genuine, actionable regression.
|
|
77
|
+
*
|
|
78
|
+
* Tree-walk / root-confinement / symlink / sanitizer machinery is shared
|
|
79
|
+
* via `scripts/lib/drift-scan.cjs`, exactly like every sibling guard.
|
|
80
|
+
*/
|
|
81
|
+
|
|
82
|
+
const fs = require('node:fs');
|
|
83
|
+
const path = require('node:path');
|
|
84
|
+
const driftScan = require('./lib/drift-scan.cjs');
|
|
85
|
+
const { sanitizeForReport, scanTree } = driftScan;
|
|
86
|
+
|
|
87
|
+
const REPO_ROOT = path.join(__dirname, '..');
|
|
88
|
+
const COMPILED_MODULE_REL = path.join('gsd-core', 'bin', 'lib', 'artifacts.cjs');
|
|
89
|
+
const COMPILED_MODULE_PATH = path.join(REPO_ROOT, COMPILED_MODULE_REL);
|
|
90
|
+
|
|
91
|
+
// Authored TypeScript source only — mirrors every sibling drift guard.
|
|
92
|
+
const SCAN_DIRS = ['src'];
|
|
93
|
+
const SCAN_EXT = new Set(['.cts']);
|
|
94
|
+
|
|
95
|
+
// `PlanningPaths` (src/planning-workspace.cts) properties that are
|
|
96
|
+
// themselves a FULL FILE path (not a directory) at the `.planning/` root,
|
|
97
|
+
// mapped to the literal file name they resolve to. `planning`/`phases`/
|
|
98
|
+
// `debug` are deliberately absent — those are directories, not files.
|
|
99
|
+
const PLANNING_PATHS_FILE_PROPS = new Map([
|
|
100
|
+
['state', 'STATE.md'],
|
|
101
|
+
['roadmap', 'ROADMAP.md'],
|
|
102
|
+
['project', 'PROJECT.md'],
|
|
103
|
+
['config', 'config.json'],
|
|
104
|
+
['requirements', 'REQUIREMENTS.md'],
|
|
105
|
+
]);
|
|
106
|
+
|
|
107
|
+
// The three unambiguous `.planning/`-root expressions this guard recognizes
|
|
108
|
+
// as the first argument of `path.join(...)`. Each takes ONLY `cwd` — a call
|
|
109
|
+
// carrying a workstream/project argument is excluded (see module docblock).
|
|
110
|
+
const ROOT_CALL_SRC = String.raw`planningRoot\(cwd\)|planningDir\(cwd\)|planningPaths\(cwd\)\.planning`;
|
|
111
|
+
|
|
112
|
+
// A quoted literal file name ending in `.md` or `.json` — single-quoted or
|
|
113
|
+
// double-quoted, as two separate alternatives (groups: single-quoted
|
|
114
|
+
// filename, double-quoted filename) rather than a `(['"])...\1`
|
|
115
|
+
// backreference: this fragment is spliced into several different larger
|
|
116
|
+
// regexes below at different capture-group OFFSETS, so a fixed
|
|
117
|
+
// backreference number (`\1`) would silently point at whichever group
|
|
118
|
+
// happens to be first in THAT particular composed regex, not necessarily
|
|
119
|
+
// this fragment's own quote group. Every call site reads
|
|
120
|
+
// `matched[i] ?? matched[i + 1]` for the two alternative filename groups
|
|
121
|
+
// this fragment always contributes, in order. Deliberately excludes
|
|
122
|
+
// backticks: a template literal is a runtime-computed target by definition
|
|
123
|
+
// and must never match here.
|
|
124
|
+
const LITERAL_FILENAME_SRC = String.raw`(?:'([^'\\]+\.(?:md|json))'|"([^"\\]+\.(?:md|json))")`;
|
|
125
|
+
|
|
126
|
+
// `const X = <ROOT>;` / `let X = <ROOT>;` — binds X to an unambiguous root
|
|
127
|
+
// expression, so a later `path.join(X, 'Literal.md')` can resolve through
|
|
128
|
+
// it (mirrors `src/config.cts`'s `planningBase` / `src/health-diagnostic
|
|
129
|
+
// .cts`'s `rootBase`/`wsBase`).
|
|
130
|
+
const ROOT_VAR_ASSIGN_RE = new RegExp(String.raw`\b(?:const|let)\s+([A-Za-z_$][\w$]*)\s*=\s*(?:${ROOT_CALL_SRC})\s*;`);
|
|
131
|
+
|
|
132
|
+
// A "binding" — either `const X = ...` / `let X = ...`, or an object-literal
|
|
133
|
+
// property `X: ...` — shared by both join-tracing regexes below so a
|
|
134
|
+
// destructured-later property (the `RepairPaths` convention) traces the
|
|
135
|
+
// same way a local variable does. Group 1 is the const/let name, group 2 is
|
|
136
|
+
// the property name; callers use whichever is non-undefined.
|
|
137
|
+
const BINDING_PREFIX_SRC = String.raw`(?:(?:const|let)\s+([A-Za-z_$][\w$]*)\s*=|([A-Za-z_$][\w$]*)\s*:)`;
|
|
138
|
+
|
|
139
|
+
// `<binding> = path.join(<ROOT>, 'Literal.md')` — the root expression is
|
|
140
|
+
// spelled out inline (not through an intermediate variable).
|
|
141
|
+
const JOIN_FROM_ROOT_CALL_RE = new RegExp(
|
|
142
|
+
String.raw`${BINDING_PREFIX_SRC}\s*path\.join\(\s*(?:${ROOT_CALL_SRC})\s*,\s*${LITERAL_FILENAME_SRC}\s*\)`,
|
|
143
|
+
);
|
|
144
|
+
|
|
145
|
+
// `<binding> = path.join(IDENT, 'Literal.md')` — the root expression was
|
|
146
|
+
// already bound to IDENT by ROOT_VAR_ASSIGN_RE elsewhere in the file.
|
|
147
|
+
const JOIN_FROM_IDENT_RE = new RegExp(
|
|
148
|
+
String.raw`${BINDING_PREFIX_SRC}\s*path\.join\(\s*([A-Za-z_$][\w$]*)\s*,\s*${LITERAL_FILENAME_SRC}\s*\)`,
|
|
149
|
+
);
|
|
150
|
+
|
|
151
|
+
// `<binding> = planningPaths(cwd).<prop>` — PLANNING_PATHS_FILE_PROPS below
|
|
152
|
+
// maps <prop> to its file name.
|
|
153
|
+
const PLANNING_PATHS_PROP_RE = new RegExp(
|
|
154
|
+
String.raw`${BINDING_PREFIX_SRC}\s*planningPaths\(cwd\)\.([A-Za-z_$][\w$]*)\b`,
|
|
155
|
+
);
|
|
156
|
+
|
|
157
|
+
// The write calls this guard checks the first argument of.
|
|
158
|
+
const WRITE_CALL_RE = /\b(?:platformWriteSync|fs\.writeFileSync)\(/g;
|
|
159
|
+
|
|
160
|
+
// A bare identifier, or an inline `path.join(<ROOT>, 'Literal.md')` /
|
|
161
|
+
// `planningPaths(cwd).<prop>` expression, as the resolved first-argument
|
|
162
|
+
// text of a write call.
|
|
163
|
+
const INLINE_JOIN_ROOT_RE = new RegExp(String.raw`^path\.join\(\s*(?:${ROOT_CALL_SRC})\s*,\s*${LITERAL_FILENAME_SRC}\s*\)$`);
|
|
164
|
+
const INLINE_PLANNING_PATHS_PROP_RE = /^planningPaths\(cwd\)\.([A-Za-z_$][\w$]*)$/;
|
|
165
|
+
const BARE_IDENT_RE = /^[A-Za-z_$][\w$]*$/;
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* Strip `//` line comments and `/* ... *\/` block comments from `line`,
|
|
169
|
+
* preserving the CONTENTS of single/double/backtick-quoted strings verbatim
|
|
170
|
+
* (so a filename literal or an identifier that happens to sit inside a
|
|
171
|
+
* string is never mistaken for code, but a `//`/`/*` inside a string never
|
|
172
|
+
* truncates the line either). No cross-line state: a template literal or
|
|
173
|
+
* block comment that spans multiple lines is left as-is on each line it
|
|
174
|
+
* touches — every real call/assignment this guard matches is single-line in
|
|
175
|
+
* `src/*.cts` today, so cross-line tracking would add complexity with no
|
|
176
|
+
* observed benefit (see this guard's "simpler than its sibling" design
|
|
177
|
+
* note).
|
|
178
|
+
*/
|
|
179
|
+
function stripLineComment(line) {
|
|
180
|
+
let out = '';
|
|
181
|
+
let i = 0;
|
|
182
|
+
while (i < line.length) {
|
|
183
|
+
const ch = line[i];
|
|
184
|
+
if (ch === '/' && line[i + 1] === '/') break;
|
|
185
|
+
if (ch === '/' && line[i + 1] === '*') {
|
|
186
|
+
const close = line.indexOf('*/', i + 2);
|
|
187
|
+
if (close === -1) { i = line.length; break; }
|
|
188
|
+
i = close + 2;
|
|
189
|
+
continue;
|
|
190
|
+
}
|
|
191
|
+
if (ch === "'" || ch === '"' || ch === '`') {
|
|
192
|
+
const quote = ch;
|
|
193
|
+
const start = i;
|
|
194
|
+
let j = i + 1;
|
|
195
|
+
while (j < line.length) {
|
|
196
|
+
if (line[j] === '\\') { j += 2; continue; }
|
|
197
|
+
if (line[j] === quote) { j++; break; }
|
|
198
|
+
j++;
|
|
199
|
+
}
|
|
200
|
+
out += line.slice(start, j);
|
|
201
|
+
i = j;
|
|
202
|
+
continue;
|
|
203
|
+
}
|
|
204
|
+
out += ch;
|
|
205
|
+
i++;
|
|
206
|
+
}
|
|
207
|
+
return out;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
/**
|
|
211
|
+
* Scan forward from `openParenIdx` (the index of a call's opening `(`) and
|
|
212
|
+
* return the TEXT of its first argument — up to the first top-level comma,
|
|
213
|
+
* or the call's own closing paren if it has only one argument — respecting
|
|
214
|
+
* nested parens and quoted strings so an inner `path.join(a, 'b.md')`
|
|
215
|
+
* comma never terminates early. Returns null if the call does not close on
|
|
216
|
+
* this line (a genuinely multi-line call is out of this guard's scope — see
|
|
217
|
+
* module docblock).
|
|
218
|
+
*/
|
|
219
|
+
function extractFirstArg(line, openParenIdx) {
|
|
220
|
+
let depth = 1;
|
|
221
|
+
let i = openParenIdx + 1;
|
|
222
|
+
const start = i;
|
|
223
|
+
while (i < line.length) {
|
|
224
|
+
const ch = line[i];
|
|
225
|
+
if (ch === "'" || ch === '"' || ch === '`') {
|
|
226
|
+
const quote = ch;
|
|
227
|
+
i++;
|
|
228
|
+
while (i < line.length) {
|
|
229
|
+
if (line[i] === '\\') { i += 2; continue; }
|
|
230
|
+
if (line[i] === quote) { i++; break; }
|
|
231
|
+
i++;
|
|
232
|
+
}
|
|
233
|
+
continue;
|
|
234
|
+
}
|
|
235
|
+
if (ch === '(') { depth++; i++; continue; }
|
|
236
|
+
if (ch === ')') {
|
|
237
|
+
if (depth === 1) return line.slice(start, i).trim();
|
|
238
|
+
depth--; i++; continue;
|
|
239
|
+
}
|
|
240
|
+
if (ch === ',' && depth === 1) return line.slice(start, i).trim();
|
|
241
|
+
i++;
|
|
242
|
+
}
|
|
243
|
+
return null; // unterminated on this line — skip (see docblock)
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
/**
|
|
247
|
+
* Pure: scan `text` (one `src/*.cts` file's contents) for every write call
|
|
248
|
+
* this guard can statically resolve to a literal `.planning/`-root file
|
|
249
|
+
* name. Returns EVERY resolved candidate (canonical or not) — filtering to
|
|
250
|
+
* violations only happens in `findArtifactWriterDrift` — so tests and
|
|
251
|
+
* callers can tell "not checked" (candidate absent) apart from "checked and
|
|
252
|
+
* passed" (candidate present, canonical).
|
|
253
|
+
*/
|
|
254
|
+
function scanFileForCandidates(text, relPath) {
|
|
255
|
+
const file = relPath.replace(/\\/g, '/');
|
|
256
|
+
const originalLines = text.split('\n');
|
|
257
|
+
const lines = originalLines.map(stripLineComment);
|
|
258
|
+
|
|
259
|
+
// Pass 1: build the whole-file name -> file-name maps (see module
|
|
260
|
+
// docblock for the "flat, same-file, name-based" tracing this performs).
|
|
261
|
+
const rootVars = new Set();
|
|
262
|
+
const filenameVars = new Map();
|
|
263
|
+
for (const line of lines) {
|
|
264
|
+
const rootMatch = ROOT_VAR_ASSIGN_RE.exec(line);
|
|
265
|
+
if (rootMatch) rootVars.add(rootMatch[1]);
|
|
266
|
+
}
|
|
267
|
+
for (const line of lines) {
|
|
268
|
+
const m1 = JOIN_FROM_ROOT_CALL_RE.exec(line);
|
|
269
|
+
if (m1) {
|
|
270
|
+
const name = m1[1] || m1[2];
|
|
271
|
+
filenameVars.set(name, m1[3] || m1[4]);
|
|
272
|
+
continue;
|
|
273
|
+
}
|
|
274
|
+
const propMatch = PLANNING_PATHS_PROP_RE.exec(line);
|
|
275
|
+
if (propMatch) {
|
|
276
|
+
const name = propMatch[1] || propMatch[2];
|
|
277
|
+
const prop = propMatch[3];
|
|
278
|
+
if (PLANNING_PATHS_FILE_PROPS.has(prop)) filenameVars.set(name, PLANNING_PATHS_FILE_PROPS.get(prop));
|
|
279
|
+
continue;
|
|
280
|
+
}
|
|
281
|
+
const m2 = JOIN_FROM_IDENT_RE.exec(line);
|
|
282
|
+
if (m2) {
|
|
283
|
+
const name = m2[1] || m2[2];
|
|
284
|
+
const sourceIdent = m2[3];
|
|
285
|
+
if (rootVars.has(sourceIdent)) filenameVars.set(name, m2[4] || m2[5]);
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
// Pass 2: resolve every write call's first argument.
|
|
290
|
+
const out = [];
|
|
291
|
+
for (let li = 0; li < lines.length; li++) {
|
|
292
|
+
const line = lines[li];
|
|
293
|
+
WRITE_CALL_RE.lastIndex = 0;
|
|
294
|
+
let callMatch;
|
|
295
|
+
while ((callMatch = WRITE_CALL_RE.exec(line)) !== null) {
|
|
296
|
+
const openParenIdx = callMatch.index + callMatch[0].length - 1;
|
|
297
|
+
const argText = extractFirstArg(line, openParenIdx);
|
|
298
|
+
if (argText === null) continue;
|
|
299
|
+
|
|
300
|
+
let filename = null;
|
|
301
|
+
if (BARE_IDENT_RE.test(argText)) {
|
|
302
|
+
if (filenameVars.has(argText)) filename = filenameVars.get(argText);
|
|
303
|
+
} else {
|
|
304
|
+
const inlineJoin = INLINE_JOIN_ROOT_RE.exec(argText);
|
|
305
|
+
if (inlineJoin) {
|
|
306
|
+
filename = inlineJoin[1] || inlineJoin[2];
|
|
307
|
+
} else {
|
|
308
|
+
const inlineProp = INLINE_PLANNING_PATHS_PROP_RE.exec(argText);
|
|
309
|
+
if (inlineProp && PLANNING_PATHS_FILE_PROPS.has(inlineProp[1])) filename = PLANNING_PATHS_FILE_PROPS.get(inlineProp[1]);
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
if (filename !== null) {
|
|
314
|
+
out.push({ file, line: li + 1, filename, text: originalLines[li].trim() });
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
return out;
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
/**
|
|
322
|
+
* Pure: `scanFileForCandidates` filtered to violations — a resolved
|
|
323
|
+
* candidate whose file name `isCanonicalPlanningFile` rejects.
|
|
324
|
+
* `isCanonical` defaults to the REAL, compiled function (loaded lazily so a
|
|
325
|
+
* missing `npm run build:lib` only errors when this guard actually runs,
|
|
326
|
+
* not merely on `require`) but is overridable for tests that want to
|
|
327
|
+
* exercise the filter without a build.
|
|
328
|
+
*/
|
|
329
|
+
function findArtifactWriterDrift(text, relPath, isCanonical) {
|
|
330
|
+
const check = isCanonical || loadIsCanonicalPlanningFile();
|
|
331
|
+
return scanFileForCandidates(text, relPath).filter((c) => !check(c.filename));
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
let _isCanonicalPlanningFile = null;
|
|
335
|
+
function loadIsCanonicalPlanningFile() {
|
|
336
|
+
if (_isCanonicalPlanningFile) return _isCanonicalPlanningFile;
|
|
337
|
+
if (!fs.existsSync(COMPILED_MODULE_PATH)) {
|
|
338
|
+
throw new Error(
|
|
339
|
+
`lint-planning-artifact-writer-drift: compiled artifact not found at ${COMPILED_MODULE_REL}.\n` +
|
|
340
|
+
'Run `npm run build:lib` first.',
|
|
341
|
+
);
|
|
342
|
+
}
|
|
343
|
+
const mod = require(COMPILED_MODULE_PATH);
|
|
344
|
+
if (typeof mod.isCanonicalPlanningFile !== 'function') {
|
|
345
|
+
throw new Error(`lint-planning-artifact-writer-drift: ${COMPILED_MODULE_REL} does not export isCanonicalPlanningFile()`);
|
|
346
|
+
}
|
|
347
|
+
_isCanonicalPlanningFile = mod.isCanonicalPlanningFile;
|
|
348
|
+
return _isCanonicalPlanningFile;
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
/** Scan the authored source tree and return every writer-registry violation. */
|
|
352
|
+
function scanRepo(root) {
|
|
353
|
+
const isCanonical = loadIsCanonicalPlanningFile();
|
|
354
|
+
return scanTree({
|
|
355
|
+
root,
|
|
356
|
+
scanDirs: SCAN_DIRS,
|
|
357
|
+
scanExt: SCAN_EXT,
|
|
358
|
+
onFile(rel, text) {
|
|
359
|
+
return findArtifactWriterDrift(text, rel, isCanonical);
|
|
360
|
+
},
|
|
361
|
+
});
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
function main() {
|
|
365
|
+
const violations = scanRepo(REPO_ROOT);
|
|
366
|
+
|
|
367
|
+
if (violations.length === 0) {
|
|
368
|
+
process.stdout.write('ok planning-artifact-writer: every statically-resolvable .planning/-root write is a registered canonical artifact\n');
|
|
369
|
+
return;
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
process.stderr.write('planning-artifact-writer: unregistered .planning/-root artifact write(s) found.\n');
|
|
373
|
+
process.stderr.write('Every write of a literal .planning/-root file name must be reflected in the registry\n');
|
|
374
|
+
process.stderr.write("(src/artifacts.cts's isCanonicalPlanningFile, consumed by validate.health's W019):\n");
|
|
375
|
+
for (const v of violations) {
|
|
376
|
+
process.stderr.write(
|
|
377
|
+
` ${sanitizeForReport(v.file)}:${v.line} '${sanitizeForReport(v.filename)}' ${sanitizeForReport(v.text)}\n` +
|
|
378
|
+
` remedy: add '${sanitizeForReport(v.filename)}' to CANONICAL_EXACT in src/artifacts.cts, ` +
|
|
379
|
+
'or a CANONICAL_PATTERNS regex if it is version-stamped\n',
|
|
380
|
+
);
|
|
381
|
+
}
|
|
382
|
+
process.exitCode = 1;
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
if (require.main === module) main();
|
|
386
|
+
|
|
387
|
+
module.exports = {
|
|
388
|
+
scanFileForCandidates,
|
|
389
|
+
findArtifactWriterDrift,
|
|
390
|
+
scanRepo,
|
|
391
|
+
stripLineComment,
|
|
392
|
+
extractFirstArg,
|
|
393
|
+
PLANNING_PATHS_FILE_PROPS,
|
|
394
|
+
SCAN_DIRS,
|
|
395
|
+
SCAN_EXT,
|
|
396
|
+
COMPILED_MODULE_PATH,
|
|
397
|
+
COMPILED_MODULE_REL,
|
|
398
|
+
};
|