diff --git a/src/resources/extensions/gsd/milestone-ids.ts b/src/resources/extensions/gsd/milestone-ids.ts index aec8cee67..fdd26f7ab 100644 --- a/src/resources/extensions/gsd/milestone-ids.ts +++ b/src/resources/extensions/gsd/milestone-ids.ts @@ -80,8 +80,9 @@ export function findMilestoneIds(basePath: string): string[] { .filter((d) => d.isDirectory()) .map((d) => { const match = d.name.match(/^(M\d+(?:-[a-z0-9]{6})?)/); - return match ? match[1] : d.name; - }); + return match ? match[1] : null; + }) + .filter((id): id is string => id !== null); // Apply custom queue order if available, else fall back to numeric sort const customOrder = loadQueueOrder(basePath); diff --git a/src/resources/extensions/gsd/tests/queue-reorder-e2e.test.ts b/src/resources/extensions/gsd/tests/queue-reorder-e2e.test.ts index b9140c561..bf86c360a 100644 --- a/src/resources/extensions/gsd/tests/queue-reorder-e2e.test.ts +++ b/src/resources/extensions/gsd/tests/queue-reorder-e2e.test.ts @@ -244,6 +244,32 @@ console.log('\n=== E2E: backward compat without QUEUE-ORDER.json ==='); } } +// ═══════════════════════════════════════════════════════════════════════════ +// Test: non-milestone directories are filtered out (#1494) +// ═══════════════════════════════════════════════════════════════════════════ + +console.log('\n=== E2E: non-milestone directories filtered from findMilestoneIds (#1494) ==='); +{ + const base = createFixtureBase(); + try { + writeContext(base, 'M001', '', 'First'); + writeContext(base, 'M002', '', 'Second'); + // Create a rogue non-milestone directory + mkdirSync(join(base, '.gsd', 'milestones', 'slices'), { recursive: true }); + mkdirSync(join(base, '.gsd', 'milestones', 'temp-backup'), { recursive: true }); + + invalidateStateCache(); + const ids = findMilestoneIds(base); + assertEq(ids.length, 2, 'only M001 and M002 returned'); + assertTrue(!ids.includes('slices'), 'slices directory excluded'); + assertTrue(!ids.includes('temp-backup'), 'temp-backup directory excluded'); + assertTrue(ids.includes('M001'), 'M001 included'); + assertTrue(ids.includes('M002'), 'M002 included'); + } finally { + cleanup(base); + } +} + // ═══════════════════════════════════════════════════════════════════════════ // Test: depends_on inline array format removal // ═══════════════════════════════════════════════════════════════════════════