openclaw-overlay-plugin 0.7.52 → 0.7.54
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 +9 -0
- package/dist/index.js +49 -42
- package/index.ts +49 -45
- package/openclaw.plugin.json +16 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -74,6 +74,15 @@ The plugin needs the HTTP hooks endpoint enabled in your global `openclaw.json`
|
|
|
74
74
|
}
|
|
75
75
|
```
|
|
76
76
|
|
|
77
|
+
## Slash Commands (Autoreply)
|
|
78
|
+
|
|
79
|
+
You can interact with the overlay network directly from the chat using slash commands. These commands execute instantly and do not invoke the AI agent.
|
|
80
|
+
|
|
81
|
+
- `/overlay status` — Quick view of identity and balance.
|
|
82
|
+
- `/overlay balance` — Check wallet funding.
|
|
83
|
+
- `/overlay discover <serviceId>` — Find providers for a specific service.
|
|
84
|
+
- `/overlay onboard` — Trigger the onboarding check.
|
|
85
|
+
|
|
77
86
|
---
|
|
78
87
|
|
|
79
88
|
## AI Tool: `overlay`
|
package/dist/index.js
CHANGED
|
@@ -7,17 +7,6 @@ import fs from 'node:fs';
|
|
|
7
7
|
import { initializeServiceSystem, serviceManager } from './src/services/index.js';
|
|
8
8
|
const __filename = fileURLToPath(import.meta.url);
|
|
9
9
|
const __dirname = path.dirname(__filename);
|
|
10
|
-
/**
|
|
11
|
-
* Helper to correctly locate the CLI script.
|
|
12
|
-
* If running from dist/index.js, CLI is in ./src/cli.js
|
|
13
|
-
* If running from index.ts, CLI is in ./dist/src/cli.js
|
|
14
|
-
*/
|
|
15
|
-
function getCliPath() {
|
|
16
|
-
const localCli = path.join(__dirname, 'src', 'cli.js');
|
|
17
|
-
if (fs.existsSync(localCli))
|
|
18
|
-
return localCli;
|
|
19
|
-
return path.join(__dirname, 'dist', 'src', 'cli.js');
|
|
20
|
-
}
|
|
21
10
|
const execFileAsync = promisify(execFile);
|
|
22
11
|
// Track background process for proper lifecycle management
|
|
23
12
|
let backgroundProcess = null;
|
|
@@ -173,7 +162,7 @@ async function autoAdvertiseServices(env, cliPath, logger) {
|
|
|
173
162
|
continue;
|
|
174
163
|
try {
|
|
175
164
|
const config = JSON.parse(fs.readFileSync(configPath, 'utf-8'));
|
|
176
|
-
const pluginConfig = config?.plugins?.entries?.['openclaw-overlay']?.config;
|
|
165
|
+
const pluginConfig = config?.plugins?.entries?.['openclaw-overlay-plugin']?.config || config?.plugins?.entries?.['openclaw-overlay-plugin'];
|
|
177
166
|
if (pluginConfig?.services && Array.isArray(pluginConfig.services)) {
|
|
178
167
|
servicesToAdvertise = pluginConfig.services;
|
|
179
168
|
break;
|
|
@@ -419,18 +408,18 @@ export async function activate(api) {
|
|
|
419
408
|
return register(api);
|
|
420
409
|
}
|
|
421
410
|
let isInitialized = false;
|
|
411
|
+
function getCliPath() {
|
|
412
|
+
// If we are already in the dist folder (running from compiled JS), don't add it again
|
|
413
|
+
const base = __dirname.endsWith('dist') ? __dirname : path.join(__dirname, 'dist');
|
|
414
|
+
return path.join(base, 'src', 'cli.js');
|
|
415
|
+
}
|
|
422
416
|
export default function register(api) {
|
|
423
417
|
if (isInitialized)
|
|
424
418
|
return;
|
|
425
419
|
isInitialized = true;
|
|
426
420
|
// Capture config at registration time
|
|
427
|
-
// Check all possible IDs for backward compatibility and various installation methods
|
|
428
421
|
const entries = api.getConfig?.()?.plugins?.entries || {};
|
|
429
|
-
const entry = entries['openclaw-overlay']
|
|
430
|
-
|| entries['openclaw-overlay-plugin']
|
|
431
|
-
|| entries['bsv-overlay']
|
|
432
|
-
|| {};
|
|
433
|
-
// Merge: gateway-level api.config > nested entry.config > flat entry properties
|
|
422
|
+
const entry = entries['openclaw-overlay-plugin'] || entries['openclaw-overlay'] || entries['bsv-overlay-skill'] || {};
|
|
434
423
|
const pluginConfig = { ...entry, ...(entry.config || {}), ...(api.config || {}) };
|
|
435
424
|
// Register the overlay agent tool
|
|
436
425
|
api.registerTool({
|
|
@@ -563,6 +552,44 @@ export default function register(api) {
|
|
|
563
552
|
}
|
|
564
553
|
}
|
|
565
554
|
});
|
|
555
|
+
// Register the /overlay slash command for direct chat interaction (Autoreply)
|
|
556
|
+
api.registerCommand({
|
|
557
|
+
name: "overlay",
|
|
558
|
+
description: "BSV Overlay Marketplace commands",
|
|
559
|
+
acceptsArgs: true,
|
|
560
|
+
requireAuth: true,
|
|
561
|
+
handler: async (ctx) => {
|
|
562
|
+
try {
|
|
563
|
+
const args = ctx.args || [];
|
|
564
|
+
const action = args[0] || 'status';
|
|
565
|
+
// Map slash command args to tool params
|
|
566
|
+
const params = { action };
|
|
567
|
+
if (action === 'request' && args[1])
|
|
568
|
+
params.service = args[1];
|
|
569
|
+
if (action === 'discover' && args[1])
|
|
570
|
+
params.service = args[1];
|
|
571
|
+
if (action === 'pay' && args[1])
|
|
572
|
+
params.identityKey = args[1];
|
|
573
|
+
if (action === 'pay' && args[2])
|
|
574
|
+
params.sats = parseInt(args[2], 10);
|
|
575
|
+
const result = await executeOverlayAction(params, pluginConfig, api);
|
|
576
|
+
let text = `**Overlay: ${action.toUpperCase()}**\n\n`;
|
|
577
|
+
if (typeof result === 'string') {
|
|
578
|
+
text += result;
|
|
579
|
+
}
|
|
580
|
+
else if (result.message) {
|
|
581
|
+
text += result.message;
|
|
582
|
+
}
|
|
583
|
+
else {
|
|
584
|
+
text += JSON.stringify(result, null, 2);
|
|
585
|
+
}
|
|
586
|
+
return { text };
|
|
587
|
+
}
|
|
588
|
+
catch (error) {
|
|
589
|
+
return { text: `❌ Overlay Error: ${error.message}` };
|
|
590
|
+
}
|
|
591
|
+
}
|
|
592
|
+
});
|
|
566
593
|
// Register background relay service
|
|
567
594
|
api.registerService({
|
|
568
595
|
id: "openclaw-overlay-relay",
|
|
@@ -571,13 +598,11 @@ export default function register(api) {
|
|
|
571
598
|
api.logger.info("Starting BSV overlay WebSocket relay...");
|
|
572
599
|
const env = buildEnvironment(pluginConfig);
|
|
573
600
|
const cliPath = getCliPath();
|
|
574
|
-
// Initialize the service system if available
|
|
575
601
|
try {
|
|
576
602
|
await initializeServiceSystem();
|
|
577
603
|
}
|
|
578
604
|
catch { }
|
|
579
605
|
startBackgroundService(env, cliPath, api.logger);
|
|
580
|
-
// Start auto-import
|
|
581
606
|
startAutoImport(env, cliPath, api.logger);
|
|
582
607
|
// Auto-check for registration on startup
|
|
583
608
|
(async () => {
|
|
@@ -587,11 +612,9 @@ export default function register(api) {
|
|
|
587
612
|
if (!fs.existsSync(regPath) && !fs.existsSync(onboardSentFile)) {
|
|
588
613
|
const walletPath = path.join(pluginConfig.walletDir || path.join(os.homedir(), '.openclaw', 'bsv-wallet'), 'wallet-identity.json');
|
|
589
614
|
if (fs.existsSync(walletPath)) {
|
|
590
|
-
// Wallet exists but not registered.
|
|
591
615
|
const balResult = await execFileAsync('node', [cliPath, 'balance'], { env });
|
|
592
616
|
const balance = parseCliOutput(balResult.stdout);
|
|
593
617
|
if ((balance.data?.walletBalance || 0) >= 1000) {
|
|
594
|
-
// Funded but not registered. Auto-register.
|
|
595
618
|
const regResult = await execFileAsync('node', [cliPath, 'register'], { env, timeout: 60000 });
|
|
596
619
|
if (parseCliOutput(regResult.stdout).success) {
|
|
597
620
|
api.logger.info('[openclaw-overlay] Agent auto-registered on startup');
|
|
@@ -734,7 +757,7 @@ export default function register(api) {
|
|
|
734
757
|
console.error("Error:", error.message);
|
|
735
758
|
}
|
|
736
759
|
});
|
|
737
|
-
});
|
|
760
|
+
}, { commands: ["overlay"] });
|
|
738
761
|
}
|
|
739
762
|
async function executeOverlayAction(params, config, api) {
|
|
740
763
|
const { action } = params;
|
|
@@ -801,7 +824,6 @@ async function handleServiceRequest(params, env, cliPath, config, api) {
|
|
|
801
824
|
if (!discoverOutput.success) {
|
|
802
825
|
throw new Error(`Discovery failed: ${discoverOutput.error}`);
|
|
803
826
|
}
|
|
804
|
-
// FIX: Use discoverOutput.data.services instead of treating data as flat array
|
|
805
827
|
const providers = discoverOutput.data.services;
|
|
806
828
|
if (!providers || providers.length === 0) {
|
|
807
829
|
throw new Error(`No providers found for service: ${service}`);
|
|
@@ -822,7 +844,7 @@ async function handleServiceRequest(params, env, cliPath, config, api) {
|
|
|
822
844
|
}
|
|
823
845
|
externalProviders = targeted;
|
|
824
846
|
}
|
|
825
|
-
// 3. Sort by price
|
|
847
|
+
// 3. Sort by price
|
|
826
848
|
externalProviders.sort((a, b) => (a.pricing?.amountSats || 0) - (b.pricing?.amountSats || 0));
|
|
827
849
|
const bestProvider = externalProviders[0];
|
|
828
850
|
const price = bestProvider.pricing?.amountSats || 0;
|
|
@@ -849,10 +871,6 @@ async function handleServiceRequest(params, env, cliPath, config, api) {
|
|
|
849
871
|
if (!requestOutput.success) {
|
|
850
872
|
throw new Error(`Service request failed: ${requestOutput.error}`);
|
|
851
873
|
}
|
|
852
|
-
// 7. Return immediately — no polling.
|
|
853
|
-
// The WebSocket background service handles incoming responses
|
|
854
|
-
// asynchronously and wakes the agent via /hooks/agent when a
|
|
855
|
-
// response arrives. This avoids blocking for up to 120s.
|
|
856
874
|
recordSpend(walletDir, price, service, bestProvider.name);
|
|
857
875
|
writeActivityEvent({ type: 'outgoing_payment', emoji: '💸', sats: price, service, provider: bestProvider.name, message: `Paid ${price} sats to ${bestProvider.name} for ${service}` });
|
|
858
876
|
return {
|
|
@@ -1149,7 +1167,7 @@ async function handleImport(params, env, cliPath) {
|
|
|
1149
1167
|
// Check if we should auto-register after successful import
|
|
1150
1168
|
const regPath = path.join(process.env.HOME || '', '.openclaw', 'openclaw-overlay', 'registration.json');
|
|
1151
1169
|
const isRegistered = fs.existsSync(regPath);
|
|
1152
|
-
if (!isRegistered && output.data?.balance >= 1000) {
|
|
1170
|
+
if (!isRegistered && (output.data?.balance || 0) >= 1000) {
|
|
1153
1171
|
// Auto-register immediately after funding
|
|
1154
1172
|
try {
|
|
1155
1173
|
const regResult = await execFileAsync('node', [cliPath, 'register'], { env, timeout: 60000 });
|
|
@@ -1281,13 +1299,11 @@ async function handleRefund(params, env, cliPath) {
|
|
|
1281
1299
|
async function handleOnboard(params, env, cliPath) {
|
|
1282
1300
|
const { agentName, agentDescription } = params;
|
|
1283
1301
|
const steps = [];
|
|
1284
|
-
// Apply agent name/description to env if provided
|
|
1285
1302
|
const onboardEnv = { ...env };
|
|
1286
1303
|
if (agentName)
|
|
1287
1304
|
onboardEnv.AGENT_NAME = agentName;
|
|
1288
1305
|
if (agentDescription)
|
|
1289
1306
|
onboardEnv.AGENT_DESCRIPTION = agentDescription;
|
|
1290
|
-
// Step 1: Setup wallet
|
|
1291
1307
|
try {
|
|
1292
1308
|
const setup = await execFileAsync('node', [cliPath, 'setup'], { env: onboardEnv });
|
|
1293
1309
|
const setupOutput = parseCliOutput(setup.stdout);
|
|
@@ -1297,7 +1313,6 @@ async function handleOnboard(params, env, cliPath) {
|
|
|
1297
1313
|
steps.push({ step: 'setup', success: false, error: err.message });
|
|
1298
1314
|
return { steps, nextStep: 'Fix wallet setup error and try again' };
|
|
1299
1315
|
}
|
|
1300
|
-
// Step 2: Get address
|
|
1301
1316
|
try {
|
|
1302
1317
|
const addr = await execFileAsync('node', [cliPath, 'address'], { env: onboardEnv });
|
|
1303
1318
|
const addrOutput = parseCliOutput(addr.stdout);
|
|
@@ -1306,7 +1321,6 @@ async function handleOnboard(params, env, cliPath) {
|
|
|
1306
1321
|
catch (err) {
|
|
1307
1322
|
steps.push({ step: 'address', success: false, error: err.message });
|
|
1308
1323
|
}
|
|
1309
|
-
// Step 3: Check balance
|
|
1310
1324
|
try {
|
|
1311
1325
|
const bal = await execFileAsync('node', [cliPath, 'balance'], { env: onboardEnv });
|
|
1312
1326
|
const balOutput = parseCliOutput(bal.stdout);
|
|
@@ -1323,7 +1337,6 @@ async function handleOnboard(params, env, cliPath) {
|
|
|
1323
1337
|
catch (err) {
|
|
1324
1338
|
steps.push({ step: 'balance', success: false, error: err.message });
|
|
1325
1339
|
}
|
|
1326
|
-
// Step 4: Register
|
|
1327
1340
|
try {
|
|
1328
1341
|
const reg = await execFileAsync('node', [cliPath, 'register'], { env: onboardEnv, timeout: 60000 });
|
|
1329
1342
|
const regOutput = parseCliOutput(reg.stdout);
|
|
@@ -1350,7 +1363,6 @@ async function handleOnboard(params, env, cliPath) {
|
|
|
1350
1363
|
};
|
|
1351
1364
|
}
|
|
1352
1365
|
async function handlePendingRequests(env, cliPath) {
|
|
1353
|
-
// Clean up old queue entries before checking pending requests
|
|
1354
1366
|
try {
|
|
1355
1367
|
const { cleanupServiceQueue } = await import('./src/scripts/utils/storage.js');
|
|
1356
1368
|
cleanupServiceQueue();
|
|
@@ -1362,7 +1374,6 @@ async function handlePendingRequests(env, cliPath) {
|
|
|
1362
1374
|
const output = parseCliOutput(result.stdout);
|
|
1363
1375
|
if (!output.success)
|
|
1364
1376
|
throw new Error(`Queue check failed: ${output.error}`);
|
|
1365
|
-
// Clear the alert file since we're checking now
|
|
1366
1377
|
const alertPath = path.join(process.env.HOME || '', '.openclaw', 'openclaw-overlay', 'pending-alert.jsonl');
|
|
1367
1378
|
try {
|
|
1368
1379
|
if (fs.existsSync(alertPath))
|
|
@@ -1382,7 +1393,6 @@ function handleActivity() {
|
|
|
1382
1393
|
catch {
|
|
1383
1394
|
return null;
|
|
1384
1395
|
} }).filter(Boolean);
|
|
1385
|
-
// Clear the feed after reading
|
|
1386
1396
|
fs.writeFileSync(feedPath, '');
|
|
1387
1397
|
return { events, count: events.length };
|
|
1388
1398
|
}
|
|
@@ -1397,7 +1407,6 @@ async function handleFulfill(params, env, cliPath) {
|
|
|
1397
1407
|
const output = parseCliOutput(cliResult.stdout);
|
|
1398
1408
|
if (!output.success)
|
|
1399
1409
|
throw new Error(`Fulfill failed: ${output.error}`);
|
|
1400
|
-
// Clean up the request ID from tracking since it's now fulfilled
|
|
1401
1410
|
wokenRequests.delete(requestId);
|
|
1402
1411
|
writeActivityEvent({ type: 'service_fulfilled', emoji: '✅', serviceId, recipientKey: recipientKey?.slice(0, 16), message: `Fulfilled ${serviceId} request — response sent` });
|
|
1403
1412
|
return output.data;
|
|
@@ -1419,7 +1428,6 @@ function buildEnvironment(config) {
|
|
|
1419
1428
|
if (config.arcUrl) {
|
|
1420
1429
|
env.BSV_ARC_URL = config.arcUrl;
|
|
1421
1430
|
}
|
|
1422
|
-
// Set defaults
|
|
1423
1431
|
env.BSV_NETWORK = env.BSV_NETWORK || 'mainnet';
|
|
1424
1432
|
if (!env.BSV_ARC_URL) {
|
|
1425
1433
|
env.BSV_ARC_URL = env.BSV_NETWORK === 'testnet'
|
|
@@ -1438,7 +1446,7 @@ function buildEnvironment(config) {
|
|
|
1438
1446
|
else if (!env.AGENT_DESCRIPTION) {
|
|
1439
1447
|
env.AGENT_DESCRIPTION = 'AI agent on the OpenClaw Overlay Network. Offers services for BSV micropayments.';
|
|
1440
1448
|
}
|
|
1441
|
-
env.AGENT_ROUTED = 'true';
|
|
1449
|
+
env.AGENT_ROUTED = 'true';
|
|
1442
1450
|
return env;
|
|
1443
1451
|
}
|
|
1444
1452
|
function parseCliOutput(stdout) {
|
|
@@ -1450,4 +1458,3 @@ function parseCliOutput(stdout) {
|
|
|
1450
1458
|
throw new Error(`Failed to parse CLI output: ${error.message}`);
|
|
1451
1459
|
}
|
|
1452
1460
|
}
|
|
1453
|
-
// sleep() removed — no longer needed since polling loop was removed
|
package/index.ts
CHANGED
|
@@ -8,17 +8,6 @@ import { initializeServiceSystem, serviceManager } from './src/services/index.js
|
|
|
8
8
|
const __filename = fileURLToPath(import.meta.url);
|
|
9
9
|
const __dirname = path.dirname(__filename);
|
|
10
10
|
|
|
11
|
-
/**
|
|
12
|
-
* Helper to correctly locate the CLI script.
|
|
13
|
-
* If running from dist/index.js, CLI is in ./src/cli.js
|
|
14
|
-
* If running from index.ts, CLI is in ./dist/src/cli.js
|
|
15
|
-
*/
|
|
16
|
-
function getCliPath(): string {
|
|
17
|
-
const localCli = path.join(__dirname, 'src', 'cli.js');
|
|
18
|
-
if (fs.existsSync(localCli)) return localCli;
|
|
19
|
-
return path.join(__dirname, 'dist', 'src', 'cli.js');
|
|
20
|
-
}
|
|
21
|
-
|
|
22
11
|
const execFileAsync = promisify(execFile);
|
|
23
12
|
|
|
24
13
|
// Track background process for proper lifecycle management
|
|
@@ -190,7 +179,7 @@ async function autoAdvertiseServices(env: any, cliPath: string, logger: any) {
|
|
|
190
179
|
if (!fs.existsSync(configPath)) continue;
|
|
191
180
|
try {
|
|
192
181
|
const config = JSON.parse(fs.readFileSync(configPath, 'utf-8'));
|
|
193
|
-
const pluginConfig = config?.plugins?.entries?.['openclaw-overlay']?.config;
|
|
182
|
+
const pluginConfig = config?.plugins?.entries?.['openclaw-overlay-plugin']?.config || config?.plugins?.entries?.['openclaw-overlay-plugin'];
|
|
194
183
|
if (pluginConfig?.services && Array.isArray(pluginConfig.services)) {
|
|
195
184
|
servicesToAdvertise = pluginConfig.services;
|
|
196
185
|
break;
|
|
@@ -464,19 +453,19 @@ export async function activate(api: any) {
|
|
|
464
453
|
|
|
465
454
|
let isInitialized = false;
|
|
466
455
|
|
|
456
|
+
function getCliPath() {
|
|
457
|
+
// If we are already in the dist folder (running from compiled JS), don't add it again
|
|
458
|
+
const base = __dirname.endsWith('dist') ? __dirname : path.join(__dirname, 'dist');
|
|
459
|
+
return path.join(base, 'src', 'cli.js');
|
|
460
|
+
}
|
|
461
|
+
|
|
467
462
|
export default function register(api: any) {
|
|
468
463
|
if (isInitialized) return;
|
|
469
464
|
isInitialized = true;
|
|
470
465
|
|
|
471
466
|
// Capture config at registration time
|
|
472
|
-
// Check all possible IDs for backward compatibility and various installation methods
|
|
473
467
|
const entries = api.getConfig?.()?.plugins?.entries || {};
|
|
474
|
-
const entry = entries['openclaw-overlay']
|
|
475
|
-
|| entries['openclaw-overlay-plugin']
|
|
476
|
-
|| entries['bsv-overlay']
|
|
477
|
-
|| {};
|
|
478
|
-
|
|
479
|
-
// Merge: gateway-level api.config > nested entry.config > flat entry properties
|
|
468
|
+
const entry = entries['openclaw-overlay-plugin'] || entries['openclaw-overlay'] || entries['bsv-overlay-skill'] || {};
|
|
480
469
|
const pluginConfig = { ...entry, ...(entry.config || {}), ...(api.config || {}) };
|
|
481
470
|
|
|
482
471
|
// Register the overlay agent tool
|
|
@@ -610,6 +599,43 @@ export default function register(api: any) {
|
|
|
610
599
|
}
|
|
611
600
|
});
|
|
612
601
|
|
|
602
|
+
// Register the /overlay slash command for direct chat interaction (Autoreply)
|
|
603
|
+
api.registerCommand({
|
|
604
|
+
name: "overlay",
|
|
605
|
+
description: "BSV Overlay Marketplace commands",
|
|
606
|
+
acceptsArgs: true,
|
|
607
|
+
requireAuth: true,
|
|
608
|
+
handler: async (ctx: any) => {
|
|
609
|
+
try {
|
|
610
|
+
const args = ctx.args || [];
|
|
611
|
+
const action = args[0] || 'status';
|
|
612
|
+
|
|
613
|
+
// Map slash command args to tool params
|
|
614
|
+
const params: any = { action };
|
|
615
|
+
|
|
616
|
+
if (action === 'request' && args[1]) params.service = args[1];
|
|
617
|
+
if (action === 'discover' && args[1]) params.service = args[1];
|
|
618
|
+
if (action === 'pay' && args[1]) params.identityKey = args[1];
|
|
619
|
+
if (action === 'pay' && args[2]) params.sats = parseInt(args[2], 10);
|
|
620
|
+
|
|
621
|
+
const result = await executeOverlayAction(params, pluginConfig, api);
|
|
622
|
+
|
|
623
|
+
let text = `**Overlay: ${action.toUpperCase()}**\n\n`;
|
|
624
|
+
if (typeof result === 'string') {
|
|
625
|
+
text += result;
|
|
626
|
+
} else if (result.message) {
|
|
627
|
+
text += result.message;
|
|
628
|
+
} else {
|
|
629
|
+
text += JSON.stringify(result, null, 2);
|
|
630
|
+
}
|
|
631
|
+
|
|
632
|
+
return { text };
|
|
633
|
+
} catch (error: any) {
|
|
634
|
+
return { text: `❌ Overlay Error: ${error.message}` };
|
|
635
|
+
}
|
|
636
|
+
}
|
|
637
|
+
});
|
|
638
|
+
|
|
613
639
|
// Register background relay service
|
|
614
640
|
api.registerService({
|
|
615
641
|
id: "openclaw-overlay-relay",
|
|
@@ -619,14 +645,11 @@ export default function register(api: any) {
|
|
|
619
645
|
const env = buildEnvironment(pluginConfig);
|
|
620
646
|
const cliPath = getCliPath();
|
|
621
647
|
|
|
622
|
-
// Initialize the service system if available
|
|
623
648
|
try {
|
|
624
649
|
await initializeServiceSystem();
|
|
625
650
|
} catch {}
|
|
626
651
|
|
|
627
652
|
startBackgroundService(env, cliPath, api.logger);
|
|
628
|
-
|
|
629
|
-
// Start auto-import
|
|
630
653
|
startAutoImport(env, cliPath, api.logger);
|
|
631
654
|
|
|
632
655
|
// Auto-check for registration on startup
|
|
@@ -639,12 +662,10 @@ export default function register(api: any) {
|
|
|
639
662
|
const walletPath = path.join(pluginConfig.walletDir || path.join(os.homedir(), '.openclaw', 'bsv-wallet'), 'wallet-identity.json');
|
|
640
663
|
|
|
641
664
|
if (fs.existsSync(walletPath)) {
|
|
642
|
-
// Wallet exists but not registered.
|
|
643
665
|
const balResult = await execFileAsync('node', [cliPath, 'balance'], { env });
|
|
644
666
|
const balance = parseCliOutput(balResult.stdout);
|
|
645
667
|
|
|
646
668
|
if ((balance.data?.walletBalance || 0) >= 1000) {
|
|
647
|
-
// Funded but not registered. Auto-register.
|
|
648
669
|
const regResult = await execFileAsync('node', [cliPath, 'register'], { env, timeout: 60000 });
|
|
649
670
|
if (parseCliOutput(regResult.stdout).success) {
|
|
650
671
|
api.logger.info('[openclaw-overlay] Agent auto-registered on startup');
|
|
@@ -789,7 +810,7 @@ export default function register(api: any) {
|
|
|
789
810
|
console.error("Error:", error.message);
|
|
790
811
|
}
|
|
791
812
|
});
|
|
792
|
-
});
|
|
813
|
+
}, { commands: ["overlay"] });
|
|
793
814
|
}
|
|
794
815
|
|
|
795
816
|
async function executeOverlayAction(params: any, config: any, api: any) {
|
|
@@ -885,7 +906,6 @@ async function handleServiceRequest(params: any, env: any, cliPath: string, conf
|
|
|
885
906
|
throw new Error(`Discovery failed: ${discoverOutput.error}`);
|
|
886
907
|
}
|
|
887
908
|
|
|
888
|
-
// FIX: Use discoverOutput.data.services instead of treating data as flat array
|
|
889
909
|
const providers = discoverOutput.data.services;
|
|
890
910
|
if (!providers || providers.length === 0) {
|
|
891
911
|
throw new Error(`No providers found for service: ${service}`);
|
|
@@ -910,7 +930,7 @@ async function handleServiceRequest(params: any, env: any, cliPath: string, conf
|
|
|
910
930
|
externalProviders = targeted;
|
|
911
931
|
}
|
|
912
932
|
|
|
913
|
-
// 3. Sort by price
|
|
933
|
+
// 3. Sort by price
|
|
914
934
|
externalProviders.sort((a: any, b: any) => (a.pricing?.amountSats || 0) - (b.pricing?.amountSats || 0));
|
|
915
935
|
|
|
916
936
|
const bestProvider = externalProviders[0];
|
|
@@ -946,10 +966,6 @@ async function handleServiceRequest(params: any, env: any, cliPath: string, conf
|
|
|
946
966
|
throw new Error(`Service request failed: ${requestOutput.error}`);
|
|
947
967
|
}
|
|
948
968
|
|
|
949
|
-
// 7. Return immediately — no polling.
|
|
950
|
-
// The WebSocket background service handles incoming responses
|
|
951
|
-
// asynchronously and wakes the agent via /hooks/agent when a
|
|
952
|
-
// response arrives. This avoids blocking for up to 120s.
|
|
953
969
|
recordSpend(walletDir, price, service, bestProvider.name);
|
|
954
970
|
writeActivityEvent({ type: 'outgoing_payment', emoji: '💸', sats: price, service, provider: bestProvider.name, message: `Paid ${price} sats to ${bestProvider.name} for ${service}` });
|
|
955
971
|
|
|
@@ -1294,7 +1310,7 @@ async function handleImport(params: any, env: any, cliPath: string) {
|
|
|
1294
1310
|
const regPath = path.join(process.env.HOME || '', '.openclaw', 'openclaw-overlay', 'registration.json');
|
|
1295
1311
|
const isRegistered = fs.existsSync(regPath);
|
|
1296
1312
|
|
|
1297
|
-
if (!isRegistered && output.data?.balance >= 1000) {
|
|
1313
|
+
if (!isRegistered && (output.data?.balance || 0) >= 1000) {
|
|
1298
1314
|
// Auto-register immediately after funding
|
|
1299
1315
|
try {
|
|
1300
1316
|
const regResult = await execFileAsync('node', [cliPath, 'register'], { env, timeout: 60000 });
|
|
@@ -1464,12 +1480,10 @@ async function handleOnboard(params: any, env: any, cliPath: string) {
|
|
|
1464
1480
|
const { agentName, agentDescription } = params;
|
|
1465
1481
|
const steps = [];
|
|
1466
1482
|
|
|
1467
|
-
// Apply agent name/description to env if provided
|
|
1468
1483
|
const onboardEnv = { ...env };
|
|
1469
1484
|
if (agentName) onboardEnv.AGENT_NAME = agentName;
|
|
1470
1485
|
if (agentDescription) onboardEnv.AGENT_DESCRIPTION = agentDescription;
|
|
1471
1486
|
|
|
1472
|
-
// Step 1: Setup wallet
|
|
1473
1487
|
try {
|
|
1474
1488
|
const setup = await execFileAsync('node', [cliPath, 'setup'], { env: onboardEnv });
|
|
1475
1489
|
const setupOutput = parseCliOutput(setup.stdout);
|
|
@@ -1479,7 +1493,6 @@ async function handleOnboard(params: any, env: any, cliPath: string) {
|
|
|
1479
1493
|
return { steps, nextStep: 'Fix wallet setup error and try again' };
|
|
1480
1494
|
}
|
|
1481
1495
|
|
|
1482
|
-
// Step 2: Get address
|
|
1483
1496
|
try {
|
|
1484
1497
|
const addr = await execFileAsync('node', [cliPath, 'address'], { env: onboardEnv });
|
|
1485
1498
|
const addrOutput = parseCliOutput(addr.stdout);
|
|
@@ -1488,7 +1501,6 @@ async function handleOnboard(params: any, env: any, cliPath: string) {
|
|
|
1488
1501
|
steps.push({ step: 'address', success: false, error: err.message });
|
|
1489
1502
|
}
|
|
1490
1503
|
|
|
1491
|
-
// Step 3: Check balance
|
|
1492
1504
|
try {
|
|
1493
1505
|
const bal = await execFileAsync('node', [cliPath, 'balance'], { env: onboardEnv });
|
|
1494
1506
|
const balOutput = parseCliOutput(bal.stdout);
|
|
@@ -1506,7 +1518,6 @@ async function handleOnboard(params: any, env: any, cliPath: string) {
|
|
|
1506
1518
|
steps.push({ step: 'balance', success: false, error: err.message });
|
|
1507
1519
|
}
|
|
1508
1520
|
|
|
1509
|
-
// Step 4: Register
|
|
1510
1521
|
try {
|
|
1511
1522
|
const reg = await execFileAsync('node', [cliPath, 'register'], { env: onboardEnv, timeout: 60000 });
|
|
1512
1523
|
const regOutput = parseCliOutput(reg.stdout);
|
|
@@ -1534,7 +1545,6 @@ async function handleOnboard(params: any, env: any, cliPath: string) {
|
|
|
1534
1545
|
}
|
|
1535
1546
|
|
|
1536
1547
|
async function handlePendingRequests(env: any, cliPath: string) {
|
|
1537
|
-
// Clean up old queue entries before checking pending requests
|
|
1538
1548
|
try {
|
|
1539
1549
|
const { cleanupServiceQueue } = await import('./src/scripts/utils/storage.js');
|
|
1540
1550
|
cleanupServiceQueue();
|
|
@@ -1546,7 +1556,6 @@ async function handlePendingRequests(env: any, cliPath: string) {
|
|
|
1546
1556
|
const output = parseCliOutput(result.stdout);
|
|
1547
1557
|
if (!output.success) throw new Error(`Queue check failed: ${output.error}`);
|
|
1548
1558
|
|
|
1549
|
-
// Clear the alert file since we're checking now
|
|
1550
1559
|
const alertPath = path.join(process.env.HOME || '', '.openclaw', 'openclaw-overlay', 'pending-alert.jsonl');
|
|
1551
1560
|
try { if (fs.existsSync(alertPath)) fs.unlinkSync(alertPath); } catch {}
|
|
1552
1561
|
|
|
@@ -1560,7 +1569,6 @@ function handleActivity() {
|
|
|
1560
1569
|
const lines = fs.readFileSync(feedPath, 'utf-8')?.trim().split('\n').filter(Boolean);
|
|
1561
1570
|
const events = lines.map(l => { try { return JSON.parse(l); } catch { return null; } }).filter(Boolean);
|
|
1562
1571
|
|
|
1563
|
-
// Clear the feed after reading
|
|
1564
1572
|
fs.writeFileSync(feedPath, '');
|
|
1565
1573
|
|
|
1566
1574
|
return { events, count: events.length };
|
|
@@ -1578,7 +1586,6 @@ async function handleFulfill(params: any, env: any, cliPath: string) {
|
|
|
1578
1586
|
const output = parseCliOutput(cliResult.stdout);
|
|
1579
1587
|
if (!output.success) throw new Error(`Fulfill failed: ${output.error}`);
|
|
1580
1588
|
|
|
1581
|
-
// Clean up the request ID from tracking since it's now fulfilled
|
|
1582
1589
|
wokenRequests.delete(requestId);
|
|
1583
1590
|
|
|
1584
1591
|
writeActivityEvent({ type: 'service_fulfilled', emoji: '✅', serviceId, recipientKey: recipientKey?.slice(0, 16), message: `Fulfilled ${serviceId} request — response sent` });
|
|
@@ -1604,7 +1611,6 @@ function buildEnvironment(config: any) {
|
|
|
1604
1611
|
env.BSV_ARC_URL = config.arcUrl;
|
|
1605
1612
|
}
|
|
1606
1613
|
|
|
1607
|
-
// Set defaults
|
|
1608
1614
|
env.BSV_NETWORK = env.BSV_NETWORK || 'mainnet';
|
|
1609
1615
|
|
|
1610
1616
|
if (!env.BSV_ARC_URL) {
|
|
@@ -1622,7 +1628,7 @@ function buildEnvironment(config: any) {
|
|
|
1622
1628
|
} else if (!env.AGENT_DESCRIPTION) {
|
|
1623
1629
|
env.AGENT_DESCRIPTION = 'AI agent on the OpenClaw Overlay Network. Offers services for BSV micropayments.';
|
|
1624
1630
|
}
|
|
1625
|
-
env.AGENT_ROUTED = 'true';
|
|
1631
|
+
env.AGENT_ROUTED = 'true';
|
|
1626
1632
|
|
|
1627
1633
|
return env;
|
|
1628
1634
|
}
|
|
@@ -1635,5 +1641,3 @@ function parseCliOutput(stdout: any) {
|
|
|
1635
1641
|
throw new Error(`Failed to parse CLI output: ${error.message}`);
|
|
1636
1642
|
}
|
|
1637
1643
|
}
|
|
1638
|
-
|
|
1639
|
-
// sleep() removed — no longer needed since polling loop was removed
|
package/openclaw.plugin.json
CHANGED
|
@@ -6,9 +6,24 @@
|
|
|
6
6
|
"skills": [
|
|
7
7
|
"./SKILL.md"
|
|
8
8
|
],
|
|
9
|
+
"commands": [
|
|
10
|
+
{
|
|
11
|
+
"name": "overlay",
|
|
12
|
+
"description": "BSV Overlay Network management",
|
|
13
|
+
"isAutoreply": true
|
|
14
|
+
}
|
|
15
|
+
],
|
|
16
|
+
"contracts": {
|
|
17
|
+
"tools": [
|
|
18
|
+
{
|
|
19
|
+
"name": "overlay",
|
|
20
|
+
"description": "Access the BSV agent marketplace - discover agents and exchange BSV micropayments for services"
|
|
21
|
+
}
|
|
22
|
+
]
|
|
23
|
+
},
|
|
9
24
|
"configSchema": {
|
|
10
25
|
"type": "object",
|
|
11
|
-
"additionalProperties":
|
|
26
|
+
"additionalProperties": true,
|
|
12
27
|
"properties": {
|
|
13
28
|
"overlayUrl": {
|
|
14
29
|
"type": "string",
|
package/package.json
CHANGED