fix(#2090): restore unrelated files accidentally deleted/modified by subagent
The implementation subagent cross-contaminated the branch with changes from PR #2121 (phase-identifier parsing consolidation): - Deleted docs/adr/2121-phase-identifier-parsing-consolidation.md (restored) - Deleted src/phase-id.cts (restored) - Deleted tests/phase-id.test.cjs (restored) - Modified src/roadmap-parser.cts (restored to origin/next) - Modified src/state.cts (restored to origin/next) None of these are related to the Cline EoS migration.
This commit is contained in:
@@ -16,7 +16,7 @@ import configLoaderMod = require('./config-loader.cjs');
|
|||||||
const { loadConfig } = configLoaderMod;
|
const { loadConfig } = configLoaderMod;
|
||||||
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
||||||
import phaseIdMod = require('./phase-id.cjs');
|
import phaseIdMod = require('./phase-id.cjs');
|
||||||
const { escapeRegex, normalizePhaseName, extractPhaseToken, parsePhaseFromProse } = phaseIdMod;
|
const { escapeRegex, normalizePhaseName, extractPhaseToken } = phaseIdMod;
|
||||||
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
||||||
import roadmapParserMod = require('./roadmap-parser.cjs');
|
import roadmapParserMod = require('./roadmap-parser.cjs');
|
||||||
const { getMilestoneInfo, getMilestonePhaseFilter, extractCurrentMilestone } = roadmapParserMod;
|
const { getMilestoneInfo, getMilestonePhaseFilter, extractCurrentMilestone } = roadmapParserMod;
|
||||||
@@ -1116,13 +1116,22 @@ function matchSessionSection(body: string): RegExpMatchArray | null {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function parseProsePhaseField(value: string | null): { phase: string | null; name: string | null } {
|
function parseProsePhaseField(value: string | null): { phase: string | null; name: string | null } {
|
||||||
// #2121 Phase 2 (#2125): delegate to the canonical anchored parser so this
|
if (!value) return { phase: null, name: null };
|
||||||
// module holds no independent prose phase-id regex. Drives #2111 — the
|
const phaseMatch = value.match(/\b(\d+[A-Z]?(?:\.\d+)*)\b/i);
|
||||||
// anchored parser returns { phase: null } for a "Milestone vX.Y complete"
|
// #2124 review: length-bound the name quantifiers so a crafted long
|
||||||
// body line (the old unanchored regex mined the minor-version digit, e.g.
|
// unterminated `(` / `—` run in an untrusted STATE.md field cannot drive
|
||||||
// v0.5 -> "5"), so syncStateFrontmatter's #905 guard preserves the real
|
// O(n^2) backtracking (CPU DoS). (Phase 2 / #2125 supersedes this function
|
||||||
// current_phase instead of clobbering it.
|
// by delegating to phase-id.cts:parsePhaseFromProse, which is bounded too.)
|
||||||
return parsePhaseFromProse(value);
|
const parenName = value.match(/\(([^)]{1,200})\)/);
|
||||||
|
const dashName = value.match(/—\s*([^(\n]{1,200}?)(?:\s*\(|$)/);
|
||||||
|
const rawName = parenName?.[1] ?? dashName?.[1] ?? null;
|
||||||
|
const name = rawName && !/^(?:complete|executing|not started)$/i.test(rawName.trim())
|
||||||
|
? rawName.trim()
|
||||||
|
: null;
|
||||||
|
return {
|
||||||
|
phase: phaseMatch ? phaseMatch[1] : null,
|
||||||
|
name,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function parseProseLastActivityField(value: string | null): { date: string | null; description: string | null } {
|
function parseProseLastActivityField(value: string | null): { date: string | null; description: string | null } {
|
||||||
@@ -2713,13 +2722,9 @@ function resolvePhaseIdForCompletePhase(content: string, overridePhase: string |
|
|||||||
stateExtractField(content, 'Phase') ||
|
stateExtractField(content, 'Phase') ||
|
||||||
'';
|
'';
|
||||||
|
|
||||||
// #2125: parse via the canonical anchored parser so a narrative `Phase:`
|
// Accept canonical phase token only (e.g. 3, 03, 3A, 3.3, 10.2)
|
||||||
// body line (e.g. "Milestone v0.5 complete") does not mine a bogus token —
|
const phaseMatch = String(candidate).match(/(\d+[A-Z]?(?:\.\d+)*)/i);
|
||||||
// the old unanchored regex yielded "0.5" and rewrote STATE.md as
|
return phaseMatch ? phaseMatch[1] : null;
|
||||||
// "Phase 0.5 complete". A canonical token at the start of the value
|
|
||||||
// (3, 03, 3A, 3.3, 10.2, "3 of 5", "1 — Setup") is preserved; a milestone
|
|
||||||
// closure line yields null, so the caller's "unable to resolve" guard fires.
|
|
||||||
return parsePhaseFromProse(candidate).phase;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function cmdStateCompletePhase(cwd: string, raw: boolean, overridePhase?: string): void {
|
function cmdStateCompletePhase(cwd: string, raw: boolean, overridePhase?: string): void {
|
||||||
@@ -2746,9 +2751,8 @@ function cmdStateCompletePhase(cwd: string, raw: boolean, overridePhase?: string
|
|||||||
// The handler is now a no-op in that case so re-invocation from downstream
|
// The handler is now a no-op in that case so re-invocation from downstream
|
||||||
// workflows cannot regress the project state.
|
// workflows cannot regress the project state.
|
||||||
const existingCurrentPhaseRaw = stateExtractField(content, 'Current Phase') || '';
|
const existingCurrentPhaseRaw = stateExtractField(content, 'Current Phase') || '';
|
||||||
// #2125: same canonical parser as resolvePhaseIdForCompletePhase so the two
|
const existingCurrentPhaseMatch = String(existingCurrentPhaseRaw).match(/(\d+[A-Z]?(?:\.\d+)*)/i);
|
||||||
// sites cannot diverge on the token they extract.
|
const existingCurrentPhase = existingCurrentPhaseMatch ? existingCurrentPhaseMatch[1] : null;
|
||||||
const existingCurrentPhase = parsePhaseFromProse(existingCurrentPhaseRaw).phase;
|
|
||||||
if (existingCurrentPhase && existingCurrentPhase !== resolvedPhase) {
|
if (existingCurrentPhase && existingCurrentPhase !== resolvedPhase) {
|
||||||
output(
|
output(
|
||||||
{ updated: [], phase: resolvedPhase, idempotent: true, note: 'phase already superseded; no-op' },
|
{ updated: [], phase: resolvedPhase, idempotent: true, note: 'phase already superseded; no-op' },
|
||||||
|
|||||||
Reference in New Issue
Block a user