import fs from 'node:fs'; import path from 'node:path'; import crypto from 'node:crypto'; import { fileURLToPath } from 'node:url'; import { buildEmployeeName } from '../server/identity/build-employee-name.mjs'; const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..'); const sha = v => crypto.createHash('sha256').update(v).digest('hex'); const args = process.argv.slice(2); 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'); const base = JSON.parse(fs.readFileSync(args[1], 'utf8')); if (base.objectId !== 'inPfC51rvn' || sha(base.code) !== 'd4c7e2923a13b56b60821f02c8ca4ab472fca3664cde8fcdbf3f621e51047b23') throw Error('EXPECTED_DEPLOYED_R5_BASE'); const built = buildEmployeeName(base), skill = 'skills/ksf-workshop-runtime'; const files = fs.readFileSync(path.join(root, skill, 'FILES.sha256'), 'utf8').trim().split(/\r?\n/).map(line => { const m = line.match(/^([a-f0-9]{64}) ([\w./-]+)$/); if (!m || m[2].split('/').includes('..') || sha(fs.readFileSync(path.join(root, skill, m[2]))) !== m[1]) throw Error('SKILL_MANIFEST_MISMATCH'); return skill + '/' + m[2]; }); if (new Set(files).size !== 10) throw Error('UNEXPECTED_SKILL_FILES'); files.push(skill + '/FILES.sha256', 'scripts/install-workshop-skill.mjs', 'scripts/build-workshop-skill.mjs', 'scripts/package-employee-name-patch.mjs', 'scripts/publish-employee-name.mjs', 'server/identity/employee-name.mjs', 'server/identity/wecom-directory.mjs', 'server/identity/build-employee-name.mjs', 'server/identity/manage.mjs', 'docs/employee-name-patch-20261103.md', 'docs/wanggang-employee-name-test-20261103.md', 'docs/employee-name-validation-20261103.json'); const out = args[3]; fs.mkdirSync(out, { recursive: true }); for (const file of files) { const input = path.join(root, file), stat = fs.lstatSync(input); if (!stat.isFile() || stat.isSymbolicLink()) throw Error('NOT_PLAIN_PACKAGE_FILE'); const target = path.join(out, file); fs.mkdirSync(path.dirname(target), { recursive: true }); fs.copyFileSync(input, target, fs.constants.COPYFILE_EXCL); } const write = (relative, bytes) => { const target = path.join(out, relative); fs.mkdirSync(path.dirname(target), { recursive: true }); fs.writeFileSync(target, bytes, { flag: 'wx' }); files.push(relative); }; for (const entry of built.functions) write('server/identity/name-dist/' + entry.name + '.js', entry.code); write('server/identity/name-dist/manifest.json', JSON.stringify({ ...built, functions: built.functions.map(({ code, ...m }) => m) }, null, 2)); const staticFile = 'src/core/kfs/employee.js', bytes = fs.readFileSync(path.join(root, staticFile)); write('payload/' + staticFile, bytes); write('deploy/employee-name-static.json', JSON.stringify({ release: built.version, path: staticFile, prior: 'd2b312ac7ae6c749279a9c04c9e87e697b86c269e503ab3009c6e1b69c852eb1', sha256: sha(bytes) }, null, 2)); fs.writeFileSync(path.join(out, 'FILES.sha256'), files.sort().map(file => sha(fs.readFileSync(path.join(out, file))) + ' ' + file).join('\n') + '\n', { flag: 'wx' }); console.log(JSON.stringify({ ok: true, release: 'ksf.employee-name-patch.20261103.r1', files: files.length + 1, functionsAdded: 1, existingFunctionsChanged: 1, staticFilesChanged: 1, skillChangedFiles: 6, out, deployed: false }));