@opengsd/gsd-core 1.14.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-code-fixer.compact.md +7 -6
- package/agents/gsd-code-fixer.md +9 -8
- package/agents/gsd-debug-session-manager.compact.md +17 -2
- package/agents/gsd-debug-session-manager.md +17 -2
- 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 +13 -8
- package/agents/gsd-intel-updater.compact.md +1 -1
- package/agents/gsd-intel-updater.md +1 -1
- 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 +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.md +155 -17
- package/agents/gsd-ui-researcher.compact.md +1 -1
- package/agents/gsd-ui-researcher.md +1 -1
- package/agents/gsd-verifier.md +10 -9
- package/bin/install.js +642 -95
- package/commands/gsd/autonomous.md +2 -2
- package/commands/gsd/capture.md +1 -1
- package/commands/gsd/mempalace-capture.md +7 -3
- package/commands/gsd/plan-review-convergence.md +6 -6
- package/commands/gsd/progress.md +1 -1
- package/commands/gsd/quick-batch.md +1 -1
- package/commands/gsd/review.md +2 -3
- package/gsd-core/bin/gsd-tools.cjs +335 -22
- package/gsd-core/bin/lib/adr-parser.cjs +3 -1
- package/gsd-core/bin/lib/audit.cjs +81 -13
- package/gsd-core/bin/lib/capability-registry.cjs +82 -187
- package/gsd-core/bin/lib/capability-validator.cjs +0 -1
- package/gsd-core/bin/lib/check-command-router.cjs +101 -14
- package/gsd-core/bin/lib/codex-agent-toml.cjs +21 -25
- package/gsd-core/bin/lib/commands.cjs +175 -42
- package/gsd-core/bin/lib/config-loader.cjs +65 -4
- package/gsd-core/bin/lib/config.cjs +33 -7
- package/gsd-core/bin/lib/decisions.cjs +30 -14
- package/gsd-core/bin/lib/frontmatter.cjs +13 -0
- package/gsd-core/bin/lib/graphify.cjs +10 -2
- package/gsd-core/bin/lib/host-runtime-detection.cjs +9 -0
- package/gsd-core/bin/lib/init.cjs +207 -41
- package/gsd-core/bin/lib/install-engine.cjs +13 -0
- package/gsd-core/bin/lib/installer-migrations.cjs +8 -1
- package/gsd-core/bin/lib/milestone.cjs +18 -5
- package/gsd-core/bin/lib/model-resolver.cjs +159 -50
- package/gsd-core/bin/lib/phase-command-router.cjs +9 -1
- 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 +109 -7
- package/gsd-core/bin/lib/phase-locator.cjs +29 -10
- package/gsd-core/bin/lib/phase.cjs +227 -26
- 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 +18 -1
- package/gsd-core/bin/lib/planning-workspace.cjs +8 -3
- package/gsd-core/bin/lib/pr-branch-patterns.cjs +57 -0
- package/gsd-core/bin/lib/probe-core.cjs +7 -1
- package/gsd-core/bin/lib/project-root.cjs +41 -2
- package/gsd-core/bin/lib/review-lane-descriptor.cjs +10 -30
- package/gsd-core/bin/lib/review-reviewer-selection.cjs +2 -2
- package/gsd-core/bin/lib/roadmap-command-router.cjs +12 -4
- package/gsd-core/bin/lib/roadmap-parser.cjs +163 -3
- package/gsd-core/bin/lib/roadmap-upgrade.cjs +1539 -13
- package/gsd-core/bin/lib/roadmap.cjs +251 -31
- package/gsd-core/bin/lib/runtime-artifact-conversion.cjs +283 -31
- package/gsd-core/bin/lib/runtime-artifact-install-plan.cjs +3 -1
- package/gsd-core/bin/lib/runtime-homes.cjs +4 -0
- package/gsd-core/bin/lib/runtime-hooks-surface.cjs +215 -33
- package/gsd-core/bin/lib/runtime-name-policy.cjs +111 -1
- package/gsd-core/bin/lib/shell-command-projection.cjs +10 -6
- package/gsd-core/bin/lib/state-transition.cjs +39 -2
- package/gsd-core/bin/lib/state.cjs +42 -0
- package/gsd-core/bin/lib/surface.cjs +17 -1
- 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 +8 -0
- 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/verification.cjs +268 -15
- package/gsd-core/bin/lib/verify-command-grounding.cjs +46 -2
- package/gsd-core/bin/lib/verify.cjs +132 -25
- package/gsd-core/bin/lib/worktree-base-ref.cjs +482 -73
- package/gsd-core/bin/lib/worktree-safety.cjs +784 -51
- package/gsd-core/bin/shared/config-defaults.manifest.json +3 -0
- package/gsd-core/bin/shared/config-schema.manifest.json +1 -0
- package/gsd-core/references/checkpoints.md +5 -3
- package/gsd-core/references/edge-probe-fixtures/01-round-half-even/expected-coverage.json +28 -3
- package/gsd-core/references/edge-probe-fixtures/02-merge-intervals/expected-coverage.json +37 -4
- package/gsd-core/references/edge-probe-fixtures/03-truncate-graphemes/expected-coverage.json +28 -3
- package/gsd-core/references/edge-probe-fixtures/04-money-rounding/expected-coverage.json +28 -3
- package/gsd-core/references/edge-probe-fixtures/05-list-dedupe/expected-coverage.json +37 -4
- package/gsd-core/references/edge-probe-fixtures/06-resolved-mixed/expected-coverage.json +37 -4
- package/gsd-core/references/edge-probe.md +195 -21
- package/gsd-core/references/execute-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/model-profiles.md +1 -1
- package/gsd-core/references/phase-argument-parsing.md +9 -7
- package/gsd-core/references/phase-id-convention.md +28 -0
- package/gsd-core/references/planner-gap-closure.md +2 -0
- package/gsd-core/references/planner-load-graph-context.md +24 -13
- package/gsd-core/references/planner-verify-command-grounding.md +14 -0
- package/gsd-core/references/planning-config.md +11 -2
- package/gsd-core/references/tdd.md +27 -4
- package/gsd-core/references/ui-consideration-probe.md +10 -5
- package/gsd-core/references/verify-command-path-resolvability.md +10 -2
- package/gsd-core/references/worktree-path-safety.md +321 -0
- 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 +3 -3
- 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 +16 -6
- package/gsd-core/workflows/check-todos.md +2 -2
- package/gsd-core/workflows/cleanup.md +2 -2
- package/gsd-core/workflows/code-review/steps/dispatch-fix.md +4 -3
- package/gsd-core/workflows/code-review/steps/structural-pre-pass.md +1 -1
- package/gsd-core/workflows/code-review-fix.md +108 -22
- package/gsd-core/workflows/code-review.md +63 -46
- package/gsd-core/workflows/complete-milestone/detail/elaboration.md +1 -1
- package/gsd-core/workflows/complete-milestone.md +2 -2
- 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.md +3 -3
- 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 +2 -2
- package/gsd-core/workflows/execute-phase/steps/code-review-disposition.md +1017 -0
- package/gsd-core/workflows/execute-phase/steps/codebase-drift-gate.md +1 -1
- package/gsd-core/workflows/execute-phase/steps/completion-reconciliation.md +3 -3
- package/gsd-core/workflows/execute-phase/steps/executor-isolation-dispatch.md +37 -3
- 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/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 +36 -26
- package/gsd-core/workflows/execute-plan.md +5 -4
- 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 +3 -3
- package/gsd-core/workflows/help/modes/full.md +5 -5
- package/gsd-core/workflows/help/modes/topic.md +15 -5
- package/gsd-core/workflows/import.md +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 +2 -2
- 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 +2 -2
- package/gsd-core/workflows/new-project/steps/auto-mode-config.md +3 -3
- package/gsd-core/workflows/new-project/steps/codebase-map-offer.md +1 -1
- package/gsd-core/workflows/new-project.md +7 -7
- package/gsd-core/workflows/new-workspace.md +2 -2
- package/gsd-core/workflows/next.md +1 -1
- package/gsd-core/workflows/note.md +1 -1
- package/gsd-core/workflows/onboard.md +1 -1
- package/gsd-core/workflows/pause-work.md +1 -1
- package/gsd-core/workflows/plan-phase/detail/elaboration.md +1 -1
- package/gsd-core/workflows/plan-phase/steps/chunked-planning-mode.md +17 -5
- package/gsd-core/workflows/plan-phase/steps/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 +24 -7
- package/gsd-core/workflows/plan-review-convergence.md +21 -5
- package/gsd-core/workflows/plant-seed.md +62 -20
- package/gsd-core/workflows/pr-branch.md +113 -13
- package/gsd-core/workflows/profile-user.md +2 -2
- package/gsd-core/workflows/progress.md +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 +21 -9
- package/gsd-core/workflows/reapply-patches.md +9 -3
- 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 +4 -4
- 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 +7 -7
- package/gsd-core/workflows/validate-phase.md +3 -2
- 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 +81 -16
- package/hooks/dist/gsd-agent-isolation-guard.js +24 -0
- package/hooks/dist/gsd-secret-read-guard.js +27 -1
- package/hooks/dist/gsd-statusline.js +70 -13
- package/hooks/dist/gsd-validate-commit.sh +63 -4
- package/hooks/gsd-agent-isolation-guard.js +24 -0
- package/hooks/gsd-secret-read-guard.js +27 -1
- package/hooks/gsd-statusline.js +70 -13
- package/hooks/gsd-validate-commit.sh +63 -4
- package/package.json +3 -2
- package/scripts/build-hooks.js +15 -6
- package/scripts/check-contract-drift.cjs +127 -11
- package/scripts/command-contract-helpers.cjs +3 -0
- package/scripts/docs-guard-registry.cjs +28 -0
- package/scripts/gen-loop-host-contract.cjs +69 -0
- package/scripts/lib/macos-conformance-tier.generated.cjs +14 -0
- package/scripts/lib/ndjson-reporter.cjs +3 -2
- package/scripts/lib/platform-conformance-tier.generated.cjs +11 -0
- package/scripts/lint-docs-guard-registration.exempt-baseline.cjs +28 -1
- package/scripts/lint-phase-arg-assignment.cjs +257 -0
- package/scripts/lint-phase-id-drift.cjs +290 -5
- package/scripts/lint-pr-branch-pattern-drift.cjs +148 -0
- package/scripts/lint-retired-runtime-name.cjs +619 -0
- package/scripts/lint-state-write-path-drift.cjs +93 -0
- package/scripts/lint-test-file-count.allowlist.json +28 -9
- package/scripts/lint-workflow-shellcheck-baseline.json +15 -0
- package/scripts/prompt-injection-scan.sh +4 -0
- package/scripts/release-tarball-smoke.cjs +194 -1
- package/skills/gsd-autonomous/SKILL.md +2 -2
- package/skills/gsd-capture/SKILL.md +1 -1
- package/skills/gsd-mempalace-capture/SKILL.md +7 -3
- package/skills/gsd-plan-review-convergence/SKILL.md +5 -5
- package/skills/gsd-progress/SKILL.md +1 -1
- package/skills/gsd-quick-batch/SKILL.md +1 -1
- package/skills/gsd-review/SKILL.md +2 -3
- package/vscode/package.json +1 -1
|
@@ -28,7 +28,7 @@ const planningScopeMod = require("./planning-scope.cjs");
|
|
|
28
28
|
const { SCOPE } = planningScopeMod;
|
|
29
29
|
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
30
30
|
const roadmapParserModule = require("./roadmap-parser.cjs");
|
|
31
|
-
const { stripShippedMilestones, extractCurrentMilestone, extractCurrentMilestoneScoped, replaceInCurrentMilestone, listMilestoneHeadings, scanMilestonePhaseIds, collectTablePhaseRows } = roadmapParserModule;
|
|
31
|
+
const { stripShippedMilestones, extractCurrentMilestone, extractCurrentMilestoneScoped, replaceInCurrentMilestone, listMilestoneHeadings, scanMilestonePhaseIds, collectTablePhaseRows, hasPhaseListingTableHeader } = roadmapParserModule;
|
|
32
32
|
const markdown_sectionizer_cjs_1 = require("./markdown-sectionizer.cjs");
|
|
33
33
|
const markdown_table_cjs_1 = require("./markdown-table.cjs");
|
|
34
34
|
const phase_lifecycle_cjs_1 = require("./phase-lifecycle.cjs");
|
|
@@ -52,6 +52,9 @@ const { extractFrontmatter, parseMustHavesBlock } = frontmatter;
|
|
|
52
52
|
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
53
53
|
const verificationMod = require("./verification.cjs");
|
|
54
54
|
const { isPhaseComplete } = verificationMod;
|
|
55
|
+
// #4906 Phase 2 (#4917/ADR-4910): the PlanningDoc parse -> mutate -> serialize
|
|
56
|
+
// seam, mirroring phase.cts's already-migrated `writePlansField` site.
|
|
57
|
+
const planning_document_cjs_1 = require("./planning-document.cjs");
|
|
55
58
|
// ─── coerceTruthToString ──────────────────────────────────────────────────────
|
|
56
59
|
/**
|
|
57
60
|
* Coerce an arbitrary YAML scalar/object into a string for cross-cutting
|
|
@@ -170,9 +173,9 @@ function searchPhaseInContent(content, escapedPhase, phaseNum, convention) {
|
|
|
170
173
|
.find((candidate) => candidate.level <= currentHeading.level);
|
|
171
174
|
const sectionEnd = nextHeading ? nextHeading.offset : content.length;
|
|
172
175
|
const section = content.slice(headerIndex, sectionEnd).trim();
|
|
173
|
-
// Extract goal if present (supports both **Goal:** and **Goal**: formats)
|
|
174
|
-
|
|
175
|
-
const goal =
|
|
176
|
+
// Extract goal if present (supports both **Goal:** and **Goal**: formats).
|
|
177
|
+
// #4731: multiline-aware — hard-wrapped Goals read past the line break.
|
|
178
|
+
const goal = roadmapParserModule.extractPhaseFieldMultiline(section, 'Goal');
|
|
176
179
|
// Mode: vertical-MVP slice mode flag. Lowercased + trimmed for canonical
|
|
177
180
|
// comparison; unrecognized values are preserved verbatim for forward-compat.
|
|
178
181
|
const modeMatch = section.match(/\*\*Mode(?::\*\*|\*\*:)\s*([^\n]+)/i);
|
|
@@ -392,8 +395,7 @@ function collectAnalyzePhases(content, phasesDir, phaseDirNames, convention) {
|
|
|
392
395
|
const nextHeader = restOfContent.match(new RegExp(`\\n {0,3}#{2,4}\\s+${phaseHeadingPrefixSrcFor(PHASE_HEADING_BASELINE.ANY_BRACKET, convention)}[A-Za-z]?\\d[\\d.-]*`, 'i'));
|
|
393
396
|
const sectionEnd = nextHeader ? sectionStart + nextHeader.index : content.length;
|
|
394
397
|
const section = content.slice(sectionStart, sectionEnd);
|
|
395
|
-
const
|
|
396
|
-
const goal = goalMatch ? goalMatch[1].trim() : null;
|
|
398
|
+
const goal = roadmapParserModule.extractPhaseFieldMultiline(section, 'Goal');
|
|
397
399
|
const modeMatch = section.match(/\*\*Mode(?::\*\*|\*\*:)\s*([^\n]+)/i);
|
|
398
400
|
const mode = modeMatch ? modeMatch[1].trim().toLowerCase() : null;
|
|
399
401
|
const dependsMatch = section.match(/\*\*Depends on(?::\*\*|\*\*:)\s*([^\n]+)/i);
|
|
@@ -658,7 +660,94 @@ function cmdRoadmapAnalyze(cwd, raw) {
|
|
|
658
660
|
if (seenChecklistKeys.has(key))
|
|
659
661
|
continue;
|
|
660
662
|
seenChecklistKeys.add(key);
|
|
661
|
-
|
|
663
|
+
// #4899: the checkbox state (`[x]` vs `[ ]`) isn't a capturing group in
|
|
664
|
+
// `checklistPattern` — adding one would shift every downstream `1 + G` /
|
|
665
|
+
// `G` index this loop and `missingDetails` below already depend on.
|
|
666
|
+
// Reading it off the full match text instead is index-safe.
|
|
667
|
+
checklistOccurrences.push({ token, bracketId, checked: /\[x\]/i.test(checklistMatch[0]) });
|
|
668
|
+
}
|
|
669
|
+
// #4899: `collectAnalyzePhases` only recognises `### Phase N:` headings and
|
|
670
|
+
// progress-table rows — the shape `templates/roadmap.md` itself emits
|
|
671
|
+
// (checklist entries only, no detail sections yet) produces `phases: []`
|
|
672
|
+
// even though `checklistOccurrences` above just proved real phases exist.
|
|
673
|
+
// That evidence was computed and then discarded on the way to the final
|
|
674
|
+
// `phases: []` output (ADR-4910 §5/Phase 4). When the heading/table scan
|
|
675
|
+
// found nothing but the checklist did, synthesize a minimal `AnalyzePhase`
|
|
676
|
+
// per non-sentinel checklist occurrence — same enrichment calls
|
|
677
|
+
// (`matchPhaseDirs`, `countPhasePlansAndSummaries`, `isPhaseComplete`) the
|
|
678
|
+
// heading branch of `collectAnalyzePhases` already uses, so a synthesized
|
|
679
|
+
// phase's on-disk status is derived identically, not approximated.
|
|
680
|
+
//
|
|
681
|
+
// `missing_phase_details` is intentionally left untouched by this branch:
|
|
682
|
+
// its contract is "this checklist token has no `### Phase N:` heading or
|
|
683
|
+
// progress-table row", and that remains true for every synthesized token —
|
|
684
|
+
// synthesis fills in `phases[]` from the checklist itself, it does not
|
|
685
|
+
// manufacture a detail section. Removing these tokens from
|
|
686
|
+
// `missing_phase_details` would hide the very malformed-ROADMAP signal
|
|
687
|
+
// ADR-4910 (#4899) treats as evidence to surface, not evidence to launder.
|
|
688
|
+
//
|
|
689
|
+
// Gated on `!hasPhaseListingTableHeader(effectiveContent)` (found by the
|
|
690
|
+
// pre-existing #4480 regression "a status table cannot hide missing phase
|
|
691
|
+
// details"): a `| Phase | Status |`-shaped table with no Name column
|
|
692
|
+
// correctly declares no phases via `collectAnalyzePhases`, but its mere
|
|
693
|
+
// presence signals this roadmap has already moved to table-based tracking —
|
|
694
|
+
// synthesizing phantom phases from checklist entries alongside a
|
|
695
|
+
// deliberately thin tracking table would manufacture phase_count where the
|
|
696
|
+
// roadmap's own structure says "not yet detailed", the same laundering this
|
|
697
|
+
// branch exists to avoid for `missing_phase_details`. #4899's actual target
|
|
698
|
+
// shape (`templates/roadmap.md`: checklist only, no Progress section at
|
|
699
|
+
// all) has no such table and is unaffected.
|
|
700
|
+
if (phases.length === 0 && checklistOccurrences.length > 0 && !hasPhaseListingTableHeader(effectiveContent)) {
|
|
701
|
+
for (const occ of checklistOccurrences) {
|
|
702
|
+
if (isSentinelPhase(occ.token, occ.bracketId))
|
|
703
|
+
continue;
|
|
704
|
+
const normalized = normalizePhaseName(occ.token);
|
|
705
|
+
const dirMatch = matchPhaseDirs(_phaseDirNames, normalized, convention).matches[0];
|
|
706
|
+
let diskStatus = 'no_directory';
|
|
707
|
+
let planCount = 0;
|
|
708
|
+
let summaryCount = 0;
|
|
709
|
+
let hasContext = false;
|
|
710
|
+
let hasResearch = false;
|
|
711
|
+
let contextReadError = null;
|
|
712
|
+
let contextScope = SCOPE.COMPLETE;
|
|
713
|
+
if (dirMatch) {
|
|
714
|
+
const counts = countPhasePlansAndSummaries(node_path_1.default.join(phasesDir, dirMatch), convention);
|
|
715
|
+
planCount = counts.planCount;
|
|
716
|
+
summaryCount = counts.summaryCount;
|
|
717
|
+
hasContext = counts.hasContext;
|
|
718
|
+
hasResearch = counts.hasResearch;
|
|
719
|
+
contextReadError = counts.contextReadError;
|
|
720
|
+
contextScope = counts.scope;
|
|
721
|
+
const completionResult = isPhaseComplete(node_path_1.default.join(phasesDir, dirMatch), { convention });
|
|
722
|
+
if (completionResult.value.complete)
|
|
723
|
+
diskStatus = 'complete';
|
|
724
|
+
else if (summaryCount > 0)
|
|
725
|
+
diskStatus = 'partial';
|
|
726
|
+
else if (planCount > 0)
|
|
727
|
+
diskStatus = 'planned';
|
|
728
|
+
else if (hasResearch)
|
|
729
|
+
diskStatus = 'researched';
|
|
730
|
+
else if (hasContext)
|
|
731
|
+
diskStatus = 'discussed';
|
|
732
|
+
else
|
|
733
|
+
diskStatus = 'empty';
|
|
734
|
+
}
|
|
735
|
+
phases.push({
|
|
736
|
+
number: occ.token,
|
|
737
|
+
name: `Phase ${occ.token}`,
|
|
738
|
+
goal: null,
|
|
739
|
+
mode: null,
|
|
740
|
+
depends_on: null,
|
|
741
|
+
plan_count: planCount,
|
|
742
|
+
summary_count: summaryCount,
|
|
743
|
+
has_context: hasContext,
|
|
744
|
+
has_research: hasResearch,
|
|
745
|
+
disk_status: diskStatus,
|
|
746
|
+
roadmap_complete: occ.checked,
|
|
747
|
+
context_read_error: contextReadError,
|
|
748
|
+
context_scope: contextScope,
|
|
749
|
+
});
|
|
750
|
+
}
|
|
662
751
|
}
|
|
663
752
|
// The EMITTED value stays the bare token, unchanged: `phases[].number` is a
|
|
664
753
|
// token under every convention, and `missing_phase_details` is read against
|
|
@@ -923,10 +1012,19 @@ function cmdRoadmapUpdatePlanProgress(cwd, phaseNum, raw) {
|
|
|
923
1012
|
let roadmapContent = originalContent;
|
|
924
1013
|
const phasePattern = phaseMarkdownRegexSource(phaseNum);
|
|
925
1014
|
// #4247: ONE local source for the ATX phase-heading anchor that every
|
|
926
|
-
// section-scoped writer below (`
|
|
1015
|
+
// section-scoped writer below (`planSectionPattern`,
|
|
927
1016
|
// `insertRowsPatternA|B`) starts with — extracted so the target-detection
|
|
928
1017
|
// gate below reads the SAME grammar the writers anchor on, and a future
|
|
929
1018
|
// edit to one cannot drift from the other three copies.
|
|
1019
|
+
// #4906 Phase 5 (#4984): NOT migrated onto the heading-baseline selector —
|
|
1020
|
+
// this write-path anchor was never one of the five ADR-4910 §8 call sites
|
|
1021
|
+
// this phase owns (init.cts/milestone.cts's buildPhaseHeadingScanRegex
|
|
1022
|
+
// sites); a direct any-bracket selector call here would have added a
|
|
1023
|
+
// fourth uncounted ANY_BRACKET consumer to roadmap.cts's pinned
|
|
1024
|
+
// tests/adr-612-bracket-heading-selection.test.cjs census. Left
|
|
1025
|
+
// bracket-blind deliberately, matching this call's pre-#4984 behavior;
|
|
1026
|
+
// folding it into the census is Phase 6 work.
|
|
1027
|
+
// phase-id-owner: deliberately unmigrated (#4984 revert) — see comment above.
|
|
930
1028
|
const phaseHeadingAnchor = `#{2,4}\\s*Phase\\s+${phasePattern}${OPTIONAL_PHASE_TAG_SOURCE}(?=[:\\s])`;
|
|
931
1029
|
// #4247: target detection runs against the ORIGINAL content's active
|
|
932
1030
|
// (post-</details>) region — the same milestone scoping every writer
|
|
@@ -936,7 +1034,7 @@ function cmdRoadmapUpdatePlanProgress(cwd, phaseNum, raw) {
|
|
|
936
1034
|
const gateActiveRegion = gateDetailsClose === -1
|
|
937
1035
|
? originalContent
|
|
938
1036
|
: originalContent.slice(gateDetailsClose + '</details>'.length);
|
|
939
|
-
// Heading target: the exact grammar `
|
|
1037
|
+
// Heading target: the exact grammar `planSectionPattern` /
|
|
940
1038
|
// `insertRowsPatternA|B` anchor on (an ATX phase heading for this phase).
|
|
941
1039
|
const headingTargetFound = new RegExp(phaseHeadingAnchor, 'i').test(gateActiveRegion);
|
|
942
1040
|
// Checklist target: when the phase is complete, its own checklist bullet
|
|
@@ -1033,7 +1131,14 @@ function cmdRoadmapUpdatePlanProgress(cwd, phaseNum, raw) {
|
|
|
1033
1131
|
// `_match` unchanged. An untouched first line cannot orphan its own
|
|
1034
1132
|
// continuation on the next line, since the pattern never spans past
|
|
1035
1133
|
// `\n` in the first place.
|
|
1036
|
-
|
|
1134
|
+
// #4906 Phase 2 (#4917/ADR-4910): migrated off the one-capture-group
|
|
1135
|
+
// regex that replaced to end of line onto the PlanningDoc `boldField`
|
|
1136
|
+
// write seam. `planSectionPattern` scopes the match to phase N's OWN
|
|
1137
|
+
// detail section (heading + body up to the next heading) — the same
|
|
1138
|
+
// window `phaseHeadingAnchor`'s siblings anchor on — and the callback
|
|
1139
|
+
// below runs parse -> classify -> (maybe) mutate -> serialize entirely
|
|
1140
|
+
// within that section text, mirroring phase.cts's `writePlansField`.
|
|
1141
|
+
const planSectionPattern = new RegExp(`${phaseHeadingAnchor}(?:(?!\\n#{1,4}\\s)[\\s\\S])*`, 'i');
|
|
1037
1142
|
const planCountText = isComplete
|
|
1038
1143
|
? `${summaryCount}/${planCount} plans complete`
|
|
1039
1144
|
: `${summaryCount}/${planCount} plans executed`;
|
|
@@ -1042,24 +1147,107 @@ function cmdRoadmapUpdatePlanProgress(cwd, phaseNum, raw) {
|
|
|
1042
1147
|
// gsd-core/templates/roadmap.md actually ships, not to "anything in
|
|
1043
1148
|
// brackets" — a bracketed human annotation like `[Deferred pending
|
|
1044
1149
|
// re-scope]` is structurally bracketed too but carries none of this
|
|
1045
|
-
// wording, so it correctly falls through to arm 3 untouched.
|
|
1150
|
+
// wording, so it correctly falls through to arm 3 untouched. Kept as a
|
|
1151
|
+
// caller-side classifier (NOT seam grammar) reused below against the
|
|
1152
|
+
// `boldField` node's own parsed `value`.
|
|
1046
1153
|
const isTemplatePlaceholder = (value) => {
|
|
1047
1154
|
const trimmed = value.trim();
|
|
1048
1155
|
return /^\[\s*Number of plans\b[\s\S]*\]$/i.test(trimmed);
|
|
1049
1156
|
};
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1157
|
+
// Positive detectors for the two "real count token" shapes (#2853 /
|
|
1158
|
+
// #3584 Finding B): a fraction count (`N/M plans complete|executed`) or a
|
|
1159
|
+
// bare singular/plural count (`N plan`/`N plans`, the fresh single-plan
|
|
1160
|
+
// template shape at gsd-core/templates/roadmap.md:62). Either one is an
|
|
1161
|
+
// existing count token to overwrite (arm 1), never template placeholder
|
|
1162
|
+
// (arm 2) or freeform prose (arm 3).
|
|
1163
|
+
// #4906 regression fix: PREFIX match (not full-string) — a real count
|
|
1164
|
+
// token may have a glued-on annotation with no ` — ` separator (e.g.
|
|
1165
|
+
// `0/1 plans executed (11-16 are gap closure from VERIFICATION)`), which
|
|
1166
|
+
// `parseBoldFieldLine`'s em-dash-only trailing-content split leaves
|
|
1167
|
+
// entirely inside `value` (TRAILING_SEPARATOR_RE in planning-document.cts
|
|
1168
|
+
// is unchanged and correct — this is a caller-side classification fix,
|
|
1169
|
+
// not a seam fix). Returns the matched prefix length, or -1 if no match.
|
|
1170
|
+
const fractionCountPrefixLength = (value) => {
|
|
1171
|
+
const m = value.match(/^\d+\s*\/\s*\d+\s+plans(?:\s+(?:complete|executed))?/i);
|
|
1172
|
+
return m ? m[0].length : -1;
|
|
1173
|
+
};
|
|
1174
|
+
const bareCountPrefixLength = (value) => {
|
|
1175
|
+
const m = value.match(/^\d+\s+plans?/i);
|
|
1176
|
+
return m ? m[0].length : -1;
|
|
1177
|
+
};
|
|
1178
|
+
roadmapContent = replaceInCurrentMilestone(roadmapContent, planSectionPattern, (sectionText) => {
|
|
1179
|
+
const parsed = (0, planning_document_cjs_1.parsePlanningDoc)(sectionText, 'ROADMAP.md');
|
|
1180
|
+
if (!parsed.ok) {
|
|
1181
|
+
// Unreadable section (e.g. an unterminated frontmatter fence) —
|
|
1182
|
+
// leave it byte-identical rather than throwing.
|
|
1183
|
+
return sectionText;
|
|
1054
1184
|
}
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1185
|
+
const fieldId = (0, planning_document_cjs_1.findField)(parsed.value, 'Plans');
|
|
1186
|
+
if (!fieldId) {
|
|
1187
|
+
// #4906 regression (#1163, caught by gsd-test): a hand-edited or
|
|
1188
|
+
// pre-template ROADMAP.md may carry a PLAIN (non-bold) `Plans:` line
|
|
1189
|
+
// rather than the canonical `**Plans**:`/`**Plans:**` bold field.
|
|
1190
|
+
// BOLD_FIELD_RE is deliberately bold-only (widening it to any bare
|
|
1191
|
+
// `Label:` would register ordinary prose like "Note: see below" as a
|
|
1192
|
+
// spurious field seam-wide) — this is domain knowledge about ONE
|
|
1193
|
+
// field's legacy tolerated shape, the same class of thing
|
|
1194
|
+
// `isTemplatePlaceholder` above already keeps caller-side rather
|
|
1195
|
+
// than seam grammar, so the fallback lives here, not in
|
|
1196
|
+
// planning-document.cts.
|
|
1197
|
+
const plainMatch = sectionText.match(/^([ \t]*)Plans:([ \t]*)([^\r\n]*)$/m);
|
|
1198
|
+
if (!plainMatch) {
|
|
1199
|
+
// No `**Plans:**`/`**Plans**:`/plain `Plans:` line in this phase's
|
|
1200
|
+
// own section — nothing to write; not a failure (mirrors the old
|
|
1201
|
+
// regex's silent no-match no-op).
|
|
1202
|
+
return sectionText;
|
|
1203
|
+
}
|
|
1204
|
+
const [whole, indent, spacing, plainValue] = plainMatch;
|
|
1205
|
+
const plainFractionLen = fractionCountPrefixLength(plainValue);
|
|
1206
|
+
const plainBareLen = bareCountPrefixLength(plainValue);
|
|
1207
|
+
const plainCountPrefixLen = plainFractionLen >= 0 ? plainFractionLen : plainBareLen;
|
|
1208
|
+
if (plainCountPrefixLen < 0 && !isTemplatePlaceholder(plainValue)) {
|
|
1209
|
+
// Arm 3: freeform prose, TBD, a bracketed human annotation, or an
|
|
1210
|
+
// empty value — leave the section exactly as it was.
|
|
1211
|
+
return sectionText;
|
|
1212
|
+
}
|
|
1213
|
+
const plainSuffix = plainCountPrefixLen >= 0 ? plainValue.slice(plainCountPrefixLen) : '';
|
|
1214
|
+
const newPlainLine = `${indent}Plans:${spacing}${planCountText}${plainSuffix}`;
|
|
1215
|
+
const start = plainMatch.index ?? sectionText.indexOf(whole);
|
|
1216
|
+
return sectionText.slice(0, start) + newPlainLine + sectionText.slice(start + whole.length);
|
|
1217
|
+
}
|
|
1218
|
+
const current = (0, planning_document_cjs_1.readNode)(parsed.value, fieldId);
|
|
1219
|
+
if (!current.ok) {
|
|
1220
|
+
return sectionText;
|
|
1221
|
+
}
|
|
1222
|
+
const currentValue = current.value;
|
|
1223
|
+
const fractionPrefixLen = fractionCountPrefixLength(currentValue);
|
|
1224
|
+
const barePrefixLen = bareCountPrefixLength(currentValue);
|
|
1225
|
+
const countPrefixLen = fractionPrefixLen >= 0 ? fractionPrefixLen : barePrefixLen;
|
|
1226
|
+
if (countPrefixLen < 0 && !isTemplatePlaceholder(currentValue)) {
|
|
1227
|
+
// Arm 3: freeform prose, TBD, a bracketed human annotation, or an
|
|
1228
|
+
// empty value — leave the section exactly as it was.
|
|
1229
|
+
return sectionText;
|
|
1058
1230
|
}
|
|
1059
|
-
// Arm
|
|
1060
|
-
//
|
|
1061
|
-
//
|
|
1062
|
-
|
|
1231
|
+
// Arm 1 (real count token, possibly with a glued-on no-separator
|
|
1232
|
+
// annotation re-attached verbatim as `suffix`) or arm 2 (fresh-template
|
|
1233
|
+
// placeholder, whole value replaced): write the computed count.
|
|
1234
|
+
// `setFieldValue`'s valueSpan/trailingSpan split additionally preserves
|
|
1235
|
+
// any EM-DASH-separated trailing annotation (#2853) automatically — no
|
|
1236
|
+
// separate "preserve trailing" branch needed for that shape.
|
|
1237
|
+
const suffix = countPrefixLen >= 0 ? currentValue.slice(countPrefixLen) : '';
|
|
1238
|
+
const newValueToWrite = planCountText + suffix;
|
|
1239
|
+
const staged = (0, planning_document_cjs_1.setFieldValue)(parsed.value, fieldId, newValueToWrite);
|
|
1240
|
+
if (!staged.ok) {
|
|
1241
|
+
return sectionText;
|
|
1242
|
+
}
|
|
1243
|
+
const out = (0, planning_document_cjs_1.serialize)(staged.value);
|
|
1244
|
+
if (!out.ok) {
|
|
1245
|
+
// `hasUnreadableNodes` refusal (ADR-4910 amendment) — a ragged
|
|
1246
|
+
// SIBLING node elsewhere in this same section refuses the whole
|
|
1247
|
+
// splice. Never throw; leave the section unchanged.
|
|
1248
|
+
return sectionText;
|
|
1249
|
+
}
|
|
1250
|
+
return out.value;
|
|
1063
1251
|
});
|
|
1064
1252
|
// If complete: check checkbox
|
|
1065
1253
|
if (isComplete) {
|
|
@@ -1067,10 +1255,17 @@ function cmdRoadmapUpdatePlanProgress(cwd, phaseNum, raw) {
|
|
|
1067
1255
|
roadmapContent = replaceInCurrentMilestone(roadmapContent, checkboxPattern, `$1x$2 (completed ${today})`);
|
|
1068
1256
|
}
|
|
1069
1257
|
// Mark completed plan checkboxes (e.g. "- [ ] 50-01-PLAN.md", "- [ ] 50-01:", or "- [ ] **50-01**")
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1258
|
+
// #4741: tick only plans the phase's own COUNT still counts. `plans` is the
|
|
1259
|
+
// superseded-filtered set (#2349 via scanPhasePlans) while `summaries` is
|
|
1260
|
+
// the raw *-SUMMARY.md listing — a superseded plan can carry a SUMMARY
|
|
1261
|
+
// (e.g. `status: halted`), and ticking it read as "executed" right under a
|
|
1262
|
+
// count line that excludes it. The prefix match mirrors the checkbox regex
|
|
1263
|
+
// below (rows match by planId prefix, which the PLAN-01.md naming shape
|
|
1264
|
+
// relies on), so non-superseded plans tick exactly as before.
|
|
1265
|
+
const tickableSummaries = phaseInfo.summaries
|
|
1266
|
+
.map((summaryFile) => ({ summaryFile, planId: summaryFile.replace('-SUMMARY.md', '').replace('SUMMARY.md', '') }))
|
|
1267
|
+
.filter(({ planId }) => planId !== '' && phaseInfo.plans.some((planFile) => planFile.startsWith(planId)));
|
|
1268
|
+
for (const { planId } of tickableSummaries) {
|
|
1074
1269
|
const planEscaped = (0, pattern_cjs_1.escapeRegex)(planId);
|
|
1075
1270
|
const planCheckboxPattern = new RegExp(`(-\\s*\\[) (\\]\\s*(?:\\*\\*)?${planEscaped}(?:\\*\\*)?)`, 'i');
|
|
1076
1271
|
roadmapContent = roadmapContent.replace(planCheckboxPattern, '$1x$2');
|
|
@@ -1094,9 +1289,26 @@ function cmdRoadmapUpdatePlanProgress(cwd, phaseNum, raw) {
|
|
|
1094
1289
|
// Detection is scoped to the active region so a plan that appears in an
|
|
1095
1290
|
// archived <details> block is still correctly detected as missing from the
|
|
1096
1291
|
// active milestone section.
|
|
1292
|
+
//
|
|
1293
|
+
// #4786: a plan row may be written WITH the `-PLAN.md` suffix (canonical
|
|
1294
|
+
// template form) or WITHOUT it (hand-written form: `- [x] 659-01 — desc`).
|
|
1295
|
+
// The tick loop above keys on the bare planId stem with a PREFIX match
|
|
1296
|
+
// (pre-existing, out of scope here), while detection required the full
|
|
1297
|
+
// `-PLAN.md` filename — so every suffix-less row was counted missing and
|
|
1298
|
+
// the insertion fired BESIDE the recognized list — 32 checkbox lines for
|
|
1299
|
+
// 16 plans, exit 0. The stem arm below accepts the bare id only up to a
|
|
1300
|
+
// boundary (whitespace / `:` / dashes / `-PLAN.md` / `.md` / `**` / `)`),
|
|
1301
|
+
// so `5-011` never satisfies `5-01`. Deliberately NOT in the boundary set:
|
|
1302
|
+
// `.` — a dotted sub-id (`5-01.5`) is a real distinct plan, and counting
|
|
1303
|
+
// its row as 5-01's presence would suppress a genuine insertion.
|
|
1097
1304
|
const missingPlans = phaseInfo.plans.filter((planFile) => {
|
|
1098
1305
|
const planEscaped = (0, pattern_cjs_1.escapeRegex)(planFile);
|
|
1099
|
-
|
|
1306
|
+
if (new RegExp(`-\\s*\\[[x ]\\]\\s*(?:\\*\\*)?${planEscaped}`, 'i').test(activeRegion))
|
|
1307
|
+
return false;
|
|
1308
|
+
const stem = planFile.replace(/-PLAN\.md$/i, '');
|
|
1309
|
+
const stemEscaped = (0, pattern_cjs_1.escapeRegex)(stem);
|
|
1310
|
+
const stemPresent = new RegExp(`-\\s*\\[[x ]\\]\\s*(?:\\*\\*)?${stemEscaped}(?=$|\\s|:|—|–|-PLAN\\.md|\\.md|\\*\\*|\\))`, 'i').test(activeRegion);
|
|
1311
|
+
return !stemPresent;
|
|
1100
1312
|
});
|
|
1101
1313
|
if (missingPlans.length > 0) {
|
|
1102
1314
|
// Insert missing plan checklist rows (#1163). We prefer to anchor to the
|
|
@@ -1139,10 +1351,9 @@ function cmdRoadmapUpdatePlanProgress(cwd, phaseNum, raw) {
|
|
|
1139
1351
|
if (withRows !== roadmapContent) {
|
|
1140
1352
|
roadmapContent = withRows;
|
|
1141
1353
|
// Mark any newly-inserted rows that already have summaries as complete
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
continue;
|
|
1354
|
+
// (#4741: same superseded-filtered tick list as the loop above — a
|
|
1355
|
+
// pre-existing superseded row must stay unchecked on this path too).
|
|
1356
|
+
for (const { planId } of tickableSummaries) {
|
|
1146
1357
|
const planEscaped = (0, pattern_cjs_1.escapeRegex)(planId);
|
|
1147
1358
|
const planCheckboxPattern = new RegExp(`(-\\s*\\[) (\\]\\s*(?:\\*\\*)?${planEscaped}(?:\\*\\*)?)`, 'i');
|
|
1148
1359
|
roadmapContent = roadmapContent.replace(planCheckboxPattern, '$1x$2');
|
|
@@ -1299,6 +1510,15 @@ function cmdRoadmapAnnotateDependencies(cwd, phaseNum, raw) {
|
|
|
1299
1510
|
// #3537: padding-tolerant fragment so the caller's resolved padded id
|
|
1300
1511
|
// matches un-padded ROADMAP headings.
|
|
1301
1512
|
const phaseEscaped = phaseMarkdownRegexSource(phaseNum);
|
|
1513
|
+
// #4906 Phase 5 (#4984): NOT migrated onto the heading-baseline selector —
|
|
1514
|
+
// this site was never one of the five ADR-4910 §8 call sites this phase
|
|
1515
|
+
// owns (init.cts/milestone.cts's buildPhaseHeadingScanRegex sites); a
|
|
1516
|
+
// direct any-bracket selector call here would have added a fifth
|
|
1517
|
+
// uncounted ANY_BRACKET consumer to roadmap.cts's pinned
|
|
1518
|
+
// tests/adr-612-bracket-heading-selection.test.cjs census. Left
|
|
1519
|
+
// bracket-blind deliberately, matching this call's pre-#4984 behavior;
|
|
1520
|
+
// folding it into the census is Phase 6 work.
|
|
1521
|
+
// phase-id-owner: deliberately unmigrated (#4984 revert) — see comment above.
|
|
1302
1522
|
const phaseHeaderPattern = new RegExp(`(#{2,4}\\s*Phase\\s+${phaseEscaped}${OPTIONAL_PHASE_TAG_SOURCE}:[^\\n]*)`, 'i');
|
|
1303
1523
|
const phaseMatch = content.match(phaseHeaderPattern);
|
|
1304
1524
|
if (!phaseMatch)
|