squad-openclaw 2026.2.1817 → 2026.2.1902

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 (2) hide show
  1. package/dist/index.js +94 -12
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -20,6 +20,20 @@ function debounced(key, fn) {
20
20
  }, DEBOUNCE_MS)
21
21
  );
22
22
  }
23
+ var fsDebounceTimers = /* @__PURE__ */ new Map();
24
+ var FS_DEBOUNCE_MS = 300;
25
+ function debouncedFs(relPath, action, fn) {
26
+ const key = `fs:${action}:${relPath}`;
27
+ const existing = fsDebounceTimers.get(key);
28
+ if (existing) clearTimeout(existing);
29
+ fsDebounceTimers.set(
30
+ key,
31
+ setTimeout(() => {
32
+ fsDebounceTimers.delete(key);
33
+ fn();
34
+ }, FS_DEBOUNCE_MS)
35
+ );
36
+ }
23
37
  function isWorkspaceIdentity(filePath, configDir) {
24
38
  const rel = path.relative(configDir, filePath);
25
39
  const match = rel.match(/^(workspace(?:-([^/]+))?)\/IDENTITY\.md$/);
@@ -126,7 +140,7 @@ function updatePlugin(pluginDirName, configDir) {
126
140
  registryDelete(`plugin:${pluginDirName}`);
127
141
  }
128
142
  }
129
- function startWatcher(configDir) {
143
+ function startWatcher(configDir, onFsChange) {
130
144
  const watcher = chokidar.watch(configDir, {
131
145
  persistent: true,
132
146
  usePolling: false,
@@ -141,7 +155,15 @@ function startWatcher(configDir) {
141
155
  "**/data/**"
142
156
  ]
143
157
  });
144
- const handleChange = (filePath) => {
158
+ const emitFsChange = (action, filePath) => {
159
+ if (!onFsChange) return;
160
+ const rel = path.relative(configDir, filePath);
161
+ debouncedFs(rel, action, () => {
162
+ onFsChange({ action, path: rel });
163
+ });
164
+ };
165
+ const handleChange = (filePath, action) => {
166
+ emitFsChange(action, filePath);
145
167
  const identity = isWorkspaceIdentity(filePath, configDir);
146
168
  if (identity) {
147
169
  debounced(
@@ -172,6 +194,7 @@ function startWatcher(configDir) {
172
194
  }
173
195
  };
174
196
  const handleAddDir = (dirPath) => {
197
+ emitFsChange("addDir", dirPath);
175
198
  const globalSkill = isGlobalSkillDir(dirPath, configDir);
176
199
  if (globalSkill) {
177
200
  debounced(
@@ -195,6 +218,7 @@ function startWatcher(configDir) {
195
218
  }
196
219
  };
197
220
  const handleUnlinkDir = (dirPath) => {
221
+ emitFsChange("unlinkDir", dirPath);
198
222
  const rel = path.relative(configDir, dirPath);
199
223
  const wsMatch = rel.match(/^workspace(?:-([^/]+))?$/);
200
224
  if (wsMatch) {
@@ -213,9 +237,9 @@ function startWatcher(configDir) {
213
237
  return;
214
238
  }
215
239
  };
216
- watcher.on("add", handleChange);
217
- watcher.on("change", handleChange);
218
- watcher.on("unlink", handleChange);
240
+ watcher.on("add", (fp) => handleChange(fp, "add"));
241
+ watcher.on("change", (fp) => handleChange(fp, "change"));
242
+ watcher.on("unlink", (fp) => handleChange(fp, "unlink"));
219
243
  watcher.on("addDir", handleAddDir);
220
244
  watcher.on("unlinkDir", handleUnlinkDir);
221
245
  return () => {
@@ -223,6 +247,10 @@ function startWatcher(configDir) {
223
247
  clearTimeout(timer);
224
248
  }
225
249
  debounceTimers.clear();
250
+ for (const timer of fsDebounceTimers.values()) {
251
+ clearTimeout(timer);
252
+ }
253
+ fsDebounceTimers.clear();
226
254
  watcher.close();
227
255
  };
228
256
  }
@@ -500,7 +528,7 @@ function fullScan(configDir) {
500
528
  scanTools(configDir);
501
529
  scanMedia(configDir);
502
530
  }
503
- function registerEntityTools(api) {
531
+ function registerEntityTools(api, onFsChange) {
504
532
  const configDir = process.env.HOME + "/.openclaw";
505
533
  api.registerTool({
506
534
  name: "entity_list",
@@ -576,7 +604,7 @@ function registerEntityTools(api) {
576
604
  }
577
605
  let stopWatcher = null;
578
606
  try {
579
- stopWatcher = startWatcher(configDir);
607
+ stopWatcher = startWatcher(configDir, onFsChange);
580
608
  } catch (err2) {
581
609
  console.error("[squad-openclaw] Watcher failed to start:", err2);
582
610
  }
@@ -773,6 +801,34 @@ function registerFilesystemTools(api) {
773
801
  }
774
802
  }
775
803
  });
804
+ api.registerTool({
805
+ name: "fs_mkdir",
806
+ label: "Create Directory",
807
+ description: "Create a directory on the server filesystem. Creates parent directories as needed. Supports ~ for home directory expansion.",
808
+ parameters: {
809
+ type: "object",
810
+ properties: {
811
+ path: {
812
+ type: "string",
813
+ description: "Absolute or ~-prefixed path of the directory to create"
814
+ }
815
+ },
816
+ required: ["path"]
817
+ },
818
+ async execute(_id, params) {
819
+ try {
820
+ const targetPath = validatePath(params.path, allowedRoots);
821
+ fs3.mkdirSync(targetPath, { recursive: true });
822
+ return ok({
823
+ path: targetPath,
824
+ created: true
825
+ });
826
+ } catch (e) {
827
+ const msg = e instanceof Error ? e.message : String(e);
828
+ return err(`fs_mkdir failed: ${msg}`);
829
+ }
830
+ }
831
+ });
776
832
  api.registerTool({
777
833
  name: "fs_delete",
778
834
  label: "Delete File or Directory",
@@ -1008,7 +1064,8 @@ function readOperatorToken() {
1008
1064
  return null;
1009
1065
  }
1010
1066
  }
1011
- var RELAY_STATE_PATH = path5.join(os.homedir(), ".openclaw", "squad-relay.json");
1067
+ var RELAY_DATA_DIR = path5.join(os.homedir(), ".openclaw", "squad-ceo-data");
1068
+ var RELAY_STATE_PATH = path5.join(RELAY_DATA_DIR, "squad-relay.json");
1012
1069
  function readRelayState() {
1013
1070
  try {
1014
1071
  const raw = fs5.readFileSync(RELAY_STATE_PATH, "utf-8");
@@ -1018,9 +1075,8 @@ function readRelayState() {
1018
1075
  }
1019
1076
  }
1020
1077
  function writeRelayState(state) {
1021
- const dir = path5.dirname(RELAY_STATE_PATH);
1022
- if (!fs5.existsSync(dir)) {
1023
- fs5.mkdirSync(dir, { recursive: true });
1078
+ if (!fs5.existsSync(RELAY_DATA_DIR)) {
1079
+ fs5.mkdirSync(RELAY_DATA_DIR, { recursive: true });
1024
1080
  }
1025
1081
  fs5.writeFileSync(RELAY_STATE_PATH, JSON.stringify(state, null, 2), { mode: 384 });
1026
1082
  }
@@ -1520,6 +1576,28 @@ var RelayClient = class {
1520
1576
  } catch {
1521
1577
  }
1522
1578
  }
1579
+ /** Broadcast an event to all connected users, E2E encrypted per-user */
1580
+ broadcastToUsers(event, payload) {
1581
+ const msg = { type: "event", event, payload };
1582
+ for (const [userId, conn] of this.userConnections) {
1583
+ if (!conn.connectHandshakeComplete) continue;
1584
+ let innerMsg = msg;
1585
+ if (conn.e2e) {
1586
+ try {
1587
+ const encrypted = conn.e2e.encrypt(JSON.stringify(msg));
1588
+ innerMsg = { _e2e: true, ...encrypted };
1589
+ } catch (err2) {
1590
+ console.error(`[relay-client] E2E encrypt error for broadcast to ${userId}:`, err2);
1591
+ innerMsg = msg;
1592
+ }
1593
+ }
1594
+ this.sendToRelay({
1595
+ type: "relay.forward",
1596
+ userId,
1597
+ inner: innerMsg
1598
+ });
1599
+ }
1600
+ }
1523
1601
  };
1524
1602
  var relayClient = null;
1525
1603
  function startRelayClient(api, relayUrl) {
@@ -1547,6 +1625,9 @@ function startRelayClient(api, relayUrl) {
1547
1625
  process.on("SIGTERM", cleanup);
1548
1626
  process.on("SIGINT", cleanup);
1549
1627
  }
1628
+ function broadcastToUsers(event, payload) {
1629
+ relayClient?.broadcastToUsers(event, payload);
1630
+ }
1550
1631
 
1551
1632
  // src/index.ts
1552
1633
  function squadAppPlugin(api) {
@@ -1558,7 +1639,8 @@ function squadAppPlugin(api) {
1558
1639
  }
1559
1640
  return origRegisterTool(toolDef);
1560
1641
  };
1561
- registerEntityTools(api);
1642
+ const onFsChange = (evt) => broadcastToUsers("fs.change", evt);
1643
+ registerEntityTools(api, onFsChange);
1562
1644
  registerFilesystemTools(api);
1563
1645
  registerVersionMethods(api);
1564
1646
  api.registerGatewayMethod(
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "squad-openclaw",
3
- "version": "2026.2.1817",
3
+ "version": "2026.2.1902",
4
4
  "description": "Entity registry, filesystem tools, and version management plugin for OpenClaw gateway",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",