package-employee-read-patch.mjs 3.1 KB

12345678910111213141516171819202122232425262728293031
  1. import fs from 'node:fs';
  2. import path from 'node:path';
  3. import crypto from 'node:crypto';
  4. import { fileURLToPath } from 'node:url';
  5. import { buildEmployeeRead } from '../server/identity/build-employee-read.mjs';
  6. const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..');
  7. const sha = bytes => crypto.createHash('sha256').update(bytes).digest('hex');
  8. const args = process.argv.slice(2);
  9. if (args.length !== 4 || args[0] !== '--base' || args[2] !== '--out' || !path.isAbsolute(args[3]) || fs.existsSync(args[3])) throw Error('Use --base PRIVATE_R5_SNAPSHOT --out NEW_ABSOLUTE_DIRECTORY');
  10. const base = JSON.parse(fs.readFileSync(args[1], 'utf8'));
  11. if (base.objectId !== 'inPfC51rvn' || sha(base.code) !== 'd4c7e2923a13b56b60821f02c8ca4ab472fca3664cde8fcdbf3f621e51047b23') throw Error('EXPECTED_DEPLOYED_R5_BASE');
  12. const built = buildEmployeeRead(base), skill = 'skills/ksf-workshop-runtime';
  13. const files = fs.readFileSync(path.join(root, skill, 'FILES.sha256'), 'utf8').trim().split(/\r?\n/).map(line => {
  14. const m = line.match(/^([a-f0-9]{64}) ([\w./-]+)$/);
  15. if (!m || m[2].split('/').includes('..') || sha(fs.readFileSync(path.join(root, skill, m[2]))) !== m[1]) throw Error('SKILL_MANIFEST_MISMATCH');
  16. return skill + '/' + m[2];
  17. });
  18. if (new Set(files).size !== 10) throw Error('UNEXPECTED_SKILL_FILES');
  19. files.push(skill + '/FILES.sha256', 'scripts/install-workshop-skill.mjs', 'scripts/build-workshop-skill.mjs', 'scripts/package-employee-read-patch.mjs',
  20. 'server/identity/employee-read.mjs', 'server/identity/wecom-directory.mjs', 'server/identity/build-employee-read.mjs', 'server/identity/manage.mjs',
  21. 'server/identity/platform.example.json', 'docs/employee-read-patch-20261103.md', 'docs/wanggang-employee-read-test-20261103.md', 'docs/employee-read-validation-20261103.json');
  22. for (const file of files) { const stat = fs.lstatSync(path.join(root, file)); if (!stat.isFile() || stat.isSymbolicLink()) throw Error('NOT_PLAIN_PACKAGE_FILE'); }
  23. const out = args[3]; fs.mkdirSync(out, { recursive: true });
  24. for (const file of files) { const target = path.join(out, file); fs.mkdirSync(path.dirname(target), { recursive: true }); fs.copyFileSync(path.join(root, file), target, fs.constants.COPYFILE_EXCL); }
  25. const dist = path.join(out, 'server/identity/read-dist'); fs.mkdirSync(dist, { recursive: true });
  26. for (const entry of built.functions) { const relative = 'server/identity/read-dist/' + entry.name + '.js'; fs.writeFileSync(path.join(out, relative), entry.code, { flag: 'wx' }); files.push(relative); }
  27. const manifest = 'server/identity/read-dist/manifest.json';
  28. fs.writeFileSync(path.join(out, manifest), JSON.stringify({ ...built, functions: built.functions.map(({ code, ...meta }) => meta) }, null, 2), { flag: 'wx' }); files.push(manifest);
  29. fs.writeFileSync(path.join(out, 'FILES.sha256'), files.sort().map(file => sha(fs.readFileSync(path.join(out, file))) + ' ' + file).join('\n') + '\n', { flag: 'wx' });
  30. console.log(JSON.stringify({ ok: true, release: 'ksf.employee-read-patch.20261103.r1', files: files.length + 1, functionsAdded: 1, existingFunctionsChanged: 0, staticFilesChanged: 0, out, deployed: false }));