agent-yes 1.192.0 → 1.192.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (29) hide show
  1. package/dist/{SUPPORTED_CLIS-C0fh_eJs.js → SUPPORTED_CLIS-CryNU1fs.js} +2 -2
  2. package/dist/SUPPORTED_CLIS-wrXQttpW.js +8 -0
  3. package/dist/{agentShare-Byzqbfk6.js → agentShare-BY9WWDBm.js} +3 -3
  4. package/dist/cli.js +7 -7
  5. package/dist/index.js +2 -2
  6. package/dist/nodeRuntime-DZRjxpNp.js +56 -0
  7. package/dist/{notifyDaemon-DjuvLK7-.js → notifyDaemon-BPcU9HOC.js} +3 -3
  8. package/dist/{remotes-WVJBNajZ.js → remotes-CW-yxSgW.js} +1 -1
  9. package/dist/{remotes-CgT91bMo.js → remotes-oSmwSYaV.js} +2 -2
  10. package/dist/{rustBinary-INWRomvk.js → rustBinary-CeRekAdR.js} +2 -2
  11. package/dist/{schedule-CsNFNbbW.js → schedule-DCVkaHCo.js} +24 -15
  12. package/dist/{serve-CfR-7uMU.js → serve-Dxxm6cs6.js} +92 -50
  13. package/dist/{setup-0Oby3hYf.js → setup-CnHHrqP9.js} +2 -2
  14. package/dist/{spawnGate-BejtWiMJ.js → spawnGate-CWbdnJ5K.js} +1 -1
  15. package/dist/{spawnGate-CA5QD7D4.js → spawnGate-DRWa_Fzj.js} +1 -1
  16. package/dist/{subcommands-D_QHSUp-.js → subcommands-BnEmKfiM.js} +2 -2
  17. package/dist/{subcommands-IIDRpOa1.js → subcommands-Cq1mzI8Z.js} +9 -9
  18. package/dist/{tray-PMOWFOfk.js → tray-BKTZ5gIf.js} +1 -1
  19. package/dist/{ts-BdFKarex.js → ts-Cp_21mny.js} +2 -2
  20. package/dist/{versionChecker-DEJVuzWZ.js → versionChecker-CaOEu_WC.js} +2 -2
  21. package/dist/{webrtcRemote-CD5EQ3uX.js → webrtcRemote-BmuVKcrx.js} +1 -1
  22. package/package.json +1 -1
  23. package/ts/nodeRuntime.spec.ts +99 -0
  24. package/ts/nodeRuntime.ts +58 -0
  25. package/ts/oxmgrService.ts +6 -0
  26. package/ts/schedule.ts +8 -0
  27. package/ts/serve.spec.ts +60 -1
  28. package/ts/serve.ts +74 -24
  29. package/dist/SUPPORTED_CLIS-DAzPSQ95.js +0 -8
@@ -1,8 +1,8 @@
1
- import { t as CLIS_CONFIG } from "./ts-BdFKarex.js";
1
+ import { t as CLIS_CONFIG } from "./ts-Cp_21mny.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-C0fh_eJs.js.map
8
+ //# sourceMappingURL=SUPPORTED_CLIS-CryNU1fs.js.map
@@ -0,0 +1,8 @@
1
+ import "./ts-Cp_21mny.js";
2
+ import "./logger-CDIsZ-Pp.js";
3
+ import "./versionChecker-CaOEu_WC.js";
4
+ import "./pidStore-BIvsBQ8X.js";
5
+ import "./globalPidIndex-CoNr7tS8.js";
6
+ import { t as SUPPORTED_CLIS } from "./SUPPORTED_CLIS-CryNU1fs.js";
7
+
8
+ export { SUPPORTED_CLIS };
@@ -1,10 +1,10 @@
1
1
  import "./logger-CDIsZ-Pp.js";
2
2
  import "./globalPidIndex-CoNr7tS8.js";
3
3
  import "./configShared-0MnIQ652.js";
4
- import { j as resolveOne } from "./subcommands-IIDRpOa1.js";
4
+ import { j as resolveOne } from "./subcommands-Cq1mzI8Z.js";
5
5
  import "./e2e-BeKjLhmO.js";
6
6
  import "./webrtcLink-BG0Xc4-W.js";
7
- import "./remotes-CgT91bMo.js";
7
+ import "./remotes-oSmwSYaV.js";
8
8
  import { r as startShare } from "./share-29YbzpbU.js";
9
9
 
10
10
  //#region ts/agentShare.ts
@@ -228,4 +228,4 @@ function transformEvent(rawEvent, agentId, forwarded) {
228
228
 
229
229
  //#endregion
230
230
  export { createScopedShare, listShares, revokeAllShares, revokeShare };
231
- //# sourceMappingURL=agentShare-Byzqbfk6.js.map
231
+ //# sourceMappingURL=agentShare-BY9WWDBm.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-DEJVuzWZ.js";
5
- import { n as getRustBinary } from "./rustBinary-INWRomvk.js";
4
+ import { i as versionString, n as displayVersion, t as checkAndAutoUpdate } from "./versionChecker-CaOEu_WC.js";
5
+ import { n as getRustBinary } from "./rustBinary-CeRekAdR.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 } = await import("./subcommands-D_QHSUp-.js");
288
+ const { isSubcommand, runSubcommand, cmdHelp } = await import("./subcommands-BnEmKfiM.js");
289
289
  if (isHelpFlag && process.argv.length === 3) {
290
290
  await cmdHelp(managerCommands);
291
291
  process.exit(0);
@@ -299,16 +299,16 @@ await checkAndAutoUpdate();
299
299
  logger.info(versionString());
300
300
  const config = parseCliArgs(process.argv);
301
301
  if (config.tray) {
302
- const { startTray } = await import("./tray-PMOWFOfk.js");
302
+ const { startTray } = await import("./tray-BKTZ5gIf.js");
303
303
  await startTray();
304
304
  await new Promise(() => {});
305
305
  }
306
306
  {
307
- const { ensureTray } = await import("./tray-PMOWFOfk.js");
307
+ const { ensureTray } = await import("./tray-BKTZ5gIf.js");
308
308
  ensureTray();
309
309
  }
310
310
  if (!config.showVersion && !config.appendPrompt && !config.tray) {
311
- const { waitForSpawnCapacity } = await import("./spawnGate-BejtWiMJ.js");
311
+ const { waitForSpawnCapacity } = await import("./spawnGate-CWbdnJ5K.js");
312
312
  await waitForSpawnCapacity({
313
313
  onWait: (reason, waitedMs) => {
314
314
  if (config.verbose || waitedMs === 0) console.error(`[agent-yes] spawn gate: ${reason} — waiting…`);
@@ -327,7 +327,7 @@ if (config.useRust) {
327
327
  }
328
328
  }
329
329
  if (rustBinary) {
330
- const { SUPPORTED_CLIS } = await import("./SUPPORTED_CLIS-DAzPSQ95.js");
330
+ const { SUPPORTED_CLIS } = await import("./SUPPORTED_CLIS-wrXQttpW.js");
331
331
  const rustArgs = buildRustArgs(process.argv, config.cli, SUPPORTED_CLIS);
332
332
  if (config.verbose) {
333
333
  console.log(`[rust] Using binary: ${rustBinary}`);
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
- import { a as removeControlCharacters, i as AgentContext, n as agentYes, r as config, t as CLIS_CONFIG } from "./ts-BdFKarex.js";
1
+ import { a as removeControlCharacters, i as AgentContext, n as agentYes, r as config, t as CLIS_CONFIG } from "./ts-Cp_21mny.js";
2
2
  import "./logger-CDIsZ-Pp.js";
3
- import "./versionChecker-DEJVuzWZ.js";
3
+ import "./versionChecker-CaOEu_WC.js";
4
4
  import "./pidStore-BIvsBQ8X.js";
5
5
  import "./globalPidIndex-CoNr7tS8.js";
6
6
 
@@ -0,0 +1,56 @@
1
+ import { t as agentYesHome } from "./agentYesHome-CtHb5b71.js";
2
+ import { chmod, mkdir, readFile, writeFile } from "fs/promises";
3
+ import path from "path";
4
+
5
+ //#region ts/nodeRuntime.ts
6
+ /**
7
+ * Snapshot of the CURRENT process.env for child spawns. Bun.spawn without an
8
+ * explicit `env` hands the child the environ captured at PROCESS STARTUP — not
9
+ * the live process.env — so post-startup mutations (ensureNodeRuntime's shim
10
+ * PATH prepend, installAndVerify's global-bin-dir prepend) silently never reach
11
+ * the child. That is exactly how `ay serve install` kept dying with
12
+ * `env: node: No such file or directory` at the `pm2 start` spawn on a bun-only
13
+ * box even though the probe (which passes env explicitly) had just succeeded.
14
+ * Every spawn of a process-manager binary must pass `env: liveEnv()`.
15
+ */
16
+ function liveEnv() {
17
+ return { ...process.env };
18
+ }
19
+ /**
20
+ * Both oxmgr's and pm2's global bins are `#!/usr/bin/env node` JS scripts, so on
21
+ * a bun-only box (setup.sh installs no node) exec dies with "env: node: No such
22
+ * file or directory" — even though pm2 is pure JS and runs perfectly under bun.
23
+ * When node is missing but bun exists, write a node→bun shim into ay's own bin
24
+ * dir and prepend it to PATH so `env node` resolves. NOT solvable with
25
+ * `bun add -g node`: that package (node-bin-gen) lands a broken arch-specific
26
+ * stub and `Bun.which("node")` still finds nothing. POSIX-only — on Windows the
27
+ * npm .cmd shims invoke node.exe directly and an sh script can't stand in.
28
+ * Read-only paths (`ay serve status`) also reach this via the manager probes:
29
+ * an up-to-date shim is left untouched there (a read, not a write), so only the
30
+ * very first run on a node-less box materializes the file.
31
+ * Returns the shim path when the shim is in effect, null when unneeded/impossible.
32
+ */
33
+ async function ensureNodeRuntime(which = Bun.which) {
34
+ if (process.platform === "win32") return null;
35
+ if (which("node")) return null;
36
+ const bun = which("bun");
37
+ if (!bun) return null;
38
+ const binDir = path.join(agentYesHome(), "bin");
39
+ const shim = path.join(binDir, "node");
40
+ const body = `#!/bin/sh\nexec '${bun.replace(/'/g, `'\\''`)}' "$@"\n`;
41
+ try {
42
+ if (await readFile(shim, "utf-8").catch(() => null) !== body) {
43
+ await mkdir(binDir, { recursive: true });
44
+ await writeFile(shim, body);
45
+ await chmod(shim, 493);
46
+ }
47
+ if (!(process.env.PATH ?? "").split(path.delimiter).includes(binDir)) process.env.PATH = `${binDir}${path.delimiter}${process.env.PATH ?? ""}`;
48
+ return shim;
49
+ } catch {
50
+ return null;
51
+ }
52
+ }
53
+
54
+ //#endregion
55
+ export { liveEnv as n, ensureNodeRuntime as t };
56
+ //# sourceMappingURL=nodeRuntime-DZRjxpNp.js.map
@@ -1,10 +1,10 @@
1
1
  import { n as logger } from "./logger-CDIsZ-Pp.js";
2
2
  import "./globalPidIndex-CoNr7tS8.js";
3
3
  import "./configShared-0MnIQ652.js";
4
- import { G as hostId, J as readInbox, K as listInboxParents, O as renderLogTailLines, Q as notifyDir, S as listRecords, U as appendEvent, W as gcInboxes, X as daemonLockDir, Y as shouldStealLock, Z as daemonLockOwnerPath, _ as isPidAlive, c as deriveLiveState, q as liveWatchers } from "./subcommands-IIDRpOa1.js";
4
+ import { G as hostId, J as readInbox, K as listInboxParents, O as renderLogTailLines, Q as notifyDir, S as listRecords, U as appendEvent, W as gcInboxes, X as daemonLockDir, Y as shouldStealLock, Z as daemonLockOwnerPath, _ as isPidAlive, c as deriveLiveState, q as liveWatchers } from "./subcommands-Cq1mzI8Z.js";
5
5
  import "./e2e-BeKjLhmO.js";
6
6
  import "./webrtcLink-BG0Xc4-W.js";
7
- import "./remotes-CgT91bMo.js";
7
+ import "./remotes-oSmwSYaV.js";
8
8
  import { mkdir, readFile, rename, rm, stat, writeFile } from "fs/promises";
9
9
  import { randomUUID } from "node:crypto";
10
10
  import { execFile } from "node:child_process";
@@ -588,4 +588,4 @@ async function ensureDaemon() {
588
588
 
589
589
  //#endregion
590
590
  export { daemonStatus, ensureDaemon, requestDaemonStop, runDaemon };
591
- //# sourceMappingURL=notifyDaemon-DjuvLK7-.js.map
591
+ //# sourceMappingURL=notifyDaemon-BPcU9HOC.js.map
@@ -1,5 +1,5 @@
1
1
  import "./e2e-BeKjLhmO.js";
2
2
  import "./webrtcLink-BG0Xc4-W.js";
3
- import { a as resolveRemoteSpec, i as readRemotes, n as deleteRemoteAlias, o as writeRemoteAlias, r as parseDirectRemoteSpec, t as cmdRemote } from "./remotes-CgT91bMo.js";
3
+ import { a as resolveRemoteSpec, i as readRemotes, n as deleteRemoteAlias, o as writeRemoteAlias, r as parseDirectRemoteSpec, t as cmdRemote } from "./remotes-oSmwSYaV.js";
4
4
 
5
5
  export { cmdRemote };
@@ -86,7 +86,7 @@ async function resolveRemoteSpec(spec) {
86
86
  * The bridge lives for the rest of the process (torn down on `process.exit`).
87
87
  */
88
88
  async function resolveWebrtc(link, keyword) {
89
- const { startWebrtcBridge } = await import("./webrtcRemote-CD5EQ3uX.js");
89
+ const { startWebrtcBridge } = await import("./webrtcRemote-BmuVKcrx.js");
90
90
  const bridge = await startWebrtcBridge(link);
91
91
  return {
92
92
  url: bridge.baseUrl,
@@ -173,4 +173,4 @@ async function cmdRemote(rest) {
173
173
 
174
174
  //#endregion
175
175
  export { resolveRemoteSpec as a, readRemotes as i, deleteRemoteAlias as n, writeRemoteAlias as o, parseDirectRemoteSpec as r, cmdRemote as t };
176
- //# sourceMappingURL=remotes-CgT91bMo.js.map
176
+ //# sourceMappingURL=remotes-oSmwSYaV.js.map
@@ -1,4 +1,4 @@
1
- import { r as getInstalledPackage } from "./versionChecker-DEJVuzWZ.js";
1
+ import { r as getInstalledPackage } from "./versionChecker-CaOEu_WC.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-INWRomvk.js.map
228
+ //# sourceMappingURL=rustBinary-CeRekAdR.js.map
@@ -1,10 +1,11 @@
1
- import "./ts-BdFKarex.js";
1
+ import "./ts-Cp_21mny.js";
2
2
  import "./logger-CDIsZ-Pp.js";
3
- import "./versionChecker-DEJVuzWZ.js";
3
+ import "./versionChecker-CaOEu_WC.js";
4
4
  import "./pidStore-BIvsBQ8X.js";
5
5
  import "./globalPidIndex-CoNr7tS8.js";
6
- import { t as SUPPORTED_CLIS } from "./SUPPORTED_CLIS-C0fh_eJs.js";
6
+ import { t as SUPPORTED_CLIS } from "./SUPPORTED_CLIS-CryNU1fs.js";
7
7
  import { d as resolveSpawnCwd } from "./workspaceConfig-_GtAZtsi.js";
8
+ import { n as liveEnv, t as ensureNodeRuntime } from "./nodeRuntime-DZRjxpNp.js";
8
9
  import { createHash } from "node:crypto";
9
10
 
10
11
  //#region ts/oxmgrService.ts
@@ -14,20 +15,26 @@ async function ensureBootAutostart(oxmgrBin) {
14
15
  oxmgrBin,
15
16
  "service",
16
17
  "status"
17
- ], { stdio: [
18
- "ignore",
19
- "ignore",
20
- "ignore"
21
- ] }).exited === 0) return true;
18
+ ], {
19
+ stdio: [
20
+ "ignore",
21
+ "ignore",
22
+ "ignore"
23
+ ],
24
+ env: liveEnv()
25
+ }).exited === 0) return true;
22
26
  return await Bun.spawn([
23
27
  oxmgrBin,
24
28
  "service",
25
29
  "install"
26
- ], { stdio: [
27
- "ignore",
28
- "ignore",
29
- "ignore"
30
- ] }).exited === 0;
30
+ ], {
31
+ stdio: [
32
+ "ignore",
33
+ "ignore",
34
+ "ignore"
35
+ ],
36
+ env: liveEnv()
37
+ }).exited === 0;
31
38
  } catch {
32
39
  return false;
33
40
  }
@@ -58,7 +65,8 @@ async function run(cmd, capture = false) {
58
65
  const p = Bun.spawn(cmd, {
59
66
  stdin: "ignore",
60
67
  stdout: capture ? "pipe" : "inherit",
61
- stderr: capture ? "pipe" : "inherit"
68
+ stderr: capture ? "pipe" : "inherit",
69
+ env: liveEnv()
62
70
  });
63
71
  const out = capture ? await new Response(p.stdout).text() : "";
64
72
  return {
@@ -67,6 +75,7 @@ async function run(cmd, capture = false) {
67
75
  };
68
76
  }
69
77
  async function cmdSchedule(rest) {
78
+ await ensureNodeRuntime();
70
79
  const oxmgrBin = Bun.which("oxmgr");
71
80
  if (!oxmgrBin) {
72
81
  process.stderr.write("ay schedule: oxmgr not found\n install with: cargo install oxmgr\n or: bun add -g oxmgr\n");
@@ -141,4 +150,4 @@ async function cmdSchedule(rest) {
141
150
 
142
151
  //#endregion
143
152
  export { cmdSchedule };
144
- //# sourceMappingURL=schedule-CsNFNbbW.js.map
153
+ //# sourceMappingURL=schedule-DCVkaHCo.js.map
@@ -1,18 +1,19 @@
1
- import "./ts-BdFKarex.js";
1
+ import "./ts-Cp_21mny.js";
2
2
  import "./logger-CDIsZ-Pp.js";
3
- import { r as getInstalledPackage } from "./versionChecker-DEJVuzWZ.js";
4
- import { t as findSpawnHiddenLauncher } from "./rustBinary-INWRomvk.js";
3
+ import { r as getInstalledPackage } from "./versionChecker-CaOEu_WC.js";
4
+ import { t as findSpawnHiddenLauncher } from "./rustBinary-CeRekAdR.js";
5
5
  import "./pidStore-BIvsBQ8X.js";
6
6
  import { a as updateGlobalPidStatus } from "./globalPidIndex-CoNr7tS8.js";
7
7
  import { t as pgidForWrapper } from "./reaper-CWF2_ATd.js";
8
8
  import "./configShared-0MnIQ652.js";
9
- import { t as SUPPORTED_CLIS } from "./SUPPORTED_CLIS-C0fh_eJs.js";
10
- import { $ as TYPING_BADGE, D as recentReadEdges, E as readPtysize, H as writeToIpc, I as snapshotStatus, O as renderLogTailLines, S as listRecords, T as readNotes, b as isUserTyping, f as extractNeedsInput, j as resolveOne, k as renderRawLog, l as deriveLiveStatus, o as controlCodeFromName, p as extractTaskCounts, u as extractBadges } from "./subcommands-IIDRpOa1.js";
9
+ import { t as SUPPORTED_CLIS } from "./SUPPORTED_CLIS-CryNU1fs.js";
10
+ import { $ as TYPING_BADGE, D as recentReadEdges, E as readPtysize, H as writeToIpc, I as snapshotStatus, O as renderLogTailLines, S as listRecords, T as readNotes, b as isUserTyping, f as extractNeedsInput, j as resolveOne, k as renderRawLog, l as deriveLiveStatus, o as controlCodeFromName, p as extractTaskCounts, u as extractBadges } from "./subcommands-Cq1mzI8Z.js";
11
11
  import "./e2e-BeKjLhmO.js";
12
12
  import "./webrtcLink-BG0Xc4-W.js";
13
- import "./remotes-CgT91bMo.js";
13
+ import "./remotes-oSmwSYaV.js";
14
14
  import { a as getSpawnHook, c as hasProvisionHook, d as resolveSpawnCwd, i as getProvisionRoot, l as hasSpawnHook, r as getProvisionHook, u as isProvisionAllowed } from "./workspaceConfig-_GtAZtsi.js";
15
- import { r as spawnRejectionReason } from "./spawnGate-CA5QD7D4.js";
15
+ import { n as liveEnv, t as ensureNodeRuntime } from "./nodeRuntime-DZRjxpNp.js";
16
+ import { r as spawnRejectionReason } from "./spawnGate-DRWa_Fzj.js";
16
17
  import yargs from "yargs";
17
18
  import { mkdir, open, readFile, stat, unlink, writeFile } from "fs/promises";
18
19
  import { arch, cpus, freemem, homedir, hostname, loadavg, platform, totalmem, uptime, userInfo } from "os";
@@ -239,7 +240,8 @@ function oxmgrHasWindowsFix(bin) {
239
240
  "ignore",
240
241
  "pipe",
241
242
  "ignore"
242
- ]
243
+ ],
244
+ env: { ...process.env }
243
245
  }));
244
246
  } catch {
245
247
  oxmgrWinFixCache = false;
@@ -289,16 +291,35 @@ async function globalBinDir(installer) {
289
291
  if (!out) return null;
290
292
  return isBun ? out : path.join(out, "bin");
291
293
  }
292
- async function managerRunnable(mgr) {
294
+ function isNoNodeExecError(stderr) {
295
+ return /env: '?node'?: No such file or directory/.test(stderr) || /'node' is not recognized/.test(stderr);
296
+ }
297
+ async function managerProbe(mgr) {
293
298
  try {
294
- return (await Bun.spawn([mgr.bin, "--version"], {
299
+ const p = Bun.spawn([mgr.bin, "--version"], {
295
300
  stdout: "ignore",
296
- stderr: "ignore"
297
- }).exited ?? 1) === 0;
298
- } catch {
299
- return false;
301
+ stderr: "pipe",
302
+ env: {
303
+ ...liveEnv(),
304
+ LC_ALL: "C"
305
+ }
306
+ });
307
+ const [code, stderr] = await Promise.all([p.exited, new Response(p.stderr).text()]);
308
+ return {
309
+ ok: (code ?? 1) === 0,
310
+ stderr
311
+ };
312
+ } catch (e) {
313
+ return {
314
+ ok: false,
315
+ stderr: String(e)
316
+ };
300
317
  }
301
318
  }
319
+ async function managerRunnable(mgr) {
320
+ await ensureNodeRuntime();
321
+ return (await managerProbe(mgr)).ok;
322
+ }
302
323
  async function resolveActiveManager() {
303
324
  const oxmgr = Bun.which("oxmgr");
304
325
  const pm2 = Bun.which("pm2");
@@ -335,11 +356,14 @@ async function installAndVerify(pkg) {
335
356
  ] : null;
336
357
  if (!installer) return null;
337
358
  process.stderr.write(`ay serve install: installing ${pkg}…\n`);
338
- const code = await Bun.spawn(installer, { stdio: [
339
- "ignore",
340
- "inherit",
341
- "inherit"
342
- ] }).exited ?? 1;
359
+ const code = await Bun.spawn(installer, {
360
+ stdio: [
361
+ "ignore",
362
+ "inherit",
363
+ "inherit"
364
+ ],
365
+ env: liveEnv()
366
+ }).exited ?? 1;
343
367
  if (code !== 0) {
344
368
  process.stderr.write(`ay serve install: '${installer.join(" ")}' failed (exit ${code})\n`);
345
369
  return null;
@@ -352,8 +376,12 @@ async function installAndVerify(pkg) {
352
376
  id: pkg,
353
377
  bin
354
378
  };
355
- if (!await managerRunnable(mgr)) {
356
- const why = pkg === "oxmgr" ? "a native/glibc mismatch, e.g. glibc < 2.39" : "pm2 needs a Node.js runtime and none was found";
379
+ await ensureNodeRuntime();
380
+ const probe = await managerProbe(mgr);
381
+ if (!probe.ok) {
382
+ const detailLine = probe.stderr.trim().split("\n").filter(Boolean).pop()?.slice(0, 160);
383
+ const detail = detailLine ? ` — ${detailLine}` : "";
384
+ const why = isNoNodeExecError(probe.stderr) ? `${pkg} needs a Node.js runtime (its bin is a '#!/usr/bin/env node' script) and none was found` : pkg === "oxmgr" ? `likely a native binary mismatch, e.g. glibc < 2.39 on Linux${detail}` : `exec probe failed${detail}`;
357
385
  process.stderr.write(`ay serve install: ${pkg} installed but can't exec here (${why})` + (pkg === "oxmgr" ? " — falling back to pm2\n" : "\n"));
358
386
  return null;
359
387
  }
@@ -417,11 +445,14 @@ async function ensureBootAutostart(mgr) {
417
445
  }
418
446
  async function spawnExit(cmd) {
419
447
  try {
420
- return await Bun.spawn(cmd, { stdio: [
421
- "ignore",
422
- "ignore",
423
- "ignore"
424
- ] }).exited ?? 1;
448
+ return await Bun.spawn(cmd, {
449
+ stdio: [
450
+ "ignore",
451
+ "ignore",
452
+ "ignore"
453
+ ],
454
+ env: liveEnv()
455
+ }).exited ?? 1;
425
456
  } catch {
426
457
  return 1;
427
458
  }
@@ -435,7 +466,8 @@ async function readDaemonServeArgs(mgr) {
435
466
  DAEMON_NAME
436
467
  ], {
437
468
  stdout: "pipe",
438
- stderr: "ignore"
469
+ stderr: "ignore",
470
+ env: liveEnv()
439
471
  });
440
472
  const out = await new Response(p.stdout).text();
441
473
  if (await p.exited !== 0) return null;
@@ -446,7 +478,8 @@ async function readDaemonServeArgs(mgr) {
446
478
  }
447
479
  const p = Bun.spawn([mgr.bin, "jlist"], {
448
480
  stdout: "pipe",
449
- stderr: "ignore"
481
+ stderr: "ignore",
482
+ env: liveEnv()
450
483
  });
451
484
  const out = await new Response(p.stdout).text();
452
485
  if (await p.exited !== 0) return null;
@@ -489,12 +522,12 @@ async function fetchDaemonVersion(port, token) {
489
522
  async function cmdServeDaemon(sub, args) {
490
523
  let mgr = resolveDaemonManager();
491
524
  if (mgr && !await managerRunnable(mgr)) {
492
- process.stderr.write(`ay serve install: ${mgr.id} is on PATH but can't exec here (likely a native/glibc mismatch) — bootstrapping a working manager…\n`);
525
+ process.stderr.write(`ay serve install: ${mgr.id} is on PATH but can't exec here — bootstrapping a working manager…\n`);
493
526
  mgr = null;
494
527
  }
495
528
  if (!mgr) mgr = await bootstrapDaemonManager();
496
529
  if (!mgr) {
497
- process.stderr.write("ay serve install: no usable process manager (need oxmgr or pm2)\n - oxmgr: bun add -g oxmgr (native binary; needs glibc ≥ 2.39 on Linux)\n - pm2: bun add -g pm2 (needs a Node.js runtime on PATH)\n On a minimal bun-only box, install node (for pm2) or a newer glibc (for oxmgr).\n");
530
+ process.stderr.write("ay serve install: no usable process manager (need oxmgr or pm2)\n - oxmgr: bun add -g oxmgr (native binary; needs glibc ≥ 2.39 on Linux)\n - pm2: bun add -g pm2 (pure JS; needs a node runtime on a bun-only box\n ay auto-writes a node→bun shim into ~/.agent-yes/bin, so if you still\n see this, check that dir is writable or install node)\n");
498
531
  return 1;
499
532
  }
500
533
  if (sub === "install") {
@@ -577,11 +610,14 @@ async function cmdServeDaemon(sub, args) {
577
610
  "--",
578
611
  ...managedArgv.slice(1)
579
612
  ];
580
- const code = await Bun.spawn(startArgv, { stdio: [
581
- "ignore",
582
- "inherit",
583
- "inherit"
584
- ] }).exited;
613
+ const code = await Bun.spawn(startArgv, {
614
+ stdio: [
615
+ "ignore",
616
+ "inherit",
617
+ "inherit"
618
+ ],
619
+ env: liveEnv()
620
+ }).exited;
585
621
  if (code === 0) {
586
622
  const onBoot = await ensureBootAutostart(mgr);
587
623
  const port = portFromArgs(effArgs);
@@ -607,11 +643,14 @@ async function cmdServeDaemon(sub, args) {
607
643
  mgr.bin,
608
644
  "delete",
609
645
  DAEMON_NAME
610
- ], { stdio: [
611
- "ignore",
612
- "inherit",
613
- "inherit"
614
- ] }).exited ?? 1;
646
+ ], {
647
+ stdio: [
648
+ "ignore",
649
+ "inherit",
650
+ "inherit"
651
+ ],
652
+ env: liveEnv()
653
+ }).exited ?? 1;
615
654
  if (mgr.id === "pm2" && code === 0) {
616
655
  await spawnExit([mgr.bin, "save"]);
617
656
  if (process.platform === "win32") await spawnExit([
@@ -630,11 +669,14 @@ async function cmdServeDaemon(sub, args) {
630
669
  "logs",
631
670
  DAEMON_NAME,
632
671
  ...args
633
- ], { stdio: [
634
- "ignore",
635
- "inherit",
636
- "inherit"
637
- ] }).exited ?? 1;
672
+ ], {
673
+ stdio: [
674
+ "ignore",
675
+ "inherit",
676
+ "inherit"
677
+ ],
678
+ env: liveEnv()
679
+ }).exited ?? 1;
638
680
  return 1;
639
681
  }
640
682
  async function cmdServeStatus(args) {
@@ -1851,7 +1893,7 @@ Options:
1851
1893
  const perm = body.perm ?? "r";
1852
1894
  if (perm !== "r" && perm !== "rw") return new Response(`invalid perm ${perm} (want r or rw)`, { status: 400 });
1853
1895
  try {
1854
- const { createScopedShare } = await import("./agentShare-Byzqbfk6.js");
1896
+ const { createScopedShare } = await import("./agentShare-BY9WWDBm.js");
1855
1897
  const share = await createScopedShare({
1856
1898
  agent: body.agent,
1857
1899
  perm,
@@ -1866,12 +1908,12 @@ Options:
1866
1908
  }
1867
1909
  }
1868
1910
  if (req.method === "GET" && p === "/api/shares") {
1869
- const { listShares } = await import("./agentShare-Byzqbfk6.js");
1911
+ const { listShares } = await import("./agentShare-BY9WWDBm.js");
1870
1912
  return Response.json(listShares());
1871
1913
  }
1872
1914
  const revokeM = /^\/api\/share\/([^/]+)$/.exec(p);
1873
1915
  if (req.method === "DELETE" && revokeM) {
1874
- const { revokeShare } = await import("./agentShare-Byzqbfk6.js");
1916
+ const { revokeShare } = await import("./agentShare-BY9WWDBm.js");
1875
1917
  const ok = revokeShare(decodeURIComponent(revokeM[1]));
1876
1918
  return new Response(ok ? "revoked" : "no such share", { status: ok ? 200 : 404 });
1877
1919
  }
@@ -2052,7 +2094,7 @@ Options:
2052
2094
  const shutdown = (resolve) => {
2053
2095
  if (heartbeat) clearInterval(heartbeat);
2054
2096
  closeShare?.();
2055
- import("./agentShare-Byzqbfk6.js").then((m) => m.revokeAllShares()).catch(() => {});
2097
+ import("./agentShare-BY9WWDBm.js").then((m) => m.revokeAllShares()).catch(() => {});
2056
2098
  server?.stop();
2057
2099
  resolve();
2058
2100
  };
@@ -2065,4 +2107,4 @@ Options:
2065
2107
 
2066
2108
  //#endregion
2067
2109
  export { cmdServe };
2068
- //# sourceMappingURL=serve-CfR-7uMU.js.map
2110
+ //# sourceMappingURL=serve-Dxxm6cs6.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-CfR-7uMU.js");
35
+ const { cmdServe } = await import("./serve-Dxxm6cs6.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-0Oby3hYf.js.map
45
+ //# sourceMappingURL=setup-CnHHrqP9.js.map
@@ -1,5 +1,5 @@
1
1
  import "./logger-CDIsZ-Pp.js";
2
2
  import "./globalPidIndex-CoNr7tS8.js";
3
- import { i as waitForSpawnCapacity, n as spawnGateEnabled, r as spawnRejectionReason, t as memAvailableMb } from "./spawnGate-CA5QD7D4.js";
3
+ import { i as waitForSpawnCapacity, n as spawnGateEnabled, r as spawnRejectionReason, t as memAvailableMb } from "./spawnGate-DRWa_Fzj.js";
4
4
 
5
5
  export { waitForSpawnCapacity };
@@ -104,4 +104,4 @@ async function waitForSpawnCapacity(opts) {
104
104
 
105
105
  //#endregion
106
106
  export { waitForSpawnCapacity as i, spawnGateEnabled as n, spawnRejectionReason as r, memAvailableMb as t };
107
- //# sourceMappingURL=spawnGate-CA5QD7D4.js.map
107
+ //# sourceMappingURL=spawnGate-DRWa_Fzj.js.map
@@ -1,9 +1,9 @@
1
1
  import "./logger-CDIsZ-Pp.js";
2
2
  import "./globalPidIndex-CoNr7tS8.js";
3
3
  import "./configShared-0MnIQ652.js";
4
- import { A as renderRawLogLines, B as waitForLogQuiet, C as matchKeyword, D as recentReadEdges, E as readPtysize, F as runSubcommand, H as writeToIpc, I as snapshotStatus, L as stdinActivityPath, M as resolveReadWindow, N as resolveResumeArgs, O as renderLogTailLines, P as restartHintLines, R as stopTipForCli, S as listRecords, T as readNotes, V as writeKeysPaced, _ as isPidAlive, a as cmdHelp, b as isUserTyping, c as deriveLiveState, d as extractMenu, f as extractNeedsInput, g as isExitRequest, h as isAgentStuck, i as backoffWhileTyping, j as resolveOne, k as renderRawLog, l as deriveLiveStatus, m as finalizedLines, n as READ_PAGE_DEFAULT, o as controlCodeFromName, p as extractTaskCounts, r as TYPING_WINDOW_MS, s as cursorAbs, t as GRACEFUL_EXIT_COMMANDS, u as extractBadges, v as isSlashCommand, w as menuSelectKeys, x as lastStdinAt, y as isSubcommand, z as submitAndConfirm } from "./subcommands-IIDRpOa1.js";
4
+ import { A as renderRawLogLines, B as waitForLogQuiet, C as matchKeyword, D as recentReadEdges, E as readPtysize, F as runSubcommand, H as writeToIpc, I as snapshotStatus, L as stdinActivityPath, M as resolveReadWindow, N as resolveResumeArgs, O as renderLogTailLines, P as restartHintLines, R as stopTipForCli, S as listRecords, T as readNotes, V as writeKeysPaced, _ as isPidAlive, a as cmdHelp, b as isUserTyping, c as deriveLiveState, d as extractMenu, f as extractNeedsInput, g as isExitRequest, h as isAgentStuck, i as backoffWhileTyping, j as resolveOne, k as renderRawLog, l as deriveLiveStatus, m as finalizedLines, n as READ_PAGE_DEFAULT, o as controlCodeFromName, p as extractTaskCounts, r as TYPING_WINDOW_MS, s as cursorAbs, t as GRACEFUL_EXIT_COMMANDS, u as extractBadges, v as isSlashCommand, w as menuSelectKeys, x as lastStdinAt, y as isSubcommand, z as submitAndConfirm } from "./subcommands-Cq1mzI8Z.js";
5
5
  import "./e2e-BeKjLhmO.js";
6
6
  import "./webrtcLink-BG0Xc4-W.js";
7
- import "./remotes-CgT91bMo.js";
7
+ import "./remotes-oSmwSYaV.js";
8
8
 
9
9
  export { cmdHelp, isSubcommand, runSubcommand };
@@ -4,7 +4,7 @@ import { t as agentYesHome } from "./agentYesHome-CtHb5b71.js";
4
4
  import { a as updateGlobalPidStatus, i as readGlobalPids } from "./globalPidIndex-CoNr7tS8.js";
5
5
  import { t as loadSharedCliDefaults } from "./configShared-0MnIQ652.js";
6
6
  import { n as isWebrtcSpec } from "./webrtcLink-BG0Xc4-W.js";
7
- import { a as resolveRemoteSpec, i as readRemotes } from "./remotes-CgT91bMo.js";
7
+ import { a as resolveRemoteSpec, i as readRemotes } from "./remotes-oSmwSYaV.js";
8
8
  import ms from "ms";
9
9
  import yargs from "yargs";
10
10
  import { appendFile, mkdir, open, readFile, readdir, rename, rm, stat, writeFile } from "fs/promises";
@@ -1147,19 +1147,19 @@ async function runSubcommand(argv) {
1147
1147
  case "restart": return await cmdRestart(rest);
1148
1148
  case "note": return await cmdNote(rest);
1149
1149
  case "serve": {
1150
- const { cmdServe } = await import("./serve-CfR-7uMU.js");
1150
+ const { cmdServe } = await import("./serve-Dxxm6cs6.js");
1151
1151
  return cmdServe(rest);
1152
1152
  }
1153
1153
  case "setup": {
1154
- const { cmdSetup } = await import("./setup-0Oby3hYf.js");
1154
+ const { cmdSetup } = await import("./setup-CnHHrqP9.js");
1155
1155
  return cmdSetup(rest);
1156
1156
  }
1157
1157
  case "schedule": {
1158
- const { cmdSchedule } = await import("./schedule-CsNFNbbW.js");
1158
+ const { cmdSchedule } = await import("./schedule-DCVkaHCo.js");
1159
1159
  return cmdSchedule(rest);
1160
1160
  }
1161
1161
  case "remote": {
1162
- const { cmdRemote } = await import("./remotes-WVJBNajZ.js");
1162
+ const { cmdRemote } = await import("./remotes-CW-yxSgW.js");
1163
1163
  return cmdRemote(rest);
1164
1164
  }
1165
1165
  case "expose": {
@@ -1556,7 +1556,7 @@ async function fetchRemoteRecordsRaw(url, token, opts) {
1556
1556
  let base = url;
1557
1557
  let bearer = token;
1558
1558
  if (isWebrtcSpec(url)) {
1559
- const { startWebrtcBridge } = await import("./webrtcRemote-CD5EQ3uX.js");
1559
+ const { startWebrtcBridge } = await import("./webrtcRemote-BmuVKcrx.js");
1560
1560
  bridge = await startWebrtcBridge(url);
1561
1561
  base = bridge.baseUrl;
1562
1562
  bearer = bridge.token;
@@ -4004,7 +4004,7 @@ async function cmdNotify(rest) {
4004
4004
  }
4005
4005
  const ensure = async () => {
4006
4006
  if (!argv["ensure-daemon"]) return;
4007
- const { ensureDaemon } = await import("./notifyDaemon-DjuvLK7-.js");
4007
+ const { ensureDaemon } = await import("./notifyDaemon-BPcU9HOC.js");
4008
4008
  await ensureDaemon().catch(() => null);
4009
4009
  };
4010
4010
  await heartbeatWatcher(parent, selfStartedAt);
@@ -4078,7 +4078,7 @@ async function cmdNotifyCursor(args) {
4078
4078
  }
4079
4079
  async function cmdNotifyd(rest) {
4080
4080
  const sub = rest[0] ?? "status";
4081
- const daemon = await import("./notifyDaemon-DjuvLK7-.js");
4081
+ const daemon = await import("./notifyDaemon-BPcU9HOC.js");
4082
4082
  switch (sub) {
4083
4083
  case "run": return daemon.runDaemon();
4084
4084
  case "once": return daemon.runDaemon({ once: true });
@@ -4105,4 +4105,4 @@ async function cmdNotifyd(rest) {
4105
4105
 
4106
4106
  //#endregion
4107
4107
  export { TYPING_BADGE as $, renderRawLogLines as A, waitForLogQuiet as B, matchKeyword as C, recentReadEdges as D, readPtysize as E, runSubcommand as F, hostId as G, writeToIpc as H, snapshotStatus as I, readInbox as J, listInboxParents as K, stdinActivityPath as L, resolveReadWindow as M, resolveResumeArgs as N, renderLogTailLines as O, restartHintLines as P, notifyDir as Q, stopTipForCli as R, listRecords as S, readNotes as T, appendEvent as U, writeKeysPaced as V, gcInboxes as W, daemonLockDir as X, shouldStealLock as Y, daemonLockOwnerPath as Z, isPidAlive as _, cmdHelp as a, isUserTyping as b, deriveLiveState as c, extractMenu as d, extractNeedsInput as f, isExitRequest as g, isAgentStuck as h, backoffWhileTyping as i, resolveOne as j, renderRawLog as k, deriveLiveStatus as l, finalizedLines as m, READ_PAGE_DEFAULT as n, controlCodeFromName as o, extractTaskCounts as p, liveWatchers as q, TYPING_WINDOW_MS as r, cursorAbs as s, GRACEFUL_EXIT_COMMANDS as t, extractBadges as u, isSlashCommand as v, menuSelectKeys as w, lastStdinAt as x, isSubcommand as y, submitAndConfirm as z };
4108
- //# sourceMappingURL=subcommands-IIDRpOa1.js.map
4108
+ //# sourceMappingURL=subcommands-Cq1mzI8Z.js.map
@@ -187,4 +187,4 @@ async function startTray() {
187
187
 
188
188
  //#endregion
189
189
  export { ensureTray, startTray };
190
- //# sourceMappingURL=tray-PMOWFOfk.js.map
190
+ //# sourceMappingURL=tray-BKTZ5gIf.js.map
@@ -1,5 +1,5 @@
1
1
  import { n as logger, t as addTransport } from "./logger-CDIsZ-Pp.js";
2
- import { r as getInstalledPackage } from "./versionChecker-DEJVuzWZ.js";
2
+ import { r as getInstalledPackage } from "./versionChecker-CaOEu_WC.js";
3
3
  import { t as agentYesHome } from "./agentYesHome-CtHb5b71.js";
4
4
  import { i as shouldUseLock, r as releaseLock, t as acquireLock } from "./runningLock-CNMl13dC.js";
5
5
  import { t as PidStore } from "./pidStore-BIvsBQ8X.js";
@@ -1824,4 +1824,4 @@ function sleep(ms) {
1824
1824
 
1825
1825
  //#endregion
1826
1826
  export { removeControlCharacters as a, AgentContext as i, agentYes as n, config as r, CLIS_CONFIG as t };
1827
- //# sourceMappingURL=ts-BdFKarex.js.map
1827
+ //# sourceMappingURL=ts-Cp_21mny.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.192.0";
10
+ var version = "1.192.2";
11
11
 
12
12
  //#endregion
13
13
  //#region ts/versionChecker.ts
@@ -215,4 +215,4 @@ async function displayVersion() {
215
215
 
216
216
  //#endregion
217
217
  export { versionString as i, displayVersion as n, getInstalledPackage as r, checkAndAutoUpdate as t };
218
- //# sourceMappingURL=versionChecker-DEJVuzWZ.js.map
218
+ //# sourceMappingURL=versionChecker-CaOEu_WC.js.map
@@ -256,4 +256,4 @@ async function startWebrtcBridge(link) {
256
256
 
257
257
  //#endregion
258
258
  export { startWebrtcBridge };
259
- //# sourceMappingURL=webrtcRemote-CD5EQ3uX.js.map
259
+ //# sourceMappingURL=webrtcRemote-BmuVKcrx.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agent-yes",
3
- "version": "1.192.0",
3
+ "version": "1.192.2",
4
4
  "description": "A wrapper tool that automates interactions with various AI CLI tools by automatically handling common prompts and responses.",
5
5
  "keywords": [
6
6
  "ai",
@@ -0,0 +1,99 @@
1
+ import { mkdtemp, readFile, rm, stat } from "fs/promises";
2
+ import { tmpdir } from "os";
3
+ import path from "path";
4
+ import { afterEach, beforeEach, describe, expect, it } from "vitest";
5
+ import { ensureNodeRuntime, liveEnv } from "./nodeRuntime.ts";
6
+
7
+ // process.platform is stubbed per test (instead of skipIf) so every branch of
8
+ // ensureNodeRuntime is exercised on every CI OS — the win32 early-return on
9
+ // POSIX runners and the POSIX shim path on Windows runners (mkdir/writeFile/
10
+ // chmod all work there; the shim just isn't consulted by real spawns).
11
+ const realPlatform = process.platform;
12
+ function setPlatform(p: string) {
13
+ Object.defineProperty(process, "platform", { value: p, configurable: true });
14
+ }
15
+
16
+ // The bun-only-no-node path (sym003): pm2/oxmgr bins are `#!/usr/bin/env node`
17
+ // scripts, so with no node on PATH they die at the shebang. ensureNodeRuntime
18
+ // must bridge that with a node→bun shim in ay's own bin dir.
19
+ describe("ensureNodeRuntime", () => {
20
+ let home: string;
21
+ let savedPath: string | undefined;
22
+ let savedHome: string | undefined;
23
+
24
+ beforeEach(async () => {
25
+ home = await mkdtemp(path.join(tmpdir(), "ay-node-shim-"));
26
+ savedPath = process.env.PATH;
27
+ savedHome = process.env.AGENT_YES_HOME;
28
+ process.env.AGENT_YES_HOME = home;
29
+ setPlatform("linux");
30
+ });
31
+
32
+ afterEach(async () => {
33
+ setPlatform(realPlatform);
34
+ process.env.PATH = savedPath;
35
+ if (savedHome === undefined) delete process.env.AGENT_YES_HOME;
36
+ else process.env.AGENT_YES_HOME = savedHome;
37
+ await rm(home, { recursive: true, force: true });
38
+ });
39
+
40
+ const noNode = (cmd: string) => (cmd === "bun" ? "/fake/bin/bun" : null);
41
+
42
+ it("writes an executable node→bun shim and prepends it to PATH when node is absent", async () => {
43
+ const shim = await ensureNodeRuntime(noNode);
44
+ expect(shim).toBe(path.join(home, "bin", "node"));
45
+ const body = await readFile(shim!, "utf-8");
46
+ expect(body).toBe("#!/bin/sh\nexec '/fake/bin/bun' \"$@\"\n");
47
+ if (realPlatform !== "win32") {
48
+ expect((await stat(shim!)).mode & 0o111).not.toBe(0); // executable
49
+ }
50
+ expect(process.env.PATH!.split(path.delimiter)[0]).toBe(path.join(home, "bin"));
51
+ });
52
+
53
+ it("does not duplicate the PATH entry", async () => {
54
+ await ensureNodeRuntime(noNode);
55
+ await ensureNodeRuntime(noNode);
56
+ const binDir = path.join(home, "bin");
57
+ const hits = process.env.PATH!.split(path.delimiter).filter((p) => p === binDir);
58
+ expect(hits).toHaveLength(1);
59
+ });
60
+
61
+ it("leaves an up-to-date shim untouched on repeat calls (read-only paths stay read-only)", async () => {
62
+ const shim = (await ensureNodeRuntime(noNode))!;
63
+ const before = await stat(shim);
64
+ await new Promise((r) => setTimeout(r, 20));
65
+ await ensureNodeRuntime(noNode);
66
+ const after = await stat(shim);
67
+ expect(after.mtimeMs).toBe(before.mtimeMs); // not rewritten
68
+ });
69
+
70
+ it("single-quotes a bun path containing sh-special characters", async () => {
71
+ const shim = await ensureNodeRuntime((cmd) => (cmd === "bun" ? "/opt/we$ird `dir'/bun" : null));
72
+ const body = await readFile(shim!, "utf-8");
73
+ expect(body).toBe("#!/bin/sh\nexec '/opt/we$ird `dir'\\''/bun' \"$@\"\n");
74
+ });
75
+
76
+ it("is a no-op when a real node exists", async () => {
77
+ expect(await ensureNodeRuntime(() => "/usr/bin/whatever")).toBeNull();
78
+ });
79
+
80
+ it("is a no-op when bun is missing too (nothing to shim to)", async () => {
81
+ expect(await ensureNodeRuntime(() => null)).toBeNull();
82
+ });
83
+
84
+ it("is a no-op on Windows (npm .cmd shims invoke node.exe directly)", async () => {
85
+ setPlatform("win32");
86
+ expect(await ensureNodeRuntime(noNode)).toBeNull();
87
+ });
88
+ });
89
+
90
+ describe("liveEnv", () => {
91
+ it("carries post-startup process.env mutations (unlike Bun.spawn's implicit env)", () => {
92
+ process.env.AY_LIVE_ENV_TEST = "set-after-start";
93
+ try {
94
+ expect(liveEnv().AY_LIVE_ENV_TEST).toBe("set-after-start");
95
+ } finally {
96
+ delete process.env.AY_LIVE_ENV_TEST;
97
+ }
98
+ });
99
+ });
@@ -0,0 +1,58 @@
1
+ import { chmod, mkdir, readFile, writeFile } from "fs/promises";
2
+ import path from "path";
3
+ import { agentYesHome } from "./agentYesHome.ts";
4
+
5
+ /**
6
+ * Snapshot of the CURRENT process.env for child spawns. Bun.spawn without an
7
+ * explicit `env` hands the child the environ captured at PROCESS STARTUP — not
8
+ * the live process.env — so post-startup mutations (ensureNodeRuntime's shim
9
+ * PATH prepend, installAndVerify's global-bin-dir prepend) silently never reach
10
+ * the child. That is exactly how `ay serve install` kept dying with
11
+ * `env: node: No such file or directory` at the `pm2 start` spawn on a bun-only
12
+ * box even though the probe (which passes env explicitly) had just succeeded.
13
+ * Every spawn of a process-manager binary must pass `env: liveEnv()`.
14
+ */
15
+ export function liveEnv(): Record<string, string | undefined> {
16
+ return { ...process.env };
17
+ }
18
+
19
+ /**
20
+ * Both oxmgr's and pm2's global bins are `#!/usr/bin/env node` JS scripts, so on
21
+ * a bun-only box (setup.sh installs no node) exec dies with "env: node: No such
22
+ * file or directory" — even though pm2 is pure JS and runs perfectly under bun.
23
+ * When node is missing but bun exists, write a node→bun shim into ay's own bin
24
+ * dir and prepend it to PATH so `env node` resolves. NOT solvable with
25
+ * `bun add -g node`: that package (node-bin-gen) lands a broken arch-specific
26
+ * stub and `Bun.which("node")` still finds nothing. POSIX-only — on Windows the
27
+ * npm .cmd shims invoke node.exe directly and an sh script can't stand in.
28
+ * Read-only paths (`ay serve status`) also reach this via the manager probes:
29
+ * an up-to-date shim is left untouched there (a read, not a write), so only the
30
+ * very first run on a node-less box materializes the file.
31
+ * Returns the shim path when the shim is in effect, null when unneeded/impossible.
32
+ */
33
+ export async function ensureNodeRuntime(
34
+ which: (cmd: string) => string | null = Bun.which,
35
+ ): Promise<string | null> {
36
+ if (process.platform === "win32") return null;
37
+ if (which("node")) return null;
38
+ const bun = which("bun");
39
+ if (!bun) return null;
40
+ const binDir = path.join(agentYesHome(), "bin");
41
+ const shim = path.join(binDir, "node");
42
+ // Single-quote the bun path: inside sh double quotes `$`, backtick and `\`
43
+ // would still expand, corrupting the shim for a path containing them.
44
+ const body = `#!/bin/sh\nexec '${bun.replace(/'/g, `'\\''`)}' "$@"\n`;
45
+ try {
46
+ if ((await readFile(shim, "utf-8").catch(() => null)) !== body) {
47
+ await mkdir(binDir, { recursive: true });
48
+ await writeFile(shim, body);
49
+ await chmod(shim, 0o755);
50
+ }
51
+ if (!(process.env.PATH ?? "").split(path.delimiter).includes(binDir)) {
52
+ process.env.PATH = `${binDir}${path.delimiter}${process.env.PATH ?? ""}`;
53
+ }
54
+ return shim;
55
+ } catch {
56
+ return null; // best-effort: the exec probe will fail and name the reason
57
+ }
58
+ }
@@ -1,3 +1,4 @@
1
+ import { liveEnv } from "./nodeRuntime.ts";
1
2
  // Register oxmgr's daemon with the platform init system (launchd on macOS,
2
3
  // systemd on Linux, Task Scheduler on Windows) so managed processes survive a
3
4
  // *reboot*, not just a crash.
@@ -18,8 +19,12 @@ export async function ensureBootAutostart(oxmgrBin: string): Promise<boolean> {
18
19
  try {
19
20
  // Already registered with the init system? Then we're done — don't bounce
20
21
  // the daemon (and all its children) just to re-assert what's already true.
22
+ // env: liveEnv() so the node→bun shim's PATH prepend reaches oxmgr's
23
+ // `#!/usr/bin/env node` launcher (implicit inheritance uses the startup
24
+ // environ, missing post-startup mutations).
21
25
  const status = Bun.spawn([oxmgrBin, "service", "status"], {
22
26
  stdio: ["ignore", "ignore", "ignore"],
27
+ env: liveEnv(),
23
28
  });
24
29
  if ((await status.exited) === 0) return true;
25
30
 
@@ -28,6 +33,7 @@ export async function ensureBootAutostart(oxmgrBin: string): Promise<boolean> {
28
33
  // so passing it after `install` is rejected.
29
34
  const svc = Bun.spawn([oxmgrBin, "service", "install"], {
30
35
  stdio: ["ignore", "ignore", "ignore"],
36
+ env: liveEnv(),
31
37
  });
32
38
  return (await svc.exited) === 0;
33
39
  } catch {
package/ts/schedule.ts CHANGED
@@ -2,6 +2,7 @@ import { createHash } from "node:crypto";
2
2
  import { SUPPORTED_CLIS } from "./SUPPORTED_CLIS.ts";
3
3
  import { resolveSpawnCwd } from "./workspaceConfig.ts";
4
4
  import { ensureBootAutostart } from "./oxmgrService.ts";
5
+ import { ensureNodeRuntime, liveEnv } from "./nodeRuntime.ts";
5
6
 
6
7
  // `ay schedule` — run an agent on a recurring schedule via oxmgr's cron support.
7
8
  // A scheduled job runs once immediately AND on every cron tick (with
@@ -33,16 +34,23 @@ function schedName(explicit: string | undefined, cli: string, key: string): stri
33
34
  }
34
35
 
35
36
  async function run(cmd: string[], capture = false): Promise<{ code: number; out: string }> {
37
+ // env: liveEnv() — oxmgr's global bin is a `#!/usr/bin/env node` script, and
38
+ // ensureNodeRuntime's shim PATH prepend only reaches children given the LIVE
39
+ // process.env (Bun.spawn's implicit inheritance uses the startup environ).
36
40
  const p = Bun.spawn(cmd, {
37
41
  stdin: "ignore",
38
42
  stdout: capture ? "pipe" : "inherit",
39
43
  stderr: capture ? "pipe" : "inherit",
44
+ env: liveEnv(),
40
45
  });
41
46
  const out = capture ? await new Response(p.stdout).text() : "";
42
47
  return { code: (await p.exited) ?? 1, out };
43
48
  }
44
49
 
45
50
  export async function cmdSchedule(rest: string[]): Promise<number> {
51
+ // On a bun-only box oxmgr's `#!/usr/bin/env node` launcher needs the node→bun
52
+ // shim before ANY oxmgr call below can exec (same fix as serve-install).
53
+ await ensureNodeRuntime();
46
54
  const oxmgrBin = Bun.which("oxmgr");
47
55
  if (!oxmgrBin) {
48
56
  process.stderr.write(
package/ts/serve.spec.ts CHANGED
@@ -1,5 +1,6 @@
1
+ import { readFile } from "fs/promises";
1
2
  import { describe, expect, it } from "vitest";
2
- import { oxmgrVersionHasWindowsFix } from "./serve.ts";
3
+ import { isNoNodeExecError, oxmgrVersionHasWindowsFix } from "./serve.ts";
3
4
 
4
5
  // Guards the Windows daemon-manager selection: on Windows we only PREFER oxmgr
5
6
  // when the installed build carries the daemon-socket-inheritance fix. Stock
@@ -31,3 +32,61 @@ describe("oxmgrVersionHasWindowsFix", () => {
31
32
  expect(oxmgrVersionHasWindowsFix("oxmgr (unknown)")).toBe(false);
32
33
  });
33
34
  });
35
+
36
+ // Guards the serve-install diagnostic: a missing node runtime must be reported
37
+ // as such, never as a "glibc mismatch" (glibc doesn't even exist on macOS).
38
+ describe("isNoNodeExecError", () => {
39
+ it("matches macOS/BSD env output", () => {
40
+ expect(isNoNodeExecError("env: node: No such file or directory")).toBe(true);
41
+ });
42
+
43
+ it("matches GNU coreutils quoted env output", () => {
44
+ expect(isNoNodeExecError("env: 'node': No such file or directory")).toBe(true);
45
+ });
46
+
47
+ it("matches Windows cmd output", () => {
48
+ expect(
49
+ isNoNodeExecError("'node' is not recognized as an internal or external command"),
50
+ ).toBe(true);
51
+ });
52
+
53
+ it("matches localized-then-normalized output (probe pins LC_ALL=C)", () => {
54
+ // managerProbe spawns with LC_ALL=C precisely so this English form is what
55
+ // we always see; this test documents the coupling.
56
+ expect(isNoNodeExecError("env: node: No such file or directory")).toBe(true);
57
+ });
58
+
59
+ it("does not match a real native/glibc failure", () => {
60
+ expect(
61
+ isNoNodeExecError(
62
+ "oxmgr: /lib/x86_64-linux-gnu/libc.so.6: version `GLIBC_2.39' not found",
63
+ ),
64
+ ).toBe(false);
65
+ expect(isNoNodeExecError("")).toBe(false);
66
+ });
67
+ });
68
+
69
+ // Bun.spawn without an explicit `env` hands the child the environ captured at
70
+ // process startup, NOT the live process.env — so ensureNodeRuntime's shim PATH
71
+ // prepend never reached children spawned that way (`pm2 start` died with
72
+ // `env: node: No such file or directory` right after the probe passed). Guard
73
+ // the fix pattern: every spawn of a daemon-manager binary in serve.ts must pass
74
+ // an explicit env.
75
+ describe("manager spawns pass a live env snapshot", () => {
76
+ it("every Bun.spawn of mgr.bin/startArgv/installer carries an env option", async () => {
77
+ const src = await readFile(new URL("./serve.ts", import.meta.url), "utf-8");
78
+ // Grab each Bun.spawn(...) call whose argv mentions a manager binary.
79
+ // Capture from the call opening through the options object's closing `})`.
80
+ const calls = src.match(
81
+ /Bun\.spawn\((?:\[[^\]]*mgr\.bin[^\]]*\]|startArgv|installer),[\s\S]*?\}\)/g,
82
+ );
83
+ expect(calls?.length).toBeGreaterThanOrEqual(7);
84
+ for (const call of calls!) {
85
+ // Require a real liveEnv() env option, not just the substring "env:"
86
+ // (which a comment inside the options object could satisfy).
87
+ expect(call, `missing explicit env in: ${call.slice(0, 80)}`).toMatch(
88
+ /env: (?:\{\s*(?:\.\.\.)?)?liveEnv\(\)/,
89
+ );
90
+ }
91
+ });
92
+ });
package/ts/serve.ts CHANGED
@@ -25,6 +25,7 @@ import {
25
25
  type CommonOpts,
26
26
  } from "./subcommands.ts";
27
27
  import { TYPING_BADGE } from "./badges.ts";
28
+ import { ensureNodeRuntime, liveEnv } from "./nodeRuntime.ts";
28
29
  import { updateGlobalPidStatus } from "./globalPidIndex.ts";
29
30
  import { spawnRejectionReason } from "./spawnGate.ts";
30
31
  import { findSpawnHiddenLauncher } from "./rustBinary.ts";
@@ -359,6 +360,7 @@ function oxmgrHasWindowsFix(bin: string): boolean {
359
360
  encoding: "utf-8",
360
361
  timeout: 3000,
361
362
  stdio: ["ignore", "pipe", "ignore"],
363
+ env: { ...process.env } as NodeJS.ProcessEnv,
362
364
  });
363
365
  oxmgrWinFixCache = oxmgrVersionHasWindowsFix(out);
364
366
  } catch {
@@ -405,18 +407,44 @@ async function globalBinDir(installer: string[]): Promise<string | null> {
405
407
  return isBun ? out : path.join(out, "bin");
406
408
  }
407
409
 
410
+ // Did an exec attempt die because `env` couldn't find a node runtime? macOS/BSD
411
+ // env says `env: node: No such file or directory`, GNU coreutils quotes it
412
+ // (`env: 'node': …`), Windows cmd says `'node' is not recognized`.
413
+ export function isNoNodeExecError(stderr: string): boolean {
414
+ return (
415
+ /env: '?node'?: No such file or directory/.test(stderr) ||
416
+ /'node' is not recognized/.test(stderr)
417
+ );
418
+ }
419
+
420
+ // Probe one manager binary with `--version`, capturing stderr so a failure can
421
+ // be diagnosed (glibc mismatch vs missing node runtime vs anything else).
422
+ // LC_ALL=C pins env(1)/libc error text to English so isNoNodeExecError's
423
+ // patterns hold on localized systems.
424
+ async function managerProbe(mgr: DaemonManager): Promise<{ ok: boolean; stderr: string }> {
425
+ try {
426
+ const p = Bun.spawn([mgr.bin, "--version"], {
427
+ stdout: "ignore",
428
+ stderr: "pipe",
429
+ env: { ...liveEnv(), LC_ALL: "C" },
430
+ });
431
+ const [code, stderr] = await Promise.all([p.exited, new Response(p.stderr).text()]);
432
+ return { ok: (code ?? 1) === 0, stderr };
433
+ } catch (e) {
434
+ return { ok: false, stderr: String(e) };
435
+ }
436
+ }
437
+
408
438
  // Does this manager's binary actually execute? A `bun add -g oxmgr` can succeed
409
439
  // yet leave a binary that can't run: oxmgr vendors a native binary requiring
410
440
  // GLIBC_2.39, which a box like Debian 12 (glibc 2.36) lacks, so exec dies with
411
- // "GLIBC_2.39 not found". Probe with `--version`: exit 0 means runnable; a
412
- // non-zero exit or spawn failure means the shim is on PATH but unusable.
441
+ // "GLIBC_2.39 not found"; and on a node-less box the `env node` shebang itself
442
+ // fails (see ensureNodeRuntime, applied here so every probe self-heals). Probe
443
+ // with `--version`: exit 0 means runnable; a non-zero exit or spawn failure
444
+ // means the shim is on PATH but unusable.
413
445
  async function managerRunnable(mgr: DaemonManager): Promise<boolean> {
414
- try {
415
- const p = Bun.spawn([mgr.bin, "--version"], { stdout: "ignore", stderr: "ignore" });
416
- return ((await p.exited) ?? 1) === 0;
417
- } catch {
418
- return false;
419
- }
446
+ await ensureNodeRuntime();
447
+ return (await managerProbe(mgr)).ok;
420
448
  }
421
449
 
422
450
  // Which manager is ACTUALLY running our daemon? `resolveDaemonManager` picks by
@@ -452,7 +480,11 @@ async function installAndVerify(pkg: "oxmgr" | "pm2"): Promise<DaemonManager | n
452
480
  const installer = bun ? [bun, "add", "-g", pkg] : npm ? [npm, "install", "-g", pkg] : null;
453
481
  if (!installer) return null;
454
482
  process.stderr.write(`ay serve install: installing ${pkg}…\n`);
455
- const code = (await Bun.spawn(installer, { stdio: ["ignore", "inherit", "inherit"] }).exited) ?? 1;
483
+ const code =
484
+ (await Bun.spawn(installer, {
485
+ stdio: ["ignore", "inherit", "inherit"],
486
+ env: liveEnv(),
487
+ }).exited) ?? 1;
456
488
  if (code !== 0) {
457
489
  process.stderr.write(`ay serve install: '${installer.join(" ")}' failed (exit ${code})\n`);
458
490
  return null;
@@ -464,14 +496,23 @@ async function installAndVerify(pkg: "oxmgr" | "pm2"): Promise<DaemonManager | n
464
496
  const bin = Bun.which(pkg);
465
497
  if (!bin) return null;
466
498
  const mgr: DaemonManager = { id: pkg, bin };
467
- if (!(await managerRunnable(mgr))) {
468
- // Name the actual reason: oxmgr ships a native binary (glibc), pm2 is a
469
- // Node.js app that needs `node` on PATH — a bun-only box has neither by
470
- // default, so a generic "glibc mismatch" would mislead for pm2.
471
- const why =
472
- pkg === "oxmgr"
473
- ? "a native/glibc mismatch, e.g. glibc < 2.39"
474
- : "pm2 needs a Node.js runtime and none was found";
499
+ await ensureNodeRuntime();
500
+ const probe = await managerProbe(mgr);
501
+ if (!probe.ok) {
502
+ // Name the ACTUAL reason from the probe's stderr. A missing node runtime
503
+ // hits both managers identically (`env: node: No such file or directory` —
504
+ // their bins are `#!/usr/bin/env node` scripts), and reporting that as a
505
+ // "glibc mismatch" is nonsense on macOS where glibc doesn't exist. Only
506
+ // blame glibc for an oxmgr that got PAST the shebang and died natively;
507
+ // any other failure just gets the probe's own last stderr line — claiming
508
+ // "no node runtime" here would be false, ensureNodeRuntime just provided one.
509
+ const detailLine = probe.stderr.trim().split("\n").filter(Boolean).pop()?.slice(0, 160);
510
+ const detail = detailLine ? ` — ${detailLine}` : "";
511
+ const why = isNoNodeExecError(probe.stderr)
512
+ ? `${pkg} needs a Node.js runtime (its bin is a '#!/usr/bin/env node' script) and none was found`
513
+ : pkg === "oxmgr"
514
+ ? `likely a native binary mismatch, e.g. glibc < 2.39 on Linux${detail}`
515
+ : `exec probe failed${detail}`;
475
516
  process.stderr.write(
476
517
  `ay serve install: ${pkg} installed but can't exec here (${why})` +
477
518
  (pkg === "oxmgr" ? " — falling back to pm2\n" : "\n"),
@@ -588,7 +629,9 @@ async function ensureBootAutostart(mgr: DaemonManager): Promise<boolean> {
588
629
 
589
630
  async function spawnExit(cmd: string[]): Promise<number> {
590
631
  try {
591
- return (await Bun.spawn(cmd, { stdio: ["ignore", "ignore", "ignore"] }).exited) ?? 1;
632
+ return (
633
+ (await Bun.spawn(cmd, { stdio: ["ignore", "ignore", "ignore"], env: liveEnv() }).exited) ?? 1
634
+ );
592
635
  } catch {
593
636
  return 1;
594
637
  }
@@ -601,7 +644,11 @@ async function spawnExit(cmd: string[]): Promise<number> {
601
644
  async function readDaemonServeArgs(mgr: DaemonManager): Promise<string[] | null> {
602
645
  try {
603
646
  if (mgr.id === "oxmgr") {
604
- const p = Bun.spawn([mgr.bin, "status", DAEMON_NAME], { stdout: "pipe", stderr: "ignore" });
647
+ const p = Bun.spawn([mgr.bin, "status", DAEMON_NAME], {
648
+ stdout: "pipe",
649
+ stderr: "ignore",
650
+ env: liveEnv(),
651
+ });
605
652
  const out = await new Response(p.stdout).text();
606
653
  if ((await p.exited) !== 0) return null;
607
654
  const m = /Command:\s*(.+)/.exec(out);
@@ -609,7 +656,7 @@ async function readDaemonServeArgs(mgr: DaemonManager): Promise<string[] | null>
609
656
  const after = /\bserve\b\s*(.*)$/.exec(m[1]!.trim());
610
657
  return after ? after[1]!.split(/\s+/).filter(Boolean) : [];
611
658
  }
612
- const p = Bun.spawn([mgr.bin, "jlist"], { stdout: "pipe", stderr: "ignore" });
659
+ const p = Bun.spawn([mgr.bin, "jlist"], { stdout: "pipe", stderr: "ignore", env: liveEnv() });
613
660
  const out = await new Response(p.stdout).text();
614
661
  if ((await p.exited) !== 0) return null;
615
662
  const list = JSON.parse(out) as Array<{ name?: string; pm2_env?: { args?: string[] } }>;
@@ -670,7 +717,7 @@ async function cmdServeDaemon(sub: string, args: string[]): Promise<number> {
670
717
  let mgr = resolveDaemonManager();
671
718
  if (mgr && !(await managerRunnable(mgr))) {
672
719
  process.stderr.write(
673
- `ay serve install: ${mgr.id} is on PATH but can't exec here (likely a native/glibc mismatch) — bootstrapping a working manager…\n`,
720
+ `ay serve install: ${mgr.id} is on PATH but can't exec here — bootstrapping a working manager…\n`,
674
721
  );
675
722
  mgr = null;
676
723
  }
@@ -679,8 +726,9 @@ async function cmdServeDaemon(sub: string, args: string[]): Promise<number> {
679
726
  process.stderr.write(
680
727
  "ay serve install: no usable process manager (need oxmgr or pm2)\n" +
681
728
  " - oxmgr: bun add -g oxmgr (native binary; needs glibc ≥ 2.39 on Linux)\n" +
682
- " - pm2: bun add -g pm2 (needs a Node.js runtime on PATH)\n" +
683
- " On a minimal bun-only box, install node (for pm2) or a newer glibc (for oxmgr).\n",
729
+ " - pm2: bun add -g pm2 (pure JS; needs a node runtime on a bun-only box\n" +
730
+ " ay auto-writes a node→bun shim into ~/.agent-yes/bin, so if you still\n" +
731
+ " see this, check that dir is writable or install node)\n",
684
732
  );
685
733
  return 1;
686
734
  }
@@ -836,7 +884,7 @@ async function cmdServeDaemon(sub: string, args: string[]): Promise<number> {
836
884
  "--",
837
885
  ...managedArgv.slice(1),
838
886
  ];
839
- const proc = Bun.spawn(startArgv, { stdio: ["ignore", "inherit", "inherit"] });
887
+ const proc = Bun.spawn(startArgv, { stdio: ["ignore", "inherit", "inherit"], env: liveEnv() });
840
888
  const code = await proc.exited;
841
889
  if (code === 0) {
842
890
  const onBoot = await ensureBootAutostart(mgr);
@@ -887,6 +935,7 @@ async function cmdServeDaemon(sub: string, args: string[]): Promise<number> {
887
935
  if (sub === "uninstall") {
888
936
  const proc = Bun.spawn([mgr.bin, "delete", DAEMON_NAME], {
889
937
  stdio: ["ignore", "inherit", "inherit"],
938
+ env: liveEnv(),
890
939
  });
891
940
  const code = (await proc.exited) ?? 1;
892
941
  if (mgr.id === "pm2" && code === 0) {
@@ -902,6 +951,7 @@ async function cmdServeDaemon(sub: string, args: string[]): Promise<number> {
902
951
  if (sub === "logs") {
903
952
  const proc = Bun.spawn([mgr.bin, "logs", DAEMON_NAME, ...args], {
904
953
  stdio: ["ignore", "inherit", "inherit"],
954
+ env: liveEnv(),
905
955
  });
906
956
  return (await proc.exited) ?? 1;
907
957
  }
@@ -1,8 +0,0 @@
1
- import "./ts-BdFKarex.js";
2
- import "./logger-CDIsZ-Pp.js";
3
- import "./versionChecker-DEJVuzWZ.js";
4
- import "./pidStore-BIvsBQ8X.js";
5
- import "./globalPidIndex-CoNr7tS8.js";
6
- import { t as SUPPORTED_CLIS } from "./SUPPORTED_CLIS-C0fh_eJs.js";
7
-
8
- export { SUPPORTED_CLIS };