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.
- package/dist/index.d.ts +0 -1
- package/dist/index.js +137 -267
- package/dist/src/cli.js +1 -1
- package/dist/src/scripts/baemail/commands.d.ts +6 -6
- package/dist/src/scripts/messaging/connect.d.ts +2 -2
- package/dist/src/scripts/messaging/connect.js +63 -16
- package/dist/src/scripts/messaging/inbox.d.ts +2 -2
- package/dist/src/scripts/messaging/poll.d.ts +1 -1
- package/dist/src/scripts/messaging/send.d.ts +1 -1
- package/dist/src/scripts/output.d.ts +5 -4
- package/dist/src/scripts/output.js +11 -2
- package/dist/src/scripts/overlay/advertisement.d.ts +2 -2
- package/dist/src/scripts/overlay/discover.d.ts +1 -1
- package/dist/src/scripts/overlay/registration.d.ts +2 -2
- package/dist/src/scripts/overlay/services.d.ts +4 -4
- package/dist/src/scripts/payment/commands.d.ts +3 -3
- package/dist/src/scripts/services/queue.d.ts +2 -2
- package/dist/src/scripts/services/request.d.ts +1 -1
- package/dist/src/scripts/services/respond.d.ts +2 -2
- package/dist/src/scripts/wallet/balance.d.ts +2 -2
- package/dist/src/scripts/wallet/setup.d.ts +4 -4
- package/dist/src/scripts/x-verification/commands.d.ts +6 -6
- package/index.ts +136 -277
- package/openclaw.plugin.json +2 -2
- package/package.json +1 -1
- package/src/cli.ts +1 -1
- package/src/scripts/baemail/commands.ts +6 -6
- package/src/scripts/messaging/connect.ts +49 -16
- package/src/scripts/messaging/inbox.ts +2 -2
- package/src/scripts/messaging/poll.ts +1 -1
- package/src/scripts/messaging/send.ts +1 -1
- package/src/scripts/output.ts +13 -4
- package/src/scripts/overlay/advertisement.ts +2 -2
- package/src/scripts/overlay/discover.ts +1 -1
- package/src/scripts/overlay/registration.ts +2 -2
- package/src/scripts/overlay/services.ts +4 -4
- package/src/scripts/payment/commands.ts +3 -3
- package/src/scripts/services/queue.ts +2 -2
- package/src/scripts/services/request.ts +1 -1
- package/src/scripts/services/respond.ts +2 -2
- package/src/scripts/wallet/balance.ts +2 -2
- package/src/scripts/wallet/setup.ts +4 -4
- package/src/scripts/x-verification/commands.ts +6 -6
package/dist/index.d.ts
CHANGED
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
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
83
|
-
|
|
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
|
-
|
|
86
|
-
const addrOutput =
|
|
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;
|
|
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
|
-
|
|
112
|
-
const importOutput =
|
|
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(
|
|
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
|
-
|
|
132
|
-
const regOutput =
|
|
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(
|
|
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
|
|
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
|
-
|
|
171
|
-
|
|
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
|
|
186
|
-
|
|
187
|
-
|
|
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 =
|
|
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
|
|
209
|
-
|
|
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
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
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 (
|
|
283
|
-
|
|
284
|
-
|
|
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
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
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
|
|
362
|
-
|
|
363
|
-
|
|
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
|
-
|
|
377
|
-
const
|
|
378
|
-
console.log(JSON.stringify(
|
|
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
|
-
|
|
382
|
-
const
|
|
383
|
-
console.log(JSON.stringify(
|
|
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<
|
|
28
|
-
export declare function cmdBaemailSetup(priceSatsStr: string, prioritySats?: string, urgentSats?: string, channel?: string): Promise<
|
|
29
|
-
export declare function cmdBaemailConfig(): Promise<
|
|
30
|
-
export declare function cmdBaemailBlock(pubkey: string): Promise<
|
|
31
|
-
export declare function cmdBaemailUnblock(pubkey: string): Promise<
|
|
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<
|
|
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
|
-
*
|
|
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>;
|