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
@@ -11,9 +11,9 @@ import { ensureStateDir } from '../utils/storage.js';
11
11
 
12
12
  /**
13
13
  * Connect command: establish WebSocket connection for real-time messaging.
14
- * Note: This function never returns normally - it runs until SIGINT/SIGTERM.
14
+ * Supports being used as a library with onMessage callback and AbortSignal.
15
15
  */
16
- export async function cmdConnect(): Promise<void> {
16
+ export async function cmdConnect(onMessage?: (data: any) => void, signal?: AbortSignal): Promise<void> {
17
17
  let WebSocketClient: any;
18
18
  try {
19
19
  const ws = await import('ws');
@@ -34,19 +34,36 @@ export async function cmdConnect(): Promise<void> {
34
34
  if (currentWs) {
35
35
  try { currentWs.close(); } catch {}
36
36
  }
37
- process.exit(0);
37
+ // Only exit if we're not running as a library
38
+ if (!onMessage) {
39
+ process.exit(0);
40
+ }
38
41
  }
39
42
 
40
- process.on('SIGINT', shutdown);
41
- process.on('SIGTERM', shutdown);
43
+ if (!onMessage) {
44
+ process.on('SIGINT', shutdown);
45
+ process.on('SIGTERM', shutdown);
46
+ }
47
+
48
+ if (signal) {
49
+ signal.addEventListener('abort', () => {
50
+ shouldReconnect = false;
51
+ if (currentWs) {
52
+ try { currentWs.close(); } catch {}
53
+ }
54
+ });
55
+ }
42
56
 
43
57
  function connect() {
58
+ if (signal?.aborted) return;
44
59
  const ws = new WebSocketClient(wsUrl);
45
60
  currentWs = ws;
46
61
 
47
62
  ws.on('open', () => {
48
63
  reconnectDelay = 1000; // reset on successful connect
49
- console.error(JSON.stringify({ event: 'connected', identity: identityKey, overlay: OVERLAY_URL }));
64
+ const log = { event: 'connected', identity: identityKey, overlay: OVERLAY_URL };
65
+ if (onMessage) onMessage(log);
66
+ else console.error(JSON.stringify(log));
50
67
  });
51
68
 
52
69
  ws.on('message', async (data: any) => {
@@ -54,8 +71,9 @@ export async function cmdConnect(): Promise<void> {
54
71
  const envelope = JSON.parse(data.toString());
55
72
  if (envelope.type === 'message') {
56
73
  const result = await processMessage(envelope.message, identityKey, privKey);
57
- // Output the result as a JSON line to stdout
58
- console.log(JSON.stringify(result));
74
+
75
+ if (onMessage) onMessage(result);
76
+ else console.log(JSON.stringify(result));
59
77
 
60
78
  // Also append to notification log
61
79
  ensureStateDir();
@@ -72,7 +90,9 @@ export async function cmdConnect(): Promise<void> {
72
90
  body: JSON.stringify({ identity: identityKey, messageIds: [result.id] }),
73
91
  });
74
92
  } catch (ackErr: any) {
75
- console.error(JSON.stringify({ event: 'ack-error', id: result.id, message: String(ackErr) }));
93
+ const log = { event: 'ack-error', id: result.id, message: String(ackErr) };
94
+ if (onMessage) onMessage(log);
95
+ else console.error(JSON.stringify(log));
76
96
  }
77
97
  }
78
98
  }
@@ -90,32 +110,45 @@ export async function cmdConnect(): Promise<void> {
90
110
  txid: envelope.txid,
91
111
  _ts: Date.now(),
92
112
  };
93
- console.log(JSON.stringify(announcement));
113
+ if (onMessage) onMessage(announcement);
114
+ else console.log(JSON.stringify(announcement));
115
+
94
116
  ensureStateDir();
95
117
  try {
96
118
  fs.appendFileSync(PATHS.notifications, JSON.stringify(announcement) + '\n');
97
119
  } catch {}
98
120
  }
99
121
  } catch (err: any) {
100
- console.error(JSON.stringify({ event: 'process-error', message: String(err) }));
122
+ const log = { event: 'process-error', message: String(err) };
123
+ if (onMessage) onMessage(log);
124
+ else console.error(JSON.stringify(log));
101
125
  }
102
126
  });
103
127
 
104
128
  ws.on('close', () => {
105
129
  currentWs = null;
106
- if (shouldReconnect) {
107
- console.error(JSON.stringify({ event: 'disconnected', reconnectMs: reconnectDelay }));
130
+ if (shouldReconnect && !signal?.aborted) {
131
+ const log = { event: 'disconnected', reconnectMs: reconnectDelay };
132
+ if (onMessage) onMessage(log);
133
+ else console.error(JSON.stringify(log));
134
+
108
135
  setTimeout(connect, reconnectDelay);
109
136
  reconnectDelay = Math.min(reconnectDelay * 2, 30000);
110
137
  }
111
138
  });
112
139
 
113
140
  ws.on('error', (err: any) => {
114
- console.error(JSON.stringify({ event: 'error', message: err.message }));
141
+ const log = { event: 'error', message: err.message };
142
+ if (onMessage) onMessage(log);
143
+ else console.error(JSON.stringify(log));
115
144
  });
116
145
  }
117
146
 
118
147
  connect();
119
- // Keep the process alive — never resolves
120
- await new Promise(() => {});
148
+ // Keep alive
149
+ return new Promise((resolve) => {
150
+ if (signal) {
151
+ signal.addEventListener('abort', () => resolve());
152
+ }
153
+ });
121
154
  }
@@ -9,7 +9,7 @@ import { loadIdentity, verifyRelaySignature } from '../wallet/identity.js';
9
9
  /**
10
10
  * Inbox command: fetch pending messages.
11
11
  */
12
- export async function cmdInbox(args: string[]): Promise<never> {
12
+ export async function cmdInbox(args: string[]): Promise<any> {
13
13
  const { identityKey } = await loadIdentity();
14
14
 
15
15
  let since = '';
@@ -41,7 +41,7 @@ export async function cmdInbox(args: string[]): Promise<never> {
41
41
  /**
42
42
  * Ack command: acknowledge processed messages.
43
43
  */
44
- export async function cmdAck(messageIds: string[]): Promise<never> {
44
+ export async function cmdAck(messageIds: string[]): Promise<any> {
45
45
  if (!messageIds || messageIds.length === 0) {
46
46
  return fail('Usage: ack <messageId> [messageId2 ...]');
47
47
  }
@@ -10,7 +10,7 @@ import { processMessage } from './handlers.js';
10
10
  /**
11
11
  * Poll command: fetch all pending messages and process them.
12
12
  */
13
- export async function cmdPoll(): Promise<never> {
13
+ export async function cmdPoll(): Promise<any> {
14
14
  const { identityKey, privKey } = await loadIdentity();
15
15
 
16
16
  // Fetch inbox
@@ -13,7 +13,7 @@ export async function cmdSend(
13
13
  targetKey: string | undefined,
14
14
  type: string | undefined,
15
15
  payloadStr: string | undefined
16
- ): Promise<never> {
16
+ ): Promise<any> {
17
17
  if (!targetKey || !type || !payloadStr) {
18
18
  return fail('Usage: send <identityKey> <type> <json_payload>');
19
19
  }
@@ -3,19 +3,28 @@
3
3
  * All CLI output follows the { success, data/error } wrapper format.
4
4
  */
5
5
 
6
+ // Global flag to prevent exit when used as a library
7
+ let noExitFlag = false;
8
+
9
+ export function setNoExit(value: boolean) {
10
+ noExitFlag = value;
11
+ }
12
+
6
13
  /**
7
- * Output a successful result and exit.
14
+ * Output a successful result and exit (unless noExit is set).
8
15
  */
9
- export function ok<T>(data: T): never {
16
+ export function ok<T>(data: T): any {
17
+ if (noExitFlag) return { success: true, data };
10
18
  console.log(JSON.stringify({ success: true, data }));
11
19
  process.exit(0);
12
20
  }
13
21
 
14
22
  /**
15
- * Output an error and exit.
23
+ * Output an error and exit (unless noExit is set).
16
24
  */
17
- export function fail(error: string | Error): never {
25
+ export function fail(error: string | Error): any {
18
26
  const message = error instanceof Error ? error.message : String(error);
27
+ if (noExitFlag) return { success: false, error: message };
19
28
  console.log(JSON.stringify({ success: false, error: message }));
20
29
  process.exit(1);
21
30
  }
@@ -14,7 +14,7 @@ import { ok, fail } from '../output.js';
14
14
  * Advertise a SHIP record.
15
15
  * Announce that you host a specific Topic Manager (tm_).
16
16
  */
17
- export async function cmdAdvertiseSHIP(domain?: string, topic?: string): Promise<never> {
17
+ export async function cmdAdvertiseSHIP(domain?: string, topic?: string): Promise<any> {
18
18
  if (!domain || !topic) {
19
19
  return fail('Usage: advertise-ship <domain> <topic>');
20
20
  }
@@ -65,7 +65,7 @@ export async function cmdAdvertiseSHIP(domain?: string, topic?: string): Promise
65
65
  * Advertise a SLAP record.
66
66
  * Announce that you host a specific Lookup Service (ls_).
67
67
  */
68
- export async function cmdAdvertiseSLAP(domain?: string, service?: string): Promise<never> {
68
+ export async function cmdAdvertiseSLAP(domain?: string, service?: string): Promise<any> {
69
69
  if (!domain || !service) {
70
70
  return fail('Usage: advertise-slap <domain> <service>');
71
71
  }
@@ -9,7 +9,7 @@ import { lookupOverlay, parseOverlayOutput } from './transaction.js';
9
9
  /**
10
10
  * Discover command: query the overlay for agents and services.
11
11
  */
12
- export async function cmdDiscover(args: string[]): Promise<never> {
12
+ export async function cmdDiscover(args: string[]): Promise<any> {
13
13
 
14
14
  // Parse flags
15
15
  let serviceFilter: string | null = null;
@@ -26,7 +26,7 @@ async function getBSVAgentWallet(): Promise<typeof BSVAgentWallet> {
26
26
  /**
27
27
  * Register command: register this agent on the overlay network.
28
28
  */
29
- export async function cmdRegister(): Promise<never> {
29
+ export async function cmdRegister(): Promise<any> {
30
30
  if (!fs.existsSync(PATHS.walletIdentity)) {
31
31
  return fail('Wallet not initialized. Run: setup');
32
32
  }
@@ -135,7 +135,7 @@ export async function cmdRegister(): Promise<never> {
135
135
  /**
136
136
  * Unregister command: submit revocation tx to remove agent from overlay network.
137
137
  */
138
- export async function cmdUnregister(): Promise<never> {
138
+ export async function cmdUnregister(): Promise<any> {
139
139
 
140
140
  const wallet = await BSVAgentWallet.load({ network: NETWORK, storageDir: WALLET_DIR });
141
141
  const { outputs, BEEF } = await wallet._setup.wallet.listOutputs({ basket: TOPICS.IDENTITY, include: 'entire transactions' });
@@ -27,7 +27,7 @@ async function getBSVAgentWallet(): Promise<typeof BSVAgentWallet> {
27
27
  /**
28
28
  * Services command: list currently advertised services.
29
29
  */
30
- export async function cmdServices(): Promise<never> {
30
+ export async function cmdServices(): Promise<any> {
31
31
  const services = loadServices();
32
32
  return ok({ services, count: services.length });
33
33
  }
@@ -40,7 +40,7 @@ export async function cmdAdvertise(
40
40
  name: string | undefined,
41
41
  priceSatsStr: string | undefined,
42
42
  description?: string
43
- ): Promise<never> {
43
+ ): Promise<any> {
44
44
  if (!serviceId || !name || !priceSatsStr) {
45
45
  return fail('Usage: advertise <serviceId> <name> <priceSats> [description]');
46
46
  }
@@ -108,7 +108,7 @@ export async function cmdAdvertise(
108
108
  /**
109
109
  * Remove command: remove a service from local registry.
110
110
  */
111
- export async function cmdRemove(serviceId: string | undefined): Promise<never> {
111
+ export async function cmdRemove(serviceId: string | undefined): Promise<any> {
112
112
  if (!serviceId) {
113
113
  return fail('Usage: remove <serviceId>');
114
114
  }
@@ -137,7 +137,7 @@ export async function cmdReadvertise(
137
137
  name?: string,
138
138
  priceSatsStr?: string,
139
139
  description?: string
140
- ): Promise<never> {
140
+ ): Promise<any> {
141
141
  if (!serviceId) {
142
142
  return fail('Usage: readvertise <serviceId> [name] [priceSats] [description]');
143
143
  }
@@ -19,7 +19,7 @@ export async function cmdPay(
19
19
  pubkey: string | undefined,
20
20
  satoshis: string | undefined,
21
21
  description?: string
22
- ): Promise<never> {
22
+ ): Promise<any> {
23
23
  if (!pubkey || !satoshis) {
24
24
  return fail('Usage: pay <pubkey> <satoshis> [description]');
25
25
  }
@@ -40,7 +40,7 @@ export async function cmdPay(
40
40
  /**
41
41
  * Verify command: verify an incoming payment BEEF.
42
42
  */
43
- export async function cmdVerify(beefBase64: string | undefined): Promise<never> {
43
+ export async function cmdVerify(beefBase64: string | undefined): Promise<any> {
44
44
  if (!beefBase64) {
45
45
  return fail('Usage: verify <beef_base64>');
46
46
  }
@@ -67,7 +67,7 @@ export async function cmdAccept(
67
67
  derivationSuffix: string | undefined,
68
68
  senderIdentityKey: string | undefined,
69
69
  description?: string
70
- ): Promise<never> {
70
+ ): Promise<any> {
71
71
  if (!beef || !derivationPrefix || !derivationSuffix || !senderIdentityKey) {
72
72
  return fail('Usage: accept <beef> <prefix> <suffix> <senderKey> [description]');
73
73
  }
@@ -10,7 +10,7 @@ import { readJsonl } from '../utils/storage.js';
10
10
  /**
11
11
  * Service queue command: list pending service requests.
12
12
  */
13
- export async function cmdServiceQueue(): Promise<never> {
13
+ export async function cmdServiceQueue(): Promise<any> {
14
14
  if (!fs.existsSync(PATHS.serviceQueue)) {
15
15
  return ok({ pending: [], count: 0 });
16
16
  }
@@ -24,7 +24,7 @@ export async function cmdServiceQueue(): Promise<never> {
24
24
  /**
25
25
  * Research queue command: list pending research requests.
26
26
  */
27
- export async function cmdResearchQueue(): Promise<never> {
27
+ export async function cmdResearchQueue(): Promise<any> {
28
28
  if (!fs.existsSync(PATHS.researchQueue)) {
29
29
  return ok({ pending: [] });
30
30
  }
@@ -15,7 +15,7 @@ export async function cmdRequestService(
15
15
  serviceId: string | undefined,
16
16
  satsStr?: string,
17
17
  inputJsonStr?: string
18
- ): Promise<never> {
18
+ ): Promise<any> {
19
19
  if (!targetKey || !serviceId) {
20
20
  return fail('Usage: request-service <identityKey> <serviceId> [sats] [inputJson]');
21
21
  }
@@ -16,7 +16,7 @@ export async function cmdRespondService(
16
16
  recipientKey: string | undefined,
17
17
  serviceId: string | undefined,
18
18
  resultJson: string | undefined
19
- ): Promise<never> {
19
+ ): Promise<any> {
20
20
  if (!requestId || !recipientKey || !serviceId || !resultJson) {
21
21
  return fail('Usage: respond-service <requestId> <recipientKey> <serviceId> <resultJson>');
22
22
  }
@@ -93,7 +93,7 @@ export async function cmdRespondService(
93
93
  /**
94
94
  * Respond to a research request with results.
95
95
  */
96
- export async function cmdResearchRespond(resultJsonPath: string | undefined): Promise<never> {
96
+ export async function cmdResearchRespond(resultJsonPath: string | undefined): Promise<any> {
97
97
  if (!resultJsonPath) return fail('Usage: research-respond <resultJsonFile>');
98
98
  if (!fs.existsSync(resultJsonPath)) return fail(`File not found: ${resultJsonPath}`);
99
99
 
@@ -59,7 +59,7 @@ function sleep(ms: number): Promise<void> {
59
59
  /**
60
60
  * Balance command: show wallet balance.
61
61
  */
62
- export async function cmdBalance(): Promise<never> {
62
+ export async function cmdBalance(): Promise<any> {
63
63
  const BSVAgentWallet = await getBSVAgentWallet();
64
64
  const sdk = await getSdk();
65
65
 
@@ -80,7 +80,7 @@ export async function cmdBalance(): Promise<never> {
80
80
  * If the transaction isn't yet on WoC (just broadcast), it will poll
81
81
  * with exponential backoff for up to 60 seconds.
82
82
  */
83
- export async function cmdImport(txidArg: string | undefined, voutStr?: string): Promise<never> {
83
+ export async function cmdImport(txidArg: string | undefined, voutStr?: string): Promise<any> {
84
84
  if (!txidArg) {
85
85
  return fail('Usage: import <txid> [vout]');
86
86
  }
@@ -49,7 +49,7 @@ async function getSdk(): Promise<any> {
49
49
  /**
50
50
  * Setup command: create wallet and show identity.
51
51
  */
52
- export async function cmdSetup(): Promise<never> {
52
+ export async function cmdSetup(): Promise<any> {
53
53
  const BSVAgentWallet = await getBSVAgentWallet();
54
54
 
55
55
  if (fs.existsSync(PATHS.walletIdentity)) {
@@ -88,7 +88,7 @@ export async function cmdSetup(): Promise<never> {
88
88
  /**
89
89
  * Identity command: show identity public key.
90
90
  */
91
- export async function cmdIdentity(): Promise<never> {
91
+ export async function cmdIdentity(): Promise<any> {
92
92
  const BSVAgentWallet = await getBSVAgentWallet();
93
93
  const wallet = await BSVAgentWallet.load({ network: NETWORK, storageDir: WALLET_DIR });
94
94
  const identityKey = await wallet.getIdentityKey();
@@ -100,7 +100,7 @@ export async function cmdIdentity(): Promise<never> {
100
100
  /**
101
101
  * Status command: show identity and balance.
102
102
  */
103
- export async function cmdStatus(): Promise<never> {
103
+ export async function cmdStatus(): Promise<any> {
104
104
  const BSVAgentWallet = await getBSVAgentWallet();
105
105
  const wallet = await BSVAgentWallet.load({ network: NETWORK, storageDir: WALLET_DIR });
106
106
  const identityKey = await wallet.getIdentityKey();
@@ -116,7 +116,7 @@ export async function cmdStatus(): Promise<never> {
116
116
  /**
117
117
  * Address command: show P2PKH receive address.
118
118
  */
119
- export async function cmdAddress(): Promise<never> {
119
+ export async function cmdAddress(): Promise<any> {
120
120
  if (!fs.existsSync(PATHS.walletIdentity)) {
121
121
  return fail('Wallet not initialized. Run: setup');
122
122
  }
@@ -47,7 +47,7 @@ async function getSdk(): Promise<any> {
47
47
  /**
48
48
  * Start X verification: generate a tweet with identity key and signature.
49
49
  */
50
- export async function cmdXVerifyStart(handleArg: string | undefined): Promise<never> {
50
+ export async function cmdXVerifyStart(handleArg: string | undefined): Promise<any> {
51
51
  if (!handleArg) {
52
52
  return fail('Usage: x-verify-start <@handle>');
53
53
  }
@@ -90,7 +90,7 @@ export async function cmdXVerifyStart(handleArg: string | undefined): Promise<ne
90
90
  /**
91
91
  * Complete X verification by checking the posted tweet.
92
92
  */
93
- export async function cmdXVerifyComplete(tweetUrl: string | undefined): Promise<never> {
93
+ export async function cmdXVerifyComplete(tweetUrl: string | undefined): Promise<any> {
94
94
  if (!tweetUrl) return fail('Usage: x-verify-complete <tweet-url>');
95
95
 
96
96
  // Load pending verification
@@ -187,7 +187,7 @@ export async function cmdXVerifyComplete(tweetUrl: string | undefined): Promise<
187
187
  /**
188
188
  * List verified X accounts (local cache).
189
189
  */
190
- export async function cmdXVerifications(): Promise<never> {
190
+ export async function cmdXVerifications(): Promise<any> {
191
191
  const verifications = loadXVerifications();
192
192
  return ok({ verifications, count: verifications.length });
193
193
  }
@@ -195,7 +195,7 @@ export async function cmdXVerifications(): Promise<never> {
195
195
  /**
196
196
  * Lookup X verifications from the overlay network.
197
197
  */
198
- export async function cmdXLookup(query: string | undefined): Promise<never> {
198
+ export async function cmdXLookup(query: string | undefined): Promise<any> {
199
199
  try {
200
200
  const lookupQuery = query
201
201
  ? (query.startsWith('@') ? { xHandle: query } : { identityKey: query })
@@ -211,7 +211,7 @@ export async function cmdXLookup(query: string | undefined): Promise<never> {
211
211
  /**
212
212
  * List pending X engagement requests.
213
213
  */
214
- export async function cmdXEngagementQueue(): Promise<never> {
214
+ export async function cmdXEngagementQueue(): Promise<any> {
215
215
  if (!fs.existsSync(PATHS.xEngagementQueue)) {
216
216
  return ok({ queue: [], count: 0 });
217
217
  }
@@ -227,7 +227,7 @@ export async function cmdXEngagementQueue(): Promise<never> {
227
227
  export async function cmdXEngagementFulfill(
228
228
  requestId: string | undefined,
229
229
  proofUrl?: string
230
- ): Promise<never> {
230
+ ): Promise<any> {
231
231
  if (!requestId) return fail('Usage: x-engagement-fulfill <requestId> [proofUrl]');
232
232
 
233
233
  if (!fs.existsSync(PATHS.xEngagementQueue)) {