fix(plugins): align clawhub clawpack downloads

This commit is contained in:
Vincent Koc
2026-05-02 09:30:49 -07:00
parent 5c15ce3476
commit 03be4bfac5
11 changed files with 229 additions and 91 deletions

View File

@@ -1,6 +1,7 @@
const crypto = require("node:crypto");
const fs = require("node:fs");
const http = require("node:http");
const os = require("node:os");
const path = require("node:path");
const { createRequire } = require("node:module");
@@ -8,18 +9,82 @@ const profile = process.argv[2];
const portFile = process.argv[3];
const requireFromApp = createRequire(path.join(process.cwd(), "package.json"));
const JSZip = requireFromApp("jszip");
const tar = requireFromApp("tar");
const packageName = "@openclaw/kitchen-sink";
const pluginId = "openclaw-kitchen-sink-fixture";
const buildClawPackSummary = ({ sha256hash, manifestSha256, size }) => ({
available: true,
specVersion: 1,
format: "clawpack.zip",
sha256: sha256hash,
size,
manifestSha256,
const buildArtifactSummary = ({
clawpackSha256,
clawpackSize,
npmIntegrity,
npmShasum,
npmTarballName,
}) => ({
kind: "npm-pack",
format: "tgz",
sha256: clawpackSha256,
size: clawpackSize,
npmIntegrity,
npmShasum,
npmTarballName,
});
const buildClawPackSummary = ({
clawpackSha256,
clawpackSize,
npmIntegrity,
npmShasum,
npmTarballName,
}) => ({
available: true,
format: "tgz",
sha256: clawpackSha256,
size: clawpackSize,
npmIntegrity,
npmShasum,
npmTarballName,
});
async function buildNpmPackArtifact(fixture) {
const packRoot = await fs.promises.mkdtemp(path.join(os.tmpdir(), "openclaw-clawhub-fixture-"));
try {
const packageDir = path.join(packRoot, "package");
await fs.promises.mkdir(packageDir, { recursive: true });
await fs.promises.writeFile(
path.join(packageDir, "package.json"),
`${JSON.stringify(fixture.packageJson, null, 2)}\n`,
);
await fs.promises.writeFile(path.join(packageDir, "index.js"), fixture.indexJs);
await fs.promises.writeFile(
path.join(packageDir, "openclaw.plugin.json"),
`${JSON.stringify(fixture.manifest, null, 2)}\n`,
);
const npmTarballName = `${packageName.replace(/^@/, "").replace("/", "-")}-${fixture.version}.tgz`;
const archivePath = path.join(packRoot, npmTarballName);
await tar.c(
{
cwd: packRoot,
file: archivePath,
gzip: true,
portable: true,
noMtime: true,
},
["package"],
);
const archive = await fs.promises.readFile(archivePath);
return {
archive,
clawpackSha256: crypto.createHash("sha256").update(archive).digest("hex"),
clawpackSize: archive.length,
npmIntegrity: `sha512-${crypto.createHash("sha512").update(archive).digest("base64")}`,
npmShasum: crypto.createHash("sha1").update(archive).digest("hex"),
npmTarballName,
};
} finally {
await fs.promises.rm(packRoot, { recursive: true, force: true }).catch(() => undefined);
}
}
const profiles = {
"kitchen-sink-plugin": {
version: "0.1.3",
@@ -98,6 +163,7 @@ export default definePluginEntry({
},
packageDetail(artifact) {
const clawpack = buildClawPackSummary(artifact);
const packageArtifact = buildArtifactSummary(artifact);
const packageDetail = {
package: {
name: packageName,
@@ -131,6 +197,7 @@ export default definePluginEntry({
hasProvenance: false,
scanStatus: "passed",
},
artifact: packageArtifact,
clawpack,
},
};
@@ -151,6 +218,7 @@ export default definePluginEntry({
compatibility: packageDetail.package.compatibility,
capabilities: packageDetail.package.capabilities,
verification: packageDetail.package.verification,
artifact: packageArtifact,
clawpack,
},
},
@@ -209,6 +277,7 @@ export default definePluginEntry({
minGatewayVersion: "2026.4.26",
};
const clawpack = buildClawPackSummary(artifact);
const packageArtifact = buildArtifactSummary(artifact);
return {
packageDetail: {
package: {
@@ -222,6 +291,7 @@ export default definePluginEntry({
createdAt: 0,
updatedAt: 0,
compatibility,
artifact: packageArtifact,
clawpack,
},
},
@@ -232,6 +302,7 @@ export default definePluginEntry({
changelog: "Kitchen-sink fixture package for Docker plugin E2E.",
sha256hash: artifact.sha256hash,
compatibility,
artifact: packageArtifact,
clawpack,
},
},
@@ -257,11 +328,10 @@ async function main() {
const archive = await zip.generateAsync({ type: "nodebuffer", compression: "DEFLATE" });
const sha256hash = crypto.createHash("sha256").update(archive).digest("hex");
const manifestSha256 = crypto.createHash("sha256").update(manifestJson).digest("hex");
const clawpack = await buildNpmPackArtifact(fixture);
const { packageDetail, versionDetail, betaStatus } = fixture.packageDetail({
sha256hash,
manifestSha256,
size: archive.length,
...clawpack,
});
const json = (response, value, status = 200) => {
@@ -304,15 +374,17 @@ async function main() {
}
if (
url.pathname ===
`/api/v1/packages/${encodeURIComponent(packageName)}/versions/${fixture.version}/clawpack`
`/api/v1/packages/${encodeURIComponent(packageName)}/versions/${fixture.version}/artifact/download`
) {
response.writeHead(200, {
"content-type": "application/zip",
"content-length": String(archive.length),
"X-ClawHub-ClawPack-Sha256": sha256hash,
"X-ClawHub-ClawPack-Spec-Version": "1",
"content-type": "application/octet-stream",
"content-length": String(clawpack.archive.length),
"X-ClawHub-Artifact-Type": "npm-pack-tarball",
"X-ClawHub-Artifact-Sha256": clawpack.clawpackSha256,
"X-ClawHub-Npm-Integrity": clawpack.npmIntegrity,
"X-ClawHub-Npm-Shasum": clawpack.npmShasum,
});
response.end(archive);
response.end(clawpack.archive);
return;
}
response.writeHead(404, { "content-type": "text/plain" });

View File

@@ -389,12 +389,7 @@ function assertInstalled() {
if (!record.version || !record.integrity || !record.resolvedAt) {
throw new Error(`missing ClawHub resolution metadata: ${JSON.stringify(record)}`);
}
if (
!record.clawpackSha256 ||
record.clawpackSpecVersion !== 1 ||
!record.clawpackManifestSha256 ||
typeof record.clawpackSize !== "number"
) {
if (!record.clawpackSha256 || typeof record.clawpackSize !== "number") {
throw new Error(`missing kitchen-sink ClawPack metadata: ${JSON.stringify(record)}`);
}
}

View File

@@ -534,12 +534,7 @@ function assertClawHubInstalled() {
if (typeof record.installPath !== "string" || record.installPath.length === 0) {
throw new Error(`missing ClawHub install path for ${pluginId}`);
}
if (
!record.clawpackSha256 ||
record.clawpackSpecVersion !== 1 ||
!record.clawpackManifestSha256 ||
typeof record.clawpackSize !== "number"
) {
if (!record.clawpackSha256 || typeof record.clawpackSize !== "number") {
throw new Error(`missing ClawHub ClawPack metadata for ${pluginId}: ${JSON.stringify(record)}`);
}