import assert from 'node:assert/strict'; import test from 'node:test'; import path from 'node:path'; import { VERIFY_PRESETS, buildPageDataDevInstruction, parseDevLoopArgs, resolveDevLoopExecutor, resolveVerifyPreset, resolveWorkspaceCwd, PAGE_DATA_DEV_COMPLEX_TASK_TYPE, } from './page-data-aider-dev-loop.mjs'; test('parseDevLoopArgs applies defaults and flags', () => { const options = parseDevLoopArgs([ '--preset', 'page-data-platform', '--max-attempts', '2', '--dry-run', '--no-insert', ]); assert.equal(options.preset, 'page-data-platform'); assert.equal(options.maxAttempts, 2); assert.equal(options.dryRun, true); assert.equal(options.testInsert, false); }); test('resolveVerifyPreset rejects unknown preset', () => { assert.throws(() => resolveVerifyPreset('missing'), /未知 preset/); assert.equal(resolveVerifyPreset('children-hobby-diet-survey').scenario, 'workspace'); }); test('resolveWorkspaceCwd maps workspace and platform scenarios', () => { const root = '/repo'; assert.equal( resolveWorkspaceCwd({ repoRoot: root, userId: 'user-1', cwdOverride: null, scenario: 'workspace', }), path.join(root, 'MindSpace', 'user-1'), ); assert.equal( resolveWorkspaceCwd({ repoRoot: root, userId: null, cwdOverride: '/custom', scenario: 'workspace', }), '/custom', ); assert.equal( resolveWorkspaceCwd({ repoRoot: root, userId: null, cwdOverride: null, scenario: 'platform', }), root, ); }); test('buildPageDataDevInstruction includes verify output and targets', () => { const instruction = buildPageDataDevInstruction({ verifyOutput: '✘ 问卷提交字段: insertRow 未包含 q4_diet_meals', cwd: '/repo/MindSpace/user-1', targetFiles: ['public/survey.html', '.mindspace/page-data-policies/page.json'], verifyCommandLabel: 'npm run verify:children-hobby-diet-survey', }); assert.match(instruction, /Page Data 开发修复任务/); assert.match(instruction, /q4_diet_meals/); assert.match(instruction, /public\/survey\.html/); assert.match(instruction, /npm run verify:children-hobby-diet-survey/); assert.match(instruction, /page-data-client\.js/); }); test('resolveDevLoopExecutor escalates to openhands after N aider rounds', () => { assert.deepEqual(resolveDevLoopExecutor(1, { escalateAfter: 2 }), { executor: 'aider', taskType: 'page_data_dev', escalated: false, }); assert.deepEqual(resolveDevLoopExecutor(3, { escalateAfter: 2 }), { executor: 'openhands', taskType: PAGE_DATA_DEV_COMPLEX_TASK_TYPE, escalated: true, }); assert.deepEqual(resolveDevLoopExecutor(3, { escalateAfter: 0 }), { executor: 'aider', taskType: 'page_data_dev', escalated: false, }); }); test('buildPageDataDevInstruction marks openhands escalation', () => { const instruction = buildPageDataDevInstruction({ verifyOutput: 'failed', cwd: '/repo/MindSpace/u1', taskType: PAGE_DATA_DEV_COMPLEX_TASK_TYPE, escalated: true, verifyCommandLabel: 'npm run verify:page-data', }); assert.match(instruction, /OpenHands 接手/); assert.match(instruction, /page_data_dev_complex/); }); test('children-hobby preset builds verify args with user id', () => { const preset = VERIFY_PRESETS['children-hobby-diet-survey']; const args = preset.buildVerifyArgs({ userId: 'abc', testInsert: false, checkRuns: false, port: 9090, }); assert.deepEqual(args, [ 'scripts/verify-children-hobby-diet-survey.mjs', '--user-id', 'abc', '--no-insert', '--no-runs', '--port', '9090', ]); });