Files
workinf_Blender_Wasm/tools/web/generate-wbv2-main-command-registry.mjs
mes123456 7549b9a15c
Some checks failed
M6 deployable RC / quick (push) Has been cancelled
M6 deployable RC / chromium (push) Has been cancelled
M6 deployable RC / release (push) Has been cancelled
feat(web): switch to implementation-first capability wave
2026-08-29 01:22:03 +08:00

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`);