mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-06 04:50:44 +00:00
refactor: remove plugin dependency cleanup leftovers
This commit is contained in:
@@ -185,7 +185,7 @@ current OpenClaw or a local checkout until a newer npm package is published.
|
||||
|
||||
<Accordion title="Memory plugins">
|
||||
- `memory-core` — bundled memory search (default via `plugins.slots.memory`)
|
||||
- `memory-lancedb` — install-on-demand long-term memory with auto-recall/capture (set `plugins.slots.memory = "memory-lancedb"`)
|
||||
- `memory-lancedb` — LanceDB-backed long-term memory with auto-recall/capture (set `plugins.slots.memory = "memory-lancedb"`)
|
||||
|
||||
See [Memory LanceDB](/plugins/memory-lancedb) for OpenAI-compatible
|
||||
embedding setup, Ollama examples, recall limits, and troubleshooting.
|
||||
|
||||
@@ -113,7 +113,7 @@ async function resolveInstalledAcpPackageBinPath(
|
||||
|
||||
async function resolveInstalledCodexAcpBinPath(): Promise<string | undefined> {
|
||||
// Keep OpenClaw's isolated CODEX_HOME wrapper, but launch the plugin-local
|
||||
// Codex ACP adapter when runtime-deps staging made it available.
|
||||
// Codex ACP adapter when the package dependency is available.
|
||||
return await resolveInstalledAcpPackageBinPath(CODEX_ACP_PACKAGE, CODEX_ACP_BIN);
|
||||
}
|
||||
|
||||
|
||||
@@ -100,7 +100,7 @@ export function createMantleAnthropicStreamFn(deps?: {
|
||||
),
|
||||
});
|
||||
const base = buildMantleAnthropicBaseOptions(model, options, apiKey);
|
||||
// Staged plugin runtime deps can give this plugin a distinct physical SDK copy.
|
||||
// Plugin package deps can give this plugin a distinct physical SDK copy.
|
||||
// The client API is the same, but the SDK class private field makes types nominal.
|
||||
const streamClient = client as unknown as AnthropicStreamClient;
|
||||
if (!options?.reasoning || requiresDefaultSampling(model.id)) {
|
||||
|
||||
@@ -68,7 +68,7 @@ describe("deliverDiscordReply", () => {
|
||||
});
|
||||
});
|
||||
|
||||
it("bridges regular replies to shared outbound with Discord runtime deps", async () => {
|
||||
it("bridges regular replies to shared outbound with Discord package deps", async () => {
|
||||
const rest = {} as RequestClient;
|
||||
const replies = [{ text: "shared path" }];
|
||||
|
||||
|
||||
@@ -12,8 +12,6 @@ import { formatErrorMessage } from "../dreaming-shared.js";
|
||||
import { filterUnregisteredMemoryEmbeddingProviderAdapters } from "./provider-adapter-registration.js";
|
||||
|
||||
const NODE_LLAMA_CPP_RUNTIME_PACKAGE = "node-llama-cpp";
|
||||
const NODE_LLAMA_CPP_RUNTIME_VERSION = "3.18.1";
|
||||
const NODE_LLAMA_CPP_INSTALL_SPEC = `${NODE_LLAMA_CPP_RUNTIME_PACKAGE}@${NODE_LLAMA_CPP_RUNTIME_VERSION}`;
|
||||
|
||||
export type BuiltinMemoryEmbeddingProviderDoctorMetadata = {
|
||||
providerId: string;
|
||||
@@ -59,7 +57,7 @@ function formatLocalSetupError(err: unknown): string {
|
||||
"To enable local embeddings:",
|
||||
"1) Use Node 24 (recommended for installs/updates; Node 22 LTS, currently 22.14+, remains supported)",
|
||||
missing
|
||||
? `2) Run openclaw doctor --fix to repair managed plugin runtime deps for ${NODE_LLAMA_CPP_INSTALL_SPEC}`
|
||||
? `2) Install ${NODE_LLAMA_CPP_RUNTIME_PACKAGE} next to the OpenClaw package or source checkout`
|
||||
: null,
|
||||
`3) If you use pnpm: pnpm approve-builds (select ${NODE_LLAMA_CPP_RUNTIME_PACKAGE}), then pnpm rebuild ${NODE_LLAMA_CPP_RUNTIME_PACKAGE}`,
|
||||
...listRemoteEmbeddingSetupHints(),
|
||||
|
||||
@@ -18,7 +18,7 @@ import memoryPlugin, {
|
||||
normalizeRecallQuery,
|
||||
shouldCapture,
|
||||
} from "./index.js";
|
||||
import { createLanceDbRuntimeLoader, type LanceDbRuntimeLogger } from "./lancedb-runtime.js";
|
||||
import { createLanceDbRuntimeLoader } from "./lancedb-runtime.js";
|
||||
import { installTmpDirHarness } from "./test-helpers.js";
|
||||
|
||||
const OPENAI_API_KEY = process.env.OPENAI_API_KEY ?? "test-key";
|
||||
@@ -38,22 +38,7 @@ type MemoryPluginTestConfig = {
|
||||
storageOptions?: Record<string, string>;
|
||||
};
|
||||
|
||||
const TEST_RUNTIME_MANIFEST = {
|
||||
name: "openclaw-memory-lancedb-runtime",
|
||||
private: true as const,
|
||||
type: "module" as const,
|
||||
dependencies: {
|
||||
"@lancedb/lancedb": "^0.27.1",
|
||||
},
|
||||
};
|
||||
|
||||
type LanceDbModule = typeof import("@lancedb/lancedb");
|
||||
type RuntimeManifest = {
|
||||
name: string;
|
||||
private: true;
|
||||
type: "module";
|
||||
dependencies: Record<string, string>;
|
||||
};
|
||||
|
||||
function createMockModule(): LanceDbModule {
|
||||
return {
|
||||
@@ -67,40 +52,19 @@ function invokeEmbeddingCreate(mock: ReturnType<typeof vi.fn>, body: unknown) {
|
||||
|
||||
function createRuntimeLoader(
|
||||
overrides: {
|
||||
env?: NodeJS.ProcessEnv;
|
||||
importBundled?: () => Promise<LanceDbModule>;
|
||||
importResolved?: (resolvedPath: string) => Promise<LanceDbModule>;
|
||||
platform?: NodeJS.Platform;
|
||||
arch?: NodeJS.Architecture;
|
||||
resolveRuntimeEntry?: (params: {
|
||||
runtimeDir: string;
|
||||
manifest: RuntimeManifest;
|
||||
}) => string | null;
|
||||
installRuntime?: (params: {
|
||||
runtimeDir: string;
|
||||
manifest: RuntimeManifest;
|
||||
env: NodeJS.ProcessEnv;
|
||||
logger?: LanceDbRuntimeLogger;
|
||||
}) => Promise<string>;
|
||||
} = {},
|
||||
) {
|
||||
return createLanceDbRuntimeLoader({
|
||||
env: overrides.env ?? ({} as NodeJS.ProcessEnv),
|
||||
platform: overrides.platform,
|
||||
arch: overrides.arch,
|
||||
resolveStateDir: () => "/tmp/openclaw-state",
|
||||
runtimeManifest: TEST_RUNTIME_MANIFEST,
|
||||
importBundled:
|
||||
overrides.importBundled ??
|
||||
(async () => {
|
||||
throw new Error("Cannot find package '@lancedb/lancedb'");
|
||||
}),
|
||||
importResolved: overrides.importResolved ?? (async () => createMockModule()),
|
||||
resolveRuntimeEntry: overrides.resolveRuntimeEntry ?? (() => null),
|
||||
installRuntime:
|
||||
overrides.installRuntime ??
|
||||
(async ({ runtimeDir }: { runtimeDir: string }) =>
|
||||
`${runtimeDir}/node_modules/@lancedb/lancedb/index.js`),
|
||||
});
|
||||
}
|
||||
|
||||
@@ -2261,131 +2225,47 @@ describe("lancedb runtime loader", () => {
|
||||
test("uses the bundled module when it is already available", async () => {
|
||||
const bundledModule = createMockModule();
|
||||
const importBundled = vi.fn(async () => bundledModule);
|
||||
const importResolved = vi.fn(async () => createMockModule());
|
||||
const resolveRuntimeEntry = vi.fn(() => null);
|
||||
const installRuntime = vi.fn(async () => "/tmp/openclaw-state/plugin-runtimes/lancedb.js");
|
||||
const loader = createRuntimeLoader({
|
||||
importBundled,
|
||||
importResolved,
|
||||
resolveRuntimeEntry,
|
||||
installRuntime,
|
||||
});
|
||||
|
||||
await expect(loader.load()).resolves.toBe(bundledModule);
|
||||
|
||||
expect(resolveRuntimeEntry).not.toHaveBeenCalled();
|
||||
expect(installRuntime).not.toHaveBeenCalled();
|
||||
expect(importResolved).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
test("reuses an existing user runtime install before attempting a reinstall", async () => {
|
||||
const runtimeModule = createMockModule();
|
||||
const importResolved = vi.fn(async () => runtimeModule);
|
||||
const resolveRuntimeEntry = vi.fn(
|
||||
() => "/tmp/openclaw-state/plugin-runtimes/memory-lancedb/runtime-entry.js",
|
||||
);
|
||||
const installRuntime = vi.fn(
|
||||
async () => "/tmp/openclaw-state/plugin-runtimes/memory-lancedb/runtime-entry.js",
|
||||
);
|
||||
const loader = createRuntimeLoader({
|
||||
importResolved,
|
||||
resolveRuntimeEntry,
|
||||
installRuntime,
|
||||
});
|
||||
|
||||
await expect(loader.load()).resolves.toBe(runtimeModule);
|
||||
|
||||
expect(resolveRuntimeEntry).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
runtimeDir: "/tmp/openclaw-state/plugin-runtimes/memory-lancedb/lancedb",
|
||||
}),
|
||||
);
|
||||
expect(installRuntime).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
test("installs LanceDB into user state when the bundled runtime is unavailable", async () => {
|
||||
const runtimeModule = createMockModule();
|
||||
const logger: LanceDbRuntimeLogger = {
|
||||
warn: vi.fn(),
|
||||
info: vi.fn(),
|
||||
};
|
||||
const importResolved = vi.fn(async () => runtimeModule);
|
||||
const resolveRuntimeEntry = vi.fn(() => null);
|
||||
const installRuntime = vi.fn(
|
||||
async ({ runtimeDir }: { runtimeDir: string }) =>
|
||||
`${runtimeDir}/node_modules/@lancedb/lancedb/index.js`,
|
||||
);
|
||||
const loader = createRuntimeLoader({
|
||||
importResolved,
|
||||
resolveRuntimeEntry,
|
||||
installRuntime,
|
||||
});
|
||||
|
||||
await expect(loader.load(logger)).resolves.toBe(runtimeModule);
|
||||
|
||||
expect(installRuntime).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
runtimeDir: "/tmp/openclaw-state/plugin-runtimes/memory-lancedb/lancedb",
|
||||
manifest: TEST_RUNTIME_MANIFEST,
|
||||
}),
|
||||
);
|
||||
expect(logger.warn).toHaveBeenCalledWith(
|
||||
expect.stringContaining(
|
||||
"installing runtime deps under /tmp/openclaw-state/plugin-runtimes/memory-lancedb/lancedb",
|
||||
),
|
||||
);
|
||||
});
|
||||
|
||||
test("fails fast in nix mode instead of attempting auto-install", async () => {
|
||||
const installRuntime = vi.fn(
|
||||
async ({ runtimeDir }: { runtimeDir: string }) =>
|
||||
`${runtimeDir}/node_modules/@lancedb/lancedb/index.js`,
|
||||
);
|
||||
const loader = createRuntimeLoader({
|
||||
env: { OPENCLAW_NIX_MODE: "1" } as NodeJS.ProcessEnv,
|
||||
installRuntime,
|
||||
});
|
||||
|
||||
await expect(loader.load()).rejects.toThrow(
|
||||
"memory-lancedb: failed to load LanceDB and Nix mode disables auto-install.",
|
||||
);
|
||||
expect(installRuntime).not.toHaveBeenCalled();
|
||||
expect(importBundled).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
test("fails clearly on Intel macOS instead of attempting an unsupported native install", async () => {
|
||||
const installRuntime = vi.fn(
|
||||
async ({ runtimeDir }: { runtimeDir: string }) =>
|
||||
`${runtimeDir}/node_modules/@lancedb/lancedb/index.js`,
|
||||
);
|
||||
const loader = createRuntimeLoader({
|
||||
platform: "darwin",
|
||||
arch: "x64",
|
||||
installRuntime,
|
||||
});
|
||||
|
||||
await expect(loader.load()).rejects.toThrow(
|
||||
"memory-lancedb: LanceDB runtime is unavailable on darwin-x64.",
|
||||
);
|
||||
expect(installRuntime).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
test("clears the cached failure so later calls can retry the install", async () => {
|
||||
test("fails fast when package dependencies are missing", async () => {
|
||||
const loader = createRuntimeLoader();
|
||||
|
||||
await expect(loader.load()).rejects.toThrow(
|
||||
"memory-lancedb: bundled @lancedb/lancedb dependency is unavailable.",
|
||||
);
|
||||
});
|
||||
|
||||
test("clears the cached failure so later calls can retry the package import", async () => {
|
||||
const runtimeModule = createMockModule();
|
||||
const installRuntime = vi
|
||||
const importBundled = vi
|
||||
.fn()
|
||||
.mockRejectedValueOnce(new Error("network down"))
|
||||
.mockResolvedValueOnce(
|
||||
"/tmp/openclaw-state/plugin-runtimes/memory-lancedb/lancedb/node_modules/@lancedb/lancedb/index.js",
|
||||
);
|
||||
const importResolved = vi.fn(async () => runtimeModule);
|
||||
.mockResolvedValueOnce(runtimeModule);
|
||||
const loader = createRuntimeLoader({
|
||||
installRuntime,
|
||||
importResolved,
|
||||
importBundled,
|
||||
});
|
||||
|
||||
await expect(loader.load()).rejects.toThrow("network down");
|
||||
await expect(loader.load()).resolves.toBe(runtimeModule);
|
||||
|
||||
expect(installRuntime).toHaveBeenCalledTimes(2);
|
||||
expect(importBundled).toHaveBeenCalledTimes(2);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,87 +0,0 @@
|
||||
import path from "node:path";
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { resolveLanceDbDependencySpec } from "./lancedb-runtime.js";
|
||||
|
||||
function mapReader(
|
||||
entries: ReadonlyArray<[string, { dependencies?: Record<string, string> } | null]>,
|
||||
): (manifestPath: string) => { dependencies?: Record<string, string> } | null {
|
||||
const byPath = new Map(
|
||||
entries.map(([manifestPath, value]) => [path.normalize(manifestPath), value]),
|
||||
);
|
||||
return (manifestPath: string) => byPath.get(path.normalize(manifestPath)) ?? null;
|
||||
}
|
||||
|
||||
describe("resolveLanceDbDependencySpec", () => {
|
||||
it("reads dependency from source-layout sibling manifest", () => {
|
||||
const modulePath = path.join("/repo/extensions/memory-lancedb", "lancedb-runtime.js");
|
||||
const packagePath = path.join("/repo/extensions/memory-lancedb", "package.json");
|
||||
const readPackageJson = mapReader([
|
||||
[
|
||||
packagePath,
|
||||
{
|
||||
dependencies: { "@lancedb/lancedb": "^0.27.1" },
|
||||
},
|
||||
],
|
||||
]);
|
||||
|
||||
expect(resolveLanceDbDependencySpec(modulePath, readPackageJson)).toBe("^0.27.1");
|
||||
});
|
||||
|
||||
it("falls back to dist/extensions memory-lancedb manifest for flattened bundles", () => {
|
||||
const modulePath = path.join(
|
||||
"/usr/lib/node_modules/openclaw/dist",
|
||||
"lancedb-runtime-3m75WU-W.js",
|
||||
);
|
||||
const distPackagePath = path.join("/usr/lib/node_modules/openclaw/dist", "package.json");
|
||||
const extensionPackagePath = path.join(
|
||||
"/usr/lib/node_modules/openclaw/dist/extensions/memory-lancedb",
|
||||
"package.json",
|
||||
);
|
||||
const readPackageJson = mapReader([
|
||||
[distPackagePath, { dependencies: {} }],
|
||||
[
|
||||
extensionPackagePath,
|
||||
{
|
||||
dependencies: { "@lancedb/lancedb": "^0.27.1" },
|
||||
},
|
||||
],
|
||||
]);
|
||||
|
||||
expect(resolveLanceDbDependencySpec(modulePath, readPackageJson)).toBe("^0.27.1");
|
||||
});
|
||||
|
||||
it("walks parent directories to support nested dist chunk paths", () => {
|
||||
const modulePath = path.join(
|
||||
"/usr/lib/node_modules/openclaw/dist/chunks/runtime",
|
||||
"lancedb-runtime-3m75WU-W.js",
|
||||
);
|
||||
const extensionPackagePath = path.join(
|
||||
"/usr/lib/node_modules/openclaw/dist/extensions/memory-lancedb",
|
||||
"package.json",
|
||||
);
|
||||
const readPackageJson = mapReader([
|
||||
[
|
||||
extensionPackagePath,
|
||||
{
|
||||
dependencies: { "@lancedb/lancedb": "0.27.2" },
|
||||
},
|
||||
],
|
||||
]);
|
||||
|
||||
expect(resolveLanceDbDependencySpec(modulePath, readPackageJson)).toBe("0.27.2");
|
||||
});
|
||||
|
||||
it("throws when no candidate package manifest declares @lancedb/lancedb", () => {
|
||||
const modulePath = path.join(
|
||||
"/usr/lib/node_modules/openclaw/dist",
|
||||
"lancedb-runtime-3m75WU-W.js",
|
||||
);
|
||||
const readPackageJson = mapReader([
|
||||
[path.join("/usr/lib/node_modules/openclaw/dist", "package.json"), null],
|
||||
]);
|
||||
|
||||
expect(() => resolveLanceDbDependencySpec(modulePath, readPackageJson)).toThrow(
|
||||
'memory-lancedb package.json is missing "@lancedb/lancedb"',
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -1,11 +1,3 @@
|
||||
import { spawn } from "node:child_process";
|
||||
import fs from "node:fs";
|
||||
import { createRequire } from "node:module";
|
||||
import os from "node:os";
|
||||
import path from "node:path";
|
||||
import { fileURLToPath, pathToFileURL } from "node:url";
|
||||
import { resolveStateDir } from "./api.js";
|
||||
|
||||
type LanceDbModule = typeof import("@lancedb/lancedb");
|
||||
|
||||
export type LanceDbRuntimeLogger = {
|
||||
@@ -13,211 +5,18 @@ export type LanceDbRuntimeLogger = {
|
||||
warn?: (message: string) => void;
|
||||
};
|
||||
|
||||
type RuntimeManifest = {
|
||||
name: string;
|
||||
private: true;
|
||||
type: "module";
|
||||
dependencies: Record<string, string>;
|
||||
};
|
||||
|
||||
type PackageJsonWithDependencies = {
|
||||
dependencies?: Record<string, string>;
|
||||
};
|
||||
|
||||
type ReadPackageJson = (manifestPath: string) => PackageJsonWithDependencies | null;
|
||||
|
||||
type LanceDbRuntimeLoaderDeps = {
|
||||
env: NodeJS.ProcessEnv;
|
||||
platform: NodeJS.Platform;
|
||||
arch: NodeJS.Architecture;
|
||||
resolveStateDir: (env?: NodeJS.ProcessEnv, homedir?: () => string) => string;
|
||||
runtimeManifest: RuntimeManifest;
|
||||
importBundled: () => Promise<LanceDbModule>;
|
||||
importResolved: (resolvedPath: string) => Promise<LanceDbModule>;
|
||||
resolveRuntimeEntry: (params: { runtimeDir: string; manifest: RuntimeManifest }) => string | null;
|
||||
installRuntime: (params: {
|
||||
runtimeDir: string;
|
||||
manifest: RuntimeManifest;
|
||||
env: NodeJS.ProcessEnv;
|
||||
logger?: LanceDbRuntimeLogger;
|
||||
}) => Promise<string>;
|
||||
};
|
||||
|
||||
function defaultReadPackageJson(manifestPath: string): PackageJsonWithDependencies | null {
|
||||
try {
|
||||
return JSON.parse(fs.readFileSync(manifestPath, "utf8")) as PackageJsonWithDependencies;
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
function buildMemoryLanceDbManifestCandidates(modulePath: string): string[] {
|
||||
const moduleDir = path.dirname(modulePath);
|
||||
const candidates = new Set<string>();
|
||||
candidates.add(path.join(moduleDir, "package.json"));
|
||||
|
||||
let cursor = moduleDir;
|
||||
while (true) {
|
||||
candidates.add(path.join(cursor, "extensions", "memory-lancedb", "package.json"));
|
||||
const parent = path.dirname(cursor);
|
||||
if (parent === cursor) {
|
||||
break;
|
||||
}
|
||||
cursor = parent;
|
||||
}
|
||||
|
||||
return [...candidates];
|
||||
}
|
||||
|
||||
export function resolveLanceDbDependencySpec(
|
||||
modulePath: string,
|
||||
readPackageJson: ReadPackageJson = defaultReadPackageJson,
|
||||
): string {
|
||||
for (const manifestPath of buildMemoryLanceDbManifestCandidates(modulePath)) {
|
||||
const lanceDbSpec = readPackageJson(manifestPath)?.dependencies?.["@lancedb/lancedb"];
|
||||
if (lanceDbSpec) {
|
||||
return lanceDbSpec;
|
||||
}
|
||||
}
|
||||
throw new Error('memory-lancedb package.json is missing "@lancedb/lancedb"');
|
||||
}
|
||||
|
||||
const MEMORY_LANCEDB_RUNTIME_MANIFEST: RuntimeManifest = (() => {
|
||||
const lanceDbSpec = resolveLanceDbDependencySpec(fileURLToPath(import.meta.url));
|
||||
return {
|
||||
name: "openclaw-memory-lancedb-runtime",
|
||||
private: true,
|
||||
type: "module",
|
||||
dependencies: {
|
||||
"@lancedb/lancedb": lanceDbSpec,
|
||||
},
|
||||
};
|
||||
})();
|
||||
|
||||
function resolveRuntimeDir(stateDir: string): string {
|
||||
return path.join(stateDir, "plugin-runtimes", "memory-lancedb", "lancedb");
|
||||
}
|
||||
|
||||
function readRuntimeManifest(filePath: string): RuntimeManifest | null {
|
||||
try {
|
||||
return JSON.parse(fs.readFileSync(filePath, "utf8")) as RuntimeManifest;
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
function manifestsMatch(actual: RuntimeManifest | null, expected: RuntimeManifest): boolean {
|
||||
if (!actual) {
|
||||
return false;
|
||||
}
|
||||
return JSON.stringify(actual) === JSON.stringify(expected);
|
||||
}
|
||||
|
||||
function defaultResolveRuntimeEntry(params: {
|
||||
runtimeDir: string;
|
||||
manifest: RuntimeManifest;
|
||||
}): string | null {
|
||||
const runtimePackagePath = path.join(params.runtimeDir, "package.json");
|
||||
if (!manifestsMatch(readRuntimeManifest(runtimePackagePath), params.manifest)) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
const runtimeRequire = createRequire(runtimePackagePath);
|
||||
return runtimeRequire.resolve("@lancedb/lancedb");
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
function collectSpawnOutput(params: {
|
||||
command: string;
|
||||
args: string[];
|
||||
cwd: string;
|
||||
env: NodeJS.ProcessEnv;
|
||||
}): Promise<{ code: number | null; stdout: string; stderr: string; error?: Error }> {
|
||||
return new Promise((resolve) => {
|
||||
const child = spawn(params.command, params.args, {
|
||||
cwd: params.cwd,
|
||||
env: params.env,
|
||||
shell: process.platform === "win32",
|
||||
stdio: ["ignore", "pipe", "pipe"],
|
||||
});
|
||||
let stdout = "";
|
||||
let stderr = "";
|
||||
child.stdout.on("data", (chunk: Buffer | string) => {
|
||||
stdout += chunk.toString();
|
||||
});
|
||||
child.stderr.on("data", (chunk: Buffer | string) => {
|
||||
stderr += chunk.toString();
|
||||
});
|
||||
child.on("error", (error) => {
|
||||
resolve({ code: null, stdout, stderr, error });
|
||||
});
|
||||
child.on("close", (code) => {
|
||||
resolve({ code, stdout, stderr });
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
async function defaultInstallRuntime(params: {
|
||||
runtimeDir: string;
|
||||
manifest: RuntimeManifest;
|
||||
env: NodeJS.ProcessEnv;
|
||||
logger?: LanceDbRuntimeLogger;
|
||||
}): Promise<string> {
|
||||
const runtimePackagePath = path.join(params.runtimeDir, "package.json");
|
||||
const currentManifest = readRuntimeManifest(runtimePackagePath);
|
||||
if (!manifestsMatch(currentManifest, params.manifest)) {
|
||||
await fs.promises.rm(path.join(params.runtimeDir, "node_modules"), {
|
||||
recursive: true,
|
||||
force: true,
|
||||
});
|
||||
await fs.promises.rm(path.join(params.runtimeDir, "package-lock.json"), { force: true });
|
||||
}
|
||||
|
||||
await fs.promises.mkdir(params.runtimeDir, { recursive: true });
|
||||
await fs.promises.writeFile(
|
||||
runtimePackagePath,
|
||||
`${JSON.stringify(params.manifest, null, 2)}\n`,
|
||||
"utf8",
|
||||
);
|
||||
|
||||
const install = await collectSpawnOutput({
|
||||
command: "npm",
|
||||
args: ["install", "--omit=dev", "--silent", "--ignore-scripts", "--package-lock=false"],
|
||||
cwd: params.runtimeDir,
|
||||
env: params.env,
|
||||
});
|
||||
if (install.error) {
|
||||
const spawnError = install.error as NodeJS.ErrnoException;
|
||||
throw new Error(
|
||||
spawnError.code === "ENOENT"
|
||||
? "npm is required to install the LanceDB runtime but was not found on PATH"
|
||||
: install.error.message,
|
||||
);
|
||||
}
|
||||
if ((install.code ?? 0) !== 0) {
|
||||
const detail = install.stderr.trim() || install.stdout.trim();
|
||||
throw new Error(detail || `npm exited with code ${install.code ?? "unknown"}`);
|
||||
}
|
||||
|
||||
const resolved = defaultResolveRuntimeEntry({
|
||||
runtimeDir: params.runtimeDir,
|
||||
manifest: params.manifest,
|
||||
});
|
||||
if (!resolved) {
|
||||
throw new Error("installed LanceDB runtime is missing the @lancedb/lancedb entry");
|
||||
}
|
||||
params.logger?.info?.(`memory-lancedb: installed LanceDB runtime under ${params.runtimeDir}`);
|
||||
return resolved;
|
||||
}
|
||||
|
||||
function defaultImportResolved(resolvedPath: string): Promise<LanceDbModule> {
|
||||
return import(pathToFileURL(resolvedPath).href);
|
||||
}
|
||||
|
||||
function buildLoadFailureMessage(prefix: string, error: unknown): string {
|
||||
return `memory-lancedb: ${prefix}. ${String(error)}`;
|
||||
function buildLoadFailureMessage(error: unknown): string {
|
||||
return [
|
||||
"memory-lancedb: bundled @lancedb/lancedb dependency is unavailable.",
|
||||
"Install or repair the memory-lancedb plugin package dependencies, then restart OpenClaw.",
|
||||
String(error),
|
||||
].join(" ");
|
||||
}
|
||||
|
||||
function isUnsupportedNativePlatform(params: {
|
||||
@@ -239,87 +38,31 @@ function buildUnsupportedNativePlatformMessage(params: {
|
||||
}
|
||||
|
||||
export function createLanceDbRuntimeLoader(overrides: Partial<LanceDbRuntimeLoaderDeps> = {}): {
|
||||
load: (logger?: LanceDbRuntimeLogger) => Promise<LanceDbModule>;
|
||||
load: (_logger?: LanceDbRuntimeLogger) => Promise<LanceDbModule>;
|
||||
} {
|
||||
const deps: LanceDbRuntimeLoaderDeps = {
|
||||
env: overrides.env ?? process.env,
|
||||
platform: overrides.platform ?? process.platform,
|
||||
arch: overrides.arch ?? process.arch,
|
||||
resolveStateDir: overrides.resolveStateDir ?? resolveStateDir,
|
||||
runtimeManifest: overrides.runtimeManifest ?? MEMORY_LANCEDB_RUNTIME_MANIFEST,
|
||||
importBundled: overrides.importBundled ?? (() => import("@lancedb/lancedb")),
|
||||
importResolved: overrides.importResolved ?? defaultImportResolved,
|
||||
resolveRuntimeEntry: overrides.resolveRuntimeEntry ?? defaultResolveRuntimeEntry,
|
||||
installRuntime: overrides.installRuntime ?? defaultInstallRuntime,
|
||||
};
|
||||
|
||||
let loadPromise: Promise<LanceDbModule> | null = null;
|
||||
|
||||
return {
|
||||
async load(logger?: LanceDbRuntimeLogger): Promise<LanceDbModule> {
|
||||
async load(_logger?: LanceDbRuntimeLogger): Promise<LanceDbModule> {
|
||||
if (!loadPromise) {
|
||||
loadPromise = (async () => {
|
||||
try {
|
||||
return await deps.importBundled();
|
||||
} catch (bundledError) {
|
||||
if (isUnsupportedNativePlatform({ platform: deps.platform, arch: deps.arch })) {
|
||||
throw new Error(
|
||||
buildUnsupportedNativePlatformMessage({
|
||||
platform: deps.platform,
|
||||
arch: deps.arch,
|
||||
}),
|
||||
{ cause: bundledError },
|
||||
);
|
||||
}
|
||||
const runtimeDir = resolveRuntimeDir(
|
||||
deps.resolveStateDir(deps.env, () =>
|
||||
deps.env.HOME?.trim() ? deps.env.HOME : os.homedir(),
|
||||
),
|
||||
);
|
||||
const existingRuntime = deps.resolveRuntimeEntry({
|
||||
runtimeDir,
|
||||
manifest: deps.runtimeManifest,
|
||||
});
|
||||
if (existingRuntime) {
|
||||
try {
|
||||
return await deps.importResolved(existingRuntime);
|
||||
} catch {
|
||||
// Reinstall below when the cached runtime is incomplete or stale.
|
||||
}
|
||||
}
|
||||
if (deps.env.OPENCLAW_NIX_MODE === "1") {
|
||||
throw new Error(
|
||||
buildLoadFailureMessage(
|
||||
"failed to load LanceDB and Nix mode disables auto-install",
|
||||
bundledError,
|
||||
),
|
||||
{ cause: bundledError },
|
||||
);
|
||||
}
|
||||
logger?.warn?.(
|
||||
`memory-lancedb: bundled LanceDB runtime unavailable (${String(bundledError)}); installing runtime deps under ${runtimeDir}`,
|
||||
);
|
||||
const installedEntry = await deps.installRuntime({
|
||||
runtimeDir,
|
||||
manifest: deps.runtimeManifest,
|
||||
env: deps.env,
|
||||
logger,
|
||||
});
|
||||
try {
|
||||
return await deps.importResolved(installedEntry);
|
||||
} catch (runtimeError) {
|
||||
throw new Error(
|
||||
buildLoadFailureMessage(
|
||||
"failed to load LanceDB after installing runtime deps",
|
||||
runtimeError,
|
||||
),
|
||||
{ cause: runtimeError },
|
||||
);
|
||||
}
|
||||
}
|
||||
})().catch((error) => {
|
||||
loadPromise = deps.importBundled().catch((error) => {
|
||||
loadPromise = null;
|
||||
throw error;
|
||||
if (isUnsupportedNativePlatform({ platform: deps.platform, arch: deps.arch })) {
|
||||
throw new Error(
|
||||
buildUnsupportedNativePlatformMessage({
|
||||
platform: deps.platform,
|
||||
arch: deps.arch,
|
||||
}),
|
||||
{ cause: error },
|
||||
);
|
||||
}
|
||||
throw new Error(buildLoadFailureMessage(error), { cause: error });
|
||||
});
|
||||
}
|
||||
return await loadPromise;
|
||||
|
||||
@@ -60,7 +60,7 @@ const jwtMockImpl = {
|
||||
};
|
||||
|
||||
vi.mock("jsonwebtoken", () => ({
|
||||
// Match jsonwebtoken@9 under dynamic ESM import from staged runtime deps:
|
||||
// Match jsonwebtoken@9 under dynamic ESM import from plugin package deps:
|
||||
// Node exposes decode as a named export, while verify is only on default.
|
||||
decode: jwtMockImpl.decode,
|
||||
default: jwtMockImpl,
|
||||
|
||||
@@ -16,10 +16,6 @@ const QA_CLI_METADATA_ENTRY_BASENAMES = Object.freeze([
|
||||
"cli-metadata.mjs",
|
||||
"cli-metadata.cjs",
|
||||
]);
|
||||
const QA_RUNTIME_DEPS_ARTIFACT_BASENAMES = new Set([
|
||||
".openclaw-runtime-deps.json",
|
||||
".openclaw-runtime-deps-stamp.json",
|
||||
]);
|
||||
|
||||
function assertSafeQaBundledPluginId(pluginId: string) {
|
||||
if (!QA_BUNDLED_PLUGIN_ID_PATTERN.test(pluginId)) {
|
||||
@@ -316,14 +312,6 @@ async function seedQaStagedBuiltTreeRoots(params: {
|
||||
}
|
||||
}
|
||||
|
||||
function shouldStageQaBundledPluginPath(sourcePath: string) {
|
||||
const basename = path.basename(sourcePath);
|
||||
return (
|
||||
!QA_RUNTIME_DEPS_ARTIFACT_BASENAMES.has(basename) &&
|
||||
!basename.startsWith(".openclaw-runtime-deps-copy-")
|
||||
);
|
||||
}
|
||||
|
||||
export async function resolveQaRuntimeHostVersion(params: {
|
||||
repoRoot: string;
|
||||
allowedPluginIds: readonly string[];
|
||||
@@ -426,10 +414,7 @@ export async function createQaBundledPluginsDir(params: {
|
||||
if (!sourceDir) {
|
||||
throw new Error(`qa bundled plugin not found: ${pluginId}`);
|
||||
}
|
||||
await fs.cp(sourceDir, path.join(bundledPluginsDir, pluginId), {
|
||||
recursive: true,
|
||||
filter: shouldStageQaBundledPluginPath,
|
||||
});
|
||||
await fs.cp(sourceDir, path.join(bundledPluginsDir, pluginId), { recursive: true });
|
||||
}
|
||||
await symlinkQaStagedDirEntry({
|
||||
sourcePath: path.join(stagedRoot, "dist"),
|
||||
|
||||
@@ -934,57 +934,6 @@ describe("qa bundled plugin dir", () => {
|
||||
).resolves.toBeTruthy();
|
||||
});
|
||||
|
||||
it("skips legacy dependency debris while staging built bundled plugins", async () => {
|
||||
const repoRoot = await mkdtemp(path.join(os.tmpdir(), "qa-bundled-legacy-deps-"));
|
||||
cleanups.push(async () => {
|
||||
await rm(repoRoot, { recursive: true, force: true });
|
||||
});
|
||||
await writeFile(
|
||||
path.join(repoRoot, "package.json"),
|
||||
JSON.stringify({ name: "openclaw", type: "module" }, null, 2),
|
||||
"utf8",
|
||||
);
|
||||
const pluginDir = path.join(repoRoot, "dist", "extensions", "qa-channel");
|
||||
await mkdir(path.join(pluginDir, ".openclaw-runtime-deps-copy-active", "node_modules"), {
|
||||
recursive: true,
|
||||
});
|
||||
await writeFile(
|
||||
path.join(pluginDir, "package.json"),
|
||||
JSON.stringify({ name: "@openclaw/qa-channel", type: "module" }, null, 2),
|
||||
"utf8",
|
||||
);
|
||||
await writeFile(path.join(pluginDir, "index.js"), "export const ok = true;\n", "utf8");
|
||||
await writeFile(path.join(pluginDir, ".openclaw-runtime-deps.json"), "{}\n", "utf8");
|
||||
await writeFile(path.join(pluginDir, ".openclaw-runtime-deps-stamp.json"), "{}\n", "utf8");
|
||||
await writeFile(
|
||||
path.join(pluginDir, ".openclaw-runtime-deps-copy-active", "node_modules", "transient.js"),
|
||||
"export {};\n",
|
||||
"utf8",
|
||||
);
|
||||
const tempRoot = await mkdtemp(path.join(os.tmpdir(), "qa-bundled-legacy-deps-target-"));
|
||||
cleanups.push(async () => {
|
||||
await rm(tempRoot, { recursive: true, force: true });
|
||||
});
|
||||
|
||||
const { bundledPluginsDir } = await __testing.createQaBundledPluginsDir({
|
||||
repoRoot,
|
||||
tempRoot,
|
||||
allowedPluginIds: ["qa-channel"],
|
||||
});
|
||||
|
||||
const stagedPluginDir = path.join(bundledPluginsDir, "qa-channel");
|
||||
await expect(readFile(path.join(stagedPluginDir, "index.js"), "utf8")).resolves.toContain("ok");
|
||||
await expect(lstat(path.join(stagedPluginDir, ".openclaw-runtime-deps.json"))).rejects.toThrow(
|
||||
/ENOENT/u,
|
||||
);
|
||||
await expect(
|
||||
lstat(path.join(stagedPluginDir, ".openclaw-runtime-deps-stamp.json")),
|
||||
).rejects.toThrow(/ENOENT/u);
|
||||
await expect(
|
||||
lstat(path.join(stagedPluginDir, ".openclaw-runtime-deps-copy-active")),
|
||||
).rejects.toThrow(/ENOENT/u);
|
||||
});
|
||||
|
||||
it("preserves dist-runtime-only root chunks when dist also exists", async () => {
|
||||
const repoRoot = await mkdtemp(path.join(os.tmpdir(), "qa-bundled-mixed-runtime-"));
|
||||
cleanups.push(async () => {
|
||||
|
||||
@@ -207,23 +207,6 @@ function snapshotTree(rootName) {
|
||||
return stats;
|
||||
}
|
||||
|
||||
export function isIgnoredDistRuntimeWatchPath(entry) {
|
||||
return (
|
||||
entry === "dist-runtime/extensions/node_modules" ||
|
||||
entry.startsWith("dist-runtime/extensions/node_modules/")
|
||||
);
|
||||
}
|
||||
|
||||
function summarizeDistRuntimeAddedPaths(added) {
|
||||
const addedPaths = added.filter((entry) => entry.startsWith("dist-runtime/"));
|
||||
const ignoredDependencyAddedPaths = addedPaths.filter(isIgnoredDistRuntimeWatchPath);
|
||||
const topologyAddedPaths = addedPaths.filter((entry) => !isIgnoredDistRuntimeWatchPath(entry));
|
||||
return {
|
||||
ignoredDependencyAddedPaths,
|
||||
topologyAddedPaths,
|
||||
};
|
||||
}
|
||||
|
||||
function writeSnapshot(snapshotDir) {
|
||||
ensureDir(snapshotDir);
|
||||
const pathEntries = [...listTreeEntries("dist"), ...listTreeEntries("dist-runtime")];
|
||||
@@ -684,10 +667,9 @@ async function main() {
|
||||
const post = writeSnapshot(postDir);
|
||||
const diff = writeDiffArtifacts(options.outputDir, preDir, postDir);
|
||||
|
||||
const distRuntimeAddedPathSummary = summarizeDistRuntimeAddedPaths(diff.added);
|
||||
const distRuntimeAddedPaths = distRuntimeAddedPathSummary.topologyAddedPaths.length;
|
||||
const distRuntimeIgnoredDependencyAddedPaths =
|
||||
distRuntimeAddedPathSummary.ignoredDependencyAddedPaths.length;
|
||||
const distRuntimeAddedPaths = diff.added.filter((entry) =>
|
||||
entry.startsWith("dist-runtime/"),
|
||||
).length;
|
||||
const distRuntimeFileGrowth = distRuntimeAddedPaths;
|
||||
const distRuntimeByteGrowth =
|
||||
distRuntimeAddedPaths === 0
|
||||
@@ -721,7 +703,6 @@ async function main() {
|
||||
distRuntimeByteGrowth,
|
||||
distRuntimeByteGrowthMax: options.distRuntimeByteGrowthMax,
|
||||
distRuntimeAddedPaths,
|
||||
distRuntimeIgnoredDependencyAddedPaths,
|
||||
addedPaths: diff.added.length,
|
||||
removedPaths: diff.removed.length,
|
||||
watchExit: watchResult.exit,
|
||||
|
||||
@@ -512,13 +512,7 @@ function toScopedIncludePattern(arg, cwd) {
|
||||
}
|
||||
|
||||
function isSkippedImportGraphDirectory(name) {
|
||||
return (
|
||||
name === ".git" ||
|
||||
name === "dist" ||
|
||||
name === "node_modules" ||
|
||||
name === "vendor" ||
|
||||
name.startsWith(".openclaw-runtime-deps")
|
||||
);
|
||||
return name === ".git" || name === "dist" || name === "node_modules" || name === "vendor";
|
||||
}
|
||||
|
||||
function listImportGraphFiles(cwd, directory, files = []) {
|
||||
|
||||
@@ -76,7 +76,6 @@ function loadChannelSetupPluginRegistry(params: {
|
||||
workspaceDir?: string;
|
||||
onlyPluginIds?: string[];
|
||||
activate?: boolean;
|
||||
installRuntimeDeps?: boolean;
|
||||
forceSetupOnlyChannelPlugins?: boolean;
|
||||
}): PluginRegistry {
|
||||
const autoEnabled = applyPluginAutoEnable({ config: params.cfg, env: process.env });
|
||||
@@ -94,8 +93,7 @@ function loadChannelSetupPluginRegistry(params: {
|
||||
logger: createPluginLoaderLogger(log),
|
||||
onlyPluginIds: params.onlyPluginIds,
|
||||
includeSetupOnlyChannelPlugins: true,
|
||||
forceSetupOnlyChannelPlugins:
|
||||
params.forceSetupOnlyChannelPlugins ?? params.installRuntimeDeps === false,
|
||||
forceSetupOnlyChannelPlugins: params.forceSetupOnlyChannelPlugins,
|
||||
activate: params.activate,
|
||||
});
|
||||
}
|
||||
@@ -163,7 +161,6 @@ export function loadChannelSetupPluginRegistrySnapshotForChannel(params: {
|
||||
channel: string;
|
||||
pluginId?: string;
|
||||
workspaceDir?: string;
|
||||
installRuntimeDeps?: boolean;
|
||||
forceSetupOnlyChannelPlugins?: boolean;
|
||||
}): PluginRegistry {
|
||||
const scopedPluginId = resolveScopedChannelPluginId({
|
||||
|
||||
@@ -520,7 +520,7 @@ describe("channelsAddCommand", () => {
|
||||
);
|
||||
expect(loadChannelSetupPluginRegistrySnapshotForChannel).toHaveBeenCalledTimes(1);
|
||||
expect(loadChannelSetupPluginRegistrySnapshotForChannel).toHaveBeenCalledWith(
|
||||
expect.objectContaining({ installRuntimeDeps: false }),
|
||||
expect.objectContaining({ forceSetupOnlyChannelPlugins: true }),
|
||||
);
|
||||
expect(registryRefreshMocks.refreshPluginRegistryAfterConfigMutation).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
@@ -554,7 +554,7 @@ describe("channelsAddCommand", () => {
|
||||
expect(ensureChannelSetupPluginInstalled).not.toHaveBeenCalled();
|
||||
expect(loadChannelSetupPluginRegistrySnapshotForChannel).toHaveBeenCalledTimes(1);
|
||||
expect(loadChannelSetupPluginRegistrySnapshotForChannel).toHaveBeenCalledWith(
|
||||
expect.objectContaining({ installRuntimeDeps: false }),
|
||||
expect.objectContaining({ forceSetupOnlyChannelPlugins: true }),
|
||||
);
|
||||
expectExternalChatEnabledConfigWrite();
|
||||
});
|
||||
|
||||
@@ -296,7 +296,7 @@ export async function channelsAddCommand(
|
||||
channel: channelId,
|
||||
...(pluginId ? { pluginId } : {}),
|
||||
workspaceDir: resolveWorkspaceDir(),
|
||||
installRuntimeDeps: false,
|
||||
forceSetupOnlyChannelPlugins: true,
|
||||
});
|
||||
return (
|
||||
snapshot.channelSetups.find((entry) => entry.plugin.id === channelId)?.plugin ??
|
||||
|
||||
@@ -471,7 +471,7 @@ describe("setupChannels workspace shadow exclusion", () => {
|
||||
channel: "external-chat",
|
||||
pluginId: "external-chat",
|
||||
workspaceDir: "/tmp/openclaw-workspace",
|
||||
installRuntimeDeps: false,
|
||||
forceSetupOnlyChannelPlugins: true,
|
||||
}),
|
||||
);
|
||||
expect(loadChannelSetupPluginRegistrySnapshotForChannel).toHaveBeenNthCalledWith(
|
||||
@@ -480,7 +480,6 @@ describe("setupChannels workspace shadow exclusion", () => {
|
||||
channel: "external-chat",
|
||||
workspaceDir: "/tmp/openclaw-workspace",
|
||||
forceSetupOnlyChannelPlugins: true,
|
||||
installRuntimeDeps: true,
|
||||
}),
|
||||
);
|
||||
expect(getChannelSetupPlugin).not.toHaveBeenCalled();
|
||||
|
||||
@@ -156,7 +156,6 @@ export async function setupChannels(
|
||||
channel: ChannelChoice,
|
||||
pluginId?: string,
|
||||
setup?: {
|
||||
installRuntimeDeps?: boolean;
|
||||
forceReload?: boolean;
|
||||
forceSetupOnlyChannelPlugins?: boolean;
|
||||
},
|
||||
@@ -171,8 +170,7 @@ export async function setupChannels(
|
||||
channel,
|
||||
...(pluginId ? { pluginId } : {}),
|
||||
workspaceDir: resolveWorkspaceDir(),
|
||||
installRuntimeDeps: setup?.installRuntimeDeps ?? false,
|
||||
forceSetupOnlyChannelPlugins: setup?.forceSetupOnlyChannelPlugins,
|
||||
forceSetupOnlyChannelPlugins: setup?.forceSetupOnlyChannelPlugins ?? true,
|
||||
});
|
||||
const plugin =
|
||||
snapshot.channelSetups.find((entry) => entry.plugin.id === channel)?.plugin ??
|
||||
@@ -442,7 +440,6 @@ export async function setupChannels(
|
||||
await loadScopedChannelPlugin(channel, undefined, {
|
||||
forceReload: true,
|
||||
forceSetupOnlyChannelPlugins: true,
|
||||
installRuntimeDeps: true,
|
||||
});
|
||||
}
|
||||
const adapter = getVisibleSetupFlowAdapter(channel);
|
||||
|
||||
@@ -167,7 +167,7 @@ afterEach(() => {
|
||||
describe("resolveBundledPluginsDir", () => {
|
||||
it.each([
|
||||
[
|
||||
"prefers the staged runtime bundled plugin tree from the package root",
|
||||
"prefers the runtime bundled plugin tree from the package root",
|
||||
{
|
||||
prefix: "openclaw-bundled-dir-runtime-",
|
||||
hasDistRuntimeExtensions: true,
|
||||
|
||||
@@ -122,10 +122,7 @@ export function loadBundledRuntimeChannelPlugin(params: {
|
||||
}
|
||||
}
|
||||
|
||||
export function resolveSetupChannelRegistration(
|
||||
moduleExport: unknown,
|
||||
params: { installRuntimeDeps?: boolean } = {},
|
||||
): {
|
||||
export function resolveSetupChannelRegistration(moduleExport: unknown): {
|
||||
plugin?: ChannelPlugin;
|
||||
setChannelRuntime?: (runtime: PluginRuntime) => void;
|
||||
usesBundledSetupContract?: boolean;
|
||||
@@ -146,14 +143,10 @@ export function resolveSetupChannelRegistration(
|
||||
typeof setupEntryRecord.loadSetupPlugin === "function"
|
||||
) {
|
||||
try {
|
||||
const setupLoadOptions =
|
||||
params.installRuntimeDeps === false ? { installRuntimeDeps: false } : undefined;
|
||||
const loadedPlugin = setupEntryRecord.loadSetupPlugin(setupLoadOptions);
|
||||
const loadedPlugin = setupEntryRecord.loadSetupPlugin();
|
||||
const loadedSecrets =
|
||||
typeof setupEntryRecord.loadSetupSecrets === "function"
|
||||
? (setupEntryRecord.loadSetupSecrets(setupLoadOptions) as
|
||||
| ChannelPlugin["secrets"]
|
||||
| undefined)
|
||||
? (setupEntryRecord.loadSetupSecrets() as ChannelPlugin["secrets"] | undefined)
|
||||
: undefined;
|
||||
if (loadedPlugin && typeof loadedPlugin === "object") {
|
||||
const mergedSecrets = mergeChannelPluginSection(
|
||||
|
||||
@@ -4,7 +4,6 @@ import path from "node:path";
|
||||
import { describe, expect, it } from "vitest";
|
||||
import {
|
||||
hasGatewayReadyLog,
|
||||
isIgnoredDistRuntimeWatchPath,
|
||||
shouldRefreshBuildStampForRestoredArtifacts,
|
||||
writeBuildAndRuntimePostBuildStamps,
|
||||
} from "../../scripts/check-gateway-watch-regression.mjs";
|
||||
@@ -14,24 +13,6 @@ import {
|
||||
} from "../../scripts/lib/local-build-metadata-paths.mjs";
|
||||
|
||||
describe("check-gateway-watch-regression", () => {
|
||||
it("ignores top-level dist-runtime extension dependency debris", () => {
|
||||
expect(isIgnoredDistRuntimeWatchPath("dist-runtime/extensions/node_modules")).toBe(true);
|
||||
expect(
|
||||
isIgnoredDistRuntimeWatchPath(
|
||||
"dist-runtime/extensions/node_modules/playwright-core/index.js",
|
||||
),
|
||||
).toBe(true);
|
||||
});
|
||||
|
||||
it("keeps plugin runtime graph paths counted", () => {
|
||||
expect(isIgnoredDistRuntimeWatchPath("dist-runtime/extensions/openai/index.js")).toBe(false);
|
||||
expect(
|
||||
isIgnoredDistRuntimeWatchPath(
|
||||
"dist-runtime/extensions/openai/node_modules/openclaw/index.js",
|
||||
),
|
||||
).toBe(false);
|
||||
});
|
||||
|
||||
it("recognizes current and legacy gateway ready logs", () => {
|
||||
expect(hasGatewayReadyLog("[gateway] http server listening (0 plugins, 0.8s)")).toBe(true);
|
||||
expect(hasGatewayReadyLog("[gateway] ready (0 plugins, 0.8s)")).toBe(true);
|
||||
|
||||
Reference in New Issue
Block a user