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.
Files changed (3) hide show
  1. package/cli.tsx +51 -3
  2. package/dist/cli.js +57 -3
  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. OpenClaw installed
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
- // 6. Plugin extension files exist
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
- // 7. Plugin enabled in OpenClaw config
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. OpenClaw installed
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
- // 6. Plugin extension files exist
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
- // 7. Plugin enabled in OpenClaw config
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.0",
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",