import fs from 'node:fs'; import path from 'node:path'; import { readIndexedTask, verifyTaskIndex, root } from './task-context-lib.mjs'; const taskArg = process.argv.indexOf('--task'); const task = taskArg >= 0 ? process.argv[taskArg + 1] : undefined; if (!task) throw new Error('usage: node tools/web/generate-task-card.mjs --task '); verifyTaskIndex(); const entry = readIndexedTask(task); if (!entry) throw new Error('unknown indexed task: ' + task); const cardPath = path.join(root, 'docs/tasks', task + '.md'); if (fs.existsSync(cardPath) && !process.argv.includes('--force')) { process.stdout.write('task-card-exists task=' + task + ' path=' + path.relative(root, cardPath) + '\n'); process.exit(0); } if (!entry.previous) throw new Error('task ' + task + ' has no indexed parent'); const safeName = entry.gapId.replace(/[^A-Za-z0-9_.-]+/g, '-').replace(/^-+|-+$/g, '') || 'gap'; const fixture = 'tests/files/web/generated/' + task + '-' + safeName + '.blend'; const source = [ '# ' + task + ': ' + entry.gapId + ' LOCAL_EXACT slice', '', '- task: ' + task, '- parent: ' + entry.previous, '- status: in_progress', '- gap: ' + entry.gapId, '- ownerFamily: ' + entry.ownerFamily, '- targetImplementationClass: ' + entry.targetImplementationClass, '', '## 目标', '', 'Make the same minimal fixture produce observable ' + entry.gapId + ' data in Blender desktop and WASM/Main, with save/reopen stability. Change only this gap; do not expand to other data-blocks, editors, or browsers.', '', '## 输入与范围', '', '- Fixture: `' + fixture + '`', '- Generator: `tools/web/generated/' + task + '.py`', '- Production: `blender-5.2.0/source/blender/web_engine/web_engine_blend_reader.cpp`', '- Checker: `tools/web/check-generated-gap.mjs`', '- Do: field read, desktop/WASM comparison, save/reopen, structured report.', '- Do not: other gaps, Firefox/WebKit, or full editor behavior.', '', '## 验收', '', 'build_blender_5.2.0/bin/blender -b --factory-startup --python tools/web/generated/' + task + '.py -- ' + fixture, 'npm --prefix web run test:generated-gap -- --task ' + task, 'node tools/web/check-generated-gap.mjs --task ' + task, '', 'Malformed/unsupported, cancellation, duplicate, over-budget, or hash-drift cases must keep in_progress; they must not change Main revision or advance nextTask.', '', '## 交付与回滚', '', '- Reports: `tests/golden/' + task + '/`', '- Status: `docs/status/' + task + '.md`', '- Manifest: `tests/golden/' + task + '/manifest.json`', '- Handoff: `node tools/web/check-task-context.mjs --task ' + task + ' --write`', '- Rollback: remove this task production entry, fixture, tests, reports, manifest, status, and context; restore the parent as queue tail without rewriting parent evidence.', ].join('\n') + '\n'; fs.mkdirSync(path.dirname(cardPath), { recursive: true }); fs.writeFileSync(cardPath, source); process.stdout.write('task-card-generated task=' + task + ' bytes=' + Buffer.byteLength(source) + ' path=' + path.relative(root, cardPath) + '\n');