squad-openclaw 2026.2.1816 → 2026.2.1901
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/dist/index.d.ts +1 -1
- package/dist/index.js +129 -12
- package/openclaw.plugin.json +1 -1
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Provides:
|
|
5
5
|
* - In-memory entity registry with filesystem watching (entity_list, entity_search, entity_sync)
|
|
6
|
-
* - Filesystem tools for remote clients (fs_read, fs_write, fs_list)
|
|
6
|
+
* - Filesystem tools for remote clients (fs_read, fs_write, fs_list, fs_delete)
|
|
7
7
|
* - Version check and self-update gateway methods (squad.version.*)
|
|
8
8
|
* - Cloud relay client for remote browser access (relay-client)
|
|
9
9
|
*/
|
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
|
|
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,69 @@ 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
|
+
});
|
|
832
|
+
api.registerTool({
|
|
833
|
+
name: "fs_delete",
|
|
834
|
+
label: "Delete File or Directory",
|
|
835
|
+
description: "Delete a file or directory from the server filesystem. For directories, removes recursively. Supports ~ for home directory expansion.",
|
|
836
|
+
parameters: {
|
|
837
|
+
type: "object",
|
|
838
|
+
properties: {
|
|
839
|
+
path: {
|
|
840
|
+
type: "string",
|
|
841
|
+
description: "Absolute or ~-prefixed path to the file or directory to delete"
|
|
842
|
+
}
|
|
843
|
+
},
|
|
844
|
+
required: ["path"]
|
|
845
|
+
},
|
|
846
|
+
async execute(_id, params) {
|
|
847
|
+
try {
|
|
848
|
+
const targetPath = validatePath(params.path, allowedRoots);
|
|
849
|
+
const stat = fs3.statSync(targetPath);
|
|
850
|
+
const wasDirectory = stat.isDirectory();
|
|
851
|
+
if (wasDirectory) {
|
|
852
|
+
fs3.rmSync(targetPath, { recursive: true });
|
|
853
|
+
} else {
|
|
854
|
+
fs3.unlinkSync(targetPath);
|
|
855
|
+
}
|
|
856
|
+
return ok({
|
|
857
|
+
path: targetPath,
|
|
858
|
+
deleted: true,
|
|
859
|
+
type: wasDirectory ? "directory" : "file"
|
|
860
|
+
});
|
|
861
|
+
} catch (e) {
|
|
862
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
863
|
+
return err(`fs_delete failed: ${msg}`);
|
|
864
|
+
}
|
|
865
|
+
}
|
|
866
|
+
});
|
|
776
867
|
}
|
|
777
868
|
|
|
778
869
|
// src/version.ts
|
|
@@ -973,7 +1064,8 @@ function readOperatorToken() {
|
|
|
973
1064
|
return null;
|
|
974
1065
|
}
|
|
975
1066
|
}
|
|
976
|
-
var
|
|
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");
|
|
977
1069
|
function readRelayState() {
|
|
978
1070
|
try {
|
|
979
1071
|
const raw = fs5.readFileSync(RELAY_STATE_PATH, "utf-8");
|
|
@@ -983,9 +1075,8 @@ function readRelayState() {
|
|
|
983
1075
|
}
|
|
984
1076
|
}
|
|
985
1077
|
function writeRelayState(state) {
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
fs5.mkdirSync(dir, { recursive: true });
|
|
1078
|
+
if (!fs5.existsSync(RELAY_DATA_DIR)) {
|
|
1079
|
+
fs5.mkdirSync(RELAY_DATA_DIR, { recursive: true });
|
|
989
1080
|
}
|
|
990
1081
|
fs5.writeFileSync(RELAY_STATE_PATH, JSON.stringify(state, null, 2), { mode: 384 });
|
|
991
1082
|
}
|
|
@@ -1485,6 +1576,28 @@ var RelayClient = class {
|
|
|
1485
1576
|
} catch {
|
|
1486
1577
|
}
|
|
1487
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
|
+
}
|
|
1488
1601
|
};
|
|
1489
1602
|
var relayClient = null;
|
|
1490
1603
|
function startRelayClient(api, relayUrl) {
|
|
@@ -1512,6 +1625,9 @@ function startRelayClient(api, relayUrl) {
|
|
|
1512
1625
|
process.on("SIGTERM", cleanup);
|
|
1513
1626
|
process.on("SIGINT", cleanup);
|
|
1514
1627
|
}
|
|
1628
|
+
function broadcastToUsers(event, payload) {
|
|
1629
|
+
relayClient?.broadcastToUsers(event, payload);
|
|
1630
|
+
}
|
|
1515
1631
|
|
|
1516
1632
|
// src/index.ts
|
|
1517
1633
|
function squadAppPlugin(api) {
|
|
@@ -1523,7 +1639,8 @@ function squadAppPlugin(api) {
|
|
|
1523
1639
|
}
|
|
1524
1640
|
return origRegisterTool(toolDef);
|
|
1525
1641
|
};
|
|
1526
|
-
|
|
1642
|
+
const onFsChange = (evt) => broadcastToUsers("fs.change", evt);
|
|
1643
|
+
registerEntityTools(api, onFsChange);
|
|
1527
1644
|
registerFilesystemTools(api);
|
|
1528
1645
|
registerVersionMethods(api);
|
|
1529
1646
|
api.registerGatewayMethod(
|
package/openclaw.plugin.json
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
"fs.allowedRoots": {
|
|
10
10
|
"type": "array",
|
|
11
11
|
"items": { "type": "string" },
|
|
12
|
-
"description": "Restrict fs_read/fs_write/fs_list to these directories. Empty or omitted = allow all."
|
|
12
|
+
"description": "Restrict fs_read/fs_write/fs_list/fs_delete to these directories. Empty or omitted = allow all."
|
|
13
13
|
},
|
|
14
14
|
"relay.enabled": {
|
|
15
15
|
"type": "boolean",
|
package/package.json
CHANGED