edge-book 0.1.0 → 0.1.2

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/package.json CHANGED
@@ -1,15 +1,17 @@
1
1
  {
2
2
  "name": "edge-book",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "description": "Run your own Edge Book agent and connect it to the hosted reader.",
5
5
  "license": "MIT",
6
6
  "type": "module",
7
7
  "bin": {
8
- "edge-book": "bin/edge-book.js"
8
+ "edge-book": "dist/edge-book.js"
9
9
  },
10
10
  "scripts": {
11
+ "build": "tsup",
11
12
  "test": "node --test test/*.test.ts",
12
- "harness": "node bin/edge-book.js harness two-agent"
13
+ "harness": "node bin/edge-book.js harness two-agent",
14
+ "prepublishOnly": "npm run build"
13
15
  },
14
16
  "openclaw": {
15
17
  "extensions": [
@@ -25,9 +27,7 @@
25
27
  }
26
28
  },
27
29
  "files": [
28
- "bin",
29
30
  "dist",
30
- "src",
31
31
  "README.md"
32
32
  ],
33
33
  "engines": {
@@ -44,5 +44,13 @@
44
44
  "openclaw": {
45
45
  "optional": true
46
46
  }
47
+ },
48
+ "devDependencies": {
49
+ "@types/ws": "^8.18.1",
50
+ "tsup": "^8.5.1",
51
+ "typescript": "^6.0.3"
52
+ },
53
+ "dependencies": {
54
+ "ws": "^8.21.0"
47
55
  }
48
56
  }
package/bin/edge-book.js DELETED
@@ -1,7 +0,0 @@
1
- #!/usr/bin/env node
2
- import { runCli } from "../src/cli.ts";
3
-
4
- runCli(process.argv.slice(2)).catch((error) => {
5
- console.error(error?.message ?? String(error));
6
- process.exitCode = 1;
7
- });
package/src/cli.ts DELETED
@@ -1,301 +0,0 @@
1
- import fs from "node:fs/promises";
2
- import net from "node:net";
3
- import path from "node:path";
4
- import { EdgeBookDialoutClient, sendPairRegistration, sendSessionsRevoke } from "./dialout.ts";
5
- import type { DialoutSocket, SessionsRevokeFrame } from "./dialout.ts";
6
- import { loadCard, runTwoAgentHarness, EdgeBookError, EdgeBookStore } from "./edge-book.ts";
7
- import { postEnvelope, postRelayEnvelope, pullRelayEnvelopes, startRelayServer, startEdgeBookServer } from "./http.ts";
8
-
9
- export interface CliContext {
10
- home?: string;
11
- textOnly?: boolean;
12
- socketFactory?: (url: string) => DialoutSocket;
13
- }
14
-
15
- export interface CliResult {
16
- text: string;
17
- json?: unknown;
18
- }
19
-
20
- function usage(): string {
21
- return `Edge Book
22
-
23
- Usage:
24
- edge-book init [--home <dir>] [--handle <handle>] [--name <display>]
25
- edge-book doctor [--home <dir>]
26
- edge-book card show [--home <dir>]
27
- edge-book card export --path <file> [--home <dir>]
28
- edge-book friend request <card-path-or-url> [--deliver] [--home <dir>]
29
- edge-book friend receive <envelope-json-path> [--home <dir>]
30
- edge-book friend accept <peer-agent-id> [--deliver] [--home <dir>]
31
- edge-book friend apply-response <envelope-json-path> [--home <dir>]
32
- edge-book friend revoke <peer-agent-id> [--home <dir>]
33
- edge-book friend block <peer-agent-id> [--home <dir>]
34
- edge-book contacts list [--home <dir>]
35
- edge-book contacts refresh <card-path-or-url> [--home <dir>]
36
- edge-book message send <peer-agent-id> --body <text> [--deliver] [--home <dir>]
37
- edge-book message receive <envelope-json-path> [--home <dir>]
38
- edge-book inbox list [--home <dir>]
39
- edge-book inbox pull --relay <url> [--home <dir>]
40
- edge-book serve --host <host> --port <port> [--home <dir>]
41
- edge-book dialout --host <ws-url> [--home <dir>]
42
- edge-book pair --host <ws-url> [--ttl-ms <ms>] [--home <dir>]
43
- edge-book sessions revoke --host <ws-url> [--home <dir>]
44
- edge-book relay serve --host <host> --port <port> --store <dir>
45
- edge-book harness two-agent`;
46
- }
47
-
48
- function takeFlag(args: string[], name: string): string | undefined {
49
- const idx = args.indexOf(name);
50
- if (idx === -1) return undefined;
51
- const value = args[idx + 1];
52
- args.splice(idx, 2);
53
- return value;
54
- }
55
-
56
- function parseHome(args: string[], ctx: CliContext): string | undefined {
57
- return takeFlag(args, "--home") || ctx.home;
58
- }
59
-
60
- function requireArg(value: string | undefined, label: string): string {
61
- if (!value) throw new EdgeBookError("missing_arg", `Missing ${label}`);
62
- return value;
63
- }
64
-
65
- function takeBoolFlag(args: string[], name: string): boolean {
66
- const idx = args.indexOf(name);
67
- if (idx === -1) return false;
68
- args.splice(idx, 1);
69
- return true;
70
- }
71
-
72
- async function readEnvelope(filePath: string) {
73
- return JSON.parse(await fs.readFile(path.resolve(filePath), "utf8"));
74
- }
75
-
76
- async function deliverToEndpoint(envelope: Awaited<ReturnType<EdgeBookStore["signEnvelope"]>>, endpoint: string): Promise<string> {
77
- await postEnvelope(endpoint, envelope);
78
- return `Delivered ${envelope.type} to ${endpoint}`;
79
- }
80
-
81
- async function deliverToPeer(store: EdgeBookStore, envelope: Awaited<ReturnType<EdgeBookStore["signEnvelope"]>>, peerAgentId: string): Promise<string> {
82
- const contacts = await store.contacts();
83
- const contact = contacts[peerAgentId];
84
- const direct = contact?.known_endpoints.find((entry) => entry.mode === "direct")?.endpoint;
85
- if (direct) return deliverToEndpoint(envelope, direct);
86
- const relay = contact?.known_endpoints.find((entry) => entry.mode === "relay")?.endpoint;
87
- if (relay) {
88
- await postRelayEnvelope(relay, peerAgentId, envelope);
89
- return `Queued ${envelope.type} via relay ${relay}`;
90
- }
91
- throw new EdgeBookError("no_route", `No direct or relay endpoint for ${peerAgentId}`);
92
- }
93
-
94
- function serverAddress(server: { address(): string | net.AddressInfo | null }): string {
95
- const address = server.address();
96
- if (!address || typeof address === "string") return String(address);
97
- return `${address.address}:${address.port}`;
98
- }
99
-
100
- export async function handleCli(inputArgs: string[], ctx: CliContext = {}): Promise<CliResult> {
101
- const args = [...inputArgs];
102
- const home = parseHome(args, ctx);
103
- const command = args.shift() || "help";
104
- const store = new EdgeBookStore({ home });
105
-
106
- if (command === "help" || command === "--help" || command === "-h") {
107
- return { text: usage() };
108
- }
109
-
110
- if (command === "init") {
111
- const handle = takeFlag(args, "--handle");
112
- const displayName = takeFlag(args, "--name");
113
- const directUrl = takeFlag(args, "--direct-url");
114
- const relayUrl = takeFlag(args, "--relay-url");
115
- const identity = await store.init({ handle, displayName, directUrl, relayUrl });
116
- return { text: `Initialized ${identity.agent_id} at ${store.home}`, json: identity };
117
- }
118
-
119
- if (command === "doctor") {
120
- const result = await store.doctor();
121
- return { text: JSON.stringify(result, null, 2), json: result };
122
- }
123
-
124
- if (command === "card") {
125
- const action = args.shift() || "show";
126
- if (action === "show") {
127
- const card = await store.writeCard();
128
- return { text: JSON.stringify(card, null, 2), json: card };
129
- }
130
- if (action === "export") {
131
- const target = requireArg(takeFlag(args, "--path"), "--path");
132
- const card = await store.writeCard();
133
- await fs.mkdir(path.dirname(path.resolve(target)), { recursive: true });
134
- await fs.writeFile(path.resolve(target), `${JSON.stringify(card, null, 2)}\n`, "utf8");
135
- return { text: `Exported Agent Card to ${path.resolve(target)}`, json: card };
136
- }
137
- }
138
-
139
- if (command === "friend") {
140
- const action = args.shift();
141
- if (action === "request") {
142
- const deliver = takeBoolFlag(args, "--deliver");
143
- const target = requireArg(args.shift(), "card-path-or-url");
144
- const card = await loadCard(target);
145
- const envelope = await store.createFriendRequest(card);
146
- if (deliver) {
147
- const direct = card.transports.find((entry) => entry.mode === "direct")?.endpoint;
148
- if (direct) return { text: await deliverToEndpoint(envelope, direct), json: envelope };
149
- const relay = card.transports.find((entry) => entry.mode === "relay")?.endpoint;
150
- if (relay) {
151
- await postRelayEnvelope(relay, card.agent_id, envelope);
152
- return { text: `Queued friend_request via relay ${relay}`, json: envelope };
153
- }
154
- throw new EdgeBookError("no_route", `No direct or relay endpoint for ${card.agent_id}`);
155
- }
156
- return { text: JSON.stringify(envelope, null, 2), json: envelope };
157
- }
158
- if (action === "receive") {
159
- const source = requireArg(args.shift(), "envelope-json-path");
160
- const contact = await store.receiveFriendRequest(await readEnvelope(source));
161
- return { text: JSON.stringify(contact, null, 2), json: contact };
162
- }
163
- if (action === "accept") {
164
- const deliver = takeBoolFlag(args, "--deliver");
165
- const peer = requireArg(args.shift(), "peer-agent-id");
166
- const envelope = await store.acceptFriend(peer);
167
- if (deliver) return { text: await deliverToPeer(store, envelope, peer), json: envelope };
168
- return { text: JSON.stringify(envelope, null, 2), json: envelope };
169
- }
170
- if (action === "apply-response") {
171
- const source = requireArg(args.shift(), "envelope-json-path");
172
- await store.applyFriendResponse(await readEnvelope(source));
173
- return { text: `Applied friend response from ${path.resolve(source)}` };
174
- }
175
- if (action === "revoke") {
176
- const peer = requireArg(args.shift(), "peer-agent-id");
177
- await store.revoke(peer);
178
- return { text: `Revoked ${peer}` };
179
- }
180
- if (action === "block") {
181
- const peer = requireArg(args.shift(), "peer-agent-id");
182
- await store.block(peer);
183
- return { text: `Blocked ${peer}` };
184
- }
185
- }
186
-
187
- if (command === "contacts") {
188
- const action = args.shift() || "list";
189
- if (action === "list") {
190
- const contacts = await store.contacts();
191
- return { text: JSON.stringify(Object.values(contacts), null, 2), json: contacts };
192
- }
193
- if (action === "refresh") {
194
- const target = requireArg(args.shift(), "card-path-or-url");
195
- const contact = await store.upsertContactFromCard(await loadCard(target));
196
- return { text: JSON.stringify(contact, null, 2), json: contact };
197
- }
198
- }
199
-
200
- if (command === "message") {
201
- const action = args.shift();
202
- if (action === "send") {
203
- const deliver = takeBoolFlag(args, "--deliver");
204
- const peer = requireArg(args.shift(), "peer-agent-id");
205
- const body = requireArg(takeFlag(args, "--body"), "--body");
206
- const envelope = await store.sendPrivilegedMessage(peer, { text: body });
207
- if (deliver) return { text: await deliverToPeer(store, envelope, peer), json: envelope };
208
- return { text: JSON.stringify(envelope, null, 2), json: envelope };
209
- }
210
- if (action === "receive") {
211
- const source = requireArg(args.shift(), "envelope-json-path");
212
- await store.receivePrivilegedMessage(await readEnvelope(source));
213
- return { text: `Received privileged message from ${path.resolve(source)}` };
214
- }
215
- }
216
-
217
- if (command === "inbox") {
218
- const action = args.shift() || "list";
219
- if (action === "list") {
220
- const inbox = await store.inbox();
221
- return { text: JSON.stringify(inbox, null, 2), json: inbox };
222
- }
223
- if (action === "pull") {
224
- const relay = requireArg(takeFlag(args, "--relay"), "--relay");
225
- const identity = await store.identity();
226
- const envelopes = await pullRelayEnvelopes(relay, identity.agent_id);
227
- for (const envelope of envelopes) await store.receiveEnvelope(envelope);
228
- return { text: `Pulled ${envelopes.length} envelope(s) from ${relay}`, json: envelopes };
229
- }
230
- }
231
-
232
- if (command === "serve") {
233
- const host = takeFlag(args, "--host") || "127.0.0.1";
234
- const port = Number(takeFlag(args, "--port") || "0");
235
- const cardUrl = takeFlag(args, "--card-url");
236
- const server = await startEdgeBookServer({ home, host, port, cardUrl });
237
- console.log(`Edge Book server listening on ${serverAddress(server)}`);
238
- await new Promise(() => undefined);
239
- }
240
-
241
- if (command === "dialout") {
242
- const hostUrl = requireArg(takeFlag(args, "--host"), "--host");
243
- const client = new EdgeBookDialoutClient({ home, host: hostUrl, socketFactory: ctx.socketFactory });
244
- await client.start();
245
- console.log(`Edge Book dial-out connected to ${hostUrl}`);
246
- await new Promise(() => undefined);
247
- }
248
-
249
- if (command === "pair") {
250
- const hostUrl = requireArg(takeFlag(args, "--host"), "--host");
251
- const ttlMs = Number(takeFlag(args, "--ttl-ms") || `${5 * 60 * 1000}`);
252
- if (!ctx.textOnly) {
253
- const client = new EdgeBookDialoutClient({ home, host: hostUrl, socketFactory: ctx.socketFactory, openLocalApi: false });
254
- await client.start();
255
- const registration = await client.pair(ttlMs);
256
- console.log(`Pairing code: ${registration.code}`);
257
- console.log(`Expires in: ${ttlMs}ms`);
258
- console.log("Edge Book dial-out remains connected; leave this process running during the hosted reader session.");
259
- await new Promise(() => undefined);
260
- }
261
- const registration = await sendPairRegistration({ home, host: hostUrl, ttlMs, socketFactory: ctx.socketFactory });
262
- return { text: `Pairing code: ${registration.code}\nExpires in: ${registration.frame.ttl_ms}ms`, json: registration };
263
- }
264
-
265
- if (command === "sessions") {
266
- const action = args.shift();
267
- if (action === "revoke") {
268
- const hostUrl = requireArg(takeFlag(args, "--host"), "--host");
269
- const frame = await sendSessionsRevoke({ home, host: hostUrl, socketFactory: ctx.socketFactory });
270
- const channel = (frame as SessionsRevokeFrame & { channel_id?: string }).channel_id || "unknown-channel";
271
- return { text: `Received sessions_revoke_ok for request ${frame.request_id} on ${channel}`, json: frame };
272
- }
273
- }
274
-
275
- if (command === "relay") {
276
- const action = args.shift();
277
- if (action === "serve") {
278
- const host = takeFlag(args, "--host") || "127.0.0.1";
279
- const port = Number(takeFlag(args, "--port") || "0");
280
- const relayStore = requireArg(takeFlag(args, "--store"), "--store");
281
- const server = await startRelayServer({ host, port, store: relayStore });
282
- console.log(`Edge Book relay listening on ${serverAddress(server)}`);
283
- await new Promise(() => undefined);
284
- }
285
- }
286
-
287
- if (command === "harness") {
288
- const action = args.shift();
289
- if (action === "two-agent") {
290
- const result = await runTwoAgentHarness();
291
- return { text: `PASS two-agent harness\n${JSON.stringify(result, null, 2)}`, json: result };
292
- }
293
- }
294
-
295
- throw new EdgeBookError("unknown_command", usage());
296
- }
297
-
298
- export async function runCli(args: string[]): Promise<void> {
299
- const result = await handleCli(args);
300
- console.log(result.text);
301
- }