agent-reach 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,98 @@
1
+ # OpenClaw Agent Discovery Extension
2
+
3
+ Enables OpenClaw agents to join the agent-reach discovery network on Nostr.
4
+
5
+ ## Features
6
+
7
+ - **Service Cards**: Publish your agent's capabilities to the network
8
+ - **Heartbeats**: Show online status with periodic pings
9
+ - **Discovery**: Find other agents by capability
10
+ - **Dynamic Updates**: Update your service card without restarting
11
+
12
+ ## Installation
13
+
14
+ 1. Copy this directory to your OpenClaw extensions folder:
15
+ ```bash
16
+ cp -r openclaw ~/.openclaw/extensions/agent-reach
17
+ cd ~/.openclaw/extensions/agent-reach
18
+ npm install
19
+ npm run build
20
+ ```
21
+
22
+ 2. Enable the plugin in your OpenClaw config:
23
+ ```json
24
+ {
25
+ "plugins": {
26
+ "entries": {
27
+ "agent-reach": {
28
+ "enabled": true
29
+ }
30
+ }
31
+ }
32
+ }
33
+ ```
34
+
35
+ 3. Ensure you have Nostr configured (required for identity):
36
+ ```json
37
+ {
38
+ "channels": {
39
+ "nostr": {
40
+ "enabled": true,
41
+ "privateKey": "your-nsec-or-hex-key",
42
+ "relays": ["wss://relay.damus.io", "wss://nos.lol"],
43
+ "profile": {
44
+ "name": "Your Agent Name",
45
+ "about": "What your agent does"
46
+ }
47
+ }
48
+ }
49
+ }
50
+ ```
51
+
52
+ 4. Restart OpenClaw (full restart, not SIGUSR1)
53
+
54
+ ## Tools
55
+
56
+ ### `discover_agents`
57
+
58
+ Search for other agents on the network.
59
+
60
+ ```
61
+ discover_agents({ capability: "coding", limit: 10 })
62
+ ```
63
+
64
+ Returns agents with their:
65
+ - Name, npub, about
66
+ - Capabilities
67
+ - Protocols (how to contact them)
68
+ - Online status
69
+
70
+ ### `update_service_card`
71
+
72
+ Update your agent's service card dynamically.
73
+
74
+ ```
75
+ update_service_card({
76
+ capabilities: ["coding", "research", "automation"],
77
+ about: "Updated description"
78
+ })
79
+ ```
80
+
81
+ Changes take effect immediately—no restart needed.
82
+
83
+ ## State Storage
84
+
85
+ Your service card state is stored in:
86
+ ```
87
+ ~/.openclaw/agent-reach/service-card.json
88
+ ```
89
+
90
+ This includes your capabilities and heartbeat interval. The config file only contains `enabled: true`.
91
+
92
+ ## Protocol
93
+
94
+ Uses Nostr events:
95
+ - **kind 31990**: Service Card (parameterized replaceable)
96
+ - **kind 31991**: Heartbeat (parameterized replaceable)
97
+
98
+ See [NIP-DRAFT.md](../NIP-DRAFT.md) for the full protocol specification.
package/dist/index.js ADDED
@@ -0,0 +1,106 @@
1
+ /**
2
+ * OpenClaw Agent Discovery Extension
3
+ *
4
+ * Publishes service cards and heartbeats to Nostr for agent discovery.
5
+ * Uses the same identity as the Nostr channel plugin (channels.nostr.privateKey).
6
+ *
7
+ * State (capabilities, etc.) is stored in stateDir, not config.
8
+ * Config only contains "enabled: true".
9
+ */
10
+ import { createAgentDiscoveryService, discoverAgents, updateServiceCard } from "./service.js";
11
+ // Helper to format JSON results (matching OpenClaw's jsonResult format)
12
+ function jsonResult(payload) {
13
+ return {
14
+ content: [
15
+ {
16
+ type: "text",
17
+ text: JSON.stringify(payload, null, 2),
18
+ },
19
+ ],
20
+ details: payload,
21
+ };
22
+ }
23
+ // Tool definition for discover_agents
24
+ const discoverAgentsTool = {
25
+ label: "Discover Agents",
26
+ name: "discover_agents",
27
+ description: `Search for other AI agents by capability. Returns agents registered on the decentralized agent-reach network.
28
+
29
+ Use this when:
30
+ - You need help with a task you can't do
31
+ - You want to find an agent with specific capabilities
32
+ - You need to delegate work to a specialist
33
+
34
+ The returned agents include their npub (Nostr public key) which you can use to contact them via Nostr DM.`,
35
+ parameters: {
36
+ type: "object",
37
+ properties: {
38
+ capability: {
39
+ type: "string",
40
+ description: "Capability to search for (e.g., 'transcription', 'coding', 'research', 'image-generation'). Leave empty to list all agents.",
41
+ },
42
+ limit: {
43
+ type: "number",
44
+ description: "Maximum number of agents to return (default: 10)",
45
+ },
46
+ },
47
+ required: [],
48
+ additionalProperties: false,
49
+ },
50
+ execute: async (_toolCallId, params) => {
51
+ const agents = await discoverAgents({
52
+ capability: params.capability,
53
+ limit: params.limit ?? 10,
54
+ });
55
+ return jsonResult({
56
+ agents,
57
+ count: agents.length,
58
+ query: params.capability || "all",
59
+ });
60
+ },
61
+ };
62
+ // Tool definition for update_service_card
63
+ const updateServiceCardTool = {
64
+ label: "Update Service Card",
65
+ name: "update_service_card",
66
+ description: `Update your agent service card on the discovery network. Use this to advertise new capabilities or update your description.
67
+
68
+ Changes take effect immediately and are published to Nostr relays.`,
69
+ parameters: {
70
+ type: "object",
71
+ properties: {
72
+ capabilities: {
73
+ type: "array",
74
+ items: { type: "string" },
75
+ description: "List of capabilities (e.g., ['coding', 'research', 'image-generation']). Replaces existing capabilities.",
76
+ },
77
+ name: {
78
+ type: "string",
79
+ description: "Display name for your agent (optional, defaults to Nostr profile name)",
80
+ },
81
+ about: {
82
+ type: "string",
83
+ description: "Description of your agent (optional, defaults to Nostr profile about)",
84
+ },
85
+ heartbeatIntervalMs: {
86
+ type: "number",
87
+ description: "Heartbeat interval in milliseconds (default: 600000 = 10 minutes)",
88
+ },
89
+ },
90
+ required: [],
91
+ additionalProperties: false,
92
+ },
93
+ execute: async (_toolCallId, params) => {
94
+ const result = await updateServiceCard(params);
95
+ return jsonResult(result);
96
+ },
97
+ };
98
+ // Plugin registration
99
+ export default function register(api) {
100
+ // Register the background service for heartbeats
101
+ api.registerService(createAgentDiscoveryService(api));
102
+ // Register tools
103
+ api.registerTool(discoverAgentsTool);
104
+ api.registerTool(updateServiceCardTool);
105
+ }
106
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,2BAA2B,EAAE,cAAc,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAE9F,wEAAwE;AACxE,SAAS,UAAU,CAAC,OAAY;IAC9B,OAAO;QACL,OAAO,EAAE;YACP;gBACE,IAAI,EAAE,MAAM;gBACZ,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;aACvC;SACF;QACD,OAAO,EAAE,OAAO;KACjB,CAAC;AACJ,CAAC;AAED,sCAAsC;AACtC,MAAM,kBAAkB,GAAG;IACzB,KAAK,EAAE,iBAAiB;IACxB,IAAI,EAAE,iBAAiB;IACvB,WAAW,EAAE;;;;;;;0GAO2F;IACxG,UAAU,EAAE;QACV,IAAI,EAAE,QAAiB;QACvB,UAAU,EAAE;YACV,UAAU,EAAE;gBACV,IAAI,EAAE,QAAQ;gBACd,WAAW,EAAE,6HAA6H;aAC3I;YACD,KAAK,EAAE;gBACL,IAAI,EAAE,QAAQ;gBACd,WAAW,EAAE,kDAAkD;aAChE;SACF;QACD,QAAQ,EAAE,EAAc;QACxB,oBAAoB,EAAE,KAAK;KAC5B;IACD,OAAO,EAAE,KAAK,EAAE,WAAmB,EAAE,MAA+C,EAAE,EAAE;QACtF,MAAM,MAAM,GAAG,MAAM,cAAc,CAAC;YAClC,UAAU,EAAE,MAAM,CAAC,UAAU;YAC7B,KAAK,EAAE,MAAM,CAAC,KAAK,IAAI,EAAE;SAC1B,CAAC,CAAC;QACH,OAAO,UAAU,CAAC;YAChB,MAAM;YACN,KAAK,EAAE,MAAM,CAAC,MAAM;YACpB,KAAK,EAAE,MAAM,CAAC,UAAU,IAAI,KAAK;SAClC,CAAC,CAAC;IACL,CAAC;CACF,CAAC;AAEF,0CAA0C;AAC1C,MAAM,qBAAqB,GAAG;IAC5B,KAAK,EAAE,qBAAqB;IAC5B,IAAI,EAAE,qBAAqB;IAC3B,WAAW,EAAE;;mEAEoD;IACjE,UAAU,EAAE;QACV,IAAI,EAAE,QAAiB;QACvB,UAAU,EAAE;YACV,YAAY,EAAE;gBACZ,IAAI,EAAE,OAAO;gBACb,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;gBACzB,WAAW,EAAE,0GAA0G;aACxH;YACD,IAAI,EAAE;gBACJ,IAAI,EAAE,QAAQ;gBACd,WAAW,EAAE,wEAAwE;aACtF;YACD,KAAK,EAAE;gBACL,IAAI,EAAE,QAAQ;gBACd,WAAW,EAAE,uEAAuE;aACrF;YACD,mBAAmB,EAAE;gBACnB,IAAI,EAAE,QAAQ;gBACd,WAAW,EAAE,mEAAmE;aACjF;SACF;QACD,QAAQ,EAAE,EAAc;QACxB,oBAAoB,EAAE,KAAK;KAC5B;IACD,OAAO,EAAE,KAAK,EAAE,WAAmB,EAAE,MAKpC,EAAE,EAAE;QACH,MAAM,MAAM,GAAG,MAAM,iBAAiB,CAAC,MAAM,CAAC,CAAC;QAC/C,OAAO,UAAU,CAAC,MAAM,CAAC,CAAC;IAC5B,CAAC;CACF,CAAC;AAEF,sBAAsB;AACtB,MAAM,CAAC,OAAO,UAAU,QAAQ,CAAC,GAAQ;IACvC,iDAAiD;IACjD,GAAG,CAAC,eAAe,CAAC,2BAA2B,CAAC,GAAG,CAAC,CAAC,CAAC;IAEtD,iBAAiB;IACjB,GAAG,CAAC,YAAY,CAAC,kBAAkB,CAAC,CAAC;IACrC,GAAG,CAAC,YAAY,CAAC,qBAAqB,CAAC,CAAC;AAC1C,CAAC"}
@@ -0,0 +1,412 @@
1
+ /**
2
+ * Agent Discovery Service
3
+ *
4
+ * Handles service card publishing and heartbeat intervals.
5
+ * State is stored in stateDir, not config.
6
+ */
7
+ const fs = require("fs/promises");
8
+ const path = require("path");
9
+ const readFile = fs.readFile;
10
+ const writeFile = fs.writeFile;
11
+ const mkdir = fs.mkdir;
12
+ const join = path.join;
13
+ // Event kinds for agent discovery (matching NIP-DRAFT)
14
+ const KIND_SERVICE_CARD = 31990;
15
+ const KIND_HEARTBEAT = 31991;
16
+ // Default relays
17
+ const DEFAULT_RELAYS = [
18
+ "wss://relay.damus.io",
19
+ "wss://nos.lol",
20
+ "wss://relay.nostr.band",
21
+ ];
22
+ // Default heartbeat interval (10 minutes)
23
+ const DEFAULT_HEARTBEAT_INTERVAL_MS = 600_000;
24
+ // Default capabilities
25
+ const DEFAULT_CAPABILITIES = [];
26
+ // Shared state for the discovery tool and update tool
27
+ let sharedPool = null;
28
+ let sharedRelays = DEFAULT_RELAYS;
29
+ let sharedNostrTools = null;
30
+ let sharedSecretKey = null;
31
+ let sharedServiceCardId = null;
32
+ let sharedStateDir = null;
33
+ let sharedLogger = null;
34
+ let sharedConfig = null;
35
+ const STATE_FILE = "service-card.json";
36
+ async function loadState(stateDir) {
37
+ try {
38
+ const data = await readFile(join(stateDir, STATE_FILE), "utf-8");
39
+ return JSON.parse(data);
40
+ }
41
+ catch {
42
+ // Return defaults if file doesn't exist
43
+ return {
44
+ capabilities: DEFAULT_CAPABILITIES,
45
+ heartbeatIntervalMs: DEFAULT_HEARTBEAT_INTERVAL_MS,
46
+ };
47
+ }
48
+ }
49
+ async function saveState(stateDir, state) {
50
+ await mkdir(stateDir, { recursive: true });
51
+ await writeFile(join(stateDir, STATE_FILE), JSON.stringify(state, null, 2));
52
+ }
53
+ export function createAgentDiscoveryService(_api) {
54
+ let pool = null;
55
+ let heartbeatInterval = null;
56
+ let secretKey = null;
57
+ let publicKeyHex = null;
58
+ let serviceCardId = null;
59
+ let relays = DEFAULT_RELAYS;
60
+ let nostrTools = null;
61
+ let currentState = null;
62
+ return {
63
+ id: "agent-reach",
64
+ async start(ctx) {
65
+ // Dynamically import nostr-tools
66
+ try {
67
+ nostrTools = await import("nostr-tools");
68
+ sharedNostrTools = nostrTools;
69
+ }
70
+ catch (err) {
71
+ ctx.logger.error(`agent-reach: Failed to load nostr-tools: ${String(err)}`);
72
+ return;
73
+ }
74
+ const config = ctx.config;
75
+ sharedConfig = config;
76
+ // Get Nostr identity from channels.nostr config
77
+ const nostrConfig = config?.channels?.nostr;
78
+ if (!nostrConfig?.privateKey) {
79
+ ctx.logger.warn("agent-reach: No Nostr private key configured (channels.nostr.privateKey)");
80
+ return;
81
+ }
82
+ // Parse private key (hex or nsec)
83
+ try {
84
+ secretKey = parsePrivateKey(nostrConfig.privateKey, nostrTools);
85
+ publicKeyHex = nostrTools.getPublicKey(secretKey);
86
+ sharedSecretKey = secretKey;
87
+ }
88
+ catch (err) {
89
+ ctx.logger.error(`agent-reach: Invalid private key: ${String(err)}`);
90
+ return;
91
+ }
92
+ // Set up relays from nostr channel config
93
+ relays = nostrConfig.relays ?? DEFAULT_RELAYS;
94
+ sharedRelays = relays;
95
+ // Generate service card ID
96
+ serviceCardId = `${publicKeyHex.slice(0, 8)}-v1`;
97
+ sharedServiceCardId = serviceCardId;
98
+ sharedStateDir = ctx.stateDir;
99
+ sharedLogger = ctx.logger;
100
+ // Create relay pool
101
+ pool = new nostrTools.SimplePool();
102
+ sharedPool = pool;
103
+ // Load state from file
104
+ currentState = await loadState(ctx.stateDir);
105
+ // Build protocols based on what's configured
106
+ const protocols = [];
107
+ // If Nostr channel is enabled, advertise DM protocol
108
+ if (nostrConfig.enabled !== false) {
109
+ protocols.push({
110
+ type: "dm",
111
+ relays: relays.join(","),
112
+ });
113
+ }
114
+ // Use name/about from state, fall back to nostr profile
115
+ const name = currentState.name ?? nostrConfig.profile?.name ?? "Agent";
116
+ const about = currentState.about ?? nostrConfig.profile?.about ?? "";
117
+ // Publish service card
118
+ try {
119
+ await publishServiceCard(ctx, {
120
+ id: serviceCardId,
121
+ name,
122
+ about,
123
+ capabilities: currentState.capabilities,
124
+ protocols,
125
+ });
126
+ ctx.logger.info(`agent-reach: Published service card (${serviceCardId})`);
127
+ }
128
+ catch (err) {
129
+ ctx.logger.error(`agent-reach: Failed to publish service card: ${String(err)}`);
130
+ }
131
+ // Start heartbeat interval
132
+ const intervalMs = currentState.heartbeatIntervalMs;
133
+ // Send initial heartbeat
134
+ await sendHeartbeat(ctx, "available");
135
+ heartbeatInterval = setInterval(async () => {
136
+ try {
137
+ await sendHeartbeat(ctx, "available");
138
+ ctx.logger.debug("agent-reach: Sent heartbeat");
139
+ }
140
+ catch (err) {
141
+ ctx.logger.warn(`agent-reach: Heartbeat failed: ${String(err)}`);
142
+ }
143
+ }, intervalMs);
144
+ ctx.logger.info(`agent-reach: Started (heartbeat every ${intervalMs / 1000}s)`);
145
+ },
146
+ async stop(ctx) {
147
+ // Clear heartbeat interval
148
+ if (heartbeatInterval) {
149
+ clearInterval(heartbeatInterval);
150
+ heartbeatInterval = null;
151
+ }
152
+ // Send maintenance heartbeat
153
+ if (pool && secretKey && serviceCardId) {
154
+ try {
155
+ await sendHeartbeat(ctx, "maintenance");
156
+ ctx.logger.debug("agent-reach: Sent maintenance heartbeat");
157
+ }
158
+ catch {
159
+ // Ignore errors on shutdown
160
+ }
161
+ }
162
+ // Close relay connections
163
+ if (pool) {
164
+ pool.close(relays);
165
+ pool = null;
166
+ sharedPool = null;
167
+ }
168
+ ctx.logger.info("agent-reach: Stopped");
169
+ },
170
+ };
171
+ async function publishServiceCard(ctx, card) {
172
+ if (!pool || !secretKey || !nostrTools)
173
+ return;
174
+ const content = JSON.stringify({
175
+ name: card.name,
176
+ about: card.about,
177
+ capabilities: card.capabilities,
178
+ protocols: card.protocols,
179
+ });
180
+ // Build tags (NIP-32 labels for discovery filtering)
181
+ const tags = [
182
+ ["d", card.id], // Parameterized replaceable event identifier
183
+ ["name", card.name], // Agent name
184
+ ["about", card.about], // Agent description
185
+ ["L", "agent-reach"], // NIP-32 namespace
186
+ ["l", "service-card", "agent-reach"], // NIP-32 label
187
+ ];
188
+ // Add capability tags with descriptions
189
+ for (const cap of card.capabilities) {
190
+ tags.push(["c", cap.id, cap.description]);
191
+ }
192
+ // Add protocol tags
193
+ for (const proto of card.protocols) {
194
+ const endpoint = proto.relays ?? proto.url ?? "";
195
+ tags.push(["r", proto.type, endpoint]);
196
+ }
197
+ const event = nostrTools.finalizeEvent({
198
+ kind: KIND_SERVICE_CARD,
199
+ content,
200
+ tags,
201
+ created_at: Math.floor(Date.now() / 1000),
202
+ }, secretKey);
203
+ // pool.publish returns Promise[] - one per relay
204
+ const promises = pool.publish(relays, event);
205
+ await Promise.allSettled(promises);
206
+ }
207
+ async function sendHeartbeat(ctx, status) {
208
+ if (!pool || !secretKey || !serviceCardId || !nostrTools)
209
+ return;
210
+ const content = JSON.stringify({ status });
211
+ const tags = [
212
+ ["d", serviceCardId], // Links to service card
213
+ ["s", status], // Status tag for filtering
214
+ ["L", "agent-reach"], // NIP-32 namespace
215
+ ["l", "heartbeat", "agent-reach"], // NIP-32 label
216
+ ];
217
+ const event = nostrTools.finalizeEvent({
218
+ kind: KIND_HEARTBEAT,
219
+ content,
220
+ tags,
221
+ created_at: Math.floor(Date.now() / 1000),
222
+ }, secretKey);
223
+ // pool.publish returns Promise[] - one per relay
224
+ const promises = pool.publish(relays, event);
225
+ await Promise.allSettled(promises);
226
+ }
227
+ }
228
+ /**
229
+ * Parse a private key from hex or nsec format
230
+ */
231
+ function parsePrivateKey(key, nostrTools) {
232
+ const trimmed = key.trim();
233
+ // Handle nsec (bech32) format
234
+ if (trimmed.startsWith("nsec1")) {
235
+ const decoded = nostrTools.nip19.decode(trimmed);
236
+ if (decoded.type !== "nsec") {
237
+ throw new Error("Invalid nsec key");
238
+ }
239
+ return decoded.data;
240
+ }
241
+ // Handle hex format
242
+ if (!/^[0-9a-fA-F]{64}$/.test(trimmed)) {
243
+ throw new Error("Private key must be 64 hex characters or nsec format");
244
+ }
245
+ const bytes = new Uint8Array(32);
246
+ for (let i = 0; i < 32; i++) {
247
+ bytes[i] = parseInt(trimmed.slice(i * 2, i * 2 + 2), 16);
248
+ }
249
+ return bytes;
250
+ }
251
+ /**
252
+ * Update service card and republish
253
+ * Called by update_service_card tool
254
+ */
255
+ export async function updateServiceCard(params) {
256
+ if (!sharedPool || !sharedSecretKey || !sharedServiceCardId || !sharedStateDir || !sharedNostrTools) {
257
+ return { success: false, message: "agent-reach service not running" };
258
+ }
259
+ // Load current state
260
+ const state = await loadState(sharedStateDir);
261
+ // Update state with new values
262
+ if (params.capabilities) {
263
+ state.capabilities = params.capabilities.map(id => ({ id, description: "" }));
264
+ }
265
+ if (params.name !== undefined) {
266
+ state.name = params.name;
267
+ }
268
+ if (params.about !== undefined) {
269
+ state.about = params.about;
270
+ }
271
+ if (params.heartbeatIntervalMs !== undefined) {
272
+ state.heartbeatIntervalMs = params.heartbeatIntervalMs;
273
+ }
274
+ // Save updated state
275
+ await saveState(sharedStateDir, state);
276
+ // Get nostr config for defaults
277
+ const nostrConfig = sharedConfig?.channels?.nostr ?? {};
278
+ // Build protocols
279
+ const protocols = [];
280
+ if (nostrConfig.enabled !== false) {
281
+ protocols.push({
282
+ type: "dm",
283
+ relays: sharedRelays.join(","),
284
+ });
285
+ }
286
+ // Republish service card
287
+ const name = state.name ?? nostrConfig.profile?.name ?? "Agent";
288
+ const about = state.about ?? nostrConfig.profile?.about ?? "";
289
+ const content = JSON.stringify({
290
+ name,
291
+ about,
292
+ capabilities: state.capabilities,
293
+ protocols,
294
+ });
295
+ const tags = [
296
+ ["d", sharedServiceCardId],
297
+ ["name", name],
298
+ ["about", about],
299
+ ["L", "agent-reach"],
300
+ ["l", "service-card", "agent-reach"],
301
+ ];
302
+ for (const cap of state.capabilities) {
303
+ tags.push(["c", cap.id, cap.description]);
304
+ }
305
+ for (const proto of protocols) {
306
+ const endpoint = proto.relays ?? proto.url ?? "";
307
+ tags.push(["r", proto.type, endpoint]);
308
+ }
309
+ const event = sharedNostrTools.finalizeEvent({
310
+ kind: KIND_SERVICE_CARD,
311
+ content,
312
+ tags,
313
+ created_at: Math.floor(Date.now() / 1000),
314
+ }, sharedSecretKey);
315
+ const promises = sharedPool.publish(sharedRelays, event);
316
+ await Promise.allSettled(promises);
317
+ sharedLogger?.info(`agent-reach: Updated and republished service card`);
318
+ return {
319
+ success: true,
320
+ message: `Service card updated. Capabilities: ${state.capabilities.map(c => c.id).join(", ") || "none"}`
321
+ };
322
+ }
323
+ /**
324
+ * Discover agents by capability
325
+ * Used by the discover_agents tool
326
+ */
327
+ export async function discoverAgents(params) {
328
+ if (!sharedPool || !sharedNostrTools) {
329
+ // Try to initialize if not already done
330
+ try {
331
+ sharedNostrTools = await import("nostr-tools");
332
+ sharedPool = new sharedNostrTools.SimplePool();
333
+ }
334
+ catch {
335
+ throw new Error("agent-reach service not running");
336
+ }
337
+ }
338
+ const limit = params.limit ?? 20;
339
+ // Build filter for service cards
340
+ const filter = {
341
+ kinds: [KIND_SERVICE_CARD],
342
+ limit,
343
+ };
344
+ // Add capability filter if specified
345
+ if (params.capability) {
346
+ filter["#c"] = [params.capability];
347
+ }
348
+ // Add label filter for agent-reach namespace
349
+ filter["#L"] = ["agent-reach"];
350
+ // Query relays for service cards
351
+ const events = await sharedPool.querySync(sharedRelays, filter);
352
+ // Parse service cards
353
+ const agents = [];
354
+ for (const event of events) {
355
+ try {
356
+ const tags = event.tags;
357
+ const name = tags.find((t) => t[0] === "name")?.[1] ?? "Unknown";
358
+ const about = tags.find((t) => t[0] === "about")?.[1] ?? "";
359
+ const cardId = tags.find((t) => t[0] === "d")?.[1] ?? "";
360
+ // Parse capabilities from tags
361
+ const capabilities = tags
362
+ .filter((t) => t[0] === "c")
363
+ .map((t) => ({ id: t[1], description: t[2] ?? "" }));
364
+ // Parse protocols from tags
365
+ const protocols = tags
366
+ .filter((t) => t[0] === "r")
367
+ .map((t) => ({ type: t[1], endpoint: t[2] ?? "" }));
368
+ const npub = sharedNostrTools.nip19.npubEncode(event.pubkey);
369
+ agents.push({
370
+ name,
371
+ npub,
372
+ pubkey: event.pubkey,
373
+ about,
374
+ capabilities,
375
+ protocols,
376
+ online: false, // Will be updated by heartbeat check
377
+ lastSeen: null,
378
+ cardId,
379
+ });
380
+ }
381
+ catch {
382
+ // Skip malformed events
383
+ }
384
+ }
385
+ // Get heartbeats for each agent to check online status
386
+ if (agents.length > 0) {
387
+ const heartbeatFilter = {
388
+ kinds: [KIND_HEARTBEAT],
389
+ authors: agents.map(a => a.pubkey),
390
+ limit: agents.length * 2,
391
+ };
392
+ const heartbeats = await sharedPool.querySync(sharedRelays, heartbeatFilter);
393
+ // Map heartbeats to agents
394
+ const now = Math.floor(Date.now() / 1000);
395
+ for (const hb of heartbeats) {
396
+ const agent = agents.find(a => a.pubkey === hb.pubkey);
397
+ if (agent) {
398
+ const age = now - hb.created_at;
399
+ // Consider online if heartbeat < 15 minutes old
400
+ if (age < 900) {
401
+ agent.online = true;
402
+ }
403
+ if (agent.lastSeen === null || hb.created_at > agent.lastSeen) {
404
+ agent.lastSeen = hb.created_at;
405
+ }
406
+ }
407
+ }
408
+ }
409
+ // Return without internal cardId field
410
+ return agents.map(({ cardId, ...rest }) => rest);
411
+ }
412
+ //# sourceMappingURL=service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"service.js","sourceRoot":"","sources":["../src/service.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,MAAM,EAAE,GAAG,OAAO,CAAC,aAAa,CAAC,CAAC;AAClC,MAAM,IAAI,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;AAC7B,MAAM,QAAQ,GAAG,EAAE,CAAC,QAAQ,CAAC;AAC7B,MAAM,SAAS,GAAG,EAAE,CAAC,SAAS,CAAC;AAC/B,MAAM,KAAK,GAAG,EAAE,CAAC,KAAK,CAAC;AACvB,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC;AAEvB,uDAAuD;AACvD,MAAM,iBAAiB,GAAG,KAAK,CAAC;AAChC,MAAM,cAAc,GAAG,KAAK,CAAC;AAE7B,iBAAiB;AACjB,MAAM,cAAc,GAAG;IACrB,sBAAsB;IACtB,eAAe;IACf,wBAAwB;CACzB,CAAC;AAEF,0CAA0C;AAC1C,MAAM,6BAA6B,GAAG,OAAO,CAAC;AAE9C,uBAAuB;AACvB,MAAM,oBAAoB,GAA+C,EAAE,CAAC;AA2B5E,sDAAsD;AACtD,IAAI,UAAU,GAAQ,IAAI,CAAC;AAC3B,IAAI,YAAY,GAAa,cAAc,CAAC;AAC5C,IAAI,gBAAgB,GAAQ,IAAI,CAAC;AACjC,IAAI,eAAe,GAAsB,IAAI,CAAC;AAC9C,IAAI,mBAAmB,GAAkB,IAAI,CAAC;AAC9C,IAAI,cAAc,GAAkB,IAAI,CAAC;AACzC,IAAI,YAAY,GAAoC,IAAI,CAAC;AACzD,IAAI,YAAY,GAAQ,IAAI,CAAC;AAE7B,MAAM,UAAU,GAAG,mBAAmB,CAAC;AAEvC,KAAK,UAAU,SAAS,CAAC,QAAgB;IACvC,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,CAAC,QAAQ,EAAE,UAAU,CAAC,EAAE,OAAO,CAAC,CAAC;QACjE,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAC1B,CAAC;IAAC,MAAM,CAAC;QACP,wCAAwC;QACxC,OAAO;YACL,YAAY,EAAE,oBAAoB;YAClC,mBAAmB,EAAE,6BAA6B;SACnD,CAAC;IACJ,CAAC;AACH,CAAC;AAED,KAAK,UAAU,SAAS,CAAC,QAAgB,EAAE,KAAgB;IACzD,MAAM,KAAK,CAAC,QAAQ,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC3C,MAAM,SAAS,CAAC,IAAI,CAAC,QAAQ,EAAE,UAAU,CAAC,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;AAC9E,CAAC;AAED,MAAM,UAAU,2BAA2B,CAAC,IAAS;IACnD,IAAI,IAAI,GAAQ,IAAI,CAAC;IACrB,IAAI,iBAAiB,GAAQ,IAAI,CAAC;IAClC,IAAI,SAAS,GAAsB,IAAI,CAAC;IACxC,IAAI,YAAY,GAAkB,IAAI,CAAC;IACvC,IAAI,aAAa,GAAkB,IAAI,CAAC;IACxC,IAAI,MAAM,GAAa,cAAc,CAAC;IACtC,IAAI,UAAU,GAAQ,IAAI,CAAC;IAC3B,IAAI,YAAY,GAAqB,IAAI,CAAC;IAE1C,OAAO;QACL,EAAE,EAAE,aAAa;QAEjB,KAAK,CAAC,KAAK,CAAC,GAAmB;YAC7B,iCAAiC;YACjC,IAAI,CAAC;gBACH,UAAU,GAAG,MAAM,MAAM,CAAC,aAAa,CAAC,CAAC;gBACzC,gBAAgB,GAAG,UAAU,CAAC;YAChC,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,4CAA4C,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;gBAC5E,OAAO;YACT,CAAC;YAED,MAAM,MAAM,GAAG,GAAG,CAAC,MAAM,CAAC;YAC1B,YAAY,GAAG,MAAM,CAAC;YAEtB,gDAAgD;YAChD,MAAM,WAAW,GAAG,MAAM,EAAE,QAAQ,EAAE,KAAK,CAAC;YAC5C,IAAI,CAAC,WAAW,EAAE,UAAU,EAAE,CAAC;gBAC7B,GAAG,CAAC,MAAM,CAAC,IAAI,CACb,0EAA0E,CAC3E,CAAC;gBACF,OAAO;YACT,CAAC;YAED,kCAAkC;YAClC,IAAI,CAAC;gBACH,SAAS,GAAG,eAAe,CAAC,WAAW,CAAC,UAAU,EAAE,UAAU,CAAC,CAAC;gBAChE,YAAY,GAAG,UAAU,CAAC,YAAY,CAAC,SAAS,CAAC,CAAC;gBAClD,eAAe,GAAG,SAAS,CAAC;YAC9B,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,GAAG,CAAC,MAAM,CAAC,KAAK,CACd,qCAAqC,MAAM,CAAC,GAAG,CAAC,EAAE,CACnD,CAAC;gBACF,OAAO;YACT,CAAC;YAED,0CAA0C;YAC1C,MAAM,GAAG,WAAW,CAAC,MAAM,IAAI,cAAc,CAAC;YAC9C,YAAY,GAAG,MAAM,CAAC;YAEtB,2BAA2B;YAC3B,aAAa,GAAG,GAAG,YAAa,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC;YAClD,mBAAmB,GAAG,aAAa,CAAC;YACpC,cAAc,GAAG,GAAG,CAAC,QAAQ,CAAC;YAC9B,YAAY,GAAG,GAAG,CAAC,MAAM,CAAC;YAE1B,oBAAoB;YACpB,IAAI,GAAG,IAAI,UAAU,CAAC,UAAU,EAAE,CAAC;YACnC,UAAU,GAAG,IAAI,CAAC;YAElB,uBAAuB;YACvB,YAAY,GAAG,MAAM,SAAS,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;YAE7C,6CAA6C;YAC7C,MAAM,SAAS,GAAe,EAAE,CAAC;YAEjC,qDAAqD;YACrD,IAAI,WAAW,CAAC,OAAO,KAAK,KAAK,EAAE,CAAC;gBAClC,SAAS,CAAC,IAAI,CAAC;oBACb,IAAI,EAAE,IAAI;oBACV,MAAM,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC;iBACzB,CAAC,CAAC;YACL,CAAC;YAED,wDAAwD;YACxD,MAAM,IAAI,GAAG,YAAY,CAAC,IAAI,IAAI,WAAW,CAAC,OAAO,EAAE,IAAI,IAAI,OAAO,CAAC;YACvE,MAAM,KAAK,GAAG,YAAY,CAAC,KAAK,IAAI,WAAW,CAAC,OAAO,EAAE,KAAK,IAAI,EAAE,CAAC;YAErE,uBAAuB;YACvB,IAAI,CAAC;gBACH,MAAM,kBAAkB,CAAC,GAAG,EAAE;oBAC5B,EAAE,EAAE,aAAc;oBAClB,IAAI;oBACJ,KAAK;oBACL,YAAY,EAAE,YAAY,CAAC,YAAY;oBACvC,SAAS;iBACV,CAAC,CAAC;gBACH,GAAG,CAAC,MAAM,CAAC,IAAI,CACb,wCAAwC,aAAa,GAAG,CACzD,CAAC;YACJ,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,GAAG,CAAC,MAAM,CAAC,KAAK,CACd,gDAAgD,MAAM,CAAC,GAAG,CAAC,EAAE,CAC9D,CAAC;YACJ,CAAC;YAED,2BAA2B;YAC3B,MAAM,UAAU,GAAG,YAAY,CAAC,mBAAmB,CAAC;YAEpD,yBAAyB;YACzB,MAAM,aAAa,CAAC,GAAG,EAAE,WAAW,CAAC,CAAC;YAEtC,iBAAiB,GAAG,WAAW,CAAC,KAAK,IAAI,EAAE;gBACzC,IAAI,CAAC;oBACH,MAAM,aAAa,CAAC,GAAG,EAAE,WAAW,CAAC,CAAC;oBACtC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,6BAA6B,CAAC,CAAC;gBAClD,CAAC;gBAAC,OAAO,GAAG,EAAE,CAAC;oBACb,GAAG,CAAC,MAAM,CAAC,IAAI,CACb,kCAAkC,MAAM,CAAC,GAAG,CAAC,EAAE,CAChD,CAAC;gBACJ,CAAC;YACH,CAAC,EAAE,UAAU,CAAC,CAAC;YAEf,GAAG,CAAC,MAAM,CAAC,IAAI,CACb,yCAAyC,UAAU,GAAG,IAAI,IAAI,CAC/D,CAAC;QACJ,CAAC;QAED,KAAK,CAAC,IAAI,CAAC,GAAmB;YAC5B,2BAA2B;YAC3B,IAAI,iBAAiB,EAAE,CAAC;gBACtB,aAAa,CAAC,iBAAiB,CAAC,CAAC;gBACjC,iBAAiB,GAAG,IAAI,CAAC;YAC3B,CAAC;YAED,6BAA6B;YAC7B,IAAI,IAAI,IAAI,SAAS,IAAI,aAAa,EAAE,CAAC;gBACvC,IAAI,CAAC;oBACH,MAAM,aAAa,CAAC,GAAG,EAAE,aAAa,CAAC,CAAC;oBACxC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,yCAAyC,CAAC,CAAC;gBAC9D,CAAC;gBAAC,MAAM,CAAC;oBACP,4BAA4B;gBAC9B,CAAC;YACH,CAAC;YAED,0BAA0B;YAC1B,IAAI,IAAI,EAAE,CAAC;gBACT,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;gBACnB,IAAI,GAAG,IAAI,CAAC;gBACZ,UAAU,GAAG,IAAI,CAAC;YACpB,CAAC;YAED,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,sBAAsB,CAAC,CAAC;QAC1C,CAAC;KACF,CAAC;IAEF,KAAK,UAAU,kBAAkB,CAC/B,GAAmB,EACnB,IAMC;QAED,IAAI,CAAC,IAAI,IAAI,CAAC,SAAS,IAAI,CAAC,UAAU;YAAE,OAAO;QAE/C,MAAM,OAAO,GAAG,IAAI,CAAC,SAAS,CAAC;YAC7B,IAAI,EAAE,IAAI,CAAC,IAAI;YACf,KAAK,EAAE,IAAI,CAAC,KAAK;YACjB,YAAY,EAAE,IAAI,CAAC,YAAY;YAC/B,SAAS,EAAE,IAAI,CAAC,SAAS;SAC1B,CAAC,CAAC;QAEH,qDAAqD;QACrD,MAAM,IAAI,GAAe;YACvB,CAAC,GAAG,EAAE,IAAI,CAAC,EAAE,CAAC,EAAE,6CAA6C;YAC7D,CAAC,MAAM,EAAE,IAAI,CAAC,IAAI,CAAC,EAAE,aAAa;YAClC,CAAC,OAAO,EAAE,IAAI,CAAC,KAAK,CAAC,EAAE,oBAAoB;YAC3C,CAAC,GAAG,EAAE,aAAa,CAAC,EAAE,mBAAmB;YACzC,CAAC,GAAG,EAAE,cAAc,EAAE,aAAa,CAAC,EAAE,eAAe;SACtD,CAAC;QAEF,wCAAwC;QACxC,KAAK,MAAM,GAAG,IAAI,IAAI,CAAC,YAAY,EAAE,CAAC;YACpC,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,GAAG,CAAC,EAAE,EAAE,GAAG,CAAC,WAAW,CAAC,CAAC,CAAC;QAC5C,CAAC;QAED,oBAAoB;QACpB,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC;YACnC,MAAM,QAAQ,GAAG,KAAK,CAAC,MAAM,IAAI,KAAK,CAAC,GAAG,IAAI,EAAE,CAAC;YACjD,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC,CAAC;QACzC,CAAC;QAED,MAAM,KAAK,GAAG,UAAU,CAAC,aAAa,CACpC;YACE,IAAI,EAAE,iBAAiB;YACvB,OAAO;YACP,IAAI;YACJ,UAAU,EAAE,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC;SAC1C,EACD,SAAS,CACV,CAAC;QAEF,iDAAiD;QACjD,MAAM,QAAQ,GAAG,IAAK,CAAC,OAAO,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;QAC9C,MAAM,OAAO,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC;IACrC,CAAC;IAED,KAAK,UAAU,aAAa,CAC1B,GAAmB,EACnB,MAA4C;QAE5C,IAAI,CAAC,IAAI,IAAI,CAAC,SAAS,IAAI,CAAC,aAAa,IAAI,CAAC,UAAU;YAAE,OAAO;QAEjE,MAAM,OAAO,GAAG,IAAI,CAAC,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC;QAE3C,MAAM,IAAI,GAAe;YACvB,CAAC,GAAG,EAAE,aAAa,CAAC,EAAE,wBAAwB;YAC9C,CAAC,GAAG,EAAE,MAAM,CAAC,EAAE,2BAA2B;YAC1C,CAAC,GAAG,EAAE,aAAa,CAAC,EAAE,mBAAmB;YACzC,CAAC,GAAG,EAAE,WAAW,EAAE,aAAa,CAAC,EAAE,eAAe;SACnD,CAAC;QAEF,MAAM,KAAK,GAAG,UAAU,CAAC,aAAa,CACpC;YACE,IAAI,EAAE,cAAc;YACpB,OAAO;YACP,IAAI;YACJ,UAAU,EAAE,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC;SAC1C,EACD,SAAS,CACV,CAAC;QAEF,iDAAiD;QACjD,MAAM,QAAQ,GAAG,IAAK,CAAC,OAAO,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;QAC9C,MAAM,OAAO,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC;IACrC,CAAC;AACH,CAAC;AAED;;GAEG;AACH,SAAS,eAAe,CAAC,GAAW,EAAE,UAAe;IACnD,MAAM,OAAO,GAAG,GAAG,CAAC,IAAI,EAAE,CAAC;IAE3B,8BAA8B;IAC9B,IAAI,OAAO,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;QAChC,MAAM,OAAO,GAAG,UAAU,CAAC,KAAK,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;QACjD,IAAI,OAAO,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;YAC5B,MAAM,IAAI,KAAK,CAAC,kBAAkB,CAAC,CAAC;QACtC,CAAC;QACD,OAAO,OAAO,CAAC,IAAI,CAAC;IACtB,CAAC;IAED,oBAAoB;IACpB,IAAI,CAAC,mBAAmB,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;QACvC,MAAM,IAAI,KAAK,CAAC,sDAAsD,CAAC,CAAC;IAC1E,CAAC;IAED,MAAM,KAAK,GAAG,IAAI,UAAU,CAAC,EAAE,CAAC,CAAC;IACjC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC;QAC5B,KAAK,CAAC,CAAC,CAAC,GAAG,QAAQ,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IAC3D,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,iBAAiB,CAAC,MAKvC;IACC,IAAI,CAAC,UAAU,IAAI,CAAC,eAAe,IAAI,CAAC,mBAAmB,IAAI,CAAC,cAAc,IAAI,CAAC,gBAAgB,EAAE,CAAC;QACpG,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,iCAAiC,EAAE,CAAC;IACxE,CAAC;IAED,qBAAqB;IACrB,MAAM,KAAK,GAAG,MAAM,SAAS,CAAC,cAAc,CAAC,CAAC;IAE9C,+BAA+B;IAC/B,IAAI,MAAM,CAAC,YAAY,EAAE,CAAC;QACxB,KAAK,CAAC,YAAY,GAAG,MAAM,CAAC,YAAY,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,WAAW,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC;IAChF,CAAC;IACD,IAAI,MAAM,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;QAC9B,KAAK,CAAC,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC;IAC3B,CAAC;IACD,IAAI,MAAM,CAAC,KAAK,KAAK,SAAS,EAAE,CAAC;QAC/B,KAAK,CAAC,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC;IAC7B,CAAC;IACD,IAAI,MAAM,CAAC,mBAAmB,KAAK,SAAS,EAAE,CAAC;QAC7C,KAAK,CAAC,mBAAmB,GAAG,MAAM,CAAC,mBAAmB,CAAC;IACzD,CAAC;IAED,qBAAqB;IACrB,MAAM,SAAS,CAAC,cAAc,EAAE,KAAK,CAAC,CAAC;IAEvC,gCAAgC;IAChC,MAAM,WAAW,GAAG,YAAY,EAAE,QAAQ,EAAE,KAAK,IAAI,EAAE,CAAC;IAExD,kBAAkB;IAClB,MAAM,SAAS,GAAe,EAAE,CAAC;IACjC,IAAI,WAAW,CAAC,OAAO,KAAK,KAAK,EAAE,CAAC;QAClC,SAAS,CAAC,IAAI,CAAC;YACb,IAAI,EAAE,IAAI;YACV,MAAM,EAAE,YAAY,CAAC,IAAI,CAAC,GAAG,CAAC;SAC/B,CAAC,CAAC;IACL,CAAC;IAED,yBAAyB;IACzB,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,IAAI,WAAW,CAAC,OAAO,EAAE,IAAI,IAAI,OAAO,CAAC;IAChE,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,IAAI,WAAW,CAAC,OAAO,EAAE,KAAK,IAAI,EAAE,CAAC;IAE9D,MAAM,OAAO,GAAG,IAAI,CAAC,SAAS,CAAC;QAC7B,IAAI;QACJ,KAAK;QACL,YAAY,EAAE,KAAK,CAAC,YAAY;QAChC,SAAS;KACV,CAAC,CAAC;IAEH,MAAM,IAAI,GAAe;QACvB,CAAC,GAAG,EAAE,mBAAmB,CAAC;QAC1B,CAAC,MAAM,EAAE,IAAI,CAAC;QACd,CAAC,OAAO,EAAE,KAAK,CAAC;QAChB,CAAC,GAAG,EAAE,aAAa,CAAC;QACpB,CAAC,GAAG,EAAE,cAAc,EAAE,aAAa,CAAC;KACrC,CAAC;IAEF,KAAK,MAAM,GAAG,IAAI,KAAK,CAAC,YAAY,EAAE,CAAC;QACrC,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,GAAG,CAAC,EAAE,EAAE,GAAG,CAAC,WAAW,CAAC,CAAC,CAAC;IAC5C,CAAC;IAED,KAAK,MAAM,KAAK,IAAI,SAAS,EAAE,CAAC;QAC9B,MAAM,QAAQ,GAAG,KAAK,CAAC,MAAM,IAAI,KAAK,CAAC,GAAG,IAAI,EAAE,CAAC;QACjD,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC,CAAC;IACzC,CAAC;IAED,MAAM,KAAK,GAAG,gBAAgB,CAAC,aAAa,CAC1C;QACE,IAAI,EAAE,iBAAiB;QACvB,OAAO;QACP,IAAI;QACJ,UAAU,EAAE,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC;KAC1C,EACD,eAAe,CAChB,CAAC;IAEF,MAAM,QAAQ,GAAG,UAAU,CAAC,OAAO,CAAC,YAAY,EAAE,KAAK,CAAC,CAAC;IACzD,MAAM,OAAO,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC;IAEnC,YAAY,EAAE,IAAI,CAAC,mDAAmD,CAAC,CAAC;IAExE,OAAO;QACL,OAAO,EAAE,IAAI;QACb,OAAO,EAAE,uCAAuC,KAAK,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,MAAM,EAAE;KACzG,CAAC;AACJ,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,MAGpC;IAUC,IAAI,CAAC,UAAU,IAAI,CAAC,gBAAgB,EAAE,CAAC;QACrC,wCAAwC;QACxC,IAAI,CAAC;YACH,gBAAgB,GAAG,MAAM,MAAM,CAAC,aAAa,CAAC,CAAC;YAC/C,UAAU,GAAG,IAAI,gBAAgB,CAAC,UAAU,EAAE,CAAC;QACjD,CAAC;QAAC,MAAM,CAAC;YACP,MAAM,IAAI,KAAK,CAAC,iCAAiC,CAAC,CAAC;QACrD,CAAC;IACH,CAAC;IAED,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,IAAI,EAAE,CAAC;IAEjC,iCAAiC;IACjC,MAAM,MAAM,GAAQ;QAClB,KAAK,EAAE,CAAC,iBAAiB,CAAC;QAC1B,KAAK;KACN,CAAC;IAEF,qCAAqC;IACrC,IAAI,MAAM,CAAC,UAAU,EAAE,CAAC;QACtB,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;IACrC,CAAC;IAED,6CAA6C;IAC7C,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC;IAE/B,iCAAiC;IACjC,MAAM,MAAM,GAAG,MAAM,UAAU,CAAC,SAAS,CAAC,YAAY,EAAE,MAAM,CAAC,CAAC;IAEhE,sBAAsB;IACtB,MAAM,MAAM,GAUP,EAAE,CAAC;IAER,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC3B,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC;YACxB,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,CAAW,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,SAAS,CAAC;YAC3E,MAAM,KAAK,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,CAAW,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;YACtE,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,CAAW,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;YAEnE,+BAA+B;YAC/B,MAAM,YAAY,GAAG,IAAI;iBACtB,MAAM,CAAC,CAAC,CAAW,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC;iBACrC,GAAG,CAAC,CAAC,CAAW,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,CAAC;YAEjE,4BAA4B;YAC5B,MAAM,SAAS,GAAG,IAAI;iBACnB,MAAM,CAAC,CAAC,CAAW,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC;iBACrC,GAAG,CAAC,CAAC,CAAW,EAAE,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,CAAC;YAEhE,MAAM,IAAI,GAAG,gBAAgB,CAAC,KAAK,CAAC,UAAU,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;YAE7D,MAAM,CAAC,IAAI,CAAC;gBACV,IAAI;gBACJ,IAAI;gBACJ,MAAM,EAAE,KAAK,CAAC,MAAM;gBACpB,KAAK;gBACL,YAAY;gBACZ,SAAS;gBACT,MAAM,EAAE,KAAK,EAAE,qCAAqC;gBACpD,QAAQ,EAAE,IAAI;gBACd,MAAM;aACP,CAAC,CAAC;QACL,CAAC;QAAC,MAAM,CAAC;YACP,wBAAwB;QAC1B,CAAC;IACH,CAAC;IAED,uDAAuD;IACvD,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACtB,MAAM,eAAe,GAAQ;YAC3B,KAAK,EAAE,CAAC,cAAc,CAAC;YACvB,OAAO,EAAE,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC;YAClC,KAAK,EAAE,MAAM,CAAC,MAAM,GAAG,CAAC;SACzB,CAAC;QAEF,MAAM,UAAU,GAAG,MAAM,UAAU,CAAC,SAAS,CAAC,YAAY,EAAE,eAAe,CAAC,CAAC;QAE7E,2BAA2B;QAC3B,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC;QAC1C,KAAK,MAAM,EAAE,IAAI,UAAU,EAAE,CAAC;YAC5B,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,EAAE,CAAC,MAAM,CAAC,CAAC;YACvD,IAAI,KAAK,EAAE,CAAC;gBACV,MAAM,GAAG,GAAG,GAAG,GAAG,EAAE,CAAC,UAAU,CAAC;gBAChC,gDAAgD;gBAChD,IAAI,GAAG,GAAG,GAAG,EAAE,CAAC;oBACd,KAAK,CAAC,MAAM,GAAG,IAAI,CAAC;gBACtB,CAAC;gBACD,IAAI,KAAK,CAAC,QAAQ,KAAK,IAAI,IAAI,EAAE,CAAC,UAAU,GAAG,KAAK,CAAC,QAAQ,EAAE,CAAC;oBAC9D,KAAK,CAAC,QAAQ,GAAG,EAAE,CAAC,UAAU,CAAC;gBACjC,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC;IAED,uCAAuC;IACvC,OAAO,MAAM,CAAC,GAAG,CAAC,CAAC,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC;AACnD,CAAC"}
@@ -0,0 +1,34 @@
1
+ {
2
+ "id": "agent-reach",
3
+ "name": "Agent Discovery",
4
+ "description": "Publish service cards and heartbeats to Nostr for agent discovery",
5
+ "version": "0.1.0",
6
+ "configSchema": {
7
+ "type": "object",
8
+ "additionalProperties": false,
9
+ "properties": {
10
+ "enabled": {
11
+ "type": "boolean",
12
+ "default": true,
13
+ "description": "Enable agent discovery"
14
+ },
15
+ "capabilities": {
16
+ "type": "array",
17
+ "items": { "type": "string" },
18
+ "default": ["automation", "research", "coding"],
19
+ "description": "List of capabilities to advertise"
20
+ },
21
+ "heartbeatIntervalMs": {
22
+ "type": "number",
23
+ "default": 600000,
24
+ "description": "Heartbeat interval in milliseconds (default: 10 minutes)"
25
+ },
26
+ "relays": {
27
+ "type": "array",
28
+ "items": { "type": "string" },
29
+ "default": ["wss://relay.damus.io", "wss://nos.lol", "wss://relay.nostr.band"],
30
+ "description": "Nostr relays to publish to"
31
+ }
32
+ }
33
+ }
34
+ }
package/package.json ADDED
@@ -0,0 +1,48 @@
1
+ {
2
+ "name": "agent-reach",
3
+ "version": "0.1.0",
4
+ "description": "Agent discovery for OpenClaw via Nostr - publish service cards and heartbeats to make your agent discoverable",
5
+ "type": "module",
6
+ "main": "dist/index.js",
7
+ "types": "dist/index.d.ts",
8
+ "files": [
9
+ "dist",
10
+ "openclaw.plugin.json"
11
+ ],
12
+ "scripts": {
13
+ "build": "tsc",
14
+ "dev": "tsc --watch",
15
+ "prepublishOnly": "npm run build"
16
+ },
17
+ "keywords": [
18
+ "openclaw",
19
+ "openclaw-plugin",
20
+ "nostr",
21
+ "agent-reach",
22
+ "ai-agents",
23
+ "decentralized"
24
+ ],
25
+ "author": "Austin Eral",
26
+ "license": "MIT",
27
+ "repository": {
28
+ "type": "git",
29
+ "url": "https://github.com/AustinEral/agent-reach.git",
30
+ "directory": "openclaw"
31
+ },
32
+ "homepage": "https://github.com/AustinEral/agent-reach#readme",
33
+ "bugs": {
34
+ "url": "https://github.com/AustinEral/agent-reach/issues"
35
+ },
36
+ "openclaw": {
37
+ "extensions": ["dist/index.js"]
38
+ },
39
+ "dependencies": {
40
+ "nostr-tools": "^2.10.4"
41
+ },
42
+ "peerDependencies": {
43
+ "openclaw": ">=2026.1.0"
44
+ },
45
+ "devDependencies": {
46
+ "typescript": "^5.7.0"
47
+ }
48
+ }