squad-openclaw 2026.2.2003 → 2026.2.2005
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/README.md +2 -2
- package/dist/cli.js +223 -0
- package/dist/index.d.ts +2 -2
- package/dist/index.js +54 -24
- package/openclaw.plugin.json +1 -1
- package/package.json +4 -1
package/README.md
CHANGED
|
@@ -31,7 +31,7 @@ These directories are **completely blocked** from all filesystem operations (rea
|
|
|
31
31
|
|
|
32
32
|
| Path | Reason |
|
|
33
33
|
|---|---|
|
|
34
|
-
| `~/.openclaw/squad-ceo-data/squad-relay.json` | Contains ed25519 private key for relay device identity |
|
|
34
|
+
| `~/.openclaw/squad-ceo-data/relay/squad-relay.json` | Contains ed25519 private key for relay device identity |
|
|
35
35
|
| `~/.openclaw/*.bak` | Backup files at the top level contain unredacted config (tokens, keys) that would bypass redaction |
|
|
36
36
|
|
|
37
37
|
### Layer 2: Redacted Files (hardcoded, non-configurable)
|
|
@@ -60,7 +60,7 @@ Operators can customize via the `fs.allowedRoots` config option.
|
|
|
60
60
|
These files/directories cannot be written to, even if they fall within `allowedRoots`:
|
|
61
61
|
|
|
62
62
|
- `~/.openclaw/openclaw.json` — operator configuration (read-only with redaction)
|
|
63
|
-
- `~/.openclaw/squad-ceo-data/squad-relay.json` — relay device private key
|
|
63
|
+
- `~/.openclaw/squad-ceo-data/relay/squad-relay.json` — relay device private key
|
|
64
64
|
- All blocked directories above (credentials, devices, identity)
|
|
65
65
|
- All `.bak` files at `~/.openclaw/` top level
|
|
66
66
|
|
package/dist/cli.js
ADDED
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// src/cli.ts
|
|
4
|
+
import crypto2 from "crypto";
|
|
5
|
+
import fs2 from "fs";
|
|
6
|
+
import path2 from "path";
|
|
7
|
+
import os2 from "os";
|
|
8
|
+
import { execSync } from "child_process";
|
|
9
|
+
|
|
10
|
+
// src/device-keys.ts
|
|
11
|
+
import crypto from "crypto";
|
|
12
|
+
import fs from "fs";
|
|
13
|
+
import path from "path";
|
|
14
|
+
import os from "os";
|
|
15
|
+
var RELAY_DATA_DIR = path.join(os.homedir(), ".openclaw", "squad-ceo-data", "relay");
|
|
16
|
+
var RELAY_STATE_PATH = path.join(RELAY_DATA_DIR, "squad-relay.json");
|
|
17
|
+
var PENDING_APPROVAL_PATH = path.join(RELAY_DATA_DIR, "pending-approval.json");
|
|
18
|
+
function readRelayState() {
|
|
19
|
+
try {
|
|
20
|
+
const raw = fs.readFileSync(RELAY_STATE_PATH, "utf-8");
|
|
21
|
+
return JSON.parse(raw);
|
|
22
|
+
} catch {
|
|
23
|
+
return {};
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
function writeRelayState(state) {
|
|
27
|
+
if (!fs.existsSync(RELAY_DATA_DIR)) {
|
|
28
|
+
fs.mkdirSync(RELAY_DATA_DIR, { recursive: true });
|
|
29
|
+
}
|
|
30
|
+
fs.writeFileSync(RELAY_STATE_PATH, JSON.stringify(state, null, 2), { mode: 384 });
|
|
31
|
+
}
|
|
32
|
+
function toBase64Url(buf) {
|
|
33
|
+
return buf.toString("base64").replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
|
|
34
|
+
}
|
|
35
|
+
function loadOrCreateRelayDeviceKeys() {
|
|
36
|
+
const state = readRelayState();
|
|
37
|
+
if (state.deviceKeys) {
|
|
38
|
+
return state.deviceKeys;
|
|
39
|
+
}
|
|
40
|
+
const { publicKey, privateKey } = crypto.generateKeyPairSync("ed25519");
|
|
41
|
+
const pubDer = publicKey.export({ type: "spki", format: "der" });
|
|
42
|
+
const rawPub = pubDer.subarray(pubDer.length - 32);
|
|
43
|
+
const deviceId = crypto.createHash("sha256").update(rawPub).digest("hex");
|
|
44
|
+
const publicKeyB64 = toBase64Url(rawPub);
|
|
45
|
+
const privateKeyPem = privateKey.export({ type: "pkcs8", format: "pem" });
|
|
46
|
+
const keys = { deviceId, publicKey: publicKeyB64, privateKeyPem };
|
|
47
|
+
writeRelayState({ ...state, deviceKeys: keys });
|
|
48
|
+
console.log(`[device-keys] Generated relay device identity: ${deviceId.substring(0, 12)}...`);
|
|
49
|
+
return keys;
|
|
50
|
+
}
|
|
51
|
+
function writeDeviceInfoFile(keys) {
|
|
52
|
+
const stateDir = process.env.OPENCLAW_STATE_DIR || path.join(os.homedir(), ".openclaw");
|
|
53
|
+
const infoPath = path.join(stateDir, "squad-ceo-data", "relay", "relay-device-info.json");
|
|
54
|
+
const info = {
|
|
55
|
+
deviceId: keys.deviceId,
|
|
56
|
+
publicKey: keys.publicKey,
|
|
57
|
+
displayName: "squad-relay",
|
|
58
|
+
platform: process.platform,
|
|
59
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
60
|
+
};
|
|
61
|
+
try {
|
|
62
|
+
fs.writeFileSync(infoPath, JSON.stringify(info, null, 2));
|
|
63
|
+
} catch (err) {
|
|
64
|
+
console.error("[device-keys] Failed to write relay-device-info.json:", err);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// src/cli.ts
|
|
69
|
+
var RELAY_URL = "https://relay.squad.ceo";
|
|
70
|
+
var DEVICES_DIR = path2.join(os2.homedir(), ".openclaw", "devices");
|
|
71
|
+
var PAIRED_JSON_PATH = path2.join(DEVICES_DIR, "paired.json");
|
|
72
|
+
function generateApprovalCode() {
|
|
73
|
+
const chars = "ABCDEFGHJKLMNPQRSTUVWXYZ23456789";
|
|
74
|
+
const bytes = crypto2.randomBytes(8);
|
|
75
|
+
let code = "";
|
|
76
|
+
for (let i = 0; i < 8; i++) {
|
|
77
|
+
code += chars[bytes[i] % chars.length];
|
|
78
|
+
}
|
|
79
|
+
return code;
|
|
80
|
+
}
|
|
81
|
+
function readPendingApproval() {
|
|
82
|
+
try {
|
|
83
|
+
const raw = fs2.readFileSync(PENDING_APPROVAL_PATH, "utf-8");
|
|
84
|
+
return JSON.parse(raw);
|
|
85
|
+
} catch {
|
|
86
|
+
return null;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
function writePendingApproval(approval) {
|
|
90
|
+
if (!fs2.existsSync(RELAY_DATA_DIR)) {
|
|
91
|
+
fs2.mkdirSync(RELAY_DATA_DIR, { recursive: true });
|
|
92
|
+
}
|
|
93
|
+
fs2.writeFileSync(PENDING_APPROVAL_PATH, JSON.stringify(approval, null, 2));
|
|
94
|
+
}
|
|
95
|
+
async function handleRequest() {
|
|
96
|
+
const state = readRelayState();
|
|
97
|
+
if (!state.claimToken) {
|
|
98
|
+
console.error("Error: No claim token found in squad-relay.json.");
|
|
99
|
+
console.error("Run the setup from the Squad web app first to get a claim token.");
|
|
100
|
+
process.exit(1);
|
|
101
|
+
}
|
|
102
|
+
const keys = loadOrCreateRelayDeviceKeys();
|
|
103
|
+
console.log(`Device ID: ${keys.deviceId.substring(0, 16)}...`);
|
|
104
|
+
writeDeviceInfoFile(keys);
|
|
105
|
+
const code = generateApprovalCode();
|
|
106
|
+
const approval = {
|
|
107
|
+
code,
|
|
108
|
+
deviceId: keys.deviceId,
|
|
109
|
+
createdAt: Date.now()
|
|
110
|
+
};
|
|
111
|
+
writePendingApproval(approval);
|
|
112
|
+
console.log("Sending pairing request to relay...");
|
|
113
|
+
try {
|
|
114
|
+
const res = await fetch(`${RELAY_URL}/api/relay/device-pair-request`, {
|
|
115
|
+
method: "POST",
|
|
116
|
+
headers: { "Content-Type": "application/json" },
|
|
117
|
+
body: JSON.stringify({
|
|
118
|
+
claimToken: state.claimToken,
|
|
119
|
+
deviceId: keys.deviceId,
|
|
120
|
+
publicKey: keys.publicKey,
|
|
121
|
+
code
|
|
122
|
+
})
|
|
123
|
+
});
|
|
124
|
+
if (!res.ok) {
|
|
125
|
+
const text = await res.text();
|
|
126
|
+
console.error(`Error: Relay returned ${res.status}: ${text}`);
|
|
127
|
+
process.exit(1);
|
|
128
|
+
}
|
|
129
|
+
console.log("");
|
|
130
|
+
console.log("Pairing request sent successfully.");
|
|
131
|
+
console.log("Ask the user to check their Squad dashboard for the approval command.");
|
|
132
|
+
} catch (err) {
|
|
133
|
+
console.error("Error: Failed to reach relay server:", err.message);
|
|
134
|
+
process.exit(1);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
async function handleApprove(code) {
|
|
138
|
+
const pending = readPendingApproval();
|
|
139
|
+
if (!pending) {
|
|
140
|
+
console.error("Error: No pending pairing request found.");
|
|
141
|
+
console.error("Run 'squad-pair request' first.");
|
|
142
|
+
process.exit(1);
|
|
143
|
+
}
|
|
144
|
+
if (pending.code !== code.toUpperCase()) {
|
|
145
|
+
console.error("Error: Approval code does not match.");
|
|
146
|
+
console.error("Check the code shown in the Squad dashboard and try again.");
|
|
147
|
+
process.exit(1);
|
|
148
|
+
}
|
|
149
|
+
if (Date.now() - pending.createdAt > 30 * 60 * 1e3) {
|
|
150
|
+
console.error("Error: Pairing request has expired. Run 'squad-pair request' again.");
|
|
151
|
+
try {
|
|
152
|
+
fs2.unlinkSync(PENDING_APPROVAL_PATH);
|
|
153
|
+
} catch {
|
|
154
|
+
}
|
|
155
|
+
process.exit(1);
|
|
156
|
+
}
|
|
157
|
+
const state = readRelayState();
|
|
158
|
+
if (!state.deviceKeys) {
|
|
159
|
+
console.error("Error: No device keys found. Run 'squad-pair request' first.");
|
|
160
|
+
process.exit(1);
|
|
161
|
+
}
|
|
162
|
+
const { deviceId, publicKey } = state.deviceKeys;
|
|
163
|
+
let paired = {};
|
|
164
|
+
if (!fs2.existsSync(DEVICES_DIR)) {
|
|
165
|
+
fs2.mkdirSync(DEVICES_DIR, { recursive: true });
|
|
166
|
+
}
|
|
167
|
+
try {
|
|
168
|
+
const raw = fs2.readFileSync(PAIRED_JSON_PATH, "utf-8");
|
|
169
|
+
paired = JSON.parse(raw);
|
|
170
|
+
} catch {
|
|
171
|
+
}
|
|
172
|
+
paired[deviceId] = {
|
|
173
|
+
deviceId,
|
|
174
|
+
publicKey,
|
|
175
|
+
role: "operator",
|
|
176
|
+
scopes: ["operator"],
|
|
177
|
+
approvedAtMs: Date.now(),
|
|
178
|
+
displayName: "squad-relay"
|
|
179
|
+
};
|
|
180
|
+
fs2.writeFileSync(PAIRED_JSON_PATH, JSON.stringify(paired, null, 2));
|
|
181
|
+
console.log("Device paired successfully.");
|
|
182
|
+
try {
|
|
183
|
+
fs2.unlinkSync(PENDING_APPROVAL_PATH);
|
|
184
|
+
} catch {
|
|
185
|
+
}
|
|
186
|
+
console.log("Restarting gateway...");
|
|
187
|
+
try {
|
|
188
|
+
execSync("openclaw gateway restart", { stdio: "inherit" });
|
|
189
|
+
} catch {
|
|
190
|
+
console.error("Warning: Could not restart gateway automatically.");
|
|
191
|
+
console.error("Run 'openclaw gateway restart' manually.");
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
var args = process.argv.slice(2);
|
|
195
|
+
var command = args[0];
|
|
196
|
+
switch (command) {
|
|
197
|
+
case "request":
|
|
198
|
+
handleRequest().catch((err) => {
|
|
199
|
+
console.error("Fatal error:", err);
|
|
200
|
+
process.exit(1);
|
|
201
|
+
});
|
|
202
|
+
break;
|
|
203
|
+
case "approve": {
|
|
204
|
+
const code = args[1];
|
|
205
|
+
if (!code) {
|
|
206
|
+
console.error("Usage: squad-pair approve <CODE>");
|
|
207
|
+
console.error("The approval code is shown in your Squad dashboard.");
|
|
208
|
+
process.exit(1);
|
|
209
|
+
}
|
|
210
|
+
handleApprove(code).catch((err) => {
|
|
211
|
+
console.error("Fatal error:", err);
|
|
212
|
+
process.exit(1);
|
|
213
|
+
});
|
|
214
|
+
break;
|
|
215
|
+
}
|
|
216
|
+
default:
|
|
217
|
+
console.log("squad-pair \u2014 Device pairing for Squad relay");
|
|
218
|
+
console.log("");
|
|
219
|
+
console.log("Commands:");
|
|
220
|
+
console.log(" squad-pair request Send a pairing request to the relay");
|
|
221
|
+
console.log(" squad-pair approve <CODE> Approve device pairing and restart gateway");
|
|
222
|
+
process.exit(command ? 1 : 0);
|
|
223
|
+
}
|
package/dist/index.d.ts
CHANGED
|
@@ -21,11 +21,11 @@
|
|
|
21
21
|
* │ REDACTED on read (sensitive fields replaced with "[REDACTED]"): │
|
|
22
22
|
* │ • ~/.openclaw/openclaw.json → channel.*.botToken │
|
|
23
23
|
* │ • ~/.openclaw/openclaw.json → gateway.auth.* │
|
|
24
|
-
* │ • squad-ceo-data/squad-relay.json → deviceKeys.privateKeyPem
|
|
24
|
+
* │ • squad-ceo-data/relay/squad-relay.json → deviceKeys.privateKeyPem │
|
|
25
25
|
* │ │
|
|
26
26
|
* │ WRITE-PROTECTED (no writes, deletes, or renames): │
|
|
27
27
|
* │ • ~/.openclaw/openclaw.json │
|
|
28
|
-
* │ • squad-ceo-data/squad-relay.json
|
|
28
|
+
* │ • squad-ceo-data/relay/squad-relay.json │
|
|
29
29
|
* │ • All blocked directories above │
|
|
30
30
|
* │ │
|
|
31
31
|
* │ The bundle is NOT minified to allow security auditing of the │
|
package/dist/index.js
CHANGED
|
@@ -370,7 +370,7 @@ var SENSITIVE_BLOCKED_DIRS = [
|
|
|
370
370
|
path2.join(OPENCLAW_DIR, "identity")
|
|
371
371
|
];
|
|
372
372
|
var SENSITIVE_BLOCKED_FILES = [
|
|
373
|
-
path2.join(OPENCLAW_DIR, "squad-ceo-data", "squad-relay.json")
|
|
373
|
+
path2.join(OPENCLAW_DIR, "squad-ceo-data", "relay", "squad-relay.json")
|
|
374
374
|
];
|
|
375
375
|
function isSensitivePath(resolvedPath) {
|
|
376
376
|
for (const blocked of SENSITIVE_BLOCKED_DIRS) {
|
|
@@ -1220,6 +1220,11 @@ import fs5 from "fs";
|
|
|
1220
1220
|
import path5 from "path";
|
|
1221
1221
|
import { fileURLToPath } from "url";
|
|
1222
1222
|
var PACKAGE_NAME = "squad-openclaw";
|
|
1223
|
+
var CONFIG_PATH = path5.join(
|
|
1224
|
+
process.env.HOME ?? "/root",
|
|
1225
|
+
".openclaw",
|
|
1226
|
+
"openclaw.json"
|
|
1227
|
+
);
|
|
1223
1228
|
function getCurrentVersion() {
|
|
1224
1229
|
const thisFile = fileURLToPath(import.meta.url);
|
|
1225
1230
|
const pkgPath = path5.resolve(path5.dirname(thisFile), "..", "package.json");
|
|
@@ -1279,6 +1284,18 @@ function registerVersionMethods(api) {
|
|
|
1279
1284
|
try {
|
|
1280
1285
|
const before = getCurrentVersion();
|
|
1281
1286
|
let updateOutput = "";
|
|
1287
|
+
let configBackup = null;
|
|
1288
|
+
try {
|
|
1289
|
+
configBackup = fs5.readFileSync(CONFIG_PATH, "utf-8");
|
|
1290
|
+
} catch {
|
|
1291
|
+
}
|
|
1292
|
+
try {
|
|
1293
|
+
execSync2("openclaw doctor --fix 2>&1", {
|
|
1294
|
+
timeout: 3e4,
|
|
1295
|
+
encoding: "utf-8"
|
|
1296
|
+
});
|
|
1297
|
+
} catch {
|
|
1298
|
+
}
|
|
1282
1299
|
try {
|
|
1283
1300
|
updateOutput = execSync2(
|
|
1284
1301
|
`openclaw plugins update ${PACKAGE_NAME} 2>&1`,
|
|
@@ -1291,6 +1308,12 @@ function registerVersionMethods(api) {
|
|
|
1291
1308
|
{ timeout: 12e4, encoding: "utf-8" }
|
|
1292
1309
|
);
|
|
1293
1310
|
} catch (npmErr) {
|
|
1311
|
+
if (configBackup) {
|
|
1312
|
+
try {
|
|
1313
|
+
fs5.writeFileSync(CONFIG_PATH, configBackup, "utf-8");
|
|
1314
|
+
} catch {
|
|
1315
|
+
}
|
|
1316
|
+
}
|
|
1294
1317
|
const msg = npmErr instanceof Error ? npmErr.message : String(npmErr);
|
|
1295
1318
|
respond(false, {
|
|
1296
1319
|
error: `Update failed: ${msg}`,
|
|
@@ -1329,10 +1352,10 @@ function registerVersionMethods(api) {
|
|
|
1329
1352
|
|
|
1330
1353
|
// src/relay-client.ts
|
|
1331
1354
|
import { WebSocket as NodeWebSocket } from "ws";
|
|
1332
|
-
import
|
|
1333
|
-
import
|
|
1334
|
-
import
|
|
1335
|
-
import
|
|
1355
|
+
import crypto3 from "crypto";
|
|
1356
|
+
import fs7 from "fs";
|
|
1357
|
+
import path7 from "path";
|
|
1358
|
+
import os2 from "os";
|
|
1336
1359
|
|
|
1337
1360
|
// src/e2e-crypto.ts
|
|
1338
1361
|
import crypto from "crypto";
|
|
@@ -1411,20 +1434,14 @@ var E2ECrypto = class {
|
|
|
1411
1434
|
}
|
|
1412
1435
|
};
|
|
1413
1436
|
|
|
1414
|
-
// src/
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
const config = JSON.parse(raw);
|
|
1421
|
-
return config?.gateway?.auth?.token ?? config?.gateway?.remote?.token ?? config?.gateway?.token ?? null;
|
|
1422
|
-
} catch {
|
|
1423
|
-
return null;
|
|
1424
|
-
}
|
|
1425
|
-
}
|
|
1426
|
-
var RELAY_DATA_DIR = path6.join(os.homedir(), ".openclaw", "squad-ceo-data");
|
|
1437
|
+
// src/device-keys.ts
|
|
1438
|
+
import crypto2 from "crypto";
|
|
1439
|
+
import fs6 from "fs";
|
|
1440
|
+
import path6 from "path";
|
|
1441
|
+
import os from "os";
|
|
1442
|
+
var RELAY_DATA_DIR = path6.join(os.homedir(), ".openclaw", "squad-ceo-data", "relay");
|
|
1427
1443
|
var RELAY_STATE_PATH = path6.join(RELAY_DATA_DIR, "squad-relay.json");
|
|
1444
|
+
var PENDING_APPROVAL_PATH = path6.join(RELAY_DATA_DIR, "pending-approval.json");
|
|
1428
1445
|
function readRelayState() {
|
|
1429
1446
|
try {
|
|
1430
1447
|
const raw = fs6.readFileSync(RELAY_STATE_PATH, "utf-8");
|
|
@@ -1455,12 +1472,12 @@ function loadOrCreateRelayDeviceKeys() {
|
|
|
1455
1472
|
const privateKeyPem = privateKey.export({ type: "pkcs8", format: "pem" });
|
|
1456
1473
|
const keys = { deviceId, publicKey: publicKeyB64, privateKeyPem };
|
|
1457
1474
|
writeRelayState({ ...state, deviceKeys: keys });
|
|
1458
|
-
console.log(`[
|
|
1475
|
+
console.log(`[device-keys] Generated relay device identity: ${deviceId.substring(0, 12)}...`);
|
|
1459
1476
|
return keys;
|
|
1460
1477
|
}
|
|
1461
1478
|
function writeDeviceInfoFile(keys) {
|
|
1462
1479
|
const stateDir = process.env.OPENCLAW_STATE_DIR || path6.join(os.homedir(), ".openclaw");
|
|
1463
|
-
const infoPath = path6.join(stateDir, "squad-ceo-data", "relay-device-info.json");
|
|
1480
|
+
const infoPath = path6.join(stateDir, "squad-ceo-data", "relay", "relay-device-info.json");
|
|
1464
1481
|
const info = {
|
|
1465
1482
|
deviceId: keys.deviceId,
|
|
1466
1483
|
publicKey: keys.publicKey,
|
|
@@ -1471,16 +1488,29 @@ function writeDeviceInfoFile(keys) {
|
|
|
1471
1488
|
try {
|
|
1472
1489
|
fs6.writeFileSync(infoPath, JSON.stringify(info, null, 2));
|
|
1473
1490
|
} catch (err2) {
|
|
1474
|
-
console.error("[
|
|
1491
|
+
console.error("[device-keys] Failed to write relay-device-info.json:", err2);
|
|
1492
|
+
}
|
|
1493
|
+
}
|
|
1494
|
+
|
|
1495
|
+
// src/relay-client.ts
|
|
1496
|
+
function readOperatorToken() {
|
|
1497
|
+
const stateDir = process.env.OPENCLAW_STATE_DIR || path7.join(os2.homedir(), ".openclaw");
|
|
1498
|
+
const configPath = path7.join(stateDir, "openclaw.json");
|
|
1499
|
+
try {
|
|
1500
|
+
const raw = fs7.readFileSync(configPath, "utf-8");
|
|
1501
|
+
const config = JSON.parse(raw);
|
|
1502
|
+
return config?.gateway?.auth?.token ?? config?.gateway?.remote?.token ?? config?.gateway?.token ?? null;
|
|
1503
|
+
} catch {
|
|
1504
|
+
return null;
|
|
1475
1505
|
}
|
|
1476
1506
|
}
|
|
1477
1507
|
function signDeviceIdentity(keys, clientId, clientMode, role, scopes, token, challengeNonce) {
|
|
1478
1508
|
const signedAtMs = Date.now();
|
|
1479
|
-
const nonce = challengeNonce ||
|
|
1509
|
+
const nonce = challengeNonce || crypto3.randomBytes(16).toString("hex");
|
|
1480
1510
|
const scopeStr = scopes.join(",");
|
|
1481
1511
|
const payload = `v2|${keys.deviceId}|${clientId}|${clientMode}|${role}|${scopeStr}|${signedAtMs}|${token ?? ""}|${nonce}`;
|
|
1482
|
-
const privateKey =
|
|
1483
|
-
const signature =
|
|
1512
|
+
const privateKey = crypto3.createPrivateKey(keys.privateKeyPem);
|
|
1513
|
+
const signature = crypto3.sign(null, Buffer.from(payload), privateKey);
|
|
1484
1514
|
return {
|
|
1485
1515
|
id: keys.deviceId,
|
|
1486
1516
|
publicKey: keys.publicKey,
|
package/openclaw.plugin.json
CHANGED
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
"type": "array",
|
|
11
11
|
"items": { "type": "string" },
|
|
12
12
|
"default": ["~/.openclaw"],
|
|
13
|
-
"description": "Restrict filesystem operations to these directories. Defaults to [\"~/.openclaw\"]. Hardcoded blocks on credentials/, devices/, identity/, squad-relay.json, and .bak files always apply."
|
|
13
|
+
"description": "Restrict filesystem operations to these directories. Defaults to [\"~/.openclaw\"]. Hardcoded blocks on credentials/, devices/, identity/, relay/squad-relay.json, and .bak files always apply."
|
|
14
14
|
},
|
|
15
15
|
"relay.enabled": {
|
|
16
16
|
"type": "boolean",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "squad-openclaw",
|
|
3
|
-
"version": "2026.2.
|
|
3
|
+
"version": "2026.2.2005",
|
|
4
4
|
"description": "Entity registry, filesystem tools, and version management plugin for OpenClaw gateway",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -16,6 +16,9 @@
|
|
|
16
16
|
"./dist/index.js"
|
|
17
17
|
]
|
|
18
18
|
},
|
|
19
|
+
"bin": {
|
|
20
|
+
"squad-pair": "./dist/cli.js"
|
|
21
|
+
},
|
|
19
22
|
"license": "MIT",
|
|
20
23
|
"files": [
|
|
21
24
|
"dist/",
|