mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-06 06:20:43 +00:00
fix: keep bundled runtime deps in managed stage
This commit is contained in:
@@ -61,6 +61,12 @@ Docs: https://docs.openclaw.ai
|
||||
|
||||
- iOS/macOS Talk Mode: allow `talk.speechLocale` to set the speech
|
||||
recognition locale for non-English voice conversations. Fixes #44688.
|
||||
- Plugins/providers: honor explicit plugin candidate lists instead of reading a
|
||||
persisted registry snapshot from local state, keeping candidate-scoped
|
||||
provider discovery hermetic.
|
||||
- Plugins/doctor: keep bundled plugin runtime-dependency repairs inside the
|
||||
managed OpenClaw stage even when user npm prefix/global config points npm at
|
||||
`$HOME/node_modules`. Fixes #71730.
|
||||
- Plugins/Voice Call: treat missing provider credentials as setup-incomplete
|
||||
during Gateway startup and log the missing keys as a warning instead of a
|
||||
runtime startup error, while keeping explicit command/tool errors when used. Thanks
|
||||
|
||||
@@ -74,6 +74,10 @@ ReadWritePaths=/var/lib/openclaw /home/openclaw/.openclaw /tmp
|
||||
|
||||
If `OPENCLAW_PLUGIN_STAGE_DIR` is not set, OpenClaw uses `$STATE_DIRECTORY` when
|
||||
systemd provides it, then falls back to `~/.openclaw/plugin-runtime-deps`.
|
||||
The repair step treats that stage as an OpenClaw-owned local package root and
|
||||
ignores user npm prefix/global settings, so global-install npm config does not
|
||||
redirect bundled plugin dependencies into `~/node_modules` or the global package
|
||||
tree.
|
||||
|
||||
### Bundled plugin runtime dependencies
|
||||
|
||||
|
||||
@@ -65,8 +65,12 @@ describe("resolveBundledRuntimeDepsNpmRunner", () => {
|
||||
{
|
||||
PATH: "/usr/bin:/bin",
|
||||
NPM_CONFIG_CACHE: "/Users/alice/.npm-uppercase",
|
||||
NPM_CONFIG_GLOBAL: "true",
|
||||
NPM_CONFIG_LOCATION: "global",
|
||||
NPM_CONFIG_PREFIX: "/Users/alice",
|
||||
npm_config_cache: "/Users/alice/.npm",
|
||||
npm_config_global: "true",
|
||||
npm_config_location: "global",
|
||||
npm_config_prefix: "/opt/homebrew",
|
||||
},
|
||||
{ cacheDir: "/opt/openclaw/runtime-cache" },
|
||||
@@ -170,6 +174,7 @@ describe("installBundledRuntimeDeps", () => {
|
||||
});
|
||||
|
||||
it("uses the npm cmd shim on Windows", () => {
|
||||
const installRoot = makeTempDir();
|
||||
vi.spyOn(process, "platform", "get").mockReturnValue("win32");
|
||||
vi.spyOn(fs, "existsSync").mockImplementation(
|
||||
(candidate) => candidate === "C:\\node\\node_modules\\npm\\bin\\npm-cli.js",
|
||||
@@ -184,7 +189,7 @@ describe("installBundledRuntimeDeps", () => {
|
||||
});
|
||||
|
||||
installBundledRuntimeDeps({
|
||||
installRoot: "C:\\openclaw",
|
||||
installRoot,
|
||||
missingSpecs: ["acpx@0.5.3"],
|
||||
env: {
|
||||
npm_config_prefix: "C:\\prefix",
|
||||
@@ -197,7 +202,7 @@ describe("installBundledRuntimeDeps", () => {
|
||||
expect.any(String),
|
||||
["C:\\node\\node_modules\\npm\\bin\\npm-cli.js", "install", "--ignore-scripts", "acpx@0.5.3"],
|
||||
expect.objectContaining({
|
||||
cwd: "C:\\openclaw",
|
||||
cwd: installRoot,
|
||||
env: expect.objectContaining({
|
||||
npm_config_legacy_peer_deps: "true",
|
||||
npm_config_package_lock: "false",
|
||||
@@ -286,10 +291,20 @@ describe("installBundledRuntimeDeps", () => {
|
||||
env: {
|
||||
HOME: "/Users/alice",
|
||||
NPM_CONFIG_CACHE: "/Users/alice/.npm-uppercase",
|
||||
NPM_CONFIG_GLOBAL: "true",
|
||||
NPM_CONFIG_LOCATION: "global",
|
||||
NPM_CONFIG_PREFIX: "/Users/alice",
|
||||
npm_config_cache: "/Users/alice/.npm",
|
||||
npm_config_global: "true",
|
||||
npm_config_location: "global",
|
||||
npm_config_prefix: "/opt/homebrew",
|
||||
},
|
||||
});
|
||||
|
||||
expect(JSON.parse(fs.readFileSync(path.join(installRoot, "package.json"), "utf8"))).toEqual({
|
||||
name: "openclaw-runtime-deps-install",
|
||||
private: true,
|
||||
});
|
||||
expect(spawnSyncMock).toHaveBeenCalledWith(
|
||||
expect.any(String),
|
||||
expect.any(Array),
|
||||
@@ -307,6 +322,12 @@ describe("installBundledRuntimeDeps", () => {
|
||||
expect.objectContaining({
|
||||
env: expect.not.objectContaining({
|
||||
NPM_CONFIG_CACHE: expect.any(String),
|
||||
NPM_CONFIG_GLOBAL: expect.any(String),
|
||||
NPM_CONFIG_LOCATION: expect.any(String),
|
||||
NPM_CONFIG_PREFIX: expect.any(String),
|
||||
npm_config_global: expect.any(String),
|
||||
npm_config_location: expect.any(String),
|
||||
npm_config_prefix: expect.any(String),
|
||||
}),
|
||||
}),
|
||||
);
|
||||
|
||||
@@ -723,6 +723,9 @@ function storeSourceCheckoutRuntimeDepsCache(params: {
|
||||
function createNestedNpmInstallEnv(env: NodeJS.ProcessEnv): NodeJS.ProcessEnv {
|
||||
const nextEnv = { ...env };
|
||||
delete nextEnv.NPM_CONFIG_CACHE;
|
||||
delete nextEnv.NPM_CONFIG_GLOBAL;
|
||||
delete nextEnv.NPM_CONFIG_LOCATION;
|
||||
delete nextEnv.NPM_CONFIG_PREFIX;
|
||||
delete nextEnv.npm_config_cache;
|
||||
delete nextEnv.npm_config_global;
|
||||
delete nextEnv.npm_config_location;
|
||||
@@ -1126,6 +1129,14 @@ function shouldCleanBundledRuntimeDepsInstallExecutionRoot(params: {
|
||||
return installExecutionRoot.startsWith(`${installRoot}${path.sep}`);
|
||||
}
|
||||
|
||||
function writeBundledRuntimeDepsInstallManifest(installExecutionRoot: string): void {
|
||||
fs.writeFileSync(
|
||||
path.join(installExecutionRoot, "package.json"),
|
||||
`${JSON.stringify({ name: "openclaw-runtime-deps-install", private: true }, null, 2)}\n`,
|
||||
"utf8",
|
||||
);
|
||||
}
|
||||
|
||||
export function installBundledRuntimeDeps(params: {
|
||||
installRoot: string;
|
||||
installExecutionRoot?: string;
|
||||
@@ -1144,13 +1155,11 @@ export function installBundledRuntimeDeps(params: {
|
||||
try {
|
||||
fs.mkdirSync(params.installRoot, { recursive: true });
|
||||
fs.mkdirSync(installExecutionRoot, { recursive: true });
|
||||
if (isolatedExecutionRoot) {
|
||||
fs.writeFileSync(
|
||||
path.join(installExecutionRoot, "package.json"),
|
||||
`${JSON.stringify({ name: "openclaw-runtime-deps-install", private: true }, null, 2)}\n`,
|
||||
"utf8",
|
||||
);
|
||||
}
|
||||
// Always make npm see an OpenClaw-owned package root. The package-level
|
||||
// doctor repair path installs directly in the external stage dir; without a
|
||||
// manifest, npm can honor a user's global prefix config and write under
|
||||
// $HOME/node_modules instead of our managed stage.
|
||||
writeBundledRuntimeDepsInstallManifest(installExecutionRoot);
|
||||
const installEnv = createBundledRuntimeDepsInstallEnv(params.env, {
|
||||
cacheDir: path.join(installExecutionRoot, ".openclaw-npm-cache"),
|
||||
});
|
||||
|
||||
@@ -56,7 +56,11 @@ function sortedValues(values: Iterable<string>): string[] {
|
||||
export function resolveInstalledPluginProviderContributionIds(
|
||||
params: ResolveInstalledPluginProviderContributionIdsParams = {},
|
||||
): string[] {
|
||||
const index = params.index ?? loadPluginRegistrySnapshot(params);
|
||||
const registryParams =
|
||||
params.candidates && params.preferPersisted === undefined
|
||||
? { ...params, preferPersisted: false }
|
||||
: params;
|
||||
const index = params.index ?? loadPluginRegistrySnapshot(registryParams);
|
||||
return sortedValues(
|
||||
listPluginContributionIds({
|
||||
index,
|
||||
|
||||
Reference in New Issue
Block a user