import { execFileSync } from "node:child_process"; import { mkdtempSync, mkdirSync, rmSync, writeFileSync } from "node:fs"; import { tmpdir } from "node:os"; import { join } from "node:path"; import { describe, expect, it } from "vitest"; const ASSERTIONS_PATH = "scripts/e2e/lib/upgrade-survivor/assertions.mjs"; function writeJson(path: string, value: unknown): void { writeFileSync(path, `${JSON.stringify(value, null, 2)}\n`); } function assertConfiguredPluginState(params: { installPath?: string } = {}): void { const root = mkdtempSync(join(tmpdir(), "openclaw-upgrade-survivor-")); try { const stateDir = join(root, "state"); const workspace = join(root, "workspace"); const matrixInstallDir = params.installPath ?? join(stateDir, "extensions", "matrix"); mkdirSync(join(stateDir, "agents", "main", "sessions"), { recursive: true }); mkdirSync(join(stateDir, "plugins"), { recursive: true }); mkdirSync(matrixInstallDir, { recursive: true }); mkdirSync(workspace, { recursive: true }); writeFileSync(join(workspace, "IDENTITY.md"), "# survivor\n"); writeJson(join(stateDir, "agents", "main", "sessions", "legacy-session.json"), { id: "legacy-session", }); writeJson(join(matrixInstallDir, "package.json"), { name: "@openclaw/matrix", }); writeJson(join(stateDir, "plugins", "installs.json"), { installRecords: { matrix: { source: "clawhub", spec: "clawhub:@openclaw/matrix", installPath: matrixInstallDir, clawhubPackage: "@openclaw/matrix", clawhubChannel: "official", artifactKind: "npm-pack", }, }, plugins: [{ pluginId: "matrix", enabled: true }], }); const coveragePath = join(root, "coverage.json"); writeJson(coveragePath, { acceptedIntents: ["configured-plugin-installs"], skippedIntents: [], }); execFileSync(process.execPath, [ASSERTIONS_PATH, "assert-state"], { env: { ...process.env, OPENCLAW_STATE_DIR: stateDir, OPENCLAW_TEST_WORKSPACE_DIR: workspace, OPENCLAW_UPGRADE_SURVIVOR_CONFIG_COVERAGE_JSON: coveragePath, OPENCLAW_UPGRADE_SURVIVOR_SCENARIO: "configured-plugin-installs", }, stdio: "pipe", }); } finally { rmSync(root, { force: true, recursive: true }); } } describe("upgrade survivor assertions", () => { it("accepts official ClawHub npm-pack installs for configured external plugins", () => { expect(() => assertConfiguredPluginState()).not.toThrow(); }); it("rejects ClawHub npm-pack installs outside the managed extensions root", () => { const root = mkdtempSync(join(tmpdir(), "openclaw-upgrade-survivor-outside-")); try { expect(() => assertConfiguredPluginState({ installPath: join(root, "outside-matrix") }), ).toThrow(/managed extensions root/); } finally { rmSync(root, { force: true, recursive: true }); } }); });