diff --git a/package.json b/package.json index 803950300bde..b084463371a1 100644 --- a/package.json +++ b/package.json @@ -1951,34 +1951,6 @@ "optionalDependencies": { "sqlite-vec": "0.1.9" }, - "overrides": { - "@anthropic-ai/sdk": "0.100.1", - "@aws-sdk/core": "3.974.13", - "@aws-sdk/xml-builder": "3.972.25", - "@hono/node-server": "1.19.14", - "axios": "1.16.0", - "basic-ftp": "6.0.1", - "defu": "6.1.5", - "fast-uri": "3.1.2", - "fast-xml-parser": "5.7.0", - "file-type": "22.0.1", - "follow-redirects": "1.16.0", - "form-data": "2.5.4", - "hono": "4.12.18", - "ip-address": "10.2.0", - "minimatch": "10.2.5", - "node-domexception": "npm:@nolyfill/domexception@1.0.28", - "path-to-regexp": "8.4.0", - "protobufjs": "8.4.0", - "qs": "6.15.2", - "request": "npm:@cypress/request@3.0.10", - "request-promise": "npm:@cypress/request-promise@5.0.0", - "tar": "7.5.15", - "tough-cookie": "4.1.3", - "typebox": "1.1.39", - "uuid": "14.0.0", - "yauzl": "3.2.1" - }, "engines": { "node": ">=22.19.0" }, diff --git a/src/infra/npm-managed-root.test.ts b/src/infra/npm-managed-root.test.ts index 4b70882d148b..edd24fc2c2b7 100644 --- a/src/infra/npm-managed-root.test.ts +++ b/src/infra/npm-managed-root.test.ts @@ -3,6 +3,7 @@ import os from "node:os"; import path from "node:path"; import { pathToFileURL } from "node:url"; import { afterAll, afterEach, beforeAll, describe, expect, it, vi } from "vitest"; +import YAML from "yaml"; import type { CommandOptions } from "../process/exec.js"; import { createSuiteTempRootTracker } from "../test-helpers/temp-dir.js"; import { @@ -232,11 +233,11 @@ describe("managed npm root", () => { }); }); - it("reads package-level npm overrides for managed plugin installs", async () => { - const manifest = JSON.parse( - await fs.readFile(path.resolve(process.cwd(), "package.json"), "utf8"), + it("reads workspace pnpm overrides for managed plugin installs", async () => { + const workspace = YAML.parse( + await fs.readFile(path.resolve(process.cwd(), "pnpm-workspace.yaml"), "utf8"), ) as { overrides?: Record }; - const expectedOverrides = manifest.overrides ?? {}; + const expectedOverrides = workspace.overrides ?? {}; expect(expectedOverrides).toMatchObject({ axios: "1.16.0", @@ -245,7 +246,7 @@ describe("managed npm root", () => { await expect(readOpenClawManagedNpmRootOverrides()).resolves.toEqual(expectedOverrides); }); - it("resolves package-level npm overrides from packaged dist chunks", async () => { + it("resolves workspace pnpm overrides from packaged dist chunks", async () => { const packageRoot = await makeTempRoot(); await fs.mkdir(path.join(packageRoot, "dist"), { recursive: true }); await fs.writeFile( @@ -253,14 +254,15 @@ describe("managed npm root", () => { `${JSON.stringify( { name: "openclaw", - overrides: { - axios: "1.16.0", - }, }, null, 2, )}\n`, ); + await fs.writeFile( + path.join(packageRoot, "pnpm-workspace.yaml"), + "overrides:\n axios: 1.16.0\n", + ); await expect( readOpenClawManagedNpmRootOverrides({ @@ -286,20 +288,24 @@ describe("managed npm root", () => { optionalDependencies: { "optional-runtime": "2.0.0", }, - overrides: { - "managed-runtime": "$managed-runtime", - nested: { - "optional-runtime": "$optional-runtime", - alias: "$node-domexception", - }, - axios: "1.16.0", - "node-domexception": "$node-domexception", - }, }, null, 2, )}\n`, ); + await fs.writeFile( + path.join(packageRoot, "pnpm-workspace.yaml"), + [ + "overrides:", + ' managed-runtime: "$managed-runtime"', + " nested:", + ' optional-runtime: "$optional-runtime"', + ' alias: "$node-domexception"', + " axios: 1.16.0", + ' node-domexception: "$node-domexception"', + "", + ].join("\n"), + ); await expect(readOpenClawManagedNpmRootOverrides({ packageRoot })).resolves.toEqual({ "managed-runtime": "3.1024.0", diff --git a/src/infra/npm-managed-root.ts b/src/infra/npm-managed-root.ts index be9eabcecad8..6cfae2e6e11c 100644 --- a/src/infra/npm-managed-root.ts +++ b/src/infra/npm-managed-root.ts @@ -4,6 +4,7 @@ import os from "node:os"; import path from "node:path"; import { isRecord } from "@openclaw/normalization-core/record-coerce"; import { normalizeOptionalString as readOptionalString } from "@openclaw/normalization-core/string-coerce"; +import { parse as parseYaml } from "yaml"; import { runCommandWithTimeout } from "../process/exec.js"; import { hasErrnoCode } from "./errors.js"; import type { NpmSpecResolution } from "./install-source-utils.js"; @@ -145,6 +146,13 @@ async function readManagedNpmRootManifest(filePath: string): Promise> { + const workspace = parseYaml( + await fs.readFile(path.join(packageRoot, "pnpm-workspace.yaml"), "utf8"), + ) as unknown; + return isRecord(workspace) ? readOverrideRecord(workspace.overrides) : {}; +} + function readHostDependencySpec( manifest: HostPackageManifest, packageName: string, @@ -194,7 +202,7 @@ function filterUnsupportedManagedNpmRootOverrides(value: unknown): Record [ key, diff --git a/src/plugins/install.npm-spec.test.ts b/src/plugins/install.npm-spec.test.ts index 6180785cdaae..657137a0a91a 100644 --- a/src/plugins/install.npm-spec.test.ts +++ b/src/plugins/install.npm-spec.test.ts @@ -2122,20 +2122,25 @@ describe("installPluginFromNpmSpec", () => { `${JSON.stringify( { name: "openclaw", - overrides: { - axios: "1.16.0", - "node-domexception": "npm:@nolyfill/domexception@1.0.28", - nested: { - alias: "npm:@scope/alias@1.0.0", - semver: "1.2.3", - }, - }, }, null, 2, )}\n`, "utf8", ); + fs.writeFileSync( + path.join(hostRoot, "pnpm-workspace.yaml"), + [ + "overrides:", + " axios: 1.16.0", + ' node-domexception: "npm:@nolyfill/domexception@1.0.28"', + " nested:", + ' alias: "npm:@scope/alias@1.0.0"', + " semver: 1.2.3", + "", + ].join("\n"), + "utf8", + ); resolveOpenClawPackageRootSyncMock.mockReturnValue(hostRoot); mockNpmViewAndInstall({ spec: "@openclaw/voice-call@0.0.1", diff --git a/test/scripts/root-package-overrides.test.ts b/test/scripts/root-package-overrides.test.ts index 914aa48d141c..48c359225015 100644 --- a/test/scripts/root-package-overrides.test.ts +++ b/test/scripts/root-package-overrides.test.ts @@ -52,22 +52,21 @@ describe("root package override guardrails", () => { expect(pnpmWorkspace.overrides).not.toHaveProperty(packageName); }); - it("pins the node-domexception alias exactly in npm and pnpm overrides", () => { + it("pins the node-domexception alias exactly in pnpm override metadata", () => { const manifest = readRootManifest(); const pnpmWorkspace = readPnpmWorkspaceConfig(); const pnpmOverride = pnpmWorkspace.overrides?.["node-domexception"]; - const npmOverride = manifest.overrides?.["node-domexception"]; expect(pnpmOverride).toBe("npm:@nolyfill/domexception@1.0.28"); - expect(npmOverride).toBe(pnpmOverride); + expect(manifest.overrides).toBeUndefined(); }); - it("keeps npm, pnpm, and lockfile override metadata aligned", () => { + it("keeps pnpm and lockfile override metadata aligned without duplicating root package policy", () => { const manifest = readRootManifest(); const pnpmWorkspace = readPnpmWorkspaceConfig(); const pnpmLockfile = readPnpmLockfileConfig(); - expect(manifest.overrides).toEqual(pnpmWorkspace.overrides); + expect(manifest.overrides).toBeUndefined(); expect(pnpmLockfile.overrides).toEqual(pnpmWorkspace.overrides); }); });