@opengsd/gsd-core 1.13.0 → 1.15.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/marketplace.json +1 -1
- package/.claude-plugin/plugin.json +1 -1
- package/README.ja-JP.md +3 -3
- package/README.ko-KR.md +3 -3
- package/README.pt-BR.md +3 -3
- package/README.zh-CN.md +3 -3
- package/agents/gsd-advisor-researcher.compact.md +85 -0
- package/agents/gsd-ai-researcher.compact.md +96 -0
- package/agents/gsd-assumptions-analyzer.compact.md +81 -0
- package/agents/gsd-code-fixer.compact.md +459 -0
- package/agents/gsd-code-fixer.md +9 -8
- package/agents/gsd-code-reviewer.compact.md +269 -0
- package/agents/gsd-code-reviewer.md +15 -3
- package/agents/gsd-codebase-mapper.compact.md +760 -0
- package/agents/gsd-debug-session-manager.compact.md +360 -0
- package/agents/gsd-debug-session-manager.md +17 -2
- package/agents/gsd-debugger.md +2 -2
- package/agents/gsd-doc-classifier.compact.md +192 -0
- package/agents/gsd-doc-synthesizer.compact.md +200 -0
- package/agents/gsd-doc-verifier.compact.md +143 -0
- package/agents/gsd-doc-writer.compact.md +440 -0
- package/agents/gsd-dom-verifier.compact.md +138 -0
- package/agents/gsd-domain-researcher.compact.md +141 -0
- package/agents/gsd-eval-auditor.compact.md +160 -0
- package/agents/gsd-eval-auditor.md +1 -1
- package/agents/gsd-eval-planner.compact.md +137 -0
- package/agents/gsd-executor.md +13 -8
- package/agents/gsd-framework-selector.compact.md +82 -0
- package/agents/gsd-integration-checker.compact.md +245 -0
- package/agents/gsd-intel-updater.compact.md +226 -0
- package/agents/gsd-intel-updater.md +1 -1
- package/agents/gsd-mempalace-curator.compact.md +45 -0
- package/agents/gsd-nyquist-auditor.compact.md +179 -0
- package/agents/gsd-pattern-mapper.compact.md +275 -0
- package/agents/gsd-phase-researcher.md +19 -11
- package/agents/gsd-plan-checker.md +8 -7
- package/agents/gsd-planner.md +12 -8
- package/agents/gsd-project-researcher.compact.md +587 -0
- package/agents/gsd-project-researcher.md +1 -1
- package/agents/gsd-research-synthesizer.compact.md +212 -0
- package/agents/gsd-research-synthesizer.md +1 -1
- package/agents/gsd-roadmapper.compact.md +454 -0
- package/agents/gsd-roadmapper.md +13 -0
- package/agents/gsd-security-auditor.compact.md +162 -0
- package/agents/gsd-ui-auditor.compact.md +404 -0
- package/agents/gsd-ui-auditor.md +155 -17
- package/agents/gsd-ui-checker.compact.md +277 -0
- package/agents/gsd-ui-researcher.compact.md +282 -0
- package/agents/gsd-ui-researcher.md +1 -1
- package/agents/gsd-user-profiler.compact.md +108 -0
- package/agents/gsd-verifier.md +10 -9
- package/bin/install.js +848 -163
- package/commands/gsd/autonomous.md +2 -2
- package/commands/gsd/capture.md +1 -1
- package/commands/gsd/cleanup.md +1 -0
- package/commands/gsd/code-review.md +2 -1
- package/commands/gsd/complete-milestone.md +1 -0
- package/commands/gsd/config.md +1 -0
- package/commands/gsd/debug.md +1 -0
- package/commands/gsd/graphify.md +1 -0
- package/commands/gsd/health.md +1 -0
- package/commands/gsd/mempalace-capture.md +8 -3
- package/commands/gsd/mempalace-recall.md +1 -0
- package/commands/gsd/new-milestone.md +1 -0
- package/commands/gsd/new-project.md +1 -0
- package/commands/gsd/next.md +1 -0
- package/commands/gsd/pause-work.md +1 -0
- package/commands/gsd/phase.md +1 -0
- package/commands/gsd/plan-review-convergence.md +6 -6
- package/commands/gsd/pr-branch.md +1 -0
- package/commands/gsd/progress.md +1 -1
- package/commands/gsd/quick-batch.md +1 -1
- package/commands/gsd/resume-work.md +1 -0
- package/commands/gsd/review-backlog.md +1 -0
- package/commands/gsd/review.md +2 -3
- package/commands/gsd/settings.md +2 -1
- package/commands/gsd/stats.md +1 -0
- package/commands/gsd/thread.md +1 -0
- package/commands/gsd/workspace.md +1 -0
- package/commands/gsd/workstreams.md +1 -0
- package/gsd-core/bin/check-latest-version.cjs +8 -3
- package/gsd-core/bin/gsd-tools.cjs +672 -146
- package/gsd-core/bin/lib/adr-parser.cjs +4 -2
- package/gsd-core/bin/lib/artifacts.cjs +2 -1
- package/gsd-core/bin/lib/audit.cjs +119 -34
- package/gsd-core/bin/lib/broken-windows.cjs +168 -49
- package/gsd-core/bin/lib/capability-lifecycle.cjs +10 -6
- package/gsd-core/bin/lib/capability-loader.cjs +135 -1
- package/gsd-core/bin/lib/capability-registry.cjs +96 -189
- package/gsd-core/bin/lib/capability-source.cjs +19 -2
- package/gsd-core/bin/lib/capability-validator.cjs +14 -2
- package/gsd-core/bin/lib/check-command-router.cjs +213 -49
- package/gsd-core/bin/lib/code-review-depth.cjs +2 -2
- package/gsd-core/bin/lib/codex-agent-toml.cjs +21 -25
- package/gsd-core/bin/lib/commands.cjs +823 -112
- package/gsd-core/bin/lib/config-loader.cjs +66 -4
- package/gsd-core/bin/lib/config.cjs +186 -45
- package/gsd-core/bin/lib/coverage.cjs +1 -1
- package/gsd-core/bin/lib/decisions.cjs +164 -45
- package/gsd-core/bin/lib/external-descriptor-trust.cjs +29 -14
- package/gsd-core/bin/lib/frontmatter.cjs +13 -0
- package/gsd-core/bin/lib/graphify.cjs +10 -2
- package/gsd-core/bin/lib/gsd2-import.cjs +1 -2
- package/gsd-core/bin/lib/health-diagnostic-rules/state-consistency.cjs +12 -1
- package/gsd-core/bin/lib/health-diagnostic-rules/worktree-health.cjs +1 -1
- package/gsd-core/bin/lib/host-runtime-detection.cjs +9 -0
- package/gsd-core/bin/lib/init.cjs +614 -86
- package/gsd-core/bin/lib/install-engine.cjs +29 -3
- package/gsd-core/bin/lib/install-profiles.cjs +14 -0
- package/gsd-core/bin/lib/installer-migrations.cjs +41 -5
- package/gsd-core/bin/lib/loop-resolver.cjs +50 -31
- package/gsd-core/bin/lib/mcp-catalog.cjs +2 -2
- package/gsd-core/bin/lib/milestone.cjs +37 -13
- package/gsd-core/bin/lib/model-resolver.cjs +253 -53
- package/gsd-core/bin/lib/phase-command-router.cjs +16 -2
- package/gsd-core/bin/lib/phase-id-card.cjs +32 -0
- package/gsd-core/bin/lib/phase-id-display.cjs +78 -0
- package/gsd-core/bin/lib/phase-id.cjs +268 -27
- package/gsd-core/bin/lib/phase-lifecycle.cjs +61 -0
- package/gsd-core/bin/lib/phase-locator.cjs +29 -10
- package/gsd-core/bin/lib/phase.cjs +393 -88
- package/gsd-core/bin/lib/plan-document.cjs +49 -1
- package/gsd-core/bin/lib/planning-document.cjs +459 -0
- package/gsd-core/bin/lib/planning-inspect.cjs +52 -19
- package/gsd-core/bin/lib/planning-snapshot.cjs +61 -12
- package/gsd-core/bin/lib/planning-workspace.cjs +57 -3
- package/gsd-core/bin/lib/pr-branch-patterns.cjs +57 -0
- package/gsd-core/bin/lib/pristine-baseline.cjs +182 -0
- package/gsd-core/bin/lib/probe-core.cjs +7 -1
- package/gsd-core/bin/lib/prohibition-enforcement.cjs +91 -4
- package/gsd-core/bin/lib/project-root.cjs +41 -2
- package/gsd-core/bin/lib/quick-batch.cjs +1 -1
- package/gsd-core/bin/lib/refactor-trigger-command-router.cjs +61 -2
- package/gsd-core/bin/lib/research-store.cjs +11 -12
- package/gsd-core/bin/lib/review-lane-descriptor.cjs +10 -30
- package/gsd-core/bin/lib/review-lane-invocation.cjs +23 -0
- package/gsd-core/bin/lib/review-reviewer-selection.cjs +2 -2
- package/gsd-core/bin/lib/reviewer-step-dispatch.cjs +337 -0
- package/gsd-core/bin/lib/roadmap-command-router.cjs +12 -4
- package/gsd-core/bin/lib/roadmap-parser.cjs +219 -18
- package/gsd-core/bin/lib/roadmap-upgrade.cjs +1539 -13
- package/gsd-core/bin/lib/roadmap.cjs +356 -42
- package/gsd-core/bin/lib/runtime-artifact-conversion.cjs +310 -41
- package/gsd-core/bin/lib/runtime-artifact-install-plan.cjs +15 -4
- package/gsd-core/bin/lib/runtime-artifact-layout.cjs +13 -5
- package/gsd-core/bin/lib/runtime-homes.cjs +4 -0
- package/gsd-core/bin/lib/runtime-hooks-surface.cjs +408 -37
- package/gsd-core/bin/lib/runtime-name-policy.cjs +111 -1
- package/gsd-core/bin/lib/security.cjs +126 -7
- package/gsd-core/bin/lib/shell-command-projection.cjs +10 -6
- package/gsd-core/bin/lib/state-document.cjs +130 -28
- package/gsd-core/bin/lib/state-md-schema.cjs +21 -14
- package/gsd-core/bin/lib/state-transition.cjs +181 -30
- package/gsd-core/bin/lib/state.cjs +265 -27
- package/gsd-core/bin/lib/surface.cjs +77 -3
- package/gsd-core/bin/lib/task-command-router.cjs +12 -6
- package/gsd-core/bin/lib/tdd-red-evidence.cjs +78 -5
- package/gsd-core/bin/lib/uat-predicate.cjs +47 -4
- package/gsd-core/bin/lib/uat.cjs +9 -1
- package/gsd-core/bin/lib/ui-consideration-probe.cjs +15 -2
- package/gsd-core/bin/lib/ui-frontend-evidence.cjs +100 -9
- package/gsd-core/bin/lib/undo-commit-selection.cjs +131 -0
- package/gsd-core/bin/lib/update-context.cjs +30 -24
- package/gsd-core/bin/lib/vendor/js-yaml.cjs +11 -3
- package/gsd-core/bin/lib/verification.cjs +315 -30
- package/gsd-core/bin/lib/verify-command-grounding.cjs +47 -3
- package/gsd-core/bin/lib/verify.cjs +320 -48
- package/gsd-core/bin/lib/workstream-inventory.cjs +1 -0
- package/gsd-core/bin/lib/worktree-base-ref.cjs +482 -73
- package/gsd-core/bin/lib/worktree-safety.cjs +797 -58
- package/gsd-core/bin/shared/config-defaults.manifest.json +4 -0
- package/gsd-core/bin/shared/config-schema.manifest.json +6 -0
- package/gsd-core/bin/verify-reapply-patches.cjs +439 -80
- package/gsd-core/references/checkpoints.md +5 -3
- package/gsd-core/references/compact-content-gate.md +66 -0
- package/gsd-core/references/edge-probe-fixtures/01-round-half-even/expected-coverage.json +28 -3
- package/gsd-core/references/edge-probe-fixtures/02-merge-intervals/expected-coverage.json +37 -4
- package/gsd-core/references/edge-probe-fixtures/03-truncate-graphemes/expected-coverage.json +28 -3
- package/gsd-core/references/edge-probe-fixtures/04-money-rounding/expected-coverage.json +28 -3
- package/gsd-core/references/edge-probe-fixtures/05-list-dedupe/expected-coverage.json +37 -4
- package/gsd-core/references/edge-probe-fixtures/06-resolved-mixed/expected-coverage.json +37 -4
- package/gsd-core/references/edge-probe.md +195 -21
- package/gsd-core/references/execute-phase-between-wave-reset.md +7 -6
- package/gsd-core/references/execute-phase-wave-guard.md +22 -11
- package/gsd-core/references/gsd-run-resolver.md +1 -1
- package/gsd-core/references/loop-hook-dispatch.md +18 -0
- package/gsd-core/references/model-profiles.md +13 -4
- package/gsd-core/references/phase-argument-parsing.md +9 -7
- package/gsd-core/references/phase-id-convention.md +28 -0
- package/gsd-core/references/planner-gap-closure.md +2 -0
- package/gsd-core/references/planner-load-graph-context.md +24 -13
- package/gsd-core/references/planner-verify-command-grounding.md +14 -0
- package/gsd-core/references/planning-config.md +14 -2
- package/gsd-core/references/tdd.md +30 -4
- package/gsd-core/references/thinking-models-planning.md +18 -2
- package/gsd-core/references/ui-consideration-probe.md +10 -5
- package/gsd-core/references/verification-patterns.md +17 -4
- package/gsd-core/references/verify-command-path-resolvability.md +10 -2
- package/gsd-core/references/worktree-path-safety.md +433 -2
- package/gsd-core/templates/README.md +7 -1
- package/gsd-core/templates/state.md +6 -3
- package/gsd-core/templates/summary.compact.md +212 -0
- package/gsd-core/templates/user-setup.compact.md +199 -0
- package/gsd-core/templates/user-setup.md +0 -9
- package/gsd-core/templates/verification-report.md +1 -1
- package/gsd-core/workflows/_runtime-launcher.snippet.sh +1 -1
- package/gsd-core/workflows/add-backlog.md +1 -1
- package/gsd-core/workflows/add-phase.md +1 -1
- package/gsd-core/workflows/add-tests.md +2 -2
- package/gsd-core/workflows/add-todo.md +6 -5
- package/gsd-core/workflows/ai-integration-phase.md +11 -3
- package/gsd-core/workflows/audit-fix.md +1 -1
- package/gsd-core/workflows/audit-milestone.md +1 -1
- package/gsd-core/workflows/audit-uat.md +1 -1
- package/gsd-core/workflows/autonomous/steps/converge-fail-fast.md +9 -18
- package/gsd-core/workflows/autonomous.md +29 -16
- package/gsd-core/workflows/check-todos.md +6 -4
- package/gsd-core/workflows/cleanup.md +5 -3
- package/gsd-core/workflows/code-review/steps/dispatch-fix.md +4 -3
- package/gsd-core/workflows/code-review/steps/structural-pre-pass.md +8 -1
- package/gsd-core/workflows/code-review-fix.md +108 -22
- package/gsd-core/workflows/code-review.md +216 -73
- package/gsd-core/workflows/complete-milestone/detail/elaboration.md +274 -0
- package/gsd-core/workflows/complete-milestone.md +41 -264
- package/gsd-core/workflows/debug.md +3 -3
- package/gsd-core/workflows/diagnose-issues.md +1 -1
- package/gsd-core/workflows/discuss-phase/modes/advisor.md +1 -1
- package/gsd-core/workflows/discuss-phase/modes/chain.md +1 -1
- package/gsd-core/workflows/discuss-phase-assumptions.md +1 -1
- package/gsd-core/workflows/discuss-phase.md +1 -1
- package/gsd-core/workflows/do.md +2 -2
- package/gsd-core/workflows/docs-update/detail/elaboration.md +179 -0
- package/gsd-core/workflows/docs-update.md +17 -158
- package/gsd-core/workflows/edit-phase.md +1 -1
- package/gsd-core/workflows/eval-review.md +10 -3
- package/gsd-core/workflows/execute-phase/detail/elaboration.md +124 -0
- package/gsd-core/workflows/execute-phase/steps/code-review-disposition.md +1017 -0
- package/gsd-core/workflows/execute-phase/steps/codebase-drift-gate.md +19 -4
- package/gsd-core/workflows/execute-phase/steps/completion-reconciliation.md +56 -0
- package/gsd-core/workflows/execute-phase/steps/executor-isolation-dispatch.md +43 -4
- package/gsd-core/workflows/execute-phase/steps/executor-progress-policy.md +43 -0
- package/gsd-core/workflows/execute-phase/steps/gap-closure-artifacts.md +1 -1
- package/gsd-core/workflows/execute-phase/steps/partial-wave.md +1 -1
- package/gsd-core/workflows/execute-phase/steps/per-plan-executor-routing.md +1 -1
- package/gsd-core/workflows/execute-phase/steps/per-plan-worktree-gate.md +1 -1
- package/gsd-core/workflows/execute-phase/steps/post-merge-gate.md +46 -9
- package/gsd-core/workflows/execute-phase/steps/protected-branch.md +1 -1
- package/gsd-core/workflows/execute-phase/steps/ready-wave-gate.md +37 -0
- package/gsd-core/workflows/execute-phase/steps/regression-gate-run.md +1 -1
- package/gsd-core/workflows/execute-phase/steps/sequential-root-pin.md +35 -0
- package/gsd-core/workflows/execute-phase/steps/stale-reverification.md +24 -0
- package/gsd-core/workflows/execute-phase/steps/tdd-applicability-resolution.md +1 -1
- package/gsd-core/workflows/execute-phase/steps/threat-id-gate.md +28 -0
- package/gsd-core/workflows/execute-phase/steps/wave-post-gate-hooks.md +1 -1
- package/gsd-core/workflows/execute-phase/steps/worktree-base-check.md +25 -0
- package/gsd-core/workflows/execute-phase.md +83 -172
- package/gsd-core/workflows/execute-plan.md +24 -10
- package/gsd-core/workflows/explore.md +3 -3
- package/gsd-core/workflows/extract-learnings.md +2 -1
- package/gsd-core/workflows/fast.md +1 -1
- package/gsd-core/workflows/forensics.md +1 -1
- package/gsd-core/workflows/graduation.md +1 -1
- package/gsd-core/workflows/health.md +2 -2
- package/gsd-core/workflows/help/modes/full.compact.md +398 -0
- package/gsd-core/workflows/help/modes/full.md +5 -5
- package/gsd-core/workflows/help/modes/topic.md +15 -5
- package/gsd-core/workflows/help.md +1 -1
- package/gsd-core/workflows/import.md +2 -2
- package/gsd-core/workflows/inbox.md +2 -2
- package/gsd-core/workflows/ingest-docs.md +3 -3
- package/gsd-core/workflows/insert-phase.md +1 -1
- package/gsd-core/workflows/list-seeds.md +1 -1
- package/gsd-core/workflows/list-workspaces.md +1 -1
- package/gsd-core/workflows/manager.md +2 -2
- package/gsd-core/workflows/map-codebase.md +52 -5
- package/gsd-core/workflows/milestone-summary.md +1 -1
- package/gsd-core/workflows/mvp-phase.md +1 -1
- package/gsd-core/workflows/new-milestone.md +56 -14
- package/gsd-core/workflows/new-project/detail/elaboration.md +216 -0
- package/gsd-core/workflows/new-project/steps/auto-mode-config.md +3 -3
- package/gsd-core/workflows/new-project/steps/codebase-map-offer.md +1 -1
- package/gsd-core/workflows/new-project.md +39 -209
- package/gsd-core/workflows/new-workspace.md +2 -2
- package/gsd-core/workflows/next.md +1 -1
- package/gsd-core/workflows/note.md +1 -1
- package/gsd-core/workflows/onboard.md +1 -1
- package/gsd-core/workflows/pause-work.md +1 -1
- package/gsd-core/workflows/plan-phase/detail/elaboration.md +209 -0
- package/gsd-core/workflows/plan-phase/steps/chunked-planning-mode.md +17 -5
- package/gsd-core/workflows/plan-phase/steps/prd-express-path.md +1 -1
- package/gsd-core/workflows/plan-phase/steps/stall-detection-helpers.md +23 -5
- package/gsd-core/workflows/plan-phase.md +45 -187
- package/gsd-core/workflows/plan-review-convergence.md +21 -5
- package/gsd-core/workflows/plant-seed.md +62 -20
- package/gsd-core/workflows/pr-branch.md +132 -20
- package/gsd-core/workflows/profile-user.md +2 -2
- package/gsd-core/workflows/progress.md +1 -1
- package/gsd-core/workflows/quick/steps/plan-checker-loop.md +25 -0
- package/gsd-core/workflows/quick/steps/quick-verification.md +1 -1
- package/gsd-core/workflows/quick/steps/worktree-pre-dispatch-commit.md +1 -1
- package/gsd-core/workflows/quick-batch/steps/batch-init.md +1 -1
- package/gsd-core/workflows/quick-batch/steps/completion.md +1 -1
- package/gsd-core/workflows/quick-batch/steps/merge-wave.md +1 -1
- package/gsd-core/workflows/quick-batch/steps/planner-wave.md +1 -1
- package/gsd-core/workflows/quick-batch/steps/research-phase.md +1 -1
- package/gsd-core/workflows/quick-batch/steps/resume-mode.md +1 -1
- package/gsd-core/workflows/quick-batch/steps/verification-wave.md +1 -1
- package/gsd-core/workflows/quick-batch/steps/worktree-dispatch.md +1 -1
- package/gsd-core/workflows/quick-batch.md +1 -1
- package/gsd-core/workflows/quick.md +29 -10
- package/gsd-core/workflows/reapply-patches.md +86 -6
- package/gsd-core/workflows/remove-phase.md +1 -1
- package/gsd-core/workflows/remove-workspace.md +2 -2
- package/gsd-core/workflows/resume-project.md +1 -1
- package/gsd-core/workflows/review.md +31 -16
- package/gsd-core/workflows/scan.md +1 -1
- package/gsd-core/workflows/secure-phase.md +3 -2
- package/gsd-core/workflows/settings-advanced.md +30 -10
- package/gsd-core/workflows/settings-integrations.md +2 -3
- package/gsd-core/workflows/settings.md +22 -9
- package/gsd-core/workflows/ship.md +3 -2
- package/gsd-core/workflows/sketch-wrap-up.md +1 -1
- package/gsd-core/workflows/sketch.md +1 -1
- package/gsd-core/workflows/smart-entry.md +2 -2
- package/gsd-core/workflows/spec-phase.md +15 -5
- package/gsd-core/workflows/spike-wrap-up.md +1 -1
- package/gsd-core/workflows/spike.md +1 -1
- package/gsd-core/workflows/stats.md +1 -1
- package/gsd-core/workflows/sync-skills.md +5 -5
- package/gsd-core/workflows/thread.md +1 -1
- package/gsd-core/workflows/transition.md +1 -1
- package/gsd-core/workflows/ui-phase.md +44 -8
- package/gsd-core/workflows/ui-review.md +18 -4
- package/gsd-core/workflows/ultraplan-phase.md +1 -1
- package/gsd-core/workflows/undo.md +339 -20
- package/gsd-core/workflows/update.md +14 -12
- package/gsd-core/workflows/validate-phase.md +3 -2
- package/gsd-core/workflows/verify-work/detail/elaboration.md +230 -0
- package/gsd-core/workflows/verify-work/steps/automated-ui-verification.md +1 -1
- package/gsd-core/workflows/verify-work/steps/mvp-uat-framing.md +1 -1
- package/gsd-core/workflows/verify-work.md +101 -196
- package/hooks/dist/gsd-agent-isolation-guard.js +66 -16
- package/hooks/dist/gsd-context-monitor.js +88 -15
- package/hooks/dist/gsd-cursor-subagent-start.js +34 -14
- package/hooks/dist/gsd-secret-read-guard.js +71 -19
- package/hooks/dist/gsd-statusline.js +81 -20
- package/hooks/dist/gsd-validate-commit.sh +97 -8
- package/hooks/dist/gsd-worktree-path-guard.js +25 -14
- package/hooks/dist/gsd-write-guard.js +46 -1
- package/hooks/dist/lib/dispatch-identity.js +187 -0
- package/hooks/dist/lib/filename-classification.js +64 -0
- package/hooks/dist/lib/isolation-deny-reason.js +53 -1
- package/hooks/dist/lib/isolation-sentinel.js +58 -19
- package/hooks/gsd-agent-isolation-guard.js +66 -16
- package/hooks/gsd-context-monitor.js +88 -15
- package/hooks/gsd-cursor-subagent-start.js +34 -14
- package/hooks/gsd-secret-read-guard.js +71 -19
- package/hooks/gsd-statusline.js +81 -20
- package/hooks/gsd-validate-commit.sh +97 -8
- package/hooks/gsd-worktree-path-guard.js +25 -14
- package/hooks/gsd-write-guard.js +46 -1
- package/hooks/lib/dispatch-identity.js +187 -0
- package/hooks/lib/filename-classification.js +64 -0
- package/hooks/lib/isolation-deny-reason.js +53 -1
- package/hooks/lib/isolation-sentinel.js +58 -19
- package/package.json +11 -6
- package/scripts/benchmark-compact-content-variants.cjs +298 -0
- package/scripts/benchmark-compact-content.cjs +368 -0
- package/scripts/build-hooks.js +15 -6
- package/scripts/check-contract-drift.cjs +131 -12
- package/scripts/check-env.cjs +36 -8
- package/scripts/check-glossary-refs.cjs +25 -21
- package/scripts/ci-next-health.cjs +271 -0
- package/scripts/ci-prepare-test-scope.cjs +7 -7
- package/scripts/ci-test-scope.cjs +126 -20
- package/scripts/ci-timeout-report.cjs +1 -1
- package/scripts/command-contract-helpers.cjs +3 -0
- package/scripts/diff-touches-shipped-paths.cjs +1 -1
- package/scripts/docs-guard-registry.cjs +35 -2
- package/scripts/gen-adr-index.cjs +8 -2
- package/scripts/gen-inventory-manifest.cjs +12 -0
- package/scripts/gen-loop-host-contract.cjs +69 -0
- package/scripts/gen-platform-conformance-tier.cjs +557 -0
- package/scripts/lib/drift-scan.cjs +1 -1
- package/scripts/lib/macos-conformance-tier.generated.cjs +224 -0
- package/scripts/lib/ndjson-reporter.cjs +3 -2
- package/scripts/lib/npm-version-check-diagnosis.cjs +59 -0
- package/scripts/lib/platform-conformance-tier.generated.cjs +287 -0
- package/scripts/lib/suite-detection.cjs +32 -0
- package/scripts/lint-allowed-tools-parity.cjs +221 -0
- package/scripts/lint-docs-guard-registration.exempt-baseline.cjs +47 -3
- package/scripts/lint-phase-arg-assignment.cjs +257 -0
- package/scripts/lint-phase-id-drift.cjs +623 -13
- package/scripts/lint-pr-branch-pattern-drift.cjs +148 -0
- package/scripts/lint-response-language-coverage.cjs +9 -3
- package/scripts/lint-retired-runtime-name.cjs +619 -0
- package/scripts/lint-source-test-name-collision.cjs +1 -1
- package/scripts/lint-state-write-path-drift.cjs +93 -0
- package/scripts/lint-test-file-count.allowlist.json +29 -9
- package/scripts/lint-vendored-deps.cjs +128 -17
- package/scripts/lint-workflow-shellcheck-baseline.json +100 -0
- package/scripts/prompt-injection-scan.sh +18 -0
- package/scripts/release-tarball-smoke.cjs +194 -1
- package/scripts/workflow-size.cjs +139 -0
- package/skills/gsd-autonomous/SKILL.md +2 -2
- package/skills/gsd-capture/SKILL.md +1 -1
- package/skills/gsd-cleanup/SKILL.md +1 -0
- package/skills/gsd-code-review/SKILL.md +2 -1
- package/skills/gsd-complete-milestone/SKILL.md +1 -0
- package/skills/gsd-config/SKILL.md +1 -0
- package/skills/gsd-debug/SKILL.md +1 -0
- package/skills/gsd-graphify/SKILL.md +1 -0
- package/skills/gsd-health/SKILL.md +1 -0
- package/skills/gsd-mempalace-capture/SKILL.md +8 -3
- package/skills/gsd-mempalace-recall/SKILL.md +1 -0
- package/skills/gsd-new-milestone/SKILL.md +1 -0
- package/skills/gsd-new-project/SKILL.md +1 -0
- package/skills/gsd-next/SKILL.md +1 -0
- package/skills/gsd-pause-work/SKILL.md +1 -0
- package/skills/gsd-phase/SKILL.md +1 -0
- package/skills/gsd-plan-review-convergence/SKILL.md +5 -5
- package/skills/gsd-pr-branch/SKILL.md +1 -0
- package/skills/gsd-progress/SKILL.md +1 -1
- package/skills/gsd-quick-batch/SKILL.md +1 -1
- package/skills/gsd-resume-work/SKILL.md +1 -0
- package/skills/gsd-review/SKILL.md +2 -3
- package/skills/gsd-review-backlog/SKILL.md +1 -0
- package/skills/gsd-settings/SKILL.md +2 -1
- package/skills/gsd-stats/SKILL.md +1 -0
- package/skills/gsd-thread/SKILL.md +1 -0
- package/skills/gsd-workspace/SKILL.md +1 -0
- package/skills/gsd-workstreams/SKILL.md +1 -0
- package/vscode/package.json +1 -1
- package/gsd-core/templates/claude-md.md +0 -145
- package/gsd-core/templates/codebase/concerns.md +0 -310
- package/gsd-core/templates/codebase/conventions.md +0 -307
- package/gsd-core/templates/codebase/integrations.md +0 -280
- package/gsd-core/templates/codebase/structure.md +0 -285
- package/gsd-core/templates/codebase/testing.md +0 -480
- package/gsd-core/templates/debug-subagent-prompt.md +0 -91
- package/gsd-core/templates/discovery.md +0 -146
|
@@ -571,6 +571,55 @@ function sliceMilestoneWindow(content, version) {
|
|
|
571
571
|
return null;
|
|
572
572
|
return content.slice(selected.index, computeMilestoneSectionEnd(content, selected[0], selected.index));
|
|
573
573
|
}
|
|
574
|
+
/**
|
|
575
|
+
* Enumerate the milestone section ranges recognized by the ROADMAP readers.
|
|
576
|
+
* Markdown boundaries reuse the reader's heading tokenizer, milestone-signal
|
|
577
|
+
* vocabulary, name/version extractor, and section-end owner. Collapsed
|
|
578
|
+
* archives reuse the same `<details><summary>` shape handled by
|
|
579
|
+
* `extractCurrentMilestoneScoped`.
|
|
580
|
+
*/
|
|
581
|
+
function milestoneSections(content) {
|
|
582
|
+
const sections = [];
|
|
583
|
+
const headings = (0, markdown_sectionizer_cjs_1.tokenizeHeadings)(content);
|
|
584
|
+
for (const heading of headings) {
|
|
585
|
+
if (heading.level < 1 || heading.level > 3)
|
|
586
|
+
continue;
|
|
587
|
+
if (/^Phase\s+\S/i.test(heading.text))
|
|
588
|
+
continue;
|
|
589
|
+
if (!MILESTONE_HEADING_SIGNAL_PATTERN.test(heading.text))
|
|
590
|
+
continue;
|
|
591
|
+
const extracted = extractMilestoneHeadingName(heading.text);
|
|
592
|
+
const version = extracted?.version ?? null;
|
|
593
|
+
const versionMajor = version?.match(/^v(\d+)/i);
|
|
594
|
+
const milestoneInt = versionMajor ? parseInt(versionMajor[1], 10) : null;
|
|
595
|
+
const lineEnd = content.indexOf('\n', heading.offset);
|
|
596
|
+
const fullLine = content.slice(heading.offset, lineEnd === -1 ? content.length : lineEnd);
|
|
597
|
+
sections.push({
|
|
598
|
+
start: heading.offset,
|
|
599
|
+
end: computeMilestoneSectionEnd(content, fullLine, heading.offset, undefined, headings),
|
|
600
|
+
version,
|
|
601
|
+
milestoneInt: milestoneInt !== null && Number.isSafeInteger(milestoneInt) ? milestoneInt : null,
|
|
602
|
+
});
|
|
603
|
+
}
|
|
604
|
+
const detailsPattern = /<details\b[^>]*>[\s\S]*?<\/details>/gi;
|
|
605
|
+
let detailsMatch;
|
|
606
|
+
while ((detailsMatch = detailsPattern.exec(content)) !== null) {
|
|
607
|
+
const summary = detailsMatch[0].match(/<summary[^>]*>([^<]*)<\/summary>/i)?.[1]?.trim() ?? '';
|
|
608
|
+
if (!MILESTONE_HEADING_SIGNAL_PATTERN.test(summary))
|
|
609
|
+
continue;
|
|
610
|
+
const extracted = extractMilestoneHeadingName(summary);
|
|
611
|
+
const version = extracted?.version ?? null;
|
|
612
|
+
const versionMajor = version?.match(/^v(\d+)/i);
|
|
613
|
+
const milestoneInt = versionMajor ? parseInt(versionMajor[1], 10) : null;
|
|
614
|
+
sections.push({
|
|
615
|
+
start: detailsMatch.index,
|
|
616
|
+
end: detailsMatch.index + detailsMatch[0].length,
|
|
617
|
+
version,
|
|
618
|
+
milestoneInt: milestoneInt !== null && Number.isSafeInteger(milestoneInt) ? milestoneInt : null,
|
|
619
|
+
});
|
|
620
|
+
}
|
|
621
|
+
return sections.sort((a, b) => a.start - b.start || a.end - b.end);
|
|
622
|
+
}
|
|
574
623
|
/**
|
|
575
624
|
* #3184: counts RAW phase references — a `#{2,4} Phase <id>:` heading
|
|
576
625
|
* (fence-aware via `tokenizeHeadings`) or a `#2199` bullet entry — BEFORE any
|
|
@@ -600,17 +649,37 @@ function sliceMilestoneWindow(content, version) {
|
|
|
600
649
|
// decoy `### [GSD.04] Notes:` outside the window manufactured a false V005
|
|
601
650
|
// while suppressing the correct V004. The digit anchor forecloses both.
|
|
602
651
|
const BRACKET_PHASE_ENTRY_HEADING_RE = new RegExp(`^${PHASE_HEADING_PREFIX_SRC}${PHASE_NUMBER_TOKEN_SOURCE}${OPTIONAL_PHASE_TAG_SOURCE}\\s*:`, 'i');
|
|
652
|
+
// #1729: `(?:\s*\([^)\n]{0,200}\))?` tolerates a pre-colon ( ) tag (literal
|
|
653
|
+
// mirror of OPTIONAL_PHASE_TAG_SOURCE). Hoisted out of hasPhaseEntries (#4144
|
|
654
|
+
// round 5 Blocker 1) so a consumer OUTSIDE this file's own phase-entry count —
|
|
655
|
+
// the bracket roadmap migrator's "phase-like but unparsed" refusal
|
|
656
|
+
// (src/roadmap-upgrade.cts) — can ask "is this heading text a phase heading
|
|
657
|
+
// by the readers' own rules" without re-deriving the pattern. A heading with
|
|
658
|
+
// no phase-number token and no trailing colon (`## Phase Details`, `##
|
|
659
|
+
// Phase Lifecycle`, `### Phase Notes`) is NOT a phase heading by this
|
|
660
|
+
// grammar — it is an ordinary section heading that happens to start with the
|
|
661
|
+
// word "Phase".
|
|
662
|
+
const PHASE_HEADING_TEXT_RE = /^(?:\[[^\]]{1,200}\]\s*)?Phase\s+([\w][\w.-]*)(?:\s*\([^)\n]{0,200}\))?\s*:/i;
|
|
663
|
+
/**
|
|
664
|
+
* #4144 round 5 Blocker 1: whether `headingText` — a heading's text with its
|
|
665
|
+
* leading `#{1,6}` markers and surrounding whitespace already stripped
|
|
666
|
+
* (`tokenizeHeadings`'s own `h.text`, or the equivalent for a line a caller
|
|
667
|
+
* already knows is a `#{2,4}` heading) — is a phase heading by the readers'
|
|
668
|
+
* own grammar. The single owner of this test; `hasPhaseEntries` below is
|
|
669
|
+
* itself just the first caller.
|
|
670
|
+
*/
|
|
671
|
+
function isPhaseHeadingText(headingText) {
|
|
672
|
+
return PHASE_HEADING_TEXT_RE.test(headingText);
|
|
673
|
+
}
|
|
603
674
|
function hasPhaseEntries(markdown, phaseIdConvention) {
|
|
604
|
-
// #1729: `(?:\s*\([^)\n]{0,200}\))?` tolerates a pre-colon ( ) tag (literal mirror of OPTIONAL_PHASE_TAG_SOURCE).
|
|
605
675
|
// #3641: the widened grammar engages ONLY when the resolved convention is
|
|
606
676
|
// 'bracket' — a project that has not opted in runs the legacy pattern
|
|
607
677
|
// alone, byte-identically.
|
|
608
|
-
const phaseHeadingPattern = /^(?:\[[^\]]{1,200}\]\s*)?Phase\s+([\w][\w.-]*)(?:\s*\([^)\n]{0,200}\))?\s*:/i;
|
|
609
678
|
const bracketMode = phaseIdConvention === 'bracket';
|
|
610
679
|
for (const h of (0, markdown_sectionizer_cjs_1.tokenizeHeadings)(markdown)) {
|
|
611
680
|
if (h.level < 2 || h.level > 4)
|
|
612
681
|
continue;
|
|
613
|
-
if (
|
|
682
|
+
if (isPhaseHeadingText(h.text))
|
|
614
683
|
return true;
|
|
615
684
|
if (bracketMode && BRACKET_PHASE_ENTRY_HEADING_RE.test(h.text))
|
|
616
685
|
return true;
|
|
@@ -626,16 +695,17 @@ function hasPhaseEntries(markdown, phaseIdConvention) {
|
|
|
626
695
|
return collectTablePhaseRows(markdown).length > 0;
|
|
627
696
|
}
|
|
628
697
|
// ─── #3577: markdown-table phase listings ─────────────────────────────────────
|
|
629
|
-
// #3577: a GFM table declares phases when its header's FIRST cell is
|
|
630
|
-
// `Phase` (optionally `Phase #` / `Phase No.` / `Phase number`)
|
|
631
|
-
//
|
|
632
|
-
//
|
|
633
|
-
//
|
|
634
|
-
// their first cell (digit-bearing canonical shape —
|
|
635
|
-
// `---` delimiter rows are digit-free and excluded
|
|
636
|
-
// via stripFencedCode, matching the #3184 lesson:
|
|
637
|
-
// form is not a declared phase.
|
|
698
|
+
// #3577/#4480: a GFM table declares phases only when its header's FIRST cell is
|
|
699
|
+
// the literal `Phase` (optionally `Phase #` / `Phase No.` / `Phase number`) AND
|
|
700
|
+
// it positively identifies a `Name` or `Phase Name` column. This fails closed:
|
|
701
|
+
// ordinary progress/summary tables such as `| Phase | Status |` cannot mint a
|
|
702
|
+
// phase whose name is whichever value happens to occupy column two. Data rows
|
|
703
|
+
// carry the phase id in their first cell (digit-bearing canonical shape —
|
|
704
|
+
// `Phase`-word header cells and `---` delimiter rows are digit-free and excluded
|
|
705
|
+
// by construction). Fence-aware via stripFencedCode, matching the #3184 lesson:
|
|
706
|
+
// a fenced EXAMPLE of the table form is not a declared phase.
|
|
638
707
|
const PHASE_LISTING_HEADER_RE = /^\|?\s*phase(?:\s*(?:#|no\.?|number))?\s*\|/i;
|
|
708
|
+
const PHASE_NAME_HEADER_RE = /^(?:phase\s+)?name$/i;
|
|
639
709
|
const TABLE_PHASE_ID_RE = /^[A-Za-z]?\d[\w.-]*$/;
|
|
640
710
|
function collectTablePhaseRows(window) {
|
|
641
711
|
const unfenced = (0, markdown_sectionizer_cjs_1.stripFencedCode)(window).text;
|
|
@@ -645,8 +715,9 @@ function collectTablePhaseRows(window) {
|
|
|
645
715
|
if (!PHASE_LISTING_HEADER_RE.test(lines[i]))
|
|
646
716
|
continue;
|
|
647
717
|
const headerCells = (0, markdown_table_cjs_1.splitTableRow)(lines[i]);
|
|
648
|
-
|
|
649
|
-
|
|
718
|
+
const nameColumn = headerCells.findIndex((cell) => PHASE_NAME_HEADER_RE.test(cell));
|
|
719
|
+
if (nameColumn === -1)
|
|
720
|
+
continue;
|
|
650
721
|
if (!(0, markdown_table_cjs_1.isDelimiterRow)((0, markdown_table_cjs_1.splitTableRow)(lines[i + 1])))
|
|
651
722
|
continue;
|
|
652
723
|
for (let j = i + 2; j < lines.length; j++) {
|
|
@@ -662,12 +733,30 @@ function collectTablePhaseRows(window) {
|
|
|
662
733
|
if (!TABLE_PHASE_ID_RE.test(first))
|
|
663
734
|
continue;
|
|
664
735
|
if (!/^999\b/.test(first)) {
|
|
665
|
-
|
|
736
|
+
const name = cells[nameColumn];
|
|
737
|
+
rows.push({ id: first, name: name && name !== '' ? name : null, row: lines[j] });
|
|
666
738
|
}
|
|
667
739
|
}
|
|
668
740
|
}
|
|
669
741
|
return rows;
|
|
670
742
|
}
|
|
743
|
+
/**
|
|
744
|
+
* True when `content` contains a GFM table whose header row is phase-listing
|
|
745
|
+
* SHAPED (`| Phase | ... |`), regardless of whether it also declares a `Name`
|
|
746
|
+
* column. `collectTablePhaseRows` correctly refuses to mint a phase from a
|
|
747
|
+
* `| Phase | Status |`-shaped table (no name column, so no declaration) —
|
|
748
|
+
* but that table's mere presence still signals this roadmap has moved to
|
|
749
|
+
* table-based tracking, not checklist-based tracking. Callers that decide
|
|
750
|
+
* whether to treat bare checklist entries as phase declarations (#4899's
|
|
751
|
+
* roadmap.cts synthesis fallback) must see this signal even when
|
|
752
|
+
* `collectTablePhaseRows` itself returns nothing for the same content —
|
|
753
|
+
* otherwise a thin, name-less Progress table cannot suppress a checklist
|
|
754
|
+
* synthesis it was never meant to coexist with.
|
|
755
|
+
*/
|
|
756
|
+
function hasPhaseListingTableHeader(content) {
|
|
757
|
+
const unfenced = (0, markdown_sectionizer_cjs_1.stripFencedCode)(content).text;
|
|
758
|
+
return unfenced.split(/\r?\n/).some((line) => PHASE_LISTING_HEADER_RE.test(line));
|
|
759
|
+
}
|
|
671
760
|
/**
|
|
672
761
|
* #3262: the sole owner of "which phase ids does THIS milestone window
|
|
673
762
|
* declare". Extracted verbatim from `getMilestonePhaseFilter`'s former inline
|
|
@@ -962,6 +1051,7 @@ function extractCurrentMilestoneScoped(content, cwd, ws, phaseIdConvention) {
|
|
|
962
1051
|
const preambleCutoff = firstMilestoneMatch ? firstMilestoneMatch.index : detailsOpenIdx;
|
|
963
1052
|
const preamble = (0, markdown_sectionizer_cjs_1.stripTaggedBlocks)(content.slice(0, preambleCutoff), 'details')
|
|
964
1053
|
// #1729: `(?:\s*\([^)\n]{0,200}\))?` tolerates a pre-colon ( ) tag (literal mirror of OPTIONAL_PHASE_TAG_SOURCE).
|
|
1054
|
+
// phase-id-owner: pre-existing hand-rolled Phase-heading pattern — grandfathered pending Phase 6 migration (ADR-4910 §8, epic #4906)
|
|
965
1055
|
.replace(/^#{2,4}\s*Phase\s+[\w][\w.-]*(?:\s*\([^)\n]{0,200}\))?\s*:[^\n]*(?:\n(?!#{1,6}\s)[^\n]*)*\n?/gim, '')
|
|
966
1056
|
.replace(/^#{1,4}\s*Phase Details\b[^\n]*\n?/gim, '');
|
|
967
1057
|
const value = preamble + content.slice(detailsOpenIdx, detailsEnd);
|
|
@@ -1197,6 +1287,7 @@ function extractCurrentMilestoneScoped(content, cwd, ws, phaseIdConvention) {
|
|
|
1197
1287
|
// every phase (phase_count: 0, exit 0). Only strip preamble phase details when
|
|
1198
1288
|
// the selected milestone section actually contains its own — otherwise the
|
|
1199
1289
|
// preamble phases ARE this milestone's phases and must be preserved.
|
|
1290
|
+
// phase-id-owner: pre-existing hand-rolled Phase-heading pattern — grandfathered pending Phase 6 migration (ADR-4910 §8, epic #4906)
|
|
1200
1291
|
const currentSectionHasPhaseDetails = /^#{2,4}\s*Phase\s+\S/im.test(currentSection);
|
|
1201
1292
|
const preambleBase = (0, markdown_sectionizer_cjs_1.stripTaggedBlocks)(beforeMilestones, 'details');
|
|
1202
1293
|
// #3235: the conditional wraps the REPLACE, not the pattern. This used to select between the
|
|
@@ -1205,6 +1296,7 @@ function extractCurrentMilestoneScoped(content, cwd, ws, phaseIdConvention) {
|
|
|
1205
1296
|
// replacement argument, so changing `''` would silently give the no-op branch a real effect.
|
|
1206
1297
|
// #1729: `(?:\s*\([^)\n]{0,200}\))?` tolerates a pre-colon ( ) tag (literal mirror of OPTIONAL_PHASE_TAG_SOURCE).
|
|
1207
1298
|
const preambleWithoutPhaseDetails = currentSectionHasPhaseDetails
|
|
1299
|
+
// phase-id-owner: pre-existing hand-rolled Phase-heading pattern — grandfathered pending Phase 6 migration (ADR-4910 §8, epic #4906)
|
|
1208
1300
|
? preambleBase.replace(/^#{2,4}\s*Phase\s+[\w][\w.-]*(?:\s*\([^)\n]{0,200}\))?\s*:[^\n]*(?:\n(?!#{1,6}\s)[^\n]*)*\n?/gim, '')
|
|
1209
1301
|
: preambleBase;
|
|
1210
1302
|
// Unconditional in BOTH branches -- the #730 `Phase Details` heading strip is independent of
|
|
@@ -1481,6 +1573,23 @@ function findRoadmapProgressTable(roadmapContent) {
|
|
|
1481
1573
|
function stripLeadingDelimiter(s) {
|
|
1482
1574
|
return s.replace(/^[\s—–:-]+/, '').trim();
|
|
1483
1575
|
}
|
|
1576
|
+
/**
|
|
1577
|
+
* #4134/#4433 (§7.2 rule 6 floor, applied symmetrically): a captured "name"
|
|
1578
|
+
* with no letter or digit anywhere is heading/bullet STRUCTURE, not a curated
|
|
1579
|
+
* name — e.g. the trailing `)` a name-then-version heading leaves after its
|
|
1580
|
+
* version token, or a malformed 🚧-bullet whose only content past the version
|
|
1581
|
+
* is punctuation (`---`, `***`, a lone `:`). #4134 fixed this for
|
|
1582
|
+
* `extractMilestoneHeadingName`'s heading path only; #4433 found the sibling
|
|
1583
|
+
* 🚧-bullet capture (`getMilestoneInfo`'s `listMatch`) and the no-STATE.md
|
|
1584
|
+
* fallback (`inProgressMatch`) both skipped straight to a bare truthiness
|
|
1585
|
+
* check, so a punctuation-only bullet name passed through as a real one. This
|
|
1586
|
+
* is now the SOLE name-validity predicate — every capture site in this file
|
|
1587
|
+
* calls it instead of re-deriving the character class. A name that merely
|
|
1588
|
+
* CONTAINS punctuation is unaffected; digits alone qualify.
|
|
1589
|
+
*/
|
|
1590
|
+
function hasNameableContent(s) {
|
|
1591
|
+
return /[\p{L}\p{N}]/u.test(s);
|
|
1592
|
+
}
|
|
1484
1593
|
/**
|
|
1485
1594
|
* #3216 (ADR-3180 §7.2's "Name extraction — pinned rule"): the sole "milestone
|
|
1486
1595
|
* heading text → version + curated name" rule. Strips everything through the
|
|
@@ -1493,6 +1602,13 @@ function stripLeadingDelimiter(s) {
|
|
|
1493
1602
|
* one implementation. Returns `null` when `headingText` carries no version
|
|
1494
1603
|
* token at all (e.g. a non-milestone heading reached this by mistake).
|
|
1495
1604
|
*
|
|
1605
|
+
* #4134 (§7.2 rule 6 floor): the rule's direction assumes version-then-name.
|
|
1606
|
+
* A name-then-version heading (`# Roadmap: Project — Name (v1.13)`) leaves a
|
|
1607
|
+
* punctuation fragment (`)`) after the token; a remainder with no letter or
|
|
1608
|
+
* digit anywhere is heading structure, not a curated name, and is refused as
|
|
1609
|
+
* `name: null` so callers report the honest rule-6 answer instead of
|
|
1610
|
+
* fabricating garbage. Names that merely CONTAIN punctuation are unaffected.
|
|
1611
|
+
*
|
|
1496
1612
|
* @param expectedVersion - When the caller already knows the exact version it
|
|
1497
1613
|
* is looking for (the STATE-anchored `getMilestoneInfo` path, which located
|
|
1498
1614
|
* this heading via `selectMilestoneHeading(roadmap, stateVersion)`), pass it
|
|
@@ -1529,7 +1645,18 @@ function extractMilestoneHeadingName(headingText, expectedVersion) {
|
|
|
1529
1645
|
// whitespace — the marker is already carried structurally by `closed`, so
|
|
1530
1646
|
// duplicating it inside `name` (e.g. "Old ✅") is redundant and wrong. Only
|
|
1531
1647
|
// these three markers, only at the end; a marker inside a name is untouched.
|
|
1532
|
-
const
|
|
1648
|
+
const candidate = stripLeadingDelimiter(afterVersion).replace(/\s*(?:[✅📋🚧]\s*)+$/, '') || null;
|
|
1649
|
+
// #4134 (§7.2 rule 6 floor): a "name" with no letter or digit anywhere is
|
|
1650
|
+
// heading structure, not a curated name. The pinned rule takes everything
|
|
1651
|
+
// AFTER the version token, so a name-then-version heading (`# Roadmap:
|
|
1652
|
+
// Project — Name (v1.13)` — the shape a first-ever ROADMAP.md drifts into)
|
|
1653
|
+
// leaves exactly `)` there, which used to be returned as a COMPLETE-scope
|
|
1654
|
+
// name and propagated into init.* output and STATE.md. Refuse it: callers
|
|
1655
|
+
// already report the honest rule-6 answer (version kept, `name: null`,
|
|
1656
|
+
// scope TRUNCATED) for an unresolvable name. A name that merely CONTAINS
|
|
1657
|
+
// punctuation is untouched — `(` is an ordinary name character (#3171) —
|
|
1658
|
+
// and digits alone qualify (`## v4.0 — 42` is the name `42`).
|
|
1659
|
+
const name = candidate !== null && hasNameableContent(candidate) ? candidate : null;
|
|
1533
1660
|
return { version, name };
|
|
1534
1661
|
}
|
|
1535
1662
|
/**
|
|
@@ -1614,7 +1741,7 @@ function getMilestoneInfo(cwd) {
|
|
|
1614
1741
|
const listMatch = roadmap.match(new RegExp(`🚧\\s*\\*?\\*?${escapedVer}\\*?\\*?\\s+([^*\\n]+)`, 'i'));
|
|
1615
1742
|
if (listMatch) {
|
|
1616
1743
|
const name = stripLeadingDelimiter(listMatch[1]);
|
|
1617
|
-
if (name)
|
|
1744
|
+
if (name && hasNameableContent(name))
|
|
1618
1745
|
return scoped({ version: stateVersion, name }, SCOPE.COMPLETE);
|
|
1619
1746
|
}
|
|
1620
1747
|
// #3216: heading selection routes through the shared owner
|
|
@@ -1648,7 +1775,10 @@ function getMilestoneInfo(cwd) {
|
|
|
1648
1775
|
// (unchanged from the pre-#3216 fallback).
|
|
1649
1776
|
const inProgressMatch = roadmap.match(/🚧\s*\*\*v(\d+(?:\.\d+)+)\s+([^*]+)\*\*/);
|
|
1650
1777
|
if (inProgressMatch) {
|
|
1651
|
-
|
|
1778
|
+
const inProgressName = inProgressMatch[2].trim();
|
|
1779
|
+
if (hasNameableContent(inProgressName)) {
|
|
1780
|
+
return scoped({ version: 'v' + inProgressMatch[1], name: inProgressName }, SCOPE.COMPLETE);
|
|
1781
|
+
}
|
|
1652
1782
|
}
|
|
1653
1783
|
// #3216: enumerate every OPEN (non-shipped) milestone heading via the
|
|
1654
1784
|
// shared owner and take the first in document order — deletes the
|
|
@@ -2015,6 +2145,69 @@ function currentMilestoneRawRanges(content, cwd) {
|
|
|
2015
2145
|
}
|
|
2016
2146
|
return { primary: { start: sectionStart, end: sectionEnd }, details };
|
|
2017
2147
|
}
|
|
2148
|
+
/**
|
|
2149
|
+
* #4731 — extract a bold-labeled phase field (Goal, Requirements, ...) reading
|
|
2150
|
+
* past hard-wrapped continuation lines. The roadmapper soft-wraps long fields
|
|
2151
|
+
* at ~85 chars, so a single-line capture silently truncated every wrapped
|
|
2152
|
+
* Goal/Requirements. Stops at: another `**Field**` label line, a blank line,
|
|
2153
|
+
* or any heading. Wrapped lines are trimmed and joined with single spaces; a
|
|
2154
|
+
* single-line field is returned unchanged (trimmed). Returns null when the
|
|
2155
|
+
* label is absent.
|
|
2156
|
+
*/
|
|
2157
|
+
function extractPhaseFieldMultiline(section, label) {
|
|
2158
|
+
// #2769 label shapes: `**X:**`, `**X**:`, and the spaced `**X** :`.
|
|
2159
|
+
// #4837: anchored to line start (`^[ \t]*`, `m` flag) so an inline
|
|
2160
|
+
// `**Label**` mention embedded in an EARLIER field's own body text cannot
|
|
2161
|
+
// shadow the real field's own declaration line. `[ \t]*` (not `\s*`) keeps
|
|
2162
|
+
// the anchor scoped to same-line leading whitespace under the `m` flag.
|
|
2163
|
+
const labelRe = new RegExp('^[ \\t]*\\*\\*' + label + '(?::\\*\\*|\\*\\*\\s*:?)\\s*([^\\n]+)', 'im');
|
|
2164
|
+
const match = section.match(labelRe);
|
|
2165
|
+
if (!match)
|
|
2166
|
+
return null;
|
|
2167
|
+
const startIdx = match.index ?? 0;
|
|
2168
|
+
const after = section.slice(startIdx + match[0].length);
|
|
2169
|
+
const firstLine = match[1].trim();
|
|
2170
|
+
// #4837 (isolated-review finding): the continuation loop's fence-stop check
|
|
2171
|
+
// only ever sees lines AFTER the label's own line — a fence opener on the
|
|
2172
|
+
// SAME line as the label (`**Requirements:** ```js`) was invisible to it,
|
|
2173
|
+
// leaking one line of fence content before the closing fence line
|
|
2174
|
+
// coincidentally matched the same stop check. Checked here too, so a fence
|
|
2175
|
+
// opening on the label's own line is caught just as conservatively.
|
|
2176
|
+
if (/^(?:`{3,}|~{3,})/.test(firstLine))
|
|
2177
|
+
return null;
|
|
2178
|
+
const contLines = [];
|
|
2179
|
+
const lines = after.split('\n');
|
|
2180
|
+
for (let li = 0; li < lines.length; li++) {
|
|
2181
|
+
const raw = lines[li];
|
|
2182
|
+
// The split's first element is the remainder of the captured first line's
|
|
2183
|
+
// own newline — an empty leading element is the line break, not a blank
|
|
2184
|
+
// continuation line.
|
|
2185
|
+
if (li === 0 && !raw.trim())
|
|
2186
|
+
continue;
|
|
2187
|
+
if (!raw.trim())
|
|
2188
|
+
break;
|
|
2189
|
+
// #4837: a list item is a structural boundary — the real corruption
|
|
2190
|
+
// vector (a `- Deferred to Phase N: OTHER-ID` bullet folding a foreign
|
|
2191
|
+
// REQ-ID into this field's citation-scan input).
|
|
2192
|
+
if (/^\s*[-*+]\s/.test(raw))
|
|
2193
|
+
break;
|
|
2194
|
+
// #4837: case-insensitive label-start character class — a
|
|
2195
|
+
// lowercase-first-letter label (`**requirements:**`) is as much a field
|
|
2196
|
+
// boundary as a capitalized one.
|
|
2197
|
+
if (/^\s*\*\*[A-Za-z][A-Za-z ]*:?(\*\*)?:?\s/.test(raw))
|
|
2198
|
+
break;
|
|
2199
|
+
if (/^\s*#{1,4}\s/.test(raw))
|
|
2200
|
+
break;
|
|
2201
|
+
if (/^\s*\|/.test(raw))
|
|
2202
|
+
break;
|
|
2203
|
+
// #4837: a fenced code block opener stops the scan — folding fence
|
|
2204
|
+
// content is never safe, and stopping early is conservative.
|
|
2205
|
+
if (/^\s*(?:`{3,}|~{3,})/.test(raw))
|
|
2206
|
+
break;
|
|
2207
|
+
contLines.push(raw.trim());
|
|
2208
|
+
}
|
|
2209
|
+
return [firstLine, ...contLines].join(' ').trim() || null;
|
|
2210
|
+
}
|
|
2018
2211
|
module.exports = {
|
|
2019
2212
|
stripShippedMilestones,
|
|
2020
2213
|
extractCurrentMilestone,
|
|
@@ -2036,6 +2229,7 @@ module.exports = {
|
|
|
2036
2229
|
// own doc comment. milestone.cts's destructive-consumer guard consumes
|
|
2037
2230
|
// this instead of composing locate+select+section-end itself.
|
|
2038
2231
|
sliceMilestoneWindow,
|
|
2232
|
+
milestoneSections,
|
|
2039
2233
|
hasVersionedMilestones,
|
|
2040
2234
|
hasMilestoneSectioning,
|
|
2041
2235
|
// #3642: the >=1 sibling buildStateFrontmatter's unbounded branch consumes.
|
|
@@ -2049,9 +2243,16 @@ module.exports = {
|
|
|
2049
2243
|
// guards and the edit-phase workflow's pre/post capture are built on.
|
|
2050
2244
|
scanMilestonePhaseIds,
|
|
2051
2245
|
collectTablePhaseRows,
|
|
2246
|
+
hasPhaseListingTableHeader,
|
|
2052
2247
|
findMilestoneScopeHeadingLines,
|
|
2053
2248
|
// #3641: the scope axis's phase-ENTRY predicate, exported so roadmap
|
|
2054
2249
|
// validate's V004 document-level check routes through the same single
|
|
2055
2250
|
// owner (and its convention gate) instead of a private inline copy.
|
|
2251
|
+
extractPhaseFieldMultiline,
|
|
2056
2252
|
hasPhaseEntries,
|
|
2253
|
+
// #4144 round 5 Blocker 1: the readers' own phase-heading grammar, so the
|
|
2254
|
+
// bracket roadmap migrator's "phase-like but unparsed" refusal
|
|
2255
|
+
// (src/roadmap-upgrade.cts) can gate on it instead of a private, looser
|
|
2256
|
+
// "starts with the word Phase" regex.
|
|
2257
|
+
isPhaseHeadingText,
|
|
2057
2258
|
};
|