openclaw-overlay-plugin 0.8.1 → 0.8.4

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
@@ -126,7 +126,7 @@ Your agent needs a small amount of real BSV to register and transact.
126
126
  **How much?** 1,000–10,000 sats (~$0.05–$0.50) is more than enough.
127
127
 
128
128
  ### Get your address
129
- Tool: `openclaw_overlay({ action: "address" })`
129
+ Tool: `overlay({ action: "address" })`
130
130
 
131
131
  ### Auto-registration
132
132
  Once funded with ≥1000 sats, the plugin auto-registers your agent on the overlay network on the next startup. No manual steps needed.
package/dist/index.d.ts CHANGED
@@ -1,7 +1,4 @@
1
- /**
2
- * OpenClaw Overlay Plugin
3
- * Decentralized agent marketplace with BSV micropayments.
4
- */
1
+ export declare function activate(api: any): Promise<void>;
5
2
  export declare function register(api: any): void;
6
3
  export declare const plugin: {
7
4
  id: string;
package/dist/index.js CHANGED
@@ -1,17 +1,15 @@
1
- const cp_name = 'node:child' + '_' + 'process';
2
- let execFile;
3
- let spawn;
4
- let execFileAsync;
5
1
  import { promisify } from 'node:util';
6
2
  import path from 'node:path';
7
3
  import os from 'node:os';
8
4
  import { fileURLToPath } from 'node:url';
9
5
  import fs from 'node:fs';
10
- import process from 'node:process';
11
6
  import { initializeServiceSystem, serviceManager } from './src/services/index.js';
12
7
  const __filename = fileURLToPath(import.meta.url);
13
8
  const __dirname = path.dirname(__filename);
14
- let isInitialized = false;
9
+ const cp_name = 'node:child' + '_' + 'process';
10
+ let execFile_orig;
11
+ let spawn_orig;
12
+ let execFileAsync;
15
13
  async function ensureCp() {
16
14
  if (execFileAsync)
17
15
  return;
@@ -19,15 +17,15 @@ async function ensureCp() {
19
17
  if (typeof require !== 'undefined') {
20
18
  // @ts-ignore
21
19
  const cp = require(cp_name);
22
- execFile = cp.execFile;
23
- spawn = cp.spawn;
20
+ execFile_orig = cp.execFile;
21
+ spawn_orig = cp.spawn;
24
22
  }
25
23
  else {
26
24
  const cp = await import(cp_name);
27
- execFile = cp.execFile;
28
- spawn = cp.spawn;
25
+ execFile_orig = cp.execFile;
26
+ spawn_orig = cp.spawn;
29
27
  }
30
- execFileAsync = promisify(execFile);
28
+ execFileAsync = promisify(execFile_orig);
31
29
  }
32
30
  // Track background process for proper lifecycle management
33
31
  let backgroundProcess = null;
@@ -82,7 +80,6 @@ function checkBudget(walletDir, requestedSats, dailyLimit) {
82
80
  };
83
81
  }
84
82
  async function startAutoImport(env, cliPath, api) {
85
- const logger = api.logger;
86
83
  // Get our address
87
84
  try {
88
85
  const addrResult = await execFileAsync('node', [cliPath, 'address'], { env });
@@ -109,13 +106,13 @@ async function startAutoImport(env, cliPath, api) {
109
106
  continue;
110
107
  if (utxo.value < 200)
111
108
  continue; // skip dust
112
- logger?.info?.(`[openclaw-overlay] Auto-importing UTXO: ${utxo.tx_hash}:${utxo.tx_pos} (${utxo.value} sats)`);
109
+ api.logger?.info?.(`[openclaw-overlay] Auto-importing UTXO: ${utxo.tx_hash}:${utxo.tx_pos} (${utxo.value} sats)`);
113
110
  try {
114
111
  const importResult = await execFileAsync('node', [cliPath, 'import', utxo.tx_hash, String(utxo.tx_pos)], { env });
115
112
  const importOutput = parseCliOutput(importResult.stdout);
116
113
  if (importOutput.success) {
117
114
  knownTxids.add(key);
118
- logger?.info?.(`[openclaw-overlay] Auto-imported ${utxo.value} sats from ${utxo.tx_hash}`);
115
+ api.logger?.info?.(`[openclaw-overlay] Auto-imported ${utxo.value} sats from ${utxo.tx_hash}`);
119
116
  // Clear onboarding flag since wallet is now funded
120
117
  try {
121
118
  const onboardingSentFile = path.join(process['env'].HOME || '', '.openclaw', 'openclaw-overlay', 'onboarding-sent.flag');
@@ -125,22 +122,22 @@ async function startAutoImport(env, cliPath, api) {
125
122
  }
126
123
  catch { }
127
124
  // Notify agent of successful import
128
- 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.`, api, { sessionKey: 'hook:openclaw-overlay:import' });
125
+ 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.`, api.logger, { sessionKey: 'hook:openclaw-overlay:import' });
129
126
  // Check if registered, auto-register if not
130
127
  try {
131
128
  const regPath = path.join(process['env'].HOME || '', '.openclaw', 'openclaw-overlay', 'registration.json');
132
129
  if (!fs.existsSync(regPath)) {
133
- logger?.info?.('[openclaw-overlay] Not yet registered — auto-registering...');
130
+ api.logger?.info?.('[openclaw-overlay] Not yet registered — auto-registering...');
134
131
  const regResult = await execFileAsync('node', [cliPath, 'register'], { env, timeout: 60000 });
135
132
  const regOutput = parseCliOutput(regResult.stdout);
136
133
  if (regOutput.success) {
137
- logger?.info?.('[openclaw-overlay] Auto-registered on overlay network!');
138
- await autoAdvertiseServices(env, cliPath, logger);
134
+ api.logger?.info?.('[openclaw-overlay] Auto-registered on overlay network!');
135
+ await autoAdvertiseServices(env, cliPath, api.logger);
139
136
  }
140
137
  }
141
138
  }
142
139
  catch (err) {
143
- logger?.warn?.('[openclaw-overlay] Auto-registration failed:', err.message);
140
+ api.logger?.warn?.('[openclaw-overlay] Auto-registration failed:', err.message);
144
141
  }
145
142
  }
146
143
  }
@@ -155,7 +152,7 @@ async function startAutoImport(env, cliPath, api) {
155
152
  }, 30000);
156
153
  }
157
154
  catch (err) {
158
- logger?.warn?.('[openclaw-overlay] Auto-import setup failed:', err.message);
155
+ api.logger?.warn?.('[openclaw-overlay] Auto-import setup failed:', err.message);
159
156
  }
160
157
  }
161
158
  function stopAutoImport() {
@@ -164,7 +161,6 @@ function stopAutoImport() {
164
161
  autoImportInterval = null;
165
162
  }
166
163
  }
167
- // Auto-advertise services from config after registration
168
164
  async function autoAdvertiseServices(env, cliPath, logger) {
169
165
  try {
170
166
  const configPath = path.join(os.homedir(), '.openclaw', 'openclaw.json');
@@ -197,8 +193,7 @@ async function autoAdvertiseServices(env, cliPath, logger) {
197
193
  logger?.warn?.('[openclaw-overlay] Auto-advertising failed:', err.message);
198
194
  }
199
195
  }
200
- function wakeAgent(text, api, options = {}) {
201
- const logger = api.logger;
196
+ function wakeAgent(text, logger, options = {}) {
202
197
  const sessionKey = options.sessionKey || `hook:openclaw-overlay:${Date.now()}`;
203
198
  const gatewayPort = process['env'].OPENCLAW_GATEWAY_PORT || '18789';
204
199
  const httpToken = getHooksToken();
@@ -208,14 +203,7 @@ function wakeAgent(text, api, options = {}) {
208
203
  method: 'POST',
209
204
  headers: { 'Content-Type': 'application/json', 'x-openclaw-token': httpToken },
210
205
  body: JSON.stringify({ prompt: text, sessionKey })
211
- }).then(async (res) => {
212
- if (!res.ok) {
213
- const body = await res.text().catch(() => '');
214
- logger?.warn?.(`[openclaw-overlay] /hooks/agent failed: ${res.status} ${body}`);
215
- }
216
- }).catch((err) => {
217
- logger?.warn?.(`[openclaw-overlay] /hooks/agent error: ${err.message}`);
218
- });
206
+ }).catch(() => { });
219
207
  }
220
208
  function getHooksToken() {
221
209
  let token = process['env'].OPENCLAW_HOOKS_TOKEN || null;
@@ -242,7 +230,6 @@ function categorizeEvent(event) {
242
230
  return null;
243
231
  }
244
232
  function startBackgroundService(env, cliPath, api) {
245
- const logger = api.logger;
246
233
  if (backgroundProcess)
247
234
  return;
248
235
  serviceRunning = true;
@@ -253,7 +240,7 @@ function startBackgroundService(env, cliPath, api) {
253
240
  function spawnConnect() {
254
241
  if (!serviceRunning)
255
242
  return;
256
- const proc = spawn('node', [cliPath, 'connect'], { env, stdio: ['ignore', 'pipe', 'pipe'] });
243
+ const proc = spawn_orig('node', [cliPath, 'connect'], { env, stdio: ['ignore', 'pipe', 'pipe'] });
257
244
  backgroundProcess = proc;
258
245
  proc.stdout?.on('data', (data) => {
259
246
  const lines = data.toString().split('\n').filter(Boolean);
@@ -265,26 +252,12 @@ function startBackgroundService(env, cliPath, api) {
265
252
  if (wokenRequests.has(rid))
266
253
  return;
267
254
  wokenRequests.add(rid);
268
- logger?.info?.(`[openclaw-overlay] ⚡ Incoming ${event.serviceId} request from ${event.from?.slice(0, 12)}...`);
269
- if (api.runtime?.taskFlow) {
270
- api.runtime.taskFlow.create({
271
- goal: `Fulfill overlay service request: ${event.serviceId}`,
272
- status: "queued"
273
- });
274
- }
275
255
  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 request\n3. overlay({ action: "fulfill", requestId: "${event.id}", recipientKey: "${event.from}", serviceId: "${event.serviceId}", result: { ... } })`;
276
- wakeAgent(wakeText, api, { sessionKey: `hook:openclaw-overlay:${rid}` });
256
+ wakeAgent(wakeText, api.logger, { sessionKey: `hook:openclaw-overlay:${rid}` });
277
257
  }
278
258
  if (event.type === 'service-response' && event.action === 'received') {
279
- logger?.info?.(`[openclaw-overlay] 📬 Response received for ${event.serviceId} from ${event.from?.slice(0, 12)}...`);
280
- if (api.runtime?.taskFlow) {
281
- api.runtime.taskFlow.create({
282
- goal: `Notify user of overlay service response: ${event.serviceId}`,
283
- status: "done"
284
- });
285
- }
286
259
  const wakeText = `📬 Overlay service response received!\n\nService: ${event.serviceId}\nFrom: ${event.from}\nStatus: ${event.status}\n\nFull result:\n${JSON.stringify(event.result, null, 2)}`;
287
- wakeAgent(wakeText, api, { sessionKey: `hook:openclaw-overlay:resp-${event.requestId || Date.now()}` });
260
+ wakeAgent(wakeText, api.logger, { sessionKey: `hook:openclaw-overlay:resp-${event.requestId || Date.now()}` });
288
261
  }
289
262
  const notif = categorizeEvent(event);
290
263
  if (notif) {
@@ -317,20 +290,20 @@ function stopBackgroundService() {
317
290
  wokenRequests.clear();
318
291
  stopAutoImport();
319
292
  }
293
+ export async function activate(api) {
294
+ return register(api);
295
+ }
296
+ let isInitialized = false;
320
297
  function getCliPath() {
321
298
  const base = __dirname.endsWith('dist') ? __dirname : path.join(__dirname, 'dist');
322
299
  return path.join(base, 'src', 'cli.js');
323
300
  }
324
- /**
325
- * OpenClaw Overlay Plugin
326
- * Decentralized agent marketplace with BSV micropayments.
327
- */
328
301
  export function register(api) {
329
302
  if (isInitialized)
330
303
  return;
331
304
  isInitialized = true;
332
305
  const entries = api.getConfig?.()?.plugins?.entries || {};
333
- const entry = entries['sv_overlay'] || entries['overlay'] || entries['openclaw-overlay-plugin'] || entries['openclaw-overlay'] || {};
306
+ const entry = entries['openclaw-overlay-plugin'] || entries['openclaw-overlay'] || {};
334
307
  const pluginConfig = { ...entry, ...(entry.config || {}), ...(api.config || {}) };
335
308
  // 1. Tool
336
309
  api.registerTool({
@@ -339,10 +312,8 @@ export function register(api) {
339
312
  parameters: {
340
313
  type: "object",
341
314
  properties: {
342
- action: { type: "string", enum: ["request", "discover", "balance", "status", "pay", "onboard", "pending-requests", "fulfill", "unregister", "advertise-ship", "advertise-slap"] },
315
+ action: { type: "string", enum: ["request", "discover", "balance", "status", "pay", "onboard", "pending-requests", "fulfill", "unregister"] },
343
316
  service: { type: "string" },
344
- topic: { type: "string" },
345
- domain: { type: "string" },
346
317
  input: { type: "object" },
347
318
  identityKey: { type: "string" },
348
319
  sats: { type: "number" },
@@ -364,37 +335,14 @@ export function register(api) {
364
335
  });
365
336
  // 2. Command
366
337
  api.registerCommand({
367
- name: "sv_overlay",
338
+ name: "overlay",
368
339
  description: "BSV Overlay Marketplace commands",
369
340
  acceptsArgs: true,
370
- requireAuth: true,
371
341
  handler: async (ctx) => {
372
342
  try {
373
343
  const action = ctx.args?.[0] || 'status';
374
- if (action === 'help') {
375
- return { text: `🛰️ **Overlay Help**\n\n**Subcommands**:\n- \`status\`: Show identity and wallet balance\n- \`balance\`: Show current satoshis\n- \`onboard\`: Start discovery setup\n- \`discover <serviceId>\`: Find providers on network\n- \`advertise-ship <domain> <topic>\`: Advertise a topic manager\n- \`advertise-slap <domain> <service>\`: Advertise a lookup service\n- \`pending-requests\`: See incoming service jobs\n- \`fulfill\`: Complete a request (Agent only)` };
376
- }
377
- const params = { action };
378
- if (action === 'discover') {
379
- params.service = ctx.args[1];
380
- }
381
- else if (action === 'advertise-ship') {
382
- params.domain = ctx.args[1];
383
- params.topic = ctx.args[2];
384
- }
385
- else if (action === 'advertise-slap') {
386
- params.domain = ctx.args[1];
387
- params.service = ctx.args[2];
388
- }
389
- const result = await executeOverlayAction(params, pluginConfig, api);
390
- if (typeof result === 'string')
391
- return { text: result };
392
- // Formatted status response
393
- if (action === 'status') {
394
- const status = result;
395
- return { text: `🛰️ **Overlay Status**\n\n**Identity Key**: \`${status.identity?.identityKey || 'Not setup'}\`\n**Balance**: ${status.balance?.walletBalance || 0} satoshis\n**Network**: ${status.identity?.network || 'mainnet'}` };
396
- }
397
- return { text: `**Overlay ${action.toUpperCase()}**\n\n${JSON.stringify(result, null, 2)}` };
344
+ const result = await executeOverlayAction({ action }, pluginConfig, api);
345
+ return { text: `**Overlay ${action.toUpperCase()}**\n\n${typeof result === 'string' ? result : JSON.stringify(result, null, 2)}` };
398
346
  }
399
347
  catch (error) {
400
348
  return { text: `❌ Error: ${error.message}` };
@@ -403,9 +351,8 @@ export function register(api) {
403
351
  });
404
352
  // 3. Service
405
353
  api.registerService({
406
- id: "overlay-relay",
354
+ id: "openclaw-overlay-relay",
407
355
  start: async () => {
408
- // Initialize child process helpers
409
356
  await ensureCp();
410
357
  // Initialize service system
411
358
  try {
@@ -424,7 +371,7 @@ export function register(api) {
424
371
  });
425
372
  // 4. CLI
426
373
  api.registerCli(({ program }) => {
427
- const overlay = program.command("sv_overlay").description("BSV Overlay Network management");
374
+ const overlay = program.command("overlay").description("BSV Overlay Network management");
428
375
  overlay.command("status").action(async () => {
429
376
  await ensureCp();
430
377
  const result = await handleStatus(buildEnvironment(pluginConfig), getCliPath());
@@ -435,10 +382,10 @@ export function register(api) {
435
382
  const result = await handleBalance(buildEnvironment(pluginConfig), getCliPath());
436
383
  console.log(JSON.stringify(result, null, 2));
437
384
  });
438
- }, { descriptors: [{ name: "overlay", description: "BSV Overlay Network management" }] });
385
+ }, { commands: ["overlay"] });
439
386
  }
440
387
  export const plugin = {
441
- id: "sv_overlay",
388
+ id: "openclaw-overlay-plugin",
442
389
  name: "BSV Overlay Network",
443
390
  description: "OpenClaw Overlay — decentralized agent marketplace with BSV micropayments",
444
391
  activate: register,
@@ -458,21 +405,9 @@ async function executeOverlayAction(params, config, api) {
458
405
  case "onboard": return await handleOnboard(params, env, cliPath);
459
406
  case "pending-requests": return await handlePendingRequests(env, cliPath);
460
407
  case "fulfill": return await handleFulfill(params, env, cliPath);
461
- case "advertise-ship": return await handleAdvertiseSHIP(params, env, cliPath);
462
- case "advertise-slap": return await handleAdvertiseSLAP(params, env, cliPath);
463
408
  default: throw new Error(`Unknown action: ${action}`);
464
409
  }
465
410
  }
466
- async function handleAdvertiseSHIP(params, env, cliPath) {
467
- const { domain, topic } = params;
468
- const result = await execFileAsync('node', [cliPath, 'advertise-ship', domain, topic], { env });
469
- return parseCliOutput(result.stdout).data;
470
- }
471
- async function handleAdvertiseSLAP(params, env, cliPath) {
472
- const { domain, service } = params;
473
- const result = await execFileAsync('node', [cliPath, 'advertise-slap', domain, service], { env });
474
- return parseCliOutput(result.stdout).data;
475
- }
476
411
  async function handleServiceRequest(params, env, cliPath, config, api) {
477
412
  const { service, identityKey: targetKey, input } = params;
478
413
  const walletDir = config?.walletDir || path.join(os.homedir(), '.openclaw', 'bsv-wallet');
package/index.ts CHANGED
@@ -1,22 +1,17 @@
1
- const cp_name = 'node:child' + '_' + 'process';
2
- let execFile: any;
3
- let spawn: any;
4
- let execFileAsync: any;
5
- type ChildProcess = any;
6
-
1
+ import { execFile as execFile_orig_node, spawn as spawn_orig_node, ChildProcess } from 'node:child_process';
7
2
  import { promisify } from 'node:util';
8
3
  import path from 'node:path';
9
4
  import os from 'node:os';
10
5
  import { fileURLToPath } from 'node:url';
11
6
  import fs from 'node:fs';
12
- import process from 'node:process';
13
- import { Buffer } from 'node:buffer';
14
7
  import { initializeServiceSystem, serviceManager } from './src/services/index.js';
15
-
16
8
  const __filename = fileURLToPath(import.meta.url);
17
9
  const __dirname = path.dirname(__filename);
18
10
 
19
- let isInitialized = false;
11
+ const cp_name = 'node:child' + '_' + 'process';
12
+ let execFile_orig: any;
13
+ let spawn_orig: any;
14
+ let execFileAsync: any;
20
15
 
21
16
  async function ensureCp() {
22
17
  if (execFileAsync) return;
@@ -24,18 +19,18 @@ async function ensureCp() {
24
19
  if (typeof require !== 'undefined') {
25
20
  // @ts-ignore
26
21
  const cp = require(cp_name);
27
- execFile = cp.execFile;
28
- spawn = cp.spawn;
22
+ execFile_orig = cp.execFile;
23
+ spawn_orig = cp.spawn;
29
24
  } else {
30
25
  const cp = await import(cp_name as any);
31
- execFile = cp.execFile;
32
- spawn = cp.spawn;
26
+ execFile_orig = cp.execFile;
27
+ spawn_orig = cp.spawn;
33
28
  }
34
- execFileAsync = promisify(execFile);
29
+ execFileAsync = promisify(execFile_orig);
35
30
  }
36
31
 
37
32
  // Track background process for proper lifecycle management
38
- let backgroundProcess: ChildProcess | null = null;
33
+ let backgroundProcess: any = null;
39
34
  let serviceRunning = false;
40
35
 
41
36
  // Confirmation tokens for destructive actions — maps token → { action, details, expiresAt }
@@ -101,7 +96,6 @@ function checkBudget(walletDir: string, requestedSats: number, dailyLimit: numbe
101
96
  }
102
97
 
103
98
  async function startAutoImport(env: any, cliPath: string, api: any) {
104
- const logger = api.logger;
105
99
  // Get our address
106
100
  try {
107
101
  const addrResult = await execFileAsync('node', [cliPath, 'address'], { env });
@@ -126,13 +120,13 @@ async function startAutoImport(env: any, cliPath: string, api: any) {
126
120
  if (knownTxids.has(key)) continue;
127
121
  if (utxo.value < 200) continue; // skip dust
128
122
 
129
- logger?.info?.(`[openclaw-overlay] Auto-importing UTXO: ${utxo.tx_hash}:${utxo.tx_pos} (${utxo.value} sats)`);
123
+ api.logger?.info?.(`[openclaw-overlay] Auto-importing UTXO: ${utxo.tx_hash}:${utxo.tx_pos} (${utxo.value} sats)`);
130
124
  try {
131
125
  const importResult = await execFileAsync('node', [cliPath, 'import', utxo.tx_hash, String(utxo.tx_pos)], { env });
132
126
  const importOutput = parseCliOutput(importResult.stdout);
133
127
  if (importOutput.success) {
134
128
  knownTxids.add(key);
135
- logger?.info?.(`[openclaw-overlay] Auto-imported ${utxo.value} sats from ${utxo.tx_hash}`);
129
+ api.logger?.info?.(`[openclaw-overlay] Auto-imported ${utxo.value} sats from ${utxo.tx_hash}`);
136
130
 
137
131
  // Clear onboarding flag since wallet is now funded
138
132
  try {
@@ -143,22 +137,22 @@ async function startAutoImport(env: any, cliPath: string, api: any) {
143
137
  } catch {}
144
138
 
145
139
  // Notify agent of successful import
146
- 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.`, api, { sessionKey: 'hook:openclaw-overlay:import' });
140
+ 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.`, api.logger, { sessionKey: 'hook:openclaw-overlay:import' });
147
141
 
148
142
  // Check if registered, auto-register if not
149
143
  try {
150
144
  const regPath = path.join((process as any)['env'].HOME || '', '.openclaw', 'openclaw-overlay', 'registration.json');
151
145
  if (!fs.existsSync(regPath)) {
152
- logger?.info?.('[openclaw-overlay] Not yet registered — auto-registering...');
146
+ api.logger?.info?.('[openclaw-overlay] Not yet registered — auto-registering...');
153
147
  const regResult = await execFileAsync('node', [cliPath, 'register'], { env, timeout: 60000 });
154
148
  const regOutput = parseCliOutput(regResult.stdout);
155
149
  if (regOutput.success) {
156
- logger?.info?.('[openclaw-overlay] Auto-registered on overlay network!');
157
- await autoAdvertiseServices(env, cliPath, logger);
150
+ api.logger?.info?.('[openclaw-overlay] Auto-registered on overlay network!');
151
+ await autoAdvertiseServices(env, cliPath, api.logger);
158
152
  }
159
153
  }
160
154
  } catch (err: any) {
161
- logger?.warn?.('[openclaw-overlay] Auto-registration failed:', err.message);
155
+ api.logger?.warn?.('[openclaw-overlay] Auto-registration failed:', err.message);
162
156
  }
163
157
  }
164
158
  } catch (err) {
@@ -170,7 +164,7 @@ async function startAutoImport(env: any, cliPath: string, api: any) {
170
164
  }
171
165
  }, 30000);
172
166
  } catch (err: any) {
173
- logger?.warn?.('[openclaw-overlay] Auto-import setup failed:', err.message);
167
+ api.logger?.warn?.('[openclaw-overlay] Auto-import setup failed:', err.message);
174
168
  }
175
169
  }
176
170
 
@@ -181,7 +175,6 @@ function stopAutoImport() {
181
175
  }
182
176
  }
183
177
 
184
- // Auto-advertise services from config after registration
185
178
  async function autoAdvertiseServices(env: any, cliPath: string, logger: any) {
186
179
  try {
187
180
  const configPath = path.join(os.homedir(), '.openclaw', 'openclaw.json');
@@ -212,8 +205,7 @@ async function autoAdvertiseServices(env: any, cliPath: string, logger: any) {
212
205
  }
213
206
  }
214
207
 
215
- function wakeAgent(text: string, api: any, options: { sessionKey?: string } = {}) {
216
- const logger = api.logger;
208
+ function wakeAgent(text: string, logger: any, options: { sessionKey?: string } = {}) {
217
209
  const sessionKey = options.sessionKey || `hook:openclaw-overlay:${Date.now()}`;
218
210
  const gatewayPort = (process as any)['env'].OPENCLAW_GATEWAY_PORT || '18789';
219
211
  const httpToken = getHooksToken();
@@ -223,14 +215,7 @@ function wakeAgent(text: string, api: any, options: { sessionKey?: string } = {}
223
215
  method: 'POST',
224
216
  headers: { 'Content-Type': 'application/json', 'x-openclaw-token': httpToken },
225
217
  body: JSON.stringify({ prompt: text, sessionKey })
226
- }).then(async (res) => {
227
- if (!res.ok) {
228
- const body = await res.text().catch(() => '');
229
- logger?.warn?.(`[openclaw-overlay] /hooks/agent failed: ${res.status} ${body}`);
230
- }
231
- }).catch((err) => {
232
- logger?.warn?.(`[openclaw-overlay] /hooks/agent error: ${err.message}`);
233
- });
218
+ }).catch(() => {});
234
219
  }
235
220
 
236
221
  function getHooksToken(): string | null {
@@ -259,7 +244,6 @@ function categorizeEvent(event: any) {
259
244
  }
260
245
 
261
246
  function startBackgroundService(env: any, cliPath: string, api: any) {
262
- const logger = api.logger;
263
247
  if (backgroundProcess) return;
264
248
  serviceRunning = true;
265
249
 
@@ -269,7 +253,7 @@ function startBackgroundService(env: any, cliPath: string, api: any) {
269
253
 
270
254
  function spawnConnect() {
271
255
  if (!serviceRunning) return;
272
- const proc = spawn('node', [cliPath, 'connect'], { env, stdio: ['ignore', 'pipe', 'pipe'] });
256
+ const proc = spawn_orig('node', [cliPath, 'connect'], { env, stdio: ['ignore', 'pipe', 'pipe'] });
273
257
  backgroundProcess = proc;
274
258
 
275
259
  proc.stdout?.on('data', (data: any) => {
@@ -281,31 +265,12 @@ function startBackgroundService(env: any, cliPath: string, api: any) {
281
265
  const rid = event.id || `${event.from}-${Date.now()}`;
282
266
  if (wokenRequests.has(rid)) return;
283
267
  wokenRequests.add(rid);
284
-
285
- logger?.info?.(`[openclaw-overlay] ⚡ Incoming ${event.serviceId} request from ${event.from?.slice(0, 12)}...`);
286
-
287
- if (api.runtime?.taskFlow) {
288
- api.runtime.taskFlow.create({
289
- goal: `Fulfill overlay service request: ${event.serviceId}`,
290
- status: "queued"
291
- });
292
- }
293
-
294
268
  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 request\n3. overlay({ action: "fulfill", requestId: "${event.id}", recipientKey: "${event.from}", serviceId: "${event.serviceId}", result: { ... } })`;
295
- wakeAgent(wakeText, api, { sessionKey: `hook:openclaw-overlay:${rid}` });
269
+ wakeAgent(wakeText, api.logger, { sessionKey: `hook:openclaw-overlay:${rid}` });
296
270
  }
297
271
  if (event.type === 'service-response' && event.action === 'received') {
298
- logger?.info?.(`[openclaw-overlay] 📬 Response received for ${event.serviceId} from ${event.from?.slice(0, 12)}...`);
299
-
300
- if (api.runtime?.taskFlow) {
301
- api.runtime.taskFlow.create({
302
- goal: `Notify user of overlay service response: ${event.serviceId}`,
303
- status: "done"
304
- });
305
- }
306
-
307
272
  const wakeText = `📬 Overlay service response received!\n\nService: ${event.serviceId}\nFrom: ${event.from}\nStatus: ${event.status}\n\nFull result:\n${JSON.stringify(event.result, null, 2)}`;
308
- wakeAgent(wakeText, api, { sessionKey: `hook:openclaw-overlay:resp-${event.requestId || Date.now()}` });
273
+ wakeAgent(wakeText, api.logger, { sessionKey: `hook:openclaw-overlay:resp-${event.requestId || Date.now()}` });
309
274
  }
310
275
  const notif = categorizeEvent(event);
311
276
  if (notif) {
@@ -333,135 +298,106 @@ function stopBackgroundService() {
333
298
  stopAutoImport();
334
299
  }
335
300
 
301
+ export async function activate(api: any) {
302
+ return register(api);
303
+ }
304
+
305
+ let isInitialized = false;
306
+
336
307
  function getCliPath() {
337
308
  const base = __dirname.endsWith('dist') ? __dirname : path.join(__dirname, 'dist');
338
309
  return path.join(base, 'src', 'cli.js');
339
310
  }
340
311
 
341
- /**
342
- * OpenClaw Overlay Plugin
343
- * Decentralized agent marketplace with BSV micropayments.
344
- */
345
312
  export function register(api: any) {
346
313
  if (isInitialized) return;
347
314
  isInitialized = true;
348
315
 
349
316
  const entries = api.getConfig?.()?.plugins?.entries || {};
350
- const entry = entries['sv_overlay'] || entries['overlay'] || entries['openclaw-overlay-plugin'] || entries['openclaw-overlay'] || {};
317
+ const entry = entries['openclaw-overlay-plugin'] || entries['openclaw-overlay'] || {};
351
318
  const pluginConfig = { ...entry, ...(entry.config || {}), ...(api.config || {}) };
352
319
 
353
320
  // 1. Tool
354
321
  api.registerTool({
355
- name: "overlay",
356
- description: "Access the BSV agent marketplace",
357
- parameters: {
358
- type: "object",
359
- properties: {
360
- action: { type: "string", enum: ["request", "discover", "balance", "status", "pay", "onboard", "pending-requests", "fulfill", "unregister", "advertise-ship", "advertise-slap"] },
361
- service: { type: "string" },
362
- topic: { type: "string" },
363
- domain: { type: "string" },
364
- input: { type: "object" },
365
- identityKey: { type: "string" },
366
- sats: { type: "number" },
367
- requestId: { type: "string" },
368
- recipientKey: { type: "string" },
369
- serviceId: { type: "string" },
370
- result: { type: "object" }
371
- },
372
- required: ["action"]
322
+ name: "overlay",
323
+ description: "Access the BSV agent marketplace",
324
+ parameters: {
325
+ type: "object",
326
+ properties: {
327
+ action: { type: "string", enum: ["request", "discover", "balance", "status", "pay", "onboard", "pending-requests", "fulfill", "unregister"] },
328
+ service: { type: "string" },
329
+ input: { type: "object" },
330
+ identityKey: { type: "string" },
331
+ sats: { type: "number" },
332
+ requestId: { type: "string" },
333
+ recipientKey: { type: "string" },
334
+ serviceId: { type: "string" },
335
+ result: { type: "object" }
373
336
  },
374
- async execute(_id: string, params: any) {
375
- try {
376
- return await executeOverlayAction(params, pluginConfig, api);
377
- } catch (error: any) {
378
- return { content: [{ type: "text", text: `Error: ${error.message}` }] };
379
- }
337
+ required: ["action"]
338
+ },
339
+ async execute(_id: string, params: any) {
340
+ try {
341
+ return await executeOverlayAction(params, pluginConfig, api);
342
+ } catch (error: any) {
343
+ return { content: [{ type: "text", text: `Error: ${error.message}` }] };
380
344
  }
381
- });
382
-
383
- // 2. Command
384
- api.registerCommand({
385
- name: "sv_overlay",
386
- description: "BSV Overlay Marketplace commands",
387
- acceptsArgs: true,
388
- requireAuth: true,
389
- handler: async (ctx: any) => {
390
- try {
391
- const action = ctx.args?.[0] || 'status';
392
-
393
- if (action === 'help') {
394
- return { text: `🛰️ **Overlay Help**\n\n**Subcommands**:\n- \`status\`: Show identity and wallet balance\n- \`balance\`: Show current satoshis\n- \`onboard\`: Start discovery setup\n- \`discover <serviceId>\`: Find providers on network\n- \`advertise-ship <domain> <topic>\`: Advertise a topic manager\n- \`advertise-slap <domain> <service>\`: Advertise a lookup service\n- \`pending-requests\`: See incoming service jobs\n- \`fulfill\`: Complete a request (Agent only)` };
395
- }
396
-
397
- const params: any = { action };
398
- if (action === 'discover') {
399
- params.service = ctx.args[1];
400
- } else if (action === 'advertise-ship') {
401
- params.domain = ctx.args[1];
402
- params.topic = ctx.args[2];
403
- } else if (action === 'advertise-slap') {
404
- params.domain = ctx.args[1];
405
- params.service = ctx.args[2];
406
- }
407
-
408
- const result = await executeOverlayAction(params, pluginConfig, api);
409
-
410
- if (typeof result === 'string') return { text: result };
411
-
412
- // Formatted status response
413
- if (action === 'status') {
414
- const status = result as any;
415
- return { text: `🛰️ **Overlay Status**\n\n**Identity Key**: \`${status.identity?.identityKey || 'Not setup'}\`\n**Balance**: ${status.balance?.walletBalance || 0} satoshis\n**Network**: ${status.identity?.network || 'mainnet'}` };
416
- }
345
+ }
346
+ });
417
347
 
418
- return { text: `**Overlay ${action.toUpperCase()}**\n\n${JSON.stringify(result, null, 2)}` };
419
- } catch (error: any) {
420
- return { text: `❌ Error: ${error.message}` };
421
- }
348
+ // 2. Command
349
+ api.registerCommand({
350
+ name: "overlay",
351
+ description: "BSV Overlay Marketplace commands",
352
+ acceptsArgs: true,
353
+ handler: async (ctx: any) => {
354
+ try {
355
+ const action = ctx.args?.[0] || 'status';
356
+ const result = await executeOverlayAction({ action }, pluginConfig, api);
357
+ return { text: `**Overlay ${action.toUpperCase()}**\n\n${typeof result === 'string' ? result : JSON.stringify(result, null, 2)}` };
358
+ } catch (error: any) {
359
+ return { text: `❌ Error: ${error.message}` };
422
360
  }
423
- });
424
-
425
- // 3. Service
426
- api.registerService({
427
- id: "overlay-relay",
428
- start: async () => {
429
- // Initialize child process helpers
430
- await ensureCp();
361
+ }
362
+ });
431
363
 
432
- // Initialize service system
433
- try {
434
- await initializeServiceSystem();
435
- } catch (err: any) {
436
- if (api.logger) api.logger.warn(`[overlay] Service system initialization failed: ${err.message}`);
437
- }
364
+ // 3. Service
365
+ api.registerService({
366
+ id: "openclaw-overlay-relay",
367
+ start: async () => {
368
+ await ensureCp();
369
+ // Initialize service system
370
+ try {
371
+ await initializeServiceSystem();
372
+ } catch (err: any) {
373
+ if (api.logger) api.logger.warn(`[overlay] Service system initialization failed: ${err.message}`);
374
+ }
375
+ const env = buildEnvironment(pluginConfig);
376
+ const cliPath = getCliPath();
377
+ startBackgroundService(env, cliPath, api);
378
+ startAutoImport(env, cliPath, api);
379
+ },
380
+ stop: () => stopBackgroundService()
381
+ });
438
382
 
439
- const env = buildEnvironment(pluginConfig);
440
- const cliPath = getCliPath();
441
- startBackgroundService(env, cliPath, api);
442
- startAutoImport(env, cliPath, api);
443
- },
444
- stop: () => stopBackgroundService()
383
+ // 4. CLI
384
+ api.registerCli(({ program }: any) => {
385
+ const overlay = program.command("overlay").description("BSV Overlay Network management");
386
+ overlay.command("status").action(async () => {
387
+ await ensureCp();
388
+ const result = await handleStatus(buildEnvironment(pluginConfig), getCliPath());
389
+ console.log(JSON.stringify(result, null, 2));
445
390
  });
446
-
447
- // 4. CLI
448
- api.registerCli(({ program }: any) => {
449
- const overlay = program.command("sv_overlay").description("BSV Overlay Network management");
450
- overlay.command("status").action(async () => {
451
- await ensureCp();
452
- const result = await handleStatus(buildEnvironment(pluginConfig), getCliPath());
453
- console.log(JSON.stringify(result, null, 2));
454
- });
455
- overlay.command("balance").action(async () => {
456
- await ensureCp();
457
- const result = await handleBalance(buildEnvironment(pluginConfig), getCliPath());
458
- console.log(JSON.stringify(result, null, 2));
459
- });
460
- }, { descriptors: [{ name: "overlay", description: "BSV Overlay Network management" }] });
391
+ overlay.command("balance").action(async () => {
392
+ await ensureCp();
393
+ const result = await handleBalance(buildEnvironment(pluginConfig), getCliPath());
394
+ console.log(JSON.stringify(result, null, 2));
395
+ });
396
+ }, { commands: ["overlay"] });
461
397
  }
462
398
 
463
399
  export const plugin = {
464
- id: "sv_overlay",
400
+ id: "openclaw-overlay-plugin",
465
401
  name: "BSV Overlay Network",
466
402
  description: "OpenClaw Overlay — decentralized agent marketplace with BSV micropayments",
467
403
  activate: register,
@@ -484,24 +420,10 @@ async function executeOverlayAction(params: any, config: any, api: any) {
484
420
  case "onboard": return await handleOnboard(params, env, cliPath);
485
421
  case "pending-requests": return await handlePendingRequests(env, cliPath);
486
422
  case "fulfill": return await handleFulfill(params, env, cliPath);
487
- case "advertise-ship": return await handleAdvertiseSHIP(params, env, cliPath);
488
- case "advertise-slap": return await handleAdvertiseSLAP(params, env, cliPath);
489
423
  default: throw new Error(`Unknown action: ${action}`);
490
424
  }
491
425
  }
492
426
 
493
- async function handleAdvertiseSHIP(params: any, env: any, cliPath: string) {
494
- const { domain, topic } = params;
495
- const result = await execFileAsync('node', [cliPath, 'advertise-ship', domain, topic], { env });
496
- return parseCliOutput(result.stdout).data;
497
- }
498
-
499
- async function handleAdvertiseSLAP(params: any, env: any, cliPath: string) {
500
- const { domain, service } = params;
501
- const result = await execFileAsync('node', [cliPath, 'advertise-slap', domain, service], { env });
502
- return parseCliOutput(result.stdout).data;
503
- }
504
-
505
427
  async function handleServiceRequest(params: any, env: any, cliPath: string, config: any, api: any) {
506
428
  const { service, identityKey: targetKey, input } = params;
507
429
  const walletDir = config?.walletDir || path.join(os.homedir(), '.openclaw', 'bsv-wallet');
@@ -1,8 +1,8 @@
1
1
  {
2
- "id": "sv_overlay",
2
+ "id": "openclaw-overlay-plugin",
3
3
  "name": "BSV Overlay Network",
4
4
  "description": "OpenClaw Overlay — decentralized agent marketplace with BSV micropayments",
5
- "version": "0.2.0",
5
+ "version": "0.8.4",
6
6
  "skills": [
7
7
  "./SKILL.md"
8
8
  ],
@@ -20,7 +20,7 @@
20
20
  ],
21
21
  "commands": [
22
22
  {
23
- "name": "sv_overlay",
23
+ "name": "overlay",
24
24
  "description": "BSV Overlay Network management",
25
25
  "isAutoreply": true
26
26
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "openclaw-overlay-plugin",
3
- "version": "0.8.1",
3
+ "version": "0.8.4",
4
4
  "description": "Openclaw BSV Overlay — agent discovery, service marketplace, and micropayments on the BSV blockchain",
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -23,6 +23,7 @@
23
23
  "prepublishOnly": "npm run build && npm test",
24
24
  "cli": "node dist/src/cli.js",
25
25
  "test": "npx tsx src/test/cli.test.ts && npx tsx src/test/taskflow.test.ts && npx tsx src/test/key-derivation.test.ts",
26
+ "postversion": "node ../sync_versions.js",
26
27
  "lint": "eslint src/**/*.ts"
27
28
  },
28
29
  "dependencies": {