@clawchatsai/connector 0.0.86 → 0.0.87

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.
package/server.js CHANGED
@@ -3,73 +3,45 @@
3
3
  var __defProp = Object.defineProperty;
4
4
  var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
5
5
 
6
- // ../server/index.js
6
+ // server/index.js
7
7
  import http from "node:http";
8
8
  import fs13 from "node:fs";
9
- import path15 from "node:path";
9
+ import path14 from "node:path";
10
10
  import os5 from "node:os";
11
- import { fileURLToPath as fileURLToPath3 } from "node:url";
11
+ import { fileURLToPath as fileURLToPath2 } from "node:url";
12
12
  import { WebSocket as WS2, WebSocketServer } from "ws";
13
13
 
14
- // ../server/bootstrap/native.js
15
- import { execSync } from "node:child_process";
16
- import { createRequire } from "node:module";
14
+ // server/bootstrap/native.js
15
+ import { DatabaseSync as Database } from "node:sqlite";
17
16
  import { AsyncLocalStorage } from "node:async_hooks";
18
- import { fileURLToPath } from "node:url";
19
- import path from "node:path";
20
- var __dirname = path.dirname(fileURLToPath(import.meta.url));
21
- var _require = createRequire(import.meta.url);
22
17
  var requestDbStore = new AsyncLocalStorage();
23
- function loadDatabase() {
24
- const isAbiMismatch = /* @__PURE__ */ __name((e) => e.message && (e.message.includes("did not self-register") || e.message.includes("NODE_MODULE_VERSION") || e.message.includes("was compiled against a different Node.js version")), "isAbiMismatch");
25
- try {
26
- return _require("better-sqlite3");
27
- } catch (e) {
28
- if (!isAbiMismatch(e)) throw e;
29
- console.error("[ClawChats] better-sqlite3 binary is incompatible with your Node.js version. Attempting auto-rebuild...");
30
- try {
31
- execSync("npm rebuild better-sqlite3", { cwd: __dirname, stdio: "inherit" });
32
- const db = _require("better-sqlite3");
33
- console.log("[ClawChats] Auto-rebuild succeeded \u2014 continuing startup.");
34
- return db;
35
- } catch (rebuildErr) {
36
- console.error("[ClawChats] Auto-rebuild failed. Build tools may be missing.");
37
- console.error(`[ClawChats] cd ${__dirname} && npm rebuild better-sqlite3`);
38
- console.error("[ClawChats] Linux: sudo apt install build-essential python3");
39
- console.error("[ClawChats] macOS: xcode-select --install");
40
- process.exit(1);
41
- }
42
- }
43
- }
44
- __name(loadDatabase, "loadDatabase");
45
- var Database = loadDatabase();
46
18
 
47
- // ../server/config.js
19
+ // server/config.js
48
20
  import fs from "node:fs";
49
- import path2 from "node:path";
21
+ import path from "node:path";
50
22
  import os from "node:os";
51
- import { execSync as execSync2 } from "node:child_process";
52
- import { fileURLToPath as fileURLToPath2 } from "node:url";
23
+ import { fileURLToPath } from "node:url";
53
24
  var HOME = os.homedir();
54
25
  var MAX_PREAMBLE_CHARS = 5e4;
55
- var __filename = fileURLToPath2(import.meta.url);
56
- var __dirname2 = path2.dirname(__filename);
26
+ var __filename = fileURLToPath(import.meta.url);
27
+ var __dirname = path.dirname(__filename);
57
28
  function parseConfigField(field) {
58
- try {
59
- const configText = fs.readFileSync(path2.join(__dirname2, "config.js"), "utf8");
60
- const match = configText.match(new RegExp(`${field}:\\s*['"]([^'"]+)['"]`));
61
- return match ? match[1] : null;
62
- } catch {
63
- return null;
29
+ const candidates = [path.join(__dirname, "config.js"), path.join(__dirname, "..", "config.js")];
30
+ for (const configPath of candidates) {
31
+ try {
32
+ const configText = fs.readFileSync(configPath, "utf8");
33
+ const match = configText.match(new RegExp(`${field}:\\s*['"]([^'"]+)['"]`));
34
+ if (match) return match[1];
35
+ } catch {
36
+ }
64
37
  }
38
+ return null;
65
39
  }
66
40
  __name(parseConfigField, "parseConfigField");
67
- var _authToken = process.env.CLAWCHATS_AUTH_TOKEN || process.env.SHELLCHAT_AUTH_TOKEN || parseConfigField("authToken") || "";
68
- if (!_authToken) console.error("WARNING: No auth token configured. Set CLAWCHATS_AUTH_TOKEN or create config.js");
69
- var AUTH_TOKEN = _authToken;
41
+ var AUTH_TOKEN = process.env.CLAWCHATS_AUTH_TOKEN || parseConfigField("authToken") || "";
70
42
  function discoverGatewayWsUrl() {
71
43
  if (process.env.GATEWAY_WS_URL) return process.env.GATEWAY_WS_URL;
72
- for (const cfgPath of [path2.join(HOME, ".openclaw", "openclaw.json"), "/etc/openclaw/openclaw.json"]) {
44
+ for (const cfgPath of [path.join(HOME, ".openclaw", "openclaw.json"), "/etc/openclaw/openclaw.json"]) {
73
45
  try {
74
46
  const raw = JSON.parse(fs.readFileSync(cfgPath, "utf8"));
75
47
  const port = raw.gateway?.port || raw.port;
@@ -82,58 +54,30 @@ function discoverGatewayWsUrl() {
82
54
  }
83
55
  __name(discoverGatewayWsUrl, "discoverGatewayWsUrl");
84
56
  var GATEWAY_WS_URL = discoverGatewayWsUrl();
85
- function discoverViaCliSync() {
86
- try {
87
- const out = execSync2("openclaw status --json", { encoding: "utf8", timeout: 5e3 });
88
- const status = JSON.parse(out);
89
- if (status.sessions?.paths?.[0]) return path2.dirname(status.sessions.paths[0]);
90
- } catch {
91
- }
92
- return null;
93
- }
94
- __name(discoverViaCliSync, "discoverViaCliSync");
95
- var OPENCLAW_SESSIONS_DIR = (() => {
96
- if (process.env.OPENCLAW_SESSIONS_DIR) {
97
- console.log(`Sessions dir: ${process.env.OPENCLAW_SESSIONS_DIR} (env)`);
98
- return process.env.OPENCLAW_SESSIONS_DIR;
99
- }
100
- const cfgDir = parseConfigField("sessionsDir");
101
- if (cfgDir) {
102
- console.log(`Sessions dir: ${cfgDir} (config)`);
103
- return cfgDir;
104
- }
105
- const cliDir = discoverViaCliSync();
106
- if (cliDir) {
107
- console.log(`Sessions dir: ${cliDir} (cli)`);
108
- return cliDir;
109
- }
110
- const fallback = path2.join(HOME, ".openclaw", "agents", "main", "sessions");
111
- console.log(`Sessions dir: ${fallback} (fallback)`);
112
- return fallback;
113
- })();
57
+ var OPENCLAW_SESSIONS_DIR = process.env.OPENCLAW_SESSIONS_DIR || parseConfigField("sessionsDir") || path.join(HOME, ".openclaw", "agents", "main", "sessions");
114
58
  function getSessionsDirForAgent(agentId) {
115
59
  if (!agentId || agentId === "main") return OPENCLAW_SESSIONS_DIR;
116
- return path2.join(HOME, ".openclaw", "agents", agentId, "sessions");
60
+ return path.join(HOME, ".openclaw", "agents", agentId, "sessions");
117
61
  }
118
62
  __name(getSessionsDirForAgent, "getSessionsDirForAgent");
119
63
  function validateAgent(agentId) {
120
64
  if (!agentId) return "main";
121
65
  if (!/^[a-zA-Z0-9_-]+$/.test(agentId)) throw new Error("Invalid agent ID");
122
- const agentDir = path2.join(HOME, ".openclaw", "agents", agentId);
66
+ const agentDir = path.join(HOME, ".openclaw", "agents", agentId);
123
67
  if (!fs.existsSync(agentDir)) throw new Error(`Agent not found: ${agentId}`);
124
68
  return agentId;
125
69
  }
126
70
  __name(validateAgent, "validateAgent");
127
71
 
128
- // ../server/debug.js
72
+ // server/debug.js
129
73
  import fs2 from "node:fs";
130
- import path3 from "node:path";
74
+ import path2 from "node:path";
131
75
  var DebugLogger = class {
132
76
  static {
133
77
  __name(this, "DebugLogger");
134
78
  }
135
79
  constructor(baseDir) {
136
- this.baseDir = path3.join(baseDir, "..", "debug");
80
+ this.baseDir = path2.join(baseDir, "..", "debug");
137
81
  this.active = false;
138
82
  this.sessionId = null;
139
83
  this.wsStream = null;
@@ -144,7 +88,7 @@ var DebugLogger = class {
144
88
  this.sessionId = ts.replace(/[:.]/g, "-");
145
89
  this.originatingClient = originatingClient;
146
90
  fs2.mkdirSync(this.baseDir, { recursive: true });
147
- this.wsStream = fs2.createWriteStream(path3.join(this.baseDir, `session-${this.sessionId}-ws.log`), { flags: "a" });
91
+ this.wsStream = fs2.createWriteStream(path2.join(this.baseDir, `session-${this.sessionId}-ws.log`), { flags: "a" });
148
92
  this.active = true;
149
93
  console.log(`Debug recording started: ${this.sessionId}`);
150
94
  return { sessionId: this.sessionId };
@@ -171,15 +115,15 @@ var DebugLogger = class {
171
115
  ${err.stack || ""}
172
116
  `;
173
117
  if (logContent) {
174
- fs2.writeFileSync(path3.join(this.baseDir, `session-${id}-client.log`), logContent);
118
+ fs2.writeFileSync(path2.join(this.baseDir, `session-${id}-client.log`), logContent);
175
119
  files.push(`session-${id}-client.log`);
176
120
  }
177
121
  if (payload.state) {
178
- fs2.writeFileSync(path3.join(this.baseDir, `session-${id}-state.json`), JSON.stringify(payload.state, null, 2));
122
+ fs2.writeFileSync(path2.join(this.baseDir, `session-${id}-state.json`), JSON.stringify(payload.state, null, 2));
179
123
  files.push(`session-${id}-state.json`);
180
124
  }
181
125
  if (payload.screenshot) {
182
- fs2.writeFileSync(path3.join(this.baseDir, `session-${id}-screenshot.jpg`), Buffer.from(payload.screenshot, "base64"));
126
+ fs2.writeFileSync(path2.join(this.baseDir, `session-${id}-screenshot.jpg`), Buffer.from(payload.screenshot, "base64"));
183
127
  files.push(`session-${id}-screenshot.jpg`);
184
128
  }
185
129
  const savedId = id;
@@ -205,14 +149,14 @@ ${err.stack || ""}
205
149
  }
206
150
  };
207
151
 
208
- // ../server/gateway.js
209
- import path5 from "node:path";
152
+ // server/gateway.js
153
+ import path4 from "node:path";
210
154
  import { WebSocket as WS } from "ws";
211
155
 
212
- // ../server/bootstrap/identity.js
156
+ // server/bootstrap/identity.js
213
157
  import crypto from "node:crypto";
214
158
  import fs3 from "node:fs";
215
- import path4 from "node:path";
159
+ import path3 from "node:path";
216
160
  var ED25519_SPKI_PREFIX = Buffer.from("302a300506032b6570032100", "hex");
217
161
  function derivePublicKeyRaw(publicKeyPem) {
218
162
  const spki = crypto.createPublicKey(publicKeyPem).export({ type: "spki", format: "der" });
@@ -242,7 +186,7 @@ function loadOrCreateDeviceIdentity(identityPath) {
242
186
  const publicKeyPem = publicKey.export({ type: "spki", format: "pem" }).toString();
243
187
  const privateKeyPem = privateKey.export({ type: "pkcs8", format: "pem" }).toString();
244
188
  const identity = { version: 1, deviceId: fingerprintPublicKey(publicKeyPem), publicKeyPem, privateKeyPem, createdAtMs: Date.now() };
245
- fs3.mkdirSync(path4.dirname(identityPath), { recursive: true });
189
+ fs3.mkdirSync(path3.dirname(identityPath), { recursive: true });
246
190
  fs3.writeFileSync(identityPath, JSON.stringify(identity, null, 2) + "\n", { mode: 384 });
247
191
  return identity;
248
192
  }
@@ -257,7 +201,7 @@ function buildDeviceAuth(identity, { clientId, clientMode, role, scopes, token,
257
201
  }
258
202
  __name(buildDeviceAuth, "buildDeviceAuth");
259
203
 
260
- // ../server/util/helpers.js
204
+ // server/util/helpers.js
261
205
  function syncThreadUnreadCount(db, threadId) {
262
206
  const count = db.prepare("SELECT COUNT(*) as c FROM unread_messages WHERE thread_id = ?").get(threadId).c;
263
207
  db.prepare("UPDATE threads SET unread_count = ? WHERE id = ?").run(count, threadId);
@@ -378,7 +322,7 @@ function writeActivityToDb(getDbFn, broadcastFn, runId, log) {
378
322
  }
379
323
  __name(writeActivityToDb, "writeActivityToDb");
380
324
 
381
- // ../server/gateway.js
325
+ // server/gateway.js
382
326
  var GatewayClient = class {
383
327
  static {
384
328
  __name(this, "GatewayClient");
@@ -440,7 +384,7 @@ var GatewayClient = class {
440
384
  return;
441
385
  }
442
386
  if (msg.type === "event" && msg.event === "connect.challenge") {
443
- const identity = loadOrCreateDeviceIdentity(path5.join(this.dataDir, "device-identity.json"));
387
+ const identity = loadOrCreateDeviceIdentity(path4.join(this.dataDir, "device-identity.json"));
444
388
  const device = buildDeviceAuth(identity, { clientId: "gateway-client", clientMode: "backend", role: "operator", scopes: ["operator.read", "operator.write", "operator.admin"], token: this.authToken, nonce: msg.payload?.nonce || "" });
445
389
  this.ws.send(JSON.stringify({ type: "req", id: "gw-connect-1", method: "connect", params: { minProtocol: 3, maxProtocol: 3, client: { id: "gateway-client", version: "0.1.0", platform: "node", mode: "backend" }, role: "operator", scopes: ["operator.read", "operator.write", "operator.admin"], device, auth: { token: this.authToken }, caps: ["tool-events"] } }));
446
390
  return;
@@ -773,14 +717,14 @@ Title:`, deliver: false, idempotencyKey: reqId } }));
773
717
  }
774
718
  };
775
719
 
776
- // ../server/providers/memory.js
720
+ // server/providers/memory.js
777
721
  import fs4 from "node:fs";
778
- import path6 from "node:path";
722
+ import path5 from "node:path";
779
723
  import os2 from "node:os";
780
724
  function discoverMemoryConfig() {
781
725
  const defaults = { provider: "qdrant", host: "localhost", port: 6333, collection: null };
782
726
  let oc = null;
783
- for (const cfgPath of [path6.join(os2.homedir(), ".openclaw", "openclaw.json"), "/etc/openclaw/openclaw.json"]) {
727
+ for (const cfgPath of [path5.join(os2.homedir(), ".openclaw", "openclaw.json"), "/etc/openclaw/openclaw.json"]) {
784
728
  try {
785
729
  oc = JSON.parse(fs4.readFileSync(cfgPath, "utf8"));
786
730
  break;
@@ -815,7 +759,7 @@ function discoverMemoryConfig() {
815
759
  } catch {
816
760
  }
817
761
  }
818
- if (!cfg.workspaceDir) cfg.workspaceDir = path6.join(os2.homedir(), ".openclaw", "workspace");
762
+ if (!cfg.workspaceDir) cfg.workspaceDir = path5.join(os2.homedir(), ".openclaw", "workspace");
819
763
  return cfg;
820
764
  }
821
765
  __name(discoverMemoryConfig, "discoverMemoryConfig");
@@ -951,11 +895,11 @@ function createMemoryProvider(config) {
951
895
  }
952
896
  __name(createMemoryProvider, "createMemoryProvider");
953
897
 
954
- // ../server/controllers/workspaces.js
898
+ // server/controllers/workspaces.js
955
899
  import fs6 from "node:fs";
956
- import path8 from "node:path";
900
+ import path7 from "node:path";
957
901
 
958
- // ../server/util/http.js
902
+ // server/util/http.js
959
903
  import crypto2 from "node:crypto";
960
904
  function parseBody(req) {
961
905
  return new Promise((resolve, reject) => {
@@ -1017,20 +961,20 @@ function matchRoute(method, url, pattern) {
1017
961
  }
1018
962
  __name(matchRoute, "matchRoute");
1019
963
 
1020
- // ../server/gateway-cleanup.js
964
+ // server/gateway-cleanup.js
1021
965
  import fs5 from "node:fs";
1022
- import path7 from "node:path";
966
+ import path6 from "node:path";
1023
967
  function cleanGatewaySession(sessionKey) {
1024
968
  try {
1025
969
  const agentMatch = (sessionKey || "").match(/^agent:([^:]+):/);
1026
970
  const sessionsDir = getSessionsDirForAgent(agentMatch?.[1]);
1027
- const sessionsPath = path7.join(sessionsDir, "sessions.json");
971
+ const sessionsPath = path6.join(sessionsDir, "sessions.json");
1028
972
  const store = JSON.parse(fs5.readFileSync(sessionsPath, "utf8"));
1029
973
  const entry = store[sessionKey];
1030
974
  if (!entry) return null;
1031
975
  if (entry.sessionId) {
1032
976
  try {
1033
- fs5.unlinkSync(path7.join(sessionsDir, `${entry.sessionId}.jsonl`));
977
+ fs5.unlinkSync(path6.join(sessionsDir, `${entry.sessionId}.jsonl`));
1034
978
  } catch {
1035
979
  }
1036
980
  }
@@ -1048,14 +992,14 @@ function cleanGatewaySessionsByPrefix(prefix) {
1048
992
  try {
1049
993
  const agentMatch = (prefix || "").match(/^agent:([^:]+):/);
1050
994
  const sessionsDir = getSessionsDirForAgent(agentMatch?.[1]);
1051
- const sessionsPath = path7.join(sessionsDir, "sessions.json");
995
+ const sessionsPath = path6.join(sessionsDir, "sessions.json");
1052
996
  const store = JSON.parse(fs5.readFileSync(sessionsPath, "utf8"));
1053
997
  let cleaned = 0;
1054
998
  for (const key of Object.keys(store)) {
1055
999
  if (!key.startsWith(prefix)) continue;
1056
1000
  if (store[key]?.sessionId) {
1057
1001
  try {
1058
- fs5.unlinkSync(path7.join(sessionsDir, `${store[key].sessionId}.jsonl`));
1002
+ fs5.unlinkSync(path6.join(sessionsDir, `${store[key].sessionId}.jsonl`));
1059
1003
  } catch {
1060
1004
  }
1061
1005
  }
@@ -1071,7 +1015,7 @@ function cleanGatewaySessionsByPrefix(prefix) {
1071
1015
  }
1072
1016
  __name(cleanGatewaySessionsByPrefix, "cleanGatewaySessionsByPrefix");
1073
1017
 
1074
- // ../server/controllers/workspaces.js
1018
+ // server/controllers/workspaces.js
1075
1019
  var WorkspaceController = class {
1076
1020
  static {
1077
1021
  __name(this, "WorkspaceController");
@@ -1148,7 +1092,7 @@ var WorkspaceController = class {
1148
1092
  if (!ws.workspaces[params.name]) return sendError(res, 404, "Workspace not found");
1149
1093
  if (Object.keys(ws.workspaces).length <= 1) return sendError(res, 400, "Cannot delete the only workspace");
1150
1094
  this.closeDb(params.name);
1151
- const dbPath = path8.join(this.dataDir, `${params.name}.db`);
1095
+ const dbPath = path7.join(this.dataDir, `${params.name}.db`);
1152
1096
  for (const suffix of ["", "-wal", "-shm"]) {
1153
1097
  try {
1154
1098
  fs6.unlinkSync(dbPath + suffix);
@@ -1183,9 +1127,9 @@ var WorkspaceController = class {
1183
1127
  }
1184
1128
  };
1185
1129
 
1186
- // ../server/controllers/threads.js
1130
+ // server/controllers/threads.js
1187
1131
  import fs7 from "node:fs";
1188
- import path9 from "node:path";
1132
+ import path8 from "node:path";
1189
1133
  var ThreadController = class {
1190
1134
  static {
1191
1135
  __name(this, "ThreadController");
@@ -1295,28 +1239,28 @@ var ThreadController = class {
1295
1239
  let sessionIdToDelete = thread.last_session_id;
1296
1240
  if (!sessionIdToDelete) {
1297
1241
  try {
1298
- sessionIdToDelete = JSON.parse(fs7.readFileSync(path9.join(sessionsDir, "sessions.json"), "utf8"))[thread.session_key]?.sessionId;
1242
+ sessionIdToDelete = JSON.parse(fs7.readFileSync(path8.join(sessionsDir, "sessions.json"), "utf8"))[thread.session_key]?.sessionId;
1299
1243
  } catch {
1300
1244
  }
1301
1245
  }
1302
1246
  cleanGatewaySession(thread.session_key);
1303
1247
  if (sessionIdToDelete) {
1304
1248
  try {
1305
- fs7.unlinkSync(path9.join(sessionsDir, `${sessionIdToDelete}.jsonl`));
1249
+ fs7.unlinkSync(path8.join(sessionsDir, `${sessionIdToDelete}.jsonl`));
1306
1250
  } catch {
1307
1251
  }
1308
1252
  }
1309
1253
  try {
1310
- fs7.rmSync(path9.join(this.uploadsDir, params.id), { recursive: true });
1254
+ fs7.rmSync(path8.join(this.uploadsDir, params.id), { recursive: true });
1311
1255
  } catch {
1312
1256
  }
1313
1257
  send(res, 200, { ok: true });
1314
1258
  }
1315
1259
  };
1316
1260
 
1317
- // ../server/util/context.js
1261
+ // server/util/context.js
1318
1262
  import fs8 from "node:fs";
1319
- import path10 from "node:path";
1263
+ import path9 from "node:path";
1320
1264
  function buildContextPreamble(db, threadId, lastSessionId, sessionKey) {
1321
1265
  let summary = null;
1322
1266
  let method = "raw";
@@ -1324,7 +1268,7 @@ function buildContextPreamble(db, threadId, lastSessionId, sessionKey) {
1324
1268
  const agentMatch = (sessionKey || "").match(/^agent:([^:]+):/);
1325
1269
  const sessionsDir = getSessionsDirForAgent(agentMatch?.[1]);
1326
1270
  try {
1327
- const lines = fs8.readFileSync(path10.join(sessionsDir, `${lastSessionId}.jsonl`), "utf8").split("\n").filter(Boolean);
1271
+ const lines = fs8.readFileSync(path9.join(sessionsDir, `${lastSessionId}.jsonl`), "utf8").split("\n").filter(Boolean);
1328
1272
  for (let i = lines.length - 1; i >= 0; i--) {
1329
1273
  try {
1330
1274
  const entry = JSON.parse(lines[i]);
@@ -1369,7 +1313,7 @@ function buildContextPreamble(db, threadId, lastSessionId, sessionKey) {
1369
1313
  }
1370
1314
  __name(buildContextPreamble, "buildContextPreamble");
1371
1315
 
1372
- // ../server/controllers/messages.js
1316
+ // server/controllers/messages.js
1373
1317
  var MessageController = class {
1374
1318
  static {
1375
1319
  __name(this, "MessageController");
@@ -1498,7 +1442,8 @@ var MessageController = class {
1498
1442
  let threadsImported = 0, messagesImported = 0;
1499
1443
  const insertThread = db.prepare("INSERT OR IGNORE INTO threads (id, session_key, title, pinned, pin_order, model, last_session_id, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)");
1500
1444
  const insertMsg = db.prepare("INSERT OR IGNORE INTO messages (id, thread_id, role, content, status, metadata, seq, timestamp, created_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)");
1501
- db.transaction(() => {
1445
+ db.exec("BEGIN");
1446
+ try {
1502
1447
  for (const t of body.threads) {
1503
1448
  if (!t.id) continue;
1504
1449
  const sessionKey = t.session_key || `agent:main:${ws.active}:chat:${t.id}`;
@@ -1509,16 +1454,20 @@ var MessageController = class {
1509
1454
  if (insertMsg.run(m.id, t.id, m.role, m.content || "", m.status || "sent", meta, m.seq || null, m.timestamp || Date.now(), m.created_at || Date.now()).changes > 0) messagesImported++;
1510
1455
  }
1511
1456
  }
1512
- })();
1457
+ db.exec("COMMIT");
1458
+ } catch (e) {
1459
+ db.exec("ROLLBACK");
1460
+ throw e;
1461
+ }
1513
1462
  send(res, 200, { ok: true, threadsImported, messagesImported });
1514
1463
  }
1515
1464
  };
1516
1465
 
1517
- // ../server/controllers/files.js
1466
+ // server/controllers/files.js
1518
1467
  import fs9 from "node:fs";
1519
- import path11 from "node:path";
1468
+ import path10 from "node:path";
1520
1469
 
1521
- // ../server/util/multipart.js
1470
+ // server/util/multipart.js
1522
1471
  function parseMultipart(req) {
1523
1472
  return new Promise((resolve, reject) => {
1524
1473
  const contentType = req.headers["content-type"] || "";
@@ -1566,7 +1515,7 @@ function parseMultipart(req) {
1566
1515
  }
1567
1516
  __name(parseMultipart, "parseMultipart");
1568
1517
 
1569
- // ../server/controllers/files.js
1518
+ // server/controllers/files.js
1570
1519
  var FileController = class {
1571
1520
  static {
1572
1521
  __name(this, "FileController");
@@ -1580,35 +1529,35 @@ var FileController = class {
1580
1529
  async upload(req, res, params) {
1581
1530
  if (!this.getActiveDb().prepare("SELECT id FROM threads WHERE id = ?").get(params.id)) return sendError(res, 404, "Thread not found");
1582
1531
  const files = await parseMultipart(req);
1583
- const dir = path11.join(this.uploadsDir, params.id);
1532
+ const dir = path10.join(this.uploadsDir, params.id);
1584
1533
  fs9.mkdirSync(dir, { recursive: true });
1585
1534
  const savedFiles = [];
1586
1535
  for (const file of files) {
1587
1536
  const fileId = uuid();
1588
- const ext = path11.extname(file.filename) || "";
1589
- fs9.writeFileSync(path11.join(dir, fileId + ext), file.data);
1537
+ const ext = path10.extname(file.filename) || "";
1538
+ fs9.writeFileSync(path10.join(dir, fileId + ext), file.data);
1590
1539
  savedFiles.push({ id: fileId, filename: file.filename, path: `/api/uploads/${params.id}/${fileId}${ext}`, mimeType: file.mimeType, size: file.data.length });
1591
1540
  }
1592
1541
  send(res, 200, { files: savedFiles });
1593
1542
  }
1594
1543
  serveUpload(req, res, params) {
1595
- const base = path11.join(this.uploadsDir, params.threadId, params.fileId);
1544
+ const base = path10.join(this.uploadsDir, params.threadId, params.fileId);
1596
1545
  let resolved = base;
1597
1546
  if (!fs9.existsSync(resolved)) {
1598
1547
  try {
1599
- const match = fs9.readdirSync(path11.join(this.uploadsDir, params.threadId)).find((e) => e.startsWith(params.fileId.replace(/\.[^.]+$/, "")));
1600
- if (match) resolved = path11.join(this.uploadsDir, params.threadId, match);
1548
+ const match = fs9.readdirSync(path10.join(this.uploadsDir, params.threadId)).find((e) => e.startsWith(params.fileId.replace(/\.[^.]+$/, "")));
1549
+ if (match) resolved = path10.join(this.uploadsDir, params.threadId, match);
1601
1550
  } catch {
1602
1551
  }
1603
1552
  }
1604
1553
  if (!fs9.existsSync(resolved)) return sendError(res, 404, "File not found");
1605
1554
  const MIME = { ".png": "image/png", ".jpg": "image/jpeg", ".jpeg": "image/jpeg", ".gif": "image/gif", ".webp": "image/webp", ".pdf": "application/pdf", ".txt": "text/plain", ".json": "application/json" };
1606
1555
  const stat = fs9.statSync(resolved);
1607
- res.writeHead(200, { "Content-Type": MIME[path11.extname(resolved).toLowerCase()] || "application/octet-stream", "Content-Length": stat.size, "Cache-Control": "public, max-age=86400", "Access-Control-Allow-Origin": "*" });
1556
+ res.writeHead(200, { "Content-Type": MIME[path10.extname(resolved).toLowerCase()] || "application/octet-stream", "Content-Length": stat.size, "Cache-Control": "public, max-age=86400", "Access-Control-Allow-Origin": "*" });
1608
1557
  fs9.createReadStream(resolved).pipe(res);
1609
1558
  }
1610
1559
  _intelligencePath(threadId) {
1611
- return path11.join(this.intelligenceDir, this.getWorkspaces().active, `${threadId}.json`);
1560
+ return path10.join(this.intelligenceDir, this.getWorkspaces().active, `${threadId}.json`);
1612
1561
  }
1613
1562
  getIntelligence(req, res, params) {
1614
1563
  const filePath = this._intelligencePath(params.id);
@@ -1622,16 +1571,16 @@ var FileController = class {
1622
1571
  async saveIntelligence(req, res, params) {
1623
1572
  const body = await parseBody(req);
1624
1573
  const filePath = this._intelligencePath(params.id);
1625
- fs9.mkdirSync(path11.dirname(filePath), { recursive: true });
1574
+ fs9.mkdirSync(path10.dirname(filePath), { recursive: true });
1626
1575
  const data = { versions: body.versions || [], currentVersion: body.currentVersion ?? -1, updatedAt: Date.now() };
1627
1576
  fs9.writeFileSync(filePath, JSON.stringify(data, null, 2));
1628
1577
  send(res, 200, data);
1629
1578
  }
1630
1579
  };
1631
1580
 
1632
- // ../server/controllers/memory.js
1581
+ // server/controllers/memory.js
1633
1582
  import fs10 from "node:fs";
1634
- import path12 from "node:path";
1583
+ import path11 from "node:path";
1635
1584
  var MemoryController = class {
1636
1585
  static {
1637
1586
  __name(this, "MemoryController");
@@ -1675,7 +1624,7 @@ var MemoryController = class {
1675
1624
  return;
1676
1625
  }
1677
1626
  for (const entry of entries) {
1678
- const fullPath = path12.join(dir, entry);
1627
+ const fullPath = path11.join(dir, entry);
1679
1628
  const stat = (() => {
1680
1629
  try {
1681
1630
  return fs10.statSync(fullPath);
@@ -1736,16 +1685,16 @@ ${body}` : body, createdAt: dateMatch ? `${dateMatch[1]}T00:00:00Z` : stat.mtime
1736
1685
  }
1737
1686
  };
1738
1687
 
1739
- // ../server/controllers/filesystem.js
1688
+ // server/controllers/filesystem.js
1740
1689
  import fs11 from "node:fs";
1741
- import path13 from "node:path";
1690
+ import path12 from "node:path";
1742
1691
  import os3 from "node:os";
1743
1692
  var HOME2 = os3.homedir();
1744
1693
  var ALLOWED_FILE_DIRS = [HOME2, "/tmp"];
1745
1694
  function handleServeFile(req, res, query, memoryConfig) {
1746
1695
  const filePath = query.path;
1747
1696
  if (!filePath) return sendError(res, 400, "Missing path parameter");
1748
- const resolved = filePath.startsWith("./") || filePath.startsWith("../") ? path13.resolve(memoryConfig.workspaceDir, filePath) : path13.resolve(filePath);
1697
+ const resolved = filePath.startsWith("./") || filePath.startsWith("../") ? path12.resolve(memoryConfig.workspaceDir, filePath) : path12.resolve(filePath);
1749
1698
  if (!ALLOWED_FILE_DIRS.some((dir) => resolved.startsWith(dir + "/") || resolved === dir)) return sendError(res, 403, "Access denied: path not in allowed directories");
1750
1699
  if (!fs11.existsSync(resolved) || !fs11.statSync(resolved).isFile()) return sendError(res, 404, "File not found");
1751
1700
  const MIME = {
@@ -1781,7 +1730,7 @@ function handleServeFile(req, res, query, memoryConfig) {
1781
1730
  ".webm": "video/webm"
1782
1731
  };
1783
1732
  const stat = fs11.statSync(resolved);
1784
- res.writeHead(200, { "Content-Type": MIME[path13.extname(resolved).toLowerCase()] || "application/octet-stream", "Content-Length": stat.size, "Cache-Control": "public, max-age=86400", "Access-Control-Allow-Origin": "*" });
1733
+ res.writeHead(200, { "Content-Type": MIME[path12.extname(resolved).toLowerCase()] || "application/octet-stream", "Content-Length": stat.size, "Cache-Control": "public, max-age=86400", "Access-Control-Allow-Origin": "*" });
1785
1734
  fs11.createReadStream(resolved).pipe(res);
1786
1735
  }
1787
1736
  __name(handleServeFile, "handleServeFile");
@@ -1789,17 +1738,17 @@ function handleWorkspaceList(req, res, query) {
1789
1738
  const reqPath = query.path || "~/.openclaw/workspace";
1790
1739
  const depth = parseInt(query.depth || "2", 10);
1791
1740
  const showHidden = query.hidden === "1" || query.hidden === "true";
1792
- const resolved = path13.resolve(reqPath.replace(/^~/, HOME2));
1741
+ const resolved = path12.resolve(reqPath.replace(/^~/, HOME2));
1793
1742
  if (!resolved.startsWith(HOME2)) return sendError(res, 403, "Access denied");
1794
1743
  if (!fs11.existsSync(resolved)) return sendError(res, 404, "Path not found");
1795
- const files = [{ path: resolved + "/", type: "dir", name: path13.basename(resolved), size: 0 }];
1744
+ const files = [{ path: resolved + "/", type: "dir", name: path12.basename(resolved), size: 0 }];
1796
1745
  const walk = /* @__PURE__ */ __name((dir, d) => {
1797
1746
  if (d > depth) return;
1798
1747
  try {
1799
1748
  for (const entry of fs11.readdirSync(dir, { withFileTypes: true })) {
1800
1749
  if (entry.name.startsWith(".") && entry.name !== ".openclaw" && !showHidden) continue;
1801
1750
  if (entry.name === "node_modules") continue;
1802
- const fullPath = path13.join(dir, entry.name);
1751
+ const fullPath = path12.join(dir, entry.name);
1803
1752
  const isDir = entry.isDirectory();
1804
1753
  files.push({ path: fullPath + (isDir ? "/" : ""), type: isDir ? "dir" : "file", name: entry.name, size: isDir ? 0 : (() => {
1805
1754
  try {
@@ -1820,11 +1769,11 @@ __name(handleWorkspaceList, "handleWorkspaceList");
1820
1769
  function handleWorkspaceFileRead(req, res, query) {
1821
1770
  const filePath = query.path;
1822
1771
  if (!filePath) return sendError(res, 400, "Missing path parameter");
1823
- const resolved = path13.resolve(filePath.replace(/^~/, HOME2));
1772
+ const resolved = path12.resolve(filePath.replace(/^~/, HOME2));
1824
1773
  if (!resolved.startsWith(HOME2)) return sendError(res, 403, "Access denied");
1825
1774
  if (!fs11.existsSync(resolved) || !fs11.statSync(resolved).isFile()) return sendError(res, 404, "File not found");
1826
1775
  const stat = fs11.statSync(resolved);
1827
- const ext = path13.extname(resolved).toLowerCase().slice(1);
1776
+ const ext = path12.extname(resolved).toLowerCase().slice(1);
1828
1777
  const binaryMime = { png: "image/png", jpg: "image/jpeg", jpeg: "image/jpeg", gif: "image/gif", webp: "image/webp", svg: "image/svg+xml", bmp: "image/bmp", ico: "image/x-icon", pdf: "application/pdf", mp3: "audio/mpeg", mp4: "video/mp4", wav: "audio/wav", ogg: "audio/ogg", webm: "video/webm" };
1829
1778
  const mime = binaryMime[ext];
1830
1779
  if (mime) {
@@ -1841,11 +1790,11 @@ __name(handleWorkspaceFileRead, "handleWorkspaceFileRead");
1841
1790
  async function handleWorkspaceFileWrite(req, res, query) {
1842
1791
  const filePath = query.path;
1843
1792
  if (!filePath) return sendError(res, 400, "Missing path parameter");
1844
- const resolved = path13.resolve(filePath.replace(/^~/, HOME2));
1793
+ const resolved = path12.resolve(filePath.replace(/^~/, HOME2));
1845
1794
  if (!resolved.startsWith(HOME2)) return sendError(res, 403, "Can only write to workspace directory");
1846
1795
  const chunks = [];
1847
1796
  for await (const chunk of req) chunks.push(chunk);
1848
- const dir = path13.dirname(resolved);
1797
+ const dir = path12.dirname(resolved);
1849
1798
  if (!fs11.existsSync(dir)) fs11.mkdirSync(dir, { recursive: true });
1850
1799
  fs11.writeFileSync(resolved, Buffer.concat(chunks).toString("utf8"), "utf8");
1851
1800
  send(res, 200, { ok: true });
@@ -1854,7 +1803,7 @@ __name(handleWorkspaceFileWrite, "handleWorkspaceFileWrite");
1854
1803
  function handleWorkspaceFileDelete(req, res, query) {
1855
1804
  const filePath = query.path;
1856
1805
  if (!filePath) return sendError(res, 400, "Missing path parameter");
1857
- const resolved = path13.resolve(filePath.replace(/^~/, HOME2));
1806
+ const resolved = path12.resolve(filePath.replace(/^~/, HOME2));
1858
1807
  if (!resolved.startsWith(HOME2)) return sendError(res, 403, "Access denied");
1859
1808
  if (!fs11.existsSync(resolved)) return sendError(res, 404, "Path not found");
1860
1809
  try {
@@ -1874,52 +1823,36 @@ __name(handleWorkspaceFileDelete, "handleWorkspaceFileDelete");
1874
1823
  async function handleWorkspaceUpload(req, res, query) {
1875
1824
  const targetDir = query.path;
1876
1825
  if (!targetDir) return sendError(res, 400, "Missing path parameter");
1877
- const resolved = path13.resolve(targetDir.replace(/^~/, HOME2));
1826
+ const resolved = path12.resolve(targetDir.replace(/^~/, HOME2));
1878
1827
  if (!resolved.startsWith(HOME2)) return sendError(res, 403, "Access denied");
1879
1828
  if (!fs11.existsSync(resolved) || !fs11.statSync(resolved).isDirectory()) return sendError(res, 404, "Target directory not found");
1880
- const contentType = req.headers["content-type"] || "";
1881
- if (!contentType.includes("multipart/form-data")) return sendError(res, 400, "Expected multipart/form-data");
1882
- const boundary = contentType.split("boundary=")[1];
1883
- if (!boundary) return sendError(res, 400, "Missing boundary");
1884
- const chunks = [];
1885
- for await (const chunk of req) chunks.push(chunk);
1886
- const body = Buffer.concat(chunks);
1887
- const boundaryBuf = Buffer.from("--" + boundary);
1829
+ if (!(req.headers["content-type"] || "").includes("multipart/form-data")) return sendError(res, 400, "Expected multipart/form-data");
1830
+ let files;
1831
+ try {
1832
+ files = await parseMultipart(req);
1833
+ } catch (err) {
1834
+ return sendError(res, 400, "Invalid multipart data: " + err.message);
1835
+ }
1888
1836
  const uploaded = [];
1889
- let start = 0;
1890
- while (true) {
1891
- const idx = body.indexOf(boundaryBuf, start);
1892
- if (idx === -1) break;
1893
- if (start > 0) {
1894
- const partData = body.slice(start, idx - 2);
1895
- const headerEnd = partData.indexOf("\r\n\r\n");
1896
- if (headerEnd !== -1) {
1897
- const headerStr = partData.slice(0, headerEnd).toString("utf8");
1898
- const fileContent = partData.slice(headerEnd + 4);
1899
- const filenameMatch = headerStr.match(/filename="([^"]+)"/);
1900
- if (filenameMatch && fileContent.length > 0) {
1901
- const filename = path13.basename(filenameMatch[1]);
1902
- let finalPath = path13.join(resolved, filename);
1903
- let counter = 1;
1904
- while (fs11.existsSync(finalPath)) {
1905
- const ext = path13.extname(filename);
1906
- finalPath = path13.join(resolved, `${path13.basename(filename, ext)} (${counter})${ext}`);
1907
- counter++;
1908
- }
1909
- fs11.writeFileSync(finalPath, fileContent);
1910
- uploaded.push({ name: path13.basename(finalPath), size: fileContent.length });
1911
- }
1912
- }
1913
- }
1914
- start = idx + boundaryBuf.length + 2;
1837
+ for (const { filename, data } of files) {
1838
+ if (!filename || !data.length) continue;
1839
+ const safeName = path12.basename(filename);
1840
+ let finalPath = path12.join(resolved, safeName);
1841
+ let counter = 1;
1842
+ while (fs11.existsSync(finalPath)) {
1843
+ const ext = path12.extname(safeName);
1844
+ finalPath = path12.join(resolved, `${path12.basename(safeName, ext)} (${counter++})${ext}`);
1845
+ }
1846
+ fs11.writeFileSync(finalPath, data);
1847
+ uploaded.push({ name: path12.basename(finalPath), size: data.length });
1915
1848
  }
1916
1849
  send(res, 200, { ok: true, uploaded });
1917
1850
  }
1918
1851
  __name(handleWorkspaceUpload, "handleWorkspaceUpload");
1919
1852
 
1920
- // ../server/controllers/transcribe.js
1853
+ // server/controllers/transcribe.js
1921
1854
  import fs12 from "node:fs";
1922
- import path14 from "node:path";
1855
+ import path13 from "node:path";
1923
1856
  import os4 from "node:os";
1924
1857
  async function handleTranscribe(req, res) {
1925
1858
  try {
@@ -1930,7 +1863,7 @@ async function handleTranscribe(req, res) {
1930
1863
  if (audioBuffer.length > 25 * 1024 * 1024) return send(res, 400, { error: "Audio too large (max 25MB)" });
1931
1864
  let apiKey;
1932
1865
  try {
1933
- const ocConfig = JSON.parse(fs12.readFileSync(path14.join(os4.homedir(), ".openclaw", "openclaw.json"), "utf8"));
1866
+ const ocConfig = JSON.parse(fs12.readFileSync(path13.join(os4.homedir(), ".openclaw", "openclaw.json"), "utf8"));
1934
1867
  apiKey = ocConfig?.skills?.entries?.["openai-whisper-api"]?.apiKey;
1935
1868
  } catch {
1936
1869
  }
@@ -1978,17 +1911,17 @@ json\r
1978
1911
  }
1979
1912
  __name(handleTranscribe, "handleTranscribe");
1980
1913
 
1981
- // ../server/index.js
1914
+ // server/index.js
1982
1915
  var HOME3 = os5.homedir();
1983
1916
  var PORT = parseInt(process.env.PORT || "3001", 10);
1984
- var __dirname3 = path15.dirname(fileURLToPath3(import.meta.url));
1985
- var PLUGIN_DIR = path15.resolve(__dirname3, "..");
1917
+ var __dirname2 = path14.dirname(fileURLToPath2(import.meta.url));
1918
+ var PLUGIN_DIR = path14.resolve(__dirname2, "..");
1986
1919
  function createApp(config = {}) {
1987
- const DATA_DIR = config.dataDir || path15.join(PLUGIN_DIR, "data");
1988
- const UPLOADS_DIR = config.uploadsDir || path15.join(PLUGIN_DIR, "uploads");
1989
- const WORKSPACES_FILE = path15.join(DATA_DIR, "workspaces.json");
1990
- const SETTINGS_FILE = path15.join(DATA_DIR, "settings.json");
1991
- const INTELLIGENCE_DIR = path15.join(DATA_DIR, "intelligence");
1920
+ const DATA_DIR = config.dataDir || path14.join(PLUGIN_DIR, "data");
1921
+ const UPLOADS_DIR = config.uploadsDir || path14.join(PLUGIN_DIR, "uploads");
1922
+ const WORKSPACES_FILE = path14.join(DATA_DIR, "workspaces.json");
1923
+ const SETTINGS_FILE = path14.join(DATA_DIR, "settings.json");
1924
+ const INTELLIGENCE_DIR = path14.join(DATA_DIR, "intelligence");
1992
1925
  const authToken = config.authToken !== void 0 ? config.authToken : AUTH_TOKEN;
1993
1926
  const gatewayToken = config.gatewayToken !== void 0 ? config.gatewayToken : authToken;
1994
1927
  const gatewayUrl = config.gatewayUrl || GATEWAY_WS_URL;
@@ -1997,10 +1930,10 @@ function createApp(config = {}) {
1997
1930
  const dbCache = /* @__PURE__ */ new Map();
1998
1931
  function getDb(workspaceName) {
1999
1932
  if (dbCache.has(workspaceName)) return dbCache.get(workspaceName);
2000
- const db = new Database(path15.join(DATA_DIR, `${workspaceName}.db`));
2001
- db.pragma("journal_mode = WAL");
2002
- db.pragma("foreign_keys = ON");
2003
- _migrate(db);
1933
+ const db = new Database(path14.join(DATA_DIR, `${workspaceName}.db`));
1934
+ db.exec("PRAGMA journal_mode = WAL");
1935
+ db.exec("PRAGMA foreign_keys = ON");
1936
+ migrate(db);
2004
1937
  dbCache.set(workspaceName, db);
2005
1938
  return db;
2006
1939
  }
@@ -2027,8 +1960,8 @@ function createApp(config = {}) {
2027
1960
  const globalDbCache = {
2028
1961
  get() {
2029
1962
  if (_globalDb) return _globalDb;
2030
- _globalDb = new Database(path15.join(DATA_DIR, "global.db"));
2031
- _globalDb.pragma("journal_mode = WAL");
1963
+ _globalDb = new Database(path14.join(DATA_DIR, "global.db"));
1964
+ _globalDb.exec("PRAGMA journal_mode = WAL");
2032
1965
  _globalDb.exec(`CREATE TABLE IF NOT EXISTS custom_emojis (name TEXT NOT NULL, pack TEXT NOT NULL DEFAULT 'slackmojis', url TEXT NOT NULL, mime_type TEXT, created_at INTEGER DEFAULT (strftime('%s','now')), PRIMARY KEY (name, pack))`);
2033
1966
  return _globalDb;
2034
1967
  },
@@ -2062,7 +1995,7 @@ function createApp(config = {}) {
2062
1995
  const memoryConfig = discoverMemoryConfig();
2063
1996
  const memoryProvider = createMemoryProvider(memoryConfig);
2064
1997
  memoryProvider.init().catch((err) => console.error("[createApp] Memory provider init error:", err.message));
2065
- const MEMORY_FILES_DIR = path15.join(memoryConfig.workspaceDir, "memory");
1998
+ const MEMORY_FILES_DIR = path14.join(memoryConfig.workspaceDir, "memory");
2066
1999
  const gatewayClient = new GatewayClient({ getDb, getWorkspaces, dataDir: DATA_DIR, debugLogger, gatewayWsUrl: gatewayUrl, authToken: gatewayToken, mediaStash });
2067
2000
  const broadcast = /* @__PURE__ */ __name((msg) => gatewayClient.broadcastToBrowsers(msg), "broadcast");
2068
2001
  const workspaces = new WorkspaceController({ getDb, closeDb, getWorkspaces, setWorkspaces, dataDir: DATA_DIR, broadcast });
@@ -2080,7 +2013,7 @@ function createApp(config = {}) {
2080
2013
  __name(handleGetSettings, "handleGetSettings");
2081
2014
  async function handleSaveSettings(req, res) {
2082
2015
  const body = await parseBody(req);
2083
- fs13.mkdirSync(path15.dirname(SETTINGS_FILE), { recursive: true });
2016
+ fs13.mkdirSync(path14.dirname(SETTINGS_FILE), { recursive: true });
2084
2017
  fs13.writeFileSync(SETTINGS_FILE, JSON.stringify(body, null, 2));
2085
2018
  send(res, 200, { ok: true });
2086
2019
  }
@@ -2124,10 +2057,10 @@ function createApp(config = {}) {
2124
2057
  const fileName = STATIC[urlPath];
2125
2058
  const isAllowed = fileName || urlPath.startsWith("/icons/") || urlPath.startsWith("/lib/") || urlPath.startsWith("/frontend/") || urlPath.startsWith("/emoji/") || urlPath === "/config.js";
2126
2059
  if (isAllowed) {
2127
- const staticPath = path15.join(PLUGIN_DIR, fileName || urlPath.slice(1));
2060
+ const staticPath = path14.join(PLUGIN_DIR, fileName || urlPath.slice(1));
2128
2061
  if (fs13.existsSync(staticPath) && fs13.statSync(staticPath).isFile()) {
2129
2062
  const MIME = { ".html": "text/html", ".js": "text/javascript", ".css": "text/css", ".json": "application/json", ".ico": "image/x-icon", ".png": "image/png", ".svg": "image/svg+xml", ".gif": "image/gif", ".webp": "image/webp" };
2130
- const ext = path15.extname(staticPath).toLowerCase();
2063
+ const ext = path14.extname(staticPath).toLowerCase();
2131
2064
  const stat = fs13.statSync(staticPath);
2132
2065
  res.writeHead(200, { "Content-Type": MIME[ext] || "application/octet-stream", "Content-Length": stat.size, "Cache-Control": ext === ".html" ? "no-cache" : "public, max-age=3600" });
2133
2066
  return fs13.createReadStream(staticPath).pipe(res);
@@ -2214,7 +2147,7 @@ function createApp(config = {}) {
2214
2147
  if (method === "GET" && urlPath === "/api/health") return send(res, 200, { ok: true, workspace: getWorkspaces().active, uptime: process.uptime() });
2215
2148
  if (method === "GET" && urlPath === "/api/agents") {
2216
2149
  try {
2217
- send(res, 200, { agents: fs13.readdirSync(path15.join(HOME3, ".openclaw", "agents"), { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) => e.name) });
2150
+ send(res, 200, { agents: fs13.readdirSync(path14.join(HOME3, ".openclaw", "agents"), { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) => e.name) });
2218
2151
  } catch {
2219
2152
  send(res, 200, { agents: ["main"] });
2220
2153
  }
@@ -2303,7 +2236,7 @@ function createApp(config = {}) {
2303
2236
  if (msg.type === "req" && msg.method === "chat.send" && msg.params?.attachments?.length > 0) {
2304
2237
  const parsed = parseSessionKey(msg.params.sessionKey || "");
2305
2238
  const threadId = parsed?.threadId || "misc";
2306
- const uploadDir = path15.join(UPLOADS_DIR, threadId);
2239
+ const uploadDir = path14.join(UPLOADS_DIR, threadId);
2307
2240
  fs13.mkdirSync(uploadDir, { recursive: true });
2308
2241
  const extMap = { jpeg: "jpg", jpg: "jpg", png: "png", gif: "gif", webp: "webp", pdf: "pdf", "svg+xml": "svg", mp3: "mp3", mp4: "mp4", wav: "wav", webm: "webm" };
2309
2242
  const savedPaths = [];
@@ -2311,7 +2244,7 @@ function createApp(config = {}) {
2311
2244
  if (!att.content || !att.mimeType) continue;
2312
2245
  try {
2313
2246
  const rawExt = att.mimeType.split("/")[1]?.split(";")[0] || "bin";
2314
- const filePath = path15.join(uploadDir, `${Date.now()}_${Math.random().toString(36).slice(2, 6)}.${extMap[rawExt] || rawExt}`);
2247
+ const filePath = path14.join(uploadDir, `${Date.now()}_${Math.random().toString(36).slice(2, 6)}.${extMap[rawExt] || rawExt}`);
2315
2248
  fs13.writeFileSync(filePath, Buffer.from(att.content, "base64"));
2316
2249
  savedPaths.push(filePath);
2317
2250
  } catch (err) {
@@ -2353,7 +2286,7 @@ ${savedPaths.map((p) => `- ${p}`).join("\n")}]`;
2353
2286
  };
2354
2287
  }
2355
2288
  __name(createApp, "createApp");
2356
- function _migrate(db) {
2289
+ function migrate(db) {
2357
2290
  db.exec(`
2358
2291
  CREATE TABLE IF NOT EXISTS threads (
2359
2292
  id TEXT PRIMARY KEY, session_key TEXT UNIQUE NOT NULL, title TEXT DEFAULT 'New chat',
@@ -2378,25 +2311,25 @@ function _migrate(db) {
2378
2311
  }
2379
2312
  db.exec(`CREATE TABLE IF NOT EXISTS unread_messages (thread_id TEXT NOT NULL, message_id TEXT NOT NULL, created_at INTEGER NOT NULL, PRIMARY KEY (thread_id, message_id), FOREIGN KEY (thread_id) REFERENCES threads(id) ON DELETE CASCADE)`);
2380
2313
  db.exec("CREATE INDEX IF NOT EXISTS idx_unread_thread ON unread_messages(thread_id)");
2381
- _ensureFts(db);
2314
+ ensureFts(db);
2382
2315
  }
2383
- __name(_migrate, "_migrate");
2384
- function _createFts(db) {
2316
+ __name(migrate, "migrate");
2317
+ function createFts(db) {
2385
2318
  db.exec(`CREATE VIRTUAL TABLE messages_fts USING fts5(content, content=messages, content_rowid=rowid, tokenize='porter unicode61 tokenchars x27')`);
2386
2319
  db.exec(`CREATE TRIGGER messages_ai AFTER INSERT ON messages BEGIN INSERT INTO messages_fts(rowid, content) VALUES (new.rowid, new.content); END`);
2387
2320
  db.exec(`CREATE TRIGGER messages_ad AFTER DELETE ON messages BEGIN INSERT INTO messages_fts(messages_fts, rowid, content) VALUES('delete', old.rowid, old.content); END`);
2388
2321
  db.exec(`CREATE TRIGGER messages_au AFTER UPDATE ON messages BEGIN INSERT INTO messages_fts(messages_fts, rowid, content) VALUES('delete', old.rowid, old.content); INSERT INTO messages_fts(rowid, content) VALUES (new.rowid, new.content); END`);
2389
2322
  }
2390
- __name(_createFts, "_createFts");
2391
- function _dropFts(db) {
2323
+ __name(createFts, "createFts");
2324
+ function dropFts(db) {
2392
2325
  db.exec("DROP TABLE IF EXISTS messages_fts; DROP TRIGGER IF EXISTS messages_ai; DROP TRIGGER IF EXISTS messages_ad; DROP TRIGGER IF EXISTS messages_au;");
2393
2326
  }
2394
- __name(_dropFts, "_dropFts");
2395
- function _ensureFts(db) {
2327
+ __name(dropFts, "dropFts");
2328
+ function ensureFts(db) {
2396
2329
  const hasFts = db.prepare("SELECT name FROM sqlite_master WHERE type='table' AND name='messages_fts'").get();
2397
2330
  if (!hasFts) {
2398
2331
  try {
2399
- _createFts(db);
2332
+ createFts(db);
2400
2333
  db.prepare("INSERT INTO messages_fts(messages_fts) VALUES('rebuild')").run();
2401
2334
  } catch (e) {
2402
2335
  console.error("[DB] messages_fts creation failed:", e.message);
@@ -2407,13 +2340,13 @@ function _ensureFts(db) {
2407
2340
  if (schema && !schema.sql.includes("tokenchars")) {
2408
2341
  console.log("[DB] Upgrading messages_fts tokenizer...");
2409
2342
  try {
2410
- _dropFts(db);
2411
- _createFts(db);
2343
+ dropFts(db);
2344
+ createFts(db);
2412
2345
  db.prepare("INSERT INTO messages_fts(messages_fts) VALUES('rebuild')").run();
2413
2346
  console.log("[DB] Upgrade complete");
2414
2347
  } catch (e) {
2415
2348
  console.error("[DB] Upgrade failed:", e.message);
2416
- _dropFts(db);
2349
+ dropFts(db);
2417
2350
  }
2418
2351
  } else {
2419
2352
  try {
@@ -2423,12 +2356,12 @@ function _ensureFts(db) {
2423
2356
  db.prepare("INSERT INTO messages_fts(messages_fts) VALUES('rebuild')").run();
2424
2357
  } catch (e) {
2425
2358
  console.error("[DB] FTS rebuild failed:", e.message);
2426
- _dropFts(db);
2359
+ dropFts(db);
2427
2360
  }
2428
2361
  }
2429
2362
  }
2430
2363
  }
2431
- __name(_ensureFts, "_ensureFts");
2364
+ __name(ensureFts, "ensureFts");
2432
2365
  var isDirectRun = import.meta.url === `file://${process.argv[1]}`;
2433
2366
  if (isDirectRun) {
2434
2367
  const app = createApp();