@johngalt5/bsv-overlay 0.2.12 → 0.2.13

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 (2) hide show
  1. package/index.ts +72 -10
  2. package/package.json +1 -1
package/index.ts CHANGED
@@ -42,6 +42,14 @@ function loadDailySpending(walletDir: string): DailySpending {
42
42
  return { date: today, totalSats: 0, transactions: [] };
43
43
  }
44
44
 
45
+ function writeActivityEvent(event) {
46
+ const alertDir = path.join(process.env.HOME || '', '.clawdbot', 'bsv-overlay');
47
+ try {
48
+ fs.mkdirSync(alertDir, { recursive: true });
49
+ fs.appendFileSync(path.join(alertDir, 'activity-feed.jsonl'), JSON.stringify({ ...event, ts: Date.now() }) + '\n');
50
+ } catch {}
51
+ }
52
+
45
53
  function recordSpend(walletDir: string, sats: number, service: string, provider: string) {
46
54
  const spending = loadDailySpending(walletDir);
47
55
  spending.totalSats += sats;
@@ -132,6 +140,33 @@ function stopAutoImport() {
132
140
  }
133
141
  }
134
142
 
143
+ // Categorize WebSocket events into notification types
144
+ function categorizeEvent(event) {
145
+ const base = { ts: Date.now(), from: event.from?.slice(0, 16), fullFrom: event.from };
146
+
147
+ // 💰 Incoming payment — someone paid us for a service
148
+ if (event.action === 'queued-for-agent' && event.satoshisReceived) {
149
+ return { ...base, type: 'incoming_payment', emoji: '💰', serviceId: event.serviceId, sats: event.satoshisReceived, requestId: event.id, message: `Received ${event.satoshisReceived} sats for ${event.serviceId}` };
150
+ }
151
+ if (event.action === 'fulfilled' && event.satoshisReceived) {
152
+ return { ...base, type: 'incoming_payment', emoji: '💰', serviceId: event.serviceId, sats: event.satoshisReceived, message: `Received ${event.satoshisReceived} sats for ${event.serviceId} (auto-fulfilled)` };
153
+ }
154
+
155
+ // 📬 Response received — a service we requested came back
156
+ if (event.type === 'service-response' && event.action === 'received') {
157
+ const payload = event.payload || {};
158
+ return { ...base, type: 'response_received', emoji: '📬', serviceId: payload.serviceId, status: payload.status, message: `Response received for ${payload.serviceId}: ${payload.status}` };
159
+ }
160
+
161
+ // ❌ Request rejected
162
+ if (event.action === 'rejected' && event.serviceId) {
163
+ return { ...base, type: 'request_rejected', emoji: '❌', serviceId: event.serviceId, reason: event.reason, message: `Rejected ${event.serviceId} request: ${event.reason}` };
164
+ }
165
+
166
+ // Skip pings/pongs and other noise
167
+ return null;
168
+ }
169
+
135
170
  function startBackgroundService(env, cliPath, logger) {
136
171
  if (backgroundProcess) return;
137
172
  serviceRunning = true;
@@ -153,16 +188,14 @@ function startBackgroundService(env, cliPath, logger) {
153
188
  const event = JSON.parse(line);
154
189
  logger?.debug?.(`[bsv-overlay] ${event.event || event.type || 'message'}:`, JSON.stringify(event).slice(0, 200));
155
190
 
156
- // Detect queued-for-agent events and wake the agent immediately
191
+ const alertDir = path.join(process.env.HOME || '', '.clawdbot', 'bsv-overlay');
192
+ fs.mkdirSync(alertDir, { recursive: true });
193
+
194
+ // Detect queued-for-agent events — write fulfillment alert
157
195
  if (event.action === 'queued-for-agent' && event.serviceId) {
158
- logger?.info?.(`[bsv-overlay] ⚡ Incoming ${event.serviceId} request from ${event.from?.slice(0, 12)}... — waking agent`);
159
-
160
- // Write alert file for the cron-based fulfillment checker to pick up
161
- const alertDir = path.join(process.env.HOME || '', '.clawdbot', 'bsv-overlay');
162
- const alertPath = path.join(alertDir, 'pending-alert.jsonl');
196
+ logger?.info?.(`[bsv-overlay] ⚡ Incoming ${event.serviceId} request from ${event.from?.slice(0, 12)}...`);
163
197
  try {
164
- fs.mkdirSync(alertDir, { recursive: true });
165
- fs.appendFileSync(alertPath, JSON.stringify({
198
+ fs.appendFileSync(path.join(alertDir, 'pending-alert.jsonl'), JSON.stringify({
166
199
  requestId: event.id,
167
200
  serviceId: event.serviceId,
168
201
  from: event.from,
@@ -171,6 +204,14 @@ function startBackgroundService(env, cliPath, logger) {
171
204
  }) + '\n');
172
205
  } catch {}
173
206
  }
207
+
208
+ // Write payment/activity notifications for ALL significant events
209
+ const notifEvent = categorizeEvent(event);
210
+ if (notifEvent) {
211
+ try {
212
+ fs.appendFileSync(path.join(alertDir, 'activity-feed.jsonl'), JSON.stringify(notifEvent) + '\n');
213
+ } catch {}
214
+ }
174
215
  } catch {}
175
216
  }
176
217
  });
@@ -601,6 +642,9 @@ async function executeOverlayAction(params, config, api) {
601
642
  case "pending-requests":
602
643
  return await handlePendingRequests(env, cliPath);
603
644
 
645
+ case "activity":
646
+ return handleActivity();
647
+
604
648
  case "fulfill":
605
649
  return await handleFulfill(params, env, cliPath);
606
650
 
@@ -698,8 +742,9 @@ async function handleServiceRequest(params, env, cliPath, config, api) {
698
742
  for (const msg of messages) {
699
743
  if (msg.type === 'service-response' && msg.from === bestProvider.identityKey) {
700
744
  api.logger.info(`Received response from ${bestProvider.agentName}`);
701
- // Record the spending
702
745
  recordSpend(walletDir, price, service, bestProvider.agentName);
746
+ writeActivityEvent({ type: 'outgoing_payment', emoji: '💸', sats: price, service, provider: bestProvider.agentName, message: `Paid ${price} sats to ${bestProvider.agentName} for ${service}` });
747
+ writeActivityEvent({ type: 'response_received', emoji: '📬', service, provider: bestProvider.agentName, status: msg.payload?.status, message: `${service} response received from ${bestProvider.agentName}` });
703
748
  return {
704
749
  provider: bestProvider.agentName,
705
750
  cost: price,
@@ -715,8 +760,8 @@ async function handleServiceRequest(params, env, cliPath, config, api) {
715
760
  }
716
761
 
717
762
  // Don't throw — the response may still arrive via WebSocket
718
- // Record the spend since payment was already sent
719
763
  recordSpend(walletDir, price, service, bestProvider.agentName);
764
+ writeActivityEvent({ type: 'outgoing_payment', emoji: '💸', sats: price, service, provider: bestProvider.agentName, message: `Paid ${price} sats to ${bestProvider.agentName} for ${service} (awaiting response)` });
720
765
  return {
721
766
  provider: bestProvider.agentName,
722
767
  cost: price,
@@ -812,6 +857,7 @@ async function handleDirectPay(params, env, cliPath, config) {
812
857
 
813
858
  // Record the spending
814
859
  recordSpend(walletDir, sats, 'direct-payment', identityKey);
860
+ writeActivityEvent({ type: 'outgoing_payment', emoji: '💸', sats, service: 'direct-payment', provider: identityKey?.slice(0, 16), message: `Direct payment: ${sats} sats sent` });
815
861
 
816
862
  return output.data;
817
863
  }
@@ -1080,6 +1126,19 @@ async function handlePendingRequests(env, cliPath) {
1080
1126
  return output.data;
1081
1127
  }
1082
1128
 
1129
+ function handleActivity() {
1130
+ const feedPath = path.join(process.env.HOME || '', '.clawdbot', 'bsv-overlay', 'activity-feed.jsonl');
1131
+ if (!fs.existsSync(feedPath)) return { events: [], count: 0 };
1132
+
1133
+ const lines = fs.readFileSync(feedPath, 'utf-8').trim().split('\n').filter(Boolean);
1134
+ const events = lines.map(l => { try { return JSON.parse(l); } catch { return null; } }).filter(Boolean);
1135
+
1136
+ // Clear the feed after reading
1137
+ fs.writeFileSync(feedPath, '');
1138
+
1139
+ return { events, count: events.length };
1140
+ }
1141
+
1083
1142
  async function handleFulfill(params, env, cliPath) {
1084
1143
  const { requestId, recipientKey, serviceId, result } = params;
1085
1144
  if (!requestId || !recipientKey || !serviceId || !result) {
@@ -1091,6 +1150,9 @@ async function handleFulfill(params, env, cliPath) {
1091
1150
  ], { env });
1092
1151
  const output = parseCliOutput(cliResult.stdout);
1093
1152
  if (!output.success) throw new Error(`Fulfill failed: ${output.error}`);
1153
+
1154
+ writeActivityEvent({ type: 'service_fulfilled', emoji: '✅', serviceId, recipientKey: recipientKey?.slice(0, 16), message: `Fulfilled ${serviceId} request — response sent` });
1155
+
1094
1156
  return output.data;
1095
1157
  }
1096
1158
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@johngalt5/bsv-overlay",
3
- "version": "0.2.12",
3
+ "version": "0.2.13",
4
4
  "description": "Clawdbot BSV Overlay — agent discovery, service marketplace, and micropayments on the BSV blockchain",
5
5
  "type": "module",
6
6
  "files": [