@chrysb/alphaclaw 0.4.6-beta.3 → 0.4.6-beta.5

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 (39) hide show
  1. package/lib/public/js/app.js +158 -1073
  2. package/lib/public/js/components/doctor/index.js +1 -2
  3. package/lib/public/js/components/general/index.js +155 -0
  4. package/lib/public/js/components/general/use-general-tab.js +233 -0
  5. package/lib/public/js/components/models-tab/index.js +286 -0
  6. package/lib/public/js/components/models-tab/provider-auth-card.js +369 -0
  7. package/lib/public/js/components/models-tab/use-models.js +262 -0
  8. package/lib/public/js/components/routes/browse-route.js +35 -0
  9. package/lib/public/js/components/routes/doctor-route.js +21 -0
  10. package/lib/public/js/components/routes/envars-route.js +11 -0
  11. package/lib/public/js/components/routes/general-route.js +45 -0
  12. package/lib/public/js/components/routes/index.js +11 -0
  13. package/lib/public/js/components/routes/models-route.js +11 -0
  14. package/lib/public/js/components/routes/providers-route.js +11 -0
  15. package/lib/public/js/components/routes/route-redirect.js +10 -0
  16. package/lib/public/js/components/routes/telegram-route.js +11 -0
  17. package/lib/public/js/components/routes/usage-route.js +15 -0
  18. package/lib/public/js/components/routes/watchdog-route.js +32 -0
  19. package/lib/public/js/components/routes/webhooks-route.js +43 -0
  20. package/lib/public/js/components/sidebar.js +2 -3
  21. package/lib/public/js/components/usage-tab/constants.js +1 -1
  22. package/lib/public/js/components/usage-tab/overview-section.js +124 -50
  23. package/lib/public/js/components/usage-tab/use-usage-tab.js +42 -11
  24. package/lib/public/js/hooks/use-app-shell-controller.js +230 -0
  25. package/lib/public/js/hooks/use-app-shell-ui.js +112 -0
  26. package/lib/public/js/hooks/use-browse-navigation.js +193 -0
  27. package/lib/public/js/hooks/use-hash-location.js +32 -0
  28. package/lib/public/js/lib/api.js +35 -0
  29. package/lib/public/js/lib/app-navigation.js +39 -0
  30. package/lib/public/js/lib/browse-restart-policy.js +28 -0
  31. package/lib/public/js/lib/browse-route.js +57 -0
  32. package/lib/public/js/lib/format.js +12 -0
  33. package/lib/server/auth-profiles.js +223 -52
  34. package/lib/server/doctor/prompt.js +4 -1
  35. package/lib/server/gateway.js +29 -9
  36. package/lib/server/routes/models.js +170 -2
  37. package/lib/server/watchdog.js +14 -1
  38. package/lib/server.js +1 -0
  39. package/package.json +1 -1
@@ -0,0 +1,57 @@
1
+ export const normalizeBrowsePath = (value) => String(value || "").replace(/^\/+|\/+$/g, "");
2
+
3
+ export const buildBrowseRoute = (relativePath, options = {}) => {
4
+ const view = String(options?.view || "edit");
5
+ const encodedPath = String(relativePath || "")
6
+ .split("/")
7
+ .filter(Boolean)
8
+ .map((segment) => encodeURIComponent(segment))
9
+ .join("/");
10
+ const baseRoute = encodedPath ? `/browse/${encodedPath}` : "/browse";
11
+ const params = new URLSearchParams();
12
+ if (view === "diff" && encodedPath) params.set("view", "diff");
13
+ if (options.line) params.set("line", String(options.line));
14
+ if (options.lineEnd) params.set("lineEnd", String(options.lineEnd));
15
+ const query = params.toString();
16
+ return query ? `${baseRoute}?${query}` : baseRoute;
17
+ };
18
+
19
+ export const parseBrowseRoute = ({ location = "", browsePreviewPath = "" } = {}) => {
20
+ const isBrowseRoute = location.startsWith("/browse");
21
+ const browseRoutePath = isBrowseRoute ? String(location || "").split("?")[0] : "";
22
+ const browseRouteQuery =
23
+ isBrowseRoute && String(location || "").includes("?")
24
+ ? String(location || "").split("?").slice(1).join("?")
25
+ : "";
26
+ const selectedBrowsePath = isBrowseRoute
27
+ ? browseRoutePath
28
+ .replace(/^\/browse\/?/, "")
29
+ .split("/")
30
+ .filter(Boolean)
31
+ .map((segment) => {
32
+ try {
33
+ return decodeURIComponent(segment);
34
+ } catch {
35
+ return segment;
36
+ }
37
+ })
38
+ .join("/")
39
+ : "";
40
+ const activeBrowsePath = browsePreviewPath || selectedBrowsePath;
41
+ const browseQueryParams = isBrowseRoute ? new URLSearchParams(browseRouteQuery) : null;
42
+ const browseViewerMode =
43
+ !browsePreviewPath && browseQueryParams?.get("view") === "diff"
44
+ ? "diff"
45
+ : "edit";
46
+ const browseLineTarget = Number.parseInt(browseQueryParams?.get("line") || "", 10) || 0;
47
+ const browseLineEndTarget = Number.parseInt(browseQueryParams?.get("lineEnd") || "", 10) || 0;
48
+
49
+ return {
50
+ activeBrowsePath,
51
+ browseLineEndTarget,
52
+ browseLineTarget,
53
+ browseViewerMode,
54
+ isBrowseRoute,
55
+ selectedBrowsePath,
56
+ };
57
+ };
@@ -1,4 +1,9 @@
1
1
  const kIntegerFormatter = new Intl.NumberFormat("en-US");
2
+ const kCompactNumberFormatter = new Intl.NumberFormat("en-US", {
3
+ notation: "compact",
4
+ minimumFractionDigits: 1,
5
+ maximumFractionDigits: 1,
6
+ });
2
7
  const kUsdFormatter = new Intl.NumberFormat("en-US", {
3
8
  style: "currency",
4
9
  currency: "USD",
@@ -25,6 +30,13 @@ const isSameDay = (left, right) =>
25
30
  export const formatInteger = (value) =>
26
31
  kIntegerFormatter.format(Number(value || 0));
27
32
 
33
+ export const formatCompactNumber = (value) => {
34
+ const numberValue = Number(value || 0);
35
+ if (!Number.isFinite(numberValue)) return "0";
36
+ if (Math.abs(numberValue) < 1000) return formatInteger(numberValue);
37
+ return kCompactNumberFormatter.format(numberValue);
38
+ };
39
+
28
40
  export const formatUsd = (value) => kUsdFormatter.format(Number(value || 0));
29
41
 
30
42
  export const formatLocaleDateTime = (
@@ -1,62 +1,216 @@
1
1
  const fs = require("fs");
2
2
  const path = require("path");
3
- const { AUTH_PROFILES_PATH, CODEX_PROFILE_ID } = require("./constants");
3
+ const { AUTH_PROFILES_PATH, CODEX_PROFILE_ID, OPENCLAW_DIR } = require("./constants");
4
4
 
5
- const createAuthProfiles = () => {
6
- const ensureAuthProfilesStore = () => {
7
- let store = { version: 1, profiles: {} };
8
- try {
9
- if (fs.existsSync(AUTH_PROFILES_PATH)) {
10
- const parsed = JSON.parse(fs.readFileSync(AUTH_PROFILES_PATH, "utf8"));
11
- if (
12
- parsed &&
13
- typeof parsed === "object" &&
14
- parsed.profiles &&
15
- typeof parsed.profiles === "object"
16
- ) {
17
- store = {
18
- version: Number(parsed.version || 1),
19
- profiles: parsed.profiles,
20
- order: parsed.order,
21
- lastGood: parsed.lastGood,
22
- usageStats: parsed.usageStats,
23
- };
24
- }
5
+ const kDefaultAgentId = "main";
6
+
7
+ const normalizeSecret = (raw) =>
8
+ String(raw ?? "")
9
+ .replace(/[\r\n\u2028\u2029]/g, "")
10
+ .trim();
11
+
12
+ const credentialMode = (credential) => {
13
+ if (credential.type === "api_key") return "api_key";
14
+ if (credential.type === "token") return "token";
15
+ return "oauth";
16
+ };
17
+
18
+ const resolveAgentDir = (agentId = kDefaultAgentId) =>
19
+ path.join(OPENCLAW_DIR, "agents", agentId, "agent");
20
+
21
+ const resolveAuthProfilesPath = (agentId = kDefaultAgentId) =>
22
+ path.join(resolveAgentDir(agentId), "auth-profiles.json");
23
+
24
+ const resolveOpenclawConfigPath = () =>
25
+ path.join(OPENCLAW_DIR, "openclaw.json");
26
+
27
+ const loadAuthStore = (agentId = kDefaultAgentId) => {
28
+ const storePath = resolveAuthProfilesPath(agentId);
29
+ let store = { version: 1, profiles: {} };
30
+ try {
31
+ if (fs.existsSync(storePath)) {
32
+ const parsed = JSON.parse(fs.readFileSync(storePath, "utf8"));
33
+ if (
34
+ parsed &&
35
+ typeof parsed === "object" &&
36
+ parsed.profiles &&
37
+ typeof parsed.profiles === "object"
38
+ ) {
39
+ store = {
40
+ version: Number(parsed.version || 1),
41
+ profiles: parsed.profiles,
42
+ order: parsed.order,
43
+ lastGood: parsed.lastGood,
44
+ usageStats: parsed.usageStats,
45
+ };
25
46
  }
26
- } catch {}
27
- return store;
47
+ }
48
+ } catch {}
49
+ return store;
50
+ };
51
+
52
+ const saveAuthStore = (agentId, store) => {
53
+ const storePath = resolveAuthProfilesPath(agentId);
54
+ fs.mkdirSync(path.dirname(storePath), { recursive: true });
55
+ fs.writeFileSync(
56
+ storePath,
57
+ JSON.stringify(
58
+ {
59
+ version: Number(store.version || 1),
60
+ profiles: store.profiles || {},
61
+ ...(store.order !== undefined ? { order: store.order } : {}),
62
+ ...(store.lastGood !== undefined ? { lastGood: store.lastGood } : {}),
63
+ ...(store.usageStats !== undefined
64
+ ? { usageStats: store.usageStats }
65
+ : {}),
66
+ },
67
+ null,
68
+ 2,
69
+ ),
70
+ );
71
+ };
72
+
73
+ const loadOpenclawConfig = () => {
74
+ const configPath = resolveOpenclawConfigPath();
75
+ try {
76
+ return JSON.parse(fs.readFileSync(configPath, "utf8"));
77
+ } catch {
78
+ return {};
79
+ }
80
+ };
81
+
82
+ const saveOpenclawConfig = (cfg) => {
83
+ const configPath = resolveOpenclawConfigPath();
84
+ fs.writeFileSync(configPath, JSON.stringify(cfg, null, 2));
85
+ };
86
+
87
+ const syncConfigAuthReference = (cfg, profileId, credential) => {
88
+ const next = { ...cfg };
89
+ if (!next.auth) next.auth = {};
90
+ if (!next.auth.profiles) next.auth.profiles = {};
91
+ next.auth = { ...next.auth, profiles: { ...next.auth.profiles } };
92
+ next.auth.profiles[profileId] = {
93
+ provider: credential.provider,
94
+ mode: credentialMode(credential),
28
95
  };
96
+ return next;
97
+ };
29
98
 
30
- const saveAuthProfilesStore = (store) => {
31
- fs.mkdirSync(path.dirname(AUTH_PROFILES_PATH), { recursive: true });
32
- fs.writeFileSync(
33
- AUTH_PROFILES_PATH,
34
- JSON.stringify(
35
- {
36
- version: Number(store.version || 1),
37
- profiles: store.profiles || {},
38
- order: store.order,
39
- lastGood: store.lastGood,
40
- usageStats: store.usageStats,
41
- },
42
- null,
43
- 2,
44
- ),
45
- );
99
+ const removeConfigAuthReference = (cfg, profileId) => {
100
+ if (!cfg.auth?.profiles?.[profileId]) return cfg;
101
+ const next = { ...cfg };
102
+ next.auth = { ...next.auth, profiles: { ...next.auth.profiles } };
103
+ delete next.auth.profiles[profileId];
104
+ if (Object.keys(next.auth.profiles).length === 0) {
105
+ delete next.auth.profiles;
106
+ }
107
+ if (Object.keys(next.auth).length === 0) {
108
+ delete next.auth;
109
+ }
110
+ return next;
111
+ };
112
+
113
+ const createAuthProfiles = () => {
114
+ // ── Generic profile operations ──
115
+
116
+ const listProfiles = (agentId = kDefaultAgentId) => {
117
+ const store = loadAuthStore(agentId);
118
+ return Object.entries(store.profiles || {}).map(([id, cred]) => ({
119
+ id,
120
+ ...cred,
121
+ }));
46
122
  };
47
123
 
48
- const listCodexProfiles = () => {
49
- const store = ensureAuthProfilesStore();
50
- return Object.entries(store.profiles || {})
51
- .filter(([, cred]) => cred?.provider === "openai-codex")
52
- .map(([id, cred]) => ({ id, cred }));
124
+ const listProfilesByProvider = (provider, agentId = kDefaultAgentId) =>
125
+ listProfiles(agentId).filter((p) => p.provider === provider);
126
+
127
+ const getProfile = (profileId, agentId = kDefaultAgentId) => {
128
+ const store = loadAuthStore(agentId);
129
+ const cred = store.profiles?.[profileId];
130
+ if (!cred) return null;
131
+ return { id: profileId, ...cred };
53
132
  };
54
133
 
134
+ const upsertProfile = (profileId, credential, agentId = kDefaultAgentId) => {
135
+ const store = loadAuthStore(agentId);
136
+ const sanitized = { ...credential };
137
+ if (sanitized.key) sanitized.key = normalizeSecret(sanitized.key);
138
+ if (sanitized.token) sanitized.token = normalizeSecret(sanitized.token);
139
+ if (sanitized.access) sanitized.access = normalizeSecret(sanitized.access);
140
+ if (sanitized.refresh)
141
+ sanitized.refresh = normalizeSecret(sanitized.refresh);
142
+ store.profiles[profileId] = sanitized;
143
+ saveAuthStore(agentId, store);
144
+
145
+ const cfg = loadOpenclawConfig();
146
+ const updated = syncConfigAuthReference(cfg, profileId, sanitized);
147
+ saveOpenclawConfig(updated);
148
+ };
149
+
150
+ const removeProfile = (profileId, agentId = kDefaultAgentId) => {
151
+ const store = loadAuthStore(agentId);
152
+ if (!store.profiles[profileId]) return false;
153
+ delete store.profiles[profileId];
154
+ saveAuthStore(agentId, store);
155
+
156
+ const cfg = loadOpenclawConfig();
157
+ const updated = removeConfigAuthReference(cfg, profileId);
158
+ saveOpenclawConfig(updated);
159
+ return true;
160
+ };
161
+
162
+ const setAuthOrder = (provider, orderedProfileIds, agentId = kDefaultAgentId) => {
163
+ const store = loadAuthStore(agentId);
164
+ if (!store.order) store.order = {};
165
+ store.order[provider] = orderedProfileIds;
166
+ saveAuthStore(agentId, store);
167
+ };
168
+
169
+ const syncConfigAuthReferencesForAgent = (agentId = kDefaultAgentId) => {
170
+ const store = loadAuthStore(agentId);
171
+ let cfg = loadOpenclawConfig();
172
+ for (const [profileId, credential] of Object.entries(store.profiles || {})) {
173
+ if (!credential?.type || !credential?.provider) continue;
174
+ cfg = syncConfigAuthReference(cfg, profileId, credential);
175
+ }
176
+ saveOpenclawConfig(cfg);
177
+ };
178
+
179
+ // ── Model config operations ──
180
+
181
+ const getModelConfig = () => {
182
+ const cfg = loadOpenclawConfig();
183
+ const defaults = cfg.agents?.defaults || {};
184
+ return {
185
+ primary: defaults.model?.primary || null,
186
+ configuredModels: defaults.models || {},
187
+ };
188
+ };
189
+
190
+ const setModelConfig = ({ primary, configuredModels }) => {
191
+ const cfg = loadOpenclawConfig();
192
+ if (!cfg.agents) cfg.agents = {};
193
+ if (!cfg.agents.defaults) cfg.agents.defaults = {};
194
+ if (!cfg.agents.defaults.model) cfg.agents.defaults.model = {};
195
+ if (primary !== undefined) {
196
+ cfg.agents.defaults.model.primary = primary;
197
+ }
198
+ if (configuredModels !== undefined) {
199
+ cfg.agents.defaults.models = configuredModels;
200
+ }
201
+ saveOpenclawConfig(cfg);
202
+ };
203
+
204
+ // ── Legacy Codex-specific wrappers ──
205
+
206
+ const listCodexProfiles = () => listProfilesByProvider("openai-codex");
207
+
55
208
  const getCodexProfile = () => {
56
209
  const profiles = listCodexProfiles();
57
210
  if (profiles.length === 0) return null;
58
- const preferred = profiles.find((p) => p.id === CODEX_PROFILE_ID) || profiles[0];
59
- return { profileId: preferred.id, ...preferred.cred };
211
+ const preferred =
212
+ profiles.find((p) => p.id === CODEX_PROFILE_ID) || profiles[0];
213
+ return { profileId: preferred.id, ...preferred };
60
214
  };
61
215
 
62
216
  const hasCodexOauthProfile = () => {
@@ -65,20 +219,18 @@ const createAuthProfiles = () => {
65
219
  };
66
220
 
67
221
  const upsertCodexProfile = ({ access, refresh, expires, accountId }) => {
68
- const store = ensureAuthProfilesStore();
69
- store.profiles[CODEX_PROFILE_ID] = {
222
+ upsertProfile(CODEX_PROFILE_ID, {
70
223
  type: "oauth",
71
224
  provider: "openai-codex",
72
225
  access,
73
226
  refresh,
74
227
  expires,
75
228
  ...(accountId ? { accountId } : {}),
76
- };
77
- saveAuthProfilesStore(store);
229
+ });
78
230
  };
79
231
 
80
232
  const removeCodexProfiles = () => {
81
- const store = ensureAuthProfilesStore();
233
+ const store = loadAuthStore();
82
234
  let changed = false;
83
235
  for (const [id, cred] of Object.entries(store.profiles || {})) {
84
236
  if (cred?.provider === "openai-codex") {
@@ -86,15 +238,34 @@ const createAuthProfiles = () => {
86
238
  changed = true;
87
239
  }
88
240
  }
89
- if (changed) saveAuthProfilesStore(store);
241
+ if (changed) {
242
+ saveAuthStore(kDefaultAgentId, store);
243
+ let cfg = loadOpenclawConfig();
244
+ for (const [id, cred] of Object.entries(cfg.auth?.profiles || {})) {
245
+ if (cred?.provider === "openai-codex") {
246
+ cfg = removeConfigAuthReference(cfg, id);
247
+ }
248
+ }
249
+ saveOpenclawConfig(cfg);
250
+ }
90
251
  return changed;
91
252
  };
92
253
 
93
254
  return {
255
+ listProfiles,
256
+ listProfilesByProvider,
257
+ getProfile,
258
+ upsertProfile,
259
+ removeProfile,
260
+ setAuthOrder,
261
+ syncConfigAuthReferencesForAgent,
262
+ getModelConfig,
263
+ setModelConfig,
94
264
  getCodexProfile,
95
265
  hasCodexOauthProfile,
96
266
  upsertCodexProfile,
97
267
  removeCodexProfiles,
268
+ loadAuthStore,
98
269
  };
99
270
  };
100
271
 
@@ -37,7 +37,9 @@ Important:
37
37
  - Return ONLY valid JSON. No markdown fences. No extra prose.
38
38
 
39
39
  OpenClaw context injection:
40
- - OpenClaw automatically injects ALL root-level \`.md\` files (e.g. AGENTS.md, SOUL.md, TOOLS.md, IDENTITY.md, USER.md, HEARTBEAT.md) into the agent's context window as "project context" on every turn.
40
+ - OpenClaw automatically injects a fixed set of named workspace files into the agent's context window ("Project Context") on every turn. The exact set is: \`AGENTS.md\`, \`SOUL.md\`, \`TOOLS.md\`, \`IDENTITY.md\`, \`USER.md\`, \`HEARTBEAT.md\`, and \`BOOTSTRAP.md\` (first-run only).
41
+ - Only these specific files are auto-injected. Other \`.md\` files at the workspace root (e.g. INTERESTS.md, MEMORY.md, README.md) are NOT injected and must be explicitly read by the agent.
42
+ - Do not flag auto-injected files as orphaned or unreferenced — they are loaded by the runtime, not by explicit file references in AGENTS.md.
41
43
  - Additionally, AlphaClaw injects bootstrap files from \`hooks/bootstrap/\` (e.g. AGENTS.md, TOOLS.md) as extra context on every turn.
42
44
 
43
45
  OpenClaw default context:
@@ -106,6 +108,7 @@ ${renderResolvedCards(resolvedCards)}Constraints:
106
108
  - Do not re-suggest findings that appear in the "Previously resolved" list above
107
109
  - Do not create cards for healthy default-template behavior
108
110
  - Do not create cards whose primary recommendation is to refactor AlphaClaw-managed file structure
111
+ - fixPrompt must only reference files the agent can edit. Never suggest editing files listed in "AlphaClaw locked/managed paths" above — they are managed by AlphaClaw, so manual edits would be lost.
109
112
  - If there are no meaningful findings, return an empty cards array
110
113
  - promptVersion: ${promptVersion}
111
114
  `.trim();
@@ -1,7 +1,13 @@
1
1
  const { spawn, execSync } = require("child_process");
2
2
  const fs = require("fs");
3
3
  const net = require("net");
4
- const { OPENCLAW_DIR, GATEWAY_HOST, GATEWAY_PORT, kChannelDefs, kRootDir } = require("./constants");
4
+ const {
5
+ OPENCLAW_DIR,
6
+ GATEWAY_HOST,
7
+ GATEWAY_PORT,
8
+ kChannelDefs,
9
+ kRootDir,
10
+ } = require("./constants");
5
11
 
6
12
  let gatewayChild = null;
7
13
  let gatewayExitHandler = null;
@@ -11,7 +17,9 @@ let gatewayStderrTail = [];
11
17
  const expectedExitPids = new Set();
12
18
 
13
19
  const appendStderrTail = (chunk) => {
14
- const text = Buffer.isBuffer(chunk) ? chunk.toString("utf8") : String(chunk ?? "");
20
+ const text = Buffer.isBuffer(chunk)
21
+ ? chunk.toString("utf8")
22
+ : String(chunk ?? "");
15
23
  for (const line of text.split("\n")) {
16
24
  const trimmed = line.trimEnd();
17
25
  if (!trimmed) continue;
@@ -76,7 +84,9 @@ const runGatewayCmd = (cmd) => {
76
84
 
77
85
  const launchGatewayProcess = () => {
78
86
  if (gatewayChild && gatewayChild.exitCode === null && !gatewayChild.killed) {
79
- console.log("[alphaclaw] Managed gateway process already running — skipping launch");
87
+ console.log(
88
+ "[alphaclaw] Managed gateway process already running — skipping launch",
89
+ );
80
90
  return gatewayChild;
81
91
  }
82
92
  gatewayStderrTail = [];
@@ -145,20 +155,24 @@ const restartGateway = (reloadEnv) => {
145
155
  gatewayChild.kill("SIGTERM");
146
156
  gatewayChild = null;
147
157
  } catch (e) {
148
- console.log(`[alphaclaw] Failed to stop managed gateway process: ${e.message}`);
158
+ console.log(
159
+ `[alphaclaw] Failed to stop managed gateway process: ${e.message}`,
160
+ );
149
161
  runGatewayCmd("stop");
150
162
  }
151
163
  } else {
152
164
  runGatewayCmd("stop");
153
165
  }
154
- runGatewayCmd("install --force");
166
+ runGatewayCmd("start");
155
167
  const launchWhenReady = async () => {
156
168
  const waitUntil = Date.now() + 8000;
157
169
  while (Date.now() < waitUntil) {
158
170
  if (!(await isGatewayRunning())) break;
159
171
  await new Promise((resolve) => setTimeout(resolve, 250));
160
172
  }
161
- console.log("[alphaclaw] Starting openclaw gateway with refreshed environment...");
173
+ console.log(
174
+ "[alphaclaw] Starting openclaw gateway with refreshed environment...",
175
+ );
162
176
  launchGatewayProcess();
163
177
  };
164
178
  void launchWhenReady();
@@ -275,7 +289,9 @@ const syncChannelConfig = (savedVars, mode = "all") => {
275
289
 
276
290
  const getChannelStatus = () => {
277
291
  try {
278
- const config = JSON.parse(fs.readFileSync(`${OPENCLAW_DIR}/openclaw.json`, "utf8"));
292
+ const config = JSON.parse(
293
+ fs.readFileSync(`${OPENCLAW_DIR}/openclaw.json`, "utf8"),
294
+ );
279
295
  const credDir = `${OPENCLAW_DIR}/credentials`;
280
296
  const channels = {};
281
297
 
@@ -287,9 +303,13 @@ const getChannelStatus = () => {
287
303
  try {
288
304
  const files = fs
289
305
  .readdirSync(credDir)
290
- .filter((f) => f.startsWith(`${ch}-`) && f.endsWith("-allowFrom.json"));
306
+ .filter(
307
+ (f) => f.startsWith(`${ch}-`) && f.endsWith("-allowFrom.json"),
308
+ );
291
309
  for (const file of files) {
292
- const data = JSON.parse(fs.readFileSync(`${credDir}/${file}`, "utf8"));
310
+ const data = JSON.parse(
311
+ fs.readFileSync(`${credDir}/${file}`, "utf8"),
312
+ );
293
313
  paired += (data.allowFrom || []).length;
294
314
  }
295
315
  } catch {}