diff --git a/src/resources/extensions/gsd/pre-execution-checks.ts b/src/resources/extensions/gsd/pre-execution-checks.ts index ed10ba50b..634a9a000 100644 --- a/src/resources/extensions/gsd/pre-execution-checks.ts +++ b/src/resources/extensions/gsd/pre-execution-checks.ts @@ -263,9 +263,9 @@ function extractPathFromAnnotation(raw: string): string { const trimmed = raw.trim(); if (!trimmed) return trimmed; - const backtickMatch = trimmed.match(/^`([^`]+)`(?:\s+[—–-]\s+.*)?$/); + const backtickMatch = trimmed.match(/^(`+)([^`]+)\1(?:(?:\s+[—–-]\s+.+)|(?:\s+\([^()]+\)))?$/); if (backtickMatch) { - return backtickMatch[1].trim(); + return backtickMatch[2].trim(); } const annotatedMatch = trimmed.match(/^(.+?)\s+[—–-]\s+.+$/); diff --git a/src/resources/extensions/gsd/tests/pre-exec-backtick-strip.test.ts b/src/resources/extensions/gsd/tests/pre-exec-backtick-strip.test.ts index ffdeae7c8..1f1ac2d35 100644 --- a/src/resources/extensions/gsd/tests/pre-exec-backtick-strip.test.ts +++ b/src/resources/extensions/gsd/tests/pre-exec-backtick-strip.test.ts @@ -12,7 +12,7 @@ import { describe, it } from 'node:test' import assert from 'node:assert/strict' import { normalizeFilePath, checkFilePathConsistency } from '../pre-execution-checks.ts' -import { readFileSync } from 'node:fs' +import { mkdirSync, readFileSync, rmSync, writeFileSync } from 'node:fs' import { resolve } from 'node:path' const src = readFileSync( @@ -25,6 +25,11 @@ describe('normalizeFilePath backtick stripping (#3649)', () => { assert.equal(normalizeFilePath('`src/foo.ts`'), 'src/foo.ts') }) + it('strips doubled backticks and trailing notes from file paths', () => { + assert.equal(normalizeFilePath('``src/foo.ts`` - current state'), 'src/foo.ts') + assert.equal(normalizeFilePath('``src/foo.ts`` (current state)'), 'src/foo.ts') + }) + it('strips backticks even when mixed with other normalization', () => { assert.equal(normalizeFilePath('`./src//bar.ts`'), 'src/bar.ts') }) @@ -66,3 +71,45 @@ describe('checkFilePathConsistency checks task.inputs not task.files (#3626)', ( ) }) }) + +describe('checkFilePathConsistency handles doubled-backtick annotations (#3892)', () => { + it('accepts existing files when task.inputs include doubled-backtick notes', () => { + const task = { + milestone_id: 'M001', + slice_id: 'S01', + id: 'T01', + title: 'Test Task', + status: 'pending', + one_liner: '', + narrative: '', + verification_result: '', + duration: '', + completed_at: null, + blocker_discovered: false, + deviations: '', + known_issues: '', + key_files: [], + key_decisions: [], + full_summary_md: '', + description: '', + estimate: '', + files: [], + verify: '', + inputs: ['``src/foo.ts`` (current state)'], + expected_output: [], + observability_impact: '', + full_plan_md: '', + sequence: 0, + } + + const tmp = resolve(process.cwd(), '.tmp-pre-exec-3892') + try { + mkdirSync(resolve(tmp, 'src'), { recursive: true }) + writeFileSync(resolve(tmp, 'src', 'foo.ts'), '// ok') + const results = checkFilePathConsistency([task as any], tmp) + assert.deepEqual(results, []) + } finally { + rmSync(tmp, { recursive: true, force: true }) + } + }) +})