edge-book 0.2.2 → 0.2.4
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/edge-book.js +112 -3
- package/package.json +1 -1
package/dist/edge-book.js
CHANGED
|
@@ -179,6 +179,19 @@ var EdgeBookStore = class {
|
|
|
179
179
|
if (!identity) throw new EdgeBookError("not_initialized", `Edge Book is not initialized at ${this.home}`);
|
|
180
180
|
return identity;
|
|
181
181
|
}
|
|
182
|
+
// Update profile fields on an existing identity without rotating keys, so the
|
|
183
|
+
// agent_id (and any pairing built on it) survives. `owner_label` is the human
|
|
184
|
+
// who owns the agent; `display_name` is the agent's own name.
|
|
185
|
+
async setProfile(input) {
|
|
186
|
+
const identity = await this.identity();
|
|
187
|
+
if (input.displayName !== void 0 && input.displayName !== "") identity.display_name = input.displayName;
|
|
188
|
+
if (input.ownerLabel !== void 0) identity.owner_label = input.ownerLabel;
|
|
189
|
+
identity.updated_at = now();
|
|
190
|
+
await writeJson(this.file(IDENTITY_FILE), identity, 384);
|
|
191
|
+
await this.writeCard();
|
|
192
|
+
await this.audit("identity.update", identity.agent_id, { display_name: identity.display_name, owner_label: identity.owner_label });
|
|
193
|
+
return identity;
|
|
194
|
+
}
|
|
182
195
|
async config() {
|
|
183
196
|
return readJson(this.file(CONFIG_FILE), {});
|
|
184
197
|
}
|
|
@@ -1249,6 +1262,7 @@ function publicIdentity(identity) {
|
|
|
1249
1262
|
handle: identity.handle,
|
|
1250
1263
|
name: identity.display_name,
|
|
1251
1264
|
display_name: identity.display_name,
|
|
1265
|
+
owner_label: identity.owner_label,
|
|
1252
1266
|
public_key: compactPem(identity.public_key_pem)
|
|
1253
1267
|
};
|
|
1254
1268
|
}
|
|
@@ -2778,6 +2792,8 @@ var EdgeBookDialoutClient = class {
|
|
|
2778
2792
|
currentBackoff;
|
|
2779
2793
|
opened;
|
|
2780
2794
|
pendingSessionRevokes = /* @__PURE__ */ new Map();
|
|
2795
|
+
// Generic request_id-keyed RPC waiters for sessions_list / session_revoke_one.
|
|
2796
|
+
pendingRpc = /* @__PURE__ */ new Map();
|
|
2781
2797
|
pendingMailboxSends = /* @__PURE__ */ new Map();
|
|
2782
2798
|
constructor(options) {
|
|
2783
2799
|
this.options = {
|
|
@@ -2817,6 +2833,30 @@ var EdgeBookDialoutClient = class {
|
|
|
2817
2833
|
this.send(frame);
|
|
2818
2834
|
return frame;
|
|
2819
2835
|
}
|
|
2836
|
+
// List this agent's remembered devices on the host (ea-claude-057).
|
|
2837
|
+
async listSessionsAndWait(timeoutMs = 5e3) {
|
|
2838
|
+
const frame = await this.rpc("sessions_list", {}, "sessions_list_ok", timeoutMs);
|
|
2839
|
+
return frame.devices || [];
|
|
2840
|
+
}
|
|
2841
|
+
// Revoke ONE device by its public device_id (ea-claude-057).
|
|
2842
|
+
async revokeOneSessionAndWait(device_id, timeoutMs = 5e3) {
|
|
2843
|
+
const frame = await this.rpc("session_revoke_one", { device_id }, "session_revoke_one_ok", timeoutMs);
|
|
2844
|
+
return Boolean(frame.revoked);
|
|
2845
|
+
}
|
|
2846
|
+
// Small request/response helper over the dial-out socket, correlated by
|
|
2847
|
+
// request_id. `expect` documents the ack type; resolution is by request_id.
|
|
2848
|
+
async rpc(type, extra, expect, timeoutMs) {
|
|
2849
|
+
const request_id = crypto2.randomUUID();
|
|
2850
|
+
const promise = new Promise((resolve, reject) => {
|
|
2851
|
+
const timer = setTimeout(() => {
|
|
2852
|
+
this.pendingRpc.delete(request_id);
|
|
2853
|
+
reject(new EdgeBookError("host_rpc_timeout", `Timed out waiting for ${expect}`));
|
|
2854
|
+
}, timeoutMs);
|
|
2855
|
+
this.pendingRpc.set(request_id, { resolve, reject, timer });
|
|
2856
|
+
});
|
|
2857
|
+
this.send({ type, request_id, ...extra });
|
|
2858
|
+
return promise;
|
|
2859
|
+
}
|
|
2820
2860
|
async revokeSessionsAndWait(timeoutMs = 5e3) {
|
|
2821
2861
|
const frame = await createSessionsRevokeFrame(this.store);
|
|
2822
2862
|
const ackPromise = new Promise((resolve, reject) => {
|
|
@@ -2959,6 +2999,16 @@ var EdgeBookDialoutClient = class {
|
|
|
2959
2999
|
this.send({ type: "pong" });
|
|
2960
3000
|
return;
|
|
2961
3001
|
}
|
|
3002
|
+
if (frame.type === "sessions_list_ok" || frame.type === "session_revoke_one_ok") {
|
|
3003
|
+
const ack = frame;
|
|
3004
|
+
const pending = this.pendingRpc.get(ack.request_id || "");
|
|
3005
|
+
if (pending) {
|
|
3006
|
+
clearTimeout(pending.timer);
|
|
3007
|
+
this.pendingRpc.delete(ack.request_id || "");
|
|
3008
|
+
pending.resolve(frame);
|
|
3009
|
+
}
|
|
3010
|
+
return;
|
|
3011
|
+
}
|
|
2962
3012
|
if (frame.type === "stand_down" || frame.type === "dialout_idle") {
|
|
2963
3013
|
await this.standDown(frame);
|
|
2964
3014
|
return;
|
|
@@ -3082,18 +3132,41 @@ async function sendSessionsRevoke(options) {
|
|
|
3082
3132
|
await client.stop();
|
|
3083
3133
|
return { ...frame, channel_id: ack.channel_id };
|
|
3084
3134
|
}
|
|
3135
|
+
async function listSessions(options) {
|
|
3136
|
+
const client = new EdgeBookDialoutClient({ ...options, reconnect: false, openLocalApi: false });
|
|
3137
|
+
await client.start();
|
|
3138
|
+
await new Promise((resolve) => setTimeout(resolve, 0));
|
|
3139
|
+
try {
|
|
3140
|
+
return await client.listSessionsAndWait();
|
|
3141
|
+
} finally {
|
|
3142
|
+
await client.stop();
|
|
3143
|
+
}
|
|
3144
|
+
}
|
|
3145
|
+
async function revokeOneSession(options) {
|
|
3146
|
+
const client = new EdgeBookDialoutClient({ ...options, reconnect: false, openLocalApi: false });
|
|
3147
|
+
await client.start();
|
|
3148
|
+
await new Promise((resolve) => setTimeout(resolve, 0));
|
|
3149
|
+
try {
|
|
3150
|
+
return await client.revokeOneSessionAndWait(options.deviceId);
|
|
3151
|
+
} finally {
|
|
3152
|
+
await client.stop();
|
|
3153
|
+
}
|
|
3154
|
+
}
|
|
3085
3155
|
|
|
3086
3156
|
// src/cli.ts
|
|
3087
3157
|
function usage() {
|
|
3088
3158
|
return `Edge Book
|
|
3089
3159
|
|
|
3090
3160
|
Usage:
|
|
3091
|
-
edge-book init [--home <dir>] [--handle <handle>] [--name <
|
|
3161
|
+
edge-book init [--home <dir>] [--handle <handle>] [--name <agent name>] [--owner <human owner>]
|
|
3162
|
+
edge-book profile show [--home <dir>]
|
|
3163
|
+
edge-book profile set [--name <agent name>] [--owner <human owner>] [--home <dir>]
|
|
3092
3164
|
|
|
3093
3165
|
Hosted reader:
|
|
3094
3166
|
edge-book dialout [--host <ws-url>] [--home <dir>]
|
|
3095
3167
|
edge-book pair [--host <ws-url>] [--ttl-ms <ms>] [--home <dir>]
|
|
3096
|
-
edge-book sessions
|
|
3168
|
+
edge-book sessions list [--host <ws-url>] [--home <dir>]
|
|
3169
|
+
edge-book sessions revoke [--device <id>] [--host <ws-url>] [--home <dir>]
|
|
3097
3170
|
|
|
3098
3171
|
Local agent:
|
|
3099
3172
|
edge-book doctor [--home <dir>]
|
|
@@ -3179,11 +3252,36 @@ async function handleCli(inputArgs, ctx = {}) {
|
|
|
3179
3252
|
if (command === "init") {
|
|
3180
3253
|
const handle = takeFlag(args, "--handle");
|
|
3181
3254
|
const displayName = takeFlag(args, "--name");
|
|
3255
|
+
const ownerLabel = takeFlag(args, "--owner");
|
|
3182
3256
|
const directUrl = takeFlag(args, "--direct-url");
|
|
3183
3257
|
const relayUrl = takeFlag(args, "--relay-url");
|
|
3184
|
-
const identity = await store.init({ handle, displayName, directUrl, relayUrl });
|
|
3258
|
+
const identity = await store.init({ handle, displayName, ownerLabel, directUrl, relayUrl });
|
|
3185
3259
|
return { text: `Initialized ${identity.agent_id} at ${store.home}`, json: identity };
|
|
3186
3260
|
}
|
|
3261
|
+
if (command === "profile") {
|
|
3262
|
+
const action = args.shift() || "show";
|
|
3263
|
+
if (action === "show") {
|
|
3264
|
+
const id = await store.identity();
|
|
3265
|
+
return {
|
|
3266
|
+
text: `display_name: ${id.display_name}
|
|
3267
|
+
owner_label: ${id.owner_label || "(unset)"}`,
|
|
3268
|
+
json: { agent_id: id.agent_id, display_name: id.display_name, owner_label: id.owner_label }
|
|
3269
|
+
};
|
|
3270
|
+
}
|
|
3271
|
+
if (action === "set") {
|
|
3272
|
+
const displayName = takeFlag(args, "--name");
|
|
3273
|
+
const ownerLabel = takeFlag(args, "--owner");
|
|
3274
|
+
if (displayName === void 0 && ownerLabel === void 0) {
|
|
3275
|
+
throw new EdgeBookError("missing_arg", "profile set needs --name (agent name) and/or --owner (human owner)");
|
|
3276
|
+
}
|
|
3277
|
+
const id = await store.setProfile({ displayName, ownerLabel });
|
|
3278
|
+
return {
|
|
3279
|
+
text: `Updated profile: display_name=${id.display_name} owner_label=${id.owner_label || "(unset)"}`,
|
|
3280
|
+
json: { agent_id: id.agent_id, display_name: id.display_name, owner_label: id.owner_label }
|
|
3281
|
+
};
|
|
3282
|
+
}
|
|
3283
|
+
throw new EdgeBookError("unknown_action", `Unknown profile action: ${action} (use "show" or "set")`);
|
|
3284
|
+
}
|
|
3187
3285
|
if (command === "doctor") {
|
|
3188
3286
|
const result = await store.doctor();
|
|
3189
3287
|
return { text: JSON.stringify(result, null, 2), json: result };
|
|
@@ -3396,8 +3494,19 @@ Expires in: ${registration.frame.ttl_ms}ms`, json: registration };
|
|
|
3396
3494
|
}
|
|
3397
3495
|
if (command === "sessions") {
|
|
3398
3496
|
const action = args.shift();
|
|
3497
|
+
if (action === "list") {
|
|
3498
|
+
const hostUrl = parseHost(args, ctx);
|
|
3499
|
+
const devices = await listSessions({ home, host: hostUrl, socketFactory: ctx.socketFactory });
|
|
3500
|
+
const lines = devices.length ? devices.map((d) => `${d.device_id} ${d.label} (added ${new Date(d.created_at).toISOString()}, last seen ${new Date(d.last_seen_at).toISOString()})`).join("\n") : "No remembered devices.";
|
|
3501
|
+
return { text: lines, json: { devices } };
|
|
3502
|
+
}
|
|
3399
3503
|
if (action === "revoke") {
|
|
3400
3504
|
const hostUrl = parseHost(args, ctx);
|
|
3505
|
+
const deviceId = takeFlag(args, "--device");
|
|
3506
|
+
if (deviceId) {
|
|
3507
|
+
const revoked = await revokeOneSession({ home, host: hostUrl, socketFactory: ctx.socketFactory, deviceId });
|
|
3508
|
+
return { text: revoked ? `Revoked device ${deviceId}` : `No device ${deviceId} found on your channel`, json: { device_id: deviceId, revoked } };
|
|
3509
|
+
}
|
|
3401
3510
|
const frame = await sendSessionsRevoke({ home, host: hostUrl, socketFactory: ctx.socketFactory });
|
|
3402
3511
|
const channel = frame.channel_id || "unknown-channel";
|
|
3403
3512
|
return { text: `Received sessions_revoke_ok for request ${frame.request_id} on ${channel}`, json: frame };
|