openclaw-safeclaw-plugin 1.0.0 → 1.1.0

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 CHANGED
@@ -15,8 +15,8 @@ npm install -g openclaw-safeclaw-plugin
15
15
 
16
16
  ```bash
17
17
  npm install -g openclaw-safeclaw-plugin
18
- safeclaw connect <your-api-key>
19
- safeclaw restart-openclaw
18
+ safeclaw-plugin connect <your-api-key>
19
+ safeclaw-plugin restart-openclaw
20
20
  ```
21
21
 
22
22
  That's it. Every tool call your AI agent makes is now governed by SafeClaw.
@@ -24,10 +24,12 @@ That's it. Every tool call your AI agent makes is now governed by SafeClaw.
24
24
  ## Commands
25
25
 
26
26
  ```
27
- safeclaw connect <api-key> Connect to SafeClaw and register with OpenClaw
28
- safeclaw setup Register plugin with OpenClaw (no key needed)
29
- safeclaw tui Open the interactive settings TUI
30
- safeclaw restart-openclaw Restart the OpenClaw daemon
27
+ safeclaw-plugin connect <api-key> Connect to SafeClaw and register with OpenClaw
28
+ safeclaw-plugin setup Register plugin with OpenClaw (no key needed)
29
+ safeclaw-plugin config show Show current plugin configuration
30
+ safeclaw-plugin config set <k> <v> Set a plugin configuration value
31
+ safeclaw-plugin tui Open the interactive settings TUI
32
+ safeclaw-plugin restart-openclaw Restart the OpenClaw daemon
31
33
  ```
32
34
 
33
35
  ## What It Does
@@ -55,7 +57,7 @@ Set via environment variables or `~/.safeclaw/config.json`:
55
57
  | Variable | Default | Description |
56
58
  |----------|---------|-------------|
57
59
  | `SAFECLAW_URL` | `https://api.safeclaw.eu/api/v1` | SafeClaw service URL |
58
- | `SAFECLAW_API_KEY` | *(empty)* | API key (set automatically by `safeclaw connect`) |
60
+ | `SAFECLAW_API_KEY` | *(empty)* | API key (set automatically by `safeclaw-plugin connect`) |
59
61
  | `SAFECLAW_TIMEOUT_MS` | `5000` | Request timeout in ms |
60
62
  | `SAFECLAW_ENABLED` | `true` | Set `false` to disable |
61
63
  | `SAFECLAW_ENFORCEMENT` | `enforce` | `enforce`, `warn-only`, `audit-only`, or `disabled` |
package/cli.tsx CHANGED
@@ -2,14 +2,15 @@
2
2
  import React from 'react';
3
3
  import { render } from 'ink';
4
4
  import { execSync } from 'child_process';
5
- import { readFileSync, writeFileSync, mkdirSync, chmodSync, existsSync, copyFileSync, lstatSync, unlinkSync, rmSync } from 'fs';
5
+ import { readFileSync, writeFileSync, mkdirSync, existsSync, copyFileSync, lstatSync, unlinkSync, rmSync } from 'fs';
6
6
  import { join, dirname } from 'path';
7
7
  import { homedir } from 'os';
8
8
  import { fileURLToPath } from 'url';
9
9
  import App from './tui/App.js';
10
- import { loadConfig } from './tui/config.js';
10
+ import { loadConfig, saveConfig, type SafeClawConfig } from './tui/config.js';
11
11
 
12
12
  const __dirname = dirname(fileURLToPath(import.meta.url));
13
+ const PKG_VERSION = JSON.parse(readFileSync(join(__dirname, '..', 'package.json'), 'utf-8')).version as string;
13
14
 
14
15
  function readJson(path: string): Record<string, unknown> {
15
16
  try {
@@ -91,7 +92,10 @@ function registerWithOpenClaw(): boolean {
91
92
  const args = process.argv.slice(2);
92
93
  const command = args[0];
93
94
 
94
- if (command === 'connect') {
95
+ // Handle --help / -h for any command position
96
+ if (!command || command === '--help' || command === '-h' || command === 'help') {
97
+ // Fall through to the else block at the bottom which prints full help
98
+ } else if (command === 'connect') {
95
99
  const apiKey = args[1];
96
100
  const serviceUrlIdx = args.indexOf('--service-url');
97
101
  const serviceUrl = serviceUrlIdx !== -1 && args[serviceUrlIdx + 1]
@@ -99,7 +103,7 @@ if (command === 'connect') {
99
103
  : 'https://api.safeclaw.eu/api/v1';
100
104
 
101
105
  if (!apiKey || apiKey.startsWith('--')) {
102
- console.error('Usage: safeclaw connect <api-key> [--service-url <url>]');
106
+ console.error('Usage: safeclaw-plugin connect <api-key> [--service-url <url>]');
103
107
  process.exit(1);
104
108
  }
105
109
 
@@ -129,10 +133,9 @@ if (command === 'connect') {
129
133
  (config.remote as Record<string, string>).apiKey = apiKey;
130
134
  (config.remote as Record<string, string>).serviceUrl = serviceUrl;
131
135
 
132
- // Write config with owner-only permissions
133
- mkdirSync(configDir, { recursive: true });
134
- writeFileSync(configPath, JSON.stringify(config, null, 2) + '\n');
135
- chmodSync(configPath, 0o600);
136
+ // Write config with owner-only permissions (atomic mode via writeFileSync option)
137
+ mkdirSync(configDir, { recursive: true, mode: 0o700 });
138
+ writeFileSync(configPath, JSON.stringify(config, null, 2) + '\n', { mode: 0o600 });
136
139
 
137
140
  console.log(`API key saved to ${configPath}`);
138
141
 
@@ -144,7 +147,7 @@ if (command === 'connect') {
144
147
  'Content-Type': 'application/json',
145
148
  'Authorization': `Bearer ${apiKey}`,
146
149
  },
147
- body: JSON.stringify({ pluginVersion: '0.1.3', configHash: '' }),
150
+ body: JSON.stringify({ pluginVersion: PKG_VERSION, configHash: '' }),
148
151
  signal: AbortSignal.timeout(5000),
149
152
  });
150
153
  if (res.ok) {
@@ -163,7 +166,7 @@ if (command === 'connect') {
163
166
  }
164
167
  } catch {
165
168
  console.warn(`Warning: API key saved but could not reach ${serviceUrl}`);
166
- console.warn('Run "safeclaw status" later to verify the connection.');
169
+ console.warn('Run "safeclaw-plugin status" later to verify the connection.');
167
170
  }
168
171
 
169
172
  // Register with OpenClaw
@@ -173,13 +176,83 @@ if (command === 'connect') {
173
176
  console.log('SafeClaw plugin registered with OpenClaw.');
174
177
  console.log('');
175
178
  console.log('Restart OpenClaw to activate:');
176
- console.log(' safeclaw restart-openclaw');
179
+ console.log(' safeclaw-plugin restart-openclaw');
177
180
  } else {
178
181
  console.log('');
179
182
  console.log('Could not auto-register with OpenClaw.');
180
183
  console.log('Register manually:');
181
184
  console.log(' openclaw plugins install openclaw-safeclaw-plugin');
182
185
  }
186
+ } else if (command === 'config') {
187
+ const subcommand = args[1];
188
+
189
+ if (subcommand === 'show') {
190
+ const cfg = loadConfig();
191
+ console.log(`enabled: ${cfg.enabled}`);
192
+ console.log(`enforcement: ${cfg.enforcement}`);
193
+ console.log(`failMode: ${cfg.failMode}`);
194
+ console.log(`serviceUrl: ${cfg.serviceUrl}`);
195
+ console.log(`apiKey: ${cfg.apiKey ? `${cfg.apiKey.slice(0, 6)}...` : '(not set)'}`);
196
+ console.log(`timeoutMs: ${cfg.timeoutMs}`);
197
+ } else if (subcommand === 'set') {
198
+ const key = args[2];
199
+ const value = args[3];
200
+
201
+ if (!key || !value) {
202
+ console.error('Usage: safeclaw-plugin config set <key> <value>');
203
+ console.error('');
204
+ console.error('Keys:');
205
+ console.error(' enforcement enforce | warn-only | audit-only | disabled');
206
+ console.error(' failMode open | closed');
207
+ console.error(' enabled true | false');
208
+ console.error(' serviceUrl https://...');
209
+ process.exit(1);
210
+ }
211
+
212
+ const cfg = loadConfig();
213
+ const validEnforcement = ['enforce', 'warn-only', 'audit-only', 'disabled'] as const;
214
+ const validFailModes = ['open', 'closed'] as const;
215
+
216
+ if (key === 'enforcement') {
217
+ if (!validEnforcement.includes(value as any)) {
218
+ console.error(`Invalid enforcement mode: "${value}". Valid: ${validEnforcement.join(', ')}`);
219
+ process.exit(1);
220
+ }
221
+ cfg.enforcement = value as SafeClawConfig['enforcement'];
222
+ } else if (key === 'failMode') {
223
+ if (!validFailModes.includes(value as any)) {
224
+ console.error(`Invalid fail mode: "${value}". Valid: ${validFailModes.join(', ')}`);
225
+ process.exit(1);
226
+ }
227
+ cfg.failMode = value as SafeClawConfig['failMode'];
228
+ } else if (key === 'enabled') {
229
+ if (value !== 'true' && value !== 'false') {
230
+ console.error('Invalid value for enabled: must be "true" or "false"');
231
+ process.exit(1);
232
+ }
233
+ cfg.enabled = value === 'true';
234
+ } else if (key === 'serviceUrl') {
235
+ cfg.serviceUrl = value;
236
+ } else {
237
+ console.error(`Unknown config key: "${key}"`);
238
+ console.error('Valid keys: enforcement, failMode, enabled, serviceUrl');
239
+ process.exit(1);
240
+ }
241
+
242
+ try {
243
+ saveConfig(cfg);
244
+ } catch (e) {
245
+ console.error(`Error: ${e instanceof Error ? e.message : e}`);
246
+ process.exit(1);
247
+ }
248
+ console.log(`Set ${key} = ${value}`);
249
+ } else {
250
+ console.error('Usage: safeclaw-plugin config <show|set>');
251
+ console.error('');
252
+ console.error(' show Display all current config values');
253
+ console.error(' set <k> <v> Set a config value (enforcement, failMode, enabled, serviceUrl)');
254
+ process.exit(1);
255
+ }
183
256
  } else if (command === 'tui') {
184
257
  render(React.createElement(App));
185
258
  } else if (command === 'restart-openclaw') {
@@ -200,8 +273,8 @@ if (command === 'connect') {
200
273
  console.log('');
201
274
  console.log('Next steps:');
202
275
  console.log(' 1. Get an API key at https://safeclaw.eu/dashboard');
203
- console.log(' 2. Run: safeclaw connect <your-api-key>');
204
- console.log(' 3. Run: safeclaw restart-openclaw');
276
+ console.log(' 2. Run: safeclaw-plugin connect <your-api-key>');
277
+ console.log(' 3. Run: safeclaw-plugin restart-openclaw');
205
278
  } else {
206
279
  console.log('Could not auto-register.');
207
280
  console.log('Try: openclaw plugins install openclaw-safeclaw-plugin');
@@ -220,7 +293,7 @@ if (command === 'connect') {
220
293
  if (existsSync(configPath)) {
221
294
  console.log('[ok] Config file: ' + configPath);
222
295
  } else {
223
- console.log('[!!] Config file not found. Run: safeclaw connect <api-key>');
296
+ console.log('[!!] Config file not found. Run: safeclaw-plugin connect <api-key>');
224
297
  allOk = false;
225
298
  }
226
299
 
@@ -231,7 +304,7 @@ if (command === 'connect') {
231
304
  console.log('[!!] API key: invalid (must start with sc_)');
232
305
  allOk = false;
233
306
  } else {
234
- console.log('[!!] API key: not set. Run: safeclaw connect <api-key>');
307
+ console.log('[!!] API key: not set. Run: safeclaw-plugin connect <api-key>');
235
308
  allOk = false;
236
309
  }
237
310
 
@@ -306,7 +379,7 @@ if (command === 'connect') {
306
379
  'Content-Type': 'application/json',
307
380
  'Authorization': `Bearer ${cfg.apiKey}`,
308
381
  },
309
- body: JSON.stringify({ pluginVersion: '0.1.3', configHash: '' }),
382
+ body: JSON.stringify({ pluginVersion: PKG_VERSION, configHash: '' }),
310
383
  signal: AbortSignal.timeout(cfg.timeoutMs),
311
384
  });
312
385
  if (res.ok) {
@@ -341,7 +414,7 @@ if (command === 'connect') {
341
414
  }
342
415
  } else if (serviceHealthy && !cfg.apiKey) {
343
416
  console.log('[!!] Handshake: skipped — no API key configured');
344
- console.log(' ↳ Run: safeclaw connect <your-api-key>');
417
+ console.log(' ↳ Run: safeclaw-plugin connect <your-api-key>');
345
418
  allOk = false;
346
419
  }
347
420
 
@@ -363,13 +436,13 @@ if (command === 'connect') {
363
436
  } else if (existsSync(extensionDir)) {
364
437
  const stat = lstatSync(extensionDir);
365
438
  if (stat.isSymbolicLink()) {
366
- console.log('[!!] Plugin: stale symlink (run safeclaw setup to fix)');
439
+ console.log('[!!] Plugin: stale symlink (run safeclaw-plugin setup to fix)');
367
440
  } else {
368
441
  console.log('[!!] Plugin: missing files in ' + extensionDir);
369
442
  }
370
443
  allOk = false;
371
444
  } else {
372
- console.log('[!!] Plugin: not installed. Run: safeclaw setup');
445
+ console.log('[!!] Plugin: not installed. Run: safeclaw-plugin setup');
373
446
  allOk = false;
374
447
  }
375
448
 
@@ -399,13 +472,30 @@ if (command === 'connect') {
399
472
  console.log('Some checks failed. Fix the issues above.');
400
473
  }
401
474
  } else {
402
- console.log('Usage: safeclaw <command>');
475
+ console.log('safeclaw-plugin — OpenClaw plugin CLI for SafeClaw governance');
476
+ console.log('');
477
+ console.log('Usage: safeclaw-plugin <command> [options]');
478
+ console.log('');
479
+ console.log('Setup:');
480
+ console.log(' connect <api-key> Save API key, validate via handshake, register with OpenClaw');
481
+ console.log(' Keys start with "sc_". Get yours at https://safeclaw.eu/dashboard');
482
+ console.log(' setup Register plugin with OpenClaw without an API key (manual setup)');
483
+ console.log(' restart-openclaw Restart the OpenClaw daemon to pick up plugin changes');
484
+ console.log('');
485
+ console.log('Diagnostics:');
486
+ console.log(' status Run 8 checks: config, API key, service health, evaluate endpoint,');
487
+ console.log(' handshake, OpenClaw binary, plugin files, OpenClaw config');
488
+ console.log('');
489
+ console.log('Configuration:');
490
+ console.log(' config show Show current enforcement, failMode, enabled, serviceUrl, apiKey');
491
+ console.log(' config set <k> <v> Set a config value. Keys: enforcement, failMode, enabled, serviceUrl');
492
+ console.log(' enforcement: enforce | warn-only | audit-only | disabled');
493
+ console.log(' failMode: open (allow on error) | closed (block on error)');
494
+ console.log(' enabled: true | false');
495
+ console.log('');
496
+ console.log('Interactive:');
497
+ console.log(' tui Open the interactive settings TUI (Status, Settings, About tabs)');
403
498
  console.log('');
404
- console.log('Commands:');
405
- console.log(' connect <api-key> Connect to SafeClaw and register with OpenClaw');
406
- console.log(' setup Register SafeClaw plugin with OpenClaw (no key needed)');
407
- console.log(' status Check SafeClaw + OpenClaw connection status');
408
- console.log(' tui Open the interactive SafeClaw settings TUI');
409
- console.log(' restart-openclaw Restart the OpenClaw daemon');
499
+ console.log('For the service CLI (serve, audit, policy, pref), use the "safeclaw" command.');
410
500
  process.exit(0);
411
501
  }
package/dist/cli.js CHANGED
@@ -2,13 +2,14 @@
2
2
  import React from 'react';
3
3
  import { render } from 'ink';
4
4
  import { execSync } from 'child_process';
5
- import { readFileSync, writeFileSync, mkdirSync, chmodSync, existsSync, copyFileSync, lstatSync, unlinkSync } from 'fs';
5
+ import { readFileSync, writeFileSync, mkdirSync, existsSync, copyFileSync, lstatSync, unlinkSync } from 'fs';
6
6
  import { join, dirname } from 'path';
7
7
  import { homedir } from 'os';
8
8
  import { fileURLToPath } from 'url';
9
9
  import App from './tui/App.js';
10
- import { loadConfig } from './tui/config.js';
10
+ import { loadConfig, saveConfig } from './tui/config.js';
11
11
  const __dirname = dirname(fileURLToPath(import.meta.url));
12
+ const PKG_VERSION = JSON.parse(readFileSync(join(__dirname, '..', 'package.json'), 'utf-8')).version;
12
13
  function readJson(path) {
13
14
  try {
14
15
  return JSON.parse(readFileSync(path, 'utf-8'));
@@ -82,14 +83,18 @@ function registerWithOpenClaw() {
82
83
  }
83
84
  const args = process.argv.slice(2);
84
85
  const command = args[0];
85
- if (command === 'connect') {
86
+ // Handle --help / -h for any command position
87
+ if (!command || command === '--help' || command === '-h' || command === 'help') {
88
+ // Fall through to the else block at the bottom which prints full help
89
+ }
90
+ else if (command === 'connect') {
86
91
  const apiKey = args[1];
87
92
  const serviceUrlIdx = args.indexOf('--service-url');
88
93
  const serviceUrl = serviceUrlIdx !== -1 && args[serviceUrlIdx + 1]
89
94
  ? args[serviceUrlIdx + 1]
90
95
  : 'https://api.safeclaw.eu/api/v1';
91
96
  if (!apiKey || apiKey.startsWith('--')) {
92
- console.error('Usage: safeclaw connect <api-key> [--service-url <url>]');
97
+ console.error('Usage: safeclaw-plugin connect <api-key> [--service-url <url>]');
93
98
  process.exit(1);
94
99
  }
95
100
  if (!apiKey.startsWith('sc_')) {
@@ -115,10 +120,9 @@ if (command === 'connect') {
115
120
  }
116
121
  config.remote.apiKey = apiKey;
117
122
  config.remote.serviceUrl = serviceUrl;
118
- // Write config with owner-only permissions
119
- mkdirSync(configDir, { recursive: true });
120
- writeFileSync(configPath, JSON.stringify(config, null, 2) + '\n');
121
- chmodSync(configPath, 0o600);
123
+ // Write config with owner-only permissions (atomic mode via writeFileSync option)
124
+ mkdirSync(configDir, { recursive: true, mode: 0o700 });
125
+ writeFileSync(configPath, JSON.stringify(config, null, 2) + '\n', { mode: 0o600 });
122
126
  console.log(`API key saved to ${configPath}`);
123
127
  // Validate key via handshake
124
128
  try {
@@ -128,7 +132,7 @@ if (command === 'connect') {
128
132
  'Content-Type': 'application/json',
129
133
  'Authorization': `Bearer ${apiKey}`,
130
134
  },
131
- body: JSON.stringify({ pluginVersion: '0.1.3', configHash: '' }),
135
+ body: JSON.stringify({ pluginVersion: PKG_VERSION, configHash: '' }),
132
136
  signal: AbortSignal.timeout(5000),
133
137
  });
134
138
  if (res.ok) {
@@ -150,7 +154,7 @@ if (command === 'connect') {
150
154
  }
151
155
  catch {
152
156
  console.warn(`Warning: API key saved but could not reach ${serviceUrl}`);
153
- console.warn('Run "safeclaw status" later to verify the connection.');
157
+ console.warn('Run "safeclaw-plugin status" later to verify the connection.');
154
158
  }
155
159
  // Register with OpenClaw
156
160
  console.log('Registering SafeClaw plugin with OpenClaw...');
@@ -159,7 +163,7 @@ if (command === 'connect') {
159
163
  console.log('SafeClaw plugin registered with OpenClaw.');
160
164
  console.log('');
161
165
  console.log('Restart OpenClaw to activate:');
162
- console.log(' safeclaw restart-openclaw');
166
+ console.log(' safeclaw-plugin restart-openclaw');
163
167
  }
164
168
  else {
165
169
  console.log('');
@@ -168,6 +172,79 @@ if (command === 'connect') {
168
172
  console.log(' openclaw plugins install openclaw-safeclaw-plugin');
169
173
  }
170
174
  }
175
+ else if (command === 'config') {
176
+ const subcommand = args[1];
177
+ if (subcommand === 'show') {
178
+ const cfg = loadConfig();
179
+ console.log(`enabled: ${cfg.enabled}`);
180
+ console.log(`enforcement: ${cfg.enforcement}`);
181
+ console.log(`failMode: ${cfg.failMode}`);
182
+ console.log(`serviceUrl: ${cfg.serviceUrl}`);
183
+ console.log(`apiKey: ${cfg.apiKey ? `${cfg.apiKey.slice(0, 6)}...` : '(not set)'}`);
184
+ console.log(`timeoutMs: ${cfg.timeoutMs}`);
185
+ }
186
+ else if (subcommand === 'set') {
187
+ const key = args[2];
188
+ const value = args[3];
189
+ if (!key || !value) {
190
+ console.error('Usage: safeclaw-plugin config set <key> <value>');
191
+ console.error('');
192
+ console.error('Keys:');
193
+ console.error(' enforcement enforce | warn-only | audit-only | disabled');
194
+ console.error(' failMode open | closed');
195
+ console.error(' enabled true | false');
196
+ console.error(' serviceUrl https://...');
197
+ process.exit(1);
198
+ }
199
+ const cfg = loadConfig();
200
+ const validEnforcement = ['enforce', 'warn-only', 'audit-only', 'disabled'];
201
+ const validFailModes = ['open', 'closed'];
202
+ if (key === 'enforcement') {
203
+ if (!validEnforcement.includes(value)) {
204
+ console.error(`Invalid enforcement mode: "${value}". Valid: ${validEnforcement.join(', ')}`);
205
+ process.exit(1);
206
+ }
207
+ cfg.enforcement = value;
208
+ }
209
+ else if (key === 'failMode') {
210
+ if (!validFailModes.includes(value)) {
211
+ console.error(`Invalid fail mode: "${value}". Valid: ${validFailModes.join(', ')}`);
212
+ process.exit(1);
213
+ }
214
+ cfg.failMode = value;
215
+ }
216
+ else if (key === 'enabled') {
217
+ if (value !== 'true' && value !== 'false') {
218
+ console.error('Invalid value for enabled: must be "true" or "false"');
219
+ process.exit(1);
220
+ }
221
+ cfg.enabled = value === 'true';
222
+ }
223
+ else if (key === 'serviceUrl') {
224
+ cfg.serviceUrl = value;
225
+ }
226
+ else {
227
+ console.error(`Unknown config key: "${key}"`);
228
+ console.error('Valid keys: enforcement, failMode, enabled, serviceUrl');
229
+ process.exit(1);
230
+ }
231
+ try {
232
+ saveConfig(cfg);
233
+ }
234
+ catch (e) {
235
+ console.error(`Error: ${e instanceof Error ? e.message : e}`);
236
+ process.exit(1);
237
+ }
238
+ console.log(`Set ${key} = ${value}`);
239
+ }
240
+ else {
241
+ console.error('Usage: safeclaw-plugin config <show|set>');
242
+ console.error('');
243
+ console.error(' show Display all current config values');
244
+ console.error(' set <k> <v> Set a config value (enforcement, failMode, enabled, serviceUrl)');
245
+ process.exit(1);
246
+ }
247
+ }
171
248
  else if (command === 'tui') {
172
249
  render(React.createElement(App));
173
250
  }
@@ -191,8 +268,8 @@ else if (command === 'setup') {
191
268
  console.log('');
192
269
  console.log('Next steps:');
193
270
  console.log(' 1. Get an API key at https://safeclaw.eu/dashboard');
194
- console.log(' 2. Run: safeclaw connect <your-api-key>');
195
- console.log(' 3. Run: safeclaw restart-openclaw');
271
+ console.log(' 2. Run: safeclaw-plugin connect <your-api-key>');
272
+ console.log(' 3. Run: safeclaw-plugin restart-openclaw');
196
273
  }
197
274
  else {
198
275
  console.log('Could not auto-register.');
@@ -212,7 +289,7 @@ else if (command === 'status') {
212
289
  console.log('[ok] Config file: ' + configPath);
213
290
  }
214
291
  else {
215
- console.log('[!!] Config file not found. Run: safeclaw connect <api-key>');
292
+ console.log('[!!] Config file not found. Run: safeclaw-plugin connect <api-key>');
216
293
  allOk = false;
217
294
  }
218
295
  // 2. API key
@@ -224,7 +301,7 @@ else if (command === 'status') {
224
301
  allOk = false;
225
302
  }
226
303
  else {
227
- console.log('[!!] API key: not set. Run: safeclaw connect <api-key>');
304
+ console.log('[!!] API key: not set. Run: safeclaw-plugin connect <api-key>');
228
305
  allOk = false;
229
306
  }
230
307
  // 3. SafeClaw service — health check (uses same timeout as plugin)
@@ -302,7 +379,7 @@ else if (command === 'status') {
302
379
  'Content-Type': 'application/json',
303
380
  'Authorization': `Bearer ${cfg.apiKey}`,
304
381
  },
305
- body: JSON.stringify({ pluginVersion: '0.1.3', configHash: '' }),
382
+ body: JSON.stringify({ pluginVersion: PKG_VERSION, configHash: '' }),
306
383
  signal: AbortSignal.timeout(cfg.timeoutMs),
307
384
  });
308
385
  if (res.ok) {
@@ -344,7 +421,7 @@ else if (command === 'status') {
344
421
  }
345
422
  else if (serviceHealthy && !cfg.apiKey) {
346
423
  console.log('[!!] Handshake: skipped — no API key configured');
347
- console.log(' ↳ Run: safeclaw connect <your-api-key>');
424
+ console.log(' ↳ Run: safeclaw-plugin connect <your-api-key>');
348
425
  allOk = false;
349
426
  }
350
427
  // 6. OpenClaw installed
@@ -366,7 +443,7 @@ else if (command === 'status') {
366
443
  else if (existsSync(extensionDir)) {
367
444
  const stat = lstatSync(extensionDir);
368
445
  if (stat.isSymbolicLink()) {
369
- console.log('[!!] Plugin: stale symlink (run safeclaw setup to fix)');
446
+ console.log('[!!] Plugin: stale symlink (run safeclaw-plugin setup to fix)');
370
447
  }
371
448
  else {
372
449
  console.log('[!!] Plugin: missing files in ' + extensionDir);
@@ -374,7 +451,7 @@ else if (command === 'status') {
374
451
  allOk = false;
375
452
  }
376
453
  else {
377
- console.log('[!!] Plugin: not installed. Run: safeclaw setup');
454
+ console.log('[!!] Plugin: not installed. Run: safeclaw-plugin setup');
378
455
  allOk = false;
379
456
  }
380
457
  // 8. Plugin enabled in OpenClaw config
@@ -406,13 +483,30 @@ else if (command === 'status') {
406
483
  }
407
484
  }
408
485
  else {
409
- console.log('Usage: safeclaw <command>');
486
+ console.log('safeclaw-plugin — OpenClaw plugin CLI for SafeClaw governance');
487
+ console.log('');
488
+ console.log('Usage: safeclaw-plugin <command> [options]');
489
+ console.log('');
490
+ console.log('Setup:');
491
+ console.log(' connect <api-key> Save API key, validate via handshake, register with OpenClaw');
492
+ console.log(' Keys start with "sc_". Get yours at https://safeclaw.eu/dashboard');
493
+ console.log(' setup Register plugin with OpenClaw without an API key (manual setup)');
494
+ console.log(' restart-openclaw Restart the OpenClaw daemon to pick up plugin changes');
495
+ console.log('');
496
+ console.log('Diagnostics:');
497
+ console.log(' status Run 8 checks: config, API key, service health, evaluate endpoint,');
498
+ console.log(' handshake, OpenClaw binary, plugin files, OpenClaw config');
499
+ console.log('');
500
+ console.log('Configuration:');
501
+ console.log(' config show Show current enforcement, failMode, enabled, serviceUrl, apiKey');
502
+ console.log(' config set <k> <v> Set a config value. Keys: enforcement, failMode, enabled, serviceUrl');
503
+ console.log(' enforcement: enforce | warn-only | audit-only | disabled');
504
+ console.log(' failMode: open (allow on error) | closed (block on error)');
505
+ console.log(' enabled: true | false');
506
+ console.log('');
507
+ console.log('Interactive:');
508
+ console.log(' tui Open the interactive settings TUI (Status, Settings, About tabs)');
410
509
  console.log('');
411
- console.log('Commands:');
412
- console.log(' connect <api-key> Connect to SafeClaw and register with OpenClaw');
413
- console.log(' setup Register SafeClaw plugin with OpenClaw (no key needed)');
414
- console.log(' status Check SafeClaw + OpenClaw connection status');
415
- console.log(' tui Open the interactive SafeClaw settings TUI');
416
- console.log(' restart-openclaw Restart the OpenClaw daemon');
510
+ console.log('For the service CLI (serve, audit, policy, pref), use the "safeclaw" command.');
417
511
  process.exit(0);
418
512
  }