






















@@ -4,11 +4,26 @@ import { runCommandWithTimeout } from "../process/exec.js";
44import type { NpmSpecResolution } from "./install-source-utils.js";
55import { readJson, readJsonIfExists, writeJson } from "./json-files.js";
66import type { ParsedRegistryNpmSpec } from "./npm-registry-spec.js";
7+import { resolveOpenClawPackageRootSync } from "./openclaw-root.js";
78import { createSafeNpmInstallEnv } from "./safe-package-install.js";
89910type ManagedNpmRootManifest = {
1011private?: boolean;
1112dependencies?: Record<string, string>;
13+overrides?: Record<string, unknown>;
14+[key: string]: unknown;
15+};
16+17+type HostPackageManifest = {
18+dependencies?: Record<string, string>;
19+devDependencies?: Record<string, string>;
20+optionalDependencies?: Record<string, string>;
21+overrides?: Record<string, unknown>;
22+peerDependencies?: Record<string, string>;
23+};
24+25+type ManagedNpmRootOpenClawMetadata = {
26+managedOverrides?: string[];
1227[key: string]: unknown;
1328};
1429@@ -51,11 +66,108 @@ function readDependencyRecord(value: unknown): Record<string, string> {
5166return dependencies;
5267}
536869+function readOverrideRecord(value: unknown): Record<string, unknown> {
70+if (!isRecord(value)) {
71+return {};
72+}
73+const overrides: Record<string, unknown> = {};
74+for (const [key, raw] of Object.entries(value)) {
75+if (key.trim()) {
76+overrides[key] = raw;
77+}
78+}
79+return overrides;
80+}
81+82+function readManagedOverrideKeys(value: unknown): string[] {
83+if (!isRecord(value) || !Array.isArray(value.managedOverrides)) {
84+return [];
85+}
86+return value.managedOverrides.filter((key): key is string => typeof key === "string");
87+}
88+89+function buildManagedOpenClawMetadata(params: {
90+current: unknown;
91+managedOverrideKeys: string[];
92+}): ManagedNpmRootOpenClawMetadata | undefined {
93+const metadata: ManagedNpmRootOpenClawMetadata = isRecord(params.current)
94+ ? { ...params.current }
95+ : {};
96+if (params.managedOverrideKeys.length > 0) {
97+metadata.managedOverrides = params.managedOverrideKeys;
98+} else {
99+delete metadata.managedOverrides;
100+}
101+return Object.keys(metadata).length > 0 ? metadata : undefined;
102+}
103+54104async function readManagedNpmRootManifest(filePath: string): Promise<ManagedNpmRootManifest> {
55105const parsed = await readJsonIfExists<unknown>(filePath);
56106return isRecord(parsed) ? { ...parsed } : {};
57107}
58108109+function readHostDependencySpec(
110+manifest: HostPackageManifest,
111+packageName: string,
112+): string | undefined {
113+return (
114+manifest.dependencies?.[packageName] ??
115+manifest.optionalDependencies?.[packageName] ??
116+manifest.peerDependencies?.[packageName] ??
117+manifest.devDependencies?.[packageName]
118+);
119+}
120+121+function resolveHostOverrideReferences(value: unknown, manifest: HostPackageManifest): unknown {
122+if (typeof value === "string" && value.startsWith("$")) {
123+return readHostDependencySpec(manifest, value.slice(1)) ?? value;
124+}
125+if (!isRecord(value)) {
126+return value;
127+}
128+const resolved: Record<string, unknown> = {};
129+for (const [key, nested] of Object.entries(value)) {
130+resolved[key] = resolveHostOverrideReferences(nested, manifest);
131+}
132+return resolved;
133+}
134+135+export async function readOpenClawManagedNpmRootOverrides(params?: {
136+argv1?: string;
137+cwd?: string;
138+moduleUrl?: string;
139+packageRoot?: string | null;
140+}): Promise<Record<string, unknown>> {
141+const packageRoot =
142+params?.packageRoot ??
143+resolveOpenClawPackageRootSync({
144+argv1: params?.argv1 ?? process.argv[1],
145+moduleUrl: params?.moduleUrl ?? import.meta.url,
146+cwd: params?.cwd ?? process.cwd(),
147+});
148+if (!packageRoot) {
149+return {};
150+}
151+try {
152+const manifest = JSON.parse(
153+await fs.readFile(path.join(packageRoot, "package.json"), "utf8"),
154+) as unknown;
155+if (!isRecord(manifest)) {
156+return {};
157+}
158+const hostManifest = manifest as HostPackageManifest;
159+const overrides = readOverrideRecord(hostManifest.overrides);
160+return Object.fromEntries(
161+Object.entries(overrides).map(([key, value]) => [
162+key,
163+resolveHostOverrideReferences(value, hostManifest),
164+]),
165+);
166+} catch {
167+return {};
168+}
169+}
170+59171export function resolveManagedNpmRootDependencySpec(params: {
60172parsedSpec: ParsedRegistryNpmSpec;
61173resolution: NpmSpecResolution;
@@ -67,11 +179,23 @@ export async function upsertManagedNpmRootDependency(params: {
67179npmRoot: string;
68180packageName: string;
69181dependencySpec: string;
182+managedOverrides?: Record<string, unknown>;
70183}): Promise<void> {
71184await fs.mkdir(params.npmRoot, { recursive: true });
72185const manifestPath = path.join(params.npmRoot, "package.json");
73186const manifest = await readManagedNpmRootManifest(manifestPath);
74187const dependencies = readDependencyRecord(manifest.dependencies);
188+const managedOverrides = readOverrideRecord(params.managedOverrides);
189+const managedOverrideKeys = Object.keys(managedOverrides).toSorted();
190+const overrides = readOverrideRecord(manifest.overrides);
191+for (const key of readManagedOverrideKeys(manifest.openclaw)) {
192+delete overrides[key];
193+}
194+Object.assign(overrides, managedOverrides);
195+const openclawMetadata = buildManagedOpenClawMetadata({
196+current: manifest.openclaw,
197+ managedOverrideKeys,
198+});
75199const next: ManagedNpmRootManifest = {
76200 ...manifest,
77201private: true,
@@ -80,6 +204,16 @@ export async function upsertManagedNpmRootDependency(params: {
80204[params.packageName]: params.dependencySpec,
81205},
82206};
207+if (Object.keys(overrides).length > 0) {
208+next.overrides = overrides;
209+} else {
210+delete next.overrides;
211+}
212+if (openclawMetadata) {
213+next.openclaw = openclawMetadata;
214+} else {
215+delete next.openclaw;
216+}
83217await writeJson(manifestPath, next, { trailingNewline: true });
84218}
85219此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。