nervepay 1.3.9 → 1.4.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/bin/nervepay-cli.js +86 -29
- package/package.json +1 -1
package/bin/nervepay-cli.js
CHANGED
|
@@ -80,6 +80,9 @@ function findOpenClawConfigPath() {
|
|
|
80
80
|
join(homedir(), '.config', 'openclaw', 'openclaw.json'),
|
|
81
81
|
join(homedir(), '.moltbot', 'openclaw.json'),
|
|
82
82
|
join(homedir(), '.clawdbot', 'openclaw.json'),
|
|
83
|
+
// Common system-level locations (e.g. running as root on a server)
|
|
84
|
+
'/home/openclaw/.openclaw/openclaw.json',
|
|
85
|
+
'/opt/openclaw/openclaw.json',
|
|
83
86
|
];
|
|
84
87
|
for (const p of candidates) {
|
|
85
88
|
if (existsSync(p)) return p;
|
|
@@ -107,7 +110,9 @@ function extractGatewayConfig(config) {
|
|
|
107
110
|
token = config.gateway.auth.token;
|
|
108
111
|
}
|
|
109
112
|
|
|
113
|
+
// Environment variable overrides
|
|
110
114
|
if (process.env.OPENCLAW_GATEWAY_TOKEN) token = token || process.env.OPENCLAW_GATEWAY_TOKEN;
|
|
115
|
+
if (process.env.OPENCLAW_GATEWAY_URL) url = url || process.env.OPENCLAW_GATEWAY_URL;
|
|
111
116
|
if (process.env.OPENCLAW_GATEWAY_PORT && !url) url = `http://127.0.0.1:${process.env.OPENCLAW_GATEWAY_PORT}`;
|
|
112
117
|
|
|
113
118
|
return { url, token };
|
|
@@ -171,6 +176,38 @@ async function updateOpenClawConfig(agentDid, privateKey, apiUrl) {
|
|
|
171
176
|
} catch { return false; }
|
|
172
177
|
}
|
|
173
178
|
|
|
179
|
+
/**
|
|
180
|
+
* Enable /v1/chat/completions on the OpenClaw gateway.
|
|
181
|
+
*
|
|
182
|
+
* Sets gateway.http.endpoints.chatCompletions.enabled = true in openclaw.json.
|
|
183
|
+
* This allows NervePay Mission Control to chat directly without spawning sub-agents.
|
|
184
|
+
*
|
|
185
|
+
* Returns true if config was updated, false otherwise.
|
|
186
|
+
* The gateway must be restarted for the change to take effect.
|
|
187
|
+
*/
|
|
188
|
+
async function enableChatCompletions() {
|
|
189
|
+
const configPath = findOpenClawConfigPath();
|
|
190
|
+
if (!configPath) return false;
|
|
191
|
+
try {
|
|
192
|
+
const config = JSON.parse(await readFile(configPath, 'utf-8'));
|
|
193
|
+
|
|
194
|
+
// Check if already enabled
|
|
195
|
+
if (config.gateway?.http?.endpoints?.chatCompletions?.enabled === true) {
|
|
196
|
+
return 'already_enabled';
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
// Deep-merge the setting
|
|
200
|
+
if (!config.gateway) config.gateway = {};
|
|
201
|
+
if (!config.gateway.http) config.gateway.http = {};
|
|
202
|
+
if (!config.gateway.http.endpoints) config.gateway.http.endpoints = {};
|
|
203
|
+
if (!config.gateway.http.endpoints.chatCompletions) config.gateway.http.endpoints.chatCompletions = {};
|
|
204
|
+
config.gateway.http.endpoints.chatCompletions.enabled = true;
|
|
205
|
+
|
|
206
|
+
await writeFile(configPath, JSON.stringify(config, null, 2));
|
|
207
|
+
return true;
|
|
208
|
+
} catch { return false; }
|
|
209
|
+
}
|
|
210
|
+
|
|
174
211
|
// ---------------------------------------------------------------------------
|
|
175
212
|
// CLI program
|
|
176
213
|
// ---------------------------------------------------------------------------
|
|
@@ -351,6 +388,13 @@ program
|
|
|
351
388
|
log(dim('Approve in Mission Control > Task Board > Incoming'));
|
|
352
389
|
}
|
|
353
390
|
|
|
391
|
+
// Enable /v1/chat/completions for direct chat (no sub-agent spawning)
|
|
392
|
+
const chatResult = await enableChatCompletions();
|
|
393
|
+
if (chatResult === true) {
|
|
394
|
+
logOk('Enabled chat completions endpoint');
|
|
395
|
+
log(dim(' Restart gateway for this to take effect:'), info('openclaw gateway restart'));
|
|
396
|
+
}
|
|
397
|
+
|
|
354
398
|
divider();
|
|
355
399
|
logOk(bold('Setup complete'));
|
|
356
400
|
console.log();
|
|
@@ -518,10 +562,8 @@ async function deviceNodePairing(options) {
|
|
|
518
562
|
const timeoutMs = parseInt(options.timeout, 10) * 1000;
|
|
519
563
|
|
|
520
564
|
// First attempt
|
|
521
|
-
let deviceToken = '';
|
|
522
565
|
try {
|
|
523
|
-
|
|
524
|
-
deviceToken = result.token;
|
|
566
|
+
await attemptConnect(WebSocket, wsUrl, ctx);
|
|
525
567
|
logOk('Connected (device already paired)');
|
|
526
568
|
} catch (e) {
|
|
527
569
|
if (e.message !== 'NOT_PAIRED') throw e;
|
|
@@ -543,8 +585,7 @@ async function deviceNodePairing(options) {
|
|
|
543
585
|
process.stdout.write(dim('.'));
|
|
544
586
|
|
|
545
587
|
try {
|
|
546
|
-
|
|
547
|
-
deviceToken = result.token;
|
|
588
|
+
await attemptConnect(WebSocket, wsUrl, ctx);
|
|
548
589
|
approved = true;
|
|
549
590
|
console.log();
|
|
550
591
|
break;
|
|
@@ -561,33 +602,38 @@ async function deviceNodePairing(options) {
|
|
|
561
602
|
logOk(bold('Paired!'));
|
|
562
603
|
console.log();
|
|
563
604
|
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
605
|
+
// Store the master gateway token (used for REST API calls by the backend).
|
|
606
|
+
// The device token from hello-ok is WS-only; the backend uses HTTP Bearer auth.
|
|
607
|
+
logInfo('Saving to NervePay...');
|
|
608
|
+
const client = new NervePayClient({
|
|
609
|
+
apiUrl: options.apiUrl || apiUrl,
|
|
610
|
+
agentDid,
|
|
611
|
+
privateKey,
|
|
612
|
+
});
|
|
571
613
|
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
614
|
+
const apiResult = await gateway.completeDevicePairing(client, {
|
|
615
|
+
device_token: gatewayToken,
|
|
616
|
+
device_id: deviceId,
|
|
617
|
+
gateway_url: gatewayUrl,
|
|
618
|
+
gateway_name: options.name,
|
|
619
|
+
});
|
|
578
620
|
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
621
|
+
divider();
|
|
622
|
+
logOk(bold('Gateway paired'));
|
|
623
|
+
field(' Gateway ID', apiResult.gateway_id);
|
|
624
|
+
field(' Device ID', deviceId.slice(0, 16) + '...');
|
|
625
|
+
field(' Agent DID', agentDid);
|
|
626
|
+
console.log();
|
|
627
|
+
|
|
628
|
+
// Enable /v1/chat/completions for direct chat (no sub-agent spawning)
|
|
629
|
+
const chatResult = await enableChatCompletions();
|
|
630
|
+
if (chatResult === true) {
|
|
631
|
+
logOk('Enabled chat completions endpoint');
|
|
632
|
+
log(dim(' Restart gateway for this to take effect:'), info('openclaw gateway restart'));
|
|
633
|
+
} else if (chatResult === 'already_enabled') {
|
|
634
|
+
logOk('Chat completions endpoint already enabled');
|
|
590
635
|
}
|
|
636
|
+
|
|
591
637
|
console.log();
|
|
592
638
|
log(dim('View in dashboard:'), info('Mission Control > Task Board'));
|
|
593
639
|
console.log();
|
|
@@ -708,6 +754,17 @@ async function legacyCodePairing(options) {
|
|
|
708
754
|
logOk(bold('Gateway paired'));
|
|
709
755
|
field(' Gateway ID', result.gateway_id || 'created');
|
|
710
756
|
field(' Agent DID', agentDid);
|
|
757
|
+
console.log();
|
|
758
|
+
|
|
759
|
+
// Enable /v1/chat/completions for direct chat (no sub-agent spawning)
|
|
760
|
+
const chatResult = await enableChatCompletions();
|
|
761
|
+
if (chatResult === true) {
|
|
762
|
+
logOk('Enabled chat completions endpoint');
|
|
763
|
+
log(dim(' Restart gateway for this to take effect:'), info('openclaw gateway restart'));
|
|
764
|
+
} else if (chatResult === 'already_enabled') {
|
|
765
|
+
logOk('Chat completions endpoint already enabled');
|
|
766
|
+
}
|
|
767
|
+
|
|
711
768
|
console.log();
|
|
712
769
|
log(dim('View in dashboard:'), info('Mission Control > Task Board'));
|
|
713
770
|
console.log();
|