wednesdayai 0.5.1-dev.25 → 0.5.1-dev.27

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (160) hide show
  1. package/dist/{agent-scope-BKsGMXqc.js → agent-scope-DCgndASv.js} +3 -3
  2. package/dist/{agent-turn-runner-LKV3FMwQ.js → agent-turn-runner-CX7rX8by.js} +6 -6
  3. package/dist/{api-key-rotation-DZNFm4xG.js → api-key-rotation-dv2YbGr8.js} +2 -2
  4. package/dist/{audio-preflight-DQous9JR.js → audio-preflight-Qwb3oAbc.js} +29 -29
  5. package/dist/{audio-transcription-runner-BK3cV_ad.js → audio-transcription-runner-C4eHWIy0.js} +26 -26
  6. package/dist/build-info.json +3 -3
  7. package/dist/bundled/boot-md/handler.js +60 -60
  8. package/dist/bundled/bootstrap-extra-files/handler.js +6 -6
  9. package/dist/bundled/command-logger/handler.js +2 -2
  10. package/dist/bundled/session-journal/handler.js +60 -60
  11. package/dist/bundled/session-memory/handler.js +60 -60
  12. package/dist/canvas-host/a2ui/.bundle.hash +1 -1
  13. package/dist/{channel-activity-BAxUpg5h.js → channel-activity-Kn1_ykXE.js} +3 -3
  14. package/dist/{chat-content-BWkiC3u3.js → chat-content-CX7Bfpgy.js} +34 -34
  15. package/dist/{chrome-Dzgbe0zH.js → chrome-Bukcguhv.js} +31 -31
  16. package/dist/{chunk-Bvf22vTh.js → chunk-CEygNI3g.js} +3 -3
  17. package/dist/{command-queue-BOMFLCHM.js → command-queue-DOzYI9q4.js} +1 -1
  18. package/dist/{commands-registry-Da3c0MbL.js → commands-registry-Cof4HjvY.js} +2 -2
  19. package/dist/config.js +9 -9
  20. package/dist/{deliver-CJjQbaJE.js → deliver-BaTG7V5x.js} +29 -29
  21. package/dist/{diagnostic-Dn_o8RGN.js → diagnostic-DMrDenZI.js} +5 -5
  22. package/dist/{errors-1FTZDNVR.js → errors-COs_vQr3.js} +1 -1
  23. package/dist/{fetch-CnDdghbc.js → fetch-B1ohBh6A.js} +8 -8
  24. package/dist/{fetch-guard-B6BYdjiQ.js → fetch-guard-BXzVwvnJ.js} +3 -3
  25. package/dist/{frontmatter-DvbDhvt1.js → frontmatter-Cw_6jMAR.js} +3 -3
  26. package/dist/{fs-safe-IYMDplSg.js → fs-safe-BK5ALzKD.js} +26 -26
  27. package/dist/github-copilot-token-DYYKoDuV.js +106 -0
  28. package/dist/{image-ops-BuzZGoUm.js → image-ops-C-5VgbLB.js} +1 -1
  29. package/dist/{ir-CBsM7qoP.js → ir-DioI2VyB.js} +5 -5
  30. package/dist/{legacy-names-Ckds5WWe.js → legacy-names-CghFcfry.js} +1 -1
  31. package/dist/llm-slug-generator.js +60 -60
  32. package/dist/{logger-BeXVb5cn.js → logger-J4xjy-6D.js} +1 -1
  33. package/dist/{manager-BujYLKny.js → manager-D728Thsn.js} +18 -18
  34. package/dist/{markdown-tables-WuCFdPlC.js → markdown-tables-DfLMw9ti.js} +2 -2
  35. package/dist/{model-selection-CHi8o17y.js → model-selection-BHGpQSa9.js} +83 -83
  36. package/dist/{models-config-CAlyknIh.js → models-config-CJUMccZW.js} +2 -2
  37. package/dist/{outbound-attachment-C6mfyze2.js → outbound-attachment-DtVXUXnX.js} +2 -2
  38. package/dist/{outbound-message-hooks-jUzcd2OQ.js → outbound-message-hooks-7ErHCBLv.js} +5 -5
  39. package/dist/{path-alias-guards-BgOxr6f8.js → path-alias-guards-E9ntDORB.js} +1 -1
  40. package/dist/paths-BIDPYPVC.js +233 -0
  41. package/dist/{pi-embedded-aOKwlbog.js → pi-embedded-DpTacVAX.js} +277 -277
  42. package/dist/{pi-embedded-utils-BGvDJMAA.js → pi-embedded-utils-BAaHvb5G.js} +3 -3
  43. package/dist/{pi-model-discovery-CYfRyzsD.js → pi-model-discovery-BaH_6win.js} +7 -7
  44. package/dist/plugin-sdk/{agent-turn-execute-C6g1y27e.js → agent-turn-execute-Dg4sVJSk.js} +12 -12
  45. package/dist/plugin-sdk/{agent-turn-runner-BkP71ySA.js → agent-turn-runner-CD9Y0Gsf.js} +4 -4
  46. package/dist/plugin-sdk/{audio-preflight-CsMLbzm_.js → audio-preflight-GgmY1Zte.js} +5 -5
  47. package/dist/plugin-sdk/{audio-transcription-runner-2bpzZm3F.js → audio-transcription-runner-0gef4Ef0.js} +1 -1
  48. package/dist/plugin-sdk/{chat-content-CCOQCwrz.js → chat-content-Dpzf2nbZ.js} +3 -3
  49. package/dist/plugin-sdk/{chrome-C2bUQR0d.js → chrome-D9DwZOSC.js} +8 -8
  50. package/dist/plugin-sdk/{command-queue-J0ZpvnYU.js → command-queue-Cm8QKC0F.js} +1 -1
  51. package/dist/plugin-sdk/{deliver-CT3Lk2kq.js → deliver-CZVPDUrt.js} +1 -1
  52. package/dist/plugin-sdk/{deliver-dkNTCb3Z.js → deliver-D6hs0zDt.js} +3 -3
  53. package/dist/plugin-sdk/{diagnostic-C-Clqb63.js → diagnostic-Bi52EuT5.js} +1 -1
  54. package/dist/plugin-sdk/{monitor-BHeL2-is.js → monitor-BrUwRgsT.js} +32 -32
  55. package/dist/plugin-sdk/{pi-embedded-utils-BmeLQMRx.js → pi-embedded-utils-CeNVVYT3.js} +1 -1
  56. package/dist/plugin-sdk/{provider-dispatcher-BkEWKVLB.js → provider-dispatcher-Bx_RMlu-.js} +12 -12
  57. package/dist/plugin-sdk/{provider-image-QDVfXKph.js → provider-image-CBXOs7yQ.js} +4 -4
  58. package/dist/plugin-sdk/{provider-image-BSV8WjkR.js → provider-image-DH8Jro3J.js} +1 -1
  59. package/dist/plugin-sdk/{pw-ai-QlS2E2LB.js → pw-ai-BP4Kwaqc.js} +1 -1
  60. package/dist/plugin-sdk/{runs-8iACp6xv.js → runs-C1Lvxfri.js} +3 -3
  61. package/dist/plugin-sdk/{runs-D0UdtKVI.js → runs-DG49eFuR.js} +5 -5
  62. package/dist/plugin-sdk/{send-BP8o2l4w.js → send-BguPpGBL.js} +2 -2
  63. package/dist/plugin-sdk/{send-CYZi6dwK.js → send-CcEF6VcP.js} +1 -1
  64. package/dist/plugin-sdk/{subagent-registry-DA50ITkO.js → subagent-registry-B4EmS6cu.js} +12 -12
  65. package/dist/plugin-sdk/testing.js +12 -12
  66. package/dist/{provider-image-CNBkTbhu.js → provider-image-BSkZoSBN.js} +6 -6
  67. package/dist/{proxy-Ds4gxPy8.js → proxy-CrSpy5Aw.js} +1 -1
  68. package/dist/{proxy-env-DAf-b2bM.js → proxy-env-BxR4m86L.js} +1 -1
  69. package/dist/{proxy-fetch-M3YAp_Kv.js → proxy-fetch-g109vqdt.js} +1 -1
  70. package/dist/{pw-ai-BcibeG9a.js → pw-ai-CNTt9O_x.js} +14 -14
  71. package/dist/{qmd-manager-C3UBJiCk.js → qmd-manager-CU9iEql0.js} +12 -12
  72. package/dist/{query-expansion-BT5lS0um.js → query-expansion-B_2rETEo.js} +13 -13
  73. package/dist/{recorder-B08vNxya.js → recorder-Clg9Kbqu.js} +2 -2
  74. package/dist/{redact-CKI6SufO.js → redact-DpE5Tg36.js} +1 -1
  75. package/dist/{replies-BHkXhmOj.js → replies-Cty02S3t.js} +5 -5
  76. package/dist/{reply-directives-DkfwzHl4.js → reply-directives-BIh2AkNd.js} +2 -2
  77. package/dist/{reply-prefix-DS2s69iC.js → reply-prefix-C-DjHvQK.js} +1 -1
  78. package/dist/{resolve-route-DxuZn3_M.js → resolve-route-DKZiteo6.js} +5 -5
  79. package/dist/{runs-DFvW_PVw.js → runs-6Q7RU60m.js} +9 -9
  80. package/dist/{send-D2WSE41A.js → send-Bf4geLyV.js} +8 -8
  81. package/dist/{send-mILKKt54.js → send-CsDSBjFo.js} +6 -6
  82. package/dist/{send-yIxOvEiz.js → send-DQvfLvpJ.js} +6 -6
  83. package/dist/{send-2aTk7PU-.js → send-VDe5tGbO.js} +28 -28
  84. package/dist/{send-odd2G3DX.js → send-bwKTbNlJ.js} +7 -7
  85. package/dist/{session-meta-B8B6RwSE.js → session-meta-5XI6vLtM.js} +1 -1
  86. package/dist/{sessions-DC7A0bw-.js → sessions-DF9biCmh.js} +5 -5
  87. package/dist/{skill-commands-DdVSQNce.js → skill-commands-CAOvM2sb.js} +8 -8
  88. package/dist/{skills-BXMjgvRl.js → skills-VN1CJK6W.js} +21 -21
  89. package/dist/{store-BVdeIl7N.js → store-HgGweM4u.js} +7 -7
  90. package/dist/subsystem-BZy3aWdW.js +2761 -0
  91. package/dist/{tables-yHwb0GsI.js → tables-DkwNUhx1.js} +1 -1
  92. package/dist/{tokens-CXBau-U0.js → tokens-PMai9bNL.js} +1 -1
  93. package/dist/{tool-loop-detection-Bw8B0hV3.js → tool-loop-detection-BqyMjpvr.js} +2 -2
  94. package/dist/{user-run-recording-8MZq1Us4.js → user-run-recording-B1HujJiT.js} +2 -2
  95. package/dist/{workspace-DK2ZEkpT.js → workspace-Bj1Jegt-.js} +27 -27
  96. package/extensions/acpx/package.json +1 -1
  97. package/extensions/anthropic/package.json +1 -1
  98. package/extensions/bifrost/package.json +1 -1
  99. package/extensions/bluebubbles/package.json +1 -1
  100. package/extensions/copilot-proxy/package.json +1 -1
  101. package/extensions/deepgram/package.json +1 -1
  102. package/extensions/deepinfra/package.json +1 -1
  103. package/extensions/diagnostics-otel/package.json +1 -1
  104. package/extensions/diffs/package.json +1 -1
  105. package/extensions/discord/package.json +1 -1
  106. package/extensions/dream-cycle/package.json +1 -1
  107. package/extensions/elevenlabs/package.json +1 -1
  108. package/extensions/feishu/package.json +1 -1
  109. package/extensions/gemini-search/package.json +1 -1
  110. package/extensions/google/package.json +1 -1
  111. package/extensions/google-gemini-cli-auth/package.json +1 -1
  112. package/extensions/googlechat/package.json +1 -1
  113. package/extensions/grok-search/package.json +1 -1
  114. package/extensions/groq/package.json +1 -1
  115. package/extensions/imessage/package.json +1 -1
  116. package/extensions/irc/package.json +1 -1
  117. package/extensions/kimi-search/package.json +1 -1
  118. package/extensions/learning-core/package.json +1 -1
  119. package/extensions/line/package.json +1 -1
  120. package/extensions/llm-task/package.json +1 -1
  121. package/extensions/lobster/package.json +1 -1
  122. package/extensions/matrix/CHANGELOG.md +1 -1
  123. package/extensions/matrix/package.json +1 -1
  124. package/extensions/mattermost/package.json +1 -1
  125. package/extensions/memory-core/package.json +1 -1
  126. package/extensions/memory-lancedb/package.json +1 -1
  127. package/extensions/minimax/package.json +1 -1
  128. package/extensions/minimax-portal-auth/package.json +1 -1
  129. package/extensions/mistral/package.json +1 -1
  130. package/extensions/moonshot/package.json +1 -1
  131. package/extensions/msteams/CHANGELOG.md +1 -1
  132. package/extensions/msteams/package.json +1 -1
  133. package/extensions/nextcloud-talk/package.json +1 -1
  134. package/extensions/nostr/CHANGELOG.md +1 -1
  135. package/extensions/nostr/package.json +1 -1
  136. package/extensions/open-prose/package.json +1 -1
  137. package/extensions/openai/package.json +1 -1
  138. package/extensions/openai-realtime/package.json +1 -1
  139. package/extensions/openrouter/package.json +1 -1
  140. package/extensions/perplexity-search/package.json +1 -1
  141. package/extensions/searxng-search/package.json +1 -1
  142. package/extensions/signal/package.json +1 -1
  143. package/extensions/slack/package.json +1 -1
  144. package/extensions/synology-chat/package.json +1 -1
  145. package/extensions/telegram/package.json +1 -1
  146. package/extensions/tlon/package.json +1 -1
  147. package/extensions/twitch/CHANGELOG.md +1 -1
  148. package/extensions/twitch/package.json +1 -1
  149. package/extensions/ui-surfaces/package.json +1 -1
  150. package/extensions/voice-call/CHANGELOG.md +1 -1
  151. package/extensions/voice-call/package.json +1 -1
  152. package/extensions/whatsapp/package.json +1 -1
  153. package/extensions/zai/package.json +1 -1
  154. package/extensions/zalo/CHANGELOG.md +1 -1
  155. package/extensions/zalo/package.json +1 -1
  156. package/extensions/zalouser/CHANGELOG.md +1 -1
  157. package/extensions/zalouser/package.json +1 -1
  158. package/package.json +6 -3
  159. package/scripts/install.ps1 +329 -0
  160. package/scripts/install.sh +2479 -0
@@ -0,0 +1,2761 @@
1
+ import { d as resolveEffectiveHomeDir, f as resolveRequiredHomeDir, r as resolveConfigPath, u as expandHomePrefix } from "./paths-BIDPYPVC.js";
2
+ import { t as isPlainObject } from "./plain-object-CLm2c5Nu.js";
3
+ import path from "node:path";
4
+ import fs from "node:fs";
5
+ import os from "node:os";
6
+ import chalk, { Chalk } from "chalk";
7
+ import { Logger } from "tslog";
8
+ import JSON5 from "json5";
9
+ import fs$1 from "node:fs/promises";
10
+ import util, { promisify } from "node:util";
11
+ import zlib from "node:zlib";
12
+
13
+ //#region src/infra/cli-root-options.ts
14
+ const FLAG_TERMINATOR = "--";
15
+ const ROOT_BOOLEAN_FLAGS = new Set(["--dev", "--no-color"]);
16
+ const ROOT_VALUE_FLAGS = new Set(["--profile", "--log-level"]);
17
+ function isValueToken(arg) {
18
+ if (!arg || arg === FLAG_TERMINATOR) return false;
19
+ if (!arg.startsWith("-")) return true;
20
+ return /^-\d+(?:\.\d+)?$/.test(arg);
21
+ }
22
+ function consumeRootOptionToken(args, index) {
23
+ const arg = args[index];
24
+ if (!arg) return 0;
25
+ if (ROOT_BOOLEAN_FLAGS.has(arg)) return 1;
26
+ if (arg.startsWith("--profile=") || arg.startsWith("--log-level=")) return 1;
27
+ if (ROOT_VALUE_FLAGS.has(arg)) return isValueToken(args[index + 1]) ? 2 : 1;
28
+ return 0;
29
+ }
30
+
31
+ //#endregion
32
+ //#region src/cli/argv.ts
33
+ function getCommandPathWithRootOptions(argv, depth = 2) {
34
+ return getCommandPathInternal(argv, depth, { skipRootOptions: true });
35
+ }
36
+ function getCommandPathInternal(argv, depth, opts) {
37
+ const args = argv.slice(2);
38
+ const path = [];
39
+ for (let i = 0; i < args.length; i += 1) {
40
+ const arg = args[i];
41
+ if (!arg) continue;
42
+ if (arg === "--") break;
43
+ if (opts.skipRootOptions) {
44
+ const consumed = consumeRootOptionToken(args, i);
45
+ if (consumed > 0) {
46
+ i += consumed - 1;
47
+ continue;
48
+ }
49
+ }
50
+ if (arg.startsWith("-")) continue;
51
+ path.push(arg);
52
+ if (path.length >= depth) break;
53
+ }
54
+ return path;
55
+ }
56
+
57
+ //#endregion
58
+ //#region src/infra/tmp-openclaw-dir.ts
59
+ const POSIX_OPENCLAW_TMP_DIR = "/tmp/openclaw";
60
+ const TMP_DIR_ACCESS_MODE = fs.constants.W_OK | fs.constants.X_OK;
61
+ function isNodeErrorWithCode(err, code) {
62
+ return typeof err === "object" && err !== null && "code" in err && err.code === code;
63
+ }
64
+ function resolvePreferredOpenClawTmpDir(options = {}) {
65
+ const accessSync = options.accessSync ?? fs.accessSync;
66
+ const chmodSync = options.chmodSync ?? fs.chmodSync;
67
+ const lstatSync = options.lstatSync ?? fs.lstatSync;
68
+ const mkdirSync = options.mkdirSync ?? fs.mkdirSync;
69
+ const warn = options.warn ?? ((message) => console.warn(message));
70
+ const getuid = options.getuid ?? (() => {
71
+ try {
72
+ return typeof process.getuid === "function" ? process.getuid() : void 0;
73
+ } catch {
74
+ return;
75
+ }
76
+ });
77
+ const tmpdir = options.tmpdir ?? os.tmpdir;
78
+ const uid = getuid();
79
+ const isSecureDirForUser = (st) => {
80
+ if (uid === void 0) return true;
81
+ if (typeof st.uid === "number" && st.uid !== uid) return false;
82
+ if (typeof st.mode === "number" && (st.mode & 18) !== 0) return false;
83
+ return true;
84
+ };
85
+ const fallback = () => {
86
+ const base = tmpdir();
87
+ const suffix = uid === void 0 ? "openclaw" : `openclaw-${uid}`;
88
+ return path.join(base, suffix);
89
+ };
90
+ const isTrustedTmpDir = (st) => {
91
+ return st.isDirectory() && !st.isSymbolicLink() && isSecureDirForUser(st);
92
+ };
93
+ const resolveDirState = (candidatePath) => {
94
+ try {
95
+ if (!isTrustedTmpDir(lstatSync(candidatePath))) return "invalid";
96
+ accessSync(candidatePath, TMP_DIR_ACCESS_MODE);
97
+ return "available";
98
+ } catch (err) {
99
+ if (isNodeErrorWithCode(err, "ENOENT")) return "missing";
100
+ return "invalid";
101
+ }
102
+ };
103
+ const tryRepairWritableBits = (candidatePath) => {
104
+ try {
105
+ const st = lstatSync(candidatePath);
106
+ if (!st.isDirectory() || st.isSymbolicLink()) return false;
107
+ if (uid !== void 0 && typeof st.uid === "number" && st.uid !== uid) return false;
108
+ if (typeof st.mode !== "number" || (st.mode & 18) === 0) return false;
109
+ chmodSync(candidatePath, 448);
110
+ warn(`[openclaw] tightened permissions on temp dir: ${candidatePath}`);
111
+ return resolveDirState(candidatePath) === "available";
112
+ } catch {
113
+ return false;
114
+ }
115
+ };
116
+ const ensureTrustedFallbackDir = () => {
117
+ const fallbackPath = fallback();
118
+ const state = resolveDirState(fallbackPath);
119
+ if (state === "available") return fallbackPath;
120
+ if (state === "invalid") {
121
+ if (tryRepairWritableBits(fallbackPath)) return fallbackPath;
122
+ throw new Error(`Unsafe fallback OpenClaw temp dir: ${fallbackPath}`);
123
+ }
124
+ try {
125
+ mkdirSync(fallbackPath, {
126
+ recursive: true,
127
+ mode: 448
128
+ });
129
+ chmodSync(fallbackPath, 448);
130
+ } catch {
131
+ throw new Error(`Unable to create fallback OpenClaw temp dir: ${fallbackPath}`);
132
+ }
133
+ if (resolveDirState(fallbackPath) !== "available" && !tryRepairWritableBits(fallbackPath)) throw new Error(`Unsafe fallback OpenClaw temp dir: ${fallbackPath}`);
134
+ return fallbackPath;
135
+ };
136
+ const existingPreferredState = resolveDirState(POSIX_OPENCLAW_TMP_DIR);
137
+ if (existingPreferredState === "available") return POSIX_OPENCLAW_TMP_DIR;
138
+ if (existingPreferredState === "invalid") {
139
+ if (tryRepairWritableBits(POSIX_OPENCLAW_TMP_DIR)) return POSIX_OPENCLAW_TMP_DIR;
140
+ return ensureTrustedFallbackDir();
141
+ }
142
+ try {
143
+ accessSync("/tmp", TMP_DIR_ACCESS_MODE);
144
+ mkdirSync(POSIX_OPENCLAW_TMP_DIR, {
145
+ recursive: true,
146
+ mode: 448
147
+ });
148
+ chmodSync(POSIX_OPENCLAW_TMP_DIR, 448);
149
+ if (resolveDirState(POSIX_OPENCLAW_TMP_DIR) !== "available" && !tryRepairWritableBits(POSIX_OPENCLAW_TMP_DIR)) return ensureTrustedFallbackDir();
150
+ return POSIX_OPENCLAW_TMP_DIR;
151
+ } catch {
152
+ return ensureTrustedFallbackDir();
153
+ }
154
+ }
155
+
156
+ //#endregion
157
+ //#region src/utils.ts
158
+ async function ensureDir(dir) {
159
+ await fs.promises.mkdir(dir, { recursive: true });
160
+ }
161
+ /**
162
+ * Check if a file or directory exists at the given path.
163
+ */
164
+ async function pathExists$1(targetPath) {
165
+ try {
166
+ await fs.promises.access(targetPath);
167
+ return true;
168
+ } catch {
169
+ return false;
170
+ }
171
+ }
172
+ function clampNumber(value, min, max) {
173
+ return Math.max(min, Math.min(max, value));
174
+ }
175
+ function clampInt(value, min, max) {
176
+ return clampNumber(Math.floor(value), min, max);
177
+ }
178
+ /**
179
+ * Escapes special regex characters in a string so it can be used in a RegExp constructor.
180
+ */
181
+ function escapeRegExp(value) {
182
+ return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
183
+ }
184
+ /**
185
+ * Safely parse JSON, returning null on error instead of throwing.
186
+ */
187
+ function safeParseJson(raw) {
188
+ try {
189
+ return JSON.parse(raw);
190
+ } catch {
191
+ return null;
192
+ }
193
+ }
194
+ /**
195
+ * Type guard for Record<string, unknown> (less strict than isPlainObject).
196
+ * Accepts any non-null object that isn't an array.
197
+ */
198
+ function isRecord(value) {
199
+ return typeof value === "object" && value !== null && !Array.isArray(value);
200
+ }
201
+ function normalizeE164(number) {
202
+ const digits = number.replace(/^whatsapp:/, "").trim().replace(/[^\d+]/g, "");
203
+ if (digits.startsWith("+")) return `+${digits.slice(1)}`;
204
+ return `+${digits}`;
205
+ }
206
+ function sleep(ms) {
207
+ return new Promise((resolve) => setTimeout(resolve, ms));
208
+ }
209
+ function isHighSurrogate(codeUnit) {
210
+ return codeUnit >= 55296 && codeUnit <= 56319;
211
+ }
212
+ function isLowSurrogate(codeUnit) {
213
+ return codeUnit >= 56320 && codeUnit <= 57343;
214
+ }
215
+ function sliceUtf16Safe(input, start, end) {
216
+ const len = input.length;
217
+ let from = start < 0 ? Math.max(len + start, 0) : Math.min(start, len);
218
+ let to = end === void 0 ? len : end < 0 ? Math.max(len + end, 0) : Math.min(end, len);
219
+ if (to < from) {
220
+ const tmp = from;
221
+ from = to;
222
+ to = tmp;
223
+ }
224
+ if (from > 0 && from < len) {
225
+ if (isLowSurrogate(input.charCodeAt(from)) && isHighSurrogate(input.charCodeAt(from - 1))) from += 1;
226
+ }
227
+ if (to > 0 && to < len) {
228
+ if (isHighSurrogate(input.charCodeAt(to - 1)) && isLowSurrogate(input.charCodeAt(to))) to -= 1;
229
+ }
230
+ return input.slice(from, to);
231
+ }
232
+ function truncateUtf16Safe(input, maxLen) {
233
+ const limit = Math.max(0, Math.floor(maxLen));
234
+ if (input.length <= limit) return input;
235
+ return sliceUtf16Safe(input, 0, limit);
236
+ }
237
+ function resolveUserPath(input) {
238
+ if (!input) return "";
239
+ const trimmed = input.trim();
240
+ if (!trimmed) return trimmed;
241
+ if (trimmed.startsWith("~")) {
242
+ const expanded = expandHomePrefix(trimmed, {
243
+ home: resolveRequiredHomeDir(process.env, os.homedir),
244
+ env: process.env,
245
+ homedir: os.homedir
246
+ });
247
+ return path.resolve(expanded);
248
+ }
249
+ return path.resolve(trimmed);
250
+ }
251
+ function resolveConfigDir(env = process.env, homedir = os.homedir) {
252
+ const override = env.OPENCLAW_STATE_DIR?.trim() || env.CLAWDBOT_STATE_DIR?.trim();
253
+ if (override) return resolveUserPath(override);
254
+ const newDir = path.join(resolveRequiredHomeDir(env, homedir), ".openclaw");
255
+ try {
256
+ if (fs.existsSync(newDir)) return newDir;
257
+ } catch {}
258
+ return newDir;
259
+ }
260
+ function resolveHomeDir() {
261
+ return resolveEffectiveHomeDir(process.env, os.homedir);
262
+ }
263
+ function resolveHomeDisplayPrefix() {
264
+ const home = resolveHomeDir();
265
+ if (!home) return;
266
+ if (process.env.OPENCLAW_HOME?.trim()) return {
267
+ home,
268
+ prefix: "$OPENCLAW_HOME"
269
+ };
270
+ return {
271
+ home,
272
+ prefix: "~"
273
+ };
274
+ }
275
+ function shortenHomePath(input) {
276
+ if (!input) return input;
277
+ const display = resolveHomeDisplayPrefix();
278
+ if (!display) return input;
279
+ const { home, prefix } = display;
280
+ if (input === home) return prefix;
281
+ if (input.startsWith(`${home}/`) || input.startsWith(`${home}\\`)) return `${prefix}${input.slice(home.length)}`;
282
+ return input;
283
+ }
284
+ function shortenHomeInString(input) {
285
+ if (!input) return input;
286
+ const display = resolveHomeDisplayPrefix();
287
+ if (!display) return input;
288
+ return input.split(display.home).join(display.prefix);
289
+ }
290
+ function formatTerminalLink(label, url, opts) {
291
+ const esc = "\x1B";
292
+ const safeLabel = label.replaceAll(esc, "");
293
+ const safeUrl = url.replaceAll(esc, "");
294
+ if (!(opts?.force === true ? true : opts?.force === false ? false : Boolean(process.stdout.isTTY))) return opts?.fallback ?? `${safeLabel} (${safeUrl})`;
295
+ return `\u001b]8;;${safeUrl}\u0007${safeLabel}\u001b]8;;\u0007`;
296
+ }
297
+ const CONFIG_DIR = resolveConfigDir();
298
+
299
+ //#endregion
300
+ //#region src/config/env-substitution.ts
301
+ /**
302
+ * Environment variable substitution for config values.
303
+ *
304
+ * Supports `${VAR_NAME}` syntax in string values, substituted at config load time.
305
+ * - Only uppercase env vars are matched: `[A-Z_][A-Z0-9_]*`
306
+ * - Escape with `$${}` to output literal `${}`
307
+ * - Missing env vars throw `MissingEnvVarError` with context
308
+ *
309
+ * @example
310
+ * ```json5
311
+ * {
312
+ * models: {
313
+ * providers: {
314
+ * "vercel-gateway": {
315
+ * apiKey: "${VERCEL_GATEWAY_API_KEY}"
316
+ * }
317
+ * }
318
+ * }
319
+ * }
320
+ * ```
321
+ */
322
+ const ENV_VAR_NAME_PATTERN = /^[A-Z_][A-Z0-9_]*$/;
323
+ var MissingEnvVarError = class extends Error {
324
+ constructor(varName, configPath) {
325
+ super(`Missing env var "${varName}" referenced at config path: ${configPath}`);
326
+ this.varName = varName;
327
+ this.configPath = configPath;
328
+ this.name = "MissingEnvVarError";
329
+ }
330
+ };
331
+ function parseEnvTokenAt(value, index) {
332
+ if (value[index] !== "$") return null;
333
+ const next = value[index + 1];
334
+ const afterNext = value[index + 2];
335
+ if (next === "$" && afterNext === "{") {
336
+ const start = index + 3;
337
+ const end = value.indexOf("}", start);
338
+ if (end !== -1) {
339
+ const name = value.slice(start, end);
340
+ if (ENV_VAR_NAME_PATTERN.test(name)) return {
341
+ kind: "escaped",
342
+ name,
343
+ end
344
+ };
345
+ }
346
+ }
347
+ if (next === "{") {
348
+ const start = index + 2;
349
+ const end = value.indexOf("}", start);
350
+ if (end !== -1) {
351
+ const name = value.slice(start, end);
352
+ if (ENV_VAR_NAME_PATTERN.test(name)) return {
353
+ kind: "substitution",
354
+ name,
355
+ end
356
+ };
357
+ }
358
+ }
359
+ return null;
360
+ }
361
+ function substituteString(value, env, configPath) {
362
+ if (!value.includes("$")) return value;
363
+ const chunks = [];
364
+ for (let i = 0; i < value.length; i += 1) {
365
+ const char = value[i];
366
+ if (char !== "$") {
367
+ chunks.push(char);
368
+ continue;
369
+ }
370
+ const token = parseEnvTokenAt(value, i);
371
+ if (token?.kind === "escaped") {
372
+ chunks.push(`\${${token.name}}`);
373
+ i = token.end;
374
+ continue;
375
+ }
376
+ if (token?.kind === "substitution") {
377
+ const envValue = env[token.name];
378
+ if (envValue === void 0 || envValue === "") throw new MissingEnvVarError(token.name, configPath);
379
+ chunks.push(envValue);
380
+ i = token.end;
381
+ continue;
382
+ }
383
+ chunks.push(char);
384
+ }
385
+ return chunks.join("");
386
+ }
387
+ function containsEnvVarReference(value) {
388
+ if (!value.includes("$")) return false;
389
+ for (let i = 0; i < value.length; i += 1) {
390
+ if (value[i] !== "$") continue;
391
+ const token = parseEnvTokenAt(value, i);
392
+ if (token?.kind === "escaped") {
393
+ i = token.end;
394
+ continue;
395
+ }
396
+ if (token?.kind === "substitution") return true;
397
+ }
398
+ return false;
399
+ }
400
+ function substituteAny(value, env, path) {
401
+ if (typeof value === "string") return substituteString(value, env, path);
402
+ if (Array.isArray(value)) return value.map((item, index) => substituteAny(item, env, `${path}[${index}]`));
403
+ if (isPlainObject(value)) {
404
+ const result = {};
405
+ for (const [key, val] of Object.entries(value)) result[key] = substituteAny(val, env, path ? `${path}.${key}` : key);
406
+ return result;
407
+ }
408
+ return value;
409
+ }
410
+ /**
411
+ * Resolves `${VAR_NAME}` environment variable references in config values.
412
+ *
413
+ * @param obj - The parsed config object (after JSON5 parse and $include resolution)
414
+ * @param env - Environment variables to use for substitution (defaults to process.env)
415
+ * @returns The config object with env vars substituted
416
+ * @throws {MissingEnvVarError} If a referenced env var is not set or empty
417
+ */
418
+ function resolveConfigEnvVars(obj, env = process.env) {
419
+ return substituteAny(obj, env, "");
420
+ }
421
+
422
+ //#endregion
423
+ //#region src/infra/host-env-security-policy.json
424
+ var host_env_security_policy_default = {
425
+ blockedKeys: [
426
+ "NODE_OPTIONS",
427
+ "NODE_PATH",
428
+ "PYTHONHOME",
429
+ "PYTHONPATH",
430
+ "PERL5LIB",
431
+ "PERL5OPT",
432
+ "RUBYLIB",
433
+ "RUBYOPT",
434
+ "BASH_ENV",
435
+ "ENV",
436
+ "GIT_EXTERNAL_DIFF",
437
+ "SHELL",
438
+ "SHELLOPTS",
439
+ "PS4",
440
+ "GCONV_PATH",
441
+ "IFS",
442
+ "SSLKEYLOGFILE"
443
+ ],
444
+ blockedOverrideKeys: ["HOME", "ZDOTDIR"],
445
+ blockedPrefixes: [
446
+ "DYLD_",
447
+ "LD_",
448
+ "BASH_FUNC_"
449
+ ]
450
+ };
451
+
452
+ //#endregion
453
+ //#region src/infra/host-env-security.ts
454
+ const PORTABLE_ENV_VAR_KEY = /^[A-Za-z_][A-Za-z0-9_]*$/;
455
+ const HOST_ENV_SECURITY_POLICY = host_env_security_policy_default;
456
+ const HOST_DANGEROUS_ENV_KEY_VALUES = Object.freeze(HOST_ENV_SECURITY_POLICY.blockedKeys.map((key) => key.toUpperCase()));
457
+ const HOST_DANGEROUS_ENV_PREFIXES = Object.freeze(HOST_ENV_SECURITY_POLICY.blockedPrefixes.map((prefix) => prefix.toUpperCase()));
458
+ const HOST_DANGEROUS_OVERRIDE_ENV_KEY_VALUES = Object.freeze((HOST_ENV_SECURITY_POLICY.blockedOverrideKeys ?? []).map((key) => key.toUpperCase()));
459
+ const HOST_SHELL_WRAPPER_ALLOWED_OVERRIDE_ENV_KEY_VALUES = Object.freeze([
460
+ "TERM",
461
+ "LANG",
462
+ "LC_ALL",
463
+ "LC_CTYPE",
464
+ "LC_MESSAGES",
465
+ "COLORTERM",
466
+ "NO_COLOR",
467
+ "FORCE_COLOR"
468
+ ]);
469
+ const HOST_DANGEROUS_ENV_KEYS = new Set(HOST_DANGEROUS_ENV_KEY_VALUES);
470
+ const HOST_DANGEROUS_OVERRIDE_ENV_KEYS = new Set(HOST_DANGEROUS_OVERRIDE_ENV_KEY_VALUES);
471
+ const HOST_SHELL_WRAPPER_ALLOWED_OVERRIDE_ENV_KEYS = new Set(HOST_SHELL_WRAPPER_ALLOWED_OVERRIDE_ENV_KEY_VALUES);
472
+ function normalizeEnvVarKey(rawKey, options) {
473
+ const key = rawKey.trim();
474
+ if (!key) return null;
475
+ if (options?.portable && !PORTABLE_ENV_VAR_KEY.test(key)) return null;
476
+ return key;
477
+ }
478
+ function isDangerousHostEnvVarName(rawKey) {
479
+ const key = normalizeEnvVarKey(rawKey);
480
+ if (!key) return false;
481
+ const upper = key.toUpperCase();
482
+ if (HOST_DANGEROUS_ENV_KEYS.has(upper)) return true;
483
+ return HOST_DANGEROUS_ENV_PREFIXES.some((prefix) => upper.startsWith(prefix));
484
+ }
485
+ function isDangerousHostEnvOverrideVarName(rawKey) {
486
+ const key = normalizeEnvVarKey(rawKey);
487
+ if (!key) return false;
488
+ return HOST_DANGEROUS_OVERRIDE_ENV_KEYS.has(key.toUpperCase());
489
+ }
490
+ function sanitizeHostExecEnv(params) {
491
+ const baseEnv = params?.baseEnv ?? process.env;
492
+ const overrides = params?.overrides ?? void 0;
493
+ const blockPathOverrides = params?.blockPathOverrides ?? true;
494
+ const merged = {};
495
+ for (const [rawKey, value] of Object.entries(baseEnv)) {
496
+ if (typeof value !== "string") continue;
497
+ const key = normalizeEnvVarKey(rawKey, { portable: true });
498
+ if (!key || isDangerousHostEnvVarName(key)) continue;
499
+ merged[key] = value;
500
+ }
501
+ if (!overrides) return merged;
502
+ for (const [rawKey, value] of Object.entries(overrides)) {
503
+ if (typeof value !== "string") continue;
504
+ const key = normalizeEnvVarKey(rawKey, { portable: true });
505
+ if (!key) continue;
506
+ const upper = key.toUpperCase();
507
+ if (blockPathOverrides && upper === "PATH") continue;
508
+ if (isDangerousHostEnvVarName(upper) || isDangerousHostEnvOverrideVarName(upper)) continue;
509
+ merged[key] = value;
510
+ }
511
+ return merged;
512
+ }
513
+
514
+ //#endregion
515
+ //#region src/config/env-vars.ts
516
+ function isBlockedConfigEnvVar(key) {
517
+ return isDangerousHostEnvVarName(key) || isDangerousHostEnvOverrideVarName(key);
518
+ }
519
+ function collectConfigEnvVarsByTarget(cfg) {
520
+ const envConfig = cfg?.env;
521
+ if (!envConfig) return {};
522
+ const entries = {};
523
+ if (envConfig.vars) for (const [rawKey, value] of Object.entries(envConfig.vars)) {
524
+ if (!value) continue;
525
+ const key = normalizeEnvVarKey(rawKey, { portable: true });
526
+ if (!key) continue;
527
+ if (isBlockedConfigEnvVar(key)) continue;
528
+ entries[key] = value;
529
+ }
530
+ for (const [rawKey, value] of Object.entries(envConfig)) {
531
+ if (rawKey === "shellEnv" || rawKey === "vars") continue;
532
+ if (typeof value !== "string" || !value.trim()) continue;
533
+ const key = normalizeEnvVarKey(rawKey, { portable: true });
534
+ if (!key) continue;
535
+ if (isBlockedConfigEnvVar(key)) continue;
536
+ entries[key] = value;
537
+ }
538
+ return entries;
539
+ }
540
+ function collectConfigRuntimeEnvVars(cfg) {
541
+ return collectConfigEnvVarsByTarget(cfg);
542
+ }
543
+ function applyConfigEnvVars(cfg, env = process.env) {
544
+ const entries = collectConfigRuntimeEnvVars(cfg);
545
+ for (const [key, value] of Object.entries(entries)) {
546
+ if (env[key]?.trim()) continue;
547
+ env[key] = value;
548
+ }
549
+ }
550
+
551
+ //#endregion
552
+ //#region src/infra/path-guards.ts
553
+ const NOT_FOUND_CODES = new Set(["ENOENT", "ENOTDIR"]);
554
+ const SYMLINK_OPEN_CODES = new Set([
555
+ "ELOOP",
556
+ "EINVAL",
557
+ "ENOTSUP"
558
+ ]);
559
+ function normalizeWindowsPathForComparison(input) {
560
+ let normalized = path.win32.normalize(input);
561
+ if (normalized.startsWith("\\\\?\\")) {
562
+ normalized = normalized.slice(4);
563
+ if (normalized.toUpperCase().startsWith("UNC\\")) normalized = `\\\\${normalized.slice(4)}`;
564
+ }
565
+ return normalized.replaceAll("/", "\\").toLowerCase();
566
+ }
567
+ function isNodeError(value) {
568
+ return Boolean(value && typeof value === "object" && "code" in value);
569
+ }
570
+ function hasNodeErrorCode(value, code) {
571
+ return isNodeError(value) && value.code === code;
572
+ }
573
+ function isNotFoundPathError(value) {
574
+ return isNodeError(value) && typeof value.code === "string" && NOT_FOUND_CODES.has(value.code);
575
+ }
576
+ function isSymlinkOpenError(value) {
577
+ return isNodeError(value) && typeof value.code === "string" && SYMLINK_OPEN_CODES.has(value.code);
578
+ }
579
+ function isPathInside$1(root, target) {
580
+ const resolvedRoot = path.resolve(root);
581
+ const resolvedTarget = path.resolve(target);
582
+ if (process.platform === "win32") {
583
+ const rootForCompare = normalizeWindowsPathForComparison(resolvedRoot);
584
+ const targetForCompare = normalizeWindowsPathForComparison(resolvedTarget);
585
+ const relative = path.win32.relative(rootForCompare, targetForCompare);
586
+ return relative === "" || !relative.startsWith("..") && !path.win32.isAbsolute(relative);
587
+ }
588
+ const relative = path.relative(resolvedRoot, resolvedTarget);
589
+ return relative === "" || !relative.startsWith("..") && !path.isAbsolute(relative);
590
+ }
591
+
592
+ //#endregion
593
+ //#region src/infra/boundary-path.ts
594
+ const BOUNDARY_PATH_ALIAS_POLICIES = {
595
+ strict: Object.freeze({
596
+ allowFinalSymlinkForUnlink: false,
597
+ allowFinalHardlinkForUnlink: false
598
+ }),
599
+ unlinkTarget: Object.freeze({
600
+ allowFinalSymlinkForUnlink: true,
601
+ allowFinalHardlinkForUnlink: true
602
+ })
603
+ };
604
+ async function resolveBoundaryPath(params) {
605
+ const rootPath = path.resolve(params.rootPath);
606
+ const absolutePath = path.resolve(params.absolutePath);
607
+ const context = createBoundaryResolutionContext({
608
+ resolveParams: params,
609
+ rootPath,
610
+ absolutePath,
611
+ rootCanonicalPath: params.rootCanonicalPath ? path.resolve(params.rootCanonicalPath) : await resolvePathViaExistingAncestor(rootPath),
612
+ outsideLexicalCanonicalPath: await resolveOutsideLexicalCanonicalPathAsync({
613
+ rootPath,
614
+ absolutePath
615
+ })
616
+ });
617
+ const outsideResult = await resolveOutsideBoundaryPathAsync({
618
+ boundaryLabel: params.boundaryLabel,
619
+ context
620
+ });
621
+ if (outsideResult) return outsideResult;
622
+ return resolveBoundaryPathLexicalAsync({
623
+ params,
624
+ absolutePath: context.absolutePath,
625
+ rootPath: context.rootPath,
626
+ rootCanonicalPath: context.rootCanonicalPath
627
+ });
628
+ }
629
+ function resolveBoundaryPathSync(params) {
630
+ const rootPath = path.resolve(params.rootPath);
631
+ const absolutePath = path.resolve(params.absolutePath);
632
+ const context = createBoundaryResolutionContext({
633
+ resolveParams: params,
634
+ rootPath,
635
+ absolutePath,
636
+ rootCanonicalPath: params.rootCanonicalPath ? path.resolve(params.rootCanonicalPath) : resolvePathViaExistingAncestorSync(rootPath),
637
+ outsideLexicalCanonicalPath: resolveOutsideLexicalCanonicalPathSync({
638
+ rootPath,
639
+ absolutePath
640
+ })
641
+ });
642
+ const outsideResult = resolveOutsideBoundaryPathSync({
643
+ boundaryLabel: params.boundaryLabel,
644
+ context
645
+ });
646
+ if (outsideResult) return outsideResult;
647
+ return resolveBoundaryPathLexicalSync({
648
+ params,
649
+ absolutePath: context.absolutePath,
650
+ rootPath: context.rootPath,
651
+ rootCanonicalPath: context.rootCanonicalPath
652
+ });
653
+ }
654
+ function isPromiseLike(value) {
655
+ return Boolean(value && (typeof value === "object" || typeof value === "function") && "then" in value && typeof value.then === "function");
656
+ }
657
+ function createLexicalTraversalState(params) {
658
+ return {
659
+ segments: path.relative(params.rootPath, params.absolutePath).split(path.sep).filter(Boolean),
660
+ allowFinalSymlink: params.params.policy?.allowFinalSymlinkForUnlink === true,
661
+ canonicalCursor: params.rootCanonicalPath,
662
+ lexicalCursor: params.rootPath,
663
+ preserveFinalSymlink: false
664
+ };
665
+ }
666
+ function assertLexicalCursorInsideBoundary(params) {
667
+ assertInsideBoundary({
668
+ boundaryLabel: params.params.boundaryLabel,
669
+ rootCanonicalPath: params.rootCanonicalPath,
670
+ candidatePath: params.candidatePath,
671
+ absolutePath: params.absolutePath
672
+ });
673
+ }
674
+ function applyMissingSuffixToCanonicalCursor(params) {
675
+ const missingSuffix = params.state.segments.slice(params.missingFromIndex);
676
+ params.state.canonicalCursor = path.resolve(params.state.canonicalCursor, ...missingSuffix);
677
+ assertLexicalCursorInsideBoundary({
678
+ params: params.params,
679
+ rootCanonicalPath: params.rootCanonicalPath,
680
+ candidatePath: params.state.canonicalCursor,
681
+ absolutePath: params.absolutePath
682
+ });
683
+ }
684
+ function advanceCanonicalCursorForSegment(params) {
685
+ params.state.canonicalCursor = path.resolve(params.state.canonicalCursor, params.segment);
686
+ assertLexicalCursorInsideBoundary({
687
+ params: params.params,
688
+ rootCanonicalPath: params.rootCanonicalPath,
689
+ candidatePath: params.state.canonicalCursor,
690
+ absolutePath: params.absolutePath
691
+ });
692
+ }
693
+ function finalizeLexicalResolution(params) {
694
+ assertLexicalCursorInsideBoundary({
695
+ params: params.params,
696
+ rootCanonicalPath: params.rootCanonicalPath,
697
+ candidatePath: params.state.canonicalCursor,
698
+ absolutePath: params.absolutePath
699
+ });
700
+ return buildResolvedBoundaryPath({
701
+ absolutePath: params.absolutePath,
702
+ canonicalPath: params.state.canonicalCursor,
703
+ rootPath: params.rootPath,
704
+ rootCanonicalPath: params.rootCanonicalPath,
705
+ kind: params.kind
706
+ });
707
+ }
708
+ function handleLexicalLstatFailure(params) {
709
+ if (!isNotFoundPathError(params.error)) return false;
710
+ applyMissingSuffixToCanonicalCursor({
711
+ state: params.state,
712
+ missingFromIndex: params.missingFromIndex,
713
+ rootCanonicalPath: params.rootCanonicalPath,
714
+ params: params.resolveParams,
715
+ absolutePath: params.absolutePath
716
+ });
717
+ return true;
718
+ }
719
+ function handleLexicalStatReadFailure(params) {
720
+ if (handleLexicalLstatFailure({
721
+ error: params.error,
722
+ state: params.state,
723
+ missingFromIndex: params.missingFromIndex,
724
+ rootCanonicalPath: params.rootCanonicalPath,
725
+ resolveParams: params.resolveParams,
726
+ absolutePath: params.absolutePath
727
+ })) return null;
728
+ throw params.error;
729
+ }
730
+ function handleLexicalStatDisposition(params) {
731
+ if (!params.isSymbolicLink) {
732
+ advanceCanonicalCursorForSegment({
733
+ state: params.state,
734
+ segment: params.segment,
735
+ rootCanonicalPath: params.rootCanonicalPath,
736
+ params: params.resolveParams,
737
+ absolutePath: params.absolutePath
738
+ });
739
+ return "continue";
740
+ }
741
+ if (params.state.allowFinalSymlink && params.isLast) {
742
+ params.state.preserveFinalSymlink = true;
743
+ advanceCanonicalCursorForSegment({
744
+ state: params.state,
745
+ segment: params.segment,
746
+ rootCanonicalPath: params.rootCanonicalPath,
747
+ params: params.resolveParams,
748
+ absolutePath: params.absolutePath
749
+ });
750
+ return "break";
751
+ }
752
+ return "resolve-link";
753
+ }
754
+ function applyResolvedSymlinkHop(params) {
755
+ if (!isPathInside$1(params.rootCanonicalPath, params.linkCanonical)) throw symlinkEscapeError({
756
+ boundaryLabel: params.boundaryLabel,
757
+ rootCanonicalPath: params.rootCanonicalPath,
758
+ symlinkPath: params.state.lexicalCursor
759
+ });
760
+ params.state.canonicalCursor = params.linkCanonical;
761
+ params.state.lexicalCursor = params.linkCanonical;
762
+ }
763
+ function readLexicalStat(params) {
764
+ try {
765
+ const stat = params.read(params.state.lexicalCursor);
766
+ if (isPromiseLike(stat)) return Promise.resolve(stat).catch((error) => handleLexicalStatReadFailure({
767
+ ...params,
768
+ error
769
+ }));
770
+ return stat;
771
+ } catch (error) {
772
+ return handleLexicalStatReadFailure({
773
+ ...params,
774
+ error
775
+ });
776
+ }
777
+ }
778
+ function resolveAndApplySymlinkHop(params) {
779
+ const linkCanonical = params.resolveLinkCanonical(params.state.lexicalCursor);
780
+ if (isPromiseLike(linkCanonical)) return Promise.resolve(linkCanonical).then((value) => applyResolvedSymlinkHop({
781
+ state: params.state,
782
+ linkCanonical: value,
783
+ rootCanonicalPath: params.rootCanonicalPath,
784
+ boundaryLabel: params.boundaryLabel
785
+ }));
786
+ applyResolvedSymlinkHop({
787
+ state: params.state,
788
+ linkCanonical,
789
+ rootCanonicalPath: params.rootCanonicalPath,
790
+ boundaryLabel: params.boundaryLabel
791
+ });
792
+ }
793
+ function* iterateLexicalTraversal(state) {
794
+ for (let idx = 0; idx < state.segments.length; idx += 1) {
795
+ const segment = state.segments[idx] ?? "";
796
+ const isLast = idx === state.segments.length - 1;
797
+ state.lexicalCursor = path.join(state.lexicalCursor, segment);
798
+ yield {
799
+ idx,
800
+ segment,
801
+ isLast
802
+ };
803
+ }
804
+ }
805
+ async function resolveBoundaryPathLexicalAsync(params) {
806
+ const state = createLexicalTraversalState(params);
807
+ const sharedStepParams = {
808
+ state,
809
+ rootCanonicalPath: params.rootCanonicalPath,
810
+ resolveParams: params.params,
811
+ absolutePath: params.absolutePath
812
+ };
813
+ for (const { idx, segment, isLast } of iterateLexicalTraversal(state)) {
814
+ const stat = await readLexicalStat({
815
+ ...sharedStepParams,
816
+ missingFromIndex: idx,
817
+ read: (cursor) => fs$1.lstat(cursor)
818
+ });
819
+ if (!stat) break;
820
+ const disposition = handleLexicalStatDisposition({
821
+ ...sharedStepParams,
822
+ isSymbolicLink: stat.isSymbolicLink(),
823
+ segment,
824
+ isLast
825
+ });
826
+ if (disposition === "continue") continue;
827
+ if (disposition === "break") break;
828
+ await resolveAndApplySymlinkHop({
829
+ state,
830
+ rootCanonicalPath: params.rootCanonicalPath,
831
+ boundaryLabel: params.params.boundaryLabel,
832
+ resolveLinkCanonical: (cursor) => resolveSymlinkHopPath(cursor)
833
+ });
834
+ }
835
+ const kind = await getPathKind(params.absolutePath, state.preserveFinalSymlink);
836
+ return finalizeLexicalResolution({
837
+ ...params,
838
+ state,
839
+ kind
840
+ });
841
+ }
842
+ function resolveBoundaryPathLexicalSync(params) {
843
+ const state = createLexicalTraversalState(params);
844
+ for (let idx = 0; idx < state.segments.length; idx += 1) {
845
+ const segment = state.segments[idx] ?? "";
846
+ const isLast = idx === state.segments.length - 1;
847
+ state.lexicalCursor = path.join(state.lexicalCursor, segment);
848
+ const maybeStat = readLexicalStat({
849
+ state,
850
+ missingFromIndex: idx,
851
+ rootCanonicalPath: params.rootCanonicalPath,
852
+ resolveParams: params.params,
853
+ absolutePath: params.absolutePath,
854
+ read: (cursor) => fs.lstatSync(cursor)
855
+ });
856
+ if (isPromiseLike(maybeStat)) throw new Error("Unexpected async lexical stat");
857
+ const stat = maybeStat;
858
+ if (!stat) break;
859
+ const disposition = handleLexicalStatDisposition({
860
+ state,
861
+ isSymbolicLink: stat.isSymbolicLink(),
862
+ segment,
863
+ isLast,
864
+ rootCanonicalPath: params.rootCanonicalPath,
865
+ resolveParams: params.params,
866
+ absolutePath: params.absolutePath
867
+ });
868
+ if (disposition === "continue") continue;
869
+ if (disposition === "break") break;
870
+ if (isPromiseLike(resolveAndApplySymlinkHop({
871
+ state,
872
+ rootCanonicalPath: params.rootCanonicalPath,
873
+ boundaryLabel: params.params.boundaryLabel,
874
+ resolveLinkCanonical: (cursor) => resolveSymlinkHopPathSync(cursor)
875
+ }))) throw new Error("Unexpected async symlink resolution");
876
+ }
877
+ const kind = getPathKindSync(params.absolutePath, state.preserveFinalSymlink);
878
+ return finalizeLexicalResolution({
879
+ ...params,
880
+ state,
881
+ kind
882
+ });
883
+ }
884
+ function resolveCanonicalOutsideLexicalPath(params) {
885
+ return params.outsideLexicalCanonicalPath ?? params.absolutePath;
886
+ }
887
+ function createBoundaryResolutionContext(params) {
888
+ const lexicalInside = isPathInside$1(params.rootPath, params.absolutePath);
889
+ const canonicalOutsideLexicalPath = resolveCanonicalOutsideLexicalPath({
890
+ absolutePath: params.absolutePath,
891
+ outsideLexicalCanonicalPath: params.outsideLexicalCanonicalPath
892
+ });
893
+ assertLexicalBoundaryOrCanonicalAlias({
894
+ skipLexicalRootCheck: params.resolveParams.skipLexicalRootCheck,
895
+ lexicalInside,
896
+ canonicalOutsideLexicalPath,
897
+ rootCanonicalPath: params.rootCanonicalPath,
898
+ boundaryLabel: params.resolveParams.boundaryLabel,
899
+ rootPath: params.rootPath,
900
+ absolutePath: params.absolutePath
901
+ });
902
+ return {
903
+ rootPath: params.rootPath,
904
+ absolutePath: params.absolutePath,
905
+ rootCanonicalPath: params.rootCanonicalPath,
906
+ lexicalInside,
907
+ canonicalOutsideLexicalPath
908
+ };
909
+ }
910
+ async function resolveOutsideBoundaryPathAsync(params) {
911
+ if (params.context.lexicalInside) return null;
912
+ const kind = await getPathKind(params.context.absolutePath, false);
913
+ return buildOutsideLexicalBoundaryPath({
914
+ boundaryLabel: params.boundaryLabel,
915
+ rootCanonicalPath: params.context.rootCanonicalPath,
916
+ absolutePath: params.context.absolutePath,
917
+ canonicalOutsideLexicalPath: params.context.canonicalOutsideLexicalPath,
918
+ rootPath: params.context.rootPath,
919
+ kind
920
+ });
921
+ }
922
+ function resolveOutsideBoundaryPathSync(params) {
923
+ if (params.context.lexicalInside) return null;
924
+ const kind = getPathKindSync(params.context.absolutePath, false);
925
+ return buildOutsideLexicalBoundaryPath({
926
+ boundaryLabel: params.boundaryLabel,
927
+ rootCanonicalPath: params.context.rootCanonicalPath,
928
+ absolutePath: params.context.absolutePath,
929
+ canonicalOutsideLexicalPath: params.context.canonicalOutsideLexicalPath,
930
+ rootPath: params.context.rootPath,
931
+ kind
932
+ });
933
+ }
934
+ async function resolveOutsideLexicalCanonicalPathAsync(params) {
935
+ if (isPathInside$1(params.rootPath, params.absolutePath)) return;
936
+ return await resolvePathViaExistingAncestor(params.absolutePath);
937
+ }
938
+ function resolveOutsideLexicalCanonicalPathSync(params) {
939
+ if (isPathInside$1(params.rootPath, params.absolutePath)) return;
940
+ return resolvePathViaExistingAncestorSync(params.absolutePath);
941
+ }
942
+ function buildOutsideLexicalBoundaryPath(params) {
943
+ assertInsideBoundary({
944
+ boundaryLabel: params.boundaryLabel,
945
+ rootCanonicalPath: params.rootCanonicalPath,
946
+ candidatePath: params.canonicalOutsideLexicalPath,
947
+ absolutePath: params.absolutePath
948
+ });
949
+ return buildResolvedBoundaryPath({
950
+ absolutePath: params.absolutePath,
951
+ canonicalPath: params.canonicalOutsideLexicalPath,
952
+ rootPath: params.rootPath,
953
+ rootCanonicalPath: params.rootCanonicalPath,
954
+ kind: params.kind
955
+ });
956
+ }
957
+ function assertLexicalBoundaryOrCanonicalAlias(params) {
958
+ if (params.skipLexicalRootCheck || params.lexicalInside) return;
959
+ if (isPathInside$1(params.rootCanonicalPath, params.canonicalOutsideLexicalPath)) return;
960
+ throw pathEscapeError({
961
+ boundaryLabel: params.boundaryLabel,
962
+ rootPath: params.rootPath,
963
+ absolutePath: params.absolutePath
964
+ });
965
+ }
966
+ function buildResolvedBoundaryPath(params) {
967
+ return {
968
+ absolutePath: params.absolutePath,
969
+ canonicalPath: params.canonicalPath,
970
+ rootPath: params.rootPath,
971
+ rootCanonicalPath: params.rootCanonicalPath,
972
+ relativePath: relativeInsideRoot(params.rootCanonicalPath, params.canonicalPath),
973
+ exists: params.kind.exists,
974
+ kind: params.kind.kind
975
+ };
976
+ }
977
+ async function resolvePathViaExistingAncestor(targetPath) {
978
+ const normalized = path.resolve(targetPath);
979
+ let cursor = normalized;
980
+ const missingSuffix = [];
981
+ while (!isFilesystemRoot(cursor) && !await pathExists(cursor)) {
982
+ missingSuffix.unshift(path.basename(cursor));
983
+ const parent = path.dirname(cursor);
984
+ if (parent === cursor) break;
985
+ cursor = parent;
986
+ }
987
+ if (!await pathExists(cursor)) return normalized;
988
+ try {
989
+ const resolvedAncestor = path.resolve(await fs$1.realpath(cursor));
990
+ if (missingSuffix.length === 0) return resolvedAncestor;
991
+ return path.resolve(resolvedAncestor, ...missingSuffix);
992
+ } catch {
993
+ return normalized;
994
+ }
995
+ }
996
+ function resolvePathViaExistingAncestorSync(targetPath) {
997
+ const normalized = path.resolve(targetPath);
998
+ let cursor = normalized;
999
+ const missingSuffix = [];
1000
+ while (!isFilesystemRoot(cursor) && !fs.existsSync(cursor)) {
1001
+ missingSuffix.unshift(path.basename(cursor));
1002
+ const parent = path.dirname(cursor);
1003
+ if (parent === cursor) break;
1004
+ cursor = parent;
1005
+ }
1006
+ if (!fs.existsSync(cursor)) return normalized;
1007
+ try {
1008
+ const resolvedAncestor = path.resolve(fs.realpathSync(cursor));
1009
+ if (missingSuffix.length === 0) return resolvedAncestor;
1010
+ return path.resolve(resolvedAncestor, ...missingSuffix);
1011
+ } catch {
1012
+ return normalized;
1013
+ }
1014
+ }
1015
+ async function getPathKind(absolutePath, preserveFinalSymlink) {
1016
+ try {
1017
+ return {
1018
+ exists: true,
1019
+ kind: toResolvedKind(preserveFinalSymlink ? await fs$1.lstat(absolutePath) : await fs$1.stat(absolutePath))
1020
+ };
1021
+ } catch (error) {
1022
+ if (isNotFoundPathError(error)) return {
1023
+ exists: false,
1024
+ kind: "missing"
1025
+ };
1026
+ throw error;
1027
+ }
1028
+ }
1029
+ function getPathKindSync(absolutePath, preserveFinalSymlink) {
1030
+ try {
1031
+ return {
1032
+ exists: true,
1033
+ kind: toResolvedKind(preserveFinalSymlink ? fs.lstatSync(absolutePath) : fs.statSync(absolutePath))
1034
+ };
1035
+ } catch (error) {
1036
+ if (isNotFoundPathError(error)) return {
1037
+ exists: false,
1038
+ kind: "missing"
1039
+ };
1040
+ throw error;
1041
+ }
1042
+ }
1043
+ function toResolvedKind(stat) {
1044
+ if (stat.isFile()) return "file";
1045
+ if (stat.isDirectory()) return "directory";
1046
+ if (stat.isSymbolicLink()) return "symlink";
1047
+ return "other";
1048
+ }
1049
+ function relativeInsideRoot(rootPath, targetPath) {
1050
+ const relative = path.relative(path.resolve(rootPath), path.resolve(targetPath));
1051
+ if (!relative || relative === ".") return "";
1052
+ if (relative.startsWith("..") || path.isAbsolute(relative)) return "";
1053
+ return relative;
1054
+ }
1055
+ function assertInsideBoundary(params) {
1056
+ if (isPathInside$1(params.rootCanonicalPath, params.candidatePath)) return;
1057
+ throw new Error(`Path resolves outside ${params.boundaryLabel} (${shortPath(params.rootCanonicalPath)}): ${shortPath(params.absolutePath)}`);
1058
+ }
1059
+ function pathEscapeError(params) {
1060
+ return /* @__PURE__ */ new Error(`Path escapes ${params.boundaryLabel} (${shortPath(params.rootPath)}): ${shortPath(params.absolutePath)}`);
1061
+ }
1062
+ function symlinkEscapeError(params) {
1063
+ return /* @__PURE__ */ new Error(`Symlink escapes ${params.boundaryLabel} (${shortPath(params.rootCanonicalPath)}): ${shortPath(params.symlinkPath)}`);
1064
+ }
1065
+ function shortPath(value) {
1066
+ const home = os.homedir();
1067
+ if (value.startsWith(home)) return `~${value.slice(home.length)}`;
1068
+ return value;
1069
+ }
1070
+ function isFilesystemRoot(candidate) {
1071
+ return path.parse(candidate).root === candidate;
1072
+ }
1073
+ async function pathExists(targetPath) {
1074
+ try {
1075
+ await fs$1.lstat(targetPath);
1076
+ return true;
1077
+ } catch (error) {
1078
+ if (isNotFoundPathError(error)) return false;
1079
+ throw error;
1080
+ }
1081
+ }
1082
+ async function resolveSymlinkHopPath(symlinkPath) {
1083
+ try {
1084
+ return path.resolve(await fs$1.realpath(symlinkPath));
1085
+ } catch (error) {
1086
+ if (!isNotFoundPathError(error)) throw error;
1087
+ const linkTarget = await fs$1.readlink(symlinkPath);
1088
+ return resolvePathViaExistingAncestor(path.resolve(path.dirname(symlinkPath), linkTarget));
1089
+ }
1090
+ }
1091
+ function resolveSymlinkHopPathSync(symlinkPath) {
1092
+ try {
1093
+ return path.resolve(fs.realpathSync(symlinkPath));
1094
+ } catch (error) {
1095
+ if (!isNotFoundPathError(error)) throw error;
1096
+ const linkTarget = fs.readlinkSync(symlinkPath);
1097
+ return resolvePathViaExistingAncestorSync(path.resolve(path.dirname(symlinkPath), linkTarget));
1098
+ }
1099
+ }
1100
+
1101
+ //#endregion
1102
+ //#region src/infra/file-identity.ts
1103
+ function isZero(value) {
1104
+ return value === 0 || value === 0n;
1105
+ }
1106
+ function sameFileIdentity$1(left, right, platform = process.platform) {
1107
+ if (left.ino !== right.ino) return false;
1108
+ if (left.dev === right.dev) return true;
1109
+ return platform === "win32" && (isZero(left.dev) || isZero(right.dev));
1110
+ }
1111
+
1112
+ //#endregion
1113
+ //#region src/infra/safe-open-sync.ts
1114
+ function isExpectedPathError(error) {
1115
+ const code = typeof error === "object" && error !== null && "code" in error ? String(error.code) : "";
1116
+ return code === "ENOENT" || code === "ENOTDIR" || code === "ELOOP";
1117
+ }
1118
+ function sameFileIdentity(left, right) {
1119
+ return sameFileIdentity$1(left, right);
1120
+ }
1121
+ function openVerifiedFileSync(params) {
1122
+ const ioFs = params.ioFs ?? fs;
1123
+ const allowedType = params.allowedType ?? "file";
1124
+ const openReadFlags = ioFs.constants.O_RDONLY | (typeof ioFs.constants.O_NOFOLLOW === "number" ? ioFs.constants.O_NOFOLLOW : 0);
1125
+ let fd = null;
1126
+ try {
1127
+ if (params.rejectPathSymlink) {
1128
+ if (ioFs.lstatSync(params.filePath).isSymbolicLink()) return {
1129
+ ok: false,
1130
+ reason: "validation"
1131
+ };
1132
+ }
1133
+ const realPath = params.resolvedPath ?? ioFs.realpathSync(params.filePath);
1134
+ const preOpenStat = ioFs.lstatSync(realPath);
1135
+ if (!isAllowedType(preOpenStat, allowedType)) return {
1136
+ ok: false,
1137
+ reason: "validation"
1138
+ };
1139
+ if (params.rejectHardlinks && preOpenStat.isFile() && preOpenStat.nlink > 1) return {
1140
+ ok: false,
1141
+ reason: "validation"
1142
+ };
1143
+ if (params.maxBytes !== void 0 && preOpenStat.isFile() && preOpenStat.size > params.maxBytes) return {
1144
+ ok: false,
1145
+ reason: "validation"
1146
+ };
1147
+ fd = ioFs.openSync(realPath, openReadFlags);
1148
+ const openedStat = ioFs.fstatSync(fd);
1149
+ if (!isAllowedType(openedStat, allowedType)) return {
1150
+ ok: false,
1151
+ reason: "validation"
1152
+ };
1153
+ if (params.rejectHardlinks && openedStat.isFile() && openedStat.nlink > 1) return {
1154
+ ok: false,
1155
+ reason: "validation"
1156
+ };
1157
+ if (params.maxBytes !== void 0 && openedStat.isFile() && openedStat.size > params.maxBytes) return {
1158
+ ok: false,
1159
+ reason: "validation"
1160
+ };
1161
+ if (!sameFileIdentity(preOpenStat, openedStat)) return {
1162
+ ok: false,
1163
+ reason: "validation"
1164
+ };
1165
+ const opened = {
1166
+ ok: true,
1167
+ path: realPath,
1168
+ fd,
1169
+ stat: openedStat
1170
+ };
1171
+ fd = null;
1172
+ return opened;
1173
+ } catch (error) {
1174
+ if (isExpectedPathError(error)) return {
1175
+ ok: false,
1176
+ reason: "path",
1177
+ error
1178
+ };
1179
+ return {
1180
+ ok: false,
1181
+ reason: "io",
1182
+ error
1183
+ };
1184
+ } finally {
1185
+ if (fd !== null) ioFs.closeSync(fd);
1186
+ }
1187
+ }
1188
+ function isAllowedType(stat, allowedType) {
1189
+ if (allowedType === "directory") return stat.isDirectory();
1190
+ return stat.isFile();
1191
+ }
1192
+
1193
+ //#endregion
1194
+ //#region src/infra/boundary-file-read.ts
1195
+ function canUseBoundaryFileOpen(ioFs) {
1196
+ return typeof ioFs.openSync === "function" && typeof ioFs.closeSync === "function" && typeof ioFs.fstatSync === "function" && typeof ioFs.lstatSync === "function" && typeof ioFs.realpathSync === "function" && typeof ioFs.readFileSync === "function" && typeof ioFs.constants === "object" && ioFs.constants !== null;
1197
+ }
1198
+ function openBoundaryFileSync(params) {
1199
+ const ioFs = params.ioFs ?? fs;
1200
+ const resolved = resolveBoundaryFilePathGeneric({
1201
+ absolutePath: params.absolutePath,
1202
+ resolve: (absolutePath) => resolveBoundaryPathSync({
1203
+ absolutePath,
1204
+ rootPath: params.rootPath,
1205
+ rootCanonicalPath: params.rootRealPath,
1206
+ boundaryLabel: params.boundaryLabel,
1207
+ skipLexicalRootCheck: params.skipLexicalRootCheck
1208
+ })
1209
+ });
1210
+ if (resolved instanceof Promise) return toBoundaryValidationError(/* @__PURE__ */ new Error("Unexpected async boundary resolution"));
1211
+ return finalizeBoundaryFileOpen({
1212
+ resolved,
1213
+ maxBytes: params.maxBytes,
1214
+ rejectHardlinks: params.rejectHardlinks,
1215
+ allowedType: params.allowedType,
1216
+ ioFs
1217
+ });
1218
+ }
1219
+ function openBoundaryFileResolved(params) {
1220
+ const opened = openVerifiedFileSync({
1221
+ filePath: params.absolutePath,
1222
+ resolvedPath: params.resolvedPath,
1223
+ rejectHardlinks: params.rejectHardlinks ?? true,
1224
+ maxBytes: params.maxBytes,
1225
+ allowedType: params.allowedType,
1226
+ ioFs: params.ioFs
1227
+ });
1228
+ if (!opened.ok) return opened;
1229
+ return {
1230
+ ok: true,
1231
+ path: opened.path,
1232
+ fd: opened.fd,
1233
+ stat: opened.stat,
1234
+ rootRealPath: params.rootRealPath
1235
+ };
1236
+ }
1237
+ function finalizeBoundaryFileOpen(params) {
1238
+ if ("ok" in params.resolved) return params.resolved;
1239
+ return openBoundaryFileResolved({
1240
+ absolutePath: params.resolved.absolutePath,
1241
+ resolvedPath: params.resolved.resolvedPath,
1242
+ rootRealPath: params.resolved.rootRealPath,
1243
+ maxBytes: params.maxBytes,
1244
+ rejectHardlinks: params.rejectHardlinks,
1245
+ allowedType: params.allowedType,
1246
+ ioFs: params.ioFs
1247
+ });
1248
+ }
1249
+ async function openBoundaryFile(params) {
1250
+ const ioFs = params.ioFs ?? fs;
1251
+ const maybeResolved = resolveBoundaryFilePathGeneric({
1252
+ absolutePath: params.absolutePath,
1253
+ resolve: (absolutePath) => resolveBoundaryPath({
1254
+ absolutePath,
1255
+ rootPath: params.rootPath,
1256
+ rootCanonicalPath: params.rootRealPath,
1257
+ boundaryLabel: params.boundaryLabel,
1258
+ policy: params.aliasPolicy,
1259
+ skipLexicalRootCheck: params.skipLexicalRootCheck
1260
+ })
1261
+ });
1262
+ return finalizeBoundaryFileOpen({
1263
+ resolved: maybeResolved instanceof Promise ? await maybeResolved : maybeResolved,
1264
+ maxBytes: params.maxBytes,
1265
+ rejectHardlinks: params.rejectHardlinks,
1266
+ allowedType: params.allowedType,
1267
+ ioFs
1268
+ });
1269
+ }
1270
+ function toBoundaryValidationError(error) {
1271
+ return {
1272
+ ok: false,
1273
+ reason: "validation",
1274
+ error
1275
+ };
1276
+ }
1277
+ function mapResolvedBoundaryPath(absolutePath, resolved) {
1278
+ return {
1279
+ absolutePath,
1280
+ resolvedPath: resolved.canonicalPath,
1281
+ rootRealPath: resolved.rootCanonicalPath
1282
+ };
1283
+ }
1284
+ function resolveBoundaryFilePathGeneric(params) {
1285
+ const absolutePath = path.resolve(params.absolutePath);
1286
+ try {
1287
+ const resolved = params.resolve(absolutePath);
1288
+ if (resolved instanceof Promise) return resolved.then((value) => mapResolvedBoundaryPath(absolutePath, value)).catch((error) => toBoundaryValidationError(error));
1289
+ return mapResolvedBoundaryPath(absolutePath, resolved);
1290
+ } catch (error) {
1291
+ return toBoundaryValidationError(error);
1292
+ }
1293
+ }
1294
+
1295
+ //#endregion
1296
+ //#region src/security/scan-paths.ts
1297
+ function isPathInside(basePath, candidatePath) {
1298
+ const base = path.resolve(basePath);
1299
+ const candidate = path.resolve(candidatePath);
1300
+ const rel = path.relative(base, candidate);
1301
+ return rel === "" || !rel.startsWith(`..${path.sep}`) && rel !== ".." && !path.isAbsolute(rel);
1302
+ }
1303
+ function safeRealpathSync(filePath) {
1304
+ try {
1305
+ return fs.realpathSync(filePath);
1306
+ } catch {
1307
+ return null;
1308
+ }
1309
+ }
1310
+ function isPathInsideWithRealpath(basePath, candidatePath, opts) {
1311
+ if (!isPathInside(basePath, candidatePath)) return false;
1312
+ const baseReal = safeRealpathSync(basePath);
1313
+ const candidateReal = safeRealpathSync(candidatePath);
1314
+ if (!baseReal || !candidateReal) return opts?.requireRealpath !== true;
1315
+ return isPathInside(baseReal, candidateReal);
1316
+ }
1317
+
1318
+ //#endregion
1319
+ //#region src/infra/prototype-keys.ts
1320
+ const BLOCKED_OBJECT_KEYS = new Set([
1321
+ "__proto__",
1322
+ "prototype",
1323
+ "constructor"
1324
+ ]);
1325
+ function isBlockedObjectKey(key) {
1326
+ return BLOCKED_OBJECT_KEYS.has(key);
1327
+ }
1328
+
1329
+ //#endregion
1330
+ //#region src/config/includes.ts
1331
+ /**
1332
+ * Config includes: $include directive for modular configs
1333
+ *
1334
+ * @example
1335
+ * ```json5
1336
+ * {
1337
+ * "$include": "./base.json5", // single file
1338
+ * "$include": ["./a.json5", "./b.json5"] // merge multiple
1339
+ * }
1340
+ * ```
1341
+ */
1342
+ const INCLUDE_KEY = "$include";
1343
+ const MAX_INCLUDE_DEPTH = 10;
1344
+ const MAX_INCLUDE_FILE_BYTES = 2 * 1024 * 1024;
1345
+ var ConfigIncludeError = class extends Error {
1346
+ constructor(message, includePath, cause) {
1347
+ super(message);
1348
+ this.includePath = includePath;
1349
+ this.cause = cause;
1350
+ this.name = "ConfigIncludeError";
1351
+ }
1352
+ };
1353
+ var CircularIncludeError = class extends ConfigIncludeError {
1354
+ constructor(chain) {
1355
+ super(`Circular include detected: ${chain.join(" -> ")}`, chain[chain.length - 1]);
1356
+ this.chain = chain;
1357
+ this.name = "CircularIncludeError";
1358
+ }
1359
+ };
1360
+ /** Deep merge: arrays concatenate, objects merge recursively, primitives: source wins */
1361
+ function deepMerge(target, source) {
1362
+ if (Array.isArray(target) && Array.isArray(source)) return [...target, ...source];
1363
+ if (isPlainObject(target) && isPlainObject(source)) {
1364
+ const result = { ...target };
1365
+ for (const key of Object.keys(source)) {
1366
+ if (isBlockedObjectKey(key)) continue;
1367
+ result[key] = key in result ? deepMerge(result[key], source[key]) : source[key];
1368
+ }
1369
+ return result;
1370
+ }
1371
+ return source;
1372
+ }
1373
+ var IncludeProcessor = class IncludeProcessor {
1374
+ constructor(basePath, resolver, rootDir) {
1375
+ this.basePath = basePath;
1376
+ this.resolver = resolver;
1377
+ this.visited = /* @__PURE__ */ new Set();
1378
+ this.depth = 0;
1379
+ this.visited.add(path.normalize(basePath));
1380
+ this.rootDir = path.normalize(rootDir ?? path.dirname(basePath));
1381
+ this.rootRealDir = path.normalize(safeRealpath(this.rootDir));
1382
+ }
1383
+ process(obj) {
1384
+ if (Array.isArray(obj)) return obj.map((item) => this.process(item));
1385
+ if (!isPlainObject(obj)) return obj;
1386
+ if (!(INCLUDE_KEY in obj)) return this.processObject(obj);
1387
+ return this.processInclude(obj);
1388
+ }
1389
+ processObject(obj) {
1390
+ const result = {};
1391
+ for (const [key, value] of Object.entries(obj)) result[key] = this.process(value);
1392
+ return result;
1393
+ }
1394
+ processInclude(obj) {
1395
+ const includeValue = obj[INCLUDE_KEY];
1396
+ const otherKeys = Object.keys(obj).filter((k) => k !== INCLUDE_KEY);
1397
+ const included = this.resolveInclude(includeValue);
1398
+ if (otherKeys.length === 0) return included;
1399
+ if (!isPlainObject(included)) throw new ConfigIncludeError("Sibling keys require included content to be an object", typeof includeValue === "string" ? includeValue : INCLUDE_KEY);
1400
+ const rest = {};
1401
+ for (const key of otherKeys) rest[key] = this.process(obj[key]);
1402
+ return deepMerge(included, rest);
1403
+ }
1404
+ resolveInclude(value) {
1405
+ if (typeof value === "string") return this.loadFile(value);
1406
+ if (Array.isArray(value)) return value.reduce((merged, item) => {
1407
+ if (typeof item !== "string") throw new ConfigIncludeError(`Invalid $include array item: expected string, got ${typeof item}`, String(item));
1408
+ return deepMerge(merged, this.loadFile(item));
1409
+ }, {});
1410
+ throw new ConfigIncludeError(`Invalid $include value: expected string or array of strings, got ${typeof value}`, String(value));
1411
+ }
1412
+ loadFile(includePath) {
1413
+ const resolvedPath = this.resolvePath(includePath);
1414
+ this.checkCircular(resolvedPath);
1415
+ this.checkDepth(includePath);
1416
+ const raw = this.readFile(includePath, resolvedPath);
1417
+ const parsed = this.parseFile(includePath, resolvedPath, raw);
1418
+ return this.processNested(resolvedPath, parsed);
1419
+ }
1420
+ resolvePath(includePath) {
1421
+ const configDir = path.dirname(this.basePath);
1422
+ const resolved = path.isAbsolute(includePath) ? includePath : path.resolve(configDir, includePath);
1423
+ const normalized = path.normalize(resolved);
1424
+ if (!isPathInside(this.rootDir, normalized)) throw new ConfigIncludeError(`Include path escapes config directory: ${includePath} (root: ${this.rootDir})`, includePath);
1425
+ try {
1426
+ const real = fs.realpathSync(normalized);
1427
+ if (!isPathInside(this.rootRealDir, real)) throw new ConfigIncludeError(`Include path resolves outside config directory (symlink): ${includePath} (root: ${this.rootDir})`, includePath);
1428
+ } catch (err) {
1429
+ if (err instanceof ConfigIncludeError) throw err;
1430
+ }
1431
+ return normalized;
1432
+ }
1433
+ checkCircular(resolvedPath) {
1434
+ if (this.visited.has(resolvedPath)) throw new CircularIncludeError([...this.visited, resolvedPath]);
1435
+ }
1436
+ checkDepth(includePath) {
1437
+ if (this.depth >= MAX_INCLUDE_DEPTH) throw new ConfigIncludeError(`Maximum include depth (${MAX_INCLUDE_DEPTH}) exceeded at: ${includePath}`, includePath);
1438
+ }
1439
+ readFile(includePath, resolvedPath) {
1440
+ try {
1441
+ if (this.resolver.readFileWithGuards) return this.resolver.readFileWithGuards({
1442
+ includePath,
1443
+ resolvedPath,
1444
+ rootRealDir: this.rootRealDir
1445
+ });
1446
+ return this.resolver.readFile(resolvedPath);
1447
+ } catch (err) {
1448
+ if (err instanceof ConfigIncludeError) throw err;
1449
+ throw new ConfigIncludeError(`Failed to read include file: ${includePath} (resolved: ${resolvedPath})`, includePath, err instanceof Error ? err : void 0);
1450
+ }
1451
+ }
1452
+ parseFile(includePath, resolvedPath, raw) {
1453
+ try {
1454
+ return this.resolver.parseJson(raw);
1455
+ } catch (err) {
1456
+ throw new ConfigIncludeError(`Failed to parse include file: ${includePath} (resolved: ${resolvedPath})`, includePath, err instanceof Error ? err : void 0);
1457
+ }
1458
+ }
1459
+ processNested(resolvedPath, parsed) {
1460
+ const nested = new IncludeProcessor(resolvedPath, this.resolver, this.rootDir);
1461
+ nested.visited = new Set([...this.visited, resolvedPath]);
1462
+ nested.depth = this.depth + 1;
1463
+ return nested.process(parsed);
1464
+ }
1465
+ };
1466
+ function safeRealpath(target) {
1467
+ try {
1468
+ return fs.realpathSync(target);
1469
+ } catch {
1470
+ return target;
1471
+ }
1472
+ }
1473
+ function readConfigIncludeFileWithGuards(params) {
1474
+ const ioFs = params.ioFs ?? fs;
1475
+ const maxBytes = params.maxBytes ?? MAX_INCLUDE_FILE_BYTES;
1476
+ if (!canUseBoundaryFileOpen(ioFs)) return ioFs.readFileSync(params.resolvedPath, "utf-8");
1477
+ const opened = openBoundaryFileSync({
1478
+ absolutePath: params.resolvedPath,
1479
+ rootPath: params.rootRealDir,
1480
+ rootRealPath: params.rootRealDir,
1481
+ boundaryLabel: "config directory",
1482
+ skipLexicalRootCheck: true,
1483
+ maxBytes,
1484
+ ioFs
1485
+ });
1486
+ if (!opened.ok) {
1487
+ if (opened.reason === "validation") throw new ConfigIncludeError(`Include file failed security checks (regular file, max ${maxBytes} bytes, no hardlinks): ${params.includePath}`, params.includePath);
1488
+ throw new ConfigIncludeError(`Failed to read include file: ${params.includePath} (resolved: ${params.resolvedPath})`, params.includePath, opened.error instanceof Error ? opened.error : void 0);
1489
+ }
1490
+ try {
1491
+ return ioFs.readFileSync(opened.fd, "utf-8");
1492
+ } finally {
1493
+ ioFs.closeSync(opened.fd);
1494
+ }
1495
+ }
1496
+ const defaultResolver = {
1497
+ readFile: (p) => fs.readFileSync(p, "utf-8"),
1498
+ readFileWithGuards: ({ includePath, resolvedPath, rootRealDir }) => readConfigIncludeFileWithGuards({
1499
+ includePath,
1500
+ resolvedPath,
1501
+ rootRealDir
1502
+ }),
1503
+ parseJson: (raw) => JSON5.parse(raw)
1504
+ };
1505
+ /**
1506
+ * Resolves all $include directives in a parsed config object.
1507
+ */
1508
+ function resolveConfigIncludes(obj, configPath, resolver = defaultResolver) {
1509
+ return new IncludeProcessor(configPath, resolver).process(obj);
1510
+ }
1511
+
1512
+ //#endregion
1513
+ //#region src/config/normalize-paths.ts
1514
+ const PATH_VALUE_RE = /^~(?=$|[\\/])/;
1515
+ const PATH_KEY_RE = /(dir|path|paths|file|root|workspace)$/i;
1516
+ const PATH_LIST_KEYS = new Set(["paths", "pathPrepend"]);
1517
+ function normalizeStringValue(key, value) {
1518
+ if (!PATH_VALUE_RE.test(value.trim())) return value;
1519
+ if (!key) return value;
1520
+ if (PATH_KEY_RE.test(key) || PATH_LIST_KEYS.has(key)) return resolveUserPath(value);
1521
+ return value;
1522
+ }
1523
+ function normalizeAny(key, value) {
1524
+ if (typeof value === "string") return normalizeStringValue(key, value);
1525
+ if (Array.isArray(value)) {
1526
+ const normalizeChildren = Boolean(key && PATH_LIST_KEYS.has(key));
1527
+ return value.map((entry) => {
1528
+ if (typeof entry === "string") return normalizeChildren ? normalizeStringValue(key, entry) : entry;
1529
+ if (Array.isArray(entry)) return normalizeAny(void 0, entry);
1530
+ if (isPlainObject(entry)) return normalizeAny(void 0, entry);
1531
+ return entry;
1532
+ });
1533
+ }
1534
+ if (!isPlainObject(value)) return value;
1535
+ for (const [childKey, childValue] of Object.entries(value)) {
1536
+ const next = normalizeAny(childKey, childValue);
1537
+ if (next !== childValue) value[childKey] = next;
1538
+ }
1539
+ return value;
1540
+ }
1541
+ /**
1542
+ * Normalize "~" paths in path-ish config fields.
1543
+ *
1544
+ * Goal: accept `~/...` consistently across config file + env overrides, while
1545
+ * keeping the surface area small and predictable.
1546
+ */
1547
+ function normalizeConfigPaths(cfg) {
1548
+ if (!cfg || typeof cfg !== "object") return cfg;
1549
+ normalizeAny(void 0, cfg);
1550
+ return cfg;
1551
+ }
1552
+
1553
+ //#endregion
1554
+ //#region src/logging/config.ts
1555
+ function readLoggingConfig() {
1556
+ const configPath = resolveConfigPath();
1557
+ try {
1558
+ if (!fs.existsSync(configPath)) return;
1559
+ const raw = fs.readFileSync(configPath, "utf-8");
1560
+ const resolvedIncludes = resolveConfigIncludes(JSON5.parse(raw), configPath, {
1561
+ readFile: (candidate) => fs.readFileSync(candidate, "utf-8"),
1562
+ readFileWithGuards: ({ includePath, resolvedPath, rootRealDir }) => readConfigIncludeFileWithGuards({
1563
+ includePath,
1564
+ resolvedPath,
1565
+ rootRealDir
1566
+ }),
1567
+ parseJson: (includeRaw) => JSON5.parse(includeRaw)
1568
+ });
1569
+ if (resolvedIncludes && typeof resolvedIncludes === "object" && "env" in resolvedIncludes) applyConfigEnvVars(resolvedIncludes);
1570
+ const resolvedConfig = resolveConfigEnvVars(resolvedIncludes);
1571
+ if (!resolvedConfig || typeof resolvedConfig !== "object" || Array.isArray(resolvedConfig)) return;
1572
+ const logging = normalizeConfigPaths(resolvedConfig).logging;
1573
+ if (!logging || typeof logging !== "object" || Array.isArray(logging)) return;
1574
+ return logging;
1575
+ } catch {
1576
+ return;
1577
+ }
1578
+ }
1579
+
1580
+ //#endregion
1581
+ //#region src/logging/levels.ts
1582
+ const ALLOWED_LOG_LEVELS = [
1583
+ "silent",
1584
+ "fatal",
1585
+ "error",
1586
+ "warn",
1587
+ "info",
1588
+ "debug",
1589
+ "trace"
1590
+ ];
1591
+ function tryParseLogLevel(level) {
1592
+ if (typeof level !== "string") return;
1593
+ const candidate = level.trim();
1594
+ return ALLOWED_LOG_LEVELS.includes(candidate) ? candidate : void 0;
1595
+ }
1596
+ function normalizeLogLevel(level, fallback = "info") {
1597
+ return tryParseLogLevel(level) ?? fallback;
1598
+ }
1599
+ function levelToMinLevel(level) {
1600
+ return {
1601
+ fatal: 0,
1602
+ error: 1,
1603
+ warn: 2,
1604
+ info: 3,
1605
+ debug: 4,
1606
+ trace: 5,
1607
+ silent: Number.POSITIVE_INFINITY
1608
+ }[level];
1609
+ }
1610
+ function levelToTslogMinLevel(level) {
1611
+ return {
1612
+ trace: 1,
1613
+ debug: 2,
1614
+ info: 3,
1615
+ warn: 4,
1616
+ error: 5,
1617
+ fatal: 6,
1618
+ silent: Number.POSITIVE_INFINITY
1619
+ }[level];
1620
+ }
1621
+
1622
+ //#endregion
1623
+ //#region src/logging/state.ts
1624
+ const loggingState = {
1625
+ cachedLogger: null,
1626
+ cachedSettings: null,
1627
+ cachedConsoleSettings: null,
1628
+ overrideSettings: null,
1629
+ invalidEnvLogLevelValue: null,
1630
+ consolePatched: false,
1631
+ forceConsoleToStderr: false,
1632
+ forceSubsystemConsoleToStderr: false,
1633
+ consoleTimestampPrefix: false,
1634
+ consoleSubsystemFilter: null,
1635
+ resolvingConsoleSettings: false,
1636
+ streamErrorHandlersInstalled: false,
1637
+ rawConsole: null
1638
+ };
1639
+
1640
+ //#endregion
1641
+ //#region src/logging/env-log-level.ts
1642
+ function resolveEnvLogLevelOverride() {
1643
+ const raw = process.env.OPENCLAW_LOG_LEVEL;
1644
+ const trimmed = typeof raw === "string" ? raw.trim() : "";
1645
+ if (!trimmed) {
1646
+ loggingState.invalidEnvLogLevelValue = null;
1647
+ return;
1648
+ }
1649
+ const parsed = tryParseLogLevel(trimmed);
1650
+ if (parsed) {
1651
+ loggingState.invalidEnvLogLevelValue = null;
1652
+ return parsed;
1653
+ }
1654
+ if (loggingState.invalidEnvLogLevelValue !== trimmed) {
1655
+ loggingState.invalidEnvLogLevelValue = trimmed;
1656
+ process.stderr.write(`[openclaw] Ignoring invalid OPENCLAW_LOG_LEVEL="${trimmed}" (allowed: ${ALLOWED_LOG_LEVELS.join("|")}).\n`);
1657
+ }
1658
+ }
1659
+
1660
+ //#endregion
1661
+ //#region src/logging/file-log-writer.ts
1662
+ const DEFAULT_MAX_FILE_BYTES = 10 * 1024 * 1024;
1663
+ const DEFAULT_MAX_BACKUPS = 5;
1664
+ const DEFAULT_MAX_QUEUED_BYTES = 1024 * 1024;
1665
+ const DEFAULT_COMPRESSION = "gzip";
1666
+ const DEFAULT_MODE = "jsonl";
1667
+ const gzipAsync = promisify(zlib.gzip);
1668
+ const writers = /* @__PURE__ */ new Map();
1669
+ const unresolvedWriterKeys = /* @__PURE__ */ new Map();
1670
+ function resolveFileLogProfile(config, profileId, overrides, options = {}) {
1671
+ const defaults = config?.fileLogs?.defaults;
1672
+ const profile = config?.fileLogs?.profiles?.[profileId];
1673
+ const merged = {
1674
+ maxFileBytes: DEFAULT_MAX_FILE_BYTES,
1675
+ maxBackups: DEFAULT_MAX_BACKUPS,
1676
+ compress: DEFAULT_COMPRESSION,
1677
+ maxQueuedBytes: DEFAULT_MAX_QUEUED_BYTES,
1678
+ mode: DEFAULT_MODE,
1679
+ ...defaults,
1680
+ ...overrides
1681
+ };
1682
+ if (profileId === "primary") {
1683
+ if (typeof config?.maxFileBytes === "number") merged.maxFileBytes = config.maxFileBytes;
1684
+ if (typeof config?.maxBackups === "number") merged.maxBackups = config.maxBackups;
1685
+ }
1686
+ if (profile) {
1687
+ let profileOverrides = profile;
1688
+ if (options.allowProfileFileOverride === false && typeof profile.file === "string") {
1689
+ const { file: _file, ...withoutFile } = profile;
1690
+ profileOverrides = withoutFile;
1691
+ }
1692
+ Object.assign(merged, profileOverrides);
1693
+ }
1694
+ return {
1695
+ profileId,
1696
+ file: typeof merged.file === "string" ? merged.file : "",
1697
+ maxFileBytes: normalizePositiveInteger(merged.maxFileBytes, DEFAULT_MAX_FILE_BYTES),
1698
+ maxBackups: normalizeNonnegativeInteger(merged.maxBackups, DEFAULT_MAX_BACKUPS),
1699
+ compress: merged.compress === false ? false : "gzip",
1700
+ maxQueuedBytes: normalizePositiveInteger(merged.maxQueuedBytes, DEFAULT_MAX_QUEUED_BYTES),
1701
+ mode: merged.mode === "text" ? "text" : "jsonl",
1702
+ keepLines: typeof merged.keepLines === "number" && Number.isFinite(merged.keepLines) && merged.keepLines > 0 ? Math.floor(merged.keepLines) : void 0
1703
+ };
1704
+ }
1705
+ function createFileLogWriter(options) {
1706
+ const { allowProfileFileOverride, config, fileMode, onRotate, profileId, strict, sync, ...overrides } = options;
1707
+ const handleOptions = {
1708
+ sync: sync === true,
1709
+ strict: strict === true,
1710
+ fileMode,
1711
+ onRotate
1712
+ };
1713
+ const unresolvedKey = config === void 0 ? unresolvedWriterKey(profileId, overrides, { allowProfileFileOverride }) : void 0;
1714
+ const cachedKey = unresolvedKey ? unresolvedWriterKeys.get(unresolvedKey) : void 0;
1715
+ const cachedWriter = cachedKey ? writers.get(cachedKey) : void 0;
1716
+ if (cachedWriter) return writerFromState(cachedWriter, handleOptions);
1717
+ const policy = resolveFileLogProfile(config ?? readLoggingConfig(), profileId, overrides, { allowProfileFileOverride });
1718
+ const key = writerKey(policy);
1719
+ const existing = writers.get(key);
1720
+ if (existing) {
1721
+ existing.policy = policy;
1722
+ if (unresolvedKey) unresolvedWriterKeys.set(unresolvedKey, key);
1723
+ return writerFromState(existing, handleOptions);
1724
+ }
1725
+ const state = {
1726
+ profileId: policy.profileId,
1727
+ file: policy.file,
1728
+ pendingWrites: 0,
1729
+ queuedBytes: 0,
1730
+ droppedWrites: 0,
1731
+ activeOperation: "idle",
1732
+ lastRotation: null,
1733
+ policy,
1734
+ queue: Promise.resolve()
1735
+ };
1736
+ writers.set(key, state);
1737
+ if (unresolvedKey) unresolvedWriterKeys.set(unresolvedKey, key);
1738
+ return writerFromState(state, handleOptions);
1739
+ }
1740
+ function appendFileLog(line, options) {
1741
+ return createFileLogWriter(options).append(line);
1742
+ }
1743
+ function rotateFileLog(filePath, policy, options = {}) {
1744
+ try {
1745
+ if (currentFileBytes(filePath) <= 0) return {
1746
+ at: (/* @__PURE__ */ new Date()).toISOString(),
1747
+ compressed: policy.compress === "gzip",
1748
+ skipped: true
1749
+ };
1750
+ if (policy.maxBackups <= 0) {
1751
+ fs.rmSync(filePath, { force: true });
1752
+ return {
1753
+ at: (/* @__PURE__ */ new Date()).toISOString(),
1754
+ compressed: policy.compress === "gzip"
1755
+ };
1756
+ }
1757
+ rotateExistingBackups(filePath, policy.maxBackups);
1758
+ const backup = `${filePath}.1${policy.compress === "gzip" ? ".gz" : ""}`;
1759
+ if (policy.compress === "gzip") {
1760
+ fs.writeFileSync(backup, zlib.gzipSync(fs.readFileSync(filePath)), { mode: options.fileMode });
1761
+ fs.rmSync(filePath, { force: true });
1762
+ } else fs.renameSync(filePath, backup);
1763
+ pruneExcessBackups(filePath, policy.maxBackups);
1764
+ return {
1765
+ at: (/* @__PURE__ */ new Date()).toISOString(),
1766
+ backup,
1767
+ compressed: policy.compress === "gzip"
1768
+ };
1769
+ } catch (err) {
1770
+ if (options.strict) throw err;
1771
+ return {
1772
+ at: (/* @__PURE__ */ new Date()).toISOString(),
1773
+ compressed: policy.compress === "gzip",
1774
+ skipped: true
1775
+ };
1776
+ }
1777
+ }
1778
+ function writerFromState(state, handleOptions) {
1779
+ return {
1780
+ append: (line) => appendWithState(state, line, handleOptions),
1781
+ diagnostics: () => {
1782
+ const { policy: _policy, queue: _queue, ...diagnostics } = state;
1783
+ return { ...diagnostics };
1784
+ }
1785
+ };
1786
+ }
1787
+ function appendWithState(state, line, opts) {
1788
+ const queuedBytes = Buffer.byteLength(line, "utf8");
1789
+ const policy = state.policy;
1790
+ const isOnlyPendingWrite = state.pendingWrites === 0 && state.queuedBytes === 0;
1791
+ if (state.queuedBytes + queuedBytes > policy.maxQueuedBytes && !isOnlyPendingWrite) {
1792
+ state.droppedWrites += 1;
1793
+ if (opts.strict) return Promise.reject(/* @__PURE__ */ new Error(`file log queue limit exceeded for ${policy.profileId}`));
1794
+ return "dropped";
1795
+ }
1796
+ state.pendingWrites += 1;
1797
+ state.queuedBytes += queuedBytes;
1798
+ if (opts.sync) {
1799
+ appendNow(state, policy, line, queuedBytes, opts);
1800
+ return "queued";
1801
+ }
1802
+ const task = state.queue.then(async () => {
1803
+ await appendNowAsync(state, policy, line, queuedBytes, opts);
1804
+ });
1805
+ state.queue = task.catch(() => void 0);
1806
+ return task.then(() => "queued");
1807
+ }
1808
+ async function appendNowAsync(state, policy, line, queuedBytes, opts) {
1809
+ try {
1810
+ state.activeOperation = "append";
1811
+ await fs.promises.mkdir(path.dirname(policy.file), { recursive: true });
1812
+ const currentBytes = await currentFileBytesAsync(policy.file);
1813
+ if (currentBytes + queuedBytes > policy.maxFileBytes && currentBytes > 0) {
1814
+ state.activeOperation = "rotate";
1815
+ state.lastRotation = await rotateFileLogAsync(policy.file, policy, {
1816
+ fileMode: opts.fileMode,
1817
+ strict: opts.strict
1818
+ });
1819
+ const rotationLine = state.lastRotation ? opts.onRotate?.(state.lastRotation) : void 0;
1820
+ if (rotationLine) await fs.promises.appendFile(policy.file, rotationLine, {
1821
+ encoding: "utf8",
1822
+ mode: opts.fileMode
1823
+ });
1824
+ }
1825
+ state.activeOperation = "append";
1826
+ await fs.promises.appendFile(policy.file, line, {
1827
+ encoding: "utf8",
1828
+ mode: opts.fileMode
1829
+ });
1830
+ } catch (err) {
1831
+ if (opts.strict) throw err;
1832
+ } finally {
1833
+ state.pendingWrites = Math.max(0, state.pendingWrites - 1);
1834
+ state.queuedBytes = Math.max(0, state.queuedBytes - queuedBytes);
1835
+ state.activeOperation = "idle";
1836
+ }
1837
+ }
1838
+ function appendNow(state, policy, line, queuedBytes, opts) {
1839
+ try {
1840
+ state.activeOperation = "append";
1841
+ fs.mkdirSync(path.dirname(policy.file), { recursive: true });
1842
+ const currentBytes = currentFileBytes(policy.file);
1843
+ if (currentBytes + queuedBytes > policy.maxFileBytes && currentBytes > 0) {
1844
+ state.activeOperation = "rotate";
1845
+ state.lastRotation = rotateFileLog(policy.file, policy, {
1846
+ fileMode: opts.fileMode,
1847
+ strict: opts.strict
1848
+ });
1849
+ const rotationLine = state.lastRotation ? opts.onRotate?.(state.lastRotation) : void 0;
1850
+ if (rotationLine) fs.appendFileSync(policy.file, rotationLine, {
1851
+ encoding: "utf8",
1852
+ mode: opts.fileMode
1853
+ });
1854
+ }
1855
+ state.activeOperation = "append";
1856
+ fs.appendFileSync(policy.file, line, {
1857
+ encoding: "utf8",
1858
+ mode: opts.fileMode
1859
+ });
1860
+ } catch (err) {
1861
+ if (opts.strict) throw err;
1862
+ } finally {
1863
+ state.pendingWrites = Math.max(0, state.pendingWrites - 1);
1864
+ state.queuedBytes = Math.max(0, state.queuedBytes - queuedBytes);
1865
+ state.activeOperation = "idle";
1866
+ }
1867
+ }
1868
+ function writerKey(policy) {
1869
+ return `${policy.profileId}:${policy.file}`;
1870
+ }
1871
+ function unresolvedWriterKey(profileId, overrides, options) {
1872
+ return stableStringify({
1873
+ profileId,
1874
+ allowProfileFileOverride: options.allowProfileFileOverride !== false,
1875
+ overrides
1876
+ });
1877
+ }
1878
+ function stableStringify(value) {
1879
+ if (Array.isArray(value)) return `[${value.map((item) => stableStringify(item)).join(",")}]`;
1880
+ if (value && typeof value === "object") return `{${Object.entries(value).filter(([, entryValue]) => entryValue !== void 0).toSorted(([a], [b]) => a.localeCompare(b)).map(([key, entryValue]) => `${JSON.stringify(key)}:${stableStringify(entryValue)}`).join(",")}}`;
1881
+ return JSON.stringify(value);
1882
+ }
1883
+ async function rotateFileLogAsync(filePath, policy, options = {}) {
1884
+ try {
1885
+ if (await currentFileBytesAsync(filePath) <= 0) return {
1886
+ at: (/* @__PURE__ */ new Date()).toISOString(),
1887
+ compressed: policy.compress === "gzip",
1888
+ skipped: true
1889
+ };
1890
+ if (policy.maxBackups <= 0) {
1891
+ await fs.promises.rm(filePath, { force: true });
1892
+ return {
1893
+ at: (/* @__PURE__ */ new Date()).toISOString(),
1894
+ compressed: policy.compress === "gzip"
1895
+ };
1896
+ }
1897
+ await rotateExistingBackupsAsync(filePath, policy.maxBackups);
1898
+ const backup = `${filePath}.1${policy.compress === "gzip" ? ".gz" : ""}`;
1899
+ if (policy.compress === "gzip") {
1900
+ await fs.promises.writeFile(backup, await gzipAsync(await fs.promises.readFile(filePath)), { mode: options.fileMode });
1901
+ await fs.promises.rm(filePath, { force: true });
1902
+ } else await fs.promises.rename(filePath, backup);
1903
+ await pruneExcessBackupsAsync(filePath, policy.maxBackups);
1904
+ return {
1905
+ at: (/* @__PURE__ */ new Date()).toISOString(),
1906
+ backup,
1907
+ compressed: policy.compress === "gzip"
1908
+ };
1909
+ } catch (err) {
1910
+ if (options.strict) throw err;
1911
+ return {
1912
+ at: (/* @__PURE__ */ new Date()).toISOString(),
1913
+ compressed: policy.compress === "gzip",
1914
+ skipped: true
1915
+ };
1916
+ }
1917
+ }
1918
+ function rotateExistingBackups(filePath, maxBackups) {
1919
+ for (const backup of listBackupEntries(filePath).toSorted((a, b) => b.slot - a.slot)) {
1920
+ if (backup.slot >= maxBackups) {
1921
+ fs.rmSync(backup.path, { force: true });
1922
+ continue;
1923
+ }
1924
+ const target = `${filePath}.${backup.slot + 1}${backup.suffix}`;
1925
+ fs.rmSync(target, { force: true });
1926
+ fs.renameSync(backup.path, target);
1927
+ }
1928
+ }
1929
+ async function rotateExistingBackupsAsync(filePath, maxBackups) {
1930
+ for (const backup of (await listBackupEntriesAsync(filePath)).toSorted((a, b) => b.slot - a.slot)) {
1931
+ if (backup.slot >= maxBackups) {
1932
+ await fs.promises.rm(backup.path, { force: true });
1933
+ continue;
1934
+ }
1935
+ const target = `${filePath}.${backup.slot + 1}${backup.suffix}`;
1936
+ await fs.promises.rm(target, { force: true });
1937
+ await fs.promises.rename(backup.path, target);
1938
+ }
1939
+ }
1940
+ function pruneExcessBackups(filePath, maxBackups) {
1941
+ const retained = listBackupEntries(filePath).toSorted((a, b) => a.slot - b.slot || b.mtimeMs - a.mtimeMs);
1942
+ for (const backup of retained.slice(maxBackups)) fs.rmSync(backup.path, { force: true });
1943
+ }
1944
+ async function pruneExcessBackupsAsync(filePath, maxBackups) {
1945
+ const retained = (await listBackupEntriesAsync(filePath)).toSorted((a, b) => a.slot - b.slot || b.mtimeMs - a.mtimeMs);
1946
+ for (const backup of retained.slice(maxBackups)) await fs.promises.rm(backup.path, { force: true });
1947
+ }
1948
+ function listBackupEntries(filePath) {
1949
+ const dir = path.dirname(filePath);
1950
+ const base = path.basename(filePath).replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
1951
+ let names = [];
1952
+ try {
1953
+ names = fs.readdirSync(dir);
1954
+ } catch {
1955
+ return [];
1956
+ }
1957
+ const backupPattern = new RegExp(`^${base}\\.(\\d+)(\\.gz)?$`);
1958
+ return names.flatMap((name) => {
1959
+ const match = backupPattern.exec(name);
1960
+ if (!match) return [];
1961
+ const backupPath = path.join(dir, name);
1962
+ let mtimeMs = 0;
1963
+ try {
1964
+ mtimeMs = fs.statSync(backupPath).mtimeMs;
1965
+ } catch {
1966
+ return [];
1967
+ }
1968
+ return [{
1969
+ path: backupPath,
1970
+ slot: Number(match[1]),
1971
+ suffix: match[2] === ".gz" ? ".gz" : "",
1972
+ mtimeMs
1973
+ }];
1974
+ });
1975
+ }
1976
+ async function listBackupEntriesAsync(filePath) {
1977
+ const dir = path.dirname(filePath);
1978
+ const base = path.basename(filePath).replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
1979
+ let names = [];
1980
+ try {
1981
+ names = await fs.promises.readdir(dir);
1982
+ } catch {
1983
+ return [];
1984
+ }
1985
+ const backupPattern = new RegExp(`^${base}\\.(\\d+)(\\.gz)?$`);
1986
+ return (await Promise.all(names.map(async (name) => {
1987
+ const match = backupPattern.exec(name);
1988
+ if (!match) return null;
1989
+ const backupPath = path.join(dir, name);
1990
+ try {
1991
+ const stat = await fs.promises.stat(backupPath);
1992
+ return {
1993
+ path: backupPath,
1994
+ slot: Number(match[1]),
1995
+ suffix: match[2] === ".gz" ? ".gz" : "",
1996
+ mtimeMs: stat.mtimeMs
1997
+ };
1998
+ } catch {
1999
+ return null;
2000
+ }
2001
+ }))).filter((entry) => entry !== null);
2002
+ }
2003
+ function currentFileBytes(filePath) {
2004
+ try {
2005
+ return fs.statSync(filePath).size;
2006
+ } catch {
2007
+ return 0;
2008
+ }
2009
+ }
2010
+ async function currentFileBytesAsync(filePath) {
2011
+ try {
2012
+ return (await fs.promises.stat(filePath)).size;
2013
+ } catch {
2014
+ return 0;
2015
+ }
2016
+ }
2017
+ function normalizePositiveInteger(value, fallback) {
2018
+ return typeof value === "number" && Number.isFinite(value) && value > 0 ? Math.floor(value) : fallback;
2019
+ }
2020
+ function normalizeNonnegativeInteger(value, fallback) {
2021
+ return typeof value === "number" && Number.isFinite(value) && value >= 0 ? Math.floor(value) : fallback;
2022
+ }
2023
+
2024
+ //#endregion
2025
+ //#region src/logging/local-date.ts
2026
+ function formatLocalDate(date) {
2027
+ return `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, "0")}-${String(date.getDate()).padStart(2, "0")}`;
2028
+ }
2029
+
2030
+ //#endregion
2031
+ //#region src/logging/node-require.ts
2032
+ function resolveNodeRequireFromMeta(metaUrl) {
2033
+ const getBuiltinModule = process.getBuiltinModule;
2034
+ if (typeof getBuiltinModule !== "function") return null;
2035
+ try {
2036
+ const moduleNamespace = getBuiltinModule("module");
2037
+ const createRequire = typeof moduleNamespace.createRequire === "function" ? moduleNamespace.createRequire : null;
2038
+ return createRequire ? createRequire(metaUrl) : null;
2039
+ } catch {
2040
+ return null;
2041
+ }
2042
+ }
2043
+
2044
+ //#endregion
2045
+ //#region src/logging/timestamps.ts
2046
+ function isValidTimeZone(tz) {
2047
+ try {
2048
+ new Intl.DateTimeFormat("en", { timeZone: tz });
2049
+ return true;
2050
+ } catch {
2051
+ return false;
2052
+ }
2053
+ }
2054
+ function formatLocalIsoWithOffset(now, timeZone) {
2055
+ const explicit = timeZone ?? process.env.TZ;
2056
+ const tz = explicit && isValidTimeZone(explicit) ? explicit : Intl.DateTimeFormat().resolvedOptions().timeZone;
2057
+ const fmt = new Intl.DateTimeFormat("en", {
2058
+ timeZone: tz,
2059
+ year: "numeric",
2060
+ month: "2-digit",
2061
+ day: "2-digit",
2062
+ hour: "2-digit",
2063
+ minute: "2-digit",
2064
+ second: "2-digit",
2065
+ hour12: false,
2066
+ fractionalSecondDigits: 3,
2067
+ timeZoneName: "longOffset"
2068
+ });
2069
+ const parts = Object.fromEntries(fmt.formatToParts(now).map((p) => [p.type, p.value]));
2070
+ const offsetRaw = parts.timeZoneName ?? "GMT";
2071
+ const offset = offsetRaw === "GMT" ? "+00:00" : offsetRaw.slice(3);
2072
+ return `${parts.year}-${parts.month}-${parts.day}T${parts.hour}:${parts.minute}:${parts.second}.${parts.fractionalSecond}${offset}`;
2073
+ }
2074
+
2075
+ //#endregion
2076
+ //#region src/logging/logger.ts
2077
+ const DEFAULT_LOG_DIR = resolvePreferredOpenClawTmpDir();
2078
+ const DEFAULT_LOG_FILE = path.join(DEFAULT_LOG_DIR, "openclaw.log");
2079
+ const LOG_PREFIX = "openclaw";
2080
+ const LOG_SUFFIX = ".log";
2081
+ const MAX_LOG_AGE_MS = 1440 * 60 * 1e3;
2082
+ const DEFAULT_MAX_LOG_FILE_BYTES = 10 * 1024 * 1024;
2083
+ const DEFAULT_MAX_LOG_BACKUPS = 5;
2084
+ const requireConfig$1 = resolveNodeRequireFromMeta(import.meta.url);
2085
+ const externalTransports = /* @__PURE__ */ new Set();
2086
+ function shouldSkipLoadConfigFallback(argv = process.argv) {
2087
+ const [primary, secondary] = getCommandPathWithRootOptions(argv, 2);
2088
+ return primary === "config" && secondary === "validate";
2089
+ }
2090
+ function toTslogMinLevel(level) {
2091
+ const minLevel = levelToTslogMinLevel(level);
2092
+ return minLevel >= 0 && minLevel <= 6 ? minLevel : void 0;
2093
+ }
2094
+ function isSilentLogging() {
2095
+ return loggingState.cachedSettings?.level === "silent";
2096
+ }
2097
+ function attachExternalTransport(logger, transport) {
2098
+ logger.attachTransport((logObj) => {
2099
+ if (!externalTransports.has(transport) || isSilentLogging()) return;
2100
+ try {
2101
+ transport(logObj);
2102
+ } catch {}
2103
+ });
2104
+ }
2105
+ function canUseSilentVitestFileLogFastPath(envLevel) {
2106
+ return process.env.VITEST === "true" && process.env.OPENCLAW_TEST_FILE_LOG !== "1" && !envLevel && !loggingState.overrideSettings;
2107
+ }
2108
+ function resolveSettings(opts = {}) {
2109
+ const envLevel = resolveEnvLogLevelOverride();
2110
+ if (canUseSilentVitestFileLogFastPath(envLevel)) return {
2111
+ level: "silent",
2112
+ file: defaultRollingPathForToday(),
2113
+ maxFileBytes: DEFAULT_MAX_LOG_FILE_BYTES,
2114
+ maxBackups: DEFAULT_MAX_LOG_BACKUPS,
2115
+ fileLogsSignature: ""
2116
+ };
2117
+ let cfg = loggingState.overrideSettings ?? readLoggingConfig();
2118
+ if (!cfg && opts.configLoadFallback !== false && !shouldSkipLoadConfigFallback()) try {
2119
+ cfg = (requireConfig$1?.("../config/config.js"))?.loadConfig?.().logging;
2120
+ } catch {
2121
+ cfg = void 0;
2122
+ }
2123
+ const defaultLevel = process.env.VITEST === "true" && process.env.OPENCLAW_TEST_FILE_LOG !== "1" ? "silent" : "info";
2124
+ const fromConfig = normalizeLogLevel(cfg?.level, defaultLevel);
2125
+ const level = envLevel ?? fromConfig;
2126
+ const configuredFile = cfg?.file ?? defaultRollingPathForToday();
2127
+ const primaryPolicy = resolveFileLogProfile(cfg, "primary", {
2128
+ file: configuredFile,
2129
+ mode: "jsonl",
2130
+ maxQueuedBytes: Number.MAX_SAFE_INTEGER
2131
+ });
2132
+ return {
2133
+ level,
2134
+ file: primaryPolicy.file || configuredFile,
2135
+ maxFileBytes: primaryPolicy.maxFileBytes,
2136
+ maxBackups: primaryPolicy.maxBackups,
2137
+ writerConfig: cfg,
2138
+ fileLogsSignature: JSON.stringify(cfg?.fileLogs ?? null)
2139
+ };
2140
+ }
2141
+ function settingsChanged(a, b) {
2142
+ if (!a) return true;
2143
+ return a.level !== b.level || a.file !== b.file || a.maxFileBytes !== b.maxFileBytes || a.maxBackups !== b.maxBackups || a.fileLogsSignature !== b.fileLogsSignature;
2144
+ }
2145
+ function isFileLogLevelEnabled(level) {
2146
+ const settings = loggingState.cachedSettings ?? resolveSettings();
2147
+ if (!loggingState.cachedSettings) loggingState.cachedSettings = settings;
2148
+ if (settings.level === "silent") return false;
2149
+ return levelToMinLevel(level) <= levelToMinLevel(settings.level);
2150
+ }
2151
+ function buildLogger(settings) {
2152
+ const logger = new Logger({
2153
+ name: "openclaw",
2154
+ minLevel: toTslogMinLevel(settings.level),
2155
+ type: "hidden"
2156
+ });
2157
+ if (settings.level === "silent") {
2158
+ for (const transport of externalTransports) attachExternalTransport(logger, transport);
2159
+ return logger;
2160
+ }
2161
+ fs.mkdirSync(path.dirname(settings.file), { recursive: true });
2162
+ if (isRollingPath(settings.file)) pruneOldRollingLogs(path.dirname(settings.file));
2163
+ const primaryPolicy = resolveFileLogProfile(settings.writerConfig, "primary", {
2164
+ file: settings.file,
2165
+ mode: "jsonl",
2166
+ maxQueuedBytes: Number.MAX_SAFE_INTEGER
2167
+ });
2168
+ const writer = createFileLogWriter({
2169
+ profileId: "primary",
2170
+ file: settings.file,
2171
+ config: settings.writerConfig,
2172
+ mode: "jsonl",
2173
+ maxQueuedBytes: Number.MAX_SAFE_INTEGER,
2174
+ sync: true,
2175
+ onRotate: (rotation) => {
2176
+ const backupSuffix = primaryPolicy.compress === "gzip" ? ".gz" : "";
2177
+ const backup = rotation.backup ?? (!rotation.skipped && primaryPolicy.maxBackups > 0 ? `${primaryPolicy.file}.1${backupSuffix}` : void 0);
2178
+ return `${JSON.stringify({
2179
+ time: formatLocalIsoWithOffset(/* @__PURE__ */ new Date()),
2180
+ level: "info",
2181
+ subsystem: "logging",
2182
+ message: "rotated log file",
2183
+ file: primaryPolicy.file,
2184
+ ...backup ? { backup } : {},
2185
+ maxBackups: primaryPolicy.maxBackups
2186
+ })}\n`;
2187
+ }
2188
+ });
2189
+ logger.attachTransport((logObj) => {
2190
+ try {
2191
+ const time = formatLocalIsoWithOffset(logObj.date ?? /* @__PURE__ */ new Date());
2192
+ const payload = `${JSON.stringify({
2193
+ ...logObj,
2194
+ time
2195
+ })}\n`;
2196
+ writer.append(payload);
2197
+ } catch {}
2198
+ });
2199
+ for (const transport of externalTransports) attachExternalTransport(logger, transport);
2200
+ return logger;
2201
+ }
2202
+ function getLogger() {
2203
+ const settings = resolveSettings();
2204
+ const cachedLogger = loggingState.cachedLogger;
2205
+ const cachedSettings = loggingState.cachedSettings;
2206
+ if (!cachedLogger || settingsChanged(cachedSettings, settings)) {
2207
+ loggingState.cachedLogger = buildLogger(settings);
2208
+ loggingState.cachedSettings = settings;
2209
+ }
2210
+ return loggingState.cachedLogger;
2211
+ }
2212
+ function getChildLogger(bindings, opts) {
2213
+ const base = getLogger();
2214
+ const minLevel = opts?.level ? toTslogMinLevel(opts.level) : void 0;
2215
+ const name = bindings ? JSON.stringify(bindings) : void 0;
2216
+ return base.getSubLogger({
2217
+ name,
2218
+ ...minLevel === void 0 ? {} : { minLevel },
2219
+ prefix: bindings ? [name ?? ""] : []
2220
+ });
2221
+ }
2222
+ function defaultRollingPathForToday() {
2223
+ const today = formatLocalDate(/* @__PURE__ */ new Date());
2224
+ return path.join(DEFAULT_LOG_DIR, `${LOG_PREFIX}-${today}${LOG_SUFFIX}`);
2225
+ }
2226
+ function isRollingPath(file) {
2227
+ const base = path.basename(file);
2228
+ return base.startsWith(`${LOG_PREFIX}-`) && base.endsWith(LOG_SUFFIX) && base.length === `${LOG_PREFIX}-YYYY-MM-DD${LOG_SUFFIX}`.length;
2229
+ }
2230
+ function pruneOldRollingLogs(dir) {
2231
+ try {
2232
+ const entries = fs.readdirSync(dir, { withFileTypes: true });
2233
+ const cutoff = Date.now() - MAX_LOG_AGE_MS;
2234
+ for (const entry of entries) {
2235
+ if (!entry.isFile()) continue;
2236
+ const fullPath = path.join(dir, entry.name);
2237
+ const backupDateMs = rollingBackupDateMs(entry.name);
2238
+ if (backupDateMs !== null) {
2239
+ if (backupDateMs < cutoff) try {
2240
+ fs.rmSync(fullPath, { force: true });
2241
+ } catch {}
2242
+ continue;
2243
+ }
2244
+ if (!entry.name.startsWith(`${LOG_PREFIX}-`) || !entry.name.endsWith(LOG_SUFFIX)) continue;
2245
+ try {
2246
+ if (fs.statSync(fullPath).mtimeMs < cutoff) fs.rmSync(fullPath, { force: true });
2247
+ } catch {}
2248
+ }
2249
+ } catch {}
2250
+ }
2251
+ function rollingBackupDateMs(name) {
2252
+ const match = /^openclaw-(\d{4})-(\d{2})-(\d{2})\.log\.\d+(?:\.gz)?$/.exec(name);
2253
+ if (!match) return null;
2254
+ const ms = new Date(Number(match[1]), Number(match[2]) - 1, Number(match[3]) + 1).getTime();
2255
+ return Number.isNaN(ms) ? null : ms;
2256
+ }
2257
+
2258
+ //#endregion
2259
+ //#region src/terminal/palette.ts
2260
+ const LOBSTER_PALETTE = {
2261
+ accent: "#6366F1",
2262
+ accentBright: "#818CF8",
2263
+ accentDim: "#4F46E5",
2264
+ info: "#818CF8",
2265
+ success: "#34D399",
2266
+ warn: "#FBBF24",
2267
+ error: "#EF4444",
2268
+ muted: "#A0A0A0"
2269
+ };
2270
+
2271
+ //#endregion
2272
+ //#region src/terminal/theme.ts
2273
+ const hasForceColor = typeof process.env.FORCE_COLOR === "string" && process.env.FORCE_COLOR.trim().length > 0 && process.env.FORCE_COLOR.trim() !== "0";
2274
+ const baseChalk = process.env.NO_COLOR && !hasForceColor ? new Chalk({ level: 0 }) : chalk;
2275
+ const hex = (value) => baseChalk.hex(value);
2276
+ const theme = {
2277
+ accent: hex(LOBSTER_PALETTE.accent),
2278
+ accentBright: hex(LOBSTER_PALETTE.accentBright),
2279
+ accentDim: hex(LOBSTER_PALETTE.accentDim),
2280
+ info: hex(LOBSTER_PALETTE.info),
2281
+ success: hex(LOBSTER_PALETTE.success),
2282
+ warn: hex(LOBSTER_PALETTE.warn),
2283
+ error: hex(LOBSTER_PALETTE.error),
2284
+ muted: hex(LOBSTER_PALETTE.muted),
2285
+ heading: baseChalk.bold.hex(LOBSTER_PALETTE.accent),
2286
+ command: hex(LOBSTER_PALETTE.accentBright),
2287
+ option: hex(LOBSTER_PALETTE.warn)
2288
+ };
2289
+ const isRich = () => Boolean(baseChalk.level > 0);
2290
+ const colorize = (rich, color, value) => rich ? color(value) : value;
2291
+
2292
+ //#endregion
2293
+ //#region src/globals.ts
2294
+ let globalVerbose = false;
2295
+ function setVerbose(v) {
2296
+ globalVerbose = v;
2297
+ }
2298
+ function isVerbose() {
2299
+ return globalVerbose;
2300
+ }
2301
+ function shouldLogVerbose() {
2302
+ return globalVerbose || isFileLogLevelEnabled("debug");
2303
+ }
2304
+ function logVerbose(message) {
2305
+ if (!shouldLogVerbose()) return;
2306
+ try {
2307
+ getLogger().debug({ message }, "verbose");
2308
+ } catch {}
2309
+ if (!globalVerbose) return;
2310
+ console.log(theme.muted(message));
2311
+ }
2312
+ function logVerboseConsole(message) {
2313
+ if (!globalVerbose) return;
2314
+ console.log(theme.muted(message));
2315
+ }
2316
+ const success = theme.success;
2317
+ const warn = theme.warn;
2318
+ const info = theme.info;
2319
+ const danger = theme.error;
2320
+
2321
+ //#endregion
2322
+ //#region src/terminal/progress-line.ts
2323
+ let activeStream = null;
2324
+ function registerActiveProgressLine(stream) {
2325
+ if (!stream.isTTY) return;
2326
+ activeStream = stream;
2327
+ }
2328
+ function clearActiveProgressLine() {
2329
+ if (!activeStream?.isTTY) return;
2330
+ activeStream.write("\r\x1B[2K");
2331
+ }
2332
+ function unregisterActiveProgressLine(stream) {
2333
+ if (!activeStream) return;
2334
+ if (stream && activeStream !== stream) return;
2335
+ activeStream = null;
2336
+ }
2337
+
2338
+ //#endregion
2339
+ //#region src/terminal/restore.ts
2340
+ const RESET_SEQUENCE = "\x1B[0m\x1B[?25h\x1B[?1000l\x1B[?1002l\x1B[?1003l\x1B[?1006l\x1B[?2004l";
2341
+ function reportRestoreFailure(scope, err, reason) {
2342
+ const suffix = reason ? ` (${reason})` : "";
2343
+ const message = `[terminal] restore ${scope} failed${suffix}: ${String(err)}`;
2344
+ try {
2345
+ process.stderr.write(`${message}\n`);
2346
+ } catch (writeErr) {
2347
+ console.error(`[terminal] restore reporting failed${suffix}: ${String(writeErr)}`);
2348
+ }
2349
+ }
2350
+ function restoreTerminalState(reason, options = {}) {
2351
+ const resumeStdin = options.resumeStdinIfPaused ?? options.resumeStdin ?? false;
2352
+ try {
2353
+ clearActiveProgressLine();
2354
+ } catch (err) {
2355
+ reportRestoreFailure("progress line", err, reason);
2356
+ }
2357
+ const stdin = process.stdin;
2358
+ if (stdin.isTTY && typeof stdin.setRawMode === "function") {
2359
+ try {
2360
+ stdin.setRawMode(false);
2361
+ } catch (err) {
2362
+ reportRestoreFailure("raw mode", err, reason);
2363
+ }
2364
+ if (resumeStdin && typeof stdin.isPaused === "function" && stdin.isPaused()) try {
2365
+ stdin.resume();
2366
+ } catch (err) {
2367
+ reportRestoreFailure("stdin resume", err, reason);
2368
+ }
2369
+ }
2370
+ if (process.stdout.isTTY) try {
2371
+ process.stdout.write(RESET_SEQUENCE);
2372
+ } catch (err) {
2373
+ reportRestoreFailure("stdout reset", err, reason);
2374
+ }
2375
+ }
2376
+
2377
+ //#endregion
2378
+ //#region src/runtime.ts
2379
+ function shouldEmitRuntimeLog(env = process.env) {
2380
+ if (env.VITEST !== "true") return true;
2381
+ if (env.OPENCLAW_TEST_RUNTIME_LOG === "1") return true;
2382
+ return typeof console.log.mock === "object";
2383
+ }
2384
+ function createRuntimeIo() {
2385
+ return {
2386
+ log: (...args) => {
2387
+ if (!shouldEmitRuntimeLog()) return;
2388
+ clearActiveProgressLine();
2389
+ console.log(...args);
2390
+ },
2391
+ error: (...args) => {
2392
+ clearActiveProgressLine();
2393
+ console.error(...args);
2394
+ }
2395
+ };
2396
+ }
2397
+ const defaultRuntime = {
2398
+ ...createRuntimeIo(),
2399
+ exit: (code) => {
2400
+ restoreTerminalState("runtime exit", { resumeStdinIfPaused: false });
2401
+ process.exit(code);
2402
+ throw new Error("unreachable");
2403
+ }
2404
+ };
2405
+ function createNonExitingRuntime() {
2406
+ return {
2407
+ ...createRuntimeIo(),
2408
+ exit: (code) => {
2409
+ throw new Error(`exit ${code}`);
2410
+ }
2411
+ };
2412
+ }
2413
+
2414
+ //#endregion
2415
+ //#region src/shared/text-chunking.ts
2416
+ /**
2417
+ * Returns a break index that does not fall between a UTF-16 surrogate pair.
2418
+ * If `breakIdx` would split a pair (high surrogate at breakIdx-1, low at breakIdx),
2419
+ * backs up by 1. Otherwise returns `breakIdx` unchanged.
2420
+ *
2421
+ * Reference: src/memory/embedding-input-limits.ts:46-56 (the only surrogate-aware
2422
+ * split in the fork before this port). Ported from upstream openclaw `18fbcef4966`.
2423
+ */
2424
+ function avoidTrailingHighSurrogateBreak(text, breakIdx) {
2425
+ if (breakIdx > 0 && breakIdx < text.length && text.charCodeAt(breakIdx - 1) >= 55296 && text.charCodeAt(breakIdx - 1) <= 56319 && text.charCodeAt(breakIdx) >= 56320 && text.charCodeAt(breakIdx) <= 57343) return breakIdx - 1;
2426
+ return breakIdx;
2427
+ }
2428
+ function chunkTextByBreakResolver(text, limit, resolveBreakIndex) {
2429
+ if (!text) return [];
2430
+ if (limit <= 0 || text.length <= limit) return [text];
2431
+ const chunks = [];
2432
+ let remaining = text;
2433
+ while (remaining.length > limit) {
2434
+ const candidateBreak = resolveBreakIndex(remaining.slice(0, limit));
2435
+ let breakIdx = avoidTrailingHighSurrogateBreak(remaining, Number.isFinite(candidateBreak) && candidateBreak > 0 && candidateBreak <= limit ? candidateBreak : limit);
2436
+ if (breakIdx <= 0) breakIdx = Math.min(remaining.length, 2);
2437
+ const chunk = remaining.slice(0, breakIdx).trimEnd();
2438
+ if (chunk.length > 0) chunks.push(chunk);
2439
+ const brokeOnSeparator = breakIdx < remaining.length && /\s/.test(remaining[breakIdx]);
2440
+ const nextStart = Math.min(remaining.length, breakIdx + (brokeOnSeparator ? 1 : 0));
2441
+ remaining = remaining.slice(nextStart).trimStart();
2442
+ }
2443
+ if (remaining.length) chunks.push(remaining);
2444
+ return chunks;
2445
+ }
2446
+
2447
+ //#endregion
2448
+ //#region src/terminal/ansi.ts
2449
+ const ANSI_SGR_PATTERN = "\\x1b\\[[0-9;]*m";
2450
+ const OSC8_PATTERN = "\\x1b\\]8;;.*?\\x1b\\\\|\\x1b\\]8;;\\x1b\\\\";
2451
+ const ANSI_REGEX = new RegExp(ANSI_SGR_PATTERN, "g");
2452
+ const OSC8_REGEX = new RegExp(OSC8_PATTERN, "g");
2453
+ function stripAnsi(input) {
2454
+ return input.replace(OSC8_REGEX, "").replace(ANSI_REGEX, "");
2455
+ }
2456
+
2457
+ //#endregion
2458
+ //#region src/logging/console.ts
2459
+ const requireConfig = resolveNodeRequireFromMeta(import.meta.url);
2460
+ const loadConfigFallbackDefault = () => {
2461
+ try {
2462
+ return (requireConfig?.("../config/config.js"))?.loadConfig?.().logging;
2463
+ } catch {
2464
+ return;
2465
+ }
2466
+ };
2467
+ let loadConfigFallback = loadConfigFallbackDefault;
2468
+ function normalizeConsoleLevel(level) {
2469
+ if (isVerbose()) return "debug";
2470
+ if (!level && process.env.VITEST === "true" && process.env.OPENCLAW_TEST_CONSOLE !== "1") return "silent";
2471
+ return normalizeLogLevel(level, "info");
2472
+ }
2473
+ function normalizeConsoleStyle(style) {
2474
+ if (style === "compact" || style === "json" || style === "pretty") return style;
2475
+ if (!process.stdout.isTTY) return "compact";
2476
+ return "pretty";
2477
+ }
2478
+ function resolveConsoleSettings() {
2479
+ const envLevel = resolveEnvLogLevelOverride();
2480
+ if (process.env.VITEST === "true" && process.env.OPENCLAW_TEST_CONSOLE !== "1" && !isVerbose() && !envLevel && !loggingState.overrideSettings) return {
2481
+ level: "silent",
2482
+ style: normalizeConsoleStyle(void 0)
2483
+ };
2484
+ let cfg = loggingState.overrideSettings ?? readLoggingConfig();
2485
+ if (!cfg) if (loggingState.resolvingConsoleSettings) cfg = void 0;
2486
+ else {
2487
+ loggingState.resolvingConsoleSettings = true;
2488
+ try {
2489
+ cfg = loadConfigFallback();
2490
+ } finally {
2491
+ loggingState.resolvingConsoleSettings = false;
2492
+ }
2493
+ }
2494
+ return {
2495
+ level: envLevel ?? normalizeConsoleLevel(cfg?.consoleLevel),
2496
+ style: normalizeConsoleStyle(cfg?.consoleStyle)
2497
+ };
2498
+ }
2499
+ function consoleSettingsChanged(a, b) {
2500
+ if (!a) return true;
2501
+ return a.level !== b.level || a.style !== b.style;
2502
+ }
2503
+ function getConsoleSettings() {
2504
+ const settings = resolveConsoleSettings();
2505
+ const cached = loggingState.cachedConsoleSettings;
2506
+ if (!cached || consoleSettingsChanged(cached, settings)) loggingState.cachedConsoleSettings = settings;
2507
+ return loggingState.cachedConsoleSettings;
2508
+ }
2509
+ function shouldLogSubsystemToConsole(subsystem) {
2510
+ const filter = loggingState.consoleSubsystemFilter;
2511
+ if (!filter || filter.length === 0) return true;
2512
+ return filter.some((prefix) => subsystem === prefix || subsystem.startsWith(`${prefix}/`));
2513
+ }
2514
+
2515
+ //#endregion
2516
+ //#region src/logging/subsystem.ts
2517
+ function shouldLogToConsole(level, settings) {
2518
+ if (settings.level === "silent") return false;
2519
+ return levelToMinLevel(level) <= levelToMinLevel(settings.level);
2520
+ }
2521
+ const inspectValue = (() => {
2522
+ const getBuiltinModule = process.getBuiltinModule;
2523
+ if (typeof getBuiltinModule !== "function") return null;
2524
+ try {
2525
+ const utilNamespace = getBuiltinModule("util");
2526
+ return typeof utilNamespace.inspect === "function" ? utilNamespace.inspect : null;
2527
+ } catch {
2528
+ return null;
2529
+ }
2530
+ })();
2531
+ function isRichConsoleEnv() {
2532
+ const term = (process.env.TERM ?? "").toLowerCase();
2533
+ if (process.env.COLORTERM || process.env.TERM_PROGRAM) return true;
2534
+ return term.length > 0 && term !== "dumb";
2535
+ }
2536
+ function getColorForConsole() {
2537
+ const hasForceColor = typeof process.env.FORCE_COLOR === "string" && process.env.FORCE_COLOR.trim().length > 0 && process.env.FORCE_COLOR.trim() !== "0";
2538
+ if (process.env.NO_COLOR && !hasForceColor) return new Chalk({ level: 0 });
2539
+ const hasTty = Boolean(process.stdout.isTTY || process.stderr.isTTY);
2540
+ return hasForceColor || hasTty || isRichConsoleEnv() ? new Chalk({ level: 1 }) : new Chalk({ level: 0 });
2541
+ }
2542
+ const SUBSYSTEM_COLORS = [
2543
+ "cyan",
2544
+ "green",
2545
+ "yellow",
2546
+ "blue",
2547
+ "magenta",
2548
+ "red"
2549
+ ];
2550
+ const SUBSYSTEM_COLOR_OVERRIDES = { "gmail-watcher": "blue" };
2551
+ const SUBSYSTEM_PREFIXES_TO_DROP = [
2552
+ "gateway",
2553
+ "channels",
2554
+ "providers"
2555
+ ];
2556
+ const SUBSYSTEM_MAX_SEGMENTS = 2;
2557
+ const CHANNEL_SUBSYSTEM_PREFIXES = new Set([
2558
+ "telegram",
2559
+ "whatsapp",
2560
+ "discord",
2561
+ "irc",
2562
+ "googlechat",
2563
+ "slack",
2564
+ "signal",
2565
+ "imessage"
2566
+ ]);
2567
+ function pickSubsystemColor(color, subsystem) {
2568
+ const override = SUBSYSTEM_COLOR_OVERRIDES[subsystem];
2569
+ if (override) return color[override];
2570
+ let hash = 0;
2571
+ for (let i = 0; i < subsystem.length; i += 1) hash = hash * 31 + subsystem.charCodeAt(i) | 0;
2572
+ return color[SUBSYSTEM_COLORS[Math.abs(hash) % SUBSYSTEM_COLORS.length]];
2573
+ }
2574
+ function formatSubsystemForConsole(subsystem) {
2575
+ const parts = subsystem.split("/").filter(Boolean);
2576
+ const original = parts.join("/") || subsystem;
2577
+ while (parts.length > 0 && SUBSYSTEM_PREFIXES_TO_DROP.includes(parts[0])) parts.shift();
2578
+ if (parts.length === 0) return original;
2579
+ if (CHANNEL_SUBSYSTEM_PREFIXES.has(parts[0])) return parts[0];
2580
+ if (parts.length > SUBSYSTEM_MAX_SEGMENTS) return parts.slice(-SUBSYSTEM_MAX_SEGMENTS).join("/");
2581
+ return parts.join("/");
2582
+ }
2583
+ function stripRedundantSubsystemPrefixForConsole(message, displaySubsystem) {
2584
+ if (!displaySubsystem) return message;
2585
+ if (message.startsWith("[")) {
2586
+ const closeIdx = message.indexOf("]");
2587
+ if (closeIdx > 1) {
2588
+ if (message.slice(1, closeIdx).toLowerCase() === displaySubsystem.toLowerCase()) {
2589
+ let i = closeIdx + 1;
2590
+ while (message[i] === " ") i += 1;
2591
+ return message.slice(i);
2592
+ }
2593
+ }
2594
+ }
2595
+ if (message.slice(0, displaySubsystem.length).toLowerCase() !== displaySubsystem.toLowerCase()) return message;
2596
+ const next = message.slice(displaySubsystem.length, displaySubsystem.length + 1);
2597
+ if (next !== ":" && next !== " ") return message;
2598
+ let i = displaySubsystem.length;
2599
+ while (message[i] === " ") i += 1;
2600
+ if (message[i] === ":") i += 1;
2601
+ while (message[i] === " ") i += 1;
2602
+ return message.slice(i);
2603
+ }
2604
+ const CONSOLE_META_VALUE_MAX = 200;
2605
+ const CONSOLE_META_SUFFIX_MAX = 512;
2606
+ const CONSOLE_META_BARE_VALUE = /^[\w./:@+-]+$/;
2607
+ function formatConsoleMetaValue(value) {
2608
+ if (value instanceof Error) return JSON.stringify(`${value.name}: ${value.message}`);
2609
+ if (typeof value === "string") {
2610
+ const bounded = value.length > CONSOLE_META_VALUE_MAX ? value.slice(0, CONSOLE_META_VALUE_MAX + 1) : value;
2611
+ return CONSOLE_META_BARE_VALUE.test(bounded) ? bounded : JSON.stringify(bounded);
2612
+ }
2613
+ if (value === null || typeof value === "number" || typeof value === "boolean" || typeof value === "bigint") return `${value}`;
2614
+ if (typeof value === "function" || typeof value === "symbol") return;
2615
+ try {
2616
+ return JSON.stringify(value);
2617
+ } catch {
2618
+ return JSON.stringify("[unserializable]");
2619
+ }
2620
+ }
2621
+ function truncateConsoleMeta(text, max) {
2622
+ if (text.length <= max) return text;
2623
+ return `${text.slice(0, avoidTrailingHighSurrogateBreak(text, Math.max(0, max - 1)))}…`;
2624
+ }
2625
+ function formatConsoleMeta(meta) {
2626
+ if (!meta) return "";
2627
+ try {
2628
+ const parts = [];
2629
+ let budget = CONSOLE_META_SUFFIX_MAX;
2630
+ for (const [key, value] of Object.entries(meta)) {
2631
+ if (value === void 0) continue;
2632
+ const rendered = formatConsoleMetaValue(value);
2633
+ if (rendered === void 0) continue;
2634
+ const part = `${key}=${truncateConsoleMeta(rendered, CONSOLE_META_VALUE_MAX)}`;
2635
+ parts.push(part);
2636
+ budget -= part.length + 1;
2637
+ if (budget <= 0) break;
2638
+ }
2639
+ return truncateConsoleMeta(parts.join(" "), CONSOLE_META_SUFFIX_MAX);
2640
+ } catch {
2641
+ return "[meta unavailable]";
2642
+ }
2643
+ }
2644
+ function formatConsoleLine(opts) {
2645
+ const displaySubsystem = opts.style === "json" ? opts.subsystem : formatSubsystemForConsole(opts.subsystem);
2646
+ if (opts.style === "json") return JSON.stringify({
2647
+ ...opts.meta,
2648
+ time: (/* @__PURE__ */ new Date()).toISOString(),
2649
+ level: opts.level,
2650
+ subsystem: displaySubsystem,
2651
+ message: opts.message
2652
+ });
2653
+ const color = getColorForConsole();
2654
+ const prefix = `[${displaySubsystem}]`;
2655
+ const prefixColor = pickSubsystemColor(color, displaySubsystem);
2656
+ const levelColor = opts.level === "error" || opts.level === "fatal" ? color.red : opts.level === "warn" ? color.yellow : opts.level === "debug" || opts.level === "trace" ? color.gray : color.cyan;
2657
+ const displayMessage = stripRedundantSubsystemPrefixForConsole(opts.message, displaySubsystem);
2658
+ const head = [(() => {
2659
+ if (opts.style === "pretty") return color.gray((/* @__PURE__ */ new Date()).toISOString().slice(11, 19));
2660
+ if (loggingState.consoleTimestampPrefix) return color.gray((/* @__PURE__ */ new Date()).toISOString());
2661
+ return "";
2662
+ })(), prefixColor(prefix)].filter(Boolean).join(" ");
2663
+ const metaSuffix = formatConsoleMeta(opts.meta);
2664
+ return metaSuffix ? `${head} ${levelColor(displayMessage)} ${color.gray(metaSuffix)}` : `${head} ${levelColor(displayMessage)}`;
2665
+ }
2666
+ function writeConsoleLine(level, line) {
2667
+ clearActiveProgressLine();
2668
+ const sanitized = process.platform === "win32" && process.env.GITHUB_ACTIONS === "true" ? line.replace(/[\uD800-\uDBFF][\uDC00-\uDFFF]/g, "?").replace(/[\uD800-\uDFFF]/g, "?") : line;
2669
+ const sink = loggingState.rawConsole ?? console;
2670
+ if (loggingState.forceConsoleToStderr || loggingState.forceSubsystemConsoleToStderr || level === "error" || level === "fatal") (sink.error ?? console.error)(sanitized);
2671
+ else if (level === "warn") (sink.warn ?? console.warn)(sanitized);
2672
+ else (sink.log ?? console.log)(sanitized);
2673
+ }
2674
+ function logToFile(fileLogger, level, message, meta) {
2675
+ if (level === "silent") return;
2676
+ const method = fileLogger[level];
2677
+ if (typeof method !== "function") return;
2678
+ if (meta && Object.keys(meta).length > 0) method.call(fileLogger, meta, message);
2679
+ else method.call(fileLogger, message);
2680
+ }
2681
+ function createSubsystemLogger(subsystem) {
2682
+ let fileLogger = null;
2683
+ const getFileLogger = () => {
2684
+ if (!fileLogger) fileLogger = getChildLogger({ subsystem });
2685
+ return fileLogger;
2686
+ };
2687
+ const emit = (level, message, meta) => {
2688
+ const consoleSettings = getConsoleSettings();
2689
+ const consoleEnabled = shouldLogToConsole(level, { level: consoleSettings.level }) && shouldLogSubsystemToConsole(subsystem);
2690
+ const fileEnabled = isFileLogLevelEnabled(level);
2691
+ if (!consoleEnabled && !fileEnabled) return;
2692
+ let consoleMessageOverride;
2693
+ let fileMeta = meta;
2694
+ try {
2695
+ if (meta && Object.keys(meta).length > 0) {
2696
+ const { consoleMessage, ...rest } = meta;
2697
+ if (typeof consoleMessage === "string") consoleMessageOverride = consoleMessage;
2698
+ fileMeta = Object.keys(rest).length > 0 ? rest : void 0;
2699
+ }
2700
+ } catch {
2701
+ consoleMessageOverride = void 0;
2702
+ fileMeta = { meta: "[meta unavailable]" };
2703
+ }
2704
+ if (fileEnabled) logToFile(getFileLogger(), level, message, fileMeta);
2705
+ if (!consoleEnabled) return;
2706
+ const consoleMessage = consoleMessageOverride ?? message;
2707
+ if (!isVerbose() && subsystem === "agent/embedded" && /(sessionId|runId)=probe-/.test(consoleMessage)) return;
2708
+ let line;
2709
+ try {
2710
+ line = formatConsoleLine({
2711
+ level,
2712
+ subsystem,
2713
+ message: consoleSettings.style === "json" ? message : consoleMessage,
2714
+ style: consoleSettings.style,
2715
+ meta: fileMeta
2716
+ });
2717
+ } catch {
2718
+ try {
2719
+ line = formatConsoleLine({
2720
+ level,
2721
+ subsystem,
2722
+ message: consoleSettings.style === "json" ? message : consoleMessage,
2723
+ style: consoleSettings.style,
2724
+ meta: { meta: "[meta unavailable]" }
2725
+ });
2726
+ } catch {
2727
+ line = `[${subsystem}] ${consoleMessage}`;
2728
+ }
2729
+ }
2730
+ writeConsoleLine(level, line);
2731
+ };
2732
+ const isConsoleEnabled = (level) => {
2733
+ return shouldLogToConsole(level, { level: getConsoleSettings().level }) && shouldLogSubsystemToConsole(subsystem);
2734
+ };
2735
+ const isFileEnabled = (level) => isFileLogLevelEnabled(level);
2736
+ return {
2737
+ subsystem,
2738
+ isEnabled: (level, target = "any") => {
2739
+ if (target === "console") return isConsoleEnabled(level);
2740
+ if (target === "file") return isFileEnabled(level);
2741
+ return isConsoleEnabled(level) || isFileEnabled(level);
2742
+ },
2743
+ trace: (message, meta) => emit("trace", message, meta),
2744
+ debug: (message, meta) => emit("debug", message, meta),
2745
+ info: (message, meta) => emit("info", message, meta),
2746
+ warn: (message, meta) => emit("warn", message, meta),
2747
+ error: (message, meta) => emit("error", message, meta),
2748
+ fatal: (message, meta) => emit("fatal", message, meta),
2749
+ raw: (message) => {
2750
+ if (isFileEnabled("info")) logToFile(getFileLogger(), "info", message, { raw: true });
2751
+ if (isConsoleEnabled("info")) {
2752
+ if (!isVerbose() && subsystem === "agent/embedded" && /(sessionId|runId)=probe-/.test(message)) return;
2753
+ writeConsoleLine("info", message);
2754
+ }
2755
+ },
2756
+ child: (name) => createSubsystemLogger(`${subsystem}/${name}`)
2757
+ };
2758
+ }
2759
+
2760
+ //#endregion
2761
+ export { clampNumber as $, resolveConfigIncludes as A, hasNodeErrorCode as B, appendFileLog as C, ConfigIncludeError as D, normalizeConfigPaths as E, openBoundaryFileSync as F, applyConfigEnvVars as G, isPathInside$1 as H, sameFileIdentity$1 as I, MissingEnvVarError as J, isDangerousHostEnvVarName as K, BOUNDARY_PATH_ALIAS_POLICIES as L, isPathInside as M, isPathInsideWithRealpath as N, INCLUDE_KEY as O, openBoundaryFile as P, clampInt as Q, resolveBoundaryPath as R, resolveNodeRequireFromMeta as S, normalizeLogLevel as T, isSymlinkOpenError as U, isNotFoundPathError as V, normalizeWindowsPathForComparison as W, resolveConfigEnvVars as X, containsEnvVarReference as Y, CONFIG_DIR as Z, colorize as _, createNonExitingRuntime as a, pathExists$1 as at, getChildLogger as b, registerActiveProgressLine as c, safeParseJson as ct, info as d, sleep as dt, ensureDir as et, logVerbose as f, sliceUtf16Safe as ft, warn as g, shouldLogVerbose as h, chunkTextByBreakResolver as i, normalizeE164 as it, isBlockedObjectKey as j, readConfigIncludeFileWithGuards as k, unregisterActiveProgressLine as l, shortenHomeInString as lt, setVerbose as m, resolvePreferredOpenClawTmpDir as mt, stripAnsi as n, formatTerminalLink as nt, defaultRuntime as o, resolveConfigDir as ot, logVerboseConsole as p, truncateUtf16Safe as pt, sanitizeHostExecEnv as q, avoidTrailingHighSurrogateBreak as r, isRecord as rt, clearActiveProgressLine as s, resolveUserPath as st, createSubsystemLogger as t, escapeRegExp as tt, danger as u, shortenHomePath as ut, isRich as v, createFileLogWriter as w, getLogger as x, theme as y, resolvePathViaExistingAncestorSync as z };