nervepay 1.0.0 → 1.0.2

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.
@@ -0,0 +1,315 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * NervePay CLI - Standalone command-line tool
4
+ * Works independently of OpenClaw plugin system
5
+ */
6
+
7
+ import { readFile, writeFile } from 'fs/promises';
8
+ import { homedir } from 'os';
9
+ import { join } from 'path';
10
+ import { Command } from 'commander';
11
+ import inquirer from 'inquirer';
12
+ import chalk from 'chalk';
13
+ import { NervePayClient } from '../dist/utils/client.js';
14
+ import * as identity from '../dist/tools/identity.js';
15
+ import * as gateway from '../dist/tools/gateway.js';
16
+ import * as vault from '../dist/tools/vault.js';
17
+
18
+ const OPENCLAW_CONFIG_PATH = join(homedir(), '.openclaw', 'openclaw.json');
19
+ const NERVEPAY_CREDS_PATH = join(homedir(), '.nervepay', 'credentials.json');
20
+
21
+ const program = new Command();
22
+
23
+ program
24
+ .name('nervepay')
25
+ .description('NervePay CLI - Self-sovereign identity for AI agents')
26
+ .version('1.0.1');
27
+
28
+ // ============================================================================
29
+ // SETUP COMMAND
30
+ // ============================================================================
31
+
32
+ program
33
+ .command('setup')
34
+ .description('Interactive setup wizard - register identity, pair gateway')
35
+ .option('--api-url <url>', 'NervePay API URL', 'https://api.nervepay.xyz')
36
+ .action(async (options) => {
37
+ console.log(chalk.cyan('\nšŸ” NervePay Setup Wizard\n'));
38
+
39
+ try {
40
+ // Read OpenClaw config
41
+ const openclawConfig = JSON.parse(await readFile(OPENCLAW_CONFIG_PATH, 'utf-8'));
42
+ const gatewayConfig = openclawConfig.gateway?.remote;
43
+
44
+ if (!gatewayConfig?.url || !gatewayConfig?.token) {
45
+ console.error(chalk.red('āŒ No OpenClaw gateway configured'));
46
+ console.error(chalk.yellow(' Run: openclaw configure'));
47
+ process.exit(1);
48
+ }
49
+
50
+ console.log(chalk.green('āœ“ Found OpenClaw gateway:'), gatewayConfig.url);
51
+
52
+ // Ask for agent details
53
+ const answers = await inquirer.prompt([
54
+ {
55
+ type: 'input',
56
+ name: 'name',
57
+ message: 'Agent name:',
58
+ default: 'My AI Agent',
59
+ },
60
+ {
61
+ type: 'input',
62
+ name: 'description',
63
+ message: 'Agent description:',
64
+ default: 'AI agent with self-sovereign identity',
65
+ },
66
+ ]);
67
+
68
+ console.log(chalk.cyan('\nšŸ“ Registering agent identity...'));
69
+
70
+ // Create client (without credentials initially)
71
+ const client = new NervePayClient({ apiUrl: options.apiUrl });
72
+
73
+ // Register pending identity
74
+ const registration = await identity.registerPendingIdentity(client, {
75
+ name: answers.name,
76
+ description: answers.description,
77
+ });
78
+
79
+ console.log(chalk.green('āœ“ Agent identity created'));
80
+ console.log(chalk.gray(' DID:'), registration.did);
81
+ console.log(chalk.gray(' Session ID:'), registration.session_id);
82
+ console.log(chalk.gray(' Claim URL:'), registration.claim_url);
83
+
84
+ console.log(chalk.cyan('\nšŸ‘¤ Please claim this agent in your dashboard:'));
85
+ console.log(chalk.yellow(` ${registration.claim_url}`));
86
+ console.log(chalk.gray(' (Opens in browser automatically if possible)\n'));
87
+
88
+ // Try to open in browser
89
+ const open = await import('open');
90
+ await open.default(registration.claim_url).catch(() => {
91
+ console.log(chalk.gray(' (Could not open browser automatically)'));
92
+ });
93
+
94
+ // Poll for claim
95
+ console.log(chalk.cyan('ā³ Waiting for claim (checking every 5 seconds)...\n'));
96
+
97
+ let claimed = false;
98
+ const maxAttempts = 60; // 5 minutes
99
+ let attempts = 0;
100
+
101
+ while (!claimed && attempts < maxAttempts) {
102
+ await new Promise((resolve) => setTimeout(resolve, 5000));
103
+ attempts++;
104
+
105
+ try {
106
+ const status = await fetch(`${options.apiUrl}/v1/agent-identity/register-pending/${registration.session_id}/status`);
107
+ const data = await status.json();
108
+
109
+ if (data.status === 'claimed') {
110
+ claimed = true;
111
+ console.log(chalk.green('āœ“ Agent claimed successfully!\n'));
112
+ } else if (data.status === 'expired') {
113
+ console.error(chalk.red('āŒ Claim session expired'));
114
+ process.exit(1);
115
+ } else {
116
+ process.stdout.write(chalk.gray('.'));
117
+ }
118
+ } catch (e) {
119
+ process.stdout.write(chalk.gray('.'));
120
+ }
121
+ }
122
+
123
+ if (!claimed) {
124
+ console.error(chalk.red('\nāŒ Claim timeout - please try again'));
125
+ process.exit(1);
126
+ }
127
+
128
+ // Update client with credentials
129
+ client.updateConfig({
130
+ agentDid: registration.did,
131
+ privateKey: registration.private_key,
132
+ });
133
+
134
+ // Save credentials
135
+ const credsDir = join(homedir(), '.nervepay');
136
+ await writeFile(
137
+ NERVEPAY_CREDS_PATH,
138
+ JSON.stringify(
139
+ {
140
+ agent_did: registration.did,
141
+ private_key: registration.private_key,
142
+ mnemonic: registration.mnemonic,
143
+ created_at: new Date().toISOString(),
144
+ },
145
+ null,
146
+ 2
147
+ )
148
+ );
149
+ console.log(chalk.green('āœ“ Credentials saved to ~/.nervepay/credentials.json'));
150
+
151
+ // Update OpenClaw config
152
+ if (!openclawConfig.plugins) openclawConfig.plugins = {};
153
+ if (!openclawConfig.plugins.entries) openclawConfig.plugins.entries = {};
154
+ if (!openclawConfig.plugins.entries.nervepay) {
155
+ openclawConfig.plugins.entries.nervepay = { enabled: true, config: {} };
156
+ }
157
+
158
+ openclawConfig.plugins.entries.nervepay.config = {
159
+ ...openclawConfig.plugins.entries.nervepay.config,
160
+ apiUrl: options.apiUrl,
161
+ agentDid: registration.did,
162
+ privateKey: registration.private_key,
163
+ enableOrchestration: true,
164
+ };
165
+
166
+ await writeFile(OPENCLAW_CONFIG_PATH, JSON.stringify(openclawConfig, null, 2));
167
+ console.log(chalk.green('āœ“ OpenClaw config updated'));
168
+
169
+ // Send pairing request
170
+ console.log(chalk.cyan('\nšŸ”— Pairing gateway...'));
171
+
172
+ const pairingRequest = await gateway.createPairingRequest(client, {
173
+ gateway_name: 'OpenClaw Gateway',
174
+ gateway_url: gatewayConfig.url,
175
+ max_concurrent_agents: 8,
176
+ default_timeout_seconds: 3600,
177
+ });
178
+
179
+ console.log(chalk.green('āœ“ Pairing request sent'));
180
+ console.log(chalk.yellow(' Approve in Mission Control > Task Board > Incoming tab'));
181
+
182
+ console.log(chalk.cyan('\nāœ… Setup complete!'));
183
+ console.log(chalk.gray('\nNext steps:'));
184
+ console.log(chalk.gray(' 1. Approve the pairing request in Mission Control'));
185
+ console.log(chalk.gray(' 2. Restart OpenClaw gateway:'), chalk.cyan('openclaw gateway restart'));
186
+ console.log(chalk.gray(' 3. Test:'), chalk.cyan('nervepay whoami'));
187
+ console.log(chalk.gray('\n Mnemonic (backup phrase):'), chalk.yellow(registration.mnemonic));
188
+ console.log(chalk.red(' āš ļø Save this mnemonic - you can recover your keys with it!'));
189
+ } catch (error) {
190
+ console.error(chalk.red('\nāŒ Setup failed:'), error.message);
191
+ process.exit(1);
192
+ }
193
+ });
194
+
195
+ // ============================================================================
196
+ // WHOAMI COMMAND
197
+ // ============================================================================
198
+
199
+ program
200
+ .command('whoami')
201
+ .description('Show current agent identity')
202
+ .action(async () => {
203
+ try {
204
+ const config = await loadConfig();
205
+ const client = new NervePayClient(config);
206
+ const result = await identity.whoami(client);
207
+
208
+ console.log(chalk.cyan('\nšŸ¤– Agent Identity\n'));
209
+ console.log(chalk.gray('DID:'), chalk.white(result.agent_did));
210
+ console.log(chalk.gray('Name:'), chalk.white(result.name));
211
+ console.log(chalk.gray('Description:'), chalk.white(result.description));
212
+ console.log(chalk.gray('Reputation:'), chalk.white(`${result.reputation_score}/100`));
213
+ console.log(chalk.gray('Created:'), chalk.white(new Date(result.created_at).toLocaleString()));
214
+ console.log();
215
+ } catch (error) {
216
+ console.error(chalk.red('āŒ Error:'), error.message);
217
+ process.exit(1);
218
+ }
219
+ });
220
+
221
+ // ============================================================================
222
+ // GATEWAYS COMMAND
223
+ // ============================================================================
224
+
225
+ program
226
+ .command('gateways')
227
+ .description('List connected gateways')
228
+ .action(async () => {
229
+ try {
230
+ const config = await loadConfig();
231
+ const client = new NervePayClient(config);
232
+ const result = await gateway.listGateways(client);
233
+
234
+ console.log(chalk.cyan('\n🌐 Connected Gateways\n'));
235
+
236
+ if (!result.gateways || result.gateways.length === 0) {
237
+ console.log(chalk.yellow('No gateways connected'));
238
+ console.log(chalk.gray('Run:'), chalk.cyan('nervepay setup'), chalk.gray('to pair your gateway'));
239
+ } else {
240
+ result.gateways.forEach((gw, i) => {
241
+ console.log(chalk.white(`${i + 1}. ${gw.name}`));
242
+ console.log(chalk.gray(' URL:'), gw.url);
243
+ console.log(chalk.gray(' Status:'), gw.last_health_status === 'healthy' ? chalk.green('healthy') : chalk.yellow(gw.last_health_status));
244
+ console.log();
245
+ });
246
+ }
247
+ } catch (error) {
248
+ console.error(chalk.red('āŒ Error:'), error.message);
249
+ process.exit(1);
250
+ }
251
+ });
252
+
253
+ // ============================================================================
254
+ // SECRETS COMMAND
255
+ // ============================================================================
256
+
257
+ program
258
+ .command('secrets')
259
+ .description('List secrets in vault')
260
+ .action(async () => {
261
+ try {
262
+ const config = await loadConfig();
263
+ const client = new NervePayClient(config);
264
+ const result = await vault.listSecrets(client);
265
+
266
+ console.log(chalk.cyan('\nšŸ” Vault Secrets\n'));
267
+
268
+ if (!result.secrets || result.secrets.length === 0) {
269
+ console.log(chalk.yellow('No secrets stored'));
270
+ console.log(chalk.gray('Add secrets in Mission Control > Agent Passports > Secrets tab'));
271
+ } else {
272
+ result.secrets.forEach((secret, i) => {
273
+ console.log(chalk.white(`${i + 1}. ${secret.name}`));
274
+ console.log(chalk.gray(' Type:'), secret.secret_type);
275
+ console.log(chalk.gray(' Updated:'), new Date(secret.updated_at).toLocaleString());
276
+ console.log();
277
+ });
278
+ }
279
+ } catch (error) {
280
+ console.error(chalk.red('āŒ Error:'), error.message);
281
+ process.exit(1);
282
+ }
283
+ });
284
+
285
+ // ============================================================================
286
+ // HELPER FUNCTIONS
287
+ // ============================================================================
288
+
289
+ async function loadConfig() {
290
+ try {
291
+ const openclawConfig = JSON.parse(await readFile(OPENCLAW_CONFIG_PATH, 'utf-8'));
292
+ const pluginConfig = openclawConfig.plugins?.entries?.nervepay?.config || {};
293
+
294
+ if (!pluginConfig.agentDid || !pluginConfig.privateKey) {
295
+ console.error(chalk.red('āŒ NervePay not configured'));
296
+ console.error(chalk.yellow(' Run:'), chalk.cyan('nervepay setup'));
297
+ process.exit(1);
298
+ }
299
+
300
+ return {
301
+ apiUrl: pluginConfig.apiUrl || 'https://api.nervepay.xyz',
302
+ agentDid: pluginConfig.agentDid,
303
+ privateKey: pluginConfig.privateKey,
304
+ };
305
+ } catch (error) {
306
+ console.error(chalk.red('āŒ Failed to load config:'), error.message);
307
+ process.exit(1);
308
+ }
309
+ }
310
+
311
+ // ============================================================================
312
+ // RUN
313
+ // ============================================================================
314
+
315
+ program.parse();
@@ -29,6 +29,15 @@
29
29
  "type": "string",
30
30
  "description": "OpenClaw gateway URL (for pairing)"
31
31
  },
32
+ "gatewayToken": {
33
+ "type": "string",
34
+ "description": "OpenClaw gateway authentication token"
35
+ },
36
+ "autoDetectGateway": {
37
+ "type": "boolean",
38
+ "description": "Automatically detect gateway from ~/.openclaw/openclaw.json",
39
+ "default": true
40
+ },
32
41
  "enableOrchestration": {
33
42
  "type": "boolean",
34
43
  "description": "Enable multi-agent orchestration features",
@@ -53,7 +62,16 @@
53
62
  },
54
63
  "gatewayUrl": {
55
64
  "label": "Gateway URL",
56
- "placeholder": "https://your-gateway:18789"
65
+ "placeholder": "ws://127.0.0.1:18789"
66
+ },
67
+ "gatewayToken": {
68
+ "label": "Gateway Token",
69
+ "placeholder": "token from ~/.openclaw/openclaw.json",
70
+ "sensitive": true
71
+ },
72
+ "autoDetectGateway": {
73
+ "label": "Auto-detect Gateway",
74
+ "description": "Read gateway config from ~/.openclaw/openclaw.json automatically"
57
75
  },
58
76
  "enableOrchestration": {
59
77
  "label": "Enable Orchestration",
package/package.json CHANGED
@@ -1,10 +1,13 @@
1
1
  {
2
2
  "name": "nervepay",
3
- "version": "1.0.0",
3
+ "version": "1.0.2",
4
4
  "description": "NervePay plugin for OpenClaw - Self-sovereign identity, vault, and orchestration",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
7
7
  "types": "dist/index.d.ts",
8
+ "bin": {
9
+ "nervepay": "./bin/nervepay-cli.js"
10
+ },
8
11
  "openclaw": {
9
12
  "extensions": [
10
13
  "dist/index.js"
@@ -36,7 +39,11 @@
36
39
  },
37
40
  "dependencies": {
38
41
  "@noble/ed25519": "^2.1.0",
39
- "@noble/hashes": "^1.5.0"
42
+ "@noble/hashes": "^1.5.0",
43
+ "commander": "^12.0.0",
44
+ "inquirer": "^9.0.0",
45
+ "chalk": "^5.0.0",
46
+ "open": "^10.0.0"
40
47
  },
41
48
  "peerDependencies": {
42
49
  "openclaw": ">=1.0.0"
@@ -51,6 +58,7 @@
51
58
  },
52
59
  "files": [
53
60
  "dist",
61
+ "bin",
54
62
  "openclaw.plugin.json",
55
63
  "README.md",
56
64
  "LICENSE",