kitchen-sink/scripts/pack-zip.mjs
Vincent Koc 89449910b4
Some checks are pending
Check / check (push) Waiting to run
Check / clawhub-dry-run (push) Waiting to run
fix(package): restore kitchen sink install artifacts
2026-05-02 08:40:15 -07:00

135 lines
4.4 KiB
JavaScript

#!/usr/bin/env node
import { Buffer } from "node:buffer";
import fs from "node:fs/promises";
import path from "node:path";
const repoRoot = process.cwd();
const packageJson = JSON.parse(await fs.readFile(path.join(repoRoot, "package.json"), "utf8"));
const pluginJson = JSON.parse(await fs.readFile(path.join(repoRoot, "openclaw.plugin.json"), "utf8"));
const packageVersion = packageJson.version;
const pluginId = pluginJson.id;
const crcTable = Array.from({ length: 256 }, (_, index) => {
let value = index;
for (let bit = 0; bit < 8; bit += 1) {
value = value & 1 ? 0xedb88320 ^ (value >>> 1) : value >>> 1;
}
return value >>> 0;
});
if (pluginId !== "openclaw-kitchen-sink-fixture") {
throw new Error(`unexpected plugin id: ${pluginId}`);
}
if (typeof packageVersion !== "string" || packageVersion.trim().length === 0) {
throw new Error("package.json version must be a non-empty string");
}
const distDir = path.join(repoRoot, "dist");
const zipName = `${pluginId}-${packageVersion}.zip`;
const zipPath = path.join(distDir, zipName);
const entries = [
"package.json",
"openclaw.plugin.json",
"plugin-inspector.config.json",
"README.md",
...(await listFiles("src")),
];
await fs.mkdir(distDir, { recursive: true });
await fs.writeFile(zipPath, await createZip(entries));
console.log(`Wrote ${path.relative(repoRoot, zipPath)} (${entries.length} files)`);
async function listFiles(root) {
const files = [];
const stack = [root];
while (stack.length > 0) {
const relativeDir = stack.pop();
const dirents = await fs.readdir(path.join(repoRoot, relativeDir), { withFileTypes: true });
for (const dirent of dirents.sort((left, right) => left.name.localeCompare(right.name))) {
const relativePath = path.posix.join(relativeDir, dirent.name);
if (dirent.isDirectory()) {
stack.push(relativePath);
} else if (dirent.isFile()) {
files.push(relativePath);
}
}
}
return files.sort();
}
async function createZip(files) {
const localParts = [];
const centralParts = [];
let offset = 0;
for (const relativePath of files) {
if (relativePath.startsWith("/") || relativePath.includes("..")) {
throw new Error(`invalid zip entry path: ${relativePath}`);
}
const data = await fs.readFile(path.join(repoRoot, relativePath));
const name = Buffer.from(relativePath, "utf8");
const crc = crc32(data);
const localHeader = Buffer.alloc(30);
localHeader.writeUInt32LE(0x04034b50, 0);
localHeader.writeUInt16LE(20, 4);
localHeader.writeUInt16LE(0x0800, 6);
localHeader.writeUInt16LE(0, 8);
localHeader.writeUInt16LE(0, 10);
localHeader.writeUInt16LE(0, 12);
localHeader.writeUInt32LE(crc, 14);
localHeader.writeUInt32LE(data.length, 18);
localHeader.writeUInt32LE(data.length, 22);
localHeader.writeUInt16LE(name.length, 26);
localHeader.writeUInt16LE(0, 28);
localParts.push(localHeader, name, data);
const centralHeader = Buffer.alloc(46);
centralHeader.writeUInt32LE(0x02014b50, 0);
centralHeader.writeUInt16LE(20, 4);
centralHeader.writeUInt16LE(20, 6);
centralHeader.writeUInt16LE(0x0800, 8);
centralHeader.writeUInt16LE(0, 10);
centralHeader.writeUInt16LE(0, 12);
centralHeader.writeUInt16LE(0, 14);
centralHeader.writeUInt32LE(crc, 16);
centralHeader.writeUInt32LE(data.length, 20);
centralHeader.writeUInt32LE(data.length, 24);
centralHeader.writeUInt16LE(name.length, 28);
centralHeader.writeUInt16LE(0, 30);
centralHeader.writeUInt16LE(0, 32);
centralHeader.writeUInt16LE(0, 34);
centralHeader.writeUInt16LE(0, 36);
centralHeader.writeUInt32LE(0, 38);
centralHeader.writeUInt32LE(offset, 42);
centralParts.push(centralHeader, name);
offset += localHeader.length + name.length + data.length;
}
const centralDirectory = Buffer.concat(centralParts);
const end = Buffer.alloc(22);
end.writeUInt32LE(0x06054b50, 0);
end.writeUInt16LE(0, 4);
end.writeUInt16LE(0, 6);
end.writeUInt16LE(files.length, 8);
end.writeUInt16LE(files.length, 10);
end.writeUInt32LE(centralDirectory.length, 12);
end.writeUInt32LE(offset, 16);
end.writeUInt16LE(0, 20);
return Buffer.concat([...localParts, centralDirectory, end]);
}
function crc32(buffer) {
let crc = 0xffffffff;
for (const byte of buffer) {
crc = (crc >>> 8) ^ crcTable[(crc ^ byte) & 0xff];
}
return (crc ^ 0xffffffff) >>> 0;
}