openclaw-safeclaw-plugin 0.9.0 → 0.9.1
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/cli.tsx +51 -3
- package/dist/cli.js +57 -3
- package/package.json +1 -1
package/cli.tsx
CHANGED
|
@@ -267,7 +267,55 @@ if (command === 'connect') {
|
|
|
267
267
|
}
|
|
268
268
|
}
|
|
269
269
|
|
|
270
|
-
// 5.
|
|
270
|
+
// 5. Handshake — validates API key actually works
|
|
271
|
+
if (serviceHealthy && cfg.apiKey) {
|
|
272
|
+
try {
|
|
273
|
+
const res = await fetch(`${cfg.serviceUrl}/handshake`, {
|
|
274
|
+
method: 'POST',
|
|
275
|
+
headers: {
|
|
276
|
+
'Content-Type': 'application/json',
|
|
277
|
+
'Authorization': `Bearer ${cfg.apiKey}`,
|
|
278
|
+
},
|
|
279
|
+
body: JSON.stringify({ pluginVersion: '0.1.3', configHash: '' }),
|
|
280
|
+
signal: AbortSignal.timeout(cfg.timeoutMs),
|
|
281
|
+
});
|
|
282
|
+
if (res.ok) {
|
|
283
|
+
const data = await res.json() as Record<string, unknown>;
|
|
284
|
+
console.log(`[ok] Handshake: org=${data.orgId}, scope=${data.scope}, engine=${data.engineReady ? 'ready' : 'not ready'}`);
|
|
285
|
+
} else {
|
|
286
|
+
let detail = `HTTP ${res.status}`;
|
|
287
|
+
try {
|
|
288
|
+
const body = await res.json() as Record<string, unknown>;
|
|
289
|
+
detail = (body.error ?? body.detail ?? detail) as string;
|
|
290
|
+
} catch { /* ignore parse errors */ }
|
|
291
|
+
console.log(`[!!] Handshake failed: ${detail}`);
|
|
292
|
+
if (res.status === 401) {
|
|
293
|
+
console.log(' ↳ API key is invalid or revoked. Get a new key at https://safeclaw.eu/dashboard');
|
|
294
|
+
} else if (res.status === 403) {
|
|
295
|
+
console.log(' ↳ API key lacks required scope. Check key permissions in your dashboard.');
|
|
296
|
+
} else if (res.status === 500) {
|
|
297
|
+
console.log(' ↳ Server error — check service logs for details.');
|
|
298
|
+
}
|
|
299
|
+
allOk = false;
|
|
300
|
+
}
|
|
301
|
+
} catch (e) {
|
|
302
|
+
const isTimeout = e instanceof DOMException && e.name === 'TimeoutError';
|
|
303
|
+
if (isTimeout) {
|
|
304
|
+
console.log(`[!!] Handshake failed: timeout after ${cfg.timeoutMs}ms`);
|
|
305
|
+
console.log(' ↳ Service may be overloaded. Try increasing SAFECLAW_TIMEOUT_MS.');
|
|
306
|
+
} else {
|
|
307
|
+
console.log('[!!] Handshake failed: could not connect');
|
|
308
|
+
console.log(` ↳ Is the service running at ${cfg.serviceUrl}?`);
|
|
309
|
+
}
|
|
310
|
+
allOk = false;
|
|
311
|
+
}
|
|
312
|
+
} else if (serviceHealthy && !cfg.apiKey) {
|
|
313
|
+
console.log('[!!] Handshake: skipped — no API key configured');
|
|
314
|
+
console.log(' ↳ Run: safeclaw connect <your-api-key>');
|
|
315
|
+
allOk = false;
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
// 6. OpenClaw installed
|
|
271
319
|
try {
|
|
272
320
|
execSync('which openclaw', { encoding: 'utf-8', stdio: 'pipe' });
|
|
273
321
|
console.log('[ok] OpenClaw: installed');
|
|
@@ -276,7 +324,7 @@ if (command === 'connect') {
|
|
|
276
324
|
allOk = false;
|
|
277
325
|
}
|
|
278
326
|
|
|
279
|
-
//
|
|
327
|
+
// 7. Plugin extension files exist
|
|
280
328
|
const extensionDir = join(homedir(), '.openclaw', 'extensions', 'safeclaw');
|
|
281
329
|
const hasManifest = existsSync(join(extensionDir, 'openclaw.plugin.json'));
|
|
282
330
|
const hasEntry = existsSync(join(extensionDir, 'index.js'));
|
|
@@ -295,7 +343,7 @@ if (command === 'connect') {
|
|
|
295
343
|
allOk = false;
|
|
296
344
|
}
|
|
297
345
|
|
|
298
|
-
//
|
|
346
|
+
// 8. Plugin enabled in OpenClaw config
|
|
299
347
|
const ocConfigPath = join(homedir(), '.openclaw', 'openclaw.json');
|
|
300
348
|
if (existsSync(ocConfigPath)) {
|
|
301
349
|
const ocConfig = readJson(ocConfigPath);
|
package/dist/cli.js
CHANGED
|
@@ -261,7 +261,61 @@ else if (command === 'status') {
|
|
|
261
261
|
allOk = false;
|
|
262
262
|
}
|
|
263
263
|
}
|
|
264
|
-
// 5.
|
|
264
|
+
// 5. Handshake — validates API key actually works
|
|
265
|
+
if (serviceHealthy && cfg.apiKey) {
|
|
266
|
+
try {
|
|
267
|
+
const res = await fetch(`${cfg.serviceUrl}/handshake`, {
|
|
268
|
+
method: 'POST',
|
|
269
|
+
headers: {
|
|
270
|
+
'Content-Type': 'application/json',
|
|
271
|
+
'Authorization': `Bearer ${cfg.apiKey}`,
|
|
272
|
+
},
|
|
273
|
+
body: JSON.stringify({ pluginVersion: '0.1.3', configHash: '' }),
|
|
274
|
+
signal: AbortSignal.timeout(cfg.timeoutMs),
|
|
275
|
+
});
|
|
276
|
+
if (res.ok) {
|
|
277
|
+
const data = await res.json();
|
|
278
|
+
console.log(`[ok] Handshake: org=${data.orgId}, scope=${data.scope}, engine=${data.engineReady ? 'ready' : 'not ready'}`);
|
|
279
|
+
}
|
|
280
|
+
else {
|
|
281
|
+
let detail = `HTTP ${res.status}`;
|
|
282
|
+
try {
|
|
283
|
+
const body = await res.json();
|
|
284
|
+
detail = (body.error ?? body.detail ?? detail);
|
|
285
|
+
}
|
|
286
|
+
catch { /* ignore parse errors */ }
|
|
287
|
+
console.log(`[!!] Handshake failed: ${detail}`);
|
|
288
|
+
if (res.status === 401) {
|
|
289
|
+
console.log(' ↳ API key is invalid or revoked. Get a new key at https://safeclaw.eu/dashboard');
|
|
290
|
+
}
|
|
291
|
+
else if (res.status === 403) {
|
|
292
|
+
console.log(' ↳ API key lacks required scope. Check key permissions in your dashboard.');
|
|
293
|
+
}
|
|
294
|
+
else if (res.status === 500) {
|
|
295
|
+
console.log(' ↳ Server error — check service logs for details.');
|
|
296
|
+
}
|
|
297
|
+
allOk = false;
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
catch (e) {
|
|
301
|
+
const isTimeout = e instanceof DOMException && e.name === 'TimeoutError';
|
|
302
|
+
if (isTimeout) {
|
|
303
|
+
console.log(`[!!] Handshake failed: timeout after ${cfg.timeoutMs}ms`);
|
|
304
|
+
console.log(' ↳ Service may be overloaded. Try increasing SAFECLAW_TIMEOUT_MS.');
|
|
305
|
+
}
|
|
306
|
+
else {
|
|
307
|
+
console.log('[!!] Handshake failed: could not connect');
|
|
308
|
+
console.log(` ↳ Is the service running at ${cfg.serviceUrl}?`);
|
|
309
|
+
}
|
|
310
|
+
allOk = false;
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
else if (serviceHealthy && !cfg.apiKey) {
|
|
314
|
+
console.log('[!!] Handshake: skipped — no API key configured');
|
|
315
|
+
console.log(' ↳ Run: safeclaw connect <your-api-key>');
|
|
316
|
+
allOk = false;
|
|
317
|
+
}
|
|
318
|
+
// 6. OpenClaw installed
|
|
265
319
|
try {
|
|
266
320
|
execSync('which openclaw', { encoding: 'utf-8', stdio: 'pipe' });
|
|
267
321
|
console.log('[ok] OpenClaw: installed');
|
|
@@ -270,7 +324,7 @@ else if (command === 'status') {
|
|
|
270
324
|
console.log('[!!] OpenClaw: not found in PATH');
|
|
271
325
|
allOk = false;
|
|
272
326
|
}
|
|
273
|
-
//
|
|
327
|
+
// 7. Plugin extension files exist
|
|
274
328
|
const extensionDir = join(homedir(), '.openclaw', 'extensions', 'safeclaw');
|
|
275
329
|
const hasManifest = existsSync(join(extensionDir, 'openclaw.plugin.json'));
|
|
276
330
|
const hasEntry = existsSync(join(extensionDir, 'index.js'));
|
|
@@ -291,7 +345,7 @@ else if (command === 'status') {
|
|
|
291
345
|
console.log('[!!] Plugin: not installed. Run: safeclaw setup');
|
|
292
346
|
allOk = false;
|
|
293
347
|
}
|
|
294
|
-
//
|
|
348
|
+
// 8. Plugin enabled in OpenClaw config
|
|
295
349
|
const ocConfigPath = join(homedir(), '.openclaw', 'openclaw.json');
|
|
296
350
|
if (existsSync(ocConfigPath)) {
|
|
297
351
|
const ocConfig = readJson(ocConfigPath);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "openclaw-safeclaw-plugin",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.1",
|
|
4
4
|
"description": "SafeClaw Neurosymbolic Governance plugin for OpenClaw — validates AI agent actions against OWL ontologies and SHACL constraints",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|