Fix full local gate on main

This commit is contained in:
Tak Hoffman 2026-03-14 15:51:21 -05:00
parent 678ea77dcf
commit e81442ac80
12 changed files with 31 additions and 47 deletions

View File

@ -88,6 +88,9 @@ fi
pnpm -s exec tsc -p "$A2UI_RENDERER_DIR/tsconfig.json" pnpm -s exec tsc -p "$A2UI_RENDERER_DIR/tsconfig.json"
if command -v rolldown >/dev/null 2>&1 && rolldown --version >/dev/null 2>&1; then if command -v rolldown >/dev/null 2>&1 && rolldown --version >/dev/null 2>&1; then
rolldown -c "$A2UI_APP_DIR/rolldown.config.mjs" rolldown -c "$A2UI_APP_DIR/rolldown.config.mjs"
elif [[ -f "$ROOT_DIR/node_modules/.pnpm/rolldown@1.0.0-rc.9/node_modules/rolldown/bin/cli.mjs" ]]; then
node "$ROOT_DIR/node_modules/.pnpm/rolldown@1.0.0-rc.9/node_modules/rolldown/bin/cli.mjs" \
-c "$A2UI_APP_DIR/rolldown.config.mjs"
else else
pnpm -s dlx rolldown -c "$A2UI_APP_DIR/rolldown.config.mjs" pnpm -s dlx rolldown -c "$A2UI_APP_DIR/rolldown.config.mjs"
fi fi

View File

@ -86,8 +86,6 @@ function expectSupportsDeveloperRoleForcedOff(overrides?: Partial<Model<Api>>):
const normalized = normalizeModelCompat(model as Model<Api>); const normalized = normalizeModelCompat(model as Model<Api>);
expect(supportsDeveloperRole(normalized)).toBe(false); expect(supportsDeveloperRole(normalized)).toBe(false);
} }
function expectResolvedForwardCompat( function expectResolvedForwardCompat(
model: Model<Api> | undefined, model: Model<Api> | undefined,
expected: { provider: string; id: string }, expected: { provider: string; id: string },

View File

@ -313,6 +313,7 @@ describe("canvas host", () => {
const linkPath = path.join(a2uiRoot, linkName); const linkPath = path.join(a2uiRoot, linkName);
let createdBundle = false; let createdBundle = false;
let createdLink = false; let createdLink = false;
let server: Awaited<ReturnType<typeof startFixtureCanvasHost>> | undefined;
try { try {
await fs.stat(bundlePath); await fs.stat(bundlePath);
@ -324,17 +325,16 @@ describe("canvas host", () => {
await fs.symlink(path.join(process.cwd(), "package.json"), linkPath); await fs.symlink(path.join(process.cwd(), "package.json"), linkPath);
createdLink = true; createdLink = true;
let server: Awaited<ReturnType<typeof startFixtureCanvasHost>>;
try { try {
server = await startFixtureCanvasHost(dir); try {
} catch (error) { server = await startFixtureCanvasHost(dir);
if (isLoopbackBindDenied(error)) { } catch (error) {
return; if (isLoopbackBindDenied(error)) {
return;
}
throw error;
} }
throw error;
}
try {
const res = await fetch(`http://127.0.0.1:${server.port}/__openclaw__/a2ui/`); const res = await fetch(`http://127.0.0.1:${server.port}/__openclaw__/a2ui/`);
const html = await res.text(); const html = await res.text();
expect(res.status).toBe(200); expect(res.status).toBe(200);
@ -356,7 +356,7 @@ describe("canvas host", () => {
expect(symlinkRes.status).toBe(404); expect(symlinkRes.status).toBe(404);
expect(await symlinkRes.text()).toBe("not found"); expect(await symlinkRes.text()).toBe("not found");
} finally { } finally {
await server.close(); await server?.close();
if (createdLink) { if (createdLink) {
await fs.rm(linkPath, { force: true }); await fs.rm(linkPath, { force: true });
} }

View File

@ -111,9 +111,12 @@ describe("Nix integration (U3, U5, U9)", () => {
}); });
it("CONFIG_PATH uses STATE_DIR when only state dir is overridden", () => { it("CONFIG_PATH uses STATE_DIR when only state dir is overridden", () => {
expect(resolveConfigPathCandidate(envWith({ OPENCLAW_STATE_DIR: "/custom/state" }))).toBe( expect(
path.join(path.resolve("/custom/state"), "openclaw.json"), resolveConfigPathCandidate(
); envWith({ OPENCLAW_STATE_DIR: "/custom/state", OPENCLAW_TEST_FAST: "1" }),
() => path.join(path.sep, "tmp", "openclaw-config-home"),
),
).toBe(path.join(path.resolve("/custom/state"), "openclaw.json"));
}); });
}); });

View File

@ -44,7 +44,6 @@ async function writePluginFixture(params: {
} }
describe("config plugin validation", () => { describe("config plugin validation", () => {
const previousUmask = process.umask(0o022);
let fixtureRoot = ""; let fixtureRoot = "";
let suiteHome = ""; let suiteHome = "";
let badPluginDir = ""; let badPluginDir = "";
@ -136,7 +135,6 @@ describe("config plugin validation", () => {
afterAll(async () => { afterAll(async () => {
await fs.rm(fixtureRoot, { recursive: true, force: true }); await fs.rm(fixtureRoot, { recursive: true, force: true });
clearPluginManifestRegistryCache(); clearPluginManifestRegistryCache();
process.umask(previousUmask);
}); });
it("reports missing plugin refs across load paths, entries, and allowlist surfaces", async () => { it("reports missing plugin refs across load paths, entries, and allowlist surfaces", async () => {

View File

@ -1,7 +1,7 @@
import fs from "node:fs"; import fs from "node:fs";
import os from "node:os"; import os from "node:os";
import path from "node:path"; import path from "node:path";
import { afterAll, afterEach, describe, expect, it } from "vitest"; import { afterEach, describe, expect, it } from "vitest";
import { clearPluginDiscoveryCache } from "../plugins/discovery.js"; import { clearPluginDiscoveryCache } from "../plugins/discovery.js";
import { import {
clearPluginManifestRegistryCache, clearPluginManifestRegistryCache,
@ -11,7 +11,6 @@ import { validateConfigObject } from "./config.js";
import { applyPluginAutoEnable } from "./plugin-auto-enable.js"; import { applyPluginAutoEnable } from "./plugin-auto-enable.js";
const tempDirs: string[] = []; const tempDirs: string[] = [];
const previousUmask = process.umask(0o022);
function chmodSafeDir(dir: string) { function chmodSafeDir(dir: string) {
if (process.platform === "win32") { if (process.platform === "win32") {
@ -126,10 +125,6 @@ afterEach(() => {
} }
}); });
afterAll(() => {
process.umask(previousUmask);
});
describe("applyPluginAutoEnable", () => { describe("applyPluginAutoEnable", () => {
it("auto-enables built-in channels and appends to existing allowlist", () => { it("auto-enables built-in channels and appends to existing allowlist", () => {
const result = applyWithSlackConfig({ plugins: { allow: ["telegram"] } }); const result = applyWithSlackConfig({ plugins: { allow: ["telegram"] } });

View File

@ -1,7 +1,7 @@
import fs from "node:fs/promises"; import fs from "node:fs/promises";
import os from "node:os"; import os from "node:os";
import path from "node:path"; import path from "node:path";
import { describe, expect, it } from "vitest"; import { describe, expect, it, vi } from "vitest";
import { loadDotEnv } from "./dotenv.js"; import { loadDotEnv } from "./dotenv.js";
async function writeEnvFile(filePath: string, contents: string) { async function writeEnvFile(filePath: string, contents: string) {
@ -11,11 +11,10 @@ async function writeEnvFile(filePath: string, contents: string) {
async function withIsolatedEnvAndCwd(run: () => Promise<void>) { async function withIsolatedEnvAndCwd(run: () => Promise<void>) {
const prevEnv = { ...process.env }; const prevEnv = { ...process.env };
const prevCwd = process.cwd();
try { try {
await run(); await run();
} finally { } finally {
process.chdir(prevCwd); vi.restoreAllMocks();
for (const key of Object.keys(process.env)) { for (const key of Object.keys(process.env)) {
if (!(key in prevEnv)) { if (!(key in prevEnv)) {
delete process.env[key]; delete process.env[key];
@ -54,7 +53,7 @@ describe("loadDotEnv", () => {
await writeEnvFile(path.join(stateDir, ".env"), "FOO=from-global\nBAR=1\n"); await writeEnvFile(path.join(stateDir, ".env"), "FOO=from-global\nBAR=1\n");
await writeEnvFile(path.join(cwdDir, ".env"), "FOO=from-cwd\n"); await writeEnvFile(path.join(cwdDir, ".env"), "FOO=from-cwd\n");
process.chdir(cwdDir); vi.spyOn(process, "cwd").mockReturnValue(cwdDir);
delete process.env.FOO; delete process.env.FOO;
delete process.env.BAR; delete process.env.BAR;
@ -74,7 +73,7 @@ describe("loadDotEnv", () => {
await writeEnvFile(path.join(stateDir, ".env"), "FOO=from-global\n"); await writeEnvFile(path.join(stateDir, ".env"), "FOO=from-global\n");
await writeEnvFile(path.join(cwdDir, ".env"), "FOO=from-cwd\n"); await writeEnvFile(path.join(cwdDir, ".env"), "FOO=from-cwd\n");
process.chdir(cwdDir); vi.spyOn(process, "cwd").mockReturnValue(cwdDir);
loadDotEnv({ quiet: true }); loadDotEnv({ quiet: true });
@ -87,7 +86,7 @@ describe("loadDotEnv", () => {
await withIsolatedEnvAndCwd(async () => { await withIsolatedEnvAndCwd(async () => {
await withDotEnvFixture(async ({ cwdDir, stateDir }) => { await withDotEnvFixture(async ({ cwdDir, stateDir }) => {
await writeEnvFile(path.join(stateDir, ".env"), "FOO=from-global\n"); await writeEnvFile(path.join(stateDir, ".env"), "FOO=from-global\n");
process.chdir(cwdDir); vi.spyOn(process, "cwd").mockReturnValue(cwdDir);
delete process.env.FOO; delete process.env.FOO;
loadDotEnv({ quiet: true }); loadDotEnv({ quiet: true });

View File

@ -42,7 +42,6 @@ describe("git commit resolution", () => {
const repoRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "../.."); const repoRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "../..");
beforeEach(async () => { beforeEach(async () => {
process.chdir(repoRoot);
vi.restoreAllMocks(); vi.restoreAllMocks();
vi.doUnmock("node:fs"); vi.doUnmock("node:fs");
vi.doUnmock("node:module"); vi.doUnmock("node:module");
@ -52,7 +51,6 @@ describe("git commit resolution", () => {
}); });
afterEach(async () => { afterEach(async () => {
process.chdir(repoRoot);
vi.restoreAllMocks(); vi.restoreAllMocks();
vi.doUnmock("node:fs"); vi.doUnmock("node:fs");
vi.doUnmock("node:module"); vi.doUnmock("node:module");
@ -87,9 +85,9 @@ describe("git commit resolution", () => {
.trim() .trim()
.slice(0, 7); .slice(0, 7);
process.chdir(otherRepo);
const { resolveCommitHash } = await import("./git-commit.js"); const { resolveCommitHash } = await import("./git-commit.js");
const entryModuleUrl = pathToFileURL(path.join(repoRoot, "src", "entry.ts")).href; const entryModuleUrl = pathToFileURL(path.join(repoRoot, "src", "entry.ts")).href;
vi.spyOn(process, "cwd").mockReturnValue(otherRepo);
expect(resolveCommitHash({ moduleUrl: entryModuleUrl })).toBe(repoHead); expect(resolveCommitHash({ moduleUrl: entryModuleUrl })).toBe(repoHead);
expect(resolveCommitHash({ moduleUrl: entryModuleUrl })).not.toBe(otherHead); expect(resolveCommitHash({ moduleUrl: entryModuleUrl })).not.toBe(otherHead);

View File

@ -1,6 +1,6 @@
import fs from "node:fs"; import fs from "node:fs";
import path from "node:path"; import path from "node:path";
import { afterAll, afterEach, describe, expect, it } from "vitest"; import { afterEach, describe, expect, it } from "vitest";
import { clearPluginDiscoveryCache, discoverOpenClawPlugins } from "./discovery.js"; import { clearPluginDiscoveryCache, discoverOpenClawPlugins } from "./discovery.js";
import { import {
cleanupTrackedTempDirs, cleanupTrackedTempDirs,
@ -9,7 +9,6 @@ import {
} from "./test-helpers/fs-fixtures.js"; } from "./test-helpers/fs-fixtures.js";
const tempDirs: string[] = []; const tempDirs: string[] = [];
const previousUmask = process.umask(0o022);
function makeTempDir() { function makeTempDir() {
return makeTrackedTempDir("openclaw-plugins", tempDirs); return makeTrackedTempDir("openclaw-plugins", tempDirs);
@ -59,10 +58,6 @@ afterEach(() => {
cleanupTrackedTempDirs(tempDirs); cleanupTrackedTempDirs(tempDirs);
}); });
afterAll(() => {
process.umask(previousUmask);
});
describe("discoverOpenClawPlugins", () => { describe("discoverOpenClawPlugins", () => {
it("discovers global and workspace extensions", async () => { it("discovers global and workspace extensions", async () => {
const stateDir = makeTempDir(); const stateDir = makeTempDir();

View File

@ -34,7 +34,6 @@ const {
loadOpenClawPlugins, loadOpenClawPlugins,
resetGlobalHookRunner, resetGlobalHookRunner,
} = await importFreshPluginTestModules(); } = await importFreshPluginTestModules();
const previousUmask = process.umask(0o022);
type TempPlugin = { dir: string; file: string; id: string }; type TempPlugin = { dir: string; file: string; id: string };
@ -300,7 +299,6 @@ afterAll(() => {
} catch { } catch {
// ignore cleanup failures // ignore cleanup failures
} finally { } finally {
process.umask(previousUmask);
cachedBundledTelegramDir = ""; cachedBundledTelegramDir = "";
cachedBundledMemoryDir = ""; cachedBundledMemoryDir = "";
} }

View File

@ -1,6 +1,6 @@
import fs from "node:fs"; import fs from "node:fs";
import path from "node:path"; import path from "node:path";
import { afterAll, afterEach, describe, expect, it } from "vitest"; import { afterEach, describe, expect, it } from "vitest";
import type { PluginCandidate } from "./discovery.js"; import type { PluginCandidate } from "./discovery.js";
import { import {
clearPluginManifestRegistryCache, clearPluginManifestRegistryCache,
@ -9,7 +9,6 @@ import {
import { cleanupTrackedTempDirs, makeTrackedTempDir } from "./test-helpers/fs-fixtures.js"; import { cleanupTrackedTempDirs, makeTrackedTempDir } from "./test-helpers/fs-fixtures.js";
const tempDirs: string[] = []; const tempDirs: string[] = [];
const previousUmask = process.umask(0o022);
function chmodSafeDir(dir: string) { function chmodSafeDir(dir: string) {
if (process.platform === "win32") { if (process.platform === "win32") {
@ -132,10 +131,6 @@ afterEach(() => {
cleanupTrackedTempDirs(tempDirs); cleanupTrackedTempDirs(tempDirs);
}); });
afterAll(() => {
process.umask(previousUmask);
});
describe("loadPluginManifestRegistry", () => { describe("loadPluginManifestRegistry", () => {
it("emits duplicate warning for truly distinct plugins with same id", () => { it("emits duplicate warning for truly distinct plugins with same id", () => {
const dirA = makeTempDir(); const dirA = makeTempDir();

View File

@ -206,11 +206,13 @@ describe("resolveJidToE164", () => {
describe("resolveUserPath", () => { describe("resolveUserPath", () => {
it("expands ~ to home dir", () => { it("expands ~ to home dir", () => {
expect(resolveUserPath("~")).toBe(path.resolve(os.homedir())); expect(resolveUserPath("~", {}, () => "/Users/thoffman")).toBe(path.resolve("/Users/thoffman"));
}); });
it("expands ~/ to home dir", () => { it("expands ~/ to home dir", () => {
expect(resolveUserPath("~/openclaw")).toBe(path.resolve(os.homedir(), "openclaw")); expect(resolveUserPath("~/openclaw", {}, () => "/Users/thoffman")).toBe(
path.resolve("/Users/thoffman", "openclaw"),
);
}); });
it("resolves relative paths", () => { it("resolves relative paths", () => {