fix(#2177): match the body Progress: line, preserve the descriptive suffix
cmdStateUpdateProgress ran its Progress: patterns against the raw STATE.md content (frontmatter included). With /i+/m the first match was the YAML frontmatter `progress:` key, not the body line — so the frontmatter block was mangled (\s* crossed the newline) while the body line stayed stale, and the next STATE.md write re-derived percent from that stale line, silently reverting the update. \2: the .* also discarded any agent-authored descriptive suffix. - Match against the frontmatter-stripped body only (reusing stripFrontmatter); reconstruct content as fmPrefix + modified body so the frontmatter is untouched. - Swap only the machine segment ([bar] NN% or bare NN%), preserving any suffix. - updated stays false when the body has no Progress: line (no false success from a frontmatter progress: key). Closes #2177
This commit is contained in:
@@ -613,17 +613,33 @@ function cmdStateUpdateProgress(cwd: string, raw: boolean): void {
|
||||
const _totalSummaries = totalSummaries;
|
||||
|
||||
readModifyWriteStateMd(statePath, (content) => {
|
||||
// Try **Progress:** bold format first, then plain Progress: format
|
||||
const boldProgressPattern = /(\*\*Progress:\*\*\s*).*/i;
|
||||
const plainProgressPattern = /^(Progress:\s*).*/im;
|
||||
if (boldProgressPattern.test(content)) {
|
||||
updated = true;
|
||||
return content.replace(boldProgressPattern, (_match, prefix: string) => `${prefix}${progressStr}`);
|
||||
} else if (plainProgressPattern.test(content)) {
|
||||
updated = true;
|
||||
return content.replace(plainProgressPattern, (_match, prefix: string) => `${prefix}${progressStr}`);
|
||||
}
|
||||
return content;
|
||||
// #2177: match against the BODY only. With /i the patterns below would
|
||||
// otherwise hit the YAML frontmatter `progress:` key first (and `\s*` would
|
||||
// eat its newline, mangling the nested block), while the body Progress: line
|
||||
// — which frontmatter `percent` is re-derived from on every write — stays
|
||||
// stale and silently reverts the update.
|
||||
const body = stripFrontmatter(content);
|
||||
const fmPrefix = content.slice(0, content.length - body.length);
|
||||
|
||||
// Swap only the machine segment ("[bar] NN%" or bare "NN%"), preserving any
|
||||
// descriptive suffix an agent authored, e.g. "(2/4 plans done; blocked on…)".
|
||||
const machineSegment = /(?:\[[^\]\r\n]*\][ \t]*)?\d{1,3}%/;
|
||||
const replaceValue = (value: string) => machineSegment.test(value)
|
||||
? value.replace(machineSegment, progressStr)
|
||||
: progressStr;
|
||||
|
||||
// Try **Progress:** bold format first, then plain Progress: format.
|
||||
const boldProgressPattern = /(\*\*Progress:\*\*[ \t]*)([^\r\n]*)/i;
|
||||
const plainProgressPattern = /^(Progress:[ \t]*)([^\r\n]*)/im;
|
||||
const pattern = boldProgressPattern.test(body)
|
||||
? boldProgressPattern
|
||||
: plainProgressPattern.test(body)
|
||||
? plainProgressPattern
|
||||
: null;
|
||||
if (!pattern) return content;
|
||||
|
||||
updated = true;
|
||||
return fmPrefix + body.replace(pattern, (_match, prefix: string, value: string) => `${prefix}${replaceValue(value)}`);
|
||||
}, cwd);
|
||||
|
||||
if (updated) {
|
||||
|
||||
Reference in New Issue
Block a user