| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546 |
- import fs from 'node:fs';
- import crypto from 'node:crypto';
- import assert from 'node:assert/strict';
- import { compileDialogue, manualFile, bankFile } from '../../scripts/update-workshop-dialogue-manual.mjs';
- const root = 'skills/ksf-workshop-runtime', out = 'docs/report-quality-html-20261111';
- const sha = x => crypto.createHash('sha256').update(x).digest('hex');
- const before = JSON.parse(fs.readFileSync(out + '/before/manifest.json'));
- const protectedFiles = Object.entries(before).filter(([p]) => /scripts\/ksf-(secure|workshop|identity)\.mjs$/.test(p));
- for (const [file, hash] of protectedFiles) assert.equal(sha(fs.readFileSync(file)), hash, file);
- assert.ok(fs.readFileSync(root + '/final-SKILL.md').equals(fs.readFileSync(root + '/SKILL.md')));
- let count = 1;
- for (const line of fs.readFileSync(root + '/FILES.sha256', 'utf8').trim().split(/\r?\n/)) {
- const [hash, file] = line.split(' ');assert.equal(sha(fs.readFileSync(root + '/' + file)), hash, file);count++;
- }
- const bank = JSON.parse(fs.readFileSync(bankFile));
- const oldBank = JSON.parse(fs.readFileSync(out + '/before/' + bankFile));
- assert.deepEqual(Object.keys(bank.steps), Object.keys(oldBank.steps));
- let rounds = 0;
- for (const id of Object.keys(bank.steps)) {
- assert.equal(bank.steps[id].title, oldBank.steps[id].title);
- assert.deepEqual(bank.steps[id].references, oldBank.steps[id].references);
- assert.equal(bank.steps[id].rounds.length, oldBank.steps[id].rounds.length);
- for (let i = 0; i < bank.steps[id].rounds.length; i++) {
- for (const key of ['title', 'purpose', 'prerequisite', 'deliver']) assert.deepEqual(bank.steps[id].rounds[i][key], oldBank.steps[id].rounds[i][key]);
- rounds++;
- }
- }
- assert.deepEqual(bank.steps.topic.rounds[0], oldBank.steps.topic.rounds[0]);
- assert.deepEqual(bank.steps.proposal.rounds.at(-1), oldBank.steps.proposal.rounds.at(-1));
- const manual = fs.readFileSync(manualFile, 'utf8');
- const data = JSON.parse(manual.match(/window\.WORKSHOP_MANUAL_DATA = (\{[\s\S]*?\n\});\r?\n<\/script>/)[1]);
- const oldData = JSON.parse(fs.readFileSync(out + '/before/' + manualFile, 'utf8').match(/window\.WORKSHOP_MANUAL_DATA = (\{[\s\S]*?\n\});\r?\n<\/script>/)[1]);
- assert.deepEqual(data.steps, oldData.steps, '课程正文与既定产出不改');
- const actual = JSON.parse(manual.match(/ const dialogueMap = (\{[^\r\n]+\});/)[1]);
- assert.deepEqual(actual, compileDialogue(bank, data.steps));
- const packageReceipt = JSON.parse(fs.readFileSync('docs/workshop-final-files-20261111/skill-package-receipt.json'));
- assert.equal(packageReceipt.sha256, sha(fs.readFileSync('docs/workshop-final-files-20261111/final-康师傅工作坊.skill')));
- assert.equal(packageReceipt.publicFilesVerified, count);
- const localLinks = [...fs.readFileSync(root + '/SKILL.md', 'utf8').matchAll(/\]\((references\/[^)#]+)(?:#[^)]*)?\)/g)].map(m => m[1]);
- for (const file of localLinks) assert.ok(fs.existsSync(root + '/' + file), file);
- const result = { ok: true, steps: data.steps.length, rounds, courseTextAndOutputsUnchanged: true,
- promptBankMatchesManual: true, accountBindingUnchanged: true, imageConfirmationRoundUnchanged: true,
- protectedRuntimeUnchanged: protectedFiles.map(([file]) => file), publicFilesVerified: count,
- skillPackageSha256: packageReceipt.sha256, browserChecks: 11, productionWrites: 0, deployed: false };
- fs.writeFileSync(out + '/release-verification.json', JSON.stringify(result, null, 2) + '\n');
- console.log(JSON.stringify(result));
|