// tests/commands/trekresearch.test.mjs // Prose-pin tests for /trekresearch. import { test } from 'node:test'; import { strict as assert } from 'node:assert'; import { readFileSync } from 'node:fs'; import { dirname, join } from 'node:path'; import { fileURLToPath } from 'node:url'; const HERE = dirname(fileURLToPath(import.meta.url)); const ROOT = join(HERE, '..', '..'); const COMMAND_FILE = join(ROOT, 'commands', 'trekresearch.md'); function read() { return readFileSync(COMMAND_FILE, 'utf8'); } // --- Phase 5 slice (heading-bounded) --- // Slice from the phase heading to the NEXT phase heading, never a fixed character window. function phaseSlice(doc, startHeading, endHeading) { const start = doc.indexOf(startHeading); assert.ok(start >= 0, `${startHeading} missing`); const end = doc.indexOf(endHeading, start); assert.ok(end > start, `${endHeading} missing — could not bound ${startHeading}`); return doc.slice(start, end); } function phase5(doc) { return phaseSlice(doc, '## Phase 5 —', '## Phase 6 —'); } test('trekresearch — Phase 4 runs the full swarm with contrarian-researcher as wave 2 every time (decision 209)', () => { const flatText = read().replace(/\s+/g, ' '); assert.ok( flatText.includes('Every run launches the FULL swarm for its scope: all 5 local agents when the scope includes local, and all 4 external agents when it includes external. `contrarian-researcher` is one of the external four and runs every time the scope includes external, as wave 2 (see Launch rules)'), 'Phase 4 must state the one fixed path: the full swarm, contrarian-researcher as wave 2 every run', ); assert.ok( !flatText.includes('use the existing conditional triggers'), 'no effort must point at a conditional trigger that nothing defines', ); }); // --- Spawn model --- /** Whitespace (line breaks too) collapsed to one space. */ const flat = (s) => s.replace(/\s+/g, ' ').trim(); /** From the line holding `marker` to the first blank line, flattened. */ function paragraphAt(text, marker) { const lines = text.split('\n'); const start = lines.findIndex((l) => l.includes(marker)); assert.ok(start !== -1, `commands/trekresearch.md must hold "${marker}"`); let end = lines.length; for (let i = start + 1; i < lines.length; i++) if (lines[i].trim() === '') { end = i; break; } return flat(lines.slice(start, end).join(' ')); } test('trekresearch — Phase 5 follow-ups: a built-in agent is spawned with model opus, at most 2', () => { const text = read(); const part = paragraphAt(phase5(text), 'launch a targeted follow-up agent'); assert.match(part, /Maximum 2 follow-ups\./); assert.ok(part.includes("A follow-up may be one of Claude Code's built-in agents: Spawn it with `model: \"opus\"`: a built-in agent has no Voyage pin."), part); }); test('trekresearch — promises no maxTurns budget', () => { const text = read(); assert.doesNotMatch(text, /maxTurns/); });