

















@@ -1,3 +1,5 @@
1+import fs from "node:fs/promises";
2+import JSON5 from "json5";
13import {
24createConfigIO,
35resolveConfigPath,
@@ -66,6 +68,12 @@ type DaemonConfigContext = {
6668configMismatch: boolean;
6769};
687071+type StatusConfigRead = {
72+summary: ConfigSummary;
73+cfg: OpenClawConfig;
74+mode: "fast" | "full";
75+};
76+6977type ResolvedGatewayStatus = {
7078gateway: GatewayStatusSummary;
7179daemonPort: number;
@@ -119,6 +127,104 @@ function resolveSnapshotRuntimeConfig(snapshot: ConfigFileSnapshot | null): Open
119127return snapshot.runtimeConfig;
120128}
121129130+function coerceStatusConfig(value: unknown): OpenClawConfig {
131+if (!value || typeof value !== "object" || Array.isArray(value)) {
132+return {};
133+}
134+return value as OpenClawConfig;
135+}
136+137+function hasOwnKey(value: unknown, key: string): boolean {
138+return Boolean(
139+value &&
140+typeof value === "object" &&
141+!Array.isArray(value) &&
142+Object.prototype.hasOwnProperty.call(value, key),
143+);
144+}
145+146+function needsFullStatusConfigRead(raw: string, parsed: unknown): boolean {
147+return raw.includes("$include") || raw.includes("${") || hasOwnKey(parsed, "env");
148+}
149+150+async function readFastStatusConfig(configPath: string): Promise<StatusConfigRead | null> {
151+let raw: string;
152+try {
153+raw = await fs.readFile(configPath, "utf8");
154+} catch {
155+return null;
156+}
157+158+let parsed: unknown;
159+try {
160+parsed = JSON5.parse(raw);
161+} catch (err) {
162+return {
163+summary: {
164+path: configPath,
165+exists: true,
166+valid: false,
167+issues: [{ path: "", message: `JSON5 parse failed: ${String(err)}` }],
168+},
169+cfg: {},
170+mode: "fast",
171+};
172+}
173+174+if (needsFullStatusConfigRead(raw, parsed)) {
175+return null;
176+}
177+178+const cfg = coerceStatusConfig(parsed);
179+return {
180+summary: {
181+path: configPath,
182+exists: true,
183+valid: true,
184+controlUi: cfg.gateway?.controlUi,
185+},
186+ cfg,
187+mode: "fast",
188+};
189+}
190+191+async function readFullStatusConfig(params: {
192+env: NodeJS.ProcessEnv;
193+configPath: string;
194+}): Promise<StatusConfigRead> {
195+const io = createConfigIO({
196+env: params.env,
197+configPath: params.configPath,
198+pluginValidation: "skip",
199+});
200+const snapshot = await io.readConfigFileSnapshot().catch(() => null);
201+const cfg = resolveSnapshotRuntimeConfig(snapshot) ?? io.loadConfig();
202+return {
203+summary: {
204+path: snapshot?.path ?? params.configPath,
205+exists: snapshot?.exists ?? false,
206+valid: snapshot?.valid ?? true,
207+ ...(snapshot?.issues?.length ? { issues: snapshot.issues } : {}),
208+controlUi: cfg.gateway?.controlUi,
209+},
210+ cfg,
211+mode: "full",
212+};
213+}
214+215+async function readStatusConfig(params: {
216+env: NodeJS.ProcessEnv;
217+configPath: string;
218+}): Promise<StatusConfigRead> {
219+return (
220+(await readFastStatusConfig(params.configPath)) ??
221+(await readFullStatusConfig({
222+env: params.env,
223+configPath: params.configPath,
224+}))
225+);
226+}
227+122228function appendProbeNote(
123229existing: string | undefined,
124230extra: string | undefined,
@@ -207,57 +313,27 @@ async function loadDaemonConfigContext(
207313mergedDaemonEnv as NodeJS.ProcessEnv,
208314resolveStateDir(mergedDaemonEnv as NodeJS.ProcessEnv),
209315);
210-211-const cliIO = createConfigIO({
316+ const sameConfigPath = cliConfigPath === daemonConfigPath;
317+const cliConfigRead = await readStatusConfig({
212318env: process.env,
213319configPath: cliConfigPath,
214-pluginValidation: "skip",
215320});
216-const sharesDaemonConfigContext = !serviceEnv && cliConfigPath === daemonConfigPath;
217-const daemonIO = sharesDaemonConfigContext
218- ? cliIO
219- : createConfigIO({
220-env: mergedDaemonEnv,
321+const sharesDaemonConfigContext =
322+sameConfigPath && (cliConfigRead.mode === "fast" || !serviceEnv);
323+const daemonConfigRead = sharesDaemonConfigContext
324+ ? cliConfigRead
325+ : await readStatusConfig({
326+env: mergedDaemonEnv as NodeJS.ProcessEnv,
221327configPath: daemonConfigPath,
222-pluginValidation: "skip",
223328});
224329225-const cliSnapshotPromise = cliIO.readConfigFileSnapshot().catch(() => null);
226-const daemonSnapshotPromise = sharesDaemonConfigContext
227- ? cliSnapshotPromise
228- : daemonIO.readConfigFileSnapshot().catch(() => null);
229-const [cliSnapshot, daemonSnapshot] = await Promise.all([
230-cliSnapshotPromise,
231-daemonSnapshotPromise,
232-]);
233-const cliCfg = resolveSnapshotRuntimeConfig(cliSnapshot) ?? cliIO.loadConfig();
234-const daemonCfg =
235-sharesDaemonConfigContext && cliSnapshot === daemonSnapshot
236- ? cliCfg
237- : (resolveSnapshotRuntimeConfig(daemonSnapshot) ?? daemonIO.loadConfig());
238-239-const cliConfigSummary: ConfigSummary = {
240-path: cliSnapshot?.path ?? cliConfigPath,
241-exists: cliSnapshot?.exists ?? false,
242-valid: cliSnapshot?.valid ?? true,
243- ...(cliSnapshot?.issues?.length ? { issues: cliSnapshot.issues } : {}),
244-controlUi: cliCfg.gateway?.controlUi,
245-};
246-const daemonConfigSummary: ConfigSummary = {
247-path: daemonSnapshot?.path ?? daemonConfigPath,
248-exists: daemonSnapshot?.exists ?? false,
249-valid: daemonSnapshot?.valid ?? true,
250- ...(daemonSnapshot?.issues?.length ? { issues: daemonSnapshot.issues } : {}),
251-controlUi: daemonCfg.gateway?.controlUi,
252-};
253-254330return {
255331 mergedDaemonEnv,
256- cliCfg,
257- daemonCfg,
258- cliConfigSummary,
259- daemonConfigSummary,
260-configMismatch: cliConfigSummary.path !== daemonConfigSummary.path,
332+cliCfg: cliConfigRead.cfg,
333+daemonCfg: daemonConfigRead.cfg,
334+cliConfigSummary: cliConfigRead.summary,
335+daemonConfigSummary: daemonConfigRead.summary,
336+configMismatch: cliConfigRead.summary.path !== daemonConfigRead.summary.path,
261337};
262338}
263339此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。