

























@@ -1089,6 +1089,71 @@ type ConfigReadResolution = {
10891089envWarnings: EnvSubstitutionWarning[];
10901090};
109110911092+const TILDE_PATH_VALUE_RE = /^~(?=$|[\\/])/;
1093+const PATH_LIKE_CONFIG_KEY_RE = /(dir|path|paths|file|root|workspace)$/i;
1094+const PATH_LIKE_CONFIG_LIST_KEYS = new Set(["paths", "pathPrepend"]);
1095+1096+function isPathLikeConfigKey(key: string | undefined): boolean {
1097+return Boolean(key && (PATH_LIKE_CONFIG_KEY_RE.test(key) || PATH_LIKE_CONFIG_LIST_KEYS.has(key)));
1098+}
1099+1100+function expandAuthoredTildePath(value: string, home: string): string {
1101+const suffix = value.slice(1);
1102+if (!suffix) {
1103+return home;
1104+}
1105+if (suffix.startsWith("/") || suffix.startsWith("\\")) {
1106+return path.join(home, suffix.slice(1));
1107+}
1108+return value;
1109+}
1110+1111+function restoreAuthoredTildePathsForWrite(
1112+next: unknown,
1113+authored: unknown,
1114+key: string | undefined,
1115+home: string,
1116+): unknown {
1117+if (
1118+typeof next === "string" &&
1119+typeof authored === "string" &&
1120+isPathLikeConfigKey(key) &&
1121+TILDE_PATH_VALUE_RE.test(authored.trim()) &&
1122+path.normalize(next) === path.normalize(expandAuthoredTildePath(authored.trim(), home))
1123+) {
1124+return authored;
1125+}
1126+1127+if (Array.isArray(next) && Array.isArray(authored)) {
1128+const normalizeChildren = isPathLikeConfigKey(key);
1129+return next.map((entry, index) =>
1130+restoreAuthoredTildePathsForWrite(
1131+entry,
1132+authored[index],
1133+normalizeChildren ? key : undefined,
1134+home,
1135+),
1136+);
1137+}
1138+1139+if (!isRecord(next) || !isRecord(authored)) {
1140+return next;
1141+}
1142+1143+const out: Record<string, unknown> = { ...next };
1144+for (const [childKey, childValue] of Object.entries(out)) {
1145+if (Object.prototype.hasOwnProperty.call(authored, childKey)) {
1146+out[childKey] = restoreAuthoredTildePathsForWrite(
1147+childValue,
1148+authored[childKey],
1149+childKey,
1150+home,
1151+);
1152+}
1153+}
1154+return out;
1155+}
1156+10921157function resolveConfigIncludesForRead(
10931158parsed: unknown,
10941159configPath: string,
@@ -2069,7 +2134,13 @@ export function createConfigIO(
20692134envRefMap && changedPaths
20702135 ? (restoreEnvRefsFromMap(cfgToWrite, "", envRefMap, changedPaths) as OpenClawConfig)
20712136 : cfgToWrite;
2072-const outputConfig = applyUnsetPathsForWrite(outputConfigBase, unsetPaths);
2137+const tildeRestoredOutputConfig = restoreAuthoredTildePathsForWrite(
2138+outputConfigBase,
2139+snapshot.parsed,
2140+undefined,
2141+deps.homedir(),
2142+) as OpenClawConfig;
2143+const outputConfig = applyUnsetPathsForWrite(tildeRestoredOutputConfig, unsetPaths);
20732144// Do NOT apply runtime defaults when writing - user config should only contain
20742145// explicitly set values. Runtime defaults are applied when loading (issue #6070).
20752146const stampedOutputConfig = stampConfigVersion(outputConfig);
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。