import fs from "node:fs"; import http from "node:http"; import os from "node:os"; import path from "node:path"; import { legacyPackageAcceptanceCompat } from "../package-compat.mjs"; const home = os.homedir(); const readJson = (file) => { try { return JSON.parse(fs.readFileSync(file, "utf8")); } catch { return {}; } }; const pluginRecordSnapshot = () => { const config = readJson(openclawPath("openclaw.json")); const index = readJson(openclawPath("plugins", "installs.json")); const records = index.installRecords ?? index.records ?? config.plugins?.installs ?? {}; const record = records["lossless-claw"] ?? records["@example/lossless-claw"]; if (!record) { throw new Error("missing plugin install record"); } const { source, spec, resolvedName, resolvedVersion, resolvedSpec, integrity, shasum } = record; return { source, spec, resolvedName, resolvedVersion, resolvedSpec, integrity, shasum }; }; function openclawPath(...parts) { return path.join(home, ".openclaw", ...parts); } function writeJson(file, value) { fs.mkdirSync(path.dirname(file), { recursive: true }); fs.writeFileSync(file, `${JSON.stringify(value, null, 2)}\n`); } function seedInstallState() { writeJson(openclawPath("extensions", "lossless-claw", "package.json"), { name: "@example/lossless-claw", version: "0.9.0", }); writeJson(process.env.OPENCLAW_CONFIG_PATH, { plugins: {} }); writeJson(openclawPath("plugins", "installs.json"), { version: 1, warning: "DO NOT EDIT. This file is generated by OpenClaw plugin registry commands.", hostContractVersion: "docker-e2e", compatRegistryVersion: "docker-e2e", migrationVersion: 1, policyHash: "docker-e2e", generatedAtMs: 1777118400000, installRecords: { "lossless-claw": { source: "npm", spec: "@example/lossless-claw@0.9.0", installPath: "~/.openclaw/extensions/lossless-claw", resolvedName: "@example/lossless-claw", resolvedVersion: "0.9.0", resolvedSpec: "@example/lossless-claw@0.9.0", integrity: "sha512-same", shasum: "same", }, }, plugins: [], diagnostics: [], }); } async function waitRegistry() { for (let attempt = 0; attempt < 50; attempt += 1) { if (await registryHealthy()) { return; } await new Promise((resolve) => setTimeout(resolve, 100)); } throw new Error("Local npm metadata registry failed to start"); } function registryHealthy() { return new Promise((resolve) => { const req = http.get("http://127.0.0.1:4873/@example%2flossless-claw", (res) => { resolve(res.statusCode === 200); res.resume(); }); req.on("error", () => resolve(false)); req.setTimeout(200, () => { req.destroy(); resolve(false); }); }); } function assertSnapshot(beforePath) { const before = readJson(beforePath); const after = pluginRecordSnapshot(); if (JSON.stringify(before) !== JSON.stringify(after)) { throw new Error( `plugin install record changed unexpectedly: ${JSON.stringify({ before, after })}`, ); } } function assertOutput(logPath) { const output = fs.readFileSync(logPath, "utf8"); const failure = output.includes("Downloading @example/lossless-claw") ? "Unexpected npm download/reinstall path" : !output.includes("lossless-claw is up to date (0.9.0).") ? "Expected up-to-date output missing" : ""; if (failure) { throw new Error(`${failure}\n${output}`); } } const [command, arg] = process.argv.slice(2); const commands = { "legacy-compat": () => console.log(legacyPackageAcceptanceCompat(arg || "") ? "1" : "0"), seed: seedInstallState, "wait-registry": waitRegistry, snapshot: () => process.stdout.write(JSON.stringify(pluginRecordSnapshot(), null, 2)), "assert-snapshot": () => assertSnapshot(arg), "assert-output": () => assertOutput(arg), }; const run = commands[command]; await ( run ?? (() => { throw new Error(`Unknown plugin update probe command: ${command || "(missing)"}`); }) )();