agent-yes 1.119.1 → 1.121.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/dist/SUPPORTED_CLIS-CegJgoEf.js +8 -0
- package/dist/{SUPPORTED_CLIS-DwPmzY8B.js → SUPPORTED_CLIS-O57LGUEG.js} +2 -2
- package/dist/cli.js +3 -3
- package/dist/index.js +2 -2
- package/dist/{serve-Bd-6ZItj.js → serve-D2czcYNC.js} +29 -18
- package/dist/{setup-DiRSdfeu.js → setup-f1FIFcZm.js} +2 -2
- package/dist/share-B6QVr5D1.js +522 -0
- package/dist/{subcommands-BC_0iPGS.js → subcommands-CzpZQHO6.js} +3 -3
- package/dist/{subcommands-BFHJ2AUQ.js → subcommands-DobVXouH.js} +1 -1
- package/dist/{ts-VrgyWwNH.js → ts-D91dm1E0.js} +2 -2
- package/dist/{versionChecker-BjZOppZJ.js → versionChecker-CAtpgnoQ.js} +2 -2
- package/lab/ui/blog/e2ee-share-links/index.html +299 -0
- package/lab/ui/e2e.d.ts +47 -0
- package/lab/ui/e2e.js +245 -0
- package/lab/ui/index.html +180 -26
- package/package.json +6 -2
- package/scripts/check-e2e.ts +40 -0
- package/ts/e2e-crypto.spec.ts +235 -0
- package/ts/serve.ts +57 -21
- package/ts/share.ts +205 -32
- package/dist/SUPPORTED_CLIS-CwM5JV4y.js +0 -8
- package/dist/share-B7J79Wq9.js +0 -254
|
@@ -0,0 +1,522 @@
|
|
|
1
|
+
import { mkdir, readFile, writeFile } from "fs/promises";
|
|
2
|
+
import { homedir } from "os";
|
|
3
|
+
import path from "path";
|
|
4
|
+
import { randomBytes } from "crypto";
|
|
5
|
+
|
|
6
|
+
//#region lab/ui/e2e.js
|
|
7
|
+
const V = 1;
|
|
8
|
+
const PROTO = `ay-e2e-${V}`;
|
|
9
|
+
const MARKER = `e${V}.`;
|
|
10
|
+
const INFO_AUTH = `ay/${PROTO}/auth`;
|
|
11
|
+
const INFO_H2C = `ay/${PROTO}/key/host->client`;
|
|
12
|
+
const INFO_C2H = `ay/${PROTO}/key/client->host`;
|
|
13
|
+
const MAX_CHUNK = 12e3;
|
|
14
|
+
const CONFIRM_TIMEOUT_MS = 5e3;
|
|
15
|
+
const VER = 1;
|
|
16
|
+
const FLAG_CONFIRM = 1;
|
|
17
|
+
const HEADER_LEN = 14;
|
|
18
|
+
const NONCE_LEN = 12;
|
|
19
|
+
const TAG_LEN = 16;
|
|
20
|
+
const COUNTER_MAX = (1n << 64n) - 1n;
|
|
21
|
+
if (PROTO !== `ay-e2e-${V}` || MARKER !== `e${V}.` || !INFO_AUTH.startsWith(`ay/${PROTO}/`)) throw new Error("e2e: version constants disagree");
|
|
22
|
+
const subtle = globalThis.crypto.subtle;
|
|
23
|
+
const enc = new TextEncoder();
|
|
24
|
+
const dec = new TextDecoder();
|
|
25
|
+
const HEX64 = /^[0-9a-f]{64}$/;
|
|
26
|
+
function concatBytes(...arrs) {
|
|
27
|
+
let len = 0;
|
|
28
|
+
for (const a of arrs) len += a.length;
|
|
29
|
+
const out = new Uint8Array(len);
|
|
30
|
+
let o = 0;
|
|
31
|
+
for (const a of arrs) {
|
|
32
|
+
out.set(a, o);
|
|
33
|
+
o += a.length;
|
|
34
|
+
}
|
|
35
|
+
return out;
|
|
36
|
+
}
|
|
37
|
+
function hexToBytes(hex) {
|
|
38
|
+
const out = new Uint8Array(hex.length / 2);
|
|
39
|
+
for (let i = 0; i < out.length; i++) out[i] = parseInt(hex.substr(i * 2, 2), 16);
|
|
40
|
+
return out;
|
|
41
|
+
}
|
|
42
|
+
function bytesToHex(b) {
|
|
43
|
+
let s = "";
|
|
44
|
+
for (let i = 0; i < b.length; i++) s += b[i].toString(16).padStart(2, "0");
|
|
45
|
+
return s;
|
|
46
|
+
}
|
|
47
|
+
async function sha256(bytes) {
|
|
48
|
+
return new Uint8Array(await subtle.digest("SHA-256", bytes));
|
|
49
|
+
}
|
|
50
|
+
async function hkdf32(ikm, salt, info) {
|
|
51
|
+
const base = await subtle.importKey("raw", ikm, "HKDF", false, ["deriveBits"]);
|
|
52
|
+
const bits = await subtle.deriveBits({
|
|
53
|
+
name: "HKDF",
|
|
54
|
+
hash: "SHA-256",
|
|
55
|
+
salt,
|
|
56
|
+
info: enc.encode(info)
|
|
57
|
+
}, base, 256);
|
|
58
|
+
return new Uint8Array(bits);
|
|
59
|
+
}
|
|
60
|
+
function validateS(s) {
|
|
61
|
+
if (typeof s !== "string" || !HEX64.test(s)) throw new Error("invalid share token");
|
|
62
|
+
return s;
|
|
63
|
+
}
|
|
64
|
+
function ikmFromS(s) {
|
|
65
|
+
return hexToBytes(validateS(s));
|
|
66
|
+
}
|
|
67
|
+
async function deriveAuthToken(s, room, sighost) {
|
|
68
|
+
const salt = await sha256(enc.encode(`${room}\n${sighost}`));
|
|
69
|
+
return bytesToHex(await hkdf32(ikmFromS(s), salt, INFO_AUTH));
|
|
70
|
+
}
|
|
71
|
+
async function importAesKey(raw) {
|
|
72
|
+
return subtle.importKey("raw", raw, { name: "AES-GCM" }, false, ["encrypt", "decrypt"]);
|
|
73
|
+
}
|
|
74
|
+
async function deriveDirKeys(s, transcriptHash) {
|
|
75
|
+
const ikm = ikmFromS(s);
|
|
76
|
+
const h2c = await hkdf32(ikm, transcriptHash, INFO_H2C);
|
|
77
|
+
const c2h = await hkdf32(ikm, transcriptHash, INFO_C2H);
|
|
78
|
+
return {
|
|
79
|
+
keyH2C: await importAesKey(h2c),
|
|
80
|
+
keyC2H: await importAesKey(c2h)
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
function allFingerprints(sdp) {
|
|
84
|
+
const out = [];
|
|
85
|
+
const re = /^a=fingerprint:(.*)$/gim;
|
|
86
|
+
let m;
|
|
87
|
+
while (m = re.exec(sdp)) out.push(m[1].trim().toLowerCase());
|
|
88
|
+
return out;
|
|
89
|
+
}
|
|
90
|
+
function firstAttr(sdp, name) {
|
|
91
|
+
const m = new RegExp(`^a=${name}:(.*)$`, "im").exec(sdp);
|
|
92
|
+
return m ? m[1].trim().toLowerCase() : "";
|
|
93
|
+
}
|
|
94
|
+
async function computeTranscriptHash(offerSdp, answerSdp) {
|
|
95
|
+
const offerFps = allFingerprints(offerSdp).sort();
|
|
96
|
+
const answerFps = allFingerprints(answerSdp).sort();
|
|
97
|
+
if (!offerFps.length || !answerFps.length) throw new Error("e2e: missing DTLS fingerprint");
|
|
98
|
+
for (const fp of offerFps.concat(answerFps)) if (!fp.startsWith("sha-256")) throw new Error("e2e: non-sha-256 DTLS fingerprint");
|
|
99
|
+
const input = `${PROTO}\noffer=${offerFps.join(",")};setup=${firstAttr(offerSdp, "setup")};ufrag=${firstAttr(offerSdp, "ice-ufrag")}\nanswer=${answerFps.join(",")};setup=${firstAttr(answerSdp, "setup")};ufrag=${firstAttr(answerSdp, "ice-ufrag")}`;
|
|
100
|
+
return await sha256(enc.encode(input));
|
|
101
|
+
}
|
|
102
|
+
function nonceFromCounter(ctr) {
|
|
103
|
+
const n = new Uint8Array(NONCE_LEN);
|
|
104
|
+
new DataView(n.buffer).setBigUint64(4, ctr, false);
|
|
105
|
+
return n;
|
|
106
|
+
}
|
|
107
|
+
async function seal(key, sendState, flags, transcriptHash, plaintext) {
|
|
108
|
+
const ctr = sendState.sendCtr;
|
|
109
|
+
if (ctr >= COUNTER_MAX) throw new Error("e2e: nonce counter overflow");
|
|
110
|
+
sendState.sendCtr = ctr + 1n;
|
|
111
|
+
const nonce = nonceFromCounter(ctr);
|
|
112
|
+
const header = new Uint8Array(HEADER_LEN);
|
|
113
|
+
header[0] = VER;
|
|
114
|
+
header[1] = flags & 255;
|
|
115
|
+
header.set(nonce, 2);
|
|
116
|
+
const aad = concatBytes(header, transcriptHash);
|
|
117
|
+
return concatBytes(header, new Uint8Array(await subtle.encrypt({
|
|
118
|
+
name: "AES-GCM",
|
|
119
|
+
iv: nonce,
|
|
120
|
+
additionalData: aad,
|
|
121
|
+
tagLength: 128
|
|
122
|
+
}, key, plaintext))).buffer;
|
|
123
|
+
}
|
|
124
|
+
async function open$1(key, frame, transcriptHash, recvState) {
|
|
125
|
+
const buf = frame instanceof Uint8Array ? frame : new Uint8Array(frame);
|
|
126
|
+
if (buf.length < HEADER_LEN + TAG_LEN) throw new Error("e2e: short frame");
|
|
127
|
+
if (buf[0] !== VER) throw new Error("e2e: bad version");
|
|
128
|
+
const header = buf.subarray(0, HEADER_LEN);
|
|
129
|
+
const nonce = buf.subarray(2, HEADER_LEN);
|
|
130
|
+
const ndv = new DataView(nonce.buffer, nonce.byteOffset, NONCE_LEN);
|
|
131
|
+
if (ndv.getUint32(0, false) !== 0) throw new Error("e2e: bad epoch");
|
|
132
|
+
const ctr = ndv.getBigUint64(4, false);
|
|
133
|
+
const sealed = buf.subarray(HEADER_LEN);
|
|
134
|
+
const aad = concatBytes(header, transcriptHash);
|
|
135
|
+
const ptBuf = await subtle.decrypt({
|
|
136
|
+
name: "AES-GCM",
|
|
137
|
+
iv: nonce,
|
|
138
|
+
additionalData: aad,
|
|
139
|
+
tagLength: 128
|
|
140
|
+
}, key, sealed);
|
|
141
|
+
if (recvState.lastSeen === -1n && ctr !== 0n) throw new Error("e2e: first frame must be counter-0");
|
|
142
|
+
if (ctr <= recvState.lastSeen) throw new Error("e2e: replay/reorder");
|
|
143
|
+
recvState.lastSeen = ctr;
|
|
144
|
+
return {
|
|
145
|
+
counter: ctr,
|
|
146
|
+
flags: header[1],
|
|
147
|
+
plaintext: new Uint8Array(ptBuf)
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
function packEnvelope(obj) {
|
|
151
|
+
return enc.encode(JSON.stringify(obj));
|
|
152
|
+
}
|
|
153
|
+
function unpackEnvelope(bytes) {
|
|
154
|
+
return JSON.parse(dec.decode(bytes));
|
|
155
|
+
}
|
|
156
|
+
function parseSecret(token) {
|
|
157
|
+
const mk = /^e(\d+)\.(.*)$/.exec(token);
|
|
158
|
+
if (mk) {
|
|
159
|
+
if (mk[1] !== String(V)) throw new Error("update required");
|
|
160
|
+
if (!HEX64.test(mk[2])) throw new Error("malformed encrypted link");
|
|
161
|
+
return {
|
|
162
|
+
s: mk[2],
|
|
163
|
+
v2: true
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
if (/^e\d/i.test(token)) throw new Error("malformed encrypted link");
|
|
167
|
+
return {
|
|
168
|
+
s: token,
|
|
169
|
+
v2: false
|
|
170
|
+
};
|
|
171
|
+
}
|
|
172
|
+
function randomHex(n) {
|
|
173
|
+
const b = new Uint8Array(n);
|
|
174
|
+
globalThis.crypto.getRandomValues(b);
|
|
175
|
+
return bytesToHex(b);
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
//#endregion
|
|
179
|
+
//#region ts/share.ts
|
|
180
|
+
const SUB = "ay-signal-1";
|
|
181
|
+
const ICE = [{ urls: "stun:stun.l.google.com:19302" }];
|
|
182
|
+
const DEFAULT_SIGHOST = "s.agent-yes.com";
|
|
183
|
+
function shareRoomPath() {
|
|
184
|
+
const home = process.env.AGENT_YES_HOME ?? path.join(homedir(), ".agent-yes");
|
|
185
|
+
return path.join(home, ".share-room");
|
|
186
|
+
}
|
|
187
|
+
async function loadOrCreateShareRoom(sighost = DEFAULT_SIGHOST) {
|
|
188
|
+
try {
|
|
189
|
+
const url = (await readFile(shareRoomPath(), "utf-8")).trim();
|
|
190
|
+
if (url.startsWith("webrtc://")) {
|
|
191
|
+
if (parseShareUrl(url).token.startsWith(MARKER)) return url;
|
|
192
|
+
}
|
|
193
|
+
} catch {}
|
|
194
|
+
const url = `webrtc://${"r" + randomBytes(3).toString("hex")}:${MARKER}${randomBytes(32).toString("hex")}@${sighost}`;
|
|
195
|
+
await mkdir(path.dirname(shareRoomPath()), { recursive: true });
|
|
196
|
+
await writeFile(shareRoomPath(), url, { mode: 384 });
|
|
197
|
+
return url;
|
|
198
|
+
}
|
|
199
|
+
function parseShareUrl(s) {
|
|
200
|
+
const m = /^webrtc:\/\/([^:@/]+):([^@/]+)@(.+)$/.exec(s);
|
|
201
|
+
if (!m) throw new Error(`bad --share url: ${s} (want webrtc://room:token@host)`);
|
|
202
|
+
return {
|
|
203
|
+
room: m[1],
|
|
204
|
+
token: m[2],
|
|
205
|
+
host: m[3]
|
|
206
|
+
};
|
|
207
|
+
}
|
|
208
|
+
async function linkFromBunCache() {
|
|
209
|
+
const { existsSync, symlinkSync, mkdirSync, readdirSync } = await import("fs");
|
|
210
|
+
const path = (await import("path")).default;
|
|
211
|
+
const { createRequire } = await import("module");
|
|
212
|
+
const require = createRequire(import.meta.url);
|
|
213
|
+
const pkg = path.dirname(require.resolve("node-datachannel/package.json"));
|
|
214
|
+
const bin = path.join(pkg, "build", "Release", "node_datachannel.node");
|
|
215
|
+
const cacheRoot = path.join((await import("os")).homedir(), ".bun", "install", "cache");
|
|
216
|
+
if (existsSync(bin) && existsSync(cacheRoot)) for (const d of readdirSync(cacheRoot)) {
|
|
217
|
+
if (!d.startsWith("node-datachannel@")) continue;
|
|
218
|
+
const dst = path.join(cacheRoot, d, "build", "Release");
|
|
219
|
+
mkdirSync(dst, { recursive: true });
|
|
220
|
+
const link = path.join(dst, "node_datachannel.node");
|
|
221
|
+
if (!existsSync(link)) symlinkSync(bin, link);
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
async function ndPackageDir() {
|
|
225
|
+
try {
|
|
226
|
+
const path = (await import("path")).default;
|
|
227
|
+
const { createRequire } = await import("module");
|
|
228
|
+
const require = createRequire(import.meta.url);
|
|
229
|
+
return path.dirname(require.resolve("node-datachannel/package.json"));
|
|
230
|
+
} catch {
|
|
231
|
+
return null;
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
async function ensureAddon(ndDir) {
|
|
235
|
+
const { existsSync } = await import("fs");
|
|
236
|
+
const path = (await import("path")).default;
|
|
237
|
+
if (existsSync(path.join(ndDir, "build", "Release", "node_datachannel.node"))) return;
|
|
238
|
+
try {
|
|
239
|
+
const { createRequire } = await import("module");
|
|
240
|
+
const binJs = createRequire(import.meta.url).resolve("prebuild-install/bin.js", { paths: [ndDir] });
|
|
241
|
+
const { spawnSync } = await import("child_process");
|
|
242
|
+
process.stderr.write("fetching node-datachannel prebuilt binary (one-time)…\n");
|
|
243
|
+
spawnSync(process.execPath, [
|
|
244
|
+
binJs,
|
|
245
|
+
"-r",
|
|
246
|
+
"napi"
|
|
247
|
+
], {
|
|
248
|
+
cwd: ndDir,
|
|
249
|
+
stdio: "ignore"
|
|
250
|
+
});
|
|
251
|
+
} catch {}
|
|
252
|
+
}
|
|
253
|
+
async function importRTC() {
|
|
254
|
+
const ndDir = await ndPackageDir();
|
|
255
|
+
if (ndDir) await ensureAddon(ndDir);
|
|
256
|
+
try {
|
|
257
|
+
return (await import("node-datachannel/polyfill")).RTCPeerConnection;
|
|
258
|
+
} catch (firstErr) {
|
|
259
|
+
await linkFromBunCache().catch(() => {});
|
|
260
|
+
try {
|
|
261
|
+
return (await import("node-datachannel/polyfill")).RTCPeerConnection;
|
|
262
|
+
} catch {
|
|
263
|
+
throw firstErr;
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
/** Start the share bridge. Resolves once signaling is connected; runs until the
|
|
268
|
+
* process exits, reconnecting signaling on drop. Returns the shareable link. */
|
|
269
|
+
async function startShare(opts) {
|
|
270
|
+
opts.url;
|
|
271
|
+
const sighost = opts.sighost ?? DEFAULT_SIGHOST;
|
|
272
|
+
const { room, token, host } = opts.url ? parseShareUrl(opts.url) : {
|
|
273
|
+
room: "r" + randomBytes(3).toString("hex"),
|
|
274
|
+
token: `${MARKER}${randomBytes(32).toString("hex")}`,
|
|
275
|
+
host: sighost
|
|
276
|
+
};
|
|
277
|
+
const { s: S, v2 } = parseSecret(token);
|
|
278
|
+
if (!v2) throw new Error("refusing to host an unencrypted room — delete ~/.agent-yes/.share-room to rotate to an encrypted link");
|
|
279
|
+
const authToken = await deriveAuthToken(S, room, host);
|
|
280
|
+
const RTCPeerConnection = await importRTC();
|
|
281
|
+
const wsScheme = host.startsWith("localhost") || host.startsWith("127.") ? "ws" : "wss";
|
|
282
|
+
const link = `${host === "s.agent-yes.com" ? "https://agent-yes.com" : "http://localhost:7778"}/#${room}:${MARKER}${S}${host === "s.agent-yes.com" ? "" : "@" + host}`;
|
|
283
|
+
const peers = /* @__PURE__ */ new Map();
|
|
284
|
+
let closed = false;
|
|
285
|
+
let currentWs;
|
|
286
|
+
const connectSignaling = (onReady) => {
|
|
287
|
+
if (closed) return;
|
|
288
|
+
const ws = new WebSocket(`${wsScheme}://${host}/${room}`, [SUB]);
|
|
289
|
+
currentWs = ws;
|
|
290
|
+
let ready = false;
|
|
291
|
+
ws.onopen = () => {
|
|
292
|
+
ws.send(JSON.stringify({
|
|
293
|
+
type: "hello",
|
|
294
|
+
role: "host",
|
|
295
|
+
v: 2,
|
|
296
|
+
token: authToken
|
|
297
|
+
}));
|
|
298
|
+
ready = true;
|
|
299
|
+
onReady();
|
|
300
|
+
};
|
|
301
|
+
ws.onmessage = async (ev) => {
|
|
302
|
+
if (closed) return;
|
|
303
|
+
const m = JSON.parse(ev.data);
|
|
304
|
+
if (m.type === "peer-join") startPeer(ws, m.peer);
|
|
305
|
+
else if (m.type === "answer") {
|
|
306
|
+
const peer = peers.get(m.from);
|
|
307
|
+
if (!peer) return;
|
|
308
|
+
try {
|
|
309
|
+
await peer.pc.setRemoteDescription({
|
|
310
|
+
type: "answer",
|
|
311
|
+
sdp: m.sdp
|
|
312
|
+
});
|
|
313
|
+
peer.th = await computeTranscriptHash(peer.pc.localDescription.sdp, peer.pc.remoteDescription.sdp);
|
|
314
|
+
const { keyH2C, keyC2H } = await deriveDirKeys(S, peer.th);
|
|
315
|
+
peer.keyH2C = keyH2C;
|
|
316
|
+
peer.keyC2H = keyC2H;
|
|
317
|
+
peer.resolveKeys();
|
|
318
|
+
} catch {
|
|
319
|
+
closePeer(m.from);
|
|
320
|
+
}
|
|
321
|
+
} else if (m.type === "candidate") await peers.get(m.from)?.pc.addIceCandidate(m.candidate).catch(() => {});
|
|
322
|
+
else if (m.type === "peer-leave") closePeer(m.peer);
|
|
323
|
+
};
|
|
324
|
+
ws.onclose = (ev) => {
|
|
325
|
+
if (closed) return;
|
|
326
|
+
if (ev?.code === 1008) {
|
|
327
|
+
closed = true;
|
|
328
|
+
process.stderr.write("[share] room rejected by signaling server — delete ~/.agent-yes/.share-room to rotate the room\n");
|
|
329
|
+
return;
|
|
330
|
+
}
|
|
331
|
+
setTimeout(() => connectSignaling(() => {}), ready ? 1500 : 4e3);
|
|
332
|
+
};
|
|
333
|
+
ws.onerror = () => {};
|
|
334
|
+
return ws;
|
|
335
|
+
};
|
|
336
|
+
function startPeer(ws, peerId) {
|
|
337
|
+
const pc = new RTCPeerConnection({ iceServers: ICE });
|
|
338
|
+
let resolveKeys;
|
|
339
|
+
const keysReady = new Promise((r) => resolveKeys = r);
|
|
340
|
+
const peer = {
|
|
341
|
+
pc,
|
|
342
|
+
aborts: /* @__PURE__ */ new Map(),
|
|
343
|
+
send: { sendCtr: 0n },
|
|
344
|
+
recv: { lastSeen: -1n },
|
|
345
|
+
keysReady,
|
|
346
|
+
resolveKeys,
|
|
347
|
+
myNonce: randomHex(16),
|
|
348
|
+
confirmedIn: false,
|
|
349
|
+
confirmedOut: false,
|
|
350
|
+
confirmed: false,
|
|
351
|
+
recvChain: Promise.resolve(),
|
|
352
|
+
sendChain: Promise.resolve()
|
|
353
|
+
};
|
|
354
|
+
peers.set(peerId, peer);
|
|
355
|
+
pc.onicecandidate = (e) => {
|
|
356
|
+
if (e.candidate) ws.send(JSON.stringify({
|
|
357
|
+
type: "candidate",
|
|
358
|
+
to: peerId,
|
|
359
|
+
candidate: e.candidate
|
|
360
|
+
}));
|
|
361
|
+
};
|
|
362
|
+
pc.onconnectionstatechange = () => {
|
|
363
|
+
if ([
|
|
364
|
+
"failed",
|
|
365
|
+
"closed",
|
|
366
|
+
"disconnected"
|
|
367
|
+
].includes(pc.connectionState)) closePeer(peerId);
|
|
368
|
+
};
|
|
369
|
+
const dc = pc.createDataChannel("api");
|
|
370
|
+
dc.binaryType = "arraybuffer";
|
|
371
|
+
dc.onopen = async () => {
|
|
372
|
+
try {
|
|
373
|
+
await peer.keysReady;
|
|
374
|
+
enqueueSeal(peerId, dc, peer, FLAG_CONFIRM, {
|
|
375
|
+
t: "confirm",
|
|
376
|
+
nonce: peer.myNonce
|
|
377
|
+
});
|
|
378
|
+
peer.confirmTimer = setTimeout(() => {
|
|
379
|
+
if (!peer.confirmed) closePeer(peerId);
|
|
380
|
+
}, CONFIRM_TIMEOUT_MS);
|
|
381
|
+
} catch {
|
|
382
|
+
closePeer(peerId);
|
|
383
|
+
}
|
|
384
|
+
};
|
|
385
|
+
dc.onmessage = (e) => {
|
|
386
|
+
peer.recvChain = peer.recvChain.then(() => onFrame(peerId, dc, peer, e.data)).catch(() => {});
|
|
387
|
+
};
|
|
388
|
+
pc.createOffer().then((o) => pc.setLocalDescription(o)).then(() => ws.send(JSON.stringify({
|
|
389
|
+
type: "offer",
|
|
390
|
+
to: peerId,
|
|
391
|
+
sdp: pc.localDescription.sdp
|
|
392
|
+
})));
|
|
393
|
+
}
|
|
394
|
+
function closePeer(peerId) {
|
|
395
|
+
const p = peers.get(peerId);
|
|
396
|
+
if (!p) return;
|
|
397
|
+
if (p.confirmTimer) clearTimeout(p.confirmTimer);
|
|
398
|
+
for (const a of p.aborts.values()) a.abort();
|
|
399
|
+
try {
|
|
400
|
+
p.pc.close();
|
|
401
|
+
} catch {}
|
|
402
|
+
peers.delete(peerId);
|
|
403
|
+
}
|
|
404
|
+
function enqueueSeal(peerId, dc, peer, flags, obj) {
|
|
405
|
+
peer.sendChain = peer.sendChain.then(async () => {
|
|
406
|
+
if (dc.readyState !== "open" || !peer.keyH2C || !peer.th) return;
|
|
407
|
+
let frame;
|
|
408
|
+
try {
|
|
409
|
+
frame = await seal(peer.keyH2C, peer.send, flags, peer.th, packEnvelope(obj));
|
|
410
|
+
} catch {
|
|
411
|
+
closePeer(peerId);
|
|
412
|
+
return;
|
|
413
|
+
}
|
|
414
|
+
try {
|
|
415
|
+
dc.send(frame);
|
|
416
|
+
} catch {}
|
|
417
|
+
});
|
|
418
|
+
return peer.sendChain;
|
|
419
|
+
}
|
|
420
|
+
async function onFrame(peerId, dc, peer, data) {
|
|
421
|
+
if (!peers.has(peerId)) return;
|
|
422
|
+
if (typeof data === "string" || !peer.keyC2H || !peer.th) return closePeer(peerId);
|
|
423
|
+
let env;
|
|
424
|
+
try {
|
|
425
|
+
const { plaintext } = await open$1(peer.keyC2H, data, peer.th, peer.recv);
|
|
426
|
+
env = unpackEnvelope(plaintext);
|
|
427
|
+
} catch {
|
|
428
|
+
return closePeer(peerId);
|
|
429
|
+
}
|
|
430
|
+
if (!peer.confirmed) {
|
|
431
|
+
if (!env || env.t !== "confirm") return closePeer(peerId);
|
|
432
|
+
if (typeof env.nonce === "string" && !peer.confirmedOut) {
|
|
433
|
+
await enqueueSeal(peerId, dc, peer, FLAG_CONFIRM, {
|
|
434
|
+
t: "confirm",
|
|
435
|
+
nonce: peer.myNonce,
|
|
436
|
+
echo: env.nonce
|
|
437
|
+
});
|
|
438
|
+
peer.confirmedOut = true;
|
|
439
|
+
}
|
|
440
|
+
if (env.echo && env.echo === peer.myNonce) peer.confirmedIn = true;
|
|
441
|
+
if (peer.confirmedIn && peer.confirmedOut) {
|
|
442
|
+
peer.confirmed = true;
|
|
443
|
+
if (peer.confirmTimer) clearTimeout(peer.confirmTimer);
|
|
444
|
+
}
|
|
445
|
+
return;
|
|
446
|
+
}
|
|
447
|
+
if (!env || env.t === "confirm") return;
|
|
448
|
+
onReq(peerId, dc, peer, env);
|
|
449
|
+
}
|
|
450
|
+
async function onReq(peerId, dc, peer, req) {
|
|
451
|
+
if (req.t === "abort") {
|
|
452
|
+
peer.aborts.get(req.id)?.abort();
|
|
453
|
+
peer.aborts.delete(req.id);
|
|
454
|
+
return;
|
|
455
|
+
}
|
|
456
|
+
if (req.t !== "req") return;
|
|
457
|
+
const { id, method, path: p, body } = req;
|
|
458
|
+
const ac = new AbortController();
|
|
459
|
+
peer.aborts.set(id, ac);
|
|
460
|
+
try {
|
|
461
|
+
const res = await opts.localFetch(new Request(`http://ay.local${p}`, {
|
|
462
|
+
method,
|
|
463
|
+
headers: {
|
|
464
|
+
Authorization: `Bearer ${opts.apiToken}`,
|
|
465
|
+
...body ? { "Content-Type": "application/json" } : {}
|
|
466
|
+
},
|
|
467
|
+
body: body ?? void 0,
|
|
468
|
+
signal: ac.signal
|
|
469
|
+
}));
|
|
470
|
+
enqueueSeal(peerId, dc, peer, 0, {
|
|
471
|
+
t: "res",
|
|
472
|
+
id,
|
|
473
|
+
status: res.status,
|
|
474
|
+
ct: res.headers.get("content-type") ?? ""
|
|
475
|
+
});
|
|
476
|
+
const reader = res.body.getReader();
|
|
477
|
+
const dec = new TextDecoder();
|
|
478
|
+
let seq = 0;
|
|
479
|
+
for (;;) {
|
|
480
|
+
const { done, value } = await reader.read();
|
|
481
|
+
if (done) break;
|
|
482
|
+
const text = dec.decode(value, { stream: true });
|
|
483
|
+
for (let i = 0; i < text.length; i += MAX_CHUNK) enqueueSeal(peerId, dc, peer, 0, {
|
|
484
|
+
t: "data",
|
|
485
|
+
id,
|
|
486
|
+
seq: seq++,
|
|
487
|
+
chunk: text.slice(i, i + MAX_CHUNK)
|
|
488
|
+
});
|
|
489
|
+
}
|
|
490
|
+
enqueueSeal(peerId, dc, peer, 0, {
|
|
491
|
+
t: "end",
|
|
492
|
+
id,
|
|
493
|
+
seq
|
|
494
|
+
});
|
|
495
|
+
} catch (e) {
|
|
496
|
+
if (e.name !== "AbortError") enqueueSeal(peerId, dc, peer, 0, {
|
|
497
|
+
t: "end",
|
|
498
|
+
id,
|
|
499
|
+
error: String(e.message ?? e)
|
|
500
|
+
});
|
|
501
|
+
} finally {
|
|
502
|
+
peer.aborts.delete(id);
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
await new Promise((resolve) => connectSignaling(resolve));
|
|
506
|
+
const close = () => {
|
|
507
|
+
closed = true;
|
|
508
|
+
try {
|
|
509
|
+
currentWs?.close();
|
|
510
|
+
} catch {}
|
|
511
|
+
for (const peerId of [...peers.keys()]) closePeer(peerId);
|
|
512
|
+
};
|
|
513
|
+
return {
|
|
514
|
+
room,
|
|
515
|
+
link,
|
|
516
|
+
close
|
|
517
|
+
};
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
//#endregion
|
|
521
|
+
export { loadOrCreateShareRoom, startShare };
|
|
522
|
+
//# sourceMappingURL=share-B6QVr5D1.js.map
|
|
@@ -231,11 +231,11 @@ async function runSubcommand(argv) {
|
|
|
231
231
|
case "restart": return await cmdRestart(rest);
|
|
232
232
|
case "note": return await cmdNote(rest);
|
|
233
233
|
case "serve": {
|
|
234
|
-
const { cmdServe } = await import("./serve-
|
|
234
|
+
const { cmdServe } = await import("./serve-D2czcYNC.js");
|
|
235
235
|
return cmdServe(rest);
|
|
236
236
|
}
|
|
237
237
|
case "setup": {
|
|
238
|
-
const { cmdSetup } = await import("./setup-
|
|
238
|
+
const { cmdSetup } = await import("./setup-f1FIFcZm.js");
|
|
239
239
|
return cmdSetup(rest);
|
|
240
240
|
}
|
|
241
241
|
case "remote": {
|
|
@@ -1680,4 +1680,4 @@ async function cmdStatus(rest) {
|
|
|
1680
1680
|
|
|
1681
1681
|
//#endregion
|
|
1682
1682
|
export { finalizedLines as a, listRecords as c, renderRawLog as d, resolveOne as f, writeToIpc as g, stopTipForCli as h, cursorAbs as i, matchKeyword as l, snapshotStatus as m, cmdHelp as n, isPidAlive as o, runSubcommand as p, controlCodeFromName as r, isSubcommand as s, GRACEFUL_EXIT_COMMANDS as t, readNotes as u };
|
|
1683
|
-
//# sourceMappingURL=subcommands-
|
|
1683
|
+
//# sourceMappingURL=subcommands-CzpZQHO6.js.map
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import "./logger-B9h0djqx.js";
|
|
2
2
|
import "./globalPidIndex-gZuTvTBs.js";
|
|
3
3
|
import "./remotes-BufkGk0e.js";
|
|
4
|
-
import { a as finalizedLines, c as listRecords, d as renderRawLog, f as resolveOne, g as writeToIpc, h as stopTipForCli, i as cursorAbs, l as matchKeyword, m as snapshotStatus, n as cmdHelp, o as isPidAlive, p as runSubcommand, r as controlCodeFromName, s as isSubcommand, t as GRACEFUL_EXIT_COMMANDS, u as readNotes } from "./subcommands-
|
|
4
|
+
import { a as finalizedLines, c as listRecords, d as renderRawLog, f as resolveOne, g as writeToIpc, h as stopTipForCli, i as cursorAbs, l as matchKeyword, m as snapshotStatus, n as cmdHelp, o as isPidAlive, p as runSubcommand, r as controlCodeFromName, s as isSubcommand, t as GRACEFUL_EXIT_COMMANDS, u as readNotes } from "./subcommands-CzpZQHO6.js";
|
|
5
5
|
|
|
6
6
|
export { cmdHelp, isSubcommand, runSubcommand };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { n as logger, t as addTransport } from "./logger-B9h0djqx.js";
|
|
2
|
-
import { r as getInstalledPackage } from "./versionChecker-
|
|
2
|
+
import { r as getInstalledPackage } from "./versionChecker-CAtpgnoQ.js";
|
|
3
3
|
import { t as agentYesHome } from "./agentYesHome-BvaUOzCV.js";
|
|
4
4
|
import { i as shouldUseLock, r as releaseLock, t as acquireLock } from "./runningLock-CJxsoGdb.js";
|
|
5
5
|
import { t as PidStore } from "./pidStore-B5vBu8Px.js";
|
|
@@ -1715,4 +1715,4 @@ function sleep(ms) {
|
|
|
1715
1715
|
|
|
1716
1716
|
//#endregion
|
|
1717
1717
|
export { removeControlCharacters as a, AgentContext as i, agentYes as n, config as r, CLIS_CONFIG as t };
|
|
1718
|
-
//# sourceMappingURL=ts-
|
|
1718
|
+
//# sourceMappingURL=ts-D91dm1E0.js.map
|
|
@@ -7,7 +7,7 @@ import { fileURLToPath } from "url";
|
|
|
7
7
|
|
|
8
8
|
//#region package.json
|
|
9
9
|
var name = "agent-yes";
|
|
10
|
-
var version = "1.
|
|
10
|
+
var version = "1.121.0";
|
|
11
11
|
|
|
12
12
|
//#endregion
|
|
13
13
|
//#region ts/versionChecker.ts
|
|
@@ -221,4 +221,4 @@ async function displayVersion() {
|
|
|
221
221
|
|
|
222
222
|
//#endregion
|
|
223
223
|
export { versionString as i, displayVersion as n, getInstalledPackage as r, checkAndAutoUpdate as t };
|
|
224
|
-
//# sourceMappingURL=versionChecker-
|
|
224
|
+
//# sourceMappingURL=versionChecker-CAtpgnoQ.js.map
|