






















@@ -3,26 +3,41 @@ import { fileURLToPath } from "node:url";
33import { openClawRootFs, openClawRootFsSync } from "./openclaw-root.fs.runtime.js";
4455const CORE_PACKAGE_NAMES = new Set(["openclaw"]);
6+const packageNameCache = new Map<string, string | null>();
7+const packageRootCache = new Map<string, string | null>();
8+const argv1CandidateCache = new Map<string, string[]>();
69710function parsePackageName(raw: string): string | null {
811const parsed = JSON.parse(raw) as { name?: unknown };
912return typeof parsed.name === "string" ? parsed.name : null;
1013}
11141215async function readPackageName(dir: string): Promise<string | null> {
16+const packageJsonPath = path.join(path.resolve(dir), "package.json");
17+if (packageNameCache.has(packageJsonPath)) {
18+return packageNameCache.get(packageJsonPath) ?? null;
19+}
1320try {
14-return parsePackageName(await openClawRootFs.readFile(path.join(dir, "package.json"), "utf-8"));
21+const name = parsePackageName(await openClawRootFs.readFile(packageJsonPath, "utf-8"));
22+packageNameCache.set(packageJsonPath, name);
23+return name;
1524} catch {
25+packageNameCache.set(packageJsonPath, null);
1626return null;
1727}
1828}
19292030function readPackageNameSync(dir: string): string | null {
31+const packageJsonPath = path.join(path.resolve(dir), "package.json");
32+if (packageNameCache.has(packageJsonPath)) {
33+return packageNameCache.get(packageJsonPath) ?? null;
34+}
2135try {
22-return parsePackageName(
23- openClawRootFsSync.readFileSync(path.join(dir, "package.json"), "utf-8"),
24-);
36+const name = parsePackageName(openClawRootFsSync.readFileSync(packageJsonPath, "utf-8"));
37+packageNameCache.set(packageJsonPath, name);
38+return name;
2539} catch {
40+packageNameCache.set(packageJsonPath, null);
2641return null;
2742}
2843}
@@ -60,6 +75,11 @@ function* iterAncestorDirs(startDir: string, maxDepth: number): Generator<string
6075}
61766277function candidateDirsFromArgv1(argv1: string): string[] {
78+const cacheKey = path.resolve(argv1);
79+const cached = argv1CandidateCache.get(cacheKey);
80+if (cached) {
81+return [...cached];
82+}
6383const normalized = path.resolve(argv1);
6484const candidates = [path.dirname(normalized)];
6585@@ -81,21 +101,30 @@ function candidateDirsFromArgv1(argv1: string): string[] {
81101const nodeModulesDir = parts.slice(0, binIndex).join(path.sep);
82102candidates.push(path.join(nodeModulesDir, binName));
83103}
84-return candidates;
104+const deduped = dedupeCandidates(candidates);
105+argv1CandidateCache.set(cacheKey, deduped);
106+return [...deduped];
85107}
8610887109export async function resolveOpenClawPackageRoot(opts: {
88110cwd?: string;
89111argv1?: string;
90112moduleUrl?: string;
91113}): Promise<string | null> {
92-for (const candidate of buildCandidates(opts)) {
114+const candidates = buildCandidates(opts);
115+const cacheKey = createPackageRootCacheKey(candidates);
116+if (packageRootCache.has(cacheKey)) {
117+return packageRootCache.get(cacheKey) ?? null;
118+}
119+for (const candidate of candidates) {
93120const found = await findPackageRoot(candidate);
94121if (found) {
122+packageRootCache.set(cacheKey, found);
95123return found;
96124}
97125}
98126127+packageRootCache.set(cacheKey, null);
99128return null;
100129}
101130@@ -104,13 +133,20 @@ export function resolveOpenClawPackageRootSync(opts: {
104133argv1?: string;
105134moduleUrl?: string;
106135}): string | null {
107-for (const candidate of buildCandidates(opts)) {
136+const candidates = buildCandidates(opts);
137+const cacheKey = createPackageRootCacheKey(candidates);
138+if (packageRootCache.has(cacheKey)) {
139+return packageRootCache.get(cacheKey) ?? null;
140+}
141+for (const candidate of candidates) {
108142const found = findPackageRootSync(candidate);
109143if (found) {
144+packageRootCache.set(cacheKey, found);
110145return found;
111146}
112147}
113148149+packageRootCache.set(cacheKey, null);
114150return null;
115151}
116152@@ -131,5 +167,31 @@ function buildCandidates(opts: { cwd?: string; argv1?: string; moduleUrl?: strin
131167candidates.push(opts.cwd);
132168}
133169134-return candidates;
170+return dedupeCandidates(candidates);
171+}
172+173+function dedupeCandidates(candidates: readonly string[]): string[] {
174+const seen = new Set<string>();
175+const deduped: string[] = [];
176+for (const candidate of candidates) {
177+const resolved = path.resolve(candidate);
178+if (seen.has(resolved)) {
179+continue;
180+}
181+seen.add(resolved);
182+deduped.push(resolved);
183+}
184+return deduped;
185+}
186+187+function createPackageRootCacheKey(candidates: readonly string[]): string {
188+return candidates.join("\0");
135189}
190+191+export const __testing = {
192+clearOpenClawPackageRootCaches(): void {
193+packageNameCache.clear();
194+packageRootCache.clear();
195+argv1CandidateCache.clear();
196+},
197+};
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。