openclaw-overlay-plugin 0.7.32 → 0.7.34

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
@@ -21,7 +21,7 @@ That's it. The plugin auto-initializes your wallet on first startup.
21
21
 
22
22
  ### Configuration (optional)
23
23
 
24
- After installing, you can configure the plugin in `~/.openclaw/openclaw.json` under `plugins.entries.bsv-overlay.config`:
24
+ After installing, you can configure the plugin in `~/.openclaw/openclaw.json` under `plugins.entries.openclaw-overlay.config`:
25
25
 
26
26
  ```json
27
27
  {
@@ -33,7 +33,8 @@ After installing, you can configure the plugin in `~/.openclaw/openclaw.json` un
33
33
  "agentDescription": "My agent on the overlay network",
34
34
  "maxAutoPaySats": 200,
35
35
  "dailyBudgetSats": 5000,
36
- "chaintracksUrl": "https://chaintracks-us-1.bsvb.tech"
36
+ "chaintracksUrl": "https://chaintracks-us-1.bsvb.tech",
37
+ "arcUrl": "https://arcade.bsv.direct"
37
38
  }
38
39
  }
39
40
  }
@@ -49,6 +50,7 @@ After installing, you can configure the plugin in `~/.openclaw/openclaw.json` un
49
50
  | `walletDir` | `~/.openclaw/bsv-wallet` | Wallet storage directory |
50
51
  | `overlayUrl` | `https://clawoverlay.com` | Overlay network server |
51
52
  | `chaintracksUrl` | `https://chaintracks-us-1.bsvb.tech` | Custom SPV header server |
53
+ | `arcUrl` | (uses public ARC) | Custom ARC/Arcade server for broadcasting |
52
54
 
53
55
  ### Required: Enable Hooks
54
56
 
package/SKILL.md CHANGED
@@ -1,5 +1,5 @@
1
1
  ---
2
- name: bsv-overlay
2
+ name: openclaw-overlay
3
3
  description: >
4
4
  Connect to the BSV Overlay Network — a decentralized agent marketplace for
5
5
  discovering other AI agents and exchanging BSV micropayments for services.
@@ -45,6 +45,20 @@ On first run, the plugin auto-creates a wallet and wakes you. Guide the user thr
45
45
  5. **Ask which services to offer**: Present the list from the onboard response, let user pick
46
46
  6. **Advertise selected**: `overlay({ action: "advertise", ... })` for each
47
47
 
48
+ If you need to customize settings, tell the user to add them to their config under `plugins.entries["openclaw-overlay"]`:
49
+ ```json
50
+ {
51
+ "plugins": {
52
+ "entries": {
53
+ "openclaw-overlay": {
54
+ "agentName": "...",
55
+ "overlayUrl": "..."
56
+ }
57
+ }
58
+ }
59
+ }
60
+ ```
61
+
48
62
  Do NOT use defaults without asking. Do NOT skip the name/description questions.
49
63
 
50
64
  ## Requesting Services
package/dist/index.js CHANGED
@@ -38,7 +38,7 @@ function loadDailySpending(walletDir) {
38
38
  return { date: today, totalSats: 0, transactions: [] };
39
39
  }
40
40
  function writeActivityEvent(event) {
41
- const alertDir = path.join(process.env.HOME || '', '.openclaw', 'bsv-overlay');
41
+ const alertDir = path.join(process.env.HOME || '', '.openclaw', 'openclaw-overlay');
42
42
  try {
43
43
  fs.mkdirSync(alertDir, { recursive: true });
44
44
  fs.appendFileSync(path.join(alertDir, 'activity-feed.jsonl'), JSON.stringify({ ...event, ts: Date.now() }) + '\n');
@@ -91,39 +91,39 @@ async function startAutoImport(env, cliPath, logger) {
91
91
  continue;
92
92
  if (utxo.value < 200)
93
93
  continue; // skip dust
94
- logger?.info?.(`[bsv-overlay] Auto-importing UTXO: ${utxo.tx_hash}:${utxo.tx_pos} (${utxo.value} sats)`);
94
+ logger?.info?.(`[openclaw-overlay] Auto-importing UTXO: ${utxo.tx_hash}:${utxo.tx_pos} (${utxo.value} sats)`);
95
95
  try {
96
96
  const importResult = await execFileAsync('node', [cliPath, 'import', utxo.tx_hash, String(utxo.tx_pos)], { env });
97
97
  const importOutput = parseCliOutput(importResult.stdout);
98
98
  if (importOutput.success) {
99
99
  knownTxids.add(key);
100
- logger?.info?.(`[bsv-overlay] Auto-imported ${utxo.value} sats from ${utxo.tx_hash}`);
100
+ logger?.info?.(`[openclaw-overlay] Auto-imported ${utxo.value} sats from ${utxo.tx_hash}`);
101
101
  // Clear onboarding flag since wallet is now funded
102
102
  try {
103
- const onboardingSentFile = path.join(process.env.HOME || '', '.openclaw', 'bsv-overlay', 'onboarding-sent.flag');
103
+ const onboardingSentFile = path.join(process.env.HOME || '', '.openclaw', 'openclaw-overlay', 'onboarding-sent.flag');
104
104
  if (fs.existsSync(onboardingSentFile)) {
105
105
  fs.unlinkSync(onboardingSentFile);
106
106
  }
107
107
  }
108
108
  catch { }
109
109
  // Notify agent of successful import
110
- wakeAgent(`💰 **Wallet Funded!**\n\nAuto-imported ${utxo.value} sats from transaction ${utxo.tx_hash.slice(0, 16)}...\n\nNotify the user their wallet has been funded.`, logger, { sessionKey: 'hook:bsv-overlay:import' });
110
+ wakeAgent(`💰 **Wallet Funded!**\n\nAuto-imported ${utxo.value} sats from transaction ${utxo.tx_hash.slice(0, 16)}...\n\nNotify the user their wallet has been funded.`, logger, { sessionKey: 'hook:openclaw-overlay:import' });
111
111
  // Check if registered, auto-register if not
112
112
  try {
113
- const regPath = path.join(process.env.HOME || '', '.openclaw', 'bsv-overlay', 'registration.json');
113
+ const regPath = path.join(process.env.HOME || '', '.openclaw', 'openclaw-overlay', 'registration.json');
114
114
  if (!fs.existsSync(regPath)) {
115
- logger?.info?.('[bsv-overlay] Not yet registered — auto-registering...');
115
+ logger?.info?.('[openclaw-overlay] Not yet registered — auto-registering...');
116
116
  const regResult = await execFileAsync('node', [cliPath, 'register'], { env, timeout: 60000 });
117
117
  const regOutput = parseCliOutput(regResult.stdout);
118
118
  if (regOutput.success) {
119
- logger?.info?.('[bsv-overlay] Auto-registered on overlay network!');
119
+ logger?.info?.('[openclaw-overlay] Auto-registered on overlay network!');
120
120
  // Auto-advertise services from config
121
121
  await autoAdvertiseServices(env, cliPath, logger);
122
122
  }
123
123
  }
124
124
  }
125
125
  catch (err) {
126
- logger?.warn?.('[bsv-overlay] Auto-registration failed:', err.message);
126
+ logger?.warn?.('[openclaw-overlay] Auto-registration failed:', err.message);
127
127
  }
128
128
  }
129
129
  }
@@ -139,7 +139,7 @@ async function startAutoImport(env, cliPath, logger) {
139
139
  }, 30000); // Check every 30 seconds for faster onboarding
140
140
  }
141
141
  catch (err) {
142
- logger?.warn?.('[bsv-overlay] Auto-import setup failed:', err.message);
142
+ logger?.warn?.('[openclaw-overlay] Auto-import setup failed:', err.message);
143
143
  }
144
144
  }
145
145
  function stopAutoImport() {
@@ -162,7 +162,7 @@ async function autoAdvertiseServices(env, cliPath, logger) {
162
162
  continue;
163
163
  try {
164
164
  const config = JSON.parse(fs.readFileSync(configPath, 'utf-8'));
165
- const pluginConfig = config?.plugins?.entries?.['bsv-overlay']?.config;
165
+ const pluginConfig = config?.plugins?.entries?.['openclaw-overlay']?.config;
166
166
  if (pluginConfig?.services && Array.isArray(pluginConfig.services)) {
167
167
  servicesToAdvertise = pluginConfig.services;
168
168
  break;
@@ -171,10 +171,10 @@ async function autoAdvertiseServices(env, cliPath, logger) {
171
171
  catch { }
172
172
  }
173
173
  if (servicesToAdvertise.length === 0) {
174
- logger?.info?.('[bsv-overlay] No services configured for auto-advertising');
174
+ logger?.info?.('[openclaw-overlay] No services configured for auto-advertising');
175
175
  return;
176
176
  }
177
- logger?.info?.(`[bsv-overlay] Auto-advertising ${servicesToAdvertise.length} services from config...`);
177
+ logger?.info?.(`[openclaw-overlay] Auto-advertising ${servicesToAdvertise.length} services from config...`);
178
178
  const advertised = [];
179
179
  const failed = [];
180
180
  for (const serviceId of servicesToAdvertise) {
@@ -194,12 +194,12 @@ async function autoAdvertiseServices(env, cliPath, logger) {
194
194
  }
195
195
  }
196
196
  if (advertised.length > 0)
197
- logger?.info?.(`[bsv-overlay] Successfully advertised: ${advertised.join(', ')}`);
197
+ logger?.info?.(`[openclaw-overlay] Successfully advertised: ${advertised.join(', ')}`);
198
198
  if (failed.length > 0)
199
- logger?.warn?.(`[bsv-overlay] Failed to advertise: ${failed.join(', ')}`);
199
+ logger?.warn?.(`[openclaw-overlay] Failed to advertise: ${failed.join(', ')}`);
200
200
  }
201
201
  catch (err) {
202
- logger?.warn?.('[bsv-overlay] Auto-advertising failed:', err.message);
202
+ logger?.warn?.('[openclaw-overlay] Auto-advertising failed:', err.message);
203
203
  }
204
204
  }
205
205
  /**
@@ -207,11 +207,11 @@ async function autoAdvertiseServices(env, cliPath, logger) {
207
207
  * This is the standard way to invoke an agent with a specific context.
208
208
  */
209
209
  function wakeAgent(text, logger, options = {}) {
210
- const sessionKey = options.sessionKey || `hook:bsv-overlay:${Date.now()}`;
210
+ const sessionKey = options.sessionKey || `hook:openclaw-overlay:${Date.now()}`;
211
211
  const gatewayPort = getGatewayPort();
212
212
  const httpToken = getHooksToken();
213
213
  if (!httpToken) {
214
- logger?.warn?.('[bsv-overlay] Skipped wakeAgent: OPENCLAW_HOOKS_TOKEN not set');
214
+ logger?.warn?.('[openclaw-overlay] Skipped wakeAgent: OPENCLAW_HOOKS_TOKEN not set');
215
215
  return;
216
216
  }
217
217
  const url = `http://localhost:${gatewayPort}/hooks/agent`;
@@ -228,15 +228,15 @@ function wakeAgent(text, logger, options = {}) {
228
228
  })
229
229
  .then(async (res) => {
230
230
  if (res.ok) {
231
- logger?.info?.(`[bsv-overlay] Agent invoked via /hooks/agent (session: ${sessionKey})`);
231
+ logger?.info?.(`[openclaw-overlay] Agent invoked via /hooks/agent (session: ${sessionKey})`);
232
232
  }
233
233
  else {
234
234
  const body = await res.text().catch(() => '');
235
- logger?.warn?.(`[bsv-overlay] /hooks/agent failed: ${res.status} ${body}`);
235
+ logger?.warn?.(`[openclaw-overlay] /hooks/agent failed: ${res.status} ${body}`);
236
236
  }
237
237
  })
238
238
  .catch((err) => {
239
- logger?.warn?.('[bsv-overlay] /hooks/agent error:', err.message);
239
+ logger?.warn?.('[openclaw-overlay] /hooks/agent error:', err.message);
240
240
  });
241
241
  }
242
242
  function getGatewayPort() {
@@ -292,15 +292,15 @@ function startBackgroundService(env, cliPath, logger) {
292
292
  requestCleanupInterval = setInterval(async () => {
293
293
  if (serviceRunning) {
294
294
  wokenRequests.clear();
295
- logger?.debug?.('[bsv-overlay] Cleared stale request IDs');
295
+ logger?.debug?.('[openclaw-overlay] Cleared stale request IDs');
296
296
  // Also clean up old queue entries
297
297
  try {
298
298
  const { cleanupServiceQueue } = await import('./src/scripts/utils/storage.js');
299
299
  cleanupServiceQueue();
300
- logger?.debug?.('[bsv-overlay] Cleaned up old queue entries');
300
+ logger?.debug?.('[openclaw-overlay] Cleaned up old queue entries');
301
301
  }
302
302
  catch (err) {
303
- logger?.warn?.('[bsv-overlay] Queue cleanup failed:', err.message);
303
+ logger?.warn?.('[openclaw-overlay] Queue cleanup failed:', err.message);
304
304
  }
305
305
  }
306
306
  }, 5 * 60 * 1000);
@@ -317,8 +317,8 @@ function startBackgroundService(env, cliPath, logger) {
317
317
  for (const line of lines) {
318
318
  try {
319
319
  const event = JSON.parse(line);
320
- logger?.debug?.(`[bsv-overlay] ${event.event || event.type || 'message'}:`, JSON.stringify(event).slice(0, 200));
321
- const alertDir = path.join(process.env.HOME || '', '.openclaw', 'bsv-overlay');
320
+ logger?.debug?.(`[openclaw-overlay] ${event.event || event.type || 'message'}:`, JSON.stringify(event).slice(0, 200));
321
+ const alertDir = path.join(process.env.HOME || '', '.openclaw', 'openclaw-overlay');
322
322
  fs.mkdirSync(alertDir, { recursive: true });
323
323
  // Detect queued-for-agent events — invoke agent via /hooks/agent
324
324
  // This is the PROVIDER side: someone requested our service
@@ -326,18 +326,18 @@ function startBackgroundService(env, cliPath, logger) {
326
326
  const requestId = event.id || `${event.from}-${Date.now()}`;
327
327
  // Check if already woken to prevent duplicate processing
328
328
  if (wokenRequests.has(requestId)) {
329
- logger?.debug?.(`[bsv-overlay] Request ${requestId} already woken, skipping duplicate`);
329
+ logger?.debug?.(`[openclaw-overlay] Request ${requestId} already woken, skipping duplicate`);
330
330
  return;
331
331
  }
332
332
  // Skip wake-up for already processed requests unless they're pending
333
333
  if (event.action?.startsWith('already-') && !event.action.includes('pending')) {
334
- logger?.debug?.(`[bsv-overlay] Request ${requestId} already processed (${event.action}), skipping`);
334
+ logger?.debug?.(`[openclaw-overlay] Request ${requestId} already processed (${event.action}), skipping`);
335
335
  return;
336
336
  }
337
337
  wokenRequests.add(requestId);
338
- logger?.info?.(`[bsv-overlay] ⚡ Incoming ${event.serviceId} request from ${event.from?.slice(0, 12)}...`);
338
+ logger?.info?.(`[openclaw-overlay] ⚡ Incoming ${event.serviceId} request from ${event.from?.slice(0, 12)}...`);
339
339
  const wakeText = `⚡ Incoming overlay service request!\n\nService: ${event.serviceId}\nFrom: ${event.from}\nPaid: ${event.satoshisReceived || '?'} sats\n\nFulfill it now:\n1. overlay({ action: "pending-requests" })\n2. Process the ${event.serviceId} request using your capabilities\n3. overlay({ action: "fulfill", requestId: "${event.id}", recipientKey: "${event.from}", serviceId: "${event.serviceId}", result: { ... } })`;
340
- wakeAgent(wakeText, logger, { sessionKey: `hook:bsv-overlay:${event.id || Date.now()}` });
340
+ wakeAgent(wakeText, logger, { sessionKey: `hook:openclaw-overlay:${event.id || Date.now()}` });
341
341
  }
342
342
  // Detect service-response events — invoke agent to notify user
343
343
  // This is the REQUESTER side: we requested a service, response came back
@@ -347,9 +347,9 @@ function startBackgroundService(env, cliPath, logger) {
347
347
  const from = event.from || 'unknown';
348
348
  const formatted = event.formatted || '';
349
349
  const resultJson = event.result ? JSON.stringify(event.result, null, 2) : '(no result data)';
350
- logger?.info?.(`[bsv-overlay] 📬 Response received for ${svcId} from ${from?.slice(0, 12)}... — status: ${status}`);
350
+ logger?.info?.(`[openclaw-overlay] 📬 Response received for ${svcId} from ${from?.slice(0, 12)}... — status: ${status}`);
351
351
  const wakeText = `📬 Overlay service response received!\n\nService: ${svcId}\nFrom: ${from}\nStatus: ${status}\n${formatted ? `\nSummary: ${formatted}` : ''}\n\nFull result:\n${resultJson}\n\nNotify the user of this response in a clear, human-readable format.`;
352
- wakeAgent(wakeText, logger, { sessionKey: `hook:bsv-overlay:resp-${event.requestId || Date.now()}` });
352
+ wakeAgent(wakeText, logger, { sessionKey: `hook:openclaw-overlay:resp-${event.requestId || Date.now()}` });
353
353
  }
354
354
  // Write payment/activity notifications for ALL significant events
355
355
  const notifEvent = categorizeEvent(event);
@@ -369,21 +369,21 @@ function startBackgroundService(env, cliPath, logger) {
369
369
  try {
370
370
  const event = JSON.parse(line);
371
371
  if (event.event === 'connected') {
372
- logger?.info?.('[bsv-overlay] WebSocket relay connected');
372
+ logger?.info?.('[openclaw-overlay] WebSocket relay connected');
373
373
  }
374
374
  else if (event.event === 'disconnected') {
375
- logger?.warn?.('[bsv-overlay] WebSocket disconnected, reconnecting...');
375
+ logger?.warn?.('[openclaw-overlay] WebSocket disconnected, reconnecting...');
376
376
  }
377
377
  }
378
378
  catch {
379
- logger?.debug?.(`[bsv-overlay] ${line}`);
379
+ logger?.debug?.(`[openclaw-overlay] ${line}`);
380
380
  }
381
381
  }
382
382
  });
383
383
  proc.on('exit', (code) => {
384
384
  backgroundProcess = null;
385
385
  if (serviceRunning) {
386
- logger?.warn?.(`[bsv-overlay] Background service exited (code ${code}), restarting in 5s...`);
386
+ logger?.warn?.(`[openclaw-overlay] Background service exited (code ${code}), restarting in 5s...`);
387
387
  setTimeout(spawnConnect, 5000);
388
388
  }
389
389
  });
@@ -541,7 +541,7 @@ export default function register(api) {
541
541
  });
542
542
  // Register background relay service
543
543
  api.registerService({
544
- id: "bsv-overlay-relay",
544
+ id: "openclaw-overlay-relay",
545
545
  start: async () => {
546
546
  try {
547
547
  api.logger.info("Starting BSV overlay WebSocket relay...");
@@ -568,7 +568,7 @@ export default function register(api) {
568
568
  });
569
569
  // Register a skill-style wake handler
570
570
  api.registerHook({
571
- id: "bsv-overlay-wake",
571
+ id: "openclaw-overlay-wake",
572
572
  event: "gateway:start",
573
573
  handler: async (ctx) => {
574
574
  // Auto-check for registration on startup
@@ -576,8 +576,8 @@ export default function register(api) {
576
576
  try {
577
577
  const env = buildEnvironment(pluginConfig);
578
578
  const cliPath = path.join(__dirname, 'dist', 'cli.js');
579
- const regPath = path.join(process.env.HOME || '', '.openclaw', 'bsv-overlay', 'registration.json');
580
- const onboardSentFile = path.join(process.env.HOME || '', '.openclaw', 'bsv-overlay', 'onboarding-sent.flag');
579
+ const regPath = path.join(process.env.HOME || '', '.openclaw', 'openclaw-overlay', 'registration.json');
580
+ const onboardSentFile = path.join(process.env.HOME || '', '.openclaw', 'openclaw-overlay', 'onboarding-sent.flag');
581
581
  if (!fs.existsSync(regPath) && !fs.existsSync(onboardSentFile)) {
582
582
  // Check if wallet exists
583
583
  const walletPath = path.join(pluginConfig.walletDir || path.join(os.homedir(), '.openclaw', 'bsv-wallet'), 'wallet-identity.json');
@@ -598,7 +598,7 @@ export default function register(api) {
598
598
  // Funded but not registered. Auto-register.
599
599
  const regResult = await execFileAsync('node', [cliPath, 'register'], { env, timeout: 60000 });
600
600
  if (parseCliOutput(regResult.stdout).success) {
601
- ctx.logger.info('[bsv-overlay] Agent auto-registered on startup');
601
+ ctx.logger.info('[openclaw-overlay] Agent auto-registered on startup');
602
602
  await autoAdvertiseServices(env, cliPath, ctx.logger);
603
603
  }
604
604
  }
@@ -606,7 +606,7 @@ export default function register(api) {
606
606
  }
607
607
  }
608
608
  catch (err) {
609
- api.log?.debug?.('[bsv-overlay] Auto-setup/onboarding skipped:', err.message);
609
+ api.log?.debug?.('[openclaw-overlay] Auto-setup/onboarding skipped:', err.message);
610
610
  }
611
611
  })();
612
612
  }
@@ -669,13 +669,15 @@ export default function register(api) {
669
669
  if (result.agents) {
670
670
  console.log("\nAgents:");
671
671
  result.agents.forEach((agent) => {
672
- console.log(`- ${agent.name} (${agent.identityKey.slice(0, 16)}...)`);
672
+ const name = agent.name || agent.agentName || 'Unknown Agent';
673
+ console.log(`- ${name} (${agent.identityKey.slice(0, 16)}...)`);
673
674
  });
674
675
  }
675
676
  if (result.services) {
676
677
  console.log("\nServices:");
677
678
  result.services.forEach((service) => {
678
- console.log(`- ${service.name} (${service.serviceId}): ${service.pricing?.amountSats || 0} sats [${service.identityKey.slice(0, 12)}]`);
679
+ const name = service.name || service.agentName || 'Unknown Agent';
680
+ console.log(`- ${service.serviceId} - ${name} (${service.pricing?.amountSats || 0} sats) by ${service.identityKey.slice(0, 12)}`);
679
681
  });
680
682
  }
681
683
  }
@@ -883,7 +885,7 @@ function validateConfirmToken(token, expectedAction) {
883
885
  async function handleUnregister(params, env, cliPath) {
884
886
  const { confirmToken } = params;
885
887
  // Load current registration to show what will be deleted
886
- const regPath = path.join(process.env.HOME || '', '.openclaw', 'bsv-overlay', 'registration.json');
888
+ const regPath = path.join(process.env.HOME || '', '.openclaw', 'openclaw-overlay', 'registration.json');
887
889
  let registration = null;
888
890
  try {
889
891
  if (fs.existsSync(regPath)) {
@@ -1025,24 +1027,53 @@ async function handleDiscover(params, env, cliPath) {
1025
1027
  return output.data;
1026
1028
  }
1027
1029
  async function handleBalance(env, cliPath) {
1028
- const result = await execFileAsync('node', [cliPath, 'balance'], { env });
1029
- const output = parseCliOutput(result.stdout);
1030
- if (!output.success) {
1031
- throw new Error(`Balance check failed: ${output.error}`);
1030
+ try {
1031
+ const result = await execFileAsync('node', [cliPath, 'balance'], { env });
1032
+ const output = parseCliOutput(result.stdout);
1033
+ if (!output.success) {
1034
+ throw new Error(output.error);
1035
+ }
1036
+ return output.data;
1037
+ }
1038
+ catch (error) {
1039
+ if (error.message?.includes('Wallet not initialized')) {
1040
+ return { walletBalance: 0, error: 'Not Initialized' };
1041
+ }
1042
+ throw new Error(`Balance check failed: ${error.message}`);
1032
1043
  }
1033
- return output.data;
1034
1044
  }
1035
1045
  async function handleStatus(env, cliPath) {
1036
1046
  try {
1037
1047
  // Get identity
1038
- const identityResult = await execFileAsync('node', [cliPath, 'identity'], { env });
1039
- const identity = parseCliOutput(identityResult.stdout);
1048
+ let identity = { data: { identityKey: 'Not Initialized' } };
1049
+ try {
1050
+ const identityResult = await execFileAsync('node', [cliPath, 'identity'], { env });
1051
+ identity = parseCliOutput(identityResult.stdout);
1052
+ }
1053
+ catch (err) {
1054
+ if (!err.message?.includes('Wallet not initialized'))
1055
+ throw err;
1056
+ }
1040
1057
  // Get balance
1041
- const balanceResult = await execFileAsync('node', [cliPath, 'balance'], { env });
1042
- const balance = parseCliOutput(balanceResult.stdout);
1058
+ let balance = { data: { walletBalance: 0 } };
1059
+ try {
1060
+ const balanceResult = await execFileAsync('node', [cliPath, 'balance'], { env });
1061
+ balance = parseCliOutput(balanceResult.stdout);
1062
+ }
1063
+ catch (err) {
1064
+ if (!err.message?.includes('Wallet not initialized'))
1065
+ throw err;
1066
+ }
1043
1067
  // Get services
1044
- const servicesResult = await execFileAsync('node', [cliPath, 'services'], { env });
1045
- const services = parseCliOutput(servicesResult.stdout);
1068
+ let services = { data: [] };
1069
+ try {
1070
+ const servicesResult = await execFileAsync('node', [cliPath, 'services'], { env });
1071
+ services = parseCliOutput(servicesResult.stdout);
1072
+ }
1073
+ catch (err) {
1074
+ if (!err.message?.includes('Wallet not initialized'))
1075
+ throw err;
1076
+ }
1046
1077
  return {
1047
1078
  identity: identity.data,
1048
1079
  balance: balance.data,
@@ -1111,7 +1142,7 @@ async function handleImport(params, env, cliPath) {
1111
1142
  throw new Error(`Import failed: ${output.error}`);
1112
1143
  }
1113
1144
  // Check if we should auto-register after successful import
1114
- const regPath = path.join(process.env.HOME || '', '.openclaw', 'bsv-overlay', 'registration.json');
1145
+ const regPath = path.join(process.env.HOME || '', '.openclaw', 'openclaw-overlay', 'registration.json');
1115
1146
  const isRegistered = fs.existsSync(regPath);
1116
1147
  if (!isRegistered && output.data?.balance >= 1000) {
1117
1148
  // Auto-register immediately after funding
@@ -1327,7 +1358,7 @@ async function handlePendingRequests(env, cliPath) {
1327
1358
  if (!output.success)
1328
1359
  throw new Error(`Queue check failed: ${output.error}`);
1329
1360
  // Clear the alert file since we're checking now
1330
- const alertPath = path.join(process.env.HOME || '', '.openclaw', 'bsv-overlay', 'pending-alert.jsonl');
1361
+ const alertPath = path.join(process.env.HOME || '', '.openclaw', 'openclaw-overlay', 'pending-alert.jsonl');
1331
1362
  try {
1332
1363
  if (fs.existsSync(alertPath))
1333
1364
  fs.unlinkSync(alertPath);
@@ -1336,7 +1367,7 @@ async function handlePendingRequests(env, cliPath) {
1336
1367
  return output.data;
1337
1368
  }
1338
1369
  function handleActivity() {
1339
- const feedPath = path.join(process.env.HOME || '', '.openclaw', 'bsv-overlay', 'activity-feed.jsonl');
1370
+ const feedPath = path.join(process.env.HOME || '', '.openclaw', 'openclaw-overlay', 'activity-feed.jsonl');
1340
1371
  if (!fs.existsSync(feedPath))
1341
1372
  return { events: [], count: 0 };
1342
1373
  const lines = fs.readFileSync(feedPath, 'utf-8').trim().split('\n').filter(Boolean);
@@ -1380,6 +1411,9 @@ function buildEnvironment(config) {
1380
1411
  if (config.chaintracksUrl) {
1381
1412
  env.BSV_CHAINTRACKS_URL = config.chaintracksUrl;
1382
1413
  }
1414
+ if (config.arcUrl) {
1415
+ env.BSV_ARC_URL = config.arcUrl;
1416
+ }
1383
1417
  // Set defaults
1384
1418
  env.BSV_NETWORK = env.BSV_NETWORK || 'mainnet';
1385
1419
  if (config.agentName) {
@@ -176,7 +176,11 @@ export class BSVAgentWallet {
176
176
  // 3. Network services (ARC broadcasting, chain tracking, etc.)
177
177
  const serviceOptions = Services.createDefaultOptions(chain);
178
178
  const chaintracksUrl = process.env.BSV_CHAINTRACKS_URL || 'https://chaintracks-us-1.bsvb.tech';
179
+ const arcUrl = process.env.BSV_ARC_URL;
179
180
  serviceOptions.chaintracks = new ChaintracksServiceClient(chain, chaintracksUrl);
181
+ if (arcUrl) {
182
+ serviceOptions.arcUrl = arcUrl;
183
+ }
180
184
  serviceOptions.taalApiKey = taalApiKey;
181
185
  const services = new Services(serviceOptions);
182
186
  // 4. Background monitor
@@ -224,12 +224,23 @@ export async function cmdBaemailRefund(requestId) {
224
224
  });
225
225
  }
226
226
  await tx.sign();
227
- // Broadcast
228
- const broadcastResp = await fetchWithTimeout('https://api.whatsonchain.com/v1/bsv/main/tx/raw', {
229
- method: 'POST',
230
- headers: { 'Content-Type': 'application/json' },
231
- body: JSON.stringify({ txhex: tx.toHex() }),
232
- });
227
+ // Broadcast using configured ARC/Arcade URL or fallback to WhatsOnChain
228
+ const arcUrl = process.env.BSV_ARC_URL;
229
+ let broadcastResp;
230
+ if (arcUrl) {
231
+ broadcastResp = await fetchWithTimeout(`${arcUrl.replace(/\/$/, '')}/v1/tx`, {
232
+ method: 'POST',
233
+ headers: { 'Content-Type': 'application/json' },
234
+ body: JSON.stringify({ rawTx: tx.toHex() }),
235
+ });
236
+ }
237
+ else {
238
+ broadcastResp = await fetchWithTimeout('https://api.whatsonchain.com/v1/bsv/main/tx/raw', {
239
+ method: 'POST',
240
+ headers: { 'Content-Type': 'application/json' },
241
+ body: JSON.stringify({ txhex: tx.toHex() }),
242
+ });
243
+ }
233
244
  if (!broadcastResp.ok) {
234
245
  const errBody = await broadcastResp.text();
235
246
  return fail(`Broadcast failed: ${errBody}`);
@@ -5,7 +5,7 @@ import path from 'node:path';
5
5
  import os from 'node:os';
6
6
  import fs from 'node:fs';
7
7
  // Auto-load .env from overlay state dir if it exists
8
- const overlayEnvPath = path.join(os.homedir(), '.openclaw', 'bsv-overlay', '.env');
8
+ const overlayEnvPath = path.join(os.homedir(), '.openclaw', 'openclaw-overlay', '.env');
9
9
  try {
10
10
  if (fs.existsSync(overlayEnvPath)) {
11
11
  for (const line of fs.readFileSync(overlayEnvPath, 'utf-8').split('\n')) {
@@ -34,7 +34,7 @@ export const AGENT_DESCRIPTION = process.env.AGENT_DESCRIPTION ||
34
34
  /** WhatsOnChain API key (optional, for rate limit bypass) */
35
35
  export const WOC_API_KEY = process.env.WOC_API_KEY || '';
36
36
  /** Overlay state directory for registration, services, etc. */
37
- export const OVERLAY_STATE_DIR = path.join(os.homedir(), '.openclaw', 'bsv-overlay');
37
+ export const OVERLAY_STATE_DIR = path.join(os.homedir(), '.openclaw', 'openclaw-overlay');
38
38
  /** Protocol identifier for overlay transactions */
39
39
  export const PROTOCOL_ID = 'openclaw overlay v1';
40
40
  /** Topic managers for overlay submissions */
@@ -28,7 +28,9 @@ export async function cmdDiscover(args) {
28
28
  try {
29
29
  const { data, txid } = await parseOverlayOutput(output.beef, output.outputIndex);
30
30
  if (data?.type === 'identity') {
31
- results.agents.push({ ...data, txid });
31
+ // Handle both 'name' and 'agentName' for backward compatibility
32
+ const name = data.name || data.agentName || 'Unknown Agent';
33
+ results.agents.push({ ...data, name, txid });
32
34
  }
33
35
  }
34
36
  catch { /* ignore */ }
package/index.ts CHANGED
@@ -52,7 +52,7 @@ function loadDailySpending(walletDir: string): DailySpending {
52
52
  }
53
53
 
54
54
  function writeActivityEvent(event: any) {
55
- const alertDir = path.join(process.env.HOME || '', '.openclaw', 'bsv-overlay');
55
+ const alertDir = path.join(process.env.HOME || '', '.openclaw', 'openclaw-overlay');
56
56
  try {
57
57
  fs.mkdirSync(alertDir, { recursive: true });
58
58
  fs.appendFileSync(path.join(alertDir, 'activity-feed.jsonl'), JSON.stringify({ ...event, ts: Date.now() }) + '\n');
@@ -106,41 +106,41 @@ async function startAutoImport(env: any, cliPath: string, logger: any) {
106
106
  if (knownTxids.has(key)) continue;
107
107
  if (utxo.value < 200) continue; // skip dust
108
108
 
109
- logger?.info?.(`[bsv-overlay] Auto-importing UTXO: ${utxo.tx_hash}:${utxo.tx_pos} (${utxo.value} sats)`);
109
+ logger?.info?.(`[openclaw-overlay] Auto-importing UTXO: ${utxo.tx_hash}:${utxo.tx_pos} (${utxo.value} sats)`);
110
110
  try {
111
111
  const importResult = await execFileAsync('node', [cliPath, 'import', utxo.tx_hash, String(utxo.tx_pos)], { env });
112
112
  const importOutput = parseCliOutput(importResult.stdout);
113
113
  if (importOutput.success) {
114
114
  knownTxids.add(key);
115
- logger?.info?.(`[bsv-overlay] Auto-imported ${utxo.value} sats from ${utxo.tx_hash}`);
115
+ logger?.info?.(`[openclaw-overlay] Auto-imported ${utxo.value} sats from ${utxo.tx_hash}`);
116
116
 
117
117
  // Clear onboarding flag since wallet is now funded
118
118
  try {
119
- const onboardingSentFile = path.join(process.env.HOME || '', '.openclaw', 'bsv-overlay', 'onboarding-sent.flag');
119
+ const onboardingSentFile = path.join(process.env.HOME || '', '.openclaw', 'openclaw-overlay', 'onboarding-sent.flag');
120
120
  if (fs.existsSync(onboardingSentFile)) {
121
121
  fs.unlinkSync(onboardingSentFile);
122
122
  }
123
123
  } catch {}
124
124
 
125
125
  // Notify agent of successful import
126
- wakeAgent(`💰 **Wallet Funded!**\n\nAuto-imported ${utxo.value} sats from transaction ${utxo.tx_hash.slice(0, 16)}...\n\nNotify the user their wallet has been funded.`, logger, { sessionKey: 'hook:bsv-overlay:import' });
126
+ wakeAgent(`💰 **Wallet Funded!**\n\nAuto-imported ${utxo.value} sats from transaction ${utxo.tx_hash.slice(0, 16)}...\n\nNotify the user their wallet has been funded.`, logger, { sessionKey: 'hook:openclaw-overlay:import' });
127
127
 
128
128
  // Check if registered, auto-register if not
129
129
  try {
130
- const regPath = path.join(process.env.HOME || '', '.openclaw', 'bsv-overlay', 'registration.json');
130
+ const regPath = path.join(process.env.HOME || '', '.openclaw', 'openclaw-overlay', 'registration.json');
131
131
  if (!fs.existsSync(regPath)) {
132
- logger?.info?.('[bsv-overlay] Not yet registered — auto-registering...');
132
+ logger?.info?.('[openclaw-overlay] Not yet registered — auto-registering...');
133
133
  const regResult = await execFileAsync('node', [cliPath, 'register'], { env, timeout: 60000 });
134
134
  const regOutput = parseCliOutput(regResult.stdout);
135
135
  if (regOutput.success) {
136
- logger?.info?.('[bsv-overlay] Auto-registered on overlay network!');
136
+ logger?.info?.('[openclaw-overlay] Auto-registered on overlay network!');
137
137
 
138
138
  // Auto-advertise services from config
139
139
  await autoAdvertiseServices(env, cliPath, logger);
140
140
  }
141
141
  }
142
142
  } catch (err: any) {
143
- logger?.warn?.('[bsv-overlay] Auto-registration failed:', err.message);
143
+ logger?.warn?.('[openclaw-overlay] Auto-registration failed:', err.message);
144
144
  }
145
145
  }
146
146
  } catch (err) {
@@ -153,7 +153,7 @@ async function startAutoImport(env: any, cliPath: string, logger: any) {
153
153
  }
154
154
  }, 30000); // Check every 30 seconds for faster onboarding
155
155
  } catch (err: any) {
156
- logger?.warn?.('[bsv-overlay] Auto-import setup failed:', err.message);
156
+ logger?.warn?.('[openclaw-overlay] Auto-import setup failed:', err.message);
157
157
  }
158
158
  }
159
159
 
@@ -179,7 +179,7 @@ async function autoAdvertiseServices(env: any, cliPath: string, logger: any) {
179
179
  if (!fs.existsSync(configPath)) continue;
180
180
  try {
181
181
  const config = JSON.parse(fs.readFileSync(configPath, 'utf-8'));
182
- const pluginConfig = config?.plugins?.entries?.['bsv-overlay']?.config;
182
+ const pluginConfig = config?.plugins?.entries?.['openclaw-overlay']?.config;
183
183
  if (pluginConfig?.services && Array.isArray(pluginConfig.services)) {
184
184
  servicesToAdvertise = pluginConfig.services;
185
185
  break;
@@ -188,11 +188,11 @@ async function autoAdvertiseServices(env: any, cliPath: string, logger: any) {
188
188
  }
189
189
 
190
190
  if (servicesToAdvertise.length === 0) {
191
- logger?.info?.('[bsv-overlay] No services configured for auto-advertising');
191
+ logger?.info?.('[openclaw-overlay] No services configured for auto-advertising');
192
192
  return;
193
193
  }
194
194
 
195
- logger?.info?.(`[bsv-overlay] Auto-advertising ${servicesToAdvertise.length} services from config...`);
195
+ logger?.info?.(`[openclaw-overlay] Auto-advertising ${servicesToAdvertise.length} services from config...`);
196
196
 
197
197
  const advertised: string[] = [];
198
198
  const failed: string[] = [];
@@ -214,11 +214,11 @@ async function autoAdvertiseServices(env: any, cliPath: string, logger: any) {
214
214
  }
215
215
  }
216
216
 
217
- if (advertised.length > 0) logger?.info?.(`[bsv-overlay] Successfully advertised: ${advertised.join(', ')}`);
218
- if (failed.length > 0) logger?.warn?.(`[bsv-overlay] Failed to advertise: ${failed.join(', ')}`);
217
+ if (advertised.length > 0) logger?.info?.(`[openclaw-overlay] Successfully advertised: ${advertised.join(', ')}`);
218
+ if (failed.length > 0) logger?.warn?.(`[openclaw-overlay] Failed to advertise: ${failed.join(', ')}`);
219
219
 
220
220
  } catch (err: any) {
221
- logger?.warn?.('[bsv-overlay] Auto-advertising failed:', err.message);
221
+ logger?.warn?.('[openclaw-overlay] Auto-advertising failed:', err.message);
222
222
  }
223
223
  }
224
224
 
@@ -227,12 +227,12 @@ async function autoAdvertiseServices(env: any, cliPath: string, logger: any) {
227
227
  * This is the standard way to invoke an agent with a specific context.
228
228
  */
229
229
  function wakeAgent(text: string, logger: any, options: { sessionKey?: string } = {}) {
230
- const sessionKey = options.sessionKey || `hook:bsv-overlay:${Date.now()}`;
230
+ const sessionKey = options.sessionKey || `hook:openclaw-overlay:${Date.now()}`;
231
231
  const gatewayPort = getGatewayPort();
232
232
  const httpToken = getHooksToken();
233
233
 
234
234
  if (!httpToken) {
235
- logger?.warn?.('[bsv-overlay] Skipped wakeAgent: OPENCLAW_HOOKS_TOKEN not set');
235
+ logger?.warn?.('[openclaw-overlay] Skipped wakeAgent: OPENCLAW_HOOKS_TOKEN not set');
236
236
  return;
237
237
  }
238
238
 
@@ -251,14 +251,14 @@ function wakeAgent(text: string, logger: any, options: { sessionKey?: string } =
251
251
  })
252
252
  .then(async (res) => {
253
253
  if (res.ok) {
254
- logger?.info?.(`[bsv-overlay] Agent invoked via /hooks/agent (session: ${sessionKey})`);
254
+ logger?.info?.(`[openclaw-overlay] Agent invoked via /hooks/agent (session: ${sessionKey})`);
255
255
  } else {
256
256
  const body = await res.text().catch(() => '');
257
- logger?.warn?.(`[bsv-overlay] /hooks/agent failed: ${res.status} ${body}`);
257
+ logger?.warn?.(`[openclaw-overlay] /hooks/agent failed: ${res.status} ${body}`);
258
258
  }
259
259
  })
260
260
  .catch((err: any) => {
261
- logger?.warn?.('[bsv-overlay] /hooks/agent error:', err.message);
261
+ logger?.warn?.('[openclaw-overlay] /hooks/agent error:', err.message);
262
262
  });
263
263
  }
264
264
 
@@ -323,15 +323,15 @@ function startBackgroundService(env: any, cliPath: string, logger: any) {
323
323
  requestCleanupInterval = setInterval(async () => {
324
324
  if (serviceRunning) {
325
325
  wokenRequests.clear();
326
- logger?.debug?.('[bsv-overlay] Cleared stale request IDs');
326
+ logger?.debug?.('[openclaw-overlay] Cleared stale request IDs');
327
327
 
328
328
  // Also clean up old queue entries
329
329
  try {
330
330
  const { cleanupServiceQueue } = await import('./src/scripts/utils/storage.js');
331
331
  cleanupServiceQueue();
332
- logger?.debug?.('[bsv-overlay] Cleaned up old queue entries');
332
+ logger?.debug?.('[openclaw-overlay] Cleaned up old queue entries');
333
333
  } catch (err: any) {
334
- logger?.warn?.('[bsv-overlay] Queue cleanup failed:', err.message);
334
+ logger?.warn?.('[openclaw-overlay] Queue cleanup failed:', err.message);
335
335
  }
336
336
  }
337
337
  }, 5 * 60 * 1000);
@@ -351,9 +351,9 @@ function startBackgroundService(env: any, cliPath: string, logger: any) {
351
351
  for (const line of lines) {
352
352
  try {
353
353
  const event = JSON.parse(line);
354
- logger?.debug?.(`[bsv-overlay] ${event.event || event.type || 'message'}:`, JSON.stringify(event).slice(0, 200));
354
+ logger?.debug?.(`[openclaw-overlay] ${event.event || event.type || 'message'}:`, JSON.stringify(event).slice(0, 200));
355
355
 
356
- const alertDir = path.join(process.env.HOME || '', '.openclaw', 'bsv-overlay');
356
+ const alertDir = path.join(process.env.HOME || '', '.openclaw', 'openclaw-overlay');
357
357
  fs.mkdirSync(alertDir, { recursive: true });
358
358
 
359
359
  // Detect queued-for-agent events — invoke agent via /hooks/agent
@@ -363,20 +363,20 @@ function startBackgroundService(env: any, cliPath: string, logger: any) {
363
363
 
364
364
  // Check if already woken to prevent duplicate processing
365
365
  if (wokenRequests.has(requestId)) {
366
- logger?.debug?.(`[bsv-overlay] Request ${requestId} already woken, skipping duplicate`);
366
+ logger?.debug?.(`[openclaw-overlay] Request ${requestId} already woken, skipping duplicate`);
367
367
  return;
368
368
  }
369
369
 
370
370
  // Skip wake-up for already processed requests unless they're pending
371
371
  if (event.action?.startsWith('already-') && !event.action.includes('pending')) {
372
- logger?.debug?.(`[bsv-overlay] Request ${requestId} already processed (${event.action}), skipping`);
372
+ logger?.debug?.(`[openclaw-overlay] Request ${requestId} already processed (${event.action}), skipping`);
373
373
  return;
374
374
  }
375
375
 
376
376
  wokenRequests.add(requestId);
377
- logger?.info?.(`[bsv-overlay] ⚡ Incoming ${event.serviceId} request from ${event.from?.slice(0, 12)}...`);
377
+ logger?.info?.(`[openclaw-overlay] ⚡ Incoming ${event.serviceId} request from ${event.from?.slice(0, 12)}...`);
378
378
  const wakeText = `⚡ Incoming overlay service request!\n\nService: ${event.serviceId}\nFrom: ${event.from}\nPaid: ${event.satoshisReceived || '?'} sats\n\nFulfill it now:\n1. overlay({ action: "pending-requests" })\n2. Process the ${event.serviceId} request using your capabilities\n3. overlay({ action: "fulfill", requestId: "${event.id}", recipientKey: "${event.from}", serviceId: "${event.serviceId}", result: { ... } })`;
379
- wakeAgent(wakeText, logger, { sessionKey: `hook:bsv-overlay:${event.id || Date.now()}` });
379
+ wakeAgent(wakeText, logger, { sessionKey: `hook:openclaw-overlay:${event.id || Date.now()}` });
380
380
  }
381
381
 
382
382
  // Detect service-response events — invoke agent to notify user
@@ -388,9 +388,9 @@ function startBackgroundService(env: any, cliPath: string, logger: any) {
388
388
  const formatted = event.formatted || '';
389
389
  const resultJson = event.result ? JSON.stringify(event.result, null, 2) : '(no result data)';
390
390
 
391
- logger?.info?.(`[bsv-overlay] 📬 Response received for ${svcId} from ${from?.slice(0, 12)}... — status: ${status}`);
391
+ logger?.info?.(`[openclaw-overlay] 📬 Response received for ${svcId} from ${from?.slice(0, 12)}... — status: ${status}`);
392
392
  const wakeText = `📬 Overlay service response received!\n\nService: ${svcId}\nFrom: ${from}\nStatus: ${status}\n${formatted ? `\nSummary: ${formatted}` : ''}\n\nFull result:\n${resultJson}\n\nNotify the user of this response in a clear, human-readable format.`;
393
- wakeAgent(wakeText, logger, { sessionKey: `hook:bsv-overlay:resp-${event.requestId || Date.now()}` });
393
+ wakeAgent(wakeText, logger, { sessionKey: `hook:openclaw-overlay:resp-${event.requestId || Date.now()}` });
394
394
  }
395
395
 
396
396
  // Write payment/activity notifications for ALL significant events
@@ -410,12 +410,12 @@ function startBackgroundService(env: any, cliPath: string, logger: any) {
410
410
  try {
411
411
  const event = JSON.parse(line);
412
412
  if (event.event === 'connected') {
413
- logger?.info?.('[bsv-overlay] WebSocket relay connected');
413
+ logger?.info?.('[openclaw-overlay] WebSocket relay connected');
414
414
  } else if (event.event === 'disconnected') {
415
- logger?.warn?.('[bsv-overlay] WebSocket disconnected, reconnecting...');
415
+ logger?.warn?.('[openclaw-overlay] WebSocket disconnected, reconnecting...');
416
416
  }
417
417
  } catch {
418
- logger?.debug?.(`[bsv-overlay] ${line}`);
418
+ logger?.debug?.(`[openclaw-overlay] ${line}`);
419
419
  }
420
420
  }
421
421
  });
@@ -423,7 +423,7 @@ function startBackgroundService(env: any, cliPath: string, logger: any) {
423
423
  proc.on('exit', (code) => {
424
424
  backgroundProcess = null;
425
425
  if (serviceRunning) {
426
- logger?.warn?.(`[bsv-overlay] Background service exited (code ${code}), restarting in 5s...`);
426
+ logger?.warn?.(`[openclaw-overlay] Background service exited (code ${code}), restarting in 5s...`);
427
427
  setTimeout(spawnConnect, 5000);
428
428
  }
429
429
  });
@@ -585,7 +585,7 @@ export default function register(api: any) {
585
585
 
586
586
  // Register background relay service
587
587
  api.registerService({
588
- id: "bsv-overlay-relay",
588
+ id: "openclaw-overlay-relay",
589
589
  start: async () => {
590
590
  try {
591
591
  api.logger.info("Starting BSV overlay WebSocket relay...");
@@ -615,7 +615,7 @@ export default function register(api: any) {
615
615
 
616
616
  // Register a skill-style wake handler
617
617
  api.registerHook({
618
- id: "bsv-overlay-wake",
618
+ id: "openclaw-overlay-wake",
619
619
  event: "gateway:start",
620
620
  handler: async (ctx: any) => {
621
621
  // Auto-check for registration on startup
@@ -624,8 +624,8 @@ export default function register(api: any) {
624
624
  const env = buildEnvironment(pluginConfig);
625
625
  const cliPath = path.join(__dirname, 'dist', 'cli.js');
626
626
 
627
- const regPath = path.join(process.env.HOME || '', '.openclaw', 'bsv-overlay', 'registration.json');
628
- const onboardSentFile = path.join(process.env.HOME || '', '.openclaw', 'bsv-overlay', 'onboarding-sent.flag');
627
+ const regPath = path.join(process.env.HOME || '', '.openclaw', 'openclaw-overlay', 'registration.json');
628
+ const onboardSentFile = path.join(process.env.HOME || '', '.openclaw', 'openclaw-overlay', 'onboarding-sent.flag');
629
629
 
630
630
  if (!fs.existsSync(regPath) && !fs.existsSync(onboardSentFile)) {
631
631
  // Check if wallet exists
@@ -647,7 +647,7 @@ export default function register(api: any) {
647
647
  // Funded but not registered. Auto-register.
648
648
  const regResult = await execFileAsync('node', [cliPath, 'register'], { env, timeout: 60000 });
649
649
  if (parseCliOutput(regResult.stdout).success) {
650
- ctx.logger.info('[bsv-overlay] Agent auto-registered on startup');
650
+ ctx.logger.info('[openclaw-overlay] Agent auto-registered on startup');
651
651
  await autoAdvertiseServices(env, cliPath, ctx.logger);
652
652
  }
653
653
  }
@@ -655,7 +655,7 @@ export default function register(api: any) {
655
655
  }
656
656
 
657
657
  } catch (err: any) {
658
- api.log?.debug?.('[bsv-overlay] Auto-setup/onboarding skipped:', err.message);
658
+ api.log?.debug?.('[openclaw-overlay] Auto-setup/onboarding skipped:', err.message);
659
659
  }
660
660
  })();
661
661
  }
@@ -721,14 +721,16 @@ export default function register(api: any) {
721
721
  if (result.agents) {
722
722
  console.log("\nAgents:");
723
723
  result.agents.forEach((agent: any) => {
724
- console.log(`- ${agent.name} (${agent.identityKey.slice(0, 16)}...)`);
724
+ const name = agent.name || agent.agentName || 'Unknown Agent';
725
+ console.log(`- ${name} (${agent.identityKey.slice(0, 16)}...)`);
725
726
  });
726
727
  }
727
728
 
728
729
  if (result.services) {
729
730
  console.log("\nServices:");
730
731
  result.services.forEach((service: any) => {
731
- console.log(`- ${service.name} (${service.serviceId}): ${service.pricing?.amountSats || 0} sats [${service.identityKey.slice(0, 12)}]`);
732
+ const name = service.name || service.agentName || 'Unknown Agent';
733
+ console.log(`- ${service.serviceId} - ${name} (${service.pricing?.amountSats || 0} sats) by ${service.identityKey.slice(0, 12)}`);
732
734
  });
733
735
  }
734
736
  } catch (error: any) {
@@ -981,7 +983,7 @@ async function handleUnregister(params: any, env: any, cliPath: string) {
981
983
  const { confirmToken } = params;
982
984
 
983
985
  // Load current registration to show what will be deleted
984
- const regPath = path.join(process.env.HOME || '', '.openclaw', 'bsv-overlay', 'registration.json');
986
+ const regPath = path.join(process.env.HOME || '', '.openclaw', 'openclaw-overlay', 'registration.json');
985
987
  let registration: any = null;
986
988
  try {
987
989
  if (fs.existsSync(regPath)) {
@@ -1148,29 +1150,51 @@ async function handleDiscover(params: any, env: any, cliPath: string) {
1148
1150
  }
1149
1151
 
1150
1152
  async function handleBalance(env: any, cliPath: string) {
1151
- const result = await execFileAsync('node', [cliPath, 'balance'], { env });
1152
- const output = parseCliOutput(result.stdout);
1153
-
1154
- if (!output.success) {
1155
- throw new Error(`Balance check failed: ${output.error}`);
1153
+ try {
1154
+ const result = await execFileAsync('node', [cliPath, 'balance'], { env });
1155
+ const output = parseCliOutput(result.stdout);
1156
+
1157
+ if (!output.success) {
1158
+ throw new Error(output.error);
1159
+ }
1160
+
1161
+ return output.data;
1162
+ } catch (error: any) {
1163
+ if (error.message?.includes('Wallet not initialized')) {
1164
+ return { walletBalance: 0, error: 'Not Initialized' };
1165
+ }
1166
+ throw new Error(`Balance check failed: ${error.message}`);
1156
1167
  }
1157
-
1158
- return output.data;
1159
1168
  }
1160
1169
 
1161
1170
  async function handleStatus(env: any, cliPath: string) {
1162
1171
  try {
1163
1172
  // Get identity
1164
- const identityResult = await execFileAsync('node', [cliPath, 'identity'], { env });
1165
- const identity = parseCliOutput(identityResult.stdout);
1173
+ let identity: any = { data: { identityKey: 'Not Initialized' } };
1174
+ try {
1175
+ const identityResult = await execFileAsync('node', [cliPath, 'identity'], { env });
1176
+ identity = parseCliOutput(identityResult.stdout);
1177
+ } catch (err: any) {
1178
+ if (!err.message?.includes('Wallet not initialized')) throw err;
1179
+ }
1166
1180
 
1167
1181
  // Get balance
1168
- const balanceResult = await execFileAsync('node', [cliPath, 'balance'], { env });
1169
- const balance = parseCliOutput(balanceResult.stdout);
1182
+ let balance: any = { data: { walletBalance: 0 } };
1183
+ try {
1184
+ const balanceResult = await execFileAsync('node', [cliPath, 'balance'], { env });
1185
+ balance = parseCliOutput(balanceResult.stdout);
1186
+ } catch (err: any) {
1187
+ if (!err.message?.includes('Wallet not initialized')) throw err;
1188
+ }
1170
1189
 
1171
1190
  // Get services
1172
- const servicesResult = await execFileAsync('node', [cliPath, 'services'], { env });
1173
- const services = parseCliOutput(servicesResult.stdout);
1191
+ let services: any = { data: [] };
1192
+ try {
1193
+ const servicesResult = await execFileAsync('node', [cliPath, 'services'], { env });
1194
+ services = parseCliOutput(servicesResult.stdout);
1195
+ } catch (err: any) {
1196
+ if (!err.message?.includes('Wallet not initialized')) throw err;
1197
+ }
1174
1198
 
1175
1199
  return {
1176
1200
  identity: identity.data,
@@ -1259,7 +1283,7 @@ async function handleImport(params: any, env: any, cliPath: string) {
1259
1283
  }
1260
1284
 
1261
1285
  // Check if we should auto-register after successful import
1262
- const regPath = path.join(process.env.HOME || '', '.openclaw', 'bsv-overlay', 'registration.json');
1286
+ const regPath = path.join(process.env.HOME || '', '.openclaw', 'openclaw-overlay', 'registration.json');
1263
1287
  const isRegistered = fs.existsSync(regPath);
1264
1288
 
1265
1289
  if (!isRegistered && output.data?.balance >= 1000) {
@@ -1515,14 +1539,14 @@ async function handlePendingRequests(env: any, cliPath: string) {
1515
1539
  if (!output.success) throw new Error(`Queue check failed: ${output.error}`);
1516
1540
 
1517
1541
  // Clear the alert file since we're checking now
1518
- const alertPath = path.join(process.env.HOME || '', '.openclaw', 'bsv-overlay', 'pending-alert.jsonl');
1542
+ const alertPath = path.join(process.env.HOME || '', '.openclaw', 'openclaw-overlay', 'pending-alert.jsonl');
1519
1543
  try { if (fs.existsSync(alertPath)) fs.unlinkSync(alertPath); } catch {}
1520
1544
 
1521
1545
  return output.data;
1522
1546
  }
1523
1547
 
1524
1548
  function handleActivity() {
1525
- const feedPath = path.join(process.env.HOME || '', '.openclaw', 'bsv-overlay', 'activity-feed.jsonl');
1549
+ const feedPath = path.join(process.env.HOME || '', '.openclaw', 'openclaw-overlay', 'activity-feed.jsonl');
1526
1550
  if (!fs.existsSync(feedPath)) return { events: [], count: 0 };
1527
1551
 
1528
1552
  const lines = fs.readFileSync(feedPath, 'utf-8').trim().split('\n').filter(Boolean);
@@ -1568,6 +1592,9 @@ function buildEnvironment(config: any) {
1568
1592
  if (config.chaintracksUrl) {
1569
1593
  env.BSV_CHAINTRACKS_URL = config.chaintracksUrl;
1570
1594
  }
1595
+ if (config.arcUrl) {
1596
+ env.BSV_ARC_URL = config.arcUrl;
1597
+ }
1571
1598
 
1572
1599
  // Set defaults
1573
1600
  env.BSV_NETWORK = env.BSV_NETWORK || 'mainnet';
@@ -15,11 +15,21 @@
15
15
  "default": "https://clawoverlay.com",
16
16
  "description": "Overlay server URL for registration, discovery, and relay"
17
17
  },
18
+ "network": {
19
+ "type": "string",
20
+ "enum": ["mainnet", "testnet"],
21
+ "default": "mainnet",
22
+ "description": "BSV network to use"
23
+ },
18
24
  "chaintracksUrl": {
19
25
  "type": "string",
20
26
  "default": "https://chaintracks-us-1.bsvb.tech",
21
27
  "description": "Custom Chaintracks server URL for SPV header verification"
22
28
  },
29
+ "arcUrl": {
30
+ "type": "string",
31
+ "description": "Custom ARC/Arcade server URL for transaction broadcasting"
32
+ },
23
33
  "agentName": {
24
34
  "type": "string",
25
35
  "description": "Display name for this agent on the overlay network (defaults to hostname)"
@@ -69,12 +79,21 @@
69
79
  "placeholder": "https://clawoverlay.com",
70
80
  "advanced": true
71
81
  },
82
+ "network": {
83
+ "label": "BSV Network"
84
+ },
72
85
  "chaintracksUrl": {
73
86
  "label": "Chaintracks Server URL",
74
87
  "placeholder": "https://chaintracks-us-1.bsvb.tech",
75
88
  "help": "Custom server for SPV block header verification",
76
89
  "advanced": true
77
90
  },
91
+ "arcUrl": {
92
+ "label": "ARC/Arcade Server URL",
93
+ "placeholder": "https://arc.taal.com",
94
+ "help": "Custom server for transaction broadcasting",
95
+ "advanced": true
96
+ },
78
97
  "agentName": {
79
98
  "label": "Agent Name",
80
99
  "placeholder": "my-agent",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "openclaw-overlay-plugin",
3
- "version": "0.7.32",
3
+ "version": "0.7.34",
4
4
  "description": "Openclaw BSV Overlay — agent discovery, service marketplace, and micropayments on the BSV blockchain",
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -232,7 +232,13 @@ export class BSVAgentWallet {
232
232
  // 3. Network services (ARC broadcasting, chain tracking, etc.)
233
233
  const serviceOptions = Services.createDefaultOptions(chain);
234
234
  const chaintracksUrl = process.env.BSV_CHAINTRACKS_URL || 'https://chaintracks-us-1.bsvb.tech';
235
+ const arcUrl = process.env.BSV_ARC_URL;
236
+
235
237
  serviceOptions.chaintracks = new ChaintracksServiceClient(chain, chaintracksUrl);
238
+ if (arcUrl) {
239
+ serviceOptions.arcUrl = arcUrl;
240
+ }
241
+
236
242
  serviceOptions.taalApiKey = taalApiKey;
237
243
  const services = new Services(serviceOptions);
238
244
 
@@ -288,12 +288,23 @@ export async function cmdBaemailRefund(requestId: string | undefined): Promise<n
288
288
 
289
289
  await tx.sign();
290
290
 
291
- // Broadcast
292
- const broadcastResp = await fetchWithTimeout('https://api.whatsonchain.com/v1/bsv/main/tx/raw', {
293
- method: 'POST',
294
- headers: { 'Content-Type': 'application/json' },
295
- body: JSON.stringify({ txhex: tx.toHex() }),
296
- });
291
+ // Broadcast using configured ARC/Arcade URL or fallback to WhatsOnChain
292
+ const arcUrl = process.env.BSV_ARC_URL;
293
+ let broadcastResp;
294
+
295
+ if (arcUrl) {
296
+ broadcastResp = await fetchWithTimeout(`${arcUrl.replace(/\/$/, '')}/v1/tx`, {
297
+ method: 'POST',
298
+ headers: { 'Content-Type': 'application/json' },
299
+ body: JSON.stringify({ rawTx: tx.toHex() }),
300
+ });
301
+ } else {
302
+ broadcastResp = await fetchWithTimeout('https://api.whatsonchain.com/v1/bsv/main/tx/raw', {
303
+ method: 'POST',
304
+ headers: { 'Content-Type': 'application/json' },
305
+ body: JSON.stringify({ txhex: tx.toHex() }),
306
+ });
307
+ }
297
308
 
298
309
  if (!broadcastResp.ok) {
299
310
  const errBody = await broadcastResp.text();
@@ -7,7 +7,7 @@ import os from 'node:os';
7
7
  import fs from 'node:fs';
8
8
 
9
9
  // Auto-load .env from overlay state dir if it exists
10
- const overlayEnvPath = path.join(os.homedir(), '.openclaw', 'bsv-overlay', '.env');
10
+ const overlayEnvPath = path.join(os.homedir(), '.openclaw', 'openclaw-overlay', '.env');
11
11
  try {
12
12
  if (fs.existsSync(overlayEnvPath)) {
13
13
  for (const line of fs.readFileSync(overlayEnvPath, 'utf-8').split('\n')) {
@@ -43,7 +43,7 @@ export const AGENT_DESCRIPTION = process.env.AGENT_DESCRIPTION ||
43
43
  export const WOC_API_KEY = process.env.WOC_API_KEY || '';
44
44
 
45
45
  /** Overlay state directory for registration, services, etc. */
46
- export const OVERLAY_STATE_DIR = path.join(os.homedir(), '.openclaw', 'bsv-overlay');
46
+ export const OVERLAY_STATE_DIR = path.join(os.homedir(), '.openclaw', 'openclaw-overlay');
47
47
 
48
48
  /** Protocol identifier for overlay transactions */
49
49
  export const PROTOCOL_ID = 'openclaw overlay v1';
@@ -38,7 +38,9 @@ export async function cmdDiscover(args: string[]): Promise<never> {
38
38
  try {
39
39
  const { data, txid } = await parseOverlayOutput(output.beef, output.outputIndex);
40
40
  if (data?.type === 'identity') {
41
- results.agents.push({ ...data, txid });
41
+ // Handle both 'name' and 'agentName' for backward compatibility
42
+ const name = data.name || data.agentName || 'Unknown Agent';
43
+ results.agents.push({ ...data, name, txid });
42
44
  }
43
45
  } catch { /* ignore */ }
44
46
  }