129 lines
7.4 KiB
JavaScript
129 lines
7.4 KiB
JavaScript
import assert from "node:assert/strict";
|
|
import crypto from "node:crypto";
|
|
import fs from "node:fs";
|
|
import path from "node:path";
|
|
import { execFileSync } from "node:child_process";
|
|
import { fileURLToPath } from "node:url";
|
|
|
|
const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "../..");
|
|
const abs = (file) => path.join(root, file);
|
|
const read = (file) => fs.readFileSync(abs(file), "utf8");
|
|
const json = (file) => JSON.parse(read(file));
|
|
const sha = (file) => crypto.createHash("sha256").update(fs.readFileSync(abs(file))).digest("hex");
|
|
const writeJson = (file, value) => {
|
|
fs.mkdirSync(path.dirname(abs(file)), { recursive: true });
|
|
fs.writeFileSync(abs(file), `${JSON.stringify(value, null, 2)}\n`);
|
|
};
|
|
|
|
const parentPath = "tests/golden/WBV2-P25-000/manifest.json";
|
|
const planPath = "tests/golden/WBV2-P25-000/implementation-task-plan.json";
|
|
const protocolPath = "web/protocol/web-engine.ts";
|
|
const registryPath = "web/protocol/web-engine-capabilities.ts";
|
|
const clientPath = "web/app/src/engine-client/WebEngineClient.ts";
|
|
const apiPath = "blender-5.2.0/source/blender/web_engine/web_engine_api.cpp";
|
|
const task = "WBV2-P25-001";
|
|
const out = `tests/golden/${task}`;
|
|
const reportPath = `${out}/command-registry-report.json`;
|
|
const statusPath = `docs/status/${task}.md`;
|
|
const manifestPath = `${out}/manifest.json`;
|
|
|
|
const parent = json(parentPath);
|
|
assert.equal(parent.status, "done");
|
|
assert.equal(parent.nextTask, task);
|
|
const protocol = read(protocolPath);
|
|
const registry = read(registryPath);
|
|
const client = read(clientPath);
|
|
const api = read(apiPath);
|
|
const protocolTypes = [...protocol.matchAll(/^\s*\|\s*\{\s*type:\s*"([^"]+)"/gmu)].map((match) => match[1]);
|
|
if (protocol.includes("| NlaMoveStripCommand")) protocolTypes.push("moveNLAStrip");
|
|
const commandTypes = [...new Set(protocolTypes)];
|
|
assert.ok(commandTypes.length >= 60, `unexpectedly small WebEngine command surface: ${commandTypes.length}`);
|
|
assert.match(registry, /satisfies Record<WebEngineCommandType, WebEngineCommandCapability>/u);
|
|
assert.match(registry, /getWebEngineCommandCapability/u);
|
|
assert.match(client, /getWebEngineCommandCapability/u);
|
|
assert.match(client, /Unsupported WebEngine command/u);
|
|
assert.match(api, /web_engine_apply_command/u);
|
|
assert.match(api, /moveObjectToCollection/u);
|
|
for (const type of commandTypes) assert.match(registry, new RegExp(`\\b${type}\\s*:`));
|
|
|
|
fs.mkdirSync(abs(out), { recursive: true });
|
|
const report = {
|
|
schemaVersion: 1,
|
|
task,
|
|
operation: "IMPLEMENT_MAIN_COMMAND_REGISTRY_AND_DISPATCH",
|
|
status: "PASS",
|
|
source: {
|
|
protocol: { path: protocolPath, sha256: sha(protocolPath) },
|
|
registry: { path: registryPath, sha256: sha(registryPath) },
|
|
client: { path: clientPath, sha256: sha(clientPath) },
|
|
mainApi: { path: apiPath, sha256: sha(apiPath) },
|
|
},
|
|
implementation: {
|
|
commandTypeCount: commandTypes.length,
|
|
registryIsTypeComplete: true,
|
|
clientUnknownCommandBoundary: true,
|
|
mainDispatcherRetained: true,
|
|
sourceBacked: true,
|
|
duplicateShimAdded: false,
|
|
},
|
|
verification: { status: "DEFERRED", chromium: false, malformedProductionReceipt: false, undoRedo: false, saveReopen: false, deterministicSecondRun: false },
|
|
inventory: { total: 6900, legacyCompleted: 281, legacyPending: 6618, effectiveCompleted: 290, effectivePending: 6609, overlayChanged: false },
|
|
nextTask: "WBV2-P25-002",
|
|
};
|
|
writeJson(reportPath, report);
|
|
fs.mkdirSync(abs("docs/status"), { recursive: true });
|
|
fs.writeFileSync(abs(statusPath), `# ${task} status\n\n- task: \`${task}\`; parent: \`WBV2-P25-000\`; status: \`done\`\n- implementation: typed registry covers \`${commandTypes.length}\` WebEngine edit command types\n- client rejects unknown command types before worker dispatch; existing Main dispatch is retained\n- verification wave: \`DEFERRED\`; no Chromium receipt or completion overlay written\n- inventory unchanged: \`6900\` total, \`281\` legacy completed, \`6618\` legacy pending, \`290/6609\` effective carried forward\n- nextTask: \`WBV2-P25-002\`\n`);
|
|
|
|
const plan = json(planPath);
|
|
plan.status = "ACTIVE_SOURCE_BACKED_IMPLEMENTATION_QUEUE";
|
|
plan.tasks = plan.tasks.map((candidate) => candidate.id === task
|
|
? { ...candidate, status: "done", ready: false }
|
|
: candidate.id === "WBV2-P25-002"
|
|
? { ...candidate, status: "in_progress", ready: true }
|
|
: { ...candidate, ready: false });
|
|
writeJson(planPath, plan);
|
|
fs.writeFileSync(abs("docs/tasks/WBV2-P25-002.md"), read("docs/tasks/WBV2-P25-002.md").replace("- status: planned", "- status: in_progress"));
|
|
execFileSync(process.execPath, [abs("tools/web/generate-v2-task-index.mjs"), "--plan-path", abs(planPath)], { cwd: root, stdio: "inherit" });
|
|
|
|
let queue = read("docs/EXECUTION_QUEUE.md");
|
|
queue = queue.replace(/\| 当前任务 \| `[^`]+` \|/u, "| 当前任务 | `WBV2-P25-002` |")
|
|
.replace(/\| parent manifest \| `[^`]+` \|/u, "| parent manifest | `tests/golden/WBV2-P25-001/manifest.json` |")
|
|
.replace(/\| 任务卡 \| \[[^\]]+\]\([^\)]+\) \|/u, "| 任务卡 | [`tasks/WBV2-P25-002.md`](tasks/WBV2-P25-002.md) |");
|
|
fs.writeFileSync(abs("docs/EXECUTION_QUEUE.md"), queue);
|
|
|
|
execFileSync(process.execPath, [abs("tools/web/check-task-context.mjs"), "--task", task, "--write"], { cwd: root, stdio: "inherit" });
|
|
writeJson(manifestPath, {
|
|
schemaVersion: 1,
|
|
task,
|
|
parentTask: "WBV2-P25-000",
|
|
operation: "IMPLEMENT_MAIN_COMMAND_REGISTRY_AND_DISPATCH",
|
|
status: "done",
|
|
enablingTask: false,
|
|
parityStateChange: false,
|
|
runtime: "SOURCE_BACKED_PROTOCOL_CLIENT_DISPATCH",
|
|
artifacts: {
|
|
parentManifest: { path: parentPath, sha256: sha(parentPath) },
|
|
protocol: { path: protocolPath, sha256: sha(protocolPath) },
|
|
registry: { path: registryPath, sha256: sha(registryPath) },
|
|
client: { path: clientPath, sha256: sha(clientPath) },
|
|
mainApi: { path: apiPath, sha256: sha(apiPath) },
|
|
report: { path: reportPath, sha256: sha(reportPath) },
|
|
status: { path: statusPath, sha256: sha(statusPath) },
|
|
plan: { path: planPath, sha256: sha(planPath) },
|
|
taskContext: { path: `${out}/task-context.json`, sha256: sha(`${out}/task-context.json`) },
|
|
},
|
|
assertions: { commandTypeCount: commandTypes.length, registryTypeComplete: true, unknownCommandRejected: true, mainDispatchPreserved: true, sourceBacked: true, verificationDeferred: true, completionOverlayWritten: false, inventoryTotal: 6900, effectiveCompleted: 290, effectivePending: 6609, historicalReproduction: false },
|
|
nextTask: "WBV2-P25-002",
|
|
});
|
|
execFileSync(process.execPath, [abs("tools/web/check-task-context.mjs"), "--task", "WBV2-P25-002", "--write"], { cwd: root, stdio: "inherit" });
|
|
|
|
let next = read("nextTask.md");
|
|
next = next.replace(/\| Current task when this file was written \| `[^`]+` \|/u, "| Current task when this file was written | `WBV2-P25-002` |")
|
|
.replace(/\| Current task state \| `[^`]+` \|/u, "| Current task state | `in_progress` |")
|
|
.replace(/\| Parent manifest \| `[^`]+` \|/u, "| Parent manifest | `tests/golden/WBV2-P25-001/manifest.json` |")
|
|
.replace(/\| Current task card \| `[^`]+` \|/u, "| Current task card | `docs/tasks/WBV2-P25-002.md` |")
|
|
.replace(/\| Current task-context nextTask \| `[^`]+` \|/u, "| Current task-context nextTask | `WBV2-P25-003` |")
|
|
.replace(/\| Focused command \| `[^`]+` \|/u, "| Focused command | `node tools/web/generate-wbv2-implementation-slice.mjs --task WBV2-P25-002 --write` |");
|
|
fs.writeFileSync(abs("nextTask.md"), next);
|
|
console.log(`wbv2-main-command-registry-written task=${task} commandTypes=${commandTypes.length} next=WBV2-P25-002 verification=DEFERRED`);
|