agent-yes 1.247.0 → 1.247.1
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-B1DPQLRV.js → SUPPORTED_CLIS-C2ABCTI-.js} +3 -3
- package/dist/{SUPPORTED_CLIS-DUALQTec.js → SUPPORTED_CLIS-CUHk1XEQ.js} +2 -2
- package/dist/{agentShare-Clx5QcyE.js → agentShare-DNLrTMuA.js} +2 -2
- package/dist/{callback-BPAlieXe.js → callback-BCtFFO6C.js} +2 -2
- package/dist/{callback-DPd9PJQA.js → callback-D4dvKSSB.js} +3 -3
- package/dist/cli.js +5 -5
- package/dist/index.js +2 -2
- package/dist/{notifyDaemon-CAML5u0d.js → notifyDaemon-BkxrvCIr.js} +274 -27
- package/dist/{rustBinary-BU3E3uMi.js → rustBinary-Ai2OdeAn.js} +2 -2
- package/dist/{schedule-C8wzhq0y.js → schedule-CLxwtJLH.js} +4 -4
- package/dist/{serve-D_DP0VBy.js → serve-BBMEzRhm.js} +13 -13
- package/dist/{setup-DIa8Y-lx.js → setup-RZycHxht.js} +2 -2
- package/dist/{subcommands-DeHlaNOY.js → subcommands-BfAb-n_1.js} +106 -21
- package/dist/{subcommands-WJz-UHyC.js → subcommands-CJYXODZ1.js} +1 -1
- package/dist/{terminal-MnictO_E.js → terminal-BtDzyBzg.js} +2 -2
- package/dist/{ts-rCPxI3aR.js → ts-C6cxg8DC.js} +2 -2
- package/dist/{versionChecker-Du1qdZR9.js → versionChecker-Cc3tPea6.js} +2 -2
- package/dist/{widget-U6HkHQcz.js → widget-hr7bHKUW.js} +3 -3
- package/dist/{ws-1vGWz9c9.js → ws-BTGDj3Hj.js} +2 -2
- package/package.json +1 -1
- package/ts/notifyDaemon.spec.ts +28 -1
- package/ts/notifyDaemon.ts +73 -33
- package/ts/notifyInbox.spec.ts +84 -0
- package/ts/notifyInbox.ts +75 -0
- package/ts/notifyStore.spec.ts +67 -0
- package/ts/notifyStore.ts +60 -7
- package/ts/ownerHeartbeat.spec.ts +161 -0
- package/ts/ownerHeartbeat.ts +166 -0
- package/ts/procStartTime.spec.ts +119 -0
- package/ts/procStartTime.ts +122 -0
- package/ts/subcommands.ts +37 -6
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import "./logger-CDIsZ-Pp.js";
|
|
2
|
-
import "./versionChecker-
|
|
3
|
-
import "./ts-
|
|
2
|
+
import "./versionChecker-Cc3tPea6.js";
|
|
3
|
+
import "./ts-C6cxg8DC.js";
|
|
4
4
|
import "./todoAutomation-Buo457VO.js";
|
|
5
5
|
import "./JsonlStore-CPGIR0Wy.js";
|
|
6
6
|
import "./globalPidIndex-D9DOSd-c.js";
|
|
7
7
|
import "./pidStore-vnX0bgra.js";
|
|
8
8
|
import "./messageLog-C-YIzhRj.js";
|
|
9
|
-
import { t as SUPPORTED_CLIS } from "./SUPPORTED_CLIS-
|
|
9
|
+
import { t as SUPPORTED_CLIS } from "./SUPPORTED_CLIS-CUHk1XEQ.js";
|
|
10
10
|
|
|
11
11
|
export { SUPPORTED_CLIS };
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { t as CLIS_CONFIG } from "./ts-
|
|
1
|
+
import { t as CLIS_CONFIG } from "./ts-C6cxg8DC.js";
|
|
2
2
|
|
|
3
3
|
//#region ts/SUPPORTED_CLIS.ts
|
|
4
4
|
const SUPPORTED_CLIS = Object.keys(CLIS_CONFIG);
|
|
5
5
|
|
|
6
6
|
//#endregion
|
|
7
7
|
export { SUPPORTED_CLIS as t };
|
|
8
|
-
//# sourceMappingURL=SUPPORTED_CLIS-
|
|
8
|
+
//# sourceMappingURL=SUPPORTED_CLIS-CUHk1XEQ.js.map
|
|
@@ -3,7 +3,7 @@ import "./globalPidIndex-D9DOSd-c.js";
|
|
|
3
3
|
import "./messageLog-C-YIzhRj.js";
|
|
4
4
|
import "./e2e-CEIdJGZ7.js";
|
|
5
5
|
import "./configShared-IBbnn9b8.js";
|
|
6
|
-
import { P as resolveOne } from "./subcommands-
|
|
6
|
+
import { P as resolveOne } from "./subcommands-BfAb-n_1.js";
|
|
7
7
|
import "./webrtcLink-BMYneHbu.js";
|
|
8
8
|
import "./remotes-BxQnNxQv.js";
|
|
9
9
|
import { a as startShare } from "./share-BGl3wutJ.js";
|
|
@@ -229,4 +229,4 @@ function transformEvent(rawEvent, agentId, forwarded) {
|
|
|
229
229
|
|
|
230
230
|
//#endregion
|
|
231
231
|
export { createScopedShare, listShares, revokeAllShares, revokeShare };
|
|
232
|
-
//# sourceMappingURL=agentShare-
|
|
232
|
+
//# sourceMappingURL=agentShare-DNLrTMuA.js.map
|
|
@@ -3,10 +3,10 @@ import "./globalPidIndex-D9DOSd-c.js";
|
|
|
3
3
|
import "./messageLog-C-YIzhRj.js";
|
|
4
4
|
import "./e2e-CEIdJGZ7.js";
|
|
5
5
|
import "./configShared-IBbnn9b8.js";
|
|
6
|
-
import "./subcommands-
|
|
6
|
+
import "./subcommands-BfAb-n_1.js";
|
|
7
7
|
import "./webrtcLink-BMYneHbu.js";
|
|
8
8
|
import "./remotes-BxQnNxQv.js";
|
|
9
9
|
import "./callbackCore-Dd28_cBM.js";
|
|
10
|
-
import { i as loadOrCreateCallbackSecret, n as isCallbackRevoked, r as loadCallbackSecretReadOnly, t as cmdCallback } from "./callback-
|
|
10
|
+
import { i as loadOrCreateCallbackSecret, n as isCallbackRevoked, r as loadCallbackSecretReadOnly, t as cmdCallback } from "./callback-D4dvKSSB.js";
|
|
11
11
|
|
|
12
12
|
export { cmdCallback };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { t as agentYesHome } from "./agentYesHome-CtmsY6I-.js";
|
|
2
|
-
import { P as resolveOne } from "./subcommands-
|
|
2
|
+
import { P as resolveOne } from "./subcommands-BfAb-n_1.js";
|
|
3
3
|
import { a as mintCapability, o as parseExpires } from "./callbackCore-Dd28_cBM.js";
|
|
4
4
|
import { randomBytes } from "node:crypto";
|
|
5
5
|
import { chmodSync, readFileSync, renameSync, writeFileSync } from "node:fs";
|
|
@@ -72,7 +72,7 @@ async function resolveBase(flag) {
|
|
|
72
72
|
if (flag) return flag;
|
|
73
73
|
if (process.env.AGENT_YES_CALLBACK_BASE) return process.env.AGENT_YES_CALLBACK_BASE;
|
|
74
74
|
try {
|
|
75
|
-
const { resolveLocalServeUrl } = await import("./serve-
|
|
75
|
+
const { resolveLocalServeUrl } = await import("./serve-BBMEzRhm.js");
|
|
76
76
|
const url = await resolveLocalServeUrl();
|
|
77
77
|
if (url) return url;
|
|
78
78
|
} catch {}
|
|
@@ -187,4 +187,4 @@ async function cmdCallback(rest) {
|
|
|
187
187
|
|
|
188
188
|
//#endregion
|
|
189
189
|
export { loadOrCreateCallbackSecret as i, isCallbackRevoked as n, loadCallbackSecretReadOnly as r, cmdCallback as t };
|
|
190
|
-
//# sourceMappingURL=callback-
|
|
190
|
+
//# sourceMappingURL=callback-D4dvKSSB.js.map
|
package/dist/cli.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env bun
|
|
2
2
|
import { t as invokedCliName } from "./invokedCli-uqM2YYA7.js";
|
|
3
3
|
import { n as logger } from "./logger-CDIsZ-Pp.js";
|
|
4
|
-
import { i as versionString, n as displayVersion, t as checkAndAutoUpdate } from "./versionChecker-
|
|
5
|
-
import { n as getRustBinary } from "./rustBinary-
|
|
4
|
+
import { i as versionString, n as displayVersion, t as checkAndAutoUpdate } from "./versionChecker-Cc3tPea6.js";
|
|
5
|
+
import { n as getRustBinary } from "./rustBinary-Ai2OdeAn.js";
|
|
6
6
|
import { argv } from "process";
|
|
7
7
|
import { spawn } from "child_process";
|
|
8
8
|
import ms from "ms";
|
|
@@ -285,7 +285,7 @@ function buildRustArgs(argv, cliFromScript, supportedClis) {
|
|
|
285
285
|
const rawArg = process.argv[2];
|
|
286
286
|
const managerCommands = !invokedCliName(process.argv);
|
|
287
287
|
const isHelpFlag = rawArg === "-h" || rawArg === "--help";
|
|
288
|
-
const { isSubcommand, runSubcommand, cmdHelp, isUnknownManagerToken } = await import("./subcommands-
|
|
288
|
+
const { isSubcommand, runSubcommand, cmdHelp, isUnknownManagerToken } = await import("./subcommands-CJYXODZ1.js");
|
|
289
289
|
if (isHelpFlag && process.argv.length === 3) {
|
|
290
290
|
await cmdHelp(managerCommands);
|
|
291
291
|
process.exit(0);
|
|
@@ -295,7 +295,7 @@ function buildRustArgs(argv, cliFromScript, supportedClis) {
|
|
|
295
295
|
process.exit(code ?? 0);
|
|
296
296
|
}
|
|
297
297
|
{
|
|
298
|
-
const { SUPPORTED_CLIS } = await import("./SUPPORTED_CLIS-
|
|
298
|
+
const { SUPPORTED_CLIS } = await import("./SUPPORTED_CLIS-C2ABCTI-.js");
|
|
299
299
|
if (isUnknownManagerToken(rawArg, managerCommands, SUPPORTED_CLIS)) {
|
|
300
300
|
process.stderr.write(`ay: unknown subcommand or CLI '${rawArg}'.\n See 'ay help' for subcommands. To run an agent, name a CLI:\n 'ay <cli> …' (e.g. 'ay claude …') or 'ay --cli <cli> …'.\n`);
|
|
301
301
|
process.exit(1);
|
|
@@ -346,7 +346,7 @@ if (config.useRust) {
|
|
|
346
346
|
}
|
|
347
347
|
}
|
|
348
348
|
if (rustBinary) {
|
|
349
|
-
const { SUPPORTED_CLIS } = await import("./SUPPORTED_CLIS-
|
|
349
|
+
const { SUPPORTED_CLIS } = await import("./SUPPORTED_CLIS-C2ABCTI-.js");
|
|
350
350
|
const rustArgs = buildRustArgs(process.argv, config.cli, SUPPORTED_CLIS);
|
|
351
351
|
if (config.verbose) {
|
|
352
352
|
console.log(`[rust] Using binary: ${rustBinary}`);
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import "./logger-CDIsZ-Pp.js";
|
|
2
|
-
import "./versionChecker-
|
|
3
|
-
import { a as hasTodoStore, i as answerAsk, l as AgentContext, n as agentYes, o as listAsks, r as config, s as listAsksForProject, t as CLIS_CONFIG } from "./ts-
|
|
2
|
+
import "./versionChecker-Cc3tPea6.js";
|
|
3
|
+
import { a as hasTodoStore, i as answerAsk, l as AgentContext, n as agentYes, o as listAsks, r as config, s as listAsksForProject, t as CLIS_CONFIG } from "./ts-C6cxg8DC.js";
|
|
4
4
|
import { _ as isKnownKind, a as renderTree, b as statesOf, c as monitorHint, d as openStore, f as DONE_STATE, g as initialState, h as canTransition, i as renderDigest, l as CycleError, m as ORPHANED_STATE, o as unblockedTasks, p as LIFECYCLES, r as openBlockers, s as describeBlock, t as reconcileTodos, u as TodoStore, v as nextStates, x as removeControlCharacters, y as requiredGate } from "./todoAutomation-Buo457VO.js";
|
|
5
5
|
import "./JsonlStore-CPGIR0Wy.js";
|
|
6
6
|
import "./globalPidIndex-D9DOSd-c.js";
|
|
@@ -3,12 +3,14 @@ import "./globalPidIndex-D9DOSd-c.js";
|
|
|
3
3
|
import "./messageLog-C-YIzhRj.js";
|
|
4
4
|
import "./e2e-CEIdJGZ7.js";
|
|
5
5
|
import "./configShared-IBbnn9b8.js";
|
|
6
|
-
import { $ as shouldStealLock, C as listRecords, J as hostId, K as appendEvent, Q as readInbox, X as listInboxParents, Z as liveWatchers, _ as isPidAlive, c as deriveLiveState, et as daemonLockDir, j as renderLogTailLines, nt as notifyDir, q as gcInboxes, tt as daemonLockOwnerPath } from "./subcommands-
|
|
6
|
+
import { $ as shouldStealLock, C as listRecords, J as hostId, K as appendEvent, Q as readInbox, X as listInboxParents, Z as liveWatchers, _ as isPidAlive, c as deriveLiveState, et as daemonLockDir, j as renderLogTailLines, nt as notifyDir, q as gcInboxes, tt as daemonLockOwnerPath } from "./subcommands-BfAb-n_1.js";
|
|
7
7
|
import "./webrtcLink-BMYneHbu.js";
|
|
8
8
|
import "./remotes-BxQnNxQv.js";
|
|
9
9
|
import { mkdir, readFile, rename, rm, stat, writeFile } from "fs/promises";
|
|
10
10
|
import { randomUUID } from "node:crypto";
|
|
11
|
-
import { execFile } from "node:child_process";
|
|
11
|
+
import { execFile, execFileSync } from "node:child_process";
|
|
12
|
+
import { readFileSync, renameSync, unlinkSync, writeFileSync } from "node:fs";
|
|
13
|
+
import { Worker } from "node:worker_threads";
|
|
12
14
|
|
|
13
15
|
//#region ts/notifyRouter.ts
|
|
14
16
|
const DEFAULT_IDLE_CONFIRM_MS = 3e4;
|
|
@@ -146,6 +148,243 @@ function syntheticExited(cs, pid) {
|
|
|
146
148
|
};
|
|
147
149
|
}
|
|
148
150
|
|
|
151
|
+
//#endregion
|
|
152
|
+
//#region ts/procStartTime.ts
|
|
153
|
+
/**
|
|
154
|
+
* Best-effort OS process start time, as an OPAQUE token.
|
|
155
|
+
*
|
|
156
|
+
* Why: `ay notifyd`'s singleton lock records `{pid, started_at}` where
|
|
157
|
+
* `started_at` is OUR OWN wall-clock stamp from when the daemon acquired the
|
|
158
|
+
* lock. That proves nothing about the pid the OS currently has: a pid recycled
|
|
159
|
+
* onto an unrelated live process inside the owner TTL would pass `isPidAlive`
|
|
160
|
+
* and be trusted as "the daemon is running" — so `ensureDaemon` would decline to
|
|
161
|
+
* start a real one. Cross-checking the OS's own notion of when that pid started
|
|
162
|
+
* closes the window: the recycled process has a different start time.
|
|
163
|
+
*
|
|
164
|
+
* The token is deliberately opaque (a raw platform string, compared only for
|
|
165
|
+
* equality) — no epoch math, no clock-tick/boot-time arithmetic, nothing to get
|
|
166
|
+
* subtly wrong across platforms. It is only ever compared against a token this
|
|
167
|
+
* same code produced for the same pid.
|
|
168
|
+
*
|
|
169
|
+
* BEST-EFFORT by contract: every reader returns `null` when it cannot answer
|
|
170
|
+
* (unsupported platform, missing /proc, `ps` unavailable or slow). Callers MUST
|
|
171
|
+
* treat null as "no opinion" and fall back to the existing checks — this
|
|
172
|
+
* tightens an edge, it must never introduce a new way to fail.
|
|
173
|
+
*
|
|
174
|
+
* Issue #169 item 1.
|
|
175
|
+
*/
|
|
176
|
+
/**
|
|
177
|
+
* Extract field 22 (`starttime`, in clock ticks since boot) from a Linux
|
|
178
|
+
* `/proc/<pid>/stat` line.
|
|
179
|
+
*
|
|
180
|
+
* The parse must start AFTER the last `)`: field 2 is the executable name in
|
|
181
|
+
* parentheses and may itself contain spaces and parens (`(my prog (v2))`), so
|
|
182
|
+
* naive whitespace splitting mis-indexes every later field. After the last `)`
|
|
183
|
+
* the remaining fields begin at field 3, hence `starttime` is index 19.
|
|
184
|
+
*/
|
|
185
|
+
function parseLinuxStartTime(stat) {
|
|
186
|
+
const close = stat.lastIndexOf(")");
|
|
187
|
+
if (close < 0) return null;
|
|
188
|
+
const starttime = stat.slice(close + 1).trim().split(/\s+/)[19];
|
|
189
|
+
return starttime && /^\d+$/.test(starttime) ? starttime : null;
|
|
190
|
+
}
|
|
191
|
+
function defaultProcStat(pid) {
|
|
192
|
+
try {
|
|
193
|
+
return readFileSync(`/proc/${pid}/stat`, "utf8");
|
|
194
|
+
} catch {
|
|
195
|
+
return null;
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
function defaultPsLstart(pid) {
|
|
199
|
+
try {
|
|
200
|
+
return execFileSync("ps", [
|
|
201
|
+
"-o",
|
|
202
|
+
"lstart=",
|
|
203
|
+
"-p",
|
|
204
|
+
String(pid)
|
|
205
|
+
], {
|
|
206
|
+
encoding: "utf8",
|
|
207
|
+
timeout: 500,
|
|
208
|
+
stdio: [
|
|
209
|
+
"ignore",
|
|
210
|
+
"pipe",
|
|
211
|
+
"ignore"
|
|
212
|
+
]
|
|
213
|
+
});
|
|
214
|
+
} catch {
|
|
215
|
+
return null;
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
/** Normalize a raw reader result: trim, and treat an empty answer as "unknown". */
|
|
219
|
+
function normalize(raw) {
|
|
220
|
+
if (raw === null) return null;
|
|
221
|
+
const trimmed = raw.trim();
|
|
222
|
+
return trimmed === "" ? null : trimmed;
|
|
223
|
+
}
|
|
224
|
+
/**
|
|
225
|
+
* An opaque token identifying WHEN `pid` started, or null when unknowable.
|
|
226
|
+
*
|
|
227
|
+
* Windows deliberately returns null: the only readily available reader is a
|
|
228
|
+
* PowerShell `Get-Process` spawn (hundreds of ms), far too heavy for a path
|
|
229
|
+
* that runs every couple of seconds under `ay notify watch`.
|
|
230
|
+
*/
|
|
231
|
+
function osProcessStartToken(pid, deps) {
|
|
232
|
+
if (!Number.isFinite(pid) || pid <= 0) return null;
|
|
233
|
+
const platform = deps?.platform ?? process.platform;
|
|
234
|
+
if (platform === "linux") {
|
|
235
|
+
const stat = (deps?.readProcStat ?? defaultProcStat)(pid);
|
|
236
|
+
return stat ? parseLinuxStartTime(stat) : null;
|
|
237
|
+
}
|
|
238
|
+
if (platform === "darwin" || platform === "freebsd" || platform === "openbsd") return normalize((deps?.readPsLstart ?? defaultPsLstart)(pid));
|
|
239
|
+
return null;
|
|
240
|
+
}
|
|
241
|
+
/**
|
|
242
|
+
* Does a RECORDED start token prove the pid has been recycled since?
|
|
243
|
+
*
|
|
244
|
+
* True only on positive disagreement — both sides present and different. A
|
|
245
|
+
* missing record (an owner written by an older build, or on a platform with no
|
|
246
|
+
* reader) or an unreadable current value yields false, i.e. "no opinion, keep
|
|
247
|
+
* trusting the other checks". Fail-open is correct here precisely because this
|
|
248
|
+
* is an ADDITIONAL guard layered on pid-liveness + heartbeat freshness.
|
|
249
|
+
*/
|
|
250
|
+
function osStartTokenMismatch(recorded, current) {
|
|
251
|
+
if (typeof recorded !== "string" || recorded === "") return false;
|
|
252
|
+
if (current === null) return false;
|
|
253
|
+
return current !== recorded;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
//#endregion
|
|
257
|
+
//#region ts/ownerHeartbeat.ts
|
|
258
|
+
/**
|
|
259
|
+
* The `ay notifyd` singleton lock's owner heartbeat, run on its OWN thread.
|
|
260
|
+
*
|
|
261
|
+
* Why a thread: the daemon proves it is alive by refreshing `ts` in the lock's
|
|
262
|
+
* `owner.json`; another `ay notify watch` steals the lock once that stamp is
|
|
263
|
+
* older than `OWNER_TTL`. On a single-threaded JS timer, a SYNCHRONOUS block in
|
|
264
|
+
* the daemon longer than the TTL would stall the heartbeat, let a second daemon
|
|
265
|
+
* take the lock, and leave two daemons writing the same inboxes. The loop is all
|
|
266
|
+
* `await`s and the TTL sits far above any realistic block, so that was always
|
|
267
|
+
* theoretical — but a single-threaded process can only bound it, never eliminate
|
|
268
|
+
* it. A worker thread does: its timer keeps firing no matter what the main
|
|
269
|
+
* thread is doing.
|
|
270
|
+
*
|
|
271
|
+
* The worker owns the whole beat (read token → verify → atomic rewrite), so a
|
|
272
|
+
* blocked main thread contributes nothing to keeping the lock alive. The owner
|
|
273
|
+
* payload is fixed for the daemon's lifetime — only `ts` moves — so there is no
|
|
274
|
+
* state to synchronize back.
|
|
275
|
+
*
|
|
276
|
+
* FENCING is preserved exactly as on the main thread: the beat refreshes only
|
|
277
|
+
* while `owner.json` still carries OUR token. Any other value — a different
|
|
278
|
+
* token (superseded) or none (another daemon's mkdir→write window) — means we no
|
|
279
|
+
* longer own the lock, so it stops rather than clobber an owner that isn't ours.
|
|
280
|
+
*
|
|
281
|
+
* Deliberately one-way: the beat never signals the daemon. Deciding to shut down
|
|
282
|
+
* stays with the daemon loop, which already re-reads the owner token every tick
|
|
283
|
+
* and exits when it isn't ours. Adding a second, cross-thread path to the same
|
|
284
|
+
* decision would only create a way for the two to disagree.
|
|
285
|
+
*
|
|
286
|
+
* The worker source is passed inline (`eval: true`) rather than shipped as a
|
|
287
|
+
* separate file: it needs no bundler entry, no dist path resolution, and works
|
|
288
|
+
* identically under both `bun` and `node` (verified on both).
|
|
289
|
+
*
|
|
290
|
+
* Falls back to a main-thread timer if a Worker can't be created for any reason,
|
|
291
|
+
* so this can only ever be as good as the previous behaviour — never worse.
|
|
292
|
+
*
|
|
293
|
+
* Issue #169 item 5.
|
|
294
|
+
*/
|
|
295
|
+
const WORKER_SRC = `
|
|
296
|
+
const { workerData } = require("node:worker_threads");
|
|
297
|
+
const fs = require("node:fs");
|
|
298
|
+
const { ownerPath, token, payload, intervalMs } = workerData;
|
|
299
|
+
|
|
300
|
+
function currentToken() {
|
|
301
|
+
try {
|
|
302
|
+
return JSON.parse(fs.readFileSync(ownerPath, "utf8")).token ?? null;
|
|
303
|
+
} catch {
|
|
304
|
+
return null;
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
function beat() {
|
|
309
|
+
if (currentToken() !== token) return false;
|
|
310
|
+
// Atomic (write temp + rename), so a concurrent reader never sees a torn owner
|
|
311
|
+
// and a null read reliably means "no owner file" rather than "write in flight".
|
|
312
|
+
const tmp = ownerPath + "." + token + ".beat.tmp";
|
|
313
|
+
try {
|
|
314
|
+
fs.writeFileSync(tmp, JSON.stringify(Object.assign({}, payload, { ts: Date.now() })));
|
|
315
|
+
fs.renameSync(tmp, ownerPath);
|
|
316
|
+
} catch {
|
|
317
|
+
try { fs.unlinkSync(tmp); } catch {}
|
|
318
|
+
}
|
|
319
|
+
return true;
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
const timer = setInterval(() => {
|
|
323
|
+
if (!beat()) clearInterval(timer);
|
|
324
|
+
}, intervalMs);
|
|
325
|
+
`;
|
|
326
|
+
/**
|
|
327
|
+
* Main-thread fallback with identical semantics, used when a Worker can't be
|
|
328
|
+
* created. Exported so the specs can exercise it directly on every platform —
|
|
329
|
+
* it is the path that runs on any runtime where worker threads are unavailable.
|
|
330
|
+
*/
|
|
331
|
+
function startInlineHeartbeat(opts) {
|
|
332
|
+
const timer = setInterval(() => {
|
|
333
|
+
let cur = null;
|
|
334
|
+
try {
|
|
335
|
+
cur = JSON.parse(readFileSync(opts.ownerPath, "utf8")).token ?? null;
|
|
336
|
+
} catch {
|
|
337
|
+
cur = null;
|
|
338
|
+
}
|
|
339
|
+
if (cur !== opts.token) {
|
|
340
|
+
clearInterval(timer);
|
|
341
|
+
return;
|
|
342
|
+
}
|
|
343
|
+
const tmp = `${opts.ownerPath}.${opts.token}.beat.tmp`;
|
|
344
|
+
try {
|
|
345
|
+
writeFileSync(tmp, JSON.stringify({
|
|
346
|
+
...opts.payload,
|
|
347
|
+
ts: Date.now()
|
|
348
|
+
}));
|
|
349
|
+
renameSync(tmp, opts.ownerPath);
|
|
350
|
+
} catch {
|
|
351
|
+
try {
|
|
352
|
+
unlinkSync(tmp);
|
|
353
|
+
} catch {}
|
|
354
|
+
}
|
|
355
|
+
}, opts.intervalMs);
|
|
356
|
+
if (typeof timer.unref === "function") timer.unref();
|
|
357
|
+
return {
|
|
358
|
+
isolated: false,
|
|
359
|
+
stop: async () => {
|
|
360
|
+
clearInterval(timer);
|
|
361
|
+
}
|
|
362
|
+
};
|
|
363
|
+
}
|
|
364
|
+
function startOwnerHeartbeat(opts) {
|
|
365
|
+
try {
|
|
366
|
+
const worker = new Worker(WORKER_SRC, {
|
|
367
|
+
eval: true,
|
|
368
|
+
workerData: {
|
|
369
|
+
ownerPath: opts.ownerPath,
|
|
370
|
+
token: opts.token,
|
|
371
|
+
payload: opts.payload,
|
|
372
|
+
intervalMs: opts.intervalMs
|
|
373
|
+
}
|
|
374
|
+
});
|
|
375
|
+
worker.on("error", () => {});
|
|
376
|
+
if (typeof worker.unref === "function") worker.unref();
|
|
377
|
+
return {
|
|
378
|
+
isolated: true,
|
|
379
|
+
stop: async () => {
|
|
380
|
+
await worker.terminate().catch(() => {});
|
|
381
|
+
}
|
|
382
|
+
};
|
|
383
|
+
} catch {
|
|
384
|
+
return startInlineHeartbeat(opts);
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
|
|
149
388
|
//#endregion
|
|
150
389
|
//#region ts/notifyDaemon.ts
|
|
151
390
|
/**
|
|
@@ -291,6 +530,7 @@ async function liveChildrenSnapshot() {
|
|
|
291
530
|
}
|
|
292
531
|
const OWNER_TTL_MS = 3e4;
|
|
293
532
|
let daemonStartedAt = 0;
|
|
533
|
+
let daemonOsStart = null;
|
|
294
534
|
let daemonToken = "";
|
|
295
535
|
/** The token currently written in the daemon lock owner file, or null. */
|
|
296
536
|
async function readDaemonOwnerToken() {
|
|
@@ -312,7 +552,8 @@ async function writeOwner() {
|
|
|
312
552
|
pid: process.pid,
|
|
313
553
|
started_at: daemonStartedAt,
|
|
314
554
|
ts: Date.now(),
|
|
315
|
-
token: daemonToken
|
|
555
|
+
token: daemonToken,
|
|
556
|
+
os_start: daemonOsStart
|
|
316
557
|
}));
|
|
317
558
|
await rename(tmp, daemonLockOwnerPath());
|
|
318
559
|
return true;
|
|
@@ -335,6 +576,7 @@ async function acquireDaemonLock(isAlive = isPidAlive) {
|
|
|
335
576
|
await mkdir(daemonLockDir(), { recursive: false });
|
|
336
577
|
daemonStartedAt = Date.now();
|
|
337
578
|
daemonToken = randomUUID();
|
|
579
|
+
daemonOsStart = osProcessStartToken(process.pid);
|
|
338
580
|
if (!await writeOwner()) {
|
|
339
581
|
await rm(daemonLockDir(), {
|
|
340
582
|
recursive: true,
|
|
@@ -352,10 +594,12 @@ async function acquireDaemonLock(isAlive = isPidAlive) {
|
|
|
352
594
|
try {
|
|
353
595
|
owner = JSON.parse(raw);
|
|
354
596
|
} catch {}
|
|
355
|
-
|
|
356
|
-
if (
|
|
597
|
+
const recycled = owner && typeof owner.pid === "number" && owner.pid > 0 ? osStartTokenMismatch(owner.os_start, osProcessStartToken(owner.pid)) : false;
|
|
598
|
+
if (owner && typeof owner.pid === "number" && owner.pid > 0 && owner.pid !== process.pid && typeof owner.ts === "number" && now - owner.ts <= OWNER_TTL_MS && isAlive(owner.pid) && !recycled) return false;
|
|
599
|
+
const lockAgeMs = now - await stat(daemonLockDir()).then((s) => s.mtimeMs).catch(() => now);
|
|
600
|
+
if (recycled || shouldStealLock(raw, now, {
|
|
357
601
|
staleMs: OWNER_TTL_MS,
|
|
358
|
-
lockAgeMs
|
|
602
|
+
lockAgeMs,
|
|
359
603
|
selfPid: process.pid,
|
|
360
604
|
isAlive
|
|
361
605
|
})) {
|
|
@@ -386,19 +630,20 @@ async function runDaemon(opts = {}) {
|
|
|
386
630
|
return 0;
|
|
387
631
|
}
|
|
388
632
|
let running = true;
|
|
389
|
-
const ownerBeat =
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
633
|
+
const ownerBeat = startOwnerHeartbeat({
|
|
634
|
+
ownerPath: daemonLockOwnerPath(),
|
|
635
|
+
token: daemonToken,
|
|
636
|
+
payload: {
|
|
637
|
+
pid: process.pid,
|
|
638
|
+
started_at: daemonStartedAt,
|
|
639
|
+
token: daemonToken,
|
|
640
|
+
os_start: daemonOsStart
|
|
641
|
+
},
|
|
642
|
+
intervalMs: Math.max(1e3, Math.floor(OWNER_TTL_MS / 3))
|
|
643
|
+
});
|
|
399
644
|
const cleanup = async () => {
|
|
400
645
|
running = false;
|
|
401
|
-
|
|
646
|
+
await ownerBeat.stop();
|
|
402
647
|
if (await readDaemonOwnerToken() === daemonToken) await rm(daemonLockDir(), {
|
|
403
648
|
recursive: true,
|
|
404
649
|
force: true
|
|
@@ -512,23 +757,25 @@ async function gcTick(host) {
|
|
|
512
757
|
* kill an unrelated process. `stop` re-reads and re-checks this identity right
|
|
513
758
|
* before signalling, so it can't SIGTERM a pid recycled between status and stop.
|
|
514
759
|
*
|
|
515
|
-
*
|
|
516
|
-
*
|
|
517
|
-
*
|
|
518
|
-
*
|
|
519
|
-
*
|
|
520
|
-
*
|
|
521
|
-
*
|
|
760
|
+
* The pid-recycled-inside-the-TTL window is closed by an OS start-time
|
|
761
|
+
* cross-check (issue #169 item 1): the owner file records the OS's own start
|
|
762
|
+
* time for the daemon pid at acquire, and every read re-reads it and rejects a
|
|
763
|
+
* disagreement — an unrelated process that inherited the pid has a different
|
|
764
|
+
* start time and is never reported as "the daemon". The reader is best-effort
|
|
765
|
+
* per platform (`/proc/<pid>/stat` on Linux, `ps -o lstart` on macOS/BSD, none
|
|
766
|
+
* on Windows); where it can't answer, behaviour is exactly as before — the
|
|
767
|
+
* heartbeat freshness + tight TTL still bound the window to seconds.
|
|
522
768
|
*/
|
|
523
769
|
async function daemonIdentity(now = Date.now()) {
|
|
524
770
|
const raw = await readFile(daemonLockOwnerPath(), "utf8").catch(() => "");
|
|
525
771
|
try {
|
|
526
772
|
const o = JSON.parse(raw);
|
|
527
|
-
if (typeof o?.pid === "number" && o.pid > 0 && typeof o.started_at === "number" && o.started_at > 0 && typeof o.ts === "number" && now - o.ts <= OWNER_TTL_MS && isPidAlive(o.pid)) return {
|
|
773
|
+
if (typeof o?.pid === "number" && o.pid > 0 && typeof o.started_at === "number" && o.started_at > 0 && typeof o.ts === "number" && now - o.ts <= OWNER_TTL_MS && isPidAlive(o.pid) && !osStartTokenMismatch(o.os_start, osProcessStartToken(o.pid))) return {
|
|
528
774
|
pid: o.pid,
|
|
529
775
|
started_at: o.started_at,
|
|
530
776
|
ts: o.ts,
|
|
531
|
-
token: typeof o.token === "string" ? o.token : null
|
|
777
|
+
token: typeof o.token === "string" ? o.token : null,
|
|
778
|
+
os_start: typeof o.os_start === "string" ? o.os_start : null
|
|
532
779
|
};
|
|
533
780
|
} catch {}
|
|
534
781
|
return null;
|
|
@@ -589,4 +836,4 @@ async function ensureDaemon() {
|
|
|
589
836
|
|
|
590
837
|
//#endregion
|
|
591
838
|
export { daemonStatus, ensureDaemon, requestDaemonStop, runDaemon };
|
|
592
|
-
//# sourceMappingURL=notifyDaemon-
|
|
839
|
+
//# sourceMappingURL=notifyDaemon-BkxrvCIr.js.map
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { r as getInstalledPackage } from "./versionChecker-
|
|
1
|
+
import { r as getInstalledPackage } from "./versionChecker-Cc3tPea6.js";
|
|
2
2
|
import { execFileSync } from "child_process";
|
|
3
3
|
import { existsSync, mkdirSync, unlinkSync } from "fs";
|
|
4
4
|
import { chmod, copyFile } from "fs/promises";
|
|
@@ -225,4 +225,4 @@ async function getRustBinary(options = {}) {
|
|
|
225
225
|
|
|
226
226
|
//#endregion
|
|
227
227
|
export { getRustBinary as n, findSpawnHiddenLauncher as t };
|
|
228
|
-
//# sourceMappingURL=rustBinary-
|
|
228
|
+
//# sourceMappingURL=rustBinary-Ai2OdeAn.js.map
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import "./logger-CDIsZ-Pp.js";
|
|
2
|
-
import "./versionChecker-
|
|
3
|
-
import "./ts-
|
|
2
|
+
import "./versionChecker-Cc3tPea6.js";
|
|
3
|
+
import "./ts-C6cxg8DC.js";
|
|
4
4
|
import "./todoAutomation-Buo457VO.js";
|
|
5
5
|
import "./JsonlStore-CPGIR0Wy.js";
|
|
6
6
|
import "./globalPidIndex-D9DOSd-c.js";
|
|
7
7
|
import "./pidStore-vnX0bgra.js";
|
|
8
8
|
import "./messageLog-C-YIzhRj.js";
|
|
9
|
-
import { t as SUPPORTED_CLIS } from "./SUPPORTED_CLIS-
|
|
9
|
+
import { t as SUPPORTED_CLIS } from "./SUPPORTED_CLIS-CUHk1XEQ.js";
|
|
10
10
|
import { f as resolveSpawnCwd } from "./workspaceConfig-CpilQzMY.js";
|
|
11
11
|
import { n as liveEnv, t as ensureNodeRuntime } from "./nodeRuntime-BtL6Oo1o.js";
|
|
12
12
|
import { createHash } from "node:crypto";
|
|
@@ -153,4 +153,4 @@ async function cmdSchedule(rest) {
|
|
|
153
153
|
|
|
154
154
|
//#endregion
|
|
155
155
|
export { cmdSchedule };
|
|
156
|
-
//# sourceMappingURL=schedule-
|
|
156
|
+
//# sourceMappingURL=schedule-CLxwtJLH.js.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import "./logger-CDIsZ-Pp.js";
|
|
2
|
-
import { r as getInstalledPackage } from "./versionChecker-
|
|
3
|
-
import { t as findSpawnHiddenLauncher } from "./rustBinary-
|
|
4
|
-
import { c as permissionBadge, i as answerAsk, o as listAsks, u as CLAUDE_SESSION_PIN_ENV } from "./ts-
|
|
2
|
+
import { r as getInstalledPackage } from "./versionChecker-Cc3tPea6.js";
|
|
3
|
+
import { t as findSpawnHiddenLauncher } from "./rustBinary-Ai2OdeAn.js";
|
|
4
|
+
import { c as permissionBadge, i as answerAsk, o as listAsks, u as CLAUDE_SESSION_PIN_ENV } from "./ts-C6cxg8DC.js";
|
|
5
5
|
import { t as agentYesHome$1 } from "./agentYesHome-CtmsY6I-.js";
|
|
6
6
|
import { x as removeControlCharacters } from "./todoAutomation-Buo457VO.js";
|
|
7
7
|
import "./JsonlStore-CPGIR0Wy.js";
|
|
@@ -11,12 +11,12 @@ import { r as recordInbox } from "./messageLog-C-YIzhRj.js";
|
|
|
11
11
|
import { t as pgidForWrapper } from "./reaper-DP49VCKx.js";
|
|
12
12
|
import "./e2e-CEIdJGZ7.js";
|
|
13
13
|
import "./configShared-IBbnn9b8.js";
|
|
14
|
-
import { t as SUPPORTED_CLIS } from "./SUPPORTED_CLIS-
|
|
15
|
-
import { A as recentReadEdges, C as listRecords, D as readNotes, G as writeToIpc, M as renderRawLog, N as renderRawLogLines, O as readPtysize, P as resolveOne, Y as isTransientLockMkdirError, f as extractNeedsInput, j as renderLogTailLines, k as recentMessageEdges, l as deriveLiveStatus, o as controlCodeFromName, p as extractTaskCounts, rt as TYPING_BADGE, u as extractBadges, x as isUserTyping, z as snapshotStatus } from "./subcommands-
|
|
14
|
+
import { t as SUPPORTED_CLIS } from "./SUPPORTED_CLIS-CUHk1XEQ.js";
|
|
15
|
+
import { A as recentReadEdges, C as listRecords, D as readNotes, G as writeToIpc, M as renderRawLog, N as renderRawLogLines, O as readPtysize, P as resolveOne, Y as isTransientLockMkdirError, f as extractNeedsInput, j as renderLogTailLines, k as recentMessageEdges, l as deriveLiveStatus, o as controlCodeFromName, p as extractTaskCounts, rt as TYPING_BADGE, u as extractBadges, x as isUserTyping, z as snapshotStatus } from "./subcommands-BfAb-n_1.js";
|
|
16
16
|
import "./webrtcLink-BMYneHbu.js";
|
|
17
17
|
import "./remotes-BxQnNxQv.js";
|
|
18
18
|
import { i as frameVisitorMessage, s as verifyCapability, t as MAX_CALLBACK_MSG_BYTES } from "./callbackCore-Dd28_cBM.js";
|
|
19
|
-
import { n as isCallbackRevoked, r as loadCallbackSecretReadOnly } from "./callback-
|
|
19
|
+
import { n as isCallbackRevoked, r as loadCallbackSecretReadOnly } from "./callback-D4dvKSSB.js";
|
|
20
20
|
import { a as getProvisionRoot, d as isProvisionAllowed, f as resolveSpawnCwd, i as getProvisionHook, l as hasProvisionHook, o as getSpawnHook, t as allowsSkipPermissions, u as hasSpawnHook } from "./workspaceConfig-CpilQzMY.js";
|
|
21
21
|
import { n as liveEnv, t as ensureNodeRuntime } from "./nodeRuntime-BtL6Oo1o.js";
|
|
22
22
|
import { r as spawnRejectionReason } from "./spawnGate-BFJPdHCQ.js";
|
|
@@ -2306,7 +2306,7 @@ Options:
|
|
|
2306
2306
|
}
|
|
2307
2307
|
});
|
|
2308
2308
|
if (req.method === "GET" && p === "/api/ws") {
|
|
2309
|
-
const ws = await import("./ws-
|
|
2309
|
+
const ws = await import("./ws-BTGDj3Hj.js");
|
|
2310
2310
|
try {
|
|
2311
2311
|
await ws.loadProvision();
|
|
2312
2312
|
} catch (e) {
|
|
@@ -2326,7 +2326,7 @@ Options:
|
|
|
2326
2326
|
if (req.method === "GET" && p === "/api/ws/status") {
|
|
2327
2327
|
const dirRaw = url.searchParams.get("path");
|
|
2328
2328
|
if (!dirRaw) return new Response("missing ?path=<workspace dir>", { status: 400 });
|
|
2329
|
-
const ws = await import("./ws-
|
|
2329
|
+
const ws = await import("./ws-BTGDj3Hj.js");
|
|
2330
2330
|
let prov;
|
|
2331
2331
|
try {
|
|
2332
2332
|
prov = await ws.loadProvision();
|
|
@@ -3079,7 +3079,7 @@ Options:
|
|
|
3079
3079
|
const perm = body.perm ?? "r";
|
|
3080
3080
|
if (perm !== "r" && perm !== "rw") return new Response(`invalid perm ${perm} (want r or rw)`, { status: 400 });
|
|
3081
3081
|
try {
|
|
3082
|
-
const { createScopedShare } = await import("./agentShare-
|
|
3082
|
+
const { createScopedShare } = await import("./agentShare-DNLrTMuA.js");
|
|
3083
3083
|
const share = await createScopedShare({
|
|
3084
3084
|
agent: body.agent,
|
|
3085
3085
|
perm,
|
|
@@ -3094,12 +3094,12 @@ Options:
|
|
|
3094
3094
|
}
|
|
3095
3095
|
}
|
|
3096
3096
|
if (req.method === "GET" && p === "/api/shares") {
|
|
3097
|
-
const { listShares } = await import("./agentShare-
|
|
3097
|
+
const { listShares } = await import("./agentShare-DNLrTMuA.js");
|
|
3098
3098
|
return Response.json(listShares());
|
|
3099
3099
|
}
|
|
3100
3100
|
const revokeM = /^\/api\/share\/([^/]+)$/.exec(p);
|
|
3101
3101
|
if (req.method === "DELETE" && revokeM) {
|
|
3102
|
-
const { revokeShare } = await import("./agentShare-
|
|
3102
|
+
const { revokeShare } = await import("./agentShare-DNLrTMuA.js");
|
|
3103
3103
|
const ok = revokeShare(decodeURIComponent(revokeM[1]));
|
|
3104
3104
|
return new Response(ok ? "revoked" : "no such share", { status: ok ? 200 : 404 });
|
|
3105
3105
|
}
|
|
@@ -3401,7 +3401,7 @@ Options:
|
|
|
3401
3401
|
const shutdown = (resolve) => {
|
|
3402
3402
|
if (heartbeat) clearInterval(heartbeat);
|
|
3403
3403
|
closeShare?.();
|
|
3404
|
-
import("./agentShare-
|
|
3404
|
+
import("./agentShare-DNLrTMuA.js").then((m) => m.revokeAllShares()).catch(() => {});
|
|
3405
3405
|
server?.stop();
|
|
3406
3406
|
Promise.resolve(releaseHostLock?.()).catch(() => {}).then(resolve);
|
|
3407
3407
|
};
|
|
@@ -3414,4 +3414,4 @@ Options:
|
|
|
3414
3414
|
|
|
3415
3415
|
//#endregion
|
|
3416
3416
|
export { cmdServe, loadTokenReadOnly, mintScopedTermToken, resolveDaemonHttpBase, resolveLocalServeUrl };
|
|
3417
|
-
//# sourceMappingURL=serve-
|
|
3417
|
+
//# sourceMappingURL=serve-BBMEzRhm.js.map
|
|
@@ -32,7 +32,7 @@ async function cmdSetup(rest) {
|
|
|
32
32
|
if (!existsSync(abs)) process.stderr.write(` note: that directory doesn't exist yet — create it, or agents spawned there will fail\n`);
|
|
33
33
|
if (noShare) return 0;
|
|
34
34
|
process.stdout.write(`\nsharing this machine to agent-yes.com…\n`);
|
|
35
|
-
const { cmdServe } = await import("./serve-
|
|
35
|
+
const { cmdServe } = await import("./serve-BBMEzRhm.js");
|
|
36
36
|
return cmdServe([
|
|
37
37
|
"install",
|
|
38
38
|
"--share",
|
|
@@ -42,4 +42,4 @@ async function cmdSetup(rest) {
|
|
|
42
42
|
|
|
43
43
|
//#endregion
|
|
44
44
|
export { cmdSetup };
|
|
45
|
-
//# sourceMappingURL=setup-
|
|
45
|
+
//# sourceMappingURL=setup-RZycHxht.js.map
|