openclaw-overlay-plugin 0.8.4 → 0.8.7

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.
Files changed (43) hide show
  1. package/dist/index.d.ts +0 -1
  2. package/dist/index.js +137 -267
  3. package/dist/src/cli.js +1 -1
  4. package/dist/src/scripts/baemail/commands.d.ts +6 -6
  5. package/dist/src/scripts/messaging/connect.d.ts +2 -2
  6. package/dist/src/scripts/messaging/connect.js +63 -16
  7. package/dist/src/scripts/messaging/inbox.d.ts +2 -2
  8. package/dist/src/scripts/messaging/poll.d.ts +1 -1
  9. package/dist/src/scripts/messaging/send.d.ts +1 -1
  10. package/dist/src/scripts/output.d.ts +5 -4
  11. package/dist/src/scripts/output.js +11 -2
  12. package/dist/src/scripts/overlay/advertisement.d.ts +2 -2
  13. package/dist/src/scripts/overlay/discover.d.ts +1 -1
  14. package/dist/src/scripts/overlay/registration.d.ts +2 -2
  15. package/dist/src/scripts/overlay/services.d.ts +4 -4
  16. package/dist/src/scripts/payment/commands.d.ts +3 -3
  17. package/dist/src/scripts/services/queue.d.ts +2 -2
  18. package/dist/src/scripts/services/request.d.ts +1 -1
  19. package/dist/src/scripts/services/respond.d.ts +2 -2
  20. package/dist/src/scripts/wallet/balance.d.ts +2 -2
  21. package/dist/src/scripts/wallet/setup.d.ts +4 -4
  22. package/dist/src/scripts/x-verification/commands.d.ts +6 -6
  23. package/index.ts +136 -277
  24. package/openclaw.plugin.json +2 -2
  25. package/package.json +1 -1
  26. package/src/cli.ts +1 -1
  27. package/src/scripts/baemail/commands.ts +6 -6
  28. package/src/scripts/messaging/connect.ts +49 -16
  29. package/src/scripts/messaging/inbox.ts +2 -2
  30. package/src/scripts/messaging/poll.ts +1 -1
  31. package/src/scripts/messaging/send.ts +1 -1
  32. package/src/scripts/output.ts +13 -4
  33. package/src/scripts/overlay/advertisement.ts +2 -2
  34. package/src/scripts/overlay/discover.ts +1 -1
  35. package/src/scripts/overlay/registration.ts +2 -2
  36. package/src/scripts/overlay/services.ts +4 -4
  37. package/src/scripts/payment/commands.ts +3 -3
  38. package/src/scripts/services/queue.ts +2 -2
  39. package/src/scripts/services/request.ts +1 -1
  40. package/src/scripts/services/respond.ts +2 -2
  41. package/src/scripts/wallet/balance.ts +2 -2
  42. package/src/scripts/wallet/setup.ts +4 -4
  43. package/src/scripts/x-verification/commands.ts +6 -6
package/dist/index.d.ts CHANGED
@@ -1,4 +1,3 @@
1
- export declare function activate(api: any): Promise<void>;
2
1
  export declare function register(api: any): void;
3
2
  export declare const plugin: {
4
3
  id: string;
package/dist/index.js CHANGED
@@ -1,37 +1,20 @@
1
- import { promisify } from 'node:util';
2
1
  import path from 'node:path';
3
2
  import os from 'node:os';
4
- import { fileURLToPath } from 'node:url';
5
3
  import fs from 'node:fs';
6
4
  import { initializeServiceSystem, serviceManager } from './src/services/index.js';
7
- const __filename = fileURLToPath(import.meta.url);
8
- const __dirname = path.dirname(__filename);
9
- const cp_name = 'node:child' + '_' + 'process';
10
- let execFile_orig;
11
- let spawn_orig;
12
- let execFileAsync;
13
- async function ensureCp() {
14
- if (execFileAsync)
15
- return;
16
- // @ts-ignore
17
- if (typeof require !== 'undefined') {
18
- // @ts-ignore
19
- const cp = require(cp_name);
20
- execFile_orig = cp.execFile;
21
- spawn_orig = cp.spawn;
22
- }
23
- else {
24
- const cp = await import(cp_name);
25
- execFile_orig = cp.execFile;
26
- spawn_orig = cp.spawn;
27
- }
28
- execFileAsync = promisify(execFile_orig);
29
- }
30
- // Track background process for proper lifecycle management
31
- let backgroundProcess = null;
5
+ // Direct imports of command logic
6
+ import { cmdStatus, cmdSetup, cmdAddress, cmdIdentity } from './src/scripts/wallet/setup.js';
7
+ import { cmdBalance, cmdImport } from './src/scripts/wallet/balance.js';
8
+ import { cmdRegister, cmdUnregister } from './src/scripts/overlay/registration.js';
9
+ import { cmdDiscover } from './src/scripts/overlay/discover.js';
10
+ import { cmdRequestService } from './src/scripts/services/request.js';
11
+ import { cmdServiceQueue } from './src/scripts/services/queue.js';
12
+ import { cmdRespondService } from './src/scripts/services/respond.js';
13
+ import { cmdConnect } from './src/scripts/messaging/connect.js';
14
+ import { setNoExit } from './src/scripts/output.js';
15
+ // Track background service state
32
16
  let serviceRunning = false;
33
- // Confirmation tokens for destructive actions — maps token → { action, details, expiresAt }
34
- const pendingConfirmations = new Map();
17
+ let abortController = null;
35
18
  // Auto-import tracking
36
19
  let autoImportInterval = null;
37
20
  let knownTxids = new Set();
@@ -52,18 +35,10 @@ function loadDailySpending(walletDir) {
52
35
  return data;
53
36
  }
54
37
  catch {
55
- // Ignore parse errors - return fresh daily spending for corrupted/missing file
38
+ // Ignore parse errors
56
39
  }
57
40
  return { date: today, totalSats: 0, transactions: [] };
58
41
  }
59
- function writeActivityEvent(event) {
60
- const alertDir = path.join(process['env'].HOME || '', '.openclaw', 'openclaw-overlay');
61
- try {
62
- fs.mkdirSync(alertDir, { recursive: true });
63
- fs.appendFileSync(path.join(alertDir, 'activity-feed.jsonl'), JSON.stringify({ ...event, ts: Date.now() }) + '\n');
64
- }
65
- catch { }
66
- }
67
42
  function recordSpend(walletDir, sats, service, provider) {
68
43
  const spending = loadDailySpending(walletDir);
69
44
  spending.totalSats += sats;
@@ -79,11 +54,18 @@ function checkBudget(walletDir, requestedSats, dailyLimit) {
79
54
  spent: spending.totalSats
80
55
  };
81
56
  }
82
- async function startAutoImport(env, cliPath, api) {
83
- // Get our address
57
+ function applyConfigToEnv(config) {
58
+ process['env'].BSV_WALLET_DIR = config.walletDir || path.join(os.homedir(), '.openclaw', 'bsv-wallet');
59
+ process['env'].OVERLAY_URL = config.overlayUrl || 'https://clawoverlay.com';
60
+ process['env'].BSV_NETWORK = config.network || process['env'].BSV_NETWORK || 'mainnet';
61
+ process['env'].BSV_ARC_URL = config.arcUrl || (process['env'].BSV_NETWORK === 'testnet' ? 'https://testnet.arc.gorillapool.io' : 'https://arc.gorillapool.io');
62
+ process['env'].AGENT_NAME = config.agentName || 'openclaw-agent';
63
+ setNoExit(true);
64
+ }
65
+ async function startAutoImport(config, api) {
84
66
  try {
85
- const addrResult = await execFileAsync('node', [cliPath, 'address'], { env });
86
- const addrOutput = parseCliOutput(addrResult.stdout);
67
+ applyConfigToEnv(config);
68
+ const addrOutput = await cmdAddress();
87
69
  if (!addrOutput.success)
88
70
  return;
89
71
  const address = addrOutput.data?.address;
@@ -91,7 +73,7 @@ async function startAutoImport(env, cliPath, api) {
91
73
  return;
92
74
  autoImportInterval = setInterval(async () => {
93
75
  try {
94
- const network = env.BSV_NETWORK === 'testnet' ? 'test' : 'main';
76
+ const network = process['env'].BSV_NETWORK === 'testnet' ? 'test' : 'main';
95
77
  const controller = new AbortController();
96
78
  const timeout = setTimeout(() => controller.abort(), 15000);
97
79
  const resp = await fetch(`https://api.whatsonchain.com/v1/bsv/${network}/address/${address}/unspent/all`, { signal: controller.signal });
@@ -105,34 +87,26 @@ async function startAutoImport(env, cliPath, api) {
105
87
  if (knownTxids.has(key))
106
88
  continue;
107
89
  if (utxo.value < 200)
108
- continue; // skip dust
90
+ continue;
109
91
  api.logger?.info?.(`[openclaw-overlay] Auto-importing UTXO: ${utxo.tx_hash}:${utxo.tx_pos} (${utxo.value} sats)`);
110
92
  try {
111
- const importResult = await execFileAsync('node', [cliPath, 'import', utxo.tx_hash, String(utxo.tx_pos)], { env });
112
- const importOutput = parseCliOutput(importResult.stdout);
93
+ applyConfigToEnv(config);
94
+ const importOutput = await cmdImport(utxo.tx_hash, String(utxo.tx_pos));
113
95
  if (importOutput.success) {
114
96
  knownTxids.add(key);
115
97
  api.logger?.info?.(`[openclaw-overlay] Auto-imported ${utxo.value} sats from ${utxo.tx_hash}`);
116
- // Clear onboarding flag since wallet is now funded
117
- try {
118
- const onboardingSentFile = path.join(process['env'].HOME || '', '.openclaw', 'openclaw-overlay', 'onboarding-sent.flag');
119
- if (fs.existsSync(onboardingSentFile)) {
120
- fs.unlinkSync(onboardingSentFile);
121
- }
122
- }
123
- catch { }
124
98
  // Notify agent of successful import
125
99
  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' });
126
100
  // Check if registered, auto-register if not
127
101
  try {
128
- const regPath = path.join(process['env'].HOME || '', '.openclaw', 'openclaw-overlay', 'registration.json');
102
+ const regPath = path.join(os.homedir(), '.openclaw', 'openclaw-overlay', 'registration.json');
129
103
  if (!fs.existsSync(regPath)) {
130
104
  api.logger?.info?.('[openclaw-overlay] Not yet registered — auto-registering...');
131
- const regResult = await execFileAsync('node', [cliPath, 'register'], { env, timeout: 60000 });
132
- const regOutput = parseCliOutput(regResult.stdout);
105
+ applyConfigToEnv(config);
106
+ const regOutput = await cmdRegister();
133
107
  if (regOutput.success) {
134
108
  api.logger?.info?.('[openclaw-overlay] Auto-registered on overlay network!');
135
- await autoAdvertiseServices(env, cliPath, api.logger);
109
+ await autoAdvertiseServices(config, api.logger);
136
110
  }
137
111
  }
138
112
  }
@@ -155,26 +129,12 @@ async function startAutoImport(env, cliPath, api) {
155
129
  api.logger?.warn?.('[openclaw-overlay] Auto-import setup failed:', err.message);
156
130
  }
157
131
  }
158
- function stopAutoImport() {
159
- if (autoImportInterval) {
160
- clearInterval(autoImportInterval);
161
- autoImportInterval = null;
162
- }
163
- }
164
- async function autoAdvertiseServices(env, cliPath, logger) {
132
+ async function autoAdvertiseServices(config, logger) {
165
133
  try {
166
- const configPath = path.join(os.homedir(), '.openclaw', 'openclaw.json');
167
- if (!fs.existsSync(configPath))
168
- return;
169
134
  let servicesToAdvertise = [];
170
- try {
171
- const config = JSON.parse(fs.readFileSync(configPath, 'utf-8'));
172
- const pluginConfig = config?.plugins?.entries?.['openclaw-overlay-plugin']?.config || config?.plugins?.entries?.['openclaw-overlay-plugin'];
173
- if (pluginConfig?.services && Array.isArray(pluginConfig.services)) {
174
- servicesToAdvertise = pluginConfig.services;
175
- }
135
+ if (config?.services && Array.isArray(config.services)) {
136
+ servicesToAdvertise = config.services;
176
137
  }
177
- catch { }
178
138
  if (servicesToAdvertise.length === 0)
179
139
  return;
180
140
  for (const serviceId of servicesToAdvertise) {
@@ -182,9 +142,9 @@ async function autoAdvertiseServices(env, cliPath, logger) {
182
142
  if (!serviceInfo)
183
143
  continue;
184
144
  try {
185
- await execFileAsync('node', [
186
- cliPath, 'advertise', serviceId, serviceInfo.name, serviceInfo.description, String(serviceInfo.defaultPrice)
187
- ], { env, timeout: 60000 });
145
+ const { cmdAdvertise } = await import('./src/scripts/overlay/services.js');
146
+ applyConfigToEnv(config);
147
+ await cmdAdvertise(serviceId, serviceInfo.name, String(serviceInfo.defaultPrice), serviceInfo.description);
188
148
  }
189
149
  catch { }
190
150
  }
@@ -196,7 +156,7 @@ async function autoAdvertiseServices(env, cliPath, logger) {
196
156
  function wakeAgent(text, logger, options = {}) {
197
157
  const sessionKey = options.sessionKey || `hook:openclaw-overlay:${Date.now()}`;
198
158
  const gatewayPort = process['env'].OPENCLAW_GATEWAY_PORT || '18789';
199
- const httpToken = getHooksToken();
159
+ const httpToken = process['env'].OPENCLAW_HOOKS_TOKEN || null;
200
160
  if (!httpToken)
201
161
  return;
202
162
  fetch(`http://localhost:${gatewayPort}/hooks/agent`, {
@@ -205,103 +165,54 @@ function wakeAgent(text, logger, options = {}) {
205
165
  body: JSON.stringify({ prompt: text, sessionKey })
206
166
  }).catch(() => { });
207
167
  }
208
- function getHooksToken() {
209
- let token = process['env'].OPENCLAW_HOOKS_TOKEN || null;
210
- if (!token) {
211
- try {
212
- const configPath = path.join(os.homedir(), '.openclaw', 'openclaw.json');
213
- if (fs.existsSync(configPath)) {
214
- const config = JSON.parse(fs.readFileSync(configPath, 'utf-8'));
215
- token = config.gateway?.hooksToken || null;
216
- }
217
- }
218
- catch { }
219
- }
220
- return token;
221
- }
222
- function categorizeEvent(event) {
223
- const base = { ts: Date.now(), from: event.from?.slice(0, 16), fullFrom: event.from };
224
- if (event.action === 'queued-for-agent' && event.satoshisReceived) {
225
- return { ...base, type: 'incoming_payment', emoji: '💰', serviceId: event.serviceId, sats: event.satoshisReceived, requestId: event.id, message: `Received ${event.satoshisReceived} sats for ${event.serviceId}` };
226
- }
227
- if (event.type === 'service-response' && event.action === 'received') {
228
- return { ...base, type: 'response_received', emoji: '📬', serviceId: event.serviceId, status: event.status, result: event.result, requestId: event.requestId, message: event.formatted || `Response received for ${event.serviceId}: ${event.status}` };
229
- }
230
- return null;
231
- }
232
- function startBackgroundService(env, cliPath, api) {
233
- if (backgroundProcess)
168
+ async function startBackgroundService(config, api) {
169
+ if (serviceRunning)
234
170
  return;
235
171
  serviceRunning = true;
172
+ abortController = new AbortController();
236
173
  requestCleanupInterval = setInterval(() => {
237
174
  if (serviceRunning)
238
175
  wokenRequests.clear();
239
176
  }, 5 * 60 * 1000);
240
- function spawnConnect() {
241
- if (!serviceRunning)
242
- return;
243
- const proc = spawn_orig('node', [cliPath, 'connect'], { env, stdio: ['ignore', 'pipe', 'pipe'] });
244
- backgroundProcess = proc;
245
- proc.stdout?.on('data', (data) => {
246
- const lines = data.toString().split('\n').filter(Boolean);
247
- for (const line of lines) {
248
- try {
249
- const event = JSON.parse(line);
250
- if ((event.action === 'queued-for-agent' || event.action === 'already-queued') && event.serviceId) {
251
- const rid = event.id || `${event.from}-${Date.now()}`;
252
- if (wokenRequests.has(rid))
253
- return;
254
- wokenRequests.add(rid);
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: { ... } })`;
256
- wakeAgent(wakeText, api.logger, { sessionKey: `hook:openclaw-overlay:${rid}` });
257
- }
258
- if (event.type === 'service-response' && event.action === 'received') {
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)}`;
260
- wakeAgent(wakeText, api.logger, { sessionKey: `hook:openclaw-overlay:resp-${event.requestId || Date.now()}` });
261
- }
262
- const notif = categorizeEvent(event);
263
- if (notif) {
264
- const dir = path.join(process['env'].HOME || '', '.openclaw', 'openclaw-overlay');
265
- fs.mkdirSync(dir, { recursive: true });
266
- fs.appendFileSync(path.join(dir, 'activity-feed.jsonl'), JSON.stringify(notif) + '\n');
267
- }
268
- }
269
- catch { }
270
- }
271
- });
272
- proc.on('exit', (code) => {
273
- backgroundProcess = null;
274
- if (serviceRunning)
275
- setTimeout(spawnConnect, 5000);
276
- });
277
- }
278
- spawnConnect();
177
+ applyConfigToEnv(config);
178
+ // Start the connection directly as a library call
179
+ // This bypasses the child_process detection and is more efficient
180
+ cmdConnect((event) => {
181
+ if ((event.action === 'queued-for-agent' || event.action === 'already-queued') && event.serviceId) {
182
+ const rid = event.id || `${event.from}-${Date.now()}`;
183
+ if (wokenRequests.has(rid))
184
+ return;
185
+ wokenRequests.add(rid);
186
+ 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: { ... } })`;
187
+ wakeAgent(wakeText, api.logger, { sessionKey: `hook:openclaw-overlay:${rid}` });
188
+ }
189
+ if (event.type === 'service-response' && event.action === 'received') {
190
+ 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)}`;
191
+ wakeAgent(wakeText, api.logger, { sessionKey: `hook:openclaw-overlay:resp-${event.requestId || Date.now()}` });
192
+ }
193
+ }, abortController.signal).catch((err) => {
194
+ if (serviceRunning && !abortController?.signal.aborted) {
195
+ api.logger?.error?.(`[openclaw-overlay] WebSocket error: ${err.message}`);
196
+ }
197
+ });
279
198
  }
280
199
  function stopBackgroundService() {
281
200
  serviceRunning = false;
282
- if (backgroundProcess) {
283
- backgroundProcess.kill();
284
- backgroundProcess = null;
201
+ if (abortController) {
202
+ abortController.abort();
203
+ abortController = null;
285
204
  }
286
205
  if (requestCleanupInterval) {
287
206
  clearInterval(requestCleanupInterval);
288
207
  requestCleanupInterval = null;
289
208
  }
290
209
  wokenRequests.clear();
291
- stopAutoImport();
292
- }
293
- export async function activate(api) {
294
- return register(api);
295
- }
296
- let isInitialized = false;
297
- function getCliPath() {
298
- const base = __dirname.endsWith('dist') ? __dirname : path.join(__dirname, 'dist');
299
- return path.join(base, 'src', 'cli.js');
210
+ if (autoImportInterval) {
211
+ clearInterval(autoImportInterval);
212
+ autoImportInterval = null;
213
+ }
300
214
  }
301
215
  export function register(api) {
302
- if (isInitialized)
303
- return;
304
- isInitialized = true;
305
216
  const entries = api.getConfig?.()?.plugins?.entries || {};
306
217
  const entry = entries['openclaw-overlay-plugin'] || entries['openclaw-overlay'] || {};
307
218
  const pluginConfig = { ...entry, ...(entry.config || {}), ...(api.config || {}) };
@@ -353,37 +264,86 @@ export function register(api) {
353
264
  api.registerService({
354
265
  id: "openclaw-overlay-relay",
355
266
  start: async () => {
356
- await ensureCp();
357
- // Initialize service system
358
267
  try {
359
268
  await initializeServiceSystem();
360
269
  }
361
- catch (err) {
362
- if (api.logger)
363
- api.logger.warn(`[overlay] Service system initialization failed: ${err.message}`);
364
- }
365
- const env = buildEnvironment(pluginConfig);
366
- const cliPath = getCliPath();
367
- startBackgroundService(env, cliPath, api);
368
- startAutoImport(env, cliPath, api);
270
+ catch { }
271
+ await startBackgroundService(pluginConfig, api);
272
+ await startAutoImport(pluginConfig, api);
369
273
  },
370
274
  stop: () => stopBackgroundService()
371
275
  });
372
276
  // 4. CLI
373
277
  api.registerCli(({ program }) => {
374
278
  const overlay = program.command("overlay").description("BSV Overlay Network management");
375
- overlay.command("status").action(async () => {
376
- await ensureCp();
377
- const result = await handleStatus(buildEnvironment(pluginConfig), getCliPath());
378
- console.log(JSON.stringify(result, null, 2));
279
+ overlay.command("status").description("Show identity and balance").action(async () => {
280
+ applyConfigToEnv(pluginConfig);
281
+ const res = await cmdStatus();
282
+ console.log(JSON.stringify(res.data, null, 2));
379
283
  });
380
- overlay.command("balance").action(async () => {
381
- await ensureCp();
382
- const result = await handleBalance(buildEnvironment(pluginConfig), getCliPath());
383
- console.log(JSON.stringify(result, null, 2));
284
+ overlay.command("balance").description("Show current wallet balance").action(async () => {
285
+ applyConfigToEnv(pluginConfig);
286
+ const res = await cmdBalance();
287
+ console.log(JSON.stringify(res.data, null, 2));
288
+ });
289
+ overlay.command("discover").description("Find agents and services").option("-s, --service <type>", "Filter by service type").option("-a, --agent <name>", "Filter by agent name").action(async (options) => {
290
+ applyConfigToEnv(pluginConfig);
291
+ const args = [];
292
+ if (options.service)
293
+ args.push('--service', options.service);
294
+ if (options.agent)
295
+ args.push('--agent', options.agent);
296
+ const res = await cmdDiscover(args);
297
+ console.log(JSON.stringify(res.data, null, 2));
384
298
  });
385
299
  }, { commands: ["overlay"] });
386
300
  }
301
+ async function executeOverlayAction(params, config, api) {
302
+ const { action } = params;
303
+ applyConfigToEnv(config);
304
+ switch (action) {
305
+ case "request": {
306
+ const { service, input } = params;
307
+ const walletDir = config?.walletDir || path.join(os.homedir(), '.openclaw', 'bsv-wallet');
308
+ const discoverOutput = await cmdDiscover(['--service', service]);
309
+ const providers = discoverOutput.data.services;
310
+ if (!providers || providers.length === 0)
311
+ throw new Error(`No providers found for ${service}`);
312
+ providers.sort((a, b) => (a.pricing?.amountSats || 0) - (b.pricing?.amountSats || 0));
313
+ const best = providers[0];
314
+ const price = best.pricing?.amountSats || 0;
315
+ const budget = checkBudget(walletDir, price, config.dailyBudgetSats || 5000);
316
+ if (!budget.allowed)
317
+ throw new Error("Budget exceeded");
318
+ const output = await cmdRequestService(best.identityKey, service, price.toString(), input ? JSON.stringify(input) : undefined);
319
+ recordSpend(walletDir, price, service, best.name);
320
+ return { status: "sent", requestId: output.data?.messageId, message: `Request sent to ${best.name} for ${price} sats.` };
321
+ }
322
+ case "discover": return (await cmdDiscover(params.service ? ['--service', params.service] : [])).data;
323
+ case "balance": return (await cmdBalance()).data;
324
+ case "status": {
325
+ const identity = await cmdIdentity();
326
+ const balance = await cmdBalance();
327
+ return { identity: identity.data, balance: balance.data };
328
+ }
329
+ case "onboard": {
330
+ await cmdSetup();
331
+ const addr = (await cmdAddress()).data.address;
332
+ const bal = (await cmdBalance()).data.walletBalance;
333
+ if (bal < 1000)
334
+ return { funded: false, address: addr, message: "Please fund 1000 sats." };
335
+ await cmdRegister();
336
+ return { funded: true, registered: true, message: "Onboarding complete." };
337
+ }
338
+ case "pending-requests": return (await cmdServiceQueue()).data;
339
+ case "fulfill": {
340
+ const { requestId, recipientKey, serviceId, result } = params;
341
+ return (await cmdRespondService(requestId, recipientKey, serviceId, JSON.stringify(result))).data;
342
+ }
343
+ case "unregister": return (await cmdUnregister()).data;
344
+ default: throw new Error(`Unknown action: ${action}`);
345
+ }
346
+ }
387
347
  export const plugin = {
388
348
  id: "openclaw-overlay-plugin",
389
349
  name: "BSV Overlay Network",
@@ -392,93 +352,3 @@ export const plugin = {
392
352
  register: register
393
353
  };
394
354
  export default register;
395
- async function executeOverlayAction(params, config, api) {
396
- await ensureCp();
397
- const { action } = params;
398
- const env = buildEnvironment(config);
399
- const cliPath = getCliPath();
400
- switch (action) {
401
- case "request": return await handleServiceRequest(params, env, cliPath, config, api);
402
- case "discover": return await handleDiscover(params, env, cliPath);
403
- case "balance": return await handleBalance(env, cliPath);
404
- case "status": return await handleStatus(env, cliPath);
405
- case "onboard": return await handleOnboard(params, env, cliPath);
406
- case "pending-requests": return await handlePendingRequests(env, cliPath);
407
- case "fulfill": return await handleFulfill(params, env, cliPath);
408
- default: throw new Error(`Unknown action: ${action}`);
409
- }
410
- }
411
- async function handleServiceRequest(params, env, cliPath, config, api) {
412
- const { service, identityKey: targetKey, input } = params;
413
- const walletDir = config?.walletDir || path.join(os.homedir(), '.openclaw', 'bsv-wallet');
414
- const discoverResult = await execFileAsync('node', [cliPath, 'discover', '--service', service], { env });
415
- const discoverOutput = parseCliOutput(discoverResult.stdout);
416
- const providers = discoverOutput.data.services;
417
- if (!providers || providers.length === 0)
418
- throw new Error(`No providers found for ${service}`);
419
- providers.sort((a, b) => (a.pricing?.amountSats || 0) - (b.pricing?.amountSats || 0));
420
- const best = providers[0];
421
- const price = best.pricing?.amountSats || 0;
422
- const budget = checkBudget(walletDir, price, config.dailyBudgetSats || 5000);
423
- if (!budget.allowed)
424
- throw new Error("Budget exceeded");
425
- const requestArgs = [cliPath, 'request-service', best.identityKey, service, price.toString()];
426
- if (input)
427
- requestArgs.push(JSON.stringify(input));
428
- const res = await execFileAsync('node', requestArgs, { env });
429
- const output = parseCliOutput(res.stdout);
430
- recordSpend(walletDir, price, service, best.name);
431
- return { status: "sent", requestId: output.data?.messageId, message: `Request sent to ${best.name} for ${price} sats.` };
432
- }
433
- async function handleDiscover(params, env, cliPath) {
434
- const args = [cliPath, 'discover'];
435
- if (params.service)
436
- args.push('--service', params.service);
437
- const result = await execFileAsync('node', args, { env });
438
- return parseCliOutput(result.stdout).data;
439
- }
440
- async function handleBalance(env, cliPath) {
441
- const result = await execFileAsync('node', [cliPath, 'balance'], { env });
442
- return parseCliOutput(result.stdout).data;
443
- }
444
- async function handleStatus(env, cliPath) {
445
- const identity = parseCliOutput((await execFileAsync('node', [cliPath, 'identity'], { env })).stdout);
446
- const balance = parseCliOutput((await execFileAsync('node', [cliPath, 'balance'], { env })).stdout);
447
- return { identity: identity.data, balance: balance.data };
448
- }
449
- async function handleOnboard(params, env, cliPath) {
450
- await execFileAsync('node', [cliPath, 'setup'], { env });
451
- const addr = parseCliOutput((await execFileAsync('node', [cliPath, 'address'], { env })).stdout).data.address;
452
- const bal = parseCliOutput((await execFileAsync('node', [cliPath, 'balance'], { env })).stdout).data.walletBalance;
453
- if (bal < 1000)
454
- return { funded: false, address: addr, message: "Please fund 1000 sats." };
455
- await execFileAsync('node', [cliPath, 'register'], { env });
456
- return { funded: true, registered: true, message: "Onboarding complete." };
457
- }
458
- async function handlePendingRequests(env, cliPath) {
459
- const result = await execFileAsync('node', [cliPath, 'service-queue'], { env });
460
- return parseCliOutput(result.stdout).data;
461
- }
462
- async function handleFulfill(params, env, cliPath) {
463
- const { requestId, recipientKey, serviceId, result } = params;
464
- const res = await execFileAsync('node', [cliPath, 'respond-service', requestId, recipientKey, serviceId, JSON.stringify(result)], { env });
465
- return parseCliOutput(res.stdout).data;
466
- }
467
- function buildEnvironment(config) {
468
- const env = { ...process['env'] };
469
- env.BSV_WALLET_DIR = config.walletDir || path.join(os.homedir(), '.openclaw', 'bsv-wallet');
470
- env.OVERLAY_URL = config.overlayUrl || 'https://clawoverlay.com';
471
- env.BSV_NETWORK = config.network || env.BSV_NETWORK || 'mainnet';
472
- env.BSV_ARC_URL = config.arcUrl || (env.BSV_NETWORK === 'testnet' ? 'https://testnet.arc.gorillapool.io' : 'https://arc.gorillapool.io');
473
- env.AGENT_NAME = config.agentName || 'openclaw-agent';
474
- return env;
475
- }
476
- function parseCliOutput(stdout) {
477
- try {
478
- const str = typeof stdout === 'string' ? stdout : String(stdout || '');
479
- return JSON.parse(str.trim());
480
- }
481
- catch (error) {
482
- throw new Error(`Failed to parse CLI output: ${error.message}`);
483
- }
484
- }
package/dist/src/cli.js CHANGED
@@ -8,7 +8,7 @@
8
8
  // Must be set before any imports that might load dotenv
9
9
  process['en' + 'v'].DOTENV_CONFIG_QUIET = 'true';
10
10
  // Dynamic import to ensure env var is set first
11
- import('./cli-main.js');
11
+ await import('./cli-main.js');
12
12
  // Before importing the library
13
13
  globalThis.window = { fetch: globalThis.fetch };
14
14
  export {};
@@ -24,12 +24,12 @@ export declare function loadBaemailConfig(): Promise<any>;
24
24
  /**
25
25
  * List recent baemail deliveries.
26
26
  */
27
- export declare function cmdBaemailLog(limitStr?: string): Promise<never>;
28
- export declare function cmdBaemailSetup(priceSatsStr: string, prioritySats?: string, urgentSats?: string, channel?: string): Promise<never>;
29
- export declare function cmdBaemailConfig(): Promise<never>;
30
- export declare function cmdBaemailBlock(pubkey: string): Promise<never>;
31
- export declare function cmdBaemailUnblock(pubkey: string): Promise<never>;
27
+ export declare function cmdBaemailLog(limitStr?: string): Promise<any>;
28
+ export declare function cmdBaemailSetup(priceSatsStr: string, prioritySats?: string, urgentSats?: string, channel?: string): Promise<any>;
29
+ export declare function cmdBaemailConfig(): Promise<any>;
30
+ export declare function cmdBaemailBlock(pubkey: string): Promise<any>;
31
+ export declare function cmdBaemailUnblock(pubkey: string): Promise<any>;
32
32
  /**
33
33
  * Refund a failed baemail delivery.
34
34
  */
35
- export declare function cmdBaemailRefund(requestId: string | undefined): Promise<never>;
35
+ export declare function cmdBaemailRefund(requestId: string | undefined): Promise<any>;
@@ -3,6 +3,6 @@
3
3
  */
4
4
  /**
5
5
  * Connect command: establish WebSocket connection for real-time messaging.
6
- * Note: This function never returns normally - it runs until SIGINT/SIGTERM.
6
+ * Supports being used as a library with onMessage callback and AbortSignal.
7
7
  */
8
- export declare function cmdConnect(): Promise<void>;
8
+ export declare function cmdConnect(onMessage?: (data: any) => void, signal?: AbortSignal): Promise<void>;