@opengsd/gsd-core 1.15.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/agents/gsd-code-fixer.compact.md +1 -1
- package/agents/gsd-code-fixer.md +1 -1
- 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 +1 -1
- package/agents/gsd-debug-session-manager.md +1 -1
- package/agents/gsd-debugger.md +2 -2
- package/agents/gsd-eval-auditor.compact.md +1 -1
- package/agents/gsd-eval-auditor.md +1 -1
- package/agents/gsd-executor.md +4 -4
- 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 +1 -1
- package/agents/gsd-plan-checker.md +7 -2
- package/agents/gsd-planner.md +3 -3
- 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 +42 -51
- package/agents/gsd-ui-researcher.compact.md +1 -1
- package/agents/gsd-ui-researcher.md +1 -1
- package/agents/gsd-verifier.md +31 -9
- package/bin/install.js +126 -196
- 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 +5 -0
- package/commands/gsd/capture.md +8 -4
- 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 +5 -1
- 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 +5 -1
- package/commands/gsd/pr-branch.md +4 -0
- package/commands/gsd/profile-user.md +5 -1
- package/commands/gsd/progress.md +6 -1
- package/commands/gsd/quick-batch.md +20 -8
- package/commands/gsd/quick.md +12 -7
- package/commands/gsd/review.md +5 -1
- 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 +142 -56
- package/gsd-core/bin/lib/active-workstream-store.cjs +15 -0
- package/gsd-core/bin/lib/agent-install-check.cjs +4 -1
- package/gsd-core/bin/lib/audit.cjs +78 -44
- 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 +183 -103
- package/gsd-core/bin/lib/capability-validator.cjs +16 -0
- package/gsd-core/bin/lib/check-auto-mode.cjs +35 -0
- package/gsd-core/bin/lib/check-command-router.cjs +164 -1712
- 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 +11 -8
- 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 +173 -170
- package/gsd-core/bin/lib/complexity-trigger.cjs +8 -7
- package/gsd-core/bin/lib/config.cjs +43 -12
- 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/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 +413 -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/health-diagnostic-rules/phase-structure.cjs +43 -47
- package/gsd-core/bin/lib/health-diagnostic.cjs +45 -8
- package/gsd-core/bin/lib/init.cjs +162 -96
- package/gsd-core/bin/lib/install-engine.cjs +19 -35
- package/gsd-core/bin/lib/install-profiles.cjs +7 -4
- 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 +19 -1
- package/gsd-core/bin/lib/model-resolver.cjs +18 -18
- 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 +11 -4
- package/gsd-core/bin/lib/phase-estimation.cjs +5 -4
- package/gsd-core/bin/lib/phase-id.cjs +1 -1
- package/gsd-core/bin/lib/phase-lifecycle.cjs +9 -2
- package/gsd-core/bin/lib/phase-status.cjs +360 -0
- package/gsd-core/bin/lib/phase.cjs +280 -80
- package/gsd-core/bin/lib/plan-document.cjs +93 -19
- package/gsd-core/bin/lib/plan-drift-guard.cjs +5 -0
- package/gsd-core/bin/lib/planning-document.cjs +273 -40
- package/gsd-core/bin/lib/planning-inspect.cjs +42 -8
- package/gsd-core/bin/lib/planning-snapshot.cjs +18 -0
- package/gsd-core/bin/lib/planning-workspace.cjs +76 -53
- package/gsd-core/bin/lib/pristine-baseline.cjs +10 -0
- 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/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/roadmap-command-router.cjs +13 -15
- package/gsd-core/bin/lib/roadmap-parser.cjs +82 -15
- package/gsd-core/bin/lib/roadmap-upgrade.cjs +127 -65
- package/gsd-core/bin/lib/roadmap.cjs +169 -72
- package/gsd-core/bin/lib/runtime-artifact-conversion.cjs +91 -157
- package/gsd-core/bin/lib/runtime-artifact-install-plan.cjs +2 -1
- package/gsd-core/bin/lib/runtime-artifact-layout.cjs +57 -1
- package/gsd-core/bin/lib/runtime-homes.cjs +13 -10
- package/gsd-core/bin/lib/runtime-hooks-surface.cjs +307 -591
- package/gsd-core/bin/lib/runtime-name-policy.cjs +142 -27
- package/gsd-core/bin/lib/runtime-slash.cjs +47 -30
- package/gsd-core/bin/lib/shell-command-projection.cjs +37 -2
- 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.cjs +214 -105
- package/gsd-core/bin/lib/surface.cjs +2 -1
- package/gsd-core/bin/lib/tdd-red-evidence.cjs +48 -152
- package/gsd-core/bin/lib/uat-predicate.cjs +313 -35
- package/gsd-core/bin/lib/uat.cjs +424 -7
- package/gsd-core/bin/lib/ui-frontend-evidence.cjs +94 -58
- 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 +1165 -314
- package/gsd-core/bin/lib/verify-command-router.cjs +18 -7
- package/gsd-core/bin/lib/verify.cjs +286 -567
- 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/shared/config-defaults.manifest.json +5 -0
- package/gsd-core/bin/shared/config-schema.manifest.json +4 -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/execute-mvp-tdd.md +5 -10
- package/gsd-core/references/execute-phase-between-wave-reset.md +3 -0
- package/gsd-core/references/execute-phase-response-language.md +1 -1
- package/gsd-core/references/gsd-run-resolver.md +1 -1
- package/gsd-core/references/loop-hook-dispatch.md +7 -1
- package/gsd-core/references/offer-next.md +1 -1
- package/gsd-core/references/planning-config.md +1 -1
- package/gsd-core/references/spidr-splitting.md +1 -1
- package/gsd-core/references/tdd.md +10 -4
- package/gsd-core/references/verifier-phase-gates.md +5 -2
- package/gsd-core/references/verify-mvp-mode.md +2 -2
- package/gsd-core/references/workstream-flag.md +33 -3
- 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 +3 -2
- package/gsd-core/workflows/add-todo.md +4 -3
- package/gsd-core/workflows/ai-integration-phase.md +3 -2
- 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.md +28 -18
- package/gsd-core/workflows/check-todos.md +6 -5
- package/gsd-core/workflows/cleanup.md +1 -1
- package/gsd-core/workflows/code-review/steps/structural-pre-pass.md +20 -13
- package/gsd-core/workflows/code-review-fix.md +5 -4
- package/gsd-core/workflows/code-review.md +84 -90
- package/gsd-core/workflows/complete-milestone/detail/elaboration.md +4 -3
- package/gsd-core/workflows/complete-milestone.md +12 -7
- package/gsd-core/workflows/debug.md +30 -5
- 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 +1 -1
- package/gsd-core/workflows/docs-update.md +4 -3
- package/gsd-core/workflows/edit-phase.md +4 -3
- package/gsd-core/workflows/eval-review.md +5 -3
- package/gsd-core/workflows/execute-phase/detail/elaboration.md +1 -1
- package/gsd-core/workflows/execute-phase/steps/code-review-disposition.md +4 -2
- 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 +1 -1
- 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 +1 -1
- package/gsd-core/workflows/execute-phase/steps/protected-branch.md +1 -1
- 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/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.md +78 -170
- package/gsd-core/workflows/execute-plan.md +13 -19
- package/gsd-core/workflows/explore.md +2 -2
- package/gsd-core/workflows/extract-learnings.md +3 -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 +2 -1
- package/gsd-core/workflows/import.md +3 -2
- package/gsd-core/workflows/inbox.md +1 -1
- package/gsd-core/workflows/ingest-docs.md +1 -1
- 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 +5 -3
- package/gsd-core/workflows/map-codebase.md +4 -3
- 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 +10 -10
- package/gsd-core/workflows/new-project/steps/auto-mode-config.md +1 -1
- package/gsd-core/workflows/new-project.md +1 -1
- package/gsd-core/workflows/new-workspace.md +1 -1
- package/gsd-core/workflows/next.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 +1 -1
- 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 +1 -1
- package/gsd-core/workflows/plan-phase.md +27 -18
- package/gsd-core/workflows/plan-review-convergence.md +1 -1
- package/gsd-core/workflows/plant-seed.md +1 -1
- package/gsd-core/workflows/pr-branch.md +1 -1
- package/gsd-core/workflows/profile-user.md +1 -1
- package/gsd-core/workflows/progress.md +19 -49
- package/gsd-core/workflows/quick/steps/plan-checker-loop.md +4 -2
- 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 +42 -31
- package/gsd-core/workflows/remove-phase.md +3 -2
- package/gsd-core/workflows/remove-workspace.md +1 -1
- package/gsd-core/workflows/resume-project.md +3 -2
- package/gsd-core/workflows/review.md +3 -2
- package/gsd-core/workflows/scan.md +3 -2
- package/gsd-core/workflows/secure-phase.md +11 -12
- package/gsd-core/workflows/settings-advanced.md +1 -1
- package/gsd-core/workflows/settings-integrations.md +1 -1
- package/gsd-core/workflows/settings.md +1 -1
- package/gsd-core/workflows/ship.md +12 -12
- 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 +1 -1
- package/gsd-core/workflows/spec-phase.md +1 -1
- 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 +1 -1
- package/gsd-core/workflows/thread.md +2 -2
- package/gsd-core/workflows/transition.md +13 -23
- package/gsd-core/workflows/ui-phase.md +5 -4
- package/gsd-core/workflows/ui-review.md +4 -3
- package/gsd-core/workflows/ultraplan-phase.md +3 -2
- package/gsd-core/workflows/undo.md +1 -1
- package/gsd-core/workflows/validate-phase.md +10 -12
- 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 +68 -59
- package/hooks/dist/gsd-agent-isolation-guard.js +8 -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 +147 -16
- package/hooks/dist/gsd-statusline.js +15 -7
- package/hooks/dist/gsd-update-banner.js +8 -0
- 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 +8 -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 +147 -16
- package/hooks/gsd-statusline.js +15 -7
- package/hooks/gsd-update-banner.js +8 -0
- 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 +21 -4
- package/scripts/changeset/parse.cjs +52 -4
- package/scripts/ci-timeout-report.cjs +770 -4
- package/scripts/command-contract-helpers.cjs +12 -8
- package/scripts/docs-guard-registry.cjs +6 -0
- package/scripts/gen-features.cjs +13 -8
- package/scripts/gen-hooks-cli-exit.cjs +12 -28
- package/scripts/gen-loop-host-contract.cjs +10 -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 +20 -2
- package/scripts/lib/ndjson-reporter.cjs +28 -3
- package/scripts/lib/platform-conformance-tier.generated.cjs +34 -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 +10 -0
- 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-enumeration-drift.cjs +12 -8
- package/scripts/lint-phase-id-drift.cjs +29 -0
- package/scripts/lint-planning-document-positive-control.cjs +329 -0
- package/scripts/lint-response-language-coverage.cjs +3 -0
- package/scripts/lint-skill-deps.cjs +7 -3
- package/scripts/lint-test-file-count.allowlist.json +11 -1
- package/scripts/lint-test-file-count.cjs +34 -1
- package/scripts/lint-vendored-deps.cjs +41 -5
- package/scripts/lint-workflow-shellcheck-baseline.json +10 -10
- package/scripts/mutation-matrix.cjs +50 -5
- 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 +5 -0
- package/skills/gsd-capture/SKILL.md +8 -4
- 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 +5 -1
- 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 +5 -1
- package/skills/gsd-pr-branch/SKILL.md +4 -0
- package/skills/gsd-profile-user/SKILL.md +5 -1
- package/skills/gsd-progress/SKILL.md +6 -1
- package/skills/gsd-quick/SKILL.md +16 -10
- package/skills/gsd-quick-batch/SKILL.md +20 -8
- package/skills/gsd-review/SKILL.md +5 -1
- 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
- package/gsd-core/workflows/execute-phase/steps/stale-reverification.md +0 -24
|
@@ -55,24 +55,24 @@ const { planningDir } = planningWorkspaceMod;
|
|
|
55
55
|
// <install>/gsd-core/bin/lib). Precedence for the gate: project config.runtime →
|
|
56
56
|
// GSD_RUNTIME env (manual/CI override + test seam) → install marker → 'claude'.
|
|
57
57
|
//
|
|
58
|
-
//
|
|
59
|
-
//
|
|
60
|
-
//
|
|
61
|
-
|
|
58
|
+
// Whether a runtime resolves tier aliases natively is a runtime-descriptor fact
|
|
59
|
+
// (`hostBehaviors.nativeModelAliases`, #5169) — `claude` is currently the ONLY
|
|
60
|
+
// runtime that declares it — not a hand-kept set in this module. A label that is
|
|
61
|
+
// not a registered runtime (a future runtime named by env/config) has none.
|
|
62
|
+
function hasNativeModelAliases(runtime) {
|
|
63
|
+
return (0, runtime_name_policy_cjs_1.hostBehaviorsFor)(runtime).nativeModelAliases === true;
|
|
64
|
+
}
|
|
62
65
|
// #3897 rung 2: the marker reader + its cache and test seams were promoted to
|
|
63
66
|
// the canonical owner, `runtime-slash.cts` (imported above) — this module now
|
|
64
67
|
// consumes that single implementation instead of holding its own copy. N5:
|
|
65
68
|
// behaviour and the seam contract are unchanged by the move; the re-exports
|
|
66
69
|
// below (`export =` at the bottom of this file) preserve every existing
|
|
67
70
|
// caller's `require('./model-resolver.cjs')` surface byte-for-behaviour.
|
|
68
|
-
// The runtime whose install is actually resolving
|
|
69
|
-
//
|
|
70
|
-
//
|
|
71
|
-
//
|
|
72
|
-
//
|
|
73
|
-
function resolveActiveRuntime(config) {
|
|
74
|
-
return (0, runtime_name_policy_cjs_1.resolveRuntimeNameFromCandidates)(process.env['GSD_RUNTIME'], config['runtime'], (0, runtime_slash_cjs_1.readInstallRuntimeMarker)()) || 'claude';
|
|
75
|
-
}
|
|
71
|
+
// The runtime whose install is actually resolving — one chain, owned by
|
|
72
|
+
// runtime-slash.cts's `resolveActiveRuntime` (#5169): GSD_RUNTIME env → project
|
|
73
|
+
// config.runtime → per-install .gsd-runtime marker → 'claude', canonicalized so
|
|
74
|
+
// an alias or case variant (e.g. "claude-code"/"Claude") cannot defeat the
|
|
75
|
+
// native-alias check below (#2297 review).
|
|
76
76
|
// Did the PROJECT's own config (root `.planning/config.json` or the active
|
|
77
77
|
// workstream/project override) explicitly set resolve_model_ids to "omit"?
|
|
78
78
|
// Project config takes precedence over the shared ~/.gsd/defaults.json (#2297
|
|
@@ -129,7 +129,7 @@ function _resolveRuntimeTier(config, tier) {
|
|
|
129
129
|
// the per-install marker), and reading it raw made
|
|
130
130
|
// `model_profile_overrides.<runtime>.<tier>` silently inert for every
|
|
131
131
|
// install that did not also write the key by hand.
|
|
132
|
-
runtime: resolveActiveRuntime(config),
|
|
132
|
+
runtime: (0, runtime_slash_cjs_1.resolveActiveRuntime)(config),
|
|
133
133
|
tier,
|
|
134
134
|
overrides: config['model_profile_overrides'],
|
|
135
135
|
});
|
|
@@ -502,7 +502,7 @@ function resolveModelInternal(cwd, agentType) {
|
|
|
502
502
|
? modelOverrides[agentType]
|
|
503
503
|
: undefined;
|
|
504
504
|
if (override) {
|
|
505
|
-
const mapped = mapClaudeOverrideForRuntime(override, resolveActiveRuntime(config), agentType);
|
|
505
|
+
const mapped = mapClaudeOverrideForRuntime(override, (0, runtime_slash_cjs_1.resolveActiveRuntime)(config), agentType);
|
|
506
506
|
if (mapped !== null)
|
|
507
507
|
return mapped;
|
|
508
508
|
// Unmappable Claude ID — fall through to tier resolution (matches model_policy).
|
|
@@ -528,7 +528,7 @@ function resolveModelInternal(cwd, agentType) {
|
|
|
528
528
|
// Never undefined, so the "no runtime declared anywhere" case still resolves
|
|
529
529
|
// 'claude' and step 3's deliberate claude skip (#1156/#2297/#4192) is
|
|
530
530
|
// unchanged for every existing install.
|
|
531
|
-
const activeRuntime = resolveActiveRuntime(config);
|
|
531
|
+
const activeRuntime = (0, runtime_slash_cjs_1.resolveActiveRuntime)(config);
|
|
532
532
|
if (tier && tier !== 'inherit') {
|
|
533
533
|
const onClaude = activeRuntime === 'claude';
|
|
534
534
|
const effectiveRuntime = activeRuntime;
|
|
@@ -582,7 +582,7 @@ function resolveModelInternal(cwd, agentType) {
|
|
|
582
582
|
// map, but only outranks the omit gate when that key canonicalizes to a
|
|
583
583
|
// recognised non-Claude runtime.
|
|
584
584
|
const omitApplies = config['resolve_model_ids'] === 'omit'
|
|
585
|
-
&& (projectExplicitlySetsOmit(cwd) || !
|
|
585
|
+
&& (projectExplicitlySetsOmit(cwd) || !hasNativeModelAliases(activeRuntime));
|
|
586
586
|
// CANONICALIZED, not the raw field. Comparing the raw value against the literal
|
|
587
587
|
// 'claude' made every spelling that is not exactly that string count as a
|
|
588
588
|
// non-Claude opt-in and outrank the omit gate: `runtime:"Claude"`,
|
|
@@ -764,13 +764,13 @@ function resolveModelForTier(cwd, agentType, attempt) {
|
|
|
764
764
|
? modelOverrides[agentType]
|
|
765
765
|
: undefined;
|
|
766
766
|
if (override) {
|
|
767
|
-
const mapped = mapClaudeOverrideForRuntime(override, resolveActiveRuntime(config), agentType);
|
|
767
|
+
const mapped = mapClaudeOverrideForRuntime(override, (0, runtime_slash_cjs_1.resolveActiveRuntime)(config), agentType);
|
|
768
768
|
if (mapped !== null)
|
|
769
769
|
return mapped;
|
|
770
770
|
// Unmappable Claude ID — fall through to dynamic_routing / model_policy resolution.
|
|
771
771
|
}
|
|
772
772
|
// #4505: same active-runtime rule as resolveModelInternal step 3.
|
|
773
|
-
if (config['model_policy'] && resolveActiveRuntime(config) !== 'claude') {
|
|
773
|
+
if (config['model_policy'] && (0, runtime_slash_cjs_1.resolveActiveRuntime)(config) !== 'claude') {
|
|
774
774
|
return resolveModelInternal(cwd, agentType);
|
|
775
775
|
}
|
|
776
776
|
const alias = dynamicRoutingModel(config, agentType, attemptN);
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
* (RFC 4122); invalid values are silently coerced to undefined.
|
|
17
17
|
* command: string — the dispatched verb
|
|
18
18
|
* args?: unknown — only present when includeArgs === true
|
|
19
|
-
* result: { kind: 'ok' | 'UnknownCommand' | 'InvalidArgs' | 'HandlerRefusal' | 'HandlerFailure', ...payload }
|
|
19
|
+
* result: { kind: 'ok' | 'UnknownCommand' | 'InvalidArgs' | 'HandlerRefusal' | 'HandlerFailure' | 'VerificationStatusInvalid', ...payload }
|
|
20
20
|
* timestamp: string — ISO 8601
|
|
21
21
|
*/
|
|
22
22
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
@@ -16,6 +16,11 @@
|
|
|
16
16
|
* No-op logger (createNoOpLogger):
|
|
17
17
|
* Silent on all events. Used as the Hub default when no logger is injected.
|
|
18
18
|
*
|
|
19
|
+
* Live-seam gate (resolveDispatchLogger, #4975):
|
|
20
|
+
* The one opt-in decision both live createHub() seams share. Resolves
|
|
21
|
+
* `audit.enabled` for the seam's cwd and returns the default logger, or
|
|
22
|
+
* undefined (inject nothing) when observability is off.
|
|
23
|
+
*
|
|
19
24
|
* ADR-457 build-at-publish: the hand-written bin/lib/observability/logger.cjs
|
|
20
25
|
* collapsed to a TypeScript source of truth. Behaviour is preserved
|
|
21
26
|
* byte-for-behaviour from the prior hand-written .cjs; only types are added.
|
|
@@ -26,6 +31,9 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
26
31
|
const node_fs_1 = __importDefault(require("node:fs"));
|
|
27
32
|
const node_path_1 = __importDefault(require("node:path"));
|
|
28
33
|
const redaction_cjs_1 = require("./redaction.cjs");
|
|
34
|
+
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
35
|
+
const planningWorkspace = require("../planning-workspace.cjs");
|
|
36
|
+
const { readScopedConfigValue } = planningWorkspace;
|
|
29
37
|
const AUDIT_FILE_NAME = '.gsd-trace.jsonl';
|
|
30
38
|
const PLANNING_DIR = '.planning';
|
|
31
39
|
// ─── helpers ─────────────────────────────────────────────────────────────────
|
|
@@ -47,6 +55,8 @@ function _safeStringify(value) {
|
|
|
47
55
|
* inject nothing (the Hub stays byte-for-byte silent, preserving the default
|
|
48
56
|
* dispatch output contract, incl. --json-errors); when on, the caller injects
|
|
49
57
|
* createDefaultLogger and gets the stderr-on-error line + opt-in file audit.
|
|
58
|
+
* The live seams reach it through resolveDispatchLogger, which supplies the
|
|
59
|
+
* project config — called bare, only the env var is seen (#4975).
|
|
50
60
|
*/
|
|
51
61
|
function _isAuditEnabled(config) {
|
|
52
62
|
if (process.env['GSD_AUDIT'] === '1')
|
|
@@ -148,4 +158,39 @@ function createDefaultLogger({ cwd = process.cwd(), config } = {}) {
|
|
|
148
158
|
},
|
|
149
159
|
};
|
|
150
160
|
}
|
|
151
|
-
|
|
161
|
+
/**
|
|
162
|
+
* Resolve `audit.enabled` for `cwd` as the value `config-get audit.enabled`
|
|
163
|
+
* reports, through planning-workspace's readScopedConfigValue — the one
|
|
164
|
+
* scope-aware ladder worktreesOptedOut (#3972) reads too, so the two gates
|
|
165
|
+
* can never resolve the same config differently. Strict `=== true`, never
|
|
166
|
+
* coerced.
|
|
167
|
+
*
|
|
168
|
+
* Direct file reads, deliberately NOT loadConfig: this runs on every live
|
|
169
|
+
* dispatch, and loadConfig can rewrite config.json, spawn git, scan the
|
|
170
|
+
* capability registry, and print warnings — none of which a dispatch that
|
|
171
|
+
* never opted in may do (the default dispatch output is a stable contract,
|
|
172
|
+
* ADR-2619). Never throws. An unreadable or unparseable config file sets
|
|
173
|
+
* nothing, so the ladder moves on: under GSD_WORKSTREAM a broken workstream
|
|
174
|
+
* config inherits the root's `audit.enabled` (where config-get fails with
|
|
175
|
+
* CONFIG_PARSE_FAILED); otherwise the GSD_AUDIT env var alone decides.
|
|
176
|
+
*/
|
|
177
|
+
function _readAuditConfig(cwd) {
|
|
178
|
+
const { present, value } = readScopedConfigValue(cwd, ['audit', 'enabled']);
|
|
179
|
+
return { audit: { enabled: present && value === true } };
|
|
180
|
+
}
|
|
181
|
+
/**
|
|
182
|
+
* The DispatchLogger a live createHub() seam injects (#4975). Either
|
|
183
|
+
* GSD_AUDIT=1 or `audit.enabled: true` in the project config turns the opt-in
|
|
184
|
+
* audit trail (and the structured stderr line on error) on; neither turns the
|
|
185
|
+
* other off. When observability is off this returns undefined so the Hub keeps
|
|
186
|
+
* its no-op fallback and the default dispatch output — including the
|
|
187
|
+
* --json-errors envelope — stays byte-for-byte unchanged (#2620).
|
|
188
|
+
*
|
|
189
|
+
* `cwd` defaults exactly as createDefaultLogger's does, so the config that
|
|
190
|
+
* decides and the directory that receives the trail are always the same.
|
|
191
|
+
*/
|
|
192
|
+
function resolveDispatchLogger(cwd = process.cwd()) {
|
|
193
|
+
const config = _readAuditConfig(cwd);
|
|
194
|
+
return _isAuditEnabled(config) ? createDefaultLogger({ cwd, config }) : undefined;
|
|
195
|
+
}
|
|
196
|
+
module.exports = { createDefaultLogger, createNoOpLogger, isAuditEnabled: _isAuditEnabled, resolveDispatchLogger };
|
|
@@ -44,6 +44,7 @@
|
|
|
44
44
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
45
45
|
exports.MAX_USER_PATTERN_LEN = void 0;
|
|
46
46
|
exports.escapeRegex = escapeRegex;
|
|
47
|
+
exports.escapeEre = escapeEre;
|
|
47
48
|
exports.literalPattern = literalPattern;
|
|
48
49
|
exports.compileUserPattern = compileUserPattern;
|
|
49
50
|
// re2js is vendored, not an npm dependency at runtime: gsd-core/bin/** is
|
|
@@ -66,6 +67,15 @@ const escapeMetachars = (value) => value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
|
66
67
|
function escapeRegex(value) {
|
|
67
68
|
return (escapeBuiltin ?? escapeMetachars)(value);
|
|
68
69
|
}
|
|
70
|
+
/**
|
|
71
|
+
* Escape `value` for a POSIX extended regular expression (e.g. `git log --extended-regexp
|
|
72
|
+
* --grep=…`). Always the plain backslash-escape of every ERE metacharacter, never
|
|
73
|
+
* `RegExp.escape`: that built-in writes a leading digit as `\x31`, which ERE does not read as a
|
|
74
|
+
* digit. #5139 (a plan id interpolated into a git `--grep` pattern).
|
|
75
|
+
*/
|
|
76
|
+
function escapeEre(value) {
|
|
77
|
+
return escapeMetachars(value);
|
|
78
|
+
}
|
|
69
79
|
function literalPattern(value, flags) {
|
|
70
80
|
return new RegExp(escapeRegex(value), flags);
|
|
71
81
|
}
|
|
@@ -22,10 +22,12 @@ const commandRoutingHub = require("./command-routing-hub.cjs");
|
|
|
22
22
|
const { createHub, ERROR_KINDS, makeInvalidArgs } = commandRoutingHub;
|
|
23
23
|
// #2620 (ADR-0174 §6): inject the reference DispatchLogger on the live phase
|
|
24
24
|
// dispatch path, but only when observability is opt-in enabled; otherwise the
|
|
25
|
-
// Hub stays byte-for-byte silent via its no-op fallback.
|
|
25
|
+
// Hub stays byte-for-byte silent via its no-op fallback. #4975: the opt-in is
|
|
26
|
+
// GSD_AUDIT=1 or `audit.enabled` in the project config — resolveDispatchLogger
|
|
27
|
+
// owns that whole decision for every live seam.
|
|
26
28
|
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
27
29
|
const observabilityLogger = require("./observability/logger.cjs");
|
|
28
|
-
const {
|
|
30
|
+
const { resolveDispatchLogger } = observabilityLogger;
|
|
29
31
|
// ─── Implementation ───────────────────────────────────────────────────────────
|
|
30
32
|
function routePhaseCommand({ phase, args, cwd, raw, error }) {
|
|
31
33
|
// ── Unsupported subcommands ─────────────────────────────────────────────────
|
|
@@ -258,8 +260,8 @@ function routePhaseCommand({ phase, args, cwd, raw, error }) {
|
|
|
258
260
|
// #175: Hub is CJS-only — no mode param, no sdkLoader.
|
|
259
261
|
// #2620: wire the reference logger (ADR-0174 §6) only when observability is
|
|
260
262
|
// opt-in enabled; otherwise leave it unset so the Hub stays byte-for-byte
|
|
261
|
-
// silent via its no-op fallback.
|
|
262
|
-
const hub = createHub({ cjsRegistry, manifest, logger:
|
|
263
|
+
// silent via its no-op fallback. #4975: GSD_AUDIT=1 or `audit.enabled`.
|
|
264
|
+
const hub = createHub({ cjsRegistry, manifest, logger: resolveDispatchLogger(cwd) });
|
|
263
265
|
// ── Dispatch ────────────────────────────────────────────────────────────────
|
|
264
266
|
const result = hub.dispatch({
|
|
265
267
|
family: 'phase',
|
|
@@ -282,6 +284,11 @@ function routePhaseCommand({ phase, args, cwd, raw, error }) {
|
|
|
282
284
|
error(result.reason);
|
|
283
285
|
return;
|
|
284
286
|
}
|
|
287
|
+
if (result.kind === ERROR_KINDS.VerificationStatusInvalid) {
|
|
288
|
+
// #5118: typed reason survives to the CLI surface
|
|
289
|
+
error(result.message, result.reason);
|
|
290
|
+
return;
|
|
291
|
+
}
|
|
285
292
|
// HandlerFailure: message field
|
|
286
293
|
error(result.message);
|
|
287
294
|
return;
|
|
@@ -47,6 +47,7 @@ exports.parseCalibrationDocument = parseCalibrationDocument;
|
|
|
47
47
|
exports.renderCalibrationDocument = renderCalibrationDocument;
|
|
48
48
|
// eslint-disable-next-line @typescript-eslint/no-require-imports -- prompt-budget.cjs is an export= CommonJS module
|
|
49
49
|
const promptBudget = require("./prompt-budget.cjs");
|
|
50
|
+
const frontmatter_fence_cjs_1 = require("./frontmatter-fence.cjs");
|
|
50
51
|
const { estimateTokens } = promptBudget;
|
|
51
52
|
/**
|
|
52
53
|
* Assert that a bare number is an UNCORRECTED projection.
|
|
@@ -239,11 +240,11 @@ function applyCalibration(rawTokens, factor) {
|
|
|
239
240
|
function extractFrontmatterBlock(text, key) {
|
|
240
241
|
if (typeof text !== 'string')
|
|
241
242
|
return null;
|
|
242
|
-
//
|
|
243
|
-
const
|
|
244
|
-
if (
|
|
243
|
+
// The block is the one the one fence owner finds (`locateFrontmatterFence`).
|
|
244
|
+
const fence = (0, frontmatter_fence_cjs_1.locateFrontmatterFence)(text);
|
|
245
|
+
if (!fence?.closed)
|
|
245
246
|
return null;
|
|
246
|
-
const lines =
|
|
247
|
+
const lines = text.slice(fence.openEnd, fence.bodyEnd).split(/\r?\n/);
|
|
247
248
|
const startIdx = lines.findIndex((l) => l === `${key}:` || l.startsWith(`${key}:`));
|
|
248
249
|
if (startIdx === -1)
|
|
249
250
|
return null;
|
|
@@ -1342,7 +1342,7 @@ const unpad = (digits) => digits.replace(/^0+(?=\d)/, '');
|
|
|
1342
1342
|
* candidates (#2237).
|
|
1343
1343
|
*
|
|
1344
1344
|
* TAKE `matches[0]` — `cmdPhasesList`, `cmdInitManager`, `cmdRoadmapAnalyze`,
|
|
1345
|
-
* `
|
|
1345
|
+
* the schema-drift gate (`resolvePhaseDirByToken`), `detectVerifyFailed`. Each read a directory to
|
|
1346
1346
|
* DECORATE a row they are already emitting; each used `.find()` before this
|
|
1347
1347
|
* PR, so first-match is their prior behavior preserved verbatim, and each is
|
|
1348
1348
|
* order-stable because the directory list is sorted and this function filters
|
|
@@ -31,6 +31,9 @@ const markdown_table_cjs_1 = require("./markdown-table.cjs");
|
|
|
31
31
|
// eslint-disable-next-line @typescript-eslint/no-require-imports -- phase-id.cjs is an export= CommonJS module
|
|
32
32
|
const phaseIdMod = require("./phase-id.cjs");
|
|
33
33
|
const { isSentinelPhaseId } = phaseIdMod;
|
|
34
|
+
// #5060: `phase-status.cjs` is a load-time leaf (no top-level requires), safe
|
|
35
|
+
// to import here for the ROADMAP Status-cell reader.
|
|
36
|
+
const phase_status_cjs_1 = require("./phase-status.cjs");
|
|
34
37
|
/**
|
|
35
38
|
* #3227: the single owner of "where is this ROADMAP's Progress table".
|
|
36
39
|
* Lifted verbatim out of deriveProgressFromRoadmap so `state-contract.cts`
|
|
@@ -93,8 +96,6 @@ function deriveProgressFromRoadmap(roadmapContent) {
|
|
|
93
96
|
const table = locateProgressTable(roadmapContent);
|
|
94
97
|
if (table) {
|
|
95
98
|
const allRows = table.rows;
|
|
96
|
-
const completed = allRows.filter((r) => /^complete$/i.test((r['Status'] ?? '').trim())).length;
|
|
97
|
-
completedPhases = completed > 0 ? completed : null;
|
|
98
99
|
// Data rows only (exclude sentinel phases 0 and 999.x).
|
|
99
100
|
// #3185: canonical sentinel predicate (SENTINEL_RANGES [0,999]) — this was a local 999-only literal that admitted Phase 0.
|
|
100
101
|
const dataRows = allRows.filter((r) => {
|
|
@@ -102,6 +103,12 @@ function deriveProgressFromRoadmap(roadmapContent) {
|
|
|
102
103
|
return /^\d/.test(phase) && !isSentinelPhaseId(phase);
|
|
103
104
|
});
|
|
104
105
|
totalPhases = dataRows.length > 0 ? dataRows.length : null;
|
|
106
|
+
// #5060: routed through the Phase Status Module's `parseRoadmapStatusCell`
|
|
107
|
+
// owner (rather than a local `/^complete$/i` regex) and counted over
|
|
108
|
+
// `dataRows` (not `allRows`) — a sentinel row's Status cell must never
|
|
109
|
+
// contribute to `completedPhases`.
|
|
110
|
+
const completed = dataRows.filter((r) => (0, phase_status_cjs_1.parseRoadmapStatusCell)(r['Status']) === phase_status_cjs_1.WIRE_STATUS.COMPLETE).length;
|
|
111
|
+
completedPhases = completed > 0 ? completed : null;
|
|
105
112
|
let totalPlansSum = 0;
|
|
106
113
|
for (const r of allRows) {
|
|
107
114
|
const cell = (r['Plans Complete'] ?? '').trim();
|
|
@@ -0,0 +1,360 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Phase Status Module — the single owner of "what state is phase P in?"
|
|
4
|
+
* (ADR-5057 §1/§2, epic #5056 Phase 1, #5060).
|
|
5
|
+
*
|
|
6
|
+
* ADR-3180 §7.4 made `isPhaseComplete` the owner of "is phase P complete?".
|
|
7
|
+
* The richer question the UI, the health rules and the ROADMAP writers ask —
|
|
8
|
+
* which rung of the lifecycle is this phase on — had no owner: it was derived
|
|
9
|
+
* at eleven sites in seven vocabularies, and two of them disagreed on a stale
|
|
10
|
+
* `passed` report. This module is that owner.
|
|
11
|
+
*
|
|
12
|
+
* - `PHASE_STATUS` is a closed, frozen ladder. Its values are the upper-case
|
|
13
|
+
* rung names, spelled unlike every projection word, so a display label or
|
|
14
|
+
* a wire value can never pass for a status.
|
|
15
|
+
* - `phaseStatusFromFacts` is the ladder itself — pure. Callers that already
|
|
16
|
+
* hold the §7 owners' answers (the health rules over `PlanningSnapshot`,
|
|
17
|
+
* the pure Workstream Inventory builder, `update-plan-progress`'s stricter
|
|
18
|
+
* write gate) hand it those facts.
|
|
19
|
+
* - `phaseStatus(phaseDir)` gathers the facts from the §7 owners only —
|
|
20
|
+
* `scanPhasePlans` (§7.5) for counts and `isPhaseComplete` (§7.4) for
|
|
21
|
+
* completion and the verification verdict. It never reads VERIFICATION.md
|
|
22
|
+
* frontmatter itself.
|
|
23
|
+
* - Every other vocabulary is a projection exported here: display labels,
|
|
24
|
+
* the `state.json` / Workstream Inventory wire values, the ROADMAP
|
|
25
|
+
* `## Progress` Status cell (both directions), `roadmap analyze` /
|
|
26
|
+
* `init manager`'s `disk_status`, `init`'s `completion_status`, and
|
|
27
|
+
* `init progress`'s `status`. A consumer never maps raw inputs to a word.
|
|
28
|
+
* - Every function that takes a `PhaseStatus` throws `TypeError` on a value
|
|
29
|
+
* outside the ladder, so an out-of-vocabulary value fails where it is
|
|
30
|
+
* produced (ADR-5057 §1.2).
|
|
31
|
+
*
|
|
32
|
+
* LOAD-TIME LEAF. `verification.cjs` and `plan-scan.cjs` are required lazily
|
|
33
|
+
* inside `phaseStatus()`. `state-contract.cjs` imports this module at top
|
|
34
|
+
* level for its wire vocabulary, and `state-contract` sits on the documented
|
|
35
|
+
* `state -> state-contract -> smart-entry -> state` require cycle; keeping this
|
|
36
|
+
* module import-free at load keeps it off that cycle.
|
|
37
|
+
*
|
|
38
|
+
* ADR-457 build-at-publish: source in src/phase-status.cts, compiled to
|
|
39
|
+
* gsd-core/bin/lib/phase-status.cjs (gitignored).
|
|
40
|
+
*/
|
|
41
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
42
|
+
exports.COMPLETION_STATUS = exports.PROGRESS_STATUS = exports.DISK_STATUS = exports.ROADMAP_STATUS_TOKEN = exports.WIRE_STATUS = exports.PHASE_STATUS = void 0;
|
|
43
|
+
exports.phaseStatusFromFacts = phaseStatusFromFacts;
|
|
44
|
+
exports.phaseStatus = phaseStatus;
|
|
45
|
+
exports.foldPhaseStatuses = foldPhaseStatuses;
|
|
46
|
+
exports.toDisplayLabel = toDisplayLabel;
|
|
47
|
+
exports.toWireStatus = toWireStatus;
|
|
48
|
+
exports.toRoadmapStatusCell = toRoadmapStatusCell;
|
|
49
|
+
exports.toDiskStatus = toDiskStatus;
|
|
50
|
+
exports.toCompletionStatus = toCompletionStatus;
|
|
51
|
+
exports.toProgressStatus = toProgressStatus;
|
|
52
|
+
exports.matchRoadmapStatusCell = matchRoadmapStatusCell;
|
|
53
|
+
exports.parseRoadmapStatusCell = parseRoadmapStatusCell;
|
|
54
|
+
// ─── Closed vocabularies ───────────────────────────────────────────────────
|
|
55
|
+
/** The lifecycle ladder, lowest rung first. */
|
|
56
|
+
exports.PHASE_STATUS = Object.freeze({
|
|
57
|
+
NOT_STARTED: 'NOT_STARTED',
|
|
58
|
+
PLANNED: 'PLANNED',
|
|
59
|
+
IN_PROGRESS: 'IN_PROGRESS',
|
|
60
|
+
EXECUTED: 'EXECUTED',
|
|
61
|
+
NEEDS_REVIEW: 'NEEDS_REVIEW',
|
|
62
|
+
COMPLETE: 'COMPLETE',
|
|
63
|
+
});
|
|
64
|
+
/**
|
|
65
|
+
* The three-value wire vocabulary published by `.planning/state.json`
|
|
66
|
+
* (`phases[].status`) and the Workstream Inventory (`PhaseStatus.status`).
|
|
67
|
+
*/
|
|
68
|
+
exports.WIRE_STATUS = Object.freeze({
|
|
69
|
+
COMPLETE: 'complete',
|
|
70
|
+
IN_PROGRESS: 'in_progress',
|
|
71
|
+
PENDING: 'pending',
|
|
72
|
+
});
|
|
73
|
+
/**
|
|
74
|
+
* The ROADMAP `## Progress` table Status-cell vocabulary: the template's
|
|
75
|
+
* `Not started | In progress | Complete | Deferred` plus the `Planned` word
|
|
76
|
+
* `roadmap update-plan-progress` writes. `In Progress` is spelled the way the
|
|
77
|
+
* writers have always written it.
|
|
78
|
+
*/
|
|
79
|
+
exports.ROADMAP_STATUS_TOKEN = Object.freeze({
|
|
80
|
+
NOT_STARTED: 'Not started',
|
|
81
|
+
PLANNED: 'Planned',
|
|
82
|
+
IN_PROGRESS: 'In Progress',
|
|
83
|
+
COMPLETE: 'Complete',
|
|
84
|
+
DEFERRED: 'Deferred',
|
|
85
|
+
});
|
|
86
|
+
/** `roadmap analyze` / `init manager`'s `disk_status` vocabulary (ADR-5057 §1.2). */
|
|
87
|
+
exports.DISK_STATUS = Object.freeze({
|
|
88
|
+
COMPLETE: 'complete',
|
|
89
|
+
EXECUTED: 'executed',
|
|
90
|
+
PARTIAL: 'partial',
|
|
91
|
+
PLANNED: 'planned',
|
|
92
|
+
RESEARCHED: 'researched',
|
|
93
|
+
DISCUSSED: 'discussed',
|
|
94
|
+
EMPTY: 'empty',
|
|
95
|
+
NO_DIRECTORY: 'no_directory',
|
|
96
|
+
});
|
|
97
|
+
/** `init progress`'s per-phase `status` vocabulary (ADR-5057 §1.2). */
|
|
98
|
+
exports.PROGRESS_STATUS = Object.freeze({
|
|
99
|
+
COMPLETE: 'complete',
|
|
100
|
+
EXECUTED: 'executed',
|
|
101
|
+
IN_PROGRESS: 'in_progress',
|
|
102
|
+
RESEARCHED: 'researched',
|
|
103
|
+
PENDING: 'pending',
|
|
104
|
+
NOT_STARTED: 'not_started',
|
|
105
|
+
});
|
|
106
|
+
/** `init`'s `completion_status` vocabulary (ADR-5057 §1.2). */
|
|
107
|
+
exports.COMPLETION_STATUS = Object.freeze({
|
|
108
|
+
COMPLETE: 'complete',
|
|
109
|
+
EXECUTED: 'executed',
|
|
110
|
+
INCOMPLETE: 'incomplete',
|
|
111
|
+
});
|
|
112
|
+
const LADDER = Object.freeze([
|
|
113
|
+
exports.PHASE_STATUS.NOT_STARTED,
|
|
114
|
+
exports.PHASE_STATUS.PLANNED,
|
|
115
|
+
exports.PHASE_STATUS.IN_PROGRESS,
|
|
116
|
+
exports.PHASE_STATUS.EXECUTED,
|
|
117
|
+
exports.PHASE_STATUS.NEEDS_REVIEW,
|
|
118
|
+
exports.PHASE_STATUS.COMPLETE,
|
|
119
|
+
]);
|
|
120
|
+
const LADDER_RANK = new Map(LADDER.map((s, i) => [s, i]));
|
|
121
|
+
function assertPhaseStatus(value, where) {
|
|
122
|
+
if (typeof value !== 'string' || !LADDER_RANK.has(value)) {
|
|
123
|
+
throw new TypeError(`${where}: ${JSON.stringify(value)} is not a PHASE_STATUS value`);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
function assertCount(value, name) {
|
|
127
|
+
if (typeof value !== 'number' || !Number.isInteger(value) || value < 0) {
|
|
128
|
+
throw new TypeError(`phaseStatusFromFacts: ${name} must be a non-negative integer, got ${JSON.stringify(value)}`);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* The ladder. First matching rung wins:
|
|
133
|
+
* complete → COMPLETE (disk-strict: no plan precondition, #3168)
|
|
134
|
+
* no plans → NOT_STARTED
|
|
135
|
+
* no summaries → PLANNED
|
|
136
|
+
* fewer summaries than plans → IN_PROGRESS
|
|
137
|
+
* verification `human_needed` → NEEDS_REVIEW
|
|
138
|
+
* otherwise → EXECUTED (gaps_found, stale, missing, unparseable, phase_dir_not_found)
|
|
139
|
+
*
|
|
140
|
+
* `verificationStatus`, when non-null, must be a VerificationStatus member
|
|
141
|
+
* (#5118) — the same fail-where-produced rule as `assertPhaseStatus`.
|
|
142
|
+
*
|
|
143
|
+
* Completion comes ONLY from `complete`. The ladder never restates a
|
|
144
|
+
* summary-versus-plan completion comparison (scripts/lint-completion-predicate-drift.cjs shape (c)).
|
|
145
|
+
*/
|
|
146
|
+
function phaseStatusFromFacts(facts) {
|
|
147
|
+
if (facts === null || typeof facts !== 'object') {
|
|
148
|
+
throw new TypeError('phaseStatusFromFacts: facts object required');
|
|
149
|
+
}
|
|
150
|
+
const { planCount, summaryCount, complete, verificationStatus } = facts;
|
|
151
|
+
assertCount(planCount, 'planCount');
|
|
152
|
+
assertCount(summaryCount, 'summaryCount');
|
|
153
|
+
if (typeof complete !== 'boolean') {
|
|
154
|
+
throw new TypeError(`phaseStatusFromFacts: complete must be a boolean, got ${JSON.stringify(complete)}`);
|
|
155
|
+
}
|
|
156
|
+
const { verification } = owners();
|
|
157
|
+
if (verificationStatus !== null && verificationStatus !== undefined) {
|
|
158
|
+
// Called through a plain function type: a lazily-required owner's
|
|
159
|
+
// assertion signature cannot narrow here (TS2775), and needs not to.
|
|
160
|
+
const assertMember = verification.assertVerificationStatus;
|
|
161
|
+
assertMember(verificationStatus, 'phaseStatusFromFacts: verificationStatus');
|
|
162
|
+
}
|
|
163
|
+
if (complete)
|
|
164
|
+
return exports.PHASE_STATUS.COMPLETE;
|
|
165
|
+
if (planCount === 0)
|
|
166
|
+
return exports.PHASE_STATUS.NOT_STARTED;
|
|
167
|
+
if (summaryCount === 0)
|
|
168
|
+
return exports.PHASE_STATUS.PLANNED;
|
|
169
|
+
if (summaryCount < planCount)
|
|
170
|
+
return exports.PHASE_STATUS.IN_PROGRESS;
|
|
171
|
+
if (verificationStatus === verification.VERIFICATION_STATUS.HUMAN_NEEDED)
|
|
172
|
+
return exports.PHASE_STATUS.NEEDS_REVIEW;
|
|
173
|
+
return exports.PHASE_STATUS.EXECUTED;
|
|
174
|
+
}
|
|
175
|
+
const SCOPE_SEVERITY = Object.freeze({
|
|
176
|
+
complete: 0,
|
|
177
|
+
truncated: 1,
|
|
178
|
+
unscoped: 2,
|
|
179
|
+
unreadable: 3,
|
|
180
|
+
});
|
|
181
|
+
let _verification = null;
|
|
182
|
+
let _planScan = null;
|
|
183
|
+
function owners() {
|
|
184
|
+
/* eslint-disable @typescript-eslint/no-require-imports */
|
|
185
|
+
if (!_verification)
|
|
186
|
+
_verification = require('./verification.cjs');
|
|
187
|
+
if (!_planScan)
|
|
188
|
+
_planScan = require('./plan-scan.cjs');
|
|
189
|
+
/* eslint-enable @typescript-eslint/no-require-imports */
|
|
190
|
+
return { verification: _verification, planScan: _planScan };
|
|
191
|
+
}
|
|
192
|
+
/**
|
|
193
|
+
* What state is the phase in `phaseDir` in? Composes only ADR-3180's §7
|
|
194
|
+
* owners. `scope` is the worse of the plan scan's and the completion read's
|
|
195
|
+
* scopes, so a caller can tell "not started" from "could not look".
|
|
196
|
+
*/
|
|
197
|
+
function phaseStatus(phaseDir, deps = {}) {
|
|
198
|
+
const { verification, planScan } = owners();
|
|
199
|
+
const scan = planScan.scanPhasePlans(phaseDir);
|
|
200
|
+
const completion = verification.isPhaseComplete(phaseDir, {
|
|
201
|
+
convention: deps.convention,
|
|
202
|
+
fs: deps.fs,
|
|
203
|
+
phaseCleanCommitTimesMs: deps.phaseCleanCommitTimesMs,
|
|
204
|
+
});
|
|
205
|
+
const status = phaseStatusFromFacts({
|
|
206
|
+
planCount: scan.planCount,
|
|
207
|
+
summaryCount: scan.summaryCount,
|
|
208
|
+
complete: completion.value.complete,
|
|
209
|
+
verificationStatus: completion.value.verification.status,
|
|
210
|
+
});
|
|
211
|
+
const scope = (SCOPE_SEVERITY[completion.scope] ?? 0) > (SCOPE_SEVERITY[scan.scope] ?? 0)
|
|
212
|
+
? completion.scope
|
|
213
|
+
: scan.scope;
|
|
214
|
+
return {
|
|
215
|
+
value: {
|
|
216
|
+
status,
|
|
217
|
+
planCount: scan.planCount,
|
|
218
|
+
summaryCount: scan.summaryCount,
|
|
219
|
+
verification: completion.value.verification,
|
|
220
|
+
...(completion.value.statusError ? { statusError: completion.value.statusError } : {}),
|
|
221
|
+
},
|
|
222
|
+
scope,
|
|
223
|
+
};
|
|
224
|
+
}
|
|
225
|
+
// ─── Fold (#2408) ──────────────────────────────────────────────────────────
|
|
226
|
+
/**
|
|
227
|
+
* Fold two statuses for directories that collide on one phase key (#2408):
|
|
228
|
+
* the further-along rung wins. Commutative, idempotent and associative, so
|
|
229
|
+
* `readdirSync` order cannot change the answer.
|
|
230
|
+
*/
|
|
231
|
+
function foldPhaseStatuses(a, b) {
|
|
232
|
+
assertPhaseStatus(a, 'foldPhaseStatuses');
|
|
233
|
+
assertPhaseStatus(b, 'foldPhaseStatuses');
|
|
234
|
+
return LADDER_RANK.get(a) >= LADDER_RANK.get(b) ? a : b;
|
|
235
|
+
}
|
|
236
|
+
const DISPLAY_LABEL = Object.freeze({
|
|
237
|
+
[exports.PHASE_STATUS.NOT_STARTED]: 'Not Started',
|
|
238
|
+
[exports.PHASE_STATUS.PLANNED]: 'Planned',
|
|
239
|
+
[exports.PHASE_STATUS.IN_PROGRESS]: 'In Progress',
|
|
240
|
+
[exports.PHASE_STATUS.EXECUTED]: 'Executed',
|
|
241
|
+
[exports.PHASE_STATUS.NEEDS_REVIEW]: 'Needs Review',
|
|
242
|
+
[exports.PHASE_STATUS.COMPLETE]: 'Complete',
|
|
243
|
+
});
|
|
244
|
+
/**
|
|
245
|
+
* The label `progress`, `stats`, `init plan-phase` and `gsd-health` show. The
|
|
246
|
+
* NOT_STARTED word is the caller's display choice (`progress` and `init` say
|
|
247
|
+
* `Pending`, `stats` and the health rule say `Not Started`).
|
|
248
|
+
*/
|
|
249
|
+
function toDisplayLabel(status, opts = {}) {
|
|
250
|
+
assertPhaseStatus(status, 'toDisplayLabel');
|
|
251
|
+
const pendingWord = opts.pendingWord ?? 'Not Started';
|
|
252
|
+
if (pendingWord !== 'Pending' && pendingWord !== 'Not Started') {
|
|
253
|
+
throw new TypeError(`toDisplayLabel: pendingWord must be 'Pending' or 'Not Started', got ${JSON.stringify(pendingWord)}`);
|
|
254
|
+
}
|
|
255
|
+
return status === exports.PHASE_STATUS.NOT_STARTED ? pendingWord : DISPLAY_LABEL[status];
|
|
256
|
+
}
|
|
257
|
+
/** `pending` means nothing is planned yet; every rung between that and COMPLETE is `in_progress`. */
|
|
258
|
+
function toWireStatus(status) {
|
|
259
|
+
assertPhaseStatus(status, 'toWireStatus');
|
|
260
|
+
if (status === exports.PHASE_STATUS.COMPLETE)
|
|
261
|
+
return exports.WIRE_STATUS.COMPLETE;
|
|
262
|
+
if (status === exports.PHASE_STATUS.NOT_STARTED)
|
|
263
|
+
return exports.WIRE_STATUS.PENDING;
|
|
264
|
+
return exports.WIRE_STATUS.IN_PROGRESS;
|
|
265
|
+
}
|
|
266
|
+
/** The word a ROADMAP writer puts in the Status cell for this rung. */
|
|
267
|
+
function toRoadmapStatusCell(status) {
|
|
268
|
+
assertPhaseStatus(status, 'toRoadmapStatusCell');
|
|
269
|
+
switch (status) {
|
|
270
|
+
case exports.PHASE_STATUS.COMPLETE: return exports.ROADMAP_STATUS_TOKEN.COMPLETE;
|
|
271
|
+
case exports.PHASE_STATUS.PLANNED: return exports.ROADMAP_STATUS_TOKEN.PLANNED;
|
|
272
|
+
case exports.PHASE_STATUS.NOT_STARTED: return exports.ROADMAP_STATUS_TOKEN.NOT_STARTED;
|
|
273
|
+
default: return exports.ROADMAP_STATUS_TOKEN.IN_PROGRESS;
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
/**
|
|
277
|
+
* `roadmap analyze` / `init manager`'s `disk_status`. Below NOT_STARTED the
|
|
278
|
+
* word records which pre-planning artifacts exist. (`no_directory` is the
|
|
279
|
+
* callers' own word for "no directory matched" — there is no phase to ask.)
|
|
280
|
+
*/
|
|
281
|
+
function toDiskStatus(status, artifacts) {
|
|
282
|
+
assertPhaseStatus(status, 'toDiskStatus');
|
|
283
|
+
switch (status) {
|
|
284
|
+
case exports.PHASE_STATUS.COMPLETE: return exports.DISK_STATUS.COMPLETE;
|
|
285
|
+
case exports.PHASE_STATUS.NEEDS_REVIEW:
|
|
286
|
+
case exports.PHASE_STATUS.EXECUTED: return exports.DISK_STATUS.EXECUTED;
|
|
287
|
+
case exports.PHASE_STATUS.IN_PROGRESS: return exports.DISK_STATUS.PARTIAL;
|
|
288
|
+
case exports.PHASE_STATUS.PLANNED: return exports.DISK_STATUS.PLANNED;
|
|
289
|
+
default:
|
|
290
|
+
if (artifacts.hasResearch)
|
|
291
|
+
return exports.DISK_STATUS.RESEARCHED;
|
|
292
|
+
if (artifacts.hasContext)
|
|
293
|
+
return exports.DISK_STATUS.DISCUSSED;
|
|
294
|
+
return exports.DISK_STATUS.EMPTY;
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
/** `init`'s `completion_status`: complete / executed / incomplete. */
|
|
298
|
+
function toCompletionStatus(status) {
|
|
299
|
+
assertPhaseStatus(status, 'toCompletionStatus');
|
|
300
|
+
if (status === exports.PHASE_STATUS.COMPLETE)
|
|
301
|
+
return exports.COMPLETION_STATUS.COMPLETE;
|
|
302
|
+
if (status === exports.PHASE_STATUS.EXECUTED || status === exports.PHASE_STATUS.NEEDS_REVIEW)
|
|
303
|
+
return exports.COMPLETION_STATUS.EXECUTED;
|
|
304
|
+
return exports.COMPLETION_STATUS.INCOMPLETE;
|
|
305
|
+
}
|
|
306
|
+
/** `init progress`'s per-phase `status`. */
|
|
307
|
+
function toProgressStatus(status, artifacts) {
|
|
308
|
+
assertPhaseStatus(status, 'toProgressStatus');
|
|
309
|
+
switch (status) {
|
|
310
|
+
case exports.PHASE_STATUS.COMPLETE: return exports.PROGRESS_STATUS.COMPLETE;
|
|
311
|
+
case exports.PHASE_STATUS.NEEDS_REVIEW:
|
|
312
|
+
case exports.PHASE_STATUS.EXECUTED: return exports.PROGRESS_STATUS.EXECUTED;
|
|
313
|
+
case exports.PHASE_STATUS.IN_PROGRESS:
|
|
314
|
+
case exports.PHASE_STATUS.PLANNED: return exports.PROGRESS_STATUS.IN_PROGRESS;
|
|
315
|
+
default: return artifacts.hasResearch ? exports.PROGRESS_STATUS.RESEARCHED : exports.PROGRESS_STATUS.PENDING;
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
// ─── ROADMAP Status cell reader ────────────────────────────────────────────
|
|
319
|
+
// Leading token of a trimmed cell, case-insensitive, a whitespace run allowed
|
|
320
|
+
// inside the two-word tokens, and `(?!\w)` so `Completed` / `Planning` are not
|
|
321
|
+
// tokens. #4925 lets operator prose follow the token; that prose is ignored.
|
|
322
|
+
const CELL_TOKEN_RE = /^(not\s+started|planned|in\s+progress|complete|deferred)(?!\w)/i;
|
|
323
|
+
const TOKEN_BY_KEY = Object.freeze({
|
|
324
|
+
'not started': exports.ROADMAP_STATUS_TOKEN.NOT_STARTED,
|
|
325
|
+
planned: exports.ROADMAP_STATUS_TOKEN.PLANNED,
|
|
326
|
+
'in progress': exports.ROADMAP_STATUS_TOKEN.IN_PROGRESS,
|
|
327
|
+
complete: exports.ROADMAP_STATUS_TOKEN.COMPLETE,
|
|
328
|
+
deferred: exports.ROADMAP_STATUS_TOKEN.DEFERRED,
|
|
329
|
+
});
|
|
330
|
+
/**
|
|
331
|
+
* Read a Status cell's leading token. Returns the canonical token and the raw
|
|
332
|
+
* text it matched (writers compare `text` to decide whether a rewrite is a
|
|
333
|
+
* no-op), or null when the cell has no leading token. Never throws.
|
|
334
|
+
*/
|
|
335
|
+
function matchRoadmapStatusCell(cell) {
|
|
336
|
+
if (typeof cell !== 'string')
|
|
337
|
+
return null;
|
|
338
|
+
const m = CELL_TOKEN_RE.exec(cell.trim());
|
|
339
|
+
if (!m)
|
|
340
|
+
return null;
|
|
341
|
+
const key = m[1].toLowerCase().replace(/\s+/g, ' ');
|
|
342
|
+
return { token: TOKEN_BY_KEY[key], text: m[1] };
|
|
343
|
+
}
|
|
344
|
+
/**
|
|
345
|
+
* A Status cell as a wire value. `Deferred`, `Not started`, a cell with no
|
|
346
|
+
* leading token, and a non-string all read `pending` — an unrecognized cell
|
|
347
|
+
* never becomes a fourth wire value. Inverse of `toRoadmapStatusCell` under
|
|
348
|
+
* `toWireStatus` (ADR-5057 Phase 1 property).
|
|
349
|
+
*/
|
|
350
|
+
function parseRoadmapStatusCell(cell) {
|
|
351
|
+
const m = matchRoadmapStatusCell(cell);
|
|
352
|
+
if (m === null)
|
|
353
|
+
return exports.WIRE_STATUS.PENDING;
|
|
354
|
+
switch (m.token) {
|
|
355
|
+
case exports.ROADMAP_STATUS_TOKEN.COMPLETE: return exports.WIRE_STATUS.COMPLETE;
|
|
356
|
+
case exports.ROADMAP_STATUS_TOKEN.IN_PROGRESS:
|
|
357
|
+
case exports.ROADMAP_STATUS_TOKEN.PLANNED: return exports.WIRE_STATUS.IN_PROGRESS;
|
|
358
|
+
default: return exports.WIRE_STATUS.PENDING;
|
|
359
|
+
}
|
|
360
|
+
}
|