agent-yes 1.300.3 → 1.300.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/{SUPPORTED_CLIS-CWJr4TJH.js → SUPPORTED_CLIS-BIg_X-jE.js} +2 -2
- package/dist/{SUPPORTED_CLIS-ChSO8FiS.js → SUPPORTED_CLIS-D7lOxOnw.js} +3 -3
- package/dist/{agentShare-NkW0b0mg.js → agentShare-BfHUZgk4.js} +4 -4
- package/dist/{callback-CjlaFXp1.js → callback-COR0F2eB.js} +3 -3
- package/dist/{callback-B8CUyag4.js → callback-yWhCmi4k.js} +3 -3
- package/dist/{channels-aYwLMbFV.js → channels-rhxQArqN.js} +2 -2
- package/dist/cli.js +5 -5
- package/dist/{cmdPs-C8DIl8V6.js → cmdPs-B3jTE4f3.js} +3 -3
- package/dist/index.js +2 -2
- package/dist/{notifyDaemon-DWIfzEE7.js → notifyDaemon-BIo7Nkk2.js} +3 -3
- package/dist/{parentPingLoop-Bh3KuFcW.js → parentPingLoop-9T4Pzp6c.js} +2 -2
- package/dist/{remotes-B4v0Nowo.js → remotes-B4CNXwDS.js} +2 -2
- package/dist/{remotes-DnMQWaqQ.js → remotes-CQTEY8Gt.js} +1 -1
- package/dist/{rustBinary-gI_r3g9K.js → rustBinary-CJXUPUWd.js} +48 -5
- package/dist/rustBinary-FhGG3Yfl.js +4 -0
- package/dist/{schedule-DryC--yx.js → schedule-DmijwnTA.js} +4 -4
- package/dist/{serve-DVoYVgBo.js → serve-F5tXYO0-.js} +99 -32
- package/dist/{serveRust-DDQiZmMf.js → serveRust-BAawe83i.js} +16 -2
- package/dist/{setup--1zRHaGW.js → setup-mCb1JbTX.js} +2 -2
- package/dist/{share-C9oGvjXT.js → share-CLataFnI.js} +18 -12
- package/dist/share-nmgSIjYP.js +4 -0
- package/dist/{shareCmd-BI3hRWGO.js → shareCmd-aOKimJeT.js} +25 -7
- package/dist/{subcommands-BviFOQZE.js → subcommands-DRq0MgSm.js} +2 -2
- package/dist/{subcommands-UWLkF5pq.js → subcommands-Ddo2TYZs.js} +404 -77
- package/dist/{terminal-DviH1E3C.js → terminal-DEXrWOa9.js} +2 -2
- package/dist/trayApp-0RVjo43f.js +5 -0
- package/dist/{trayApp-PJrwfyDs.js → trayApp-BUXx7cES.js} +2 -2
- package/dist/{ts--JmSY117.js → ts-CRbycTni.js} +5 -5
- package/dist/{versionChecker-CCGSbjio.js → versionChecker-DeQEhRGB.js} +2 -2
- package/dist/{webrtcRemote-Cd4vTrgv.js → webrtcRemote-Cy5kB8aR.js} +115 -14
- package/dist/{widget-DgBDIGRQ.js → widget-DneXqnL8.js} +3 -3
- package/dist/{ws-DnBg8-g-.js → ws-DPw1lVTi.js} +3 -3
- package/dist/{ws-dc7MP054.js → ws-Dr-0Ckq7.js} +2 -2
- package/package.json +1 -1
- package/ts/remoteCache.bun.spec.ts +191 -0
- package/ts/remoteCache.spec.ts +191 -0
- package/ts/remoteCache.ts +193 -0
- package/ts/rustBinary.bun.spec.ts +39 -2
- package/ts/rustBinary.spec.ts +53 -2
- package/ts/rustBinary.ts +61 -3
- package/ts/serve.spec.ts +103 -0
- package/ts/serve.ts +100 -15
- package/ts/serveRust.spec.ts +24 -1
- package/ts/serveRust.ts +19 -0
- package/ts/share.bun.spec.ts +54 -2
- package/ts/share.spec.ts +54 -2
- package/ts/share.ts +40 -15
- package/ts/shareCmd.ts +33 -2
- package/ts/strayServe.ts +1 -0
- package/ts/subcommands.spec.ts +36 -3
- package/ts/subcommands.ts +384 -98
- package/ts/webrtcRemote.ts +66 -20
- package/ts/webrtcSignal.bun.spec.ts +120 -0
- package/ts/webrtcSignal.spec.ts +120 -0
- package/ts/webrtcSignal.ts +143 -0
- package/dist/rustBinary-BNmAJEBb.js +0 -4
- package/dist/share-Bmnd_qT0.js +0 -4
- package/dist/trayApp-BDIb8fOj.js +0 -5
|
@@ -98,7 +98,7 @@ async function cmdTermMint(args) {
|
|
|
98
98
|
if (flags.ro && flags.interactive) throw new Error("--ro and --interactive are mutually exclusive");
|
|
99
99
|
const ttlSec = parseTtlSec(typeof flags.ttl === "string" ? flags.ttl : "15m");
|
|
100
100
|
const canSend = flags.interactive === true;
|
|
101
|
-
const { mintScopedTermToken } = await import("./serve-
|
|
101
|
+
const { mintScopedTermToken } = await import("./serve-F5tXYO0-.js");
|
|
102
102
|
const r = await mintScopedTermToken(pid, {
|
|
103
103
|
ttlSec,
|
|
104
104
|
canSend
|
|
@@ -135,4 +135,4 @@ async function cmdTerm(args) {
|
|
|
135
135
|
|
|
136
136
|
//#endregion
|
|
137
137
|
export { cmdTerm };
|
|
138
|
-
//# sourceMappingURL=terminal-
|
|
138
|
+
//# sourceMappingURL=terminal-DEXrWOa9.js.map
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { c as findTrayLauncher } from "./rustBinary-CJXUPUWd.js";
|
|
2
2
|
import { t as agentYesHome } from "./agentYesHome-BNtn19J4.js";
|
|
3
3
|
import { existsSync } from "node:fs";
|
|
4
4
|
import path from "node:path";
|
|
@@ -97,4 +97,4 @@ async function cmdTray(args) {
|
|
|
97
97
|
|
|
98
98
|
//#endregion
|
|
99
99
|
export { trayHiddenMarker as a, launchTray as i, hasDesktop as n, isTrayHidden as r, cmdTray as t };
|
|
100
|
-
//# sourceMappingURL=trayApp-
|
|
100
|
+
//# sourceMappingURL=trayApp-BUXx7cES.js.map
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { n as __esmMin, r as __exportAll } from "./chunk-cZBX9HZv.js";
|
|
2
2
|
import { n as logger, t as addTransport } from "./logger-CDIsZ-Pp.js";
|
|
3
|
-
import { i as getInstalledPackage } from "./versionChecker-
|
|
3
|
+
import { i as getInstalledPackage } from "./versionChecker-DeQEhRGB.js";
|
|
4
4
|
import { t as agentYesHome } from "./agentYesHome-BNtn19J4.js";
|
|
5
5
|
import { u as removeControlCharacters } from "./todoAutomation-CbVVS4re.js";
|
|
6
6
|
import { i as shouldUseLock, r as releaseLock, t as acquireLock } from "./runningLock-BOIPD_Vs.js";
|
|
@@ -24,7 +24,7 @@ import sflow from "sflow";
|
|
|
24
24
|
import xterm from "@xterm/headless";
|
|
25
25
|
import { createServer } from "net";
|
|
26
26
|
import { execSync as execSync$1 } from "node:child_process";
|
|
27
|
-
import { accessSync, constants as constants$1, existsSync as existsSync$1, statSync as statSync$1 } from "node:fs";
|
|
27
|
+
import { accessSync as accessSync$1, constants as constants$1, existsSync as existsSync$1, statSync as statSync$1 } from "node:fs";
|
|
28
28
|
import path$1 from "node:path";
|
|
29
29
|
import os$1 from "node:os";
|
|
30
30
|
import { readFile as readFile$1 } from "node:fs/promises";
|
|
@@ -897,7 +897,7 @@ async function applyAgentNice(pid, env = process.env) {
|
|
|
897
897
|
function isExecutableFile(candidate) {
|
|
898
898
|
try {
|
|
899
899
|
if (!statSync$1(candidate).isFile()) return false;
|
|
900
|
-
accessSync(candidate, constants$1.X_OK);
|
|
900
|
+
accessSync$1(candidate, constants$1.X_OK);
|
|
901
901
|
return true;
|
|
902
902
|
} catch {
|
|
903
903
|
return false;
|
|
@@ -2086,7 +2086,7 @@ async function agentYes({ cli, cliArgs = [], skipPermissions = false, prompt, ro
|
|
|
2086
2086
|
}, 100);
|
|
2087
2087
|
const cleanupHeartbeat = () => clearInterval(heartbeatInterval);
|
|
2088
2088
|
shell.onExit(cleanupHeartbeat);
|
|
2089
|
-
const { startParentPingLoop } = await import("./parentPingLoop-
|
|
2089
|
+
const { startParentPingLoop } = await import("./parentPingLoop-9T4Pzp6c.js");
|
|
2090
2090
|
const parentPingLoop = startParentPingLoop({
|
|
2091
2091
|
parentPid,
|
|
2092
2092
|
selfWrapperPid: process.pid,
|
|
@@ -2349,4 +2349,4 @@ function sleep(ms) {
|
|
|
2349
2349
|
|
|
2350
2350
|
//#endregion
|
|
2351
2351
|
export { hasTodoStore as a, permissionBadge as c, answerAsk as i, AgentContext as l, agentYes as n, listAsks as o, config as r, listAsksForProject as s, CLIS_CONFIG as t, CLAUDE_SESSION_PIN_ENV as u };
|
|
2352
|
-
//# sourceMappingURL=ts
|
|
2352
|
+
//# sourceMappingURL=ts-CRbycTni.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.300.
|
|
10
|
+
var version = "1.300.4";
|
|
11
11
|
|
|
12
12
|
//#endregion
|
|
13
13
|
//#region ts/versionChecker.ts
|
|
@@ -285,4 +285,4 @@ async function displayVersion() {
|
|
|
285
285
|
|
|
286
286
|
//#endregion
|
|
287
287
|
export { versionString as a, getInstalledPackage as i, compareVersions as n, displayVersion as r, checkAndAutoUpdate as t };
|
|
288
|
-
//# sourceMappingURL=versionChecker-
|
|
288
|
+
//# sourceMappingURL=versionChecker-DeQEhRGB.js.map
|
|
@@ -36,6 +36,78 @@ function signalingFailureHint(cause, probe, host) {
|
|
|
36
36
|
}
|
|
37
37
|
}
|
|
38
38
|
|
|
39
|
+
//#endregion
|
|
40
|
+
//#region ts/webrtcSignal.ts
|
|
41
|
+
var ConnectError = class extends Error {
|
|
42
|
+
constructor(phase, message) {
|
|
43
|
+
super(message);
|
|
44
|
+
this.phase = phase;
|
|
45
|
+
this.name = "ConnectError";
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
/** Classify one signaling frame against the current state. */
|
|
49
|
+
function reduceSignal(state, m) {
|
|
50
|
+
if (!m || typeof m !== "object") return { kind: "ignore" };
|
|
51
|
+
switch (m.type) {
|
|
52
|
+
case "welcome":
|
|
53
|
+
if (m.hostPresent === false) return {
|
|
54
|
+
kind: "fail",
|
|
55
|
+
error: new ConnectError("no-host", "the room is open but no host is attached to it")
|
|
56
|
+
};
|
|
57
|
+
return { kind: "ignore" };
|
|
58
|
+
case "offer":
|
|
59
|
+
if (state.offered) return { kind: "duplicate-offer" };
|
|
60
|
+
return {
|
|
61
|
+
kind: "offer",
|
|
62
|
+
sdp: m.sdp,
|
|
63
|
+
iceServers: m.iceServers || [],
|
|
64
|
+
from: m.from
|
|
65
|
+
};
|
|
66
|
+
case "candidate": return {
|
|
67
|
+
kind: "candidate",
|
|
68
|
+
candidate: m.candidate,
|
|
69
|
+
queue: !state.offered
|
|
70
|
+
};
|
|
71
|
+
default: return { kind: "ignore" };
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
/** The error for a socket that closed before the channel was confirmed. */
|
|
75
|
+
function closeError(state, code, reason) {
|
|
76
|
+
const why = `signaling closed (code ${code}${reason ? `: ${reason}` : ""})`;
|
|
77
|
+
if (!state.opened) return new ConnectError("ws-not-open", `${why} before the socket opened`);
|
|
78
|
+
if (code === 1008 || reason) return new ConnectError("rejected", why);
|
|
79
|
+
if (!state.offered) return new ConnectError("no-host", `${why} before the host offered`);
|
|
80
|
+
return new ConnectError("ice-timeout", `${why} during the WebRTC handshake`);
|
|
81
|
+
}
|
|
82
|
+
/** The error for the connect deadline expiring. */
|
|
83
|
+
function timeoutError(state, timeoutMs) {
|
|
84
|
+
const s = `${Math.round(timeoutMs / 1e3)}s`;
|
|
85
|
+
if (!state.opened) return new ConnectError("ws-not-open", `signaling did not open within ${s}`);
|
|
86
|
+
if (!state.offered) return new ConnectError("no-host", `no host answered the join within ${s}`);
|
|
87
|
+
return new ConnectError("ice-timeout", `no WebRTC data channel came up within ${s}`);
|
|
88
|
+
}
|
|
89
|
+
/** The error for a WebSocket `error` event. */
|
|
90
|
+
function socketError(state, detail) {
|
|
91
|
+
return state.opened ? new ConnectError("rejected", `signaling error after connect: ${detail}`) : new ConnectError("ws-not-open", `signaling error: ${detail}`);
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* The operator-facing explanation. `sandboxHint` is the HTTPS-probe-derived
|
|
95
|
+
* note from signalingHint.ts and is consulted ONLY for a socket that never
|
|
96
|
+
* opened: every later phase proves the WebSocket upgrade worked, so blaming a
|
|
97
|
+
* sandbox or proxy there would be wrong — and sent one reader down exactly
|
|
98
|
+
* that path.
|
|
99
|
+
*/
|
|
100
|
+
function describeConnectFailure(err, host, sandboxHint) {
|
|
101
|
+
const phase = err instanceof ConnectError ? err.phase : "ws-not-open";
|
|
102
|
+
const cause = err.message;
|
|
103
|
+
switch (phase) {
|
|
104
|
+
case "no-host": return Promise.resolve(`no host in the room at ${host}: ${cause}\n The signaling server is reachable and accepted the join — the daemon on the\n other machine is not attached to this room. There, run \`ay share status\`:\n if it prints a different link, the room rotated (or the daemon was\n reinstalled) and this saved remote is stale — re-add it with the new link.`);
|
|
105
|
+
case "rejected": return Promise.resolve(`join rejected by the signaling host ${host}: ${cause}\n The room id or secret in this saved remote no longer matches what the host\n serves (it rotated, or the link was copied from a different machine).\n On the host run \`ay share status\` and re-add the remote with that link.`);
|
|
106
|
+
case "ice-timeout": return Promise.resolve(`WebRTC handshake with the host behind ${host} failed: ${cause}\n Signaling worked and the host answered, so this is not a sandbox or proxy\n problem — the two machines could not open a data channel. Usual causes: a\n second host answering in the same room (on the host: \`ay serve status\`,\n and kill any stray \`ayrs serve\`), or ICE blocked between the networks.`);
|
|
107
|
+
default: return sandboxHint(cause);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
39
111
|
//#endregion
|
|
40
112
|
//#region ts/webrtcRemote.ts
|
|
41
113
|
const CONNECT_TIMEOUT_MS = 25e3;
|
|
@@ -54,6 +126,13 @@ var WebRtcConn = class {
|
|
|
54
126
|
confirmedIn = false;
|
|
55
127
|
confirmedOut = false;
|
|
56
128
|
confirmed = false;
|
|
129
|
+
sig = {
|
|
130
|
+
opened: false,
|
|
131
|
+
offered: false,
|
|
132
|
+
confirmed: false
|
|
133
|
+
};
|
|
134
|
+
earlyCandidates = [];
|
|
135
|
+
warnedDuplicateHost = false;
|
|
57
136
|
sendChain = Promise.resolve();
|
|
58
137
|
recvChain = Promise.resolve();
|
|
59
138
|
idCounter = 0;
|
|
@@ -67,7 +146,7 @@ var WebRtcConn = class {
|
|
|
67
146
|
this.resolveReady = res;
|
|
68
147
|
this.rejectReady = rej;
|
|
69
148
|
});
|
|
70
|
-
const timer = setTimeout(() => this.rejectReady(
|
|
149
|
+
const timer = setTimeout(() => this.rejectReady(timeoutError(this.sig, CONNECT_TIMEOUT_MS)), CONNECT_TIMEOUT_MS);
|
|
71
150
|
this.ready.then(() => clearTimeout(timer), () => clearTimeout(timer));
|
|
72
151
|
this.ws = this.dial();
|
|
73
152
|
}
|
|
@@ -75,6 +154,7 @@ var WebRtcConn = class {
|
|
|
75
154
|
const { room, host } = this.link;
|
|
76
155
|
const ws = new WebSocket(`wss://${host}/${room}`, [SIGNAL_SUBPROTOCOL]);
|
|
77
156
|
ws.onopen = async () => {
|
|
157
|
+
this.sig.opened = true;
|
|
78
158
|
const authToken = await deriveAuthToken(this.link.s, room, host);
|
|
79
159
|
ws.send(JSON.stringify({
|
|
80
160
|
type: "hello",
|
|
@@ -83,18 +163,36 @@ var WebRtcConn = class {
|
|
|
83
163
|
token: authToken
|
|
84
164
|
}));
|
|
85
165
|
};
|
|
86
|
-
ws.onerror = (e) => this.rejectReady(
|
|
87
|
-
ws.onclose = () => {
|
|
88
|
-
if (!this.confirmed) this.rejectReady(
|
|
166
|
+
ws.onerror = (e) => this.rejectReady(socketError(this.sig, String(e?.message ?? e)));
|
|
167
|
+
ws.onclose = (ev) => {
|
|
168
|
+
if (!this.confirmed) this.rejectReady(closeError(this.sig, Number(ev?.code ?? 0), String(ev?.reason ?? "")));
|
|
89
169
|
};
|
|
90
170
|
ws.onmessage = (ev) => void this.onSignal(ev);
|
|
91
171
|
return ws;
|
|
92
172
|
}
|
|
93
173
|
async onSignal(ev) {
|
|
94
174
|
const m = JSON.parse(typeof ev.data === "string" ? ev.data : await ev.data.text());
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
175
|
+
const action = reduceSignal(this.sig, m);
|
|
176
|
+
if (action.kind === "fail") {
|
|
177
|
+
this.rejectReady(action.error);
|
|
178
|
+
return;
|
|
179
|
+
}
|
|
180
|
+
if (action.kind === "duplicate-offer") {
|
|
181
|
+
if (!this.warnedDuplicateHost) {
|
|
182
|
+
this.warnedDuplicateHost = true;
|
|
183
|
+
process.stderr.write(`[webrtc] a second host offered in room ${this.link.room} — two hosts serve this room; on the host, stop the stray one (\`ay serve status\`)\n`);
|
|
184
|
+
}
|
|
185
|
+
return;
|
|
186
|
+
}
|
|
187
|
+
if (action.kind === "candidate") {
|
|
188
|
+
if (action.queue) this.earlyCandidates.push(action.candidate);
|
|
189
|
+
else if (this.pc) await this.pc.addIceCandidate(action.candidate).catch(() => {});
|
|
190
|
+
return;
|
|
191
|
+
}
|
|
192
|
+
if (action.kind === "offer") {
|
|
193
|
+
this.sig.offered = true;
|
|
194
|
+
this.hostPeer = action.from ?? null;
|
|
195
|
+
const pc = new RTCPeerConnection({ iceServers: action.iceServers || [] });
|
|
98
196
|
this.pc = pc;
|
|
99
197
|
pc.onicecandidate = (e) => {
|
|
100
198
|
if (e.candidate) this.ws.send(JSON.stringify({
|
|
@@ -117,11 +215,14 @@ var WebRtcConn = class {
|
|
|
117
215
|
};
|
|
118
216
|
await pc.setRemoteDescription({
|
|
119
217
|
type: "offer",
|
|
120
|
-
sdp:
|
|
218
|
+
sdp: action.sdp
|
|
121
219
|
});
|
|
220
|
+
const early = this.earlyCandidates;
|
|
221
|
+
this.earlyCandidates = [];
|
|
222
|
+
for (const c of early) await pc.addIceCandidate(c).catch(() => {});
|
|
122
223
|
const answer = await pc.createAnswer();
|
|
123
224
|
await pc.setLocalDescription(answer);
|
|
124
|
-
this.th = await computeTranscriptHash(
|
|
225
|
+
this.th = await computeTranscriptHash(action.sdp, pc.localDescription.sdp);
|
|
125
226
|
const keys = await deriveDirKeys(this.link.s, this.th);
|
|
126
227
|
this.keyC2H = keys.keyC2H;
|
|
127
228
|
this.keyH2C = keys.keyH2C;
|
|
@@ -130,7 +231,7 @@ var WebRtcConn = class {
|
|
|
130
231
|
to: this.hostPeer,
|
|
131
232
|
sdp: pc.localDescription.sdp
|
|
132
233
|
}));
|
|
133
|
-
}
|
|
234
|
+
}
|
|
134
235
|
}
|
|
135
236
|
enqueueSeal(flags, obj) {
|
|
136
237
|
this.sendChain = this.sendChain.then(async () => {
|
|
@@ -164,6 +265,7 @@ var WebRtcConn = class {
|
|
|
164
265
|
if (env.echo && env.echo === this.myNonce) this.confirmedIn = true;
|
|
165
266
|
if (this.confirmedIn && this.confirmedOut) {
|
|
166
267
|
this.confirmed = true;
|
|
268
|
+
this.sig.confirmed = true;
|
|
167
269
|
this.resolveReady();
|
|
168
270
|
}
|
|
169
271
|
return;
|
|
@@ -260,9 +362,8 @@ async function startWebrtcBridge(link) {
|
|
|
260
362
|
try {
|
|
261
363
|
await conn.ready;
|
|
262
364
|
} catch (e) {
|
|
263
|
-
const
|
|
264
|
-
|
|
265
|
-
throw new Error(signalingFailureHint(cause, probe, parsed.host));
|
|
365
|
+
const err = e instanceof Error ? e : new Error(String(e));
|
|
366
|
+
throw new Error(await describeConnectFailure(err, parsed.host, async (cause) => signalingFailureHint(cause, await probeSignalingHost(parsed.host), parsed.host)));
|
|
266
367
|
}
|
|
267
368
|
const server = Bun.serve({
|
|
268
369
|
port: 0,
|
|
@@ -297,4 +398,4 @@ async function startWebrtcBridge(link) {
|
|
|
297
398
|
|
|
298
399
|
//#endregion
|
|
299
400
|
export { startWebrtcBridge };
|
|
300
|
-
//# sourceMappingURL=webrtcRemote-
|
|
401
|
+
//# sourceMappingURL=webrtcRemote-Cy5kB8aR.js.map
|
|
@@ -28,7 +28,7 @@ function parseFlags(args, known) {
|
|
|
28
28
|
}
|
|
29
29
|
/** Resolve the local daemon base URL + token (flags override discovery). */
|
|
30
30
|
async function daemonTarget(flags) {
|
|
31
|
-
const { resolveDaemonHttpBase, loadTokenReadOnly } = await import("./serve-
|
|
31
|
+
const { resolveDaemonHttpBase, loadTokenReadOnly } = await import("./serve-F5tXYO0-.js");
|
|
32
32
|
const base = typeof flags.base === "string" ? flags.base : await resolveDaemonHttpBase();
|
|
33
33
|
if (!base) throw new Error("no running ay serve daemon found — start `ay serve` or pass --base <url> (e.g. http://127.0.0.1:PORT)");
|
|
34
34
|
const token = typeof flags.token === "string" ? flags.token : await loadTokenReadOnly() ?? "";
|
|
@@ -186,7 +186,7 @@ async function cmdMint(args) {
|
|
|
186
186
|
const bad = caps.filter((c) => !KNOWN_CAPS.has(c));
|
|
187
187
|
if (bad.length) throw new Error(`unknown cap(s): ${bad.join(", ")} (valid: ${[...KNOWN_CAPS].join(", ")})`);
|
|
188
188
|
const ttlSec = parseTtlSec(typeof flags.ttl === "string" ? flags.ttl : "15m");
|
|
189
|
-
const { mintScopedTermToken } = await import("./serve-
|
|
189
|
+
const { mintScopedTermToken } = await import("./serve-F5tXYO0-.js");
|
|
190
190
|
const r = await mintScopedTermToken(target, {
|
|
191
191
|
ttlSec,
|
|
192
192
|
caps
|
|
@@ -202,4 +202,4 @@ async function cmdMint(args) {
|
|
|
202
202
|
|
|
203
203
|
//#endregion
|
|
204
204
|
export { cmdMint, cmdWidget };
|
|
205
|
-
//# sourceMappingURL=widget-
|
|
205
|
+
//# sourceMappingURL=widget-DneXqnL8.js.map
|
|
@@ -5,10 +5,10 @@ import "./pidStore-DXWqzTSz.js";
|
|
|
5
5
|
import "./messageLog-Brx3w6zT.js";
|
|
6
6
|
import "./e2e-z1xpwSAg.js";
|
|
7
7
|
import "./configShared-DKTgiz7K.js";
|
|
8
|
-
import "./subcommands-
|
|
8
|
+
import "./subcommands-Ddo2TYZs.js";
|
|
9
9
|
import "./notifyStore-2SWKGwZI.js";
|
|
10
10
|
import "./webrtcLink-DFRyWNMs.js";
|
|
11
|
-
import "./remotes-
|
|
12
|
-
import { a as isPathInside, c as walkWorkspaces, i as importProvisionModule, l as workspaceStatus, n as cmdWs, o as loadProvision, r as collectWorkspaces, s as resolveOperand, t as WS_JSON_SCHEMA } from "./ws-
|
|
11
|
+
import "./remotes-B4CNXwDS.js";
|
|
12
|
+
import { a as isPathInside, c as walkWorkspaces, i as importProvisionModule, l as workspaceStatus, n as cmdWs, o as loadProvision, r as collectWorkspaces, s as resolveOperand, t as WS_JSON_SCHEMA } from "./ws-Dr-0Ckq7.js";
|
|
13
13
|
|
|
14
14
|
export { WS_JSON_SCHEMA, cmdWs, collectWorkspaces, isPathInside, loadProvision, walkWorkspaces, workspaceStatus };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { V as listRecords } from "./subcommands-
|
|
1
|
+
import { V as listRecords } from "./subcommands-Ddo2TYZs.js";
|
|
2
2
|
import { a as getProvisionRoot } from "./workspaceConfig-DTvPtr5j.js";
|
|
3
3
|
import { existsSync } from "fs";
|
|
4
4
|
import { lstat, opendir } from "fs/promises";
|
|
@@ -424,4 +424,4 @@ async function cmdWs(args) {
|
|
|
424
424
|
|
|
425
425
|
//#endregion
|
|
426
426
|
export { isPathInside as a, walkWorkspaces as c, importProvisionModule as i, workspaceStatus as l, cmdWs as n, loadProvision as o, collectWorkspaces as r, resolveOperand as s, WS_JSON_SCHEMA as t };
|
|
427
|
-
//# sourceMappingURL=ws-
|
|
427
|
+
//# sourceMappingURL=ws-Dr-0Ckq7.js.map
|
package/package.json
CHANGED
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
import { afterEach, beforeEach, describe, expect, it } from "bun:test";
|
|
2
|
+
import { mkdtemp, readdir, readFile, rm, writeFile } from "fs/promises";
|
|
3
|
+
import { tmpdir } from "os";
|
|
4
|
+
import path from "path";
|
|
5
|
+
import {
|
|
6
|
+
cacheAgeLabel,
|
|
7
|
+
hhmm,
|
|
8
|
+
humanizeAge,
|
|
9
|
+
isStale,
|
|
10
|
+
jsonRemote,
|
|
11
|
+
noteSnapshotResult,
|
|
12
|
+
parseWaitFor,
|
|
13
|
+
readRemoteSnapshot,
|
|
14
|
+
remoteCachePath,
|
|
15
|
+
writeRemoteSnapshot,
|
|
16
|
+
type RemoteSnapshot,
|
|
17
|
+
} from "./remoteCache.ts";
|
|
18
|
+
|
|
19
|
+
const T = 1_800_000_000_000;
|
|
20
|
+
const rows = [{ pid: 1111, cli: "claude", status: "active" }];
|
|
21
|
+
const good: RemoteSnapshot = {
|
|
22
|
+
version: 1,
|
|
23
|
+
alias: "alpha",
|
|
24
|
+
fetchedAt: T,
|
|
25
|
+
records: rows,
|
|
26
|
+
error: null,
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
describe("noteSnapshotResult", () => {
|
|
30
|
+
it("a success replaces the rows, stamps fetchedAt and clears the error", () => {
|
|
31
|
+
const prev: RemoteSnapshot = {
|
|
32
|
+
...good,
|
|
33
|
+
fetchedAt: T - 60_000,
|
|
34
|
+
records: [],
|
|
35
|
+
error: { message: "x", since: T - 30_000, lastTriedAt: T - 1 },
|
|
36
|
+
};
|
|
37
|
+
expect(noteSnapshotResult(prev, "alpha", { ok: true, records: rows }, T)).toEqual(good);
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
it("a failure keeps the last good rows and preserves when the streak began", () => {
|
|
41
|
+
const first = noteSnapshotResult(good, "alpha", { ok: false, message: "timeout" }, T + 1000);
|
|
42
|
+
expect(first.records).toBe(rows);
|
|
43
|
+
expect(first.fetchedAt).toBe(T);
|
|
44
|
+
expect(first.error).toEqual({ message: "timeout", since: T + 1000, lastTriedAt: T + 1000 });
|
|
45
|
+
const second = noteSnapshotResult(first, "alpha", { ok: false, message: "refused" }, T + 5000);
|
|
46
|
+
expect(second.error).toEqual({ message: "refused", since: T + 1000, lastTriedAt: T + 5000 });
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
it("a first-ever failure has no rows and starts the streak now", () => {
|
|
50
|
+
const s = noteSnapshotResult(null, "beta", { ok: false, message: "dns" }, T);
|
|
51
|
+
expect(s).toEqual({
|
|
52
|
+
version: 1,
|
|
53
|
+
alias: "beta",
|
|
54
|
+
fetchedAt: null,
|
|
55
|
+
records: [],
|
|
56
|
+
error: { message: "dns", since: T, lastTriedAt: T },
|
|
57
|
+
});
|
|
58
|
+
});
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
describe("isStale", () => {
|
|
62
|
+
it("treats no snapshot, never-fetched, old, and clock-backwards as stale", () => {
|
|
63
|
+
expect(isStale(null, T)).toBe(true);
|
|
64
|
+
expect(isStale({ ...good, fetchedAt: null }, T)).toBe(true);
|
|
65
|
+
expect(isStale(good, T + 30_000)).toBe(true);
|
|
66
|
+
expect(isStale(good, T - 1)).toBe(true);
|
|
67
|
+
});
|
|
68
|
+
it("serves fresh rows as-is", () => {
|
|
69
|
+
expect(isStale(good, T + 29_999)).toBe(false);
|
|
70
|
+
expect(isStale(good, T + 5_000, 1_000)).toBe(true);
|
|
71
|
+
});
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
describe("labels", () => {
|
|
75
|
+
it("humanizeAge keeps the table vocabulary", () => {
|
|
76
|
+
expect(humanizeAge(500)).toBe("0s");
|
|
77
|
+
expect(humanizeAge(59_000)).toBe("59s");
|
|
78
|
+
expect(humanizeAge(60_000)).toBe("1m");
|
|
79
|
+
expect(humanizeAge(3_600_000)).toBe("1h");
|
|
80
|
+
expect(humanizeAge(2 * 86_400_000)).toBe("2d");
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
it("hhmm is zero-padded local wall-clock", () => {
|
|
84
|
+
const d = new Date(2026, 0, 1, 9, 5);
|
|
85
|
+
expect(hhmm(d.getTime())).toBe("09:05");
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
it("cacheAgeLabel says where the rows came from and never hides an outage", () => {
|
|
89
|
+
expect(cacheAgeLabel(good, T + 180_000, true)).toBe("cached 3m ago, refreshing…");
|
|
90
|
+
expect(cacheAgeLabel(good, T + 180_000, false)).toBe("cached 3m ago");
|
|
91
|
+
expect(cacheAgeLabel(null, T, true)).toBe("no cache yet, refreshing…");
|
|
92
|
+
const since = new Date(2026, 0, 1, 14, 2).getTime();
|
|
93
|
+
const down: RemoteSnapshot = { ...good, error: { message: "x", since, lastTriedAt: since } };
|
|
94
|
+
expect(cacheAgeLabel(down, T + 720_000, true)).toBe("cached 12m ago, unreachable since 14:02");
|
|
95
|
+
});
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
describe("parseWaitFor", () => {
|
|
99
|
+
const aliases = ["alpha", "beta"];
|
|
100
|
+
it("expands all / local, and accepts a comma list of configured aliases", () => {
|
|
101
|
+
expect(parseWaitFor("all", aliases)).toEqual({ local: true, remotes: ["alpha", "beta"] });
|
|
102
|
+
expect(parseWaitFor("local", aliases)).toEqual({ local: true, remotes: [] });
|
|
103
|
+
expect(parseWaitFor("beta", aliases)).toEqual({ local: false, remotes: ["beta"] });
|
|
104
|
+
expect(parseWaitFor(" alpha, beta ,alpha", aliases)).toEqual({
|
|
105
|
+
local: false,
|
|
106
|
+
remotes: ["alpha", "beta"],
|
|
107
|
+
});
|
|
108
|
+
});
|
|
109
|
+
it("refuses an unknown alias or an empty value rather than waiting for nothing", () => {
|
|
110
|
+
expect(parseWaitFor("gamma", aliases)).toMatchObject({
|
|
111
|
+
error: expect.stringContaining("gamma"),
|
|
112
|
+
});
|
|
113
|
+
expect(parseWaitFor("", aliases)).toMatchObject({
|
|
114
|
+
error: expect.stringContaining("--waitFor"),
|
|
115
|
+
});
|
|
116
|
+
expect(parseWaitFor("x", [])).toMatchObject({ error: expect.stringContaining("none") });
|
|
117
|
+
});
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
describe("jsonRemote", () => {
|
|
121
|
+
it("exposes fetchedAt, stale and age so a parser can decide", () => {
|
|
122
|
+
expect(jsonRemote(good, T + 1000)).toEqual({
|
|
123
|
+
fetchedAt: T,
|
|
124
|
+
stale: false,
|
|
125
|
+
ageMs: 1000,
|
|
126
|
+
error: null,
|
|
127
|
+
records: rows,
|
|
128
|
+
});
|
|
129
|
+
expect(jsonRemote(null, T)).toEqual({
|
|
130
|
+
fetchedAt: null,
|
|
131
|
+
stale: true,
|
|
132
|
+
ageMs: null,
|
|
133
|
+
error: null,
|
|
134
|
+
records: [],
|
|
135
|
+
});
|
|
136
|
+
});
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
describe("snapshot files", () => {
|
|
140
|
+
let home: string;
|
|
141
|
+
const prev = process.env.AGENT_YES_HOME;
|
|
142
|
+
beforeEach(async () => {
|
|
143
|
+
home = await mkdtemp(path.join(tmpdir(), "ay-remote-cache-"));
|
|
144
|
+
process.env.AGENT_YES_HOME = home;
|
|
145
|
+
});
|
|
146
|
+
afterEach(async () => {
|
|
147
|
+
if (prev === undefined) delete process.env.AGENT_YES_HOME;
|
|
148
|
+
else process.env.AGENT_YES_HOME = prev;
|
|
149
|
+
await rm(home, { recursive: true, force: true });
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
it("round-trips, encodes an unsafe alias into the file name, and leaves no temp file", async () => {
|
|
153
|
+
const snap: RemoteSnapshot = { ...good, alias: "a/b c" };
|
|
154
|
+
await writeRemoteSnapshot(snap);
|
|
155
|
+
expect(remoteCachePath("a/b c")).toBe(path.join(home, "remotes", "a%2Fb%20c.cache.json"));
|
|
156
|
+
expect(await readRemoteSnapshot("a/b c")).toEqual(snap);
|
|
157
|
+
expect(await readdir(path.join(home, "remotes"))).toEqual(["a%2Fb%20c.cache.json"]);
|
|
158
|
+
expect(JSON.parse(await readFile(remoteCachePath("a/b c"), "utf-8")).version).toBe(1);
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
it("reads a missing, corrupt, or foreign file as a cold cache", async () => {
|
|
162
|
+
expect(await readRemoteSnapshot("none")).toBeNull();
|
|
163
|
+
await writeRemoteSnapshot(good);
|
|
164
|
+
await writeFile(remoteCachePath("alpha"), "{not json");
|
|
165
|
+
expect(await readRemoteSnapshot("alpha")).toBeNull();
|
|
166
|
+
await writeFile(remoteCachePath("alpha"), JSON.stringify({ version: 2, records: [] }));
|
|
167
|
+
expect(await readRemoteSnapshot("alpha")).toBeNull();
|
|
168
|
+
await writeFile(remoteCachePath("alpha"), JSON.stringify([1, 2]));
|
|
169
|
+
expect(await readRemoteSnapshot("alpha")).toBeNull();
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
it("tolerates a half-valid error object and a bad fetchedAt", async () => {
|
|
173
|
+
await writeFile(
|
|
174
|
+
remoteCachePath("alpha"),
|
|
175
|
+
JSON.stringify({ version: 1, fetchedAt: "soon", records: rows, error: { message: "x" } }),
|
|
176
|
+
).catch(async () => {
|
|
177
|
+
await writeRemoteSnapshot(good); // ensure the dir exists, then overwrite
|
|
178
|
+
await writeFile(
|
|
179
|
+
remoteCachePath("alpha"),
|
|
180
|
+
JSON.stringify({ version: 1, fetchedAt: "soon", records: rows, error: { message: "x" } }),
|
|
181
|
+
);
|
|
182
|
+
});
|
|
183
|
+
expect(await readRemoteSnapshot("alpha")).toEqual({
|
|
184
|
+
version: 1,
|
|
185
|
+
alias: "alpha",
|
|
186
|
+
fetchedAt: null,
|
|
187
|
+
records: rows,
|
|
188
|
+
error: null,
|
|
189
|
+
});
|
|
190
|
+
});
|
|
191
|
+
});
|