@code-yeongyu/senpi 2026.8.31 → 2026.9.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 (93) hide show
  1. package/CHANGELOG.md +32 -0
  2. package/dist/core/extensions/builtin/compaction/context-pipeline.d.ts +6 -0
  3. package/dist/core/extensions/builtin/compaction/context-pipeline.d.ts.map +1 -1
  4. package/dist/core/extensions/builtin/compaction/context-pipeline.js +11 -0
  5. package/dist/core/extensions/builtin/compaction/context-pipeline.js.map +1 -1
  6. package/dist/core/extensions/builtin/compaction/index.js +4 -4
  7. package/dist/core/extensions/builtin/compaction/index.js.map +1 -1
  8. package/dist/core/extensions/builtin/prompt-preset/claude-fable-5-1.d.ts +3 -0
  9. package/dist/core/extensions/builtin/prompt-preset/claude-fable-5-1.d.ts.map +1 -0
  10. package/dist/core/extensions/builtin/prompt-preset/claude-fable-5-1.js +108 -0
  11. package/dist/core/extensions/builtin/prompt-preset/claude-fable-5-1.js.map +1 -0
  12. package/dist/core/extensions/builtin/prompt-preset/presets.d.ts.map +1 -1
  13. package/dist/core/extensions/builtin/prompt-preset/presets.js +11 -0
  14. package/dist/core/extensions/builtin/prompt-preset/presets.js.map +1 -1
  15. package/dist/core/extensions/builtin/prompt-preset/settings.d.ts +1 -1
  16. package/dist/core/extensions/builtin/prompt-preset/settings.d.ts.map +1 -1
  17. package/dist/core/extensions/builtin/prompt-preset/settings.js +1 -0
  18. package/dist/core/extensions/builtin/prompt-preset/settings.js.map +1 -1
  19. package/dist/core/extensions/builtin/recommended-models/index.d.ts +1 -1
  20. package/dist/core/extensions/builtin/recommended-models/index.d.ts.map +1 -1
  21. package/dist/core/extensions/builtin/recommended-models/index.js +1 -1
  22. package/dist/core/extensions/builtin/recommended-models/index.js.map +1 -1
  23. package/dist/core/retry-fallback/settings.d.ts.map +1 -1
  24. package/dist/core/retry-fallback/settings.js +1 -0
  25. package/dist/core/retry-fallback/settings.js.map +1 -1
  26. package/dist/main.d.ts +4 -4
  27. package/dist/main.d.ts.map +1 -1
  28. package/dist/main.js +10 -6
  29. package/dist/main.js.map +1 -1
  30. package/dist/modes/app-server/daemon/process.d.ts +13 -2
  31. package/dist/modes/app-server/daemon/process.d.ts.map +1 -1
  32. package/dist/modes/app-server/daemon/process.js +58 -12
  33. package/dist/modes/app-server/daemon/process.js.map +1 -1
  34. package/dist/modes/app-server/daemon.js +62 -4
  35. package/dist/modes/app-server/daemon.js.map +1 -1
  36. package/dist/modes/interactive/interactive-mode.d.ts +11 -1
  37. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  38. package/dist/modes/interactive/interactive-mode.js +35 -6
  39. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  40. package/dist/modes/interactive/tips/catalog/ethos-tips.js +1 -1
  41. package/dist/modes/interactive/tips/catalog/ethos-tips.js.map +1 -1
  42. package/dist/modes/rpc/connection-handler.d.ts.map +1 -1
  43. package/dist/modes/rpc/connection-handler.js +8 -3
  44. package/dist/modes/rpc/connection-handler.js.map +1 -1
  45. package/dist/modes/rpc/custom-capability.d.ts +1 -0
  46. package/dist/modes/rpc/custom-capability.d.ts.map +1 -1
  47. package/dist/modes/rpc/custom-capability.js +1 -0
  48. package/dist/modes/rpc/custom-capability.js.map +1 -1
  49. package/dist/modes/rpc/host-ensure.d.ts.map +1 -1
  50. package/dist/modes/rpc/host-ensure.js +93 -17
  51. package/dist/modes/rpc/host-ensure.js.map +1 -1
  52. package/dist/modes/rpc/host-lifecycle.d.ts +15 -0
  53. package/dist/modes/rpc/host-lifecycle.d.ts.map +1 -1
  54. package/dist/modes/rpc/host-lifecycle.js +180 -55
  55. package/dist/modes/rpc/host-lifecycle.js.map +1 -1
  56. package/dist/modes/rpc/host-watchdog.d.ts +2 -2
  57. package/dist/modes/rpc/host-watchdog.d.ts.map +1 -1
  58. package/dist/modes/rpc/host-watchdog.js +89 -21
  59. package/dist/modes/rpc/host-watchdog.js.map +1 -1
  60. package/dist/modes/rpc/multi-session-host.d.ts.map +1 -1
  61. package/dist/modes/rpc/multi-session-host.js +94 -56
  62. package/dist/modes/rpc/multi-session-host.js.map +1 -1
  63. package/dist/modes/rpc/rpc-client.d.ts.map +1 -1
  64. package/dist/modes/rpc/rpc-client.js +8 -1
  65. package/dist/modes/rpc/rpc-client.js.map +1 -1
  66. package/dist/modes/rpc/session-command-router.d.ts.map +1 -1
  67. package/dist/modes/rpc/session-command-router.js +7 -2
  68. package/dist/modes/rpc/session-command-router.js.map +1 -1
  69. package/dist/modes/rpc/socket-transport.d.ts +13 -0
  70. package/dist/modes/rpc/socket-transport.d.ts.map +1 -0
  71. package/dist/modes/rpc/socket-transport.js +92 -0
  72. package/dist/modes/rpc/socket-transport.js.map +1 -0
  73. package/docs/extensions.md +1 -1
  74. package/docs/rpc.md +5 -1
  75. package/docs/settings.md +4 -4
  76. package/node_modules/@code-yeongyu/senpi-codemode/CHANGELOG.md +12 -0
  77. package/node_modules/@code-yeongyu/senpi-codemode/package.json +4 -4
  78. package/node_modules/@earendil-works/pi-agent-core/package.json +3 -3
  79. package/node_modules/@earendil-works/pi-ai/dist/providers/data/.manifest.json +1 -1
  80. package/node_modules/@earendil-works/pi-ai/dist/providers/data/amazon-bedrock.json +1 -1
  81. package/node_modules/@earendil-works/pi-ai/dist/providers/data/anthropic.json +1 -1
  82. package/node_modules/@earendil-works/pi-ai/dist/providers/data/fireworks.json +1 -1
  83. package/node_modules/@earendil-works/pi-ai/dist/providers/data/google.json +1 -1
  84. package/node_modules/@earendil-works/pi-ai/dist/providers/data/groq.json +1 -1
  85. package/node_modules/@earendil-works/pi-ai/dist/providers/data/nvidia.json +1 -1
  86. package/node_modules/@earendil-works/pi-ai/dist/providers/data/opengateway.json +1 -1
  87. package/node_modules/@earendil-works/pi-ai/dist/providers/data/openrouter.json +1 -1
  88. package/node_modules/@earendil-works/pi-ai/dist/providers/data/vercel-ai-gateway.json +1 -1
  89. package/node_modules/@earendil-works/pi-ai/package.json +2 -2
  90. package/node_modules/@earendil-works/pi-pty/package.json +1 -1
  91. package/node_modules/@earendil-works/pi-telemetry/package.json +1 -1
  92. package/node_modules/@earendil-works/pi-tui/package.json +1 -1
  93. package/package.json +7 -7
@@ -40,15 +40,17 @@
40
40
  import { spawn } from "node:child_process";
41
41
  import { randomUUID } from "node:crypto";
42
42
  import { realpathSync, writeSync } from "node:fs";
43
- import { access, chmod, mkdir, readFile, rm, unlink } from "node:fs/promises";
43
+ import { access, chmod, mkdir, readFile, rm, unlink, writeFile } from "node:fs/promises";
44
44
  import { createConnection, createServer } from "node:net";
45
45
  import { tmpdir } from "node:os";
46
- import { dirname, join, resolve } from "node:path";
46
+ import { dirname, extname, join, resolve } from "node:path";
47
47
  import { fileURLToPath } from "node:url";
48
48
  import { getAgentDir, isBunBinary } from "../../config.js";
49
+ import { readProcessStartTime } from "../app-server/daemon/process.js";
49
50
  import { createHostDaemonPaths } from "./host-ensure.js";
50
51
  import { HOST_CLEANUP_PATHS_ENV, HOST_SCRATCH_DIR_ENV, HOST_WATCH_FD_ENV, HOST_WATCH_PPID_ENV, } from "./host-watchdog.js";
51
52
  import { attachJsonlLineReader, MAX_RPC_LINE_CHARACTERS } from "./jsonl.js";
53
+ import { authenticateSocket, createSocketSecret, readSocketSecret, resolveSocketTransportAddress, SOCKET_SECRET_FILE_ENV, sendSocketHandshake, socketSecretPath, } from "./socket-transport.js";
52
54
  /** Environment override for the cold-start policy: `transient` or `persistent`. */
53
55
  export const HOST_COLD_START_ENV = "SENPI_RPC_HOST_COLD_START";
54
56
  /** Environment override for the idle-exit window in milliseconds. */
@@ -56,6 +58,8 @@ export const HOST_IDLE_EXIT_MS_ENV = "SENPI_RPC_HOST_IDLE_EXIT_MS";
56
58
  /** Default idle-exit window: 15 minutes of continuous no-connection, no-turn idle. */
57
59
  export const DEFAULT_HOST_IDLE_EXIT_MS = 15 * 60_000;
58
60
  const CHILD_STOP_TIMEOUT_MS = 5_000;
61
+ /** Win32 named-pipe shutdown can leave supervisor handles live after close starts. */
62
+ const WINDOWS_SUPERVISOR_SHUTDOWN_HARD_EXIT_MS = 2_000;
59
63
  /**
60
64
  * Child stdio slot carrying the supervisor-lifetime pipe. The supervisor holds
61
65
  * the write end open and never writes; the kernel closes it when the supervisor
@@ -68,10 +72,24 @@ const CHILD_WATCH_FD = 3;
68
72
  * regardless of where the public socket lives, and private against other local
69
73
  * users, so it gets its own 0700 directory under the OS temp directory.
70
74
  */
71
- async function createInternalSocketPath() {
75
+ async function createInternalSocketPath(baseDir = tmpdir()) {
76
+ if (process.platform === "win32") {
77
+ const dir = join(baseDir, `internal-${randomUUID()}`);
78
+ await mkdir(dir, { recursive: false, mode: 0o700 });
79
+ return {
80
+ socket: `\\\\.\\pipe\\senpi-rpc-internal-${randomUUID()}`,
81
+ dir,
82
+ secretPath: join(dir, "secret"),
83
+ };
84
+ }
72
85
  const dir = join(tmpdir(), `senpi-rpc-host-internal-${randomUUID().slice(0, 8)}`);
73
86
  await mkdir(dir, { recursive: false, mode: 0o700 });
74
- return { socket: join(dir, "host.sock"), dir };
87
+ await writeFile(join(dir, ".owner"), JSON.stringify({
88
+ pid: process.pid,
89
+ processStartTime: await readProcessStartTime(process.pid),
90
+ createdAt: Date.now(),
91
+ }), { mode: 0o600 });
92
+ return { socket: join(dir, "host.sock"), dir, secretPath: join(dir, ".secret") };
75
93
  }
76
94
  export function parseColdStart(value) {
77
95
  return value === "transient" || value === "persistent" ? value : undefined;
@@ -236,31 +254,72 @@ export function resolveHostChildLaunch(launch, internalSocket, compiled = isBunB
236
254
  ],
237
255
  };
238
256
  }
257
+ /** Mirrors cross-spawn: survives cmd.exe parsing and `CommandLineToArgvW`. */
258
+ function quoteWindowsShellArg(value) {
259
+ const escaped = value
260
+ .replace(/(\\*)"/g, '$1$1\\"')
261
+ .replace(/(\\*)$/, "$1$1")
262
+ .replace(/([()%!^"<>&|;,])/g, "^$1");
263
+ return `"${escaped}"`;
264
+ }
265
+ /**
266
+ * Windows refuses to spawn a `.cmd`/`.bat` without a shell, and Node's
267
+ * `shell: true` concatenates argv without escaping it. Escape each original
268
+ * value before adding the surrounding quotes so `.cmd`/`.bat` launchers survive
269
+ * cmd.exe parsing without double-escaping.
270
+ * Exported for tests.
271
+ */
272
+ export function spawnableChildLaunch(launch, platform = process.platform) {
273
+ const extension = extname(launch.command).toLowerCase();
274
+ if (platform !== "win32" || (extension !== ".cmd" && extension !== ".bat")) {
275
+ return { ...launch, shell: false };
276
+ }
277
+ return {
278
+ command: quoteWindowsShellArg(launch.command),
279
+ args: launch.args.map(quoteWindowsShellArg),
280
+ shell: true,
281
+ };
282
+ }
239
283
  export async function runHostSupervisor(launch) {
240
284
  const paths = createHostDaemonPaths(launch.agentDir ?? getAgentDir());
241
285
  const policy = resolveHostPolicy(await readSettingsFile(paths.settingsFile), process.env);
242
286
  const publicSocket = launch.socket;
243
- const internal = await createInternalSocketPath();
287
+ const internal = await createInternalSocketPath(paths.dir);
244
288
  const internalSocket = internal.socket;
289
+ const internalSecretPath = internal.secretPath ?? socketSecretPath(internalSocket);
290
+ const internalSecret = process.platform === "win32" ? await createSocketSecret(internalSecretPath) : undefined;
291
+ const publicSecret = process.platform === "win32" ? await readSocketSecret(socketSecretPath(publicSocket)) : undefined;
245
292
  const clientSockets = new Set();
246
293
  const busySessions = new Map();
247
294
  let observerHealthy = false;
248
295
  let observerReconnectTimer;
296
+ let childExitWatchTimer;
249
297
  let shuttingDown = false;
250
298
  let shutdownPromise;
251
- const childLaunch = resolveHostChildLaunch(launch, internalSocket);
299
+ const childLaunch = spawnableChildLaunch(resolveHostChildLaunch(launch, internalSocket));
252
300
  const child = spawn(childLaunch.command, childLaunch.args, {
253
301
  env: {
254
302
  ...process.env,
255
303
  ...(launch.agentDir ? { SENPI_CODING_AGENT_DIR: launch.agentDir } : {}),
256
304
  [HOST_WATCH_FD_ENV]: String(CHILD_WATCH_FD),
257
305
  [HOST_WATCH_PPID_ENV]: String(process.pid),
258
- [HOST_SCRATCH_DIR_ENV]: internal.dir,
259
- [HOST_CLEANUP_PATHS_ENV]: [publicSocket, paths.pidFile, paths.settingsFile].join("\n"),
306
+ ...(internal.dir ? { [HOST_SCRATCH_DIR_ENV]: internal.dir } : {}),
307
+ ...(internalSecret ? { [SOCKET_SECRET_FILE_ENV]: internalSecretPath } : {}),
308
+ [HOST_CLEANUP_PATHS_ENV]: [
309
+ paths.pidFile,
310
+ paths.settingsFile,
311
+ ...(process.platform === "win32" ? [] : [publicSocket]),
312
+ ].join("\n"),
260
313
  },
261
314
  // Slot 3 is the lifetime pipe: "pipe" gives the child a read end it can
262
315
  // wait on and keeps the write end owned by this process alone.
316
+ shell: childLaunch.shell,
263
317
  stdio: ["ignore", "ignore", "inherit", "pipe"],
318
+ // The supervisor is spawned detached, so on win32 it owns no console. A
319
+ // console-subsystem child started from it would allocate a fresh one,
320
+ // which Windows Terminal renders as an empty window that takes focus.
321
+ // CREATE_NO_WINDOW gives the child a console with no window instead.
322
+ windowsHide: true,
264
323
  });
265
324
  // Nothing is ever written; the pipe exists purely so its EOF is a reliable
266
325
  // death notification. Errors on it must not crash the supervisor.
@@ -272,23 +331,31 @@ export async function runHostSupervisor(launch) {
272
331
  void shutdown(reason, exitCode);
273
332
  });
274
333
  const server = createServer((client) => {
275
- if (shuttingDown) {
276
- client.destroy();
277
- return;
278
- }
279
- const internal = createConnection(internalSocket);
280
- clientSockets.add(client);
281
- const detach = () => {
282
- clientSockets.delete(client);
283
- internal.destroy();
284
- client.destroy();
334
+ const accept = () => {
335
+ if (shuttingDown) {
336
+ client.destroy();
337
+ return;
338
+ }
339
+ const internal = createConnection(resolveSocketTransportAddress(internalSocket, process.platform, internalSecret));
340
+ if (internalSecret)
341
+ sendSocketHandshake(internal, internalSecret);
342
+ clientSockets.add(client);
343
+ const detach = () => {
344
+ clientSockets.delete(client);
345
+ internal.destroy();
346
+ client.destroy();
347
+ };
348
+ client.pipe(internal);
349
+ internal.pipe(client);
350
+ client.once("close", detach);
351
+ client.once("error", detach);
352
+ internal.once("close", detach);
353
+ internal.once("error", detach);
285
354
  };
286
- client.pipe(internal);
287
- internal.pipe(client);
288
- client.once("close", detach);
289
- client.once("error", detach);
290
- internal.once("close", detach);
291
- internal.once("error", detach);
355
+ if (publicSecret)
356
+ authenticateSocket(client, publicSecret, accept);
357
+ else
358
+ accept();
292
359
  });
293
360
  server.once("error", (cause) => {
294
361
  if (!shuttingDown)
@@ -343,25 +410,40 @@ export async function runHostSupervisor(launch) {
343
410
  process.exit(exitCode);
344
411
  shuttingDown = true;
345
412
  clearInterval(ticker);
346
- writeStderrLine(`senpi rpc host supervisor: ${reason} shutdown`);
347
- for (const client of clientSockets)
348
- client.destroy();
349
- await closeServer(server);
350
- // Unlink the private directory BEFORE the child stop, which can take seconds:
351
- // an external SIGKILL landing during that wait (ensureHost escalates while
352
- // replacing a host) would otherwise leave the directory behind. The child
353
- // keeps serving through its already-open socket fd until it exits, and its
354
- // own watchdog cleanup makes the removal idempotent.
355
- await rm(internal.dir, { recursive: true, force: true });
356
- await stopChild(child);
357
- observer?.destroy();
358
- if (publicSocketOwned)
359
- await rm(publicSocket, { force: true });
360
- // Mirror ensureHost's cleanupState: the pidfile and settings describe a
361
- // live host only; the stderr log stays for diagnostics.
362
- await rm(paths.pidFile, { force: true });
363
- await rm(paths.settingsFile, { force: true });
364
- process.exit(exitCode);
413
+ if (childExitWatchTimer)
414
+ clearInterval(childExitWatchTimer);
415
+ const hardExit = process.platform === "win32"
416
+ ? setTimeout(() => process.exit(exitCode), WINDOWS_SUPERVISOR_SHUTDOWN_HARD_EXIT_MS)
417
+ : undefined;
418
+ try {
419
+ writeStderrLine(`senpi rpc host supervisor: ${reason} shutdown`);
420
+ for (const client of clientSockets)
421
+ client.destroy();
422
+ await closeServer(server);
423
+ // Unlink the private directory BEFORE the child stop, which can take seconds:
424
+ // an external SIGKILL landing during that wait (ensureHost escalates while
425
+ // replacing a host) would otherwise leave the directory behind. The child
426
+ // keeps serving through its already-open socket fd until it exits, and its
427
+ // own watchdog cleanup makes the removal idempotent.
428
+ if (internal.dir)
429
+ await rm(internal.dir, { recursive: true, force: true });
430
+ await stopChild(child);
431
+ observer?.destroy();
432
+ if (publicSocketOwned && process.platform !== "win32")
433
+ await rm(publicSocket, { force: true });
434
+ // Mirror ensureHost's cleanupState: the pidfile and settings describe a
435
+ // live host only; the stderr log stays for diagnostics.
436
+ await rm(paths.pidFile, { force: true });
437
+ await rm(paths.settingsFile, { force: true });
438
+ }
439
+ finally {
440
+ if (hardExit)
441
+ clearTimeout(hardExit);
442
+ // Explicitly terminate after every supervisor shutdown trigger. Windows
443
+ // named-pipe handles can outlive their JavaScript wrappers, so cleanup
444
+ // failure must never leave the supervisor resident or the host orphaned.
445
+ process.exit(exitCode);
446
+ }
365
447
  }
366
448
  let observer;
367
449
  let publicSocketOwned = false;
@@ -371,17 +453,20 @@ export async function runHostSupervisor(launch) {
371
453
  // would leave that directory behind.
372
454
  registerSupervisorSignals(shutdown);
373
455
  try {
374
- await waitForListener(internalSocket, 30_000);
456
+ await waitForListener(internalSocket, 30_000, internalSecret);
375
457
  await connectObserver();
376
458
  await prepareSocketPath(publicSocket);
377
- await listen(server, publicSocket);
459
+ await listen(server, publicSocket, publicSecret);
378
460
  publicSocketOwned = true;
379
461
  }
380
462
  catch (cause) {
381
463
  await shutdown(`startup failed: ${errorMessage(cause)}`, 1);
382
464
  }
383
465
  async function connectObserver() {
384
- const next = createConnection(internalSocket);
466
+ const secret = internalSecret;
467
+ const next = createConnection(resolveSocketTransportAddress(internalSocket, process.platform, secret));
468
+ if (secret)
469
+ sendSocketHandshake(next, secret);
385
470
  await waitForConnect(next, 5_000);
386
471
  observer = next;
387
472
  observerHealthy = true;
@@ -402,6 +487,33 @@ export async function runHostSupervisor(launch) {
402
487
  next.once("close", lost);
403
488
  next.once("error", lost);
404
489
  }
490
+ if (process.platform === "win32" && child.pid !== undefined) {
491
+ const childStartTime = await readProcessStartTime(child.pid, process.platform, 1_000);
492
+ let missingIdentityChecks = 0;
493
+ let checkingChildIdentity = false;
494
+ const checkChildIdentity = () => {
495
+ if (shuttingDown || checkingChildIdentity || child.exitCode !== null || child.signalCode !== null)
496
+ return;
497
+ checkingChildIdentity = true;
498
+ void readProcessStartTime(child.pid, process.platform, 1_000)
499
+ .then((currentStartTime) => {
500
+ if (currentStartTime === undefined)
501
+ missingIdentityChecks++;
502
+ else
503
+ missingIdentityChecks = 0;
504
+ const identityChanged = childStartTime !== undefined && currentStartTime !== undefined && currentStartTime !== childStartTime;
505
+ if (identityChanged || missingIdentityChecks >= 2) {
506
+ void shutdown("rpc host child exit observed by identity watchdog", 0);
507
+ }
508
+ })
509
+ .catch(() => { })
510
+ .finally(() => {
511
+ checkingChildIdentity = false;
512
+ });
513
+ };
514
+ childExitWatchTimer = setInterval(checkChildIdentity, 500);
515
+ childExitWatchTimer.unref?.();
516
+ }
405
517
  writeStderrLine(`senpi rpc host ready on unix://${publicSocket} (coldStart=${policy.coldStart}, idleExitMs=${policy.coldStart === "persistent" ? "never" : String(policy.idleExitMs)})`);
406
518
  await new Promise(() => { });
407
519
  }
@@ -455,18 +567,20 @@ function waitForChildExit(child, timeoutMs) {
455
567
  child.once("exit", onExit);
456
568
  });
457
569
  }
458
- async function waitForListener(socketPath, timeoutMs) {
570
+ async function waitForListener(socketPath, timeoutMs, secret) {
459
571
  const deadline = Date.now() + timeoutMs;
460
572
  while (Date.now() <= deadline) {
461
- if (await canConnect(socketPath))
573
+ if (await canConnect(socketPath, secret))
462
574
  return;
463
575
  await delay(50);
464
576
  }
465
577
  throw new Error(`${socketPath}: host did not start listening within ${timeoutMs}ms`);
466
578
  }
467
- function canConnect(socketPath) {
579
+ function canConnect(socketPath, secret) {
468
580
  return new Promise((resolve) => {
469
- const socket = createConnection(socketPath);
581
+ const socket = createConnection(resolveSocketTransportAddress(socketPath, process.platform, secret));
582
+ if (secret)
583
+ sendSocketHandshake(socket, secret);
470
584
  const settle = (value) => {
471
585
  socket.destroy();
472
586
  resolve(value);
@@ -499,6 +613,8 @@ function waitForConnect(socket, timeoutMs) {
499
613
  });
500
614
  }
501
615
  async function prepareSocketPath(socketPath) {
616
+ if (process.platform === "win32")
617
+ return;
502
618
  await mkdir(dirname(socketPath), { recursive: true, mode: 0o700 });
503
619
  try {
504
620
  await access(socketPath);
@@ -512,14 +628,23 @@ async function prepareSocketPath(socketPath) {
512
628
  throw new Error(`${socketPath}: address already in use by a live server.`);
513
629
  await unlink(socketPath);
514
630
  }
515
- function listen(server, socketPath) {
631
+ function listen(server, socketPath, secret) {
516
632
  return new Promise((resolve, reject) => {
517
633
  server.once("error", reject);
518
- server.listen(socketPath, async () => {
634
+ server.listen({
635
+ path: resolveSocketTransportAddress(socketPath, process.platform, secret),
636
+ readableAll: false,
637
+ writableAll: false,
638
+ }, async () => {
519
639
  server.off("error", reject);
520
- if (!socketPath.startsWith("\0"))
521
- await chmod(socketPath, 0o600);
522
- resolve();
640
+ try {
641
+ if (process.platform !== "win32" && !socketPath.startsWith("\0"))
642
+ await chmod(socketPath, 0o600);
643
+ resolve();
644
+ }
645
+ catch (cause) {
646
+ reject(cause);
647
+ }
523
648
  });
524
649
  });
525
650
  }
@@ -1 +1 @@
1
- {"version":3,"file":"host-lifecycle.js","sourceRoot":"","sources":["../../../src/modes/rpc/host-lifecycle.ts"],"names":[],"mappings":"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","sourcesContent":["#!/usr/bin/env node\n/**\n * Lifecycle supervisor for the shared RPC socket host started by ensureHost().\n *\n * Process tree:\n *\n * ensureHost() ──detached──▶ host-lifecycle.ts (this supervisor, owns the pidfile)\n * │ byte-proxies the public socket\n * ▼\n * cli-main --mode rpc --listen unix://<public>.internal\n *\n * The supervisor exists to enforce the host lifecycle policy without touching the\n * RPC host itself:\n *\n * - cold start: `transient` (default) means the host lives for the current login\n * session and idle-exits; `persistent` never idle-exits.\n * - idle exit: after a continuous window with zero attached client connections\n * and zero active agent turns, the supervisor tears the host down cleanly\n * (child SIGTERM first so the host flushes pending output and removes its own\n * socket, then pidfile/settings removal mirroring ensureHost's cleanupState).\n *\n * Observability without host changes: proxying the public socket yields the\n * exact connection count, and the supervisor keeps one always-on observer\n * connection to the internal socket. The multi-session host broadcasts every\n * session lifecycle/agent event to every connection, so the observer sees\n * `agent_start`/`agent_settled` for all sessions even when no client is\n * attached. If the observer connection is ever unhealthy, activity is reported\n * as unknown (non-idle), so a broken observer can only keep the host alive,\n * never kill it mid-turn.\n *\n * Lifetime binding: the host is spawned with an extra inherited pipe on fd 3\n * whose write end this supervisor holds and never writes to. The kernel closes\n * that end whenever the supervisor dies - including SIGKILL, an OOM kill, or a\n * crash, where no JS handler runs at all - so the host reads EOF and shuts down\n * cleanly, removing the private internal directory. `stopChild()` remains the\n * fast path for orderly shutdowns; the pipe is what makes an orphaned host\n * impossible. `SENPI_RPC_HOST_WATCH_PPID` is passed alongside as a belt-and-\n * braces fallback for platforms where the extra fd is not inherited.\n */\nimport { type ChildProcess, spawn } from \"node:child_process\";\nimport { randomUUID } from \"node:crypto\";\nimport { realpathSync, writeSync } from \"node:fs\";\nimport { access, chmod, mkdir, readFile, rm, unlink } from \"node:fs/promises\";\nimport { createConnection, createServer, type Server, type Socket } from \"node:net\";\nimport { tmpdir } from \"node:os\";\nimport { dirname, join, resolve } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport { getAgentDir, isBunBinary } from \"../../config.ts\";\nimport { createHostDaemonPaths } from \"./host-ensure.ts\";\nimport {\n\tHOST_CLEANUP_PATHS_ENV,\n\tHOST_SCRATCH_DIR_ENV,\n\tHOST_WATCH_FD_ENV,\n\tHOST_WATCH_PPID_ENV,\n} from \"./host-watchdog.ts\";\nimport { attachJsonlLineReader, MAX_RPC_LINE_CHARACTERS } from \"./jsonl.ts\";\n\nexport type HostColdStart = \"transient\" | \"persistent\";\n\n/** Environment override for the cold-start policy: `transient` or `persistent`. */\nexport const HOST_COLD_START_ENV = \"SENPI_RPC_HOST_COLD_START\";\n/** Environment override for the idle-exit window in milliseconds. */\nexport const HOST_IDLE_EXIT_MS_ENV = \"SENPI_RPC_HOST_IDLE_EXIT_MS\";\n/** Default idle-exit window: 15 minutes of continuous no-connection, no-turn idle. */\nexport const DEFAULT_HOST_IDLE_EXIT_MS = 15 * 60_000;\n\n/** The policy fields ensureHost() records in rpc-host-daemon/settings.json. */\nexport interface HostLifecyclePolicyInput {\n\treadonly coldStart?: HostColdStart;\n\treadonly idleExitMs?: number;\n}\n\nexport interface HostLifecyclePolicy {\n\treadonly coldStart: HostColdStart;\n\treadonly idleExitMs: number;\n}\n\nconst CHILD_STOP_TIMEOUT_MS = 5_000;\n\n/**\n * Child stdio slot carrying the supervisor-lifetime pipe. The supervisor holds\n * the write end open and never writes; the kernel closes it when the supervisor\n * dies for ANY reason (SIGKILL, OOM kill, crash), so the host sees EOF on this\n * fd and shuts itself down. Catchable-signal cleanup alone cannot do this.\n */\nconst CHILD_WATCH_FD = 3;\n\n/**\n * The internal hop must stay short enough for sun_path (104 bytes on macOS)\n * regardless of where the public socket lives, and private against other local\n * users, so it gets its own 0700 directory under the OS temp directory.\n */\nasync function createInternalSocketPath(): Promise<{ socket: string; dir: string }> {\n\tconst dir = join(tmpdir(), `senpi-rpc-host-internal-${randomUUID().slice(0, 8)}`);\n\tawait mkdir(dir, { recursive: false, mode: 0o700 });\n\treturn { socket: join(dir, \"host.sock\"), dir };\n}\n\nexport function parseColdStart(value: string | undefined): HostColdStart | undefined {\n\treturn value === \"transient\" || value === \"persistent\" ? value : undefined;\n}\n\nexport function parseIdleExitMs(value: string | undefined): number | undefined {\n\tif (value === undefined || !/^\\d+$/.test(value.trim())) return undefined;\n\tconst parsed = Number(value.trim());\n\treturn Number.isFinite(parsed) && parsed > 0 ? parsed : undefined;\n}\n\n/**\n * Resolves the effective host policy. Precedence: environment overrides beat\n * settings.json, which beats the documented defaults (transient, 15 minutes).\n * Invalid values at either source fall through to the next source.\n */\nexport function resolveHostPolicy(\n\tsettings: unknown,\n\tenv: Readonly<Record<string, string | undefined>>,\n): HostLifecyclePolicy {\n\tconst record = isRecord(settings) ? settings : {};\n\tconst coldStart =\n\t\tparseColdStart(env[HOST_COLD_START_ENV]) ?? parseColdStart(asOptionalString(record.coldStart)) ?? \"transient\";\n\tconst idleExitMs =\n\t\tparseIdleExitMs(env[HOST_IDLE_EXIT_MS_ENV]) ??\n\t\tparseIdleExitMs(asOptionalString(record.idleExitMs)) ??\n\t\tDEFAULT_HOST_IDLE_EXIT_MS;\n\treturn { coldStart, idleExitMs };\n}\n\nexport interface HostActivity {\n\treadonly connections: number;\n\treadonly activeTurns: number;\n}\n\n/**\n * How the supervisor reads its child's exit. The RPC host exits 0 only through\n * its own clean shutdown path - including its idle/empty-host policy - so that\n * is an intentional stop, not a crash: the supervisor mirrors its own idle exit\n * instead of reporting failure. Any non-zero code or signal stays a crash.\n */\nexport function classifyChildExit(\n\tcode: number | null,\n\tsignal: NodeJS.Signals | null,\n): { reason: string; exitCode: number } {\n\tif (code === 0 && signal === null) return { reason: \"rpc host exited on its own idle policy\", exitCode: 0 };\n\treturn { reason: `rpc host process exited unexpectedly (${code ?? signal})`, exitCode: 1 };\n}\n\nexport type IdleExitDecision = \"active\" | \"idle\" | \"exit\";\n\n/**\n * Pure idle-window decision core. `update()` must be called with the CURRENT\n * activity state; the window only counts continuously idle time and any\n * activity resets it, so a busy host can never cross the threshold.\n */\nexport class IdleExitDecider {\n\tprivate idleSince: number | undefined;\n\tprivate readonly now: () => number;\n\treadonly idleExitMs: number;\n\n\tconstructor(idleExitMs: number, now: () => number = Date.now) {\n\t\tthis.idleExitMs = idleExitMs;\n\t\tthis.now = now;\n\t}\n\n\tupdate(activity: HostActivity): IdleExitDecision {\n\t\t// Any attachment or active turn both holds the host open and resets the\n\t\t// window, so only CONTINUOUS idle can ever cross the threshold.\n\t\tif (activity.connections > 0 || activity.activeTurns > 0) {\n\t\t\tthis.idleSince = undefined;\n\t\t\treturn \"active\";\n\t\t}\n\t\tif (this.idleExitMs === Number.POSITIVE_INFINITY) return \"idle\";\n\t\tif (this.idleSince === undefined) {\n\t\t\tthis.idleSince = this.now();\n\t\t\treturn \"idle\";\n\t\t}\n\t\treturn this.now() - this.idleSince >= this.idleExitMs ? \"exit\" : \"idle\";\n\t}\n}\n\nexport interface SupervisorLaunch {\n\treadonly socket: string;\n\treadonly hostArgs: readonly string[];\n\t/** Optional runtime command used by rebranded/bundled callers. */\n\treadonly childCommand?: string;\n\treadonly childArgs?: readonly string[];\n\t/** Explicit ownership directory for callers whose environment is not yet branded. */\n\treadonly agentDir?: string;\n}\n\n/** Hidden internal launch route: wire-invisible, never advertised by the public CLI surface. */\nexport const INTERNAL_SUPERVISOR_FLAG = \"--internal-rpc-host-supervisor\";\n\n/**\n * Engine-global flags a rebranded wrapper may legitimately prepend when it\n * re-dispatches this binary. `packages/omo-native` injects `--extension <dir>`\n * for every non-early command, which pushed the sentinel off argv[0].\n */\nconst INJECTABLE_PREFIX_FLAGS = new Set([\"--extension\"]);\n\n/**\n * Returns the internal supervisor payload when argv selects that route.\n *\n * The route dispatches when the sentinel is argv[0] OR is preceded only by\n * known injectable prefix flags and their values - the one perturbation\n * wrappers legitimately perform. Everything else disqualifies it: a positional\n * operand, `--`, or an unknown flag before the sentinel all return undefined,\n * so a user-supplied value that happens to equal the sentinel can never reach\n * the supervisor.\n *\n * The skipped prefix is deliberately NOT forwarded to the host: a wrapper\n * re-injects its own prefix on every re-entry, so the host child receives it\n * from the wrapper rather than twice from here.\n */\nexport function findInternalSupervisorArgs(argv: readonly string[]): readonly string[] | undefined {\n\tfor (let index = 0; index < argv.length; index++) {\n\t\tconst arg = argv[index];\n\t\tif (arg === INTERNAL_SUPERVISOR_FLAG) return argv.slice(index + 1);\n\t\t// A prefix flag only counts when its value is actually present.\n\t\tif (!INJECTABLE_PREFIX_FLAGS.has(arg) || index + 1 >= argv.length) return undefined;\n\t\tindex++;\n\t}\n\treturn undefined;\n}\n\n/** `--socket <path>` selects the public socket; every other argument is forwarded to the host CLI. */\nexport function parseSupervisorArgs(argv: readonly string[]): SupervisorLaunch | undefined {\n\tconst hostArgs: string[] = [];\n\tlet socket: string | undefined;\n\tlet childCommand: string | undefined;\n\tlet childArgs: readonly string[] | undefined;\n\tlet agentDir: string | undefined;\n\tfor (let index = 0; index < argv.length; index++) {\n\t\tconst arg = argv[index];\n\t\tif (arg === \"--socket\" && index + 1 < argv.length) {\n\t\t\tsocket = argv[++index];\n\t\t\tcontinue;\n\t\t}\n\t\tif (arg === \"--child-command\" && index + 1 < argv.length) {\n\t\t\tchildCommand = argv[++index];\n\t\t\tcontinue;\n\t\t}\n\t\tif (arg === \"--child-args\" && index + 1 < argv.length) {\n\t\t\ttry {\n\t\t\t\tconst parsed: unknown = JSON.parse(argv[++index]);\n\t\t\t\tif (Array.isArray(parsed) && parsed.every((value) => typeof value === \"string\")) childArgs = parsed;\n\t\t\t} catch {\n\t\t\t\treturn undefined;\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\t\tif (arg === \"--agent-dir\" && index + 1 < argv.length) {\n\t\t\tagentDir = argv[++index];\n\t\t\tcontinue;\n\t\t}\n\t\thostArgs.push(arg);\n\t}\n\treturn socket === undefined ? undefined : { socket, hostArgs, childCommand, childArgs, agentDir };\n}\n\n/** Resolves the committed CLI entry this supervisor wraps (source tree or built dist). */\nexport function resolveCliMainPath(): string {\n\tconst modulePath = fileURLToPath(import.meta.url);\n\tconst extension = modulePath.endsWith(\".ts\") ? \".ts\" : \".js\";\n\treturn resolve(dirname(modulePath), \"..\", \"..\", `cli-main${extension}`);\n}\n\n/**\n * Resolves the host child spawn. Explicit child commands (desktop launchers)\n * are forwarded untouched. The default re-enters the committed CLI entry\n * through the runtime, except in compiled standalone binaries, which always\n * boot their embedded entrypoint and would parse a script path as CLI\n * arguments - there the executable itself is the CLI, so the mode flags are\n * passed directly. Exported for tests.\n */\nexport function resolveHostChildLaunch(\n\tlaunch: SupervisorLaunch,\n\tinternalSocket: string,\n\tcompiled: boolean = isBunBinary,\n): { command: string; args: string[] } {\n\tif (launch.childCommand) {\n\t\treturn {\n\t\t\tcommand: launch.childCommand,\n\t\t\targs: [...(launch.childArgs ?? []), \"--listen\", `unix://${internalSocket}`],\n\t\t};\n\t}\n\treturn {\n\t\tcommand: process.execPath,\n\t\targs: [\n\t\t\t...(compiled ? [] : [...process.execArgv, resolveCliMainPath()]),\n\t\t\t\"--mode\",\n\t\t\t\"rpc\",\n\t\t\t\"--multi-session\",\n\t\t\t\"--listen\",\n\t\t\t`unix://${internalSocket}`,\n\t\t\t...launch.hostArgs,\n\t\t],\n\t};\n}\n\nexport async function runHostSupervisor(launch: SupervisorLaunch): Promise<void> {\n\tconst paths = createHostDaemonPaths(launch.agentDir ?? getAgentDir());\n\tconst policy = resolveHostPolicy(await readSettingsFile(paths.settingsFile), process.env);\n\tconst publicSocket = launch.socket;\n\tconst internal = await createInternalSocketPath();\n\tconst internalSocket = internal.socket;\n\tconst clientSockets = new Set<Socket>();\n\tconst busySessions = new Map<string, number>();\n\tlet observerHealthy = false;\n\tlet observerReconnectTimer: ReturnType<typeof setTimeout> | undefined;\n\tlet shuttingDown = false;\n\tlet shutdownPromise: Promise<never> | undefined;\n\n\tconst childLaunch = resolveHostChildLaunch(launch, internalSocket);\n\tconst child = spawn(childLaunch.command, childLaunch.args, {\n\t\tenv: {\n\t\t\t...process.env,\n\t\t\t...(launch.agentDir ? { SENPI_CODING_AGENT_DIR: launch.agentDir } : {}),\n\t\t\t[HOST_WATCH_FD_ENV]: String(CHILD_WATCH_FD),\n\t\t\t[HOST_WATCH_PPID_ENV]: String(process.pid),\n\t\t\t[HOST_SCRATCH_DIR_ENV]: internal.dir,\n\t\t\t[HOST_CLEANUP_PATHS_ENV]: [publicSocket, paths.pidFile, paths.settingsFile].join(\"\\n\"),\n\t\t},\n\t\t// Slot 3 is the lifetime pipe: \"pipe\" gives the child a read end it can\n\t\t// wait on and keeps the write end owned by this process alone.\n\t\tstdio: [\"ignore\", \"ignore\", \"inherit\", \"pipe\"],\n\t});\n\t// Nothing is ever written; the pipe exists purely so its EOF is a reliable\n\t// death notification. Errors on it must not crash the supervisor.\n\tchild.stdio[CHILD_WATCH_FD]?.on(\"error\", () => {});\n\tchild.once(\"exit\", (code, signal) => {\n\t\tif (shuttingDown) return;\n\t\tconst { reason, exitCode } = classifyChildExit(code, signal);\n\t\tvoid shutdown(reason, exitCode);\n\t});\n\n\tconst server = createServer((client) => {\n\t\tif (shuttingDown) {\n\t\t\tclient.destroy();\n\t\t\treturn;\n\t\t}\n\t\tconst internal = createConnection(internalSocket);\n\t\tclientSockets.add(client);\n\t\tconst detach = (): void => {\n\t\t\tclientSockets.delete(client);\n\t\t\tinternal.destroy();\n\t\t\tclient.destroy();\n\t\t};\n\t\tclient.pipe(internal);\n\t\tinternal.pipe(client);\n\t\tclient.once(\"close\", detach);\n\t\tclient.once(\"error\", detach);\n\t\tinternal.once(\"close\", detach);\n\t\tinternal.once(\"error\", detach);\n\t});\n\tserver.once(\"error\", (cause) => {\n\t\tif (!shuttingDown) void shutdown(`public socket listener failed: ${errorMessage(cause)}`, 1);\n\t});\n\n\tconst decider = new IdleExitDecider(\n\t\tpolicy.coldStart === \"persistent\" ? Number.POSITIVE_INFINITY : policy.idleExitMs,\n\t);\n\tconst tickIntervalMs = Math.max(20, Math.min(1_000, policy.idleExitMs / 4));\n\tconst ticker = setInterval(() => {\n\t\tif (decider.update(currentActivity()) === \"exit\") void shutdown(\"idle\", 0);\n\t}, tickIntervalMs);\n\n\tfunction currentActivity(): HostActivity {\n\t\treturn {\n\t\t\tconnections: clientSockets.size,\n\t\t\tactiveTurns: observerHealthy ? countBusySessions() : 1,\n\t\t};\n\t}\n\n\tfunction countBusySessions(): number {\n\t\tlet busy = 0;\n\t\tfor (const count of busySessions.values()) if (count > 0) busy++;\n\t\treturn busy;\n\t}\n\n\tfunction observeHostEvent(line: string): void {\n\t\tlet event: unknown;\n\t\ttry {\n\t\t\tevent = JSON.parse(line);\n\t\t} catch {\n\t\t\treturn;\n\t\t}\n\t\tif (typeof event !== \"object\" || event === null) return;\n\t\tconst { type, sessionId } = event as { type?: unknown; sessionId?: unknown };\n\t\tif (typeof sessionId !== \"string\") return;\n\t\tif (type === \"agent_start\") busySessions.set(sessionId, (busySessions.get(sessionId) ?? 0) + 1);\n\t\telse if (type === \"agent_settled\")\n\t\t\tbusySessions.set(sessionId, Math.max(0, (busySessions.get(sessionId) ?? 1) - 1));\n\t}\n\n\tasync function shutdown(reason: string, exitCode: number): Promise<never> {\n\t\t// Single-flight: concurrent triggers (listener error, child exit, signals)\n\t\t// must not process.exit mid-cleanup. Late callers park on this promise while\n\t\t// the first shutdown finishes tearing down and exits.\n\t\tshutdownPromise ??= performShutdown(reason, exitCode);\n\t\treturn shutdownPromise;\n\t}\n\n\tasync function performShutdown(reason: string, exitCode: number): Promise<never> {\n\t\tif (shuttingDown) process.exit(exitCode);\n\t\tshuttingDown = true;\n\t\tclearInterval(ticker);\n\t\twriteStderrLine(`senpi rpc host supervisor: ${reason} shutdown`);\n\t\tfor (const client of clientSockets) client.destroy();\n\t\tawait closeServer(server);\n\t\t// Unlink the private directory BEFORE the child stop, which can take seconds:\n\t\t// an external SIGKILL landing during that wait (ensureHost escalates while\n\t\t// replacing a host) would otherwise leave the directory behind. The child\n\t\t// keeps serving through its already-open socket fd until it exits, and its\n\t\t// own watchdog cleanup makes the removal idempotent.\n\t\tawait rm(internal.dir, { recursive: true, force: true });\n\t\tawait stopChild(child);\n\t\tobserver?.destroy();\n\t\tif (publicSocketOwned) await rm(publicSocket, { force: true });\n\t\t// Mirror ensureHost's cleanupState: the pidfile and settings describe a\n\t\t// live host only; the stderr log stays for diagnostics.\n\t\tawait rm(paths.pidFile, { force: true });\n\t\tawait rm(paths.settingsFile, { force: true });\n\t\tprocess.exit(exitCode);\n\t}\n\n\tlet observer: Socket | undefined;\n\tlet publicSocketOwned = false;\n\t// Registered before the startup handshake, not after it: the private internal\n\t// directory already exists at this point, so a SIGTERM arriving during host\n\t// startup must run the same cleanup instead of Node's default kill, which\n\t// would leave that directory behind.\n\tregisterSupervisorSignals(shutdown);\n\ttry {\n\t\tawait waitForListener(internalSocket, 30_000);\n\t\tawait connectObserver();\n\t\tawait prepareSocketPath(publicSocket);\n\t\tawait listen(server, publicSocket);\n\t\tpublicSocketOwned = true;\n\t} catch (cause) {\n\t\tawait shutdown(`startup failed: ${errorMessage(cause)}`, 1);\n\t}\n\tasync function connectObserver(): Promise<void> {\n\t\tconst next = createConnection(internalSocket);\n\t\tawait waitForConnect(next, 5_000);\n\t\tobserver = next;\n\t\tobserverHealthy = true;\n\t\tattachJsonlLineReader(next, observeHostEvent, { maxLineLength: MAX_RPC_LINE_CHARACTERS });\n\t\tconst lost = (): void => {\n\t\t\tif (observer !== next || shuttingDown) return;\n\t\t\tobserverHealthy = false;\n\t\t\tobserver = undefined;\n\t\t\tif (observerReconnectTimer === undefined) {\n\t\t\t\tobserverReconnectTimer = setTimeout(() => {\n\t\t\t\t\tobserverReconnectTimer = undefined;\n\t\t\t\t\tvoid connectObserver().catch(() => lost());\n\t\t\t\t}, 250);\n\t\t\t\tobserverReconnectTimer.unref?.();\n\t\t\t}\n\t\t};\n\t\tnext.once(\"close\", lost);\n\t\tnext.once(\"error\", lost);\n\t}\n\n\twriteStderrLine(\n\t\t`senpi rpc host ready on unix://${publicSocket} (coldStart=${policy.coldStart}, idleExitMs=${\n\t\t\tpolicy.coldStart === \"persistent\" ? \"never\" : String(policy.idleExitMs)\n\t\t})`,\n\t);\n\tawait new Promise<never>(() => {});\n}\n\n/** External stop (ensureHost replacement, tests, QA) must clean up like idle exit. */\nfunction registerSupervisorSignals(shutdown: (reason: string, exitCode: number) => Promise<never>): void {\n\tfor (const signal of process.platform === \"win32\" ? ([\"SIGTERM\"] as const) : ([\"SIGTERM\", \"SIGHUP\"] as const)) {\n\t\tprocess.on(signal, () => {\n\t\t\tvoid shutdown(`signal:${signal}`, signal === \"SIGHUP\" ? 129 : 143);\n\t\t});\n\t}\n}\n\nasync function readSettingsFile(settingsFile: string): Promise<unknown> {\n\ttry {\n\t\treturn JSON.parse(await readFile(settingsFile, \"utf8\"));\n\t} catch {\n\t\treturn undefined;\n\t}\n}\n\nasync function stopChild(child: ChildProcess): Promise<void> {\n\tif (child.exitCode !== null || child.signalCode !== null) return;\n\ttry {\n\t\tchild.kill(\"SIGTERM\");\n\t} catch {\n\t\treturn;\n\t}\n\tif (await waitForChildExit(child, CHILD_STOP_TIMEOUT_MS)) return;\n\ttry {\n\t\tchild.kill(\"SIGKILL\");\n\t} catch {\n\t\treturn;\n\t}\n\tawait waitForChildExit(child, 2_000);\n}\n\nfunction waitForChildExit(child: ChildProcess, timeoutMs: number): Promise<boolean> {\n\tif (child.exitCode !== null || child.signalCode !== null) return Promise.resolve(true);\n\treturn new Promise((resolve) => {\n\t\tconst timer = setTimeout(() => {\n\t\t\tchild.off(\"exit\", onExit);\n\t\t\tresolve(false);\n\t\t}, timeoutMs);\n\t\tconst onExit = (): void => {\n\t\t\tclearTimeout(timer);\n\t\t\tresolve(true);\n\t\t};\n\t\tchild.once(\"exit\", onExit);\n\t});\n}\n\nasync function waitForListener(socketPath: string, timeoutMs: number): Promise<void> {\n\tconst deadline = Date.now() + timeoutMs;\n\twhile (Date.now() <= deadline) {\n\t\tif (await canConnect(socketPath)) return;\n\t\tawait delay(50);\n\t}\n\tthrow new Error(`${socketPath}: host did not start listening within ${timeoutMs}ms`);\n}\n\nfunction canConnect(socketPath: string): Promise<boolean> {\n\treturn new Promise((resolve) => {\n\t\tconst socket = createConnection(socketPath);\n\t\tconst settle = (value: boolean): void => {\n\t\t\tsocket.destroy();\n\t\t\tresolve(value);\n\t\t};\n\t\tsocket.once(\"connect\", () => settle(true));\n\t\tsocket.once(\"error\", () => settle(false));\n\t});\n}\n\nfunction waitForConnect(socket: Socket, timeoutMs: number): Promise<void> {\n\treturn new Promise((resolve, reject) => {\n\t\tconst timer = setTimeout(() => {\n\t\t\tcleanup();\n\t\t\treject(new Error(`observer connection to internal host timed out after ${timeoutMs}ms`));\n\t\t}, timeoutMs);\n\t\tconst onConnect = (): void => {\n\t\t\tcleanup();\n\t\t\tresolve();\n\t\t};\n\t\tconst onError = (cause: Error): void => {\n\t\t\tcleanup();\n\t\t\treject(cause);\n\t\t};\n\t\tconst cleanup = (): void => {\n\t\t\tclearTimeout(timer);\n\t\t\tsocket.off(\"connect\", onConnect);\n\t\t\tsocket.off(\"error\", onError);\n\t\t};\n\t\tsocket.once(\"connect\", onConnect);\n\t\tsocket.once(\"error\", onError);\n\t});\n}\n\nasync function prepareSocketPath(socketPath: string): Promise<void> {\n\tawait mkdir(dirname(socketPath), { recursive: true, mode: 0o700 });\n\ttry {\n\t\tawait access(socketPath);\n\t} catch (cause) {\n\t\tif (isNodeErrorCode(cause, \"ENOENT\")) return;\n\t\tthrow cause;\n\t}\n\tif (await canConnect(socketPath)) throw new Error(`${socketPath}: address already in use by a live server.`);\n\tawait unlink(socketPath);\n}\n\nfunction listen(server: Server, socketPath: string): Promise<void> {\n\treturn new Promise((resolve, reject) => {\n\t\tserver.once(\"error\", reject);\n\t\tserver.listen(socketPath, async () => {\n\t\t\tserver.off(\"error\", reject);\n\t\t\tif (!socketPath.startsWith(\"\\0\")) await chmod(socketPath, 0o600);\n\t\t\tresolve();\n\t\t});\n\t});\n}\n\nfunction closeServer(server: Server): Promise<void> {\n\treturn new Promise((resolve) => {\n\t\tserver.close(() => resolve());\n\t});\n}\n\nfunction writeStderrLine(text: string): void {\n\t// A detached daemon exiting right after an async stderr.write to a file can\n\t// lose the output entirely; write synchronously so diagnostics always land.\n\ttry {\n\t\twriteSync(2, `${text}\\n`);\n\t} catch {\n\t\t/* fd 2 unavailable: nothing more we can do. */\n\t}\n}\n\nfunction delay(ms: number): Promise<void> {\n\treturn new Promise((resolveDelay) => setTimeout(resolveDelay, ms));\n}\n\nfunction errorMessage(cause: unknown): string {\n\treturn cause instanceof Error ? cause.message : String(cause);\n}\n\nfunction isNodeErrorCode(cause: unknown, code: string): boolean {\n\treturn cause instanceof Error && \"code\" in cause && cause.code === code;\n}\n\nfunction isRecord(value: unknown): value is Readonly<Record<string, unknown>> {\n\treturn typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction asOptionalString(value: unknown): string | undefined {\n\treturn typeof value === \"string\" ? value : typeof value === \"number\" ? String(value) : undefined;\n}\n\nfunction isEntryScript(): boolean {\n\tconst entry = process.argv[1];\n\tif (!entry) return false;\n\ttry {\n\t\treturn fileURLToPath(import.meta.url) === realpathSync(entry);\n\t} catch {\n\t\treturn false;\n\t}\n}\n\nif (isEntryScript()) {\n\tconst launch = parseSupervisorArgs(process.argv.slice(2));\n\tif (!launch) {\n\t\twriteStderrLine(\"usage: host-lifecycle.ts --socket <path> [host cli args...]\");\n\t\tprocess.exit(2);\n\t}\n\tvoid runHostSupervisor(launch);\n}\n"]}
1
+ {"version":3,"file":"host-lifecycle.js","sourceRoot":"","sources":["../../../src/modes/rpc/host-lifecycle.ts"],"names":[],"mappings":"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","sourcesContent":["#!/usr/bin/env node\n/**\n * Lifecycle supervisor for the shared RPC socket host started by ensureHost().\n *\n * Process tree:\n *\n * ensureHost() ──detached──▶ host-lifecycle.ts (this supervisor, owns the pidfile)\n * │ byte-proxies the public socket\n * ▼\n * cli-main --mode rpc --listen unix://<public>.internal\n *\n * The supervisor exists to enforce the host lifecycle policy without touching the\n * RPC host itself:\n *\n * - cold start: `transient` (default) means the host lives for the current login\n * session and idle-exits; `persistent` never idle-exits.\n * - idle exit: after a continuous window with zero attached client connections\n * and zero active agent turns, the supervisor tears the host down cleanly\n * (child SIGTERM first so the host flushes pending output and removes its own\n * socket, then pidfile/settings removal mirroring ensureHost's cleanupState).\n *\n * Observability without host changes: proxying the public socket yields the\n * exact connection count, and the supervisor keeps one always-on observer\n * connection to the internal socket. The multi-session host broadcasts every\n * session lifecycle/agent event to every connection, so the observer sees\n * `agent_start`/`agent_settled` for all sessions even when no client is\n * attached. If the observer connection is ever unhealthy, activity is reported\n * as unknown (non-idle), so a broken observer can only keep the host alive,\n * never kill it mid-turn.\n *\n * Lifetime binding: the host is spawned with an extra inherited pipe on fd 3\n * whose write end this supervisor holds and never writes to. The kernel closes\n * that end whenever the supervisor dies - including SIGKILL, an OOM kill, or a\n * crash, where no JS handler runs at all - so the host reads EOF and shuts down\n * cleanly, removing the private internal directory. `stopChild()` remains the\n * fast path for orderly shutdowns; the pipe is what makes an orphaned host\n * impossible. `SENPI_RPC_HOST_WATCH_PPID` is passed alongside as a belt-and-\n * braces fallback for platforms where the extra fd is not inherited.\n */\nimport { type ChildProcess, spawn } from \"node:child_process\";\nimport { randomUUID } from \"node:crypto\";\nimport { realpathSync, writeSync } from \"node:fs\";\nimport { access, chmod, mkdir, readFile, rm, unlink, writeFile } from \"node:fs/promises\";\nimport { createConnection, createServer, type Server, type Socket } from \"node:net\";\nimport { tmpdir } from \"node:os\";\nimport { dirname, extname, join, resolve } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport { getAgentDir, isBunBinary } from \"../../config.ts\";\nimport { readProcessStartTime } from \"../app-server/daemon/process.ts\";\nimport { createHostDaemonPaths } from \"./host-ensure.ts\";\nimport {\n\tHOST_CLEANUP_PATHS_ENV,\n\tHOST_SCRATCH_DIR_ENV,\n\tHOST_WATCH_FD_ENV,\n\tHOST_WATCH_PPID_ENV,\n} from \"./host-watchdog.ts\";\nimport { attachJsonlLineReader, MAX_RPC_LINE_CHARACTERS } from \"./jsonl.ts\";\nimport {\n\tauthenticateSocket,\n\tcreateSocketSecret,\n\treadSocketSecret,\n\tresolveSocketTransportAddress,\n\tSOCKET_SECRET_FILE_ENV,\n\tsendSocketHandshake,\n\tsocketSecretPath,\n} from \"./socket-transport.ts\";\n\nexport type HostColdStart = \"transient\" | \"persistent\";\n\n/** Environment override for the cold-start policy: `transient` or `persistent`. */\nexport const HOST_COLD_START_ENV = \"SENPI_RPC_HOST_COLD_START\";\n/** Environment override for the idle-exit window in milliseconds. */\nexport const HOST_IDLE_EXIT_MS_ENV = \"SENPI_RPC_HOST_IDLE_EXIT_MS\";\n/** Default idle-exit window: 15 minutes of continuous no-connection, no-turn idle. */\nexport const DEFAULT_HOST_IDLE_EXIT_MS = 15 * 60_000;\n\n/** The policy fields ensureHost() records in rpc-host-daemon/settings.json. */\nexport interface HostLifecyclePolicyInput {\n\treadonly coldStart?: HostColdStart;\n\treadonly idleExitMs?: number;\n}\n\nexport interface HostLifecyclePolicy {\n\treadonly coldStart: HostColdStart;\n\treadonly idleExitMs: number;\n}\n\nconst CHILD_STOP_TIMEOUT_MS = 5_000;\n/** Win32 named-pipe shutdown can leave supervisor handles live after close starts. */\nconst WINDOWS_SUPERVISOR_SHUTDOWN_HARD_EXIT_MS = 2_000;\n\n/**\n * Child stdio slot carrying the supervisor-lifetime pipe. The supervisor holds\n * the write end open and never writes; the kernel closes it when the supervisor\n * dies for ANY reason (SIGKILL, OOM kill, crash), so the host sees EOF on this\n * fd and shuts itself down. Catchable-signal cleanup alone cannot do this.\n */\nconst CHILD_WATCH_FD = 3;\n\n/**\n * The internal hop must stay short enough for sun_path (104 bytes on macOS)\n * regardless of where the public socket lives, and private against other local\n * users, so it gets its own 0700 directory under the OS temp directory.\n */\nasync function createInternalSocketPath(\n\tbaseDir = tmpdir(),\n): Promise<{ socket: string; dir?: string; secretPath?: string }> {\n\tif (process.platform === \"win32\") {\n\t\tconst dir = join(baseDir, `internal-${randomUUID()}`);\n\t\tawait mkdir(dir, { recursive: false, mode: 0o700 });\n\t\treturn {\n\t\t\tsocket: `\\\\\\\\.\\\\pipe\\\\senpi-rpc-internal-${randomUUID()}`,\n\t\t\tdir,\n\t\t\tsecretPath: join(dir, \"secret\"),\n\t\t};\n\t}\n\tconst dir = join(tmpdir(), `senpi-rpc-host-internal-${randomUUID().slice(0, 8)}`);\n\tawait mkdir(dir, { recursive: false, mode: 0o700 });\n\tawait writeFile(\n\t\tjoin(dir, \".owner\"),\n\t\tJSON.stringify({\n\t\t\tpid: process.pid,\n\t\t\tprocessStartTime: await readProcessStartTime(process.pid),\n\t\t\tcreatedAt: Date.now(),\n\t\t}),\n\t\t{ mode: 0o600 },\n\t);\n\treturn { socket: join(dir, \"host.sock\"), dir, secretPath: join(dir, \".secret\") };\n}\n\nexport function parseColdStart(value: string | undefined): HostColdStart | undefined {\n\treturn value === \"transient\" || value === \"persistent\" ? value : undefined;\n}\n\nexport function parseIdleExitMs(value: string | undefined): number | undefined {\n\tif (value === undefined || !/^\\d+$/.test(value.trim())) return undefined;\n\tconst parsed = Number(value.trim());\n\treturn Number.isFinite(parsed) && parsed > 0 ? parsed : undefined;\n}\n\n/**\n * Resolves the effective host policy. Precedence: environment overrides beat\n * settings.json, which beats the documented defaults (transient, 15 minutes).\n * Invalid values at either source fall through to the next source.\n */\nexport function resolveHostPolicy(\n\tsettings: unknown,\n\tenv: Readonly<Record<string, string | undefined>>,\n): HostLifecyclePolicy {\n\tconst record = isRecord(settings) ? settings : {};\n\tconst coldStart =\n\t\tparseColdStart(env[HOST_COLD_START_ENV]) ?? parseColdStart(asOptionalString(record.coldStart)) ?? \"transient\";\n\tconst idleExitMs =\n\t\tparseIdleExitMs(env[HOST_IDLE_EXIT_MS_ENV]) ??\n\t\tparseIdleExitMs(asOptionalString(record.idleExitMs)) ??\n\t\tDEFAULT_HOST_IDLE_EXIT_MS;\n\treturn { coldStart, idleExitMs };\n}\n\nexport interface HostActivity {\n\treadonly connections: number;\n\treadonly activeTurns: number;\n}\n\n/**\n * How the supervisor reads its child's exit. The RPC host exits 0 only through\n * its own clean shutdown path - including its idle/empty-host policy - so that\n * is an intentional stop, not a crash: the supervisor mirrors its own idle exit\n * instead of reporting failure. Any non-zero code or signal stays a crash.\n */\nexport function classifyChildExit(\n\tcode: number | null,\n\tsignal: NodeJS.Signals | null,\n): { reason: string; exitCode: number } {\n\tif (code === 0 && signal === null) return { reason: \"rpc host exited on its own idle policy\", exitCode: 0 };\n\treturn { reason: `rpc host process exited unexpectedly (${code ?? signal})`, exitCode: 1 };\n}\n\nexport type IdleExitDecision = \"active\" | \"idle\" | \"exit\";\n\n/**\n * Pure idle-window decision core. `update()` must be called with the CURRENT\n * activity state; the window only counts continuously idle time and any\n * activity resets it, so a busy host can never cross the threshold.\n */\nexport class IdleExitDecider {\n\tprivate idleSince: number | undefined;\n\tprivate readonly now: () => number;\n\treadonly idleExitMs: number;\n\n\tconstructor(idleExitMs: number, now: () => number = Date.now) {\n\t\tthis.idleExitMs = idleExitMs;\n\t\tthis.now = now;\n\t}\n\n\tupdate(activity: HostActivity): IdleExitDecision {\n\t\t// Any attachment or active turn both holds the host open and resets the\n\t\t// window, so only CONTINUOUS idle can ever cross the threshold.\n\t\tif (activity.connections > 0 || activity.activeTurns > 0) {\n\t\t\tthis.idleSince = undefined;\n\t\t\treturn \"active\";\n\t\t}\n\t\tif (this.idleExitMs === Number.POSITIVE_INFINITY) return \"idle\";\n\t\tif (this.idleSince === undefined) {\n\t\t\tthis.idleSince = this.now();\n\t\t\treturn \"idle\";\n\t\t}\n\t\treturn this.now() - this.idleSince >= this.idleExitMs ? \"exit\" : \"idle\";\n\t}\n}\n\nexport interface SupervisorLaunch {\n\treadonly socket: string;\n\treadonly hostArgs: readonly string[];\n\t/** Optional runtime command used by rebranded/bundled callers. */\n\treadonly childCommand?: string;\n\treadonly childArgs?: readonly string[];\n\t/** Explicit ownership directory for callers whose environment is not yet branded. */\n\treadonly agentDir?: string;\n}\n\n/** Hidden internal launch route: wire-invisible, never advertised by the public CLI surface. */\nexport const INTERNAL_SUPERVISOR_FLAG = \"--internal-rpc-host-supervisor\";\n\n/**\n * Engine-global flags a rebranded wrapper may legitimately prepend when it\n * re-dispatches this binary. `packages/omo-native` injects `--extension <dir>`\n * for every non-early command, which pushed the sentinel off argv[0].\n */\nconst INJECTABLE_PREFIX_FLAGS = new Set([\"--extension\"]);\n\n/**\n * Returns the internal supervisor payload when argv selects that route.\n *\n * The route dispatches when the sentinel is argv[0] OR is preceded only by\n * known injectable prefix flags and their values - the one perturbation\n * wrappers legitimately perform. Everything else disqualifies it: a positional\n * operand, `--`, or an unknown flag before the sentinel all return undefined,\n * so a user-supplied value that happens to equal the sentinel can never reach\n * the supervisor.\n *\n * The skipped prefix is deliberately NOT forwarded to the host: a wrapper\n * re-injects its own prefix on every re-entry, so the host child receives it\n * from the wrapper rather than twice from here.\n */\nexport function findInternalSupervisorArgs(argv: readonly string[]): readonly string[] | undefined {\n\tfor (let index = 0; index < argv.length; index++) {\n\t\tconst arg = argv[index];\n\t\tif (arg === INTERNAL_SUPERVISOR_FLAG) return argv.slice(index + 1);\n\t\t// A prefix flag only counts when its value is actually present.\n\t\tif (!INJECTABLE_PREFIX_FLAGS.has(arg) || index + 1 >= argv.length) return undefined;\n\t\tindex++;\n\t}\n\treturn undefined;\n}\n\n/** `--socket <path>` selects the public socket; every other argument is forwarded to the host CLI. */\nexport function parseSupervisorArgs(argv: readonly string[]): SupervisorLaunch | undefined {\n\tconst hostArgs: string[] = [];\n\tlet socket: string | undefined;\n\tlet childCommand: string | undefined;\n\tlet childArgs: readonly string[] | undefined;\n\tlet agentDir: string | undefined;\n\tfor (let index = 0; index < argv.length; index++) {\n\t\tconst arg = argv[index];\n\t\tif (arg === \"--socket\" && index + 1 < argv.length) {\n\t\t\tsocket = argv[++index];\n\t\t\tcontinue;\n\t\t}\n\t\tif (arg === \"--child-command\" && index + 1 < argv.length) {\n\t\t\tchildCommand = argv[++index];\n\t\t\tcontinue;\n\t\t}\n\t\tif (arg === \"--child-args\" && index + 1 < argv.length) {\n\t\t\ttry {\n\t\t\t\tconst parsed: unknown = JSON.parse(argv[++index]);\n\t\t\t\tif (Array.isArray(parsed) && parsed.every((value) => typeof value === \"string\")) childArgs = parsed;\n\t\t\t} catch {\n\t\t\t\treturn undefined;\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\t\tif (arg === \"--agent-dir\" && index + 1 < argv.length) {\n\t\t\tagentDir = argv[++index];\n\t\t\tcontinue;\n\t\t}\n\t\thostArgs.push(arg);\n\t}\n\treturn socket === undefined ? undefined : { socket, hostArgs, childCommand, childArgs, agentDir };\n}\n\n/** Resolves the committed CLI entry this supervisor wraps (source tree or built dist). */\nexport function resolveCliMainPath(): string {\n\tconst modulePath = fileURLToPath(import.meta.url);\n\tconst extension = modulePath.endsWith(\".ts\") ? \".ts\" : \".js\";\n\treturn resolve(dirname(modulePath), \"..\", \"..\", `cli-main${extension}`);\n}\n\n/**\n * Resolves the host child spawn. Explicit child commands (desktop launchers)\n * are forwarded untouched. The default re-enters the committed CLI entry\n * through the runtime, except in compiled standalone binaries, which always\n * boot their embedded entrypoint and would parse a script path as CLI\n * arguments - there the executable itself is the CLI, so the mode flags are\n * passed directly. Exported for tests.\n */\nexport function resolveHostChildLaunch(\n\tlaunch: SupervisorLaunch,\n\tinternalSocket: string,\n\tcompiled: boolean = isBunBinary,\n): { command: string; args: string[] } {\n\tif (launch.childCommand) {\n\t\treturn {\n\t\t\tcommand: launch.childCommand,\n\t\t\targs: [...(launch.childArgs ?? []), \"--listen\", `unix://${internalSocket}`],\n\t\t};\n\t}\n\treturn {\n\t\tcommand: process.execPath,\n\t\targs: [\n\t\t\t...(compiled ? [] : [...process.execArgv, resolveCliMainPath()]),\n\t\t\t\"--mode\",\n\t\t\t\"rpc\",\n\t\t\t\"--multi-session\",\n\t\t\t\"--listen\",\n\t\t\t`unix://${internalSocket}`,\n\t\t\t...launch.hostArgs,\n\t\t],\n\t};\n}\n\n/** Mirrors cross-spawn: survives cmd.exe parsing and `CommandLineToArgvW`. */\nfunction quoteWindowsShellArg(value: string): string {\n\tconst escaped = value\n\t\t.replace(/(\\\\*)\"/g, '$1$1\\\\\"')\n\t\t.replace(/(\\\\*)$/, \"$1$1\")\n\t\t.replace(/([()%!^\"<>&|;,])/g, \"^$1\");\n\treturn `\"${escaped}\"`;\n}\n\n/**\n * Windows refuses to spawn a `.cmd`/`.bat` without a shell, and Node's\n * `shell: true` concatenates argv without escaping it. Escape each original\n * value before adding the surrounding quotes so `.cmd`/`.bat` launchers survive\n * cmd.exe parsing without double-escaping.\n * Exported for tests.\n */\nexport function spawnableChildLaunch(\n\tlaunch: { command: string; args: string[] },\n\tplatform: NodeJS.Platform = process.platform,\n): { command: string; args: string[]; shell: boolean } {\n\tconst extension = extname(launch.command).toLowerCase();\n\tif (platform !== \"win32\" || (extension !== \".cmd\" && extension !== \".bat\")) {\n\t\treturn { ...launch, shell: false };\n\t}\n\treturn {\n\t\tcommand: quoteWindowsShellArg(launch.command),\n\t\targs: launch.args.map(quoteWindowsShellArg),\n\t\tshell: true,\n\t};\n}\n\nexport async function runHostSupervisor(launch: SupervisorLaunch): Promise<void> {\n\tconst paths = createHostDaemonPaths(launch.agentDir ?? getAgentDir());\n\tconst policy = resolveHostPolicy(await readSettingsFile(paths.settingsFile), process.env);\n\tconst publicSocket = launch.socket;\n\tconst internal = await createInternalSocketPath(paths.dir);\n\tconst internalSocket = internal.socket;\n\tconst internalSecretPath = internal.secretPath ?? socketSecretPath(internalSocket);\n\tconst internalSecret = process.platform === \"win32\" ? await createSocketSecret(internalSecretPath) : undefined;\n\tconst publicSecret =\n\t\tprocess.platform === \"win32\" ? await readSocketSecret(socketSecretPath(publicSocket)) : undefined;\n\tconst clientSockets = new Set<Socket>();\n\tconst busySessions = new Map<string, number>();\n\tlet observerHealthy = false;\n\tlet observerReconnectTimer: ReturnType<typeof setTimeout> | undefined;\n\tlet childExitWatchTimer: ReturnType<typeof setInterval> | undefined;\n\tlet shuttingDown = false;\n\tlet shutdownPromise: Promise<never> | undefined;\n\n\tconst childLaunch = spawnableChildLaunch(resolveHostChildLaunch(launch, internalSocket));\n\tconst child = spawn(childLaunch.command, childLaunch.args, {\n\t\tenv: {\n\t\t\t...process.env,\n\t\t\t...(launch.agentDir ? { SENPI_CODING_AGENT_DIR: launch.agentDir } : {}),\n\t\t\t[HOST_WATCH_FD_ENV]: String(CHILD_WATCH_FD),\n\t\t\t[HOST_WATCH_PPID_ENV]: String(process.pid),\n\t\t\t...(internal.dir ? { [HOST_SCRATCH_DIR_ENV]: internal.dir } : {}),\n\t\t\t...(internalSecret ? { [SOCKET_SECRET_FILE_ENV]: internalSecretPath } : {}),\n\t\t\t[HOST_CLEANUP_PATHS_ENV]: [\n\t\t\t\tpaths.pidFile,\n\t\t\t\tpaths.settingsFile,\n\t\t\t\t...(process.platform === \"win32\" ? [] : [publicSocket]),\n\t\t\t].join(\"\\n\"),\n\t\t},\n\t\t// Slot 3 is the lifetime pipe: \"pipe\" gives the child a read end it can\n\t\t// wait on and keeps the write end owned by this process alone.\n\t\tshell: childLaunch.shell,\n\t\tstdio: [\"ignore\", \"ignore\", \"inherit\", \"pipe\"],\n\t\t// The supervisor is spawned detached, so on win32 it owns no console. A\n\t\t// console-subsystem child started from it would allocate a fresh one,\n\t\t// which Windows Terminal renders as an empty window that takes focus.\n\t\t// CREATE_NO_WINDOW gives the child a console with no window instead.\n\t\twindowsHide: true,\n\t});\n\t// Nothing is ever written; the pipe exists purely so its EOF is a reliable\n\t// death notification. Errors on it must not crash the supervisor.\n\tchild.stdio[CHILD_WATCH_FD]?.on(\"error\", () => {});\n\tchild.once(\"exit\", (code, signal) => {\n\t\tif (shuttingDown) return;\n\t\tconst { reason, exitCode } = classifyChildExit(code, signal);\n\t\tvoid shutdown(reason, exitCode);\n\t});\n\n\tconst server = createServer((client) => {\n\t\tconst accept = (): void => {\n\t\t\tif (shuttingDown) {\n\t\t\t\tclient.destroy();\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst internal = createConnection(\n\t\t\t\tresolveSocketTransportAddress(internalSocket, process.platform, internalSecret),\n\t\t\t);\n\t\t\tif (internalSecret) sendSocketHandshake(internal, internalSecret);\n\t\t\tclientSockets.add(client);\n\t\t\tconst detach = (): void => {\n\t\t\t\tclientSockets.delete(client);\n\t\t\t\tinternal.destroy();\n\t\t\t\tclient.destroy();\n\t\t\t};\n\t\t\tclient.pipe(internal);\n\t\t\tinternal.pipe(client);\n\t\t\tclient.once(\"close\", detach);\n\t\t\tclient.once(\"error\", detach);\n\t\t\tinternal.once(\"close\", detach);\n\t\t\tinternal.once(\"error\", detach);\n\t\t};\n\t\tif (publicSecret) authenticateSocket(client, publicSecret, accept);\n\t\telse accept();\n\t});\n\tserver.once(\"error\", (cause) => {\n\t\tif (!shuttingDown) void shutdown(`public socket listener failed: ${errorMessage(cause)}`, 1);\n\t});\n\n\tconst decider = new IdleExitDecider(\n\t\tpolicy.coldStart === \"persistent\" ? Number.POSITIVE_INFINITY : policy.idleExitMs,\n\t);\n\tconst tickIntervalMs = Math.max(20, Math.min(1_000, policy.idleExitMs / 4));\n\tconst ticker = setInterval(() => {\n\t\tif (decider.update(currentActivity()) === \"exit\") void shutdown(\"idle\", 0);\n\t}, tickIntervalMs);\n\n\tfunction currentActivity(): HostActivity {\n\t\treturn {\n\t\t\tconnections: clientSockets.size,\n\t\t\tactiveTurns: observerHealthy ? countBusySessions() : 1,\n\t\t};\n\t}\n\n\tfunction countBusySessions(): number {\n\t\tlet busy = 0;\n\t\tfor (const count of busySessions.values()) if (count > 0) busy++;\n\t\treturn busy;\n\t}\n\n\tfunction observeHostEvent(line: string): void {\n\t\tlet event: unknown;\n\t\ttry {\n\t\t\tevent = JSON.parse(line);\n\t\t} catch {\n\t\t\treturn;\n\t\t}\n\t\tif (typeof event !== \"object\" || event === null) return;\n\t\tconst { type, sessionId } = event as { type?: unknown; sessionId?: unknown };\n\t\tif (typeof sessionId !== \"string\") return;\n\t\tif (type === \"agent_start\") busySessions.set(sessionId, (busySessions.get(sessionId) ?? 0) + 1);\n\t\telse if (type === \"agent_settled\")\n\t\t\tbusySessions.set(sessionId, Math.max(0, (busySessions.get(sessionId) ?? 1) - 1));\n\t}\n\n\tasync function shutdown(reason: string, exitCode: number): Promise<never> {\n\t\t// Single-flight: concurrent triggers (listener error, child exit, signals)\n\t\t// must not process.exit mid-cleanup. Late callers park on this promise while\n\t\t// the first shutdown finishes tearing down and exits.\n\t\tshutdownPromise ??= performShutdown(reason, exitCode);\n\t\treturn shutdownPromise;\n\t}\n\n\tasync function performShutdown(reason: string, exitCode: number): Promise<never> {\n\t\tif (shuttingDown) process.exit(exitCode);\n\t\tshuttingDown = true;\n\t\tclearInterval(ticker);\n\t\tif (childExitWatchTimer) clearInterval(childExitWatchTimer);\n\t\tconst hardExit =\n\t\t\tprocess.platform === \"win32\"\n\t\t\t\t? setTimeout(() => process.exit(exitCode), WINDOWS_SUPERVISOR_SHUTDOWN_HARD_EXIT_MS)\n\t\t\t\t: undefined;\n\t\ttry {\n\t\t\twriteStderrLine(`senpi rpc host supervisor: ${reason} shutdown`);\n\t\t\tfor (const client of clientSockets) client.destroy();\n\t\t\tawait closeServer(server);\n\t\t\t// Unlink the private directory BEFORE the child stop, which can take seconds:\n\t\t\t// an external SIGKILL landing during that wait (ensureHost escalates while\n\t\t\t// replacing a host) would otherwise leave the directory behind. The child\n\t\t\t// keeps serving through its already-open socket fd until it exits, and its\n\t\t\t// own watchdog cleanup makes the removal idempotent.\n\t\t\tif (internal.dir) await rm(internal.dir, { recursive: true, force: true });\n\t\t\tawait stopChild(child);\n\t\t\tobserver?.destroy();\n\t\t\tif (publicSocketOwned && process.platform !== \"win32\") await rm(publicSocket, { force: true });\n\t\t\t// Mirror ensureHost's cleanupState: the pidfile and settings describe a\n\t\t\t// live host only; the stderr log stays for diagnostics.\n\t\t\tawait rm(paths.pidFile, { force: true });\n\t\t\tawait rm(paths.settingsFile, { force: true });\n\t\t} finally {\n\t\t\tif (hardExit) clearTimeout(hardExit);\n\t\t\t// Explicitly terminate after every supervisor shutdown trigger. Windows\n\t\t\t// named-pipe handles can outlive their JavaScript wrappers, so cleanup\n\t\t\t// failure must never leave the supervisor resident or the host orphaned.\n\t\t\tprocess.exit(exitCode);\n\t\t}\n\t}\n\n\tlet observer: Socket | undefined;\n\tlet publicSocketOwned = false;\n\t// Registered before the startup handshake, not after it: the private internal\n\t// directory already exists at this point, so a SIGTERM arriving during host\n\t// startup must run the same cleanup instead of Node's default kill, which\n\t// would leave that directory behind.\n\tregisterSupervisorSignals(shutdown);\n\ttry {\n\t\tawait waitForListener(internalSocket, 30_000, internalSecret);\n\t\tawait connectObserver();\n\t\tawait prepareSocketPath(publicSocket);\n\t\tawait listen(server, publicSocket, publicSecret);\n\t\tpublicSocketOwned = true;\n\t} catch (cause) {\n\t\tawait shutdown(`startup failed: ${errorMessage(cause)}`, 1);\n\t}\n\tasync function connectObserver(): Promise<void> {\n\t\tconst secret = internalSecret;\n\t\tconst next = createConnection(resolveSocketTransportAddress(internalSocket, process.platform, secret));\n\t\tif (secret) sendSocketHandshake(next, secret);\n\t\tawait waitForConnect(next, 5_000);\n\t\tobserver = next;\n\t\tobserverHealthy = true;\n\t\tattachJsonlLineReader(next, observeHostEvent, { maxLineLength: MAX_RPC_LINE_CHARACTERS });\n\t\tconst lost = (): void => {\n\t\t\tif (observer !== next || shuttingDown) return;\n\t\t\tobserverHealthy = false;\n\t\t\tobserver = undefined;\n\t\t\tif (observerReconnectTimer === undefined) {\n\t\t\t\tobserverReconnectTimer = setTimeout(() => {\n\t\t\t\t\tobserverReconnectTimer = undefined;\n\t\t\t\t\tvoid connectObserver().catch(() => lost());\n\t\t\t\t}, 250);\n\t\t\t\tobserverReconnectTimer.unref?.();\n\t\t\t}\n\t\t};\n\t\tnext.once(\"close\", lost);\n\t\tnext.once(\"error\", lost);\n\t}\n\n\tif (process.platform === \"win32\" && child.pid !== undefined) {\n\t\tconst childStartTime = await readProcessStartTime(child.pid, process.platform, 1_000);\n\t\tlet missingIdentityChecks = 0;\n\t\tlet checkingChildIdentity = false;\n\t\tconst checkChildIdentity = (): void => {\n\t\t\tif (shuttingDown || checkingChildIdentity || child.exitCode !== null || child.signalCode !== null) return;\n\t\t\tcheckingChildIdentity = true;\n\t\t\tvoid readProcessStartTime(child.pid!, process.platform, 1_000)\n\t\t\t\t.then((currentStartTime) => {\n\t\t\t\t\tif (currentStartTime === undefined) missingIdentityChecks++;\n\t\t\t\t\telse missingIdentityChecks = 0;\n\t\t\t\t\tconst identityChanged =\n\t\t\t\t\t\tchildStartTime !== undefined && currentStartTime !== undefined && currentStartTime !== childStartTime;\n\t\t\t\t\tif (identityChanged || missingIdentityChecks >= 2) {\n\t\t\t\t\t\tvoid shutdown(\"rpc host child exit observed by identity watchdog\", 0);\n\t\t\t\t\t}\n\t\t\t\t})\n\t\t\t\t.catch(() => {})\n\t\t\t\t.finally(() => {\n\t\t\t\t\tcheckingChildIdentity = false;\n\t\t\t\t});\n\t\t};\n\t\tchildExitWatchTimer = setInterval(checkChildIdentity, 500);\n\t\tchildExitWatchTimer.unref?.();\n\t}\n\twriteStderrLine(\n\t\t`senpi rpc host ready on unix://${publicSocket} (coldStart=${policy.coldStart}, idleExitMs=${\n\t\t\tpolicy.coldStart === \"persistent\" ? \"never\" : String(policy.idleExitMs)\n\t\t})`,\n\t);\n\tawait new Promise<never>(() => {});\n}\n\n/** External stop (ensureHost replacement, tests, QA) must clean up like idle exit. */\nfunction registerSupervisorSignals(shutdown: (reason: string, exitCode: number) => Promise<never>): void {\n\tfor (const signal of process.platform === \"win32\" ? ([\"SIGTERM\"] as const) : ([\"SIGTERM\", \"SIGHUP\"] as const)) {\n\t\tprocess.on(signal, () => {\n\t\t\tvoid shutdown(`signal:${signal}`, signal === \"SIGHUP\" ? 129 : 143);\n\t\t});\n\t}\n}\n\nasync function readSettingsFile(settingsFile: string): Promise<unknown> {\n\ttry {\n\t\treturn JSON.parse(await readFile(settingsFile, \"utf8\"));\n\t} catch {\n\t\treturn undefined;\n\t}\n}\n\nasync function stopChild(child: ChildProcess): Promise<void> {\n\tif (child.exitCode !== null || child.signalCode !== null) return;\n\ttry {\n\t\tchild.kill(\"SIGTERM\");\n\t} catch {\n\t\treturn;\n\t}\n\tif (await waitForChildExit(child, CHILD_STOP_TIMEOUT_MS)) return;\n\ttry {\n\t\tchild.kill(\"SIGKILL\");\n\t} catch {\n\t\treturn;\n\t}\n\tawait waitForChildExit(child, 2_000);\n}\n\nfunction waitForChildExit(child: ChildProcess, timeoutMs: number): Promise<boolean> {\n\tif (child.exitCode !== null || child.signalCode !== null) return Promise.resolve(true);\n\treturn new Promise((resolve) => {\n\t\tconst timer = setTimeout(() => {\n\t\t\tchild.off(\"exit\", onExit);\n\t\t\tresolve(false);\n\t\t}, timeoutMs);\n\t\tconst onExit = (): void => {\n\t\t\tclearTimeout(timer);\n\t\t\tresolve(true);\n\t\t};\n\t\tchild.once(\"exit\", onExit);\n\t});\n}\n\nasync function waitForListener(socketPath: string, timeoutMs: number, secret?: Uint8Array): Promise<void> {\n\tconst deadline = Date.now() + timeoutMs;\n\twhile (Date.now() <= deadline) {\n\t\tif (await canConnect(socketPath, secret)) return;\n\t\tawait delay(50);\n\t}\n\tthrow new Error(`${socketPath}: host did not start listening within ${timeoutMs}ms`);\n}\n\nfunction canConnect(socketPath: string, secret?: Uint8Array): Promise<boolean> {\n\treturn new Promise((resolve) => {\n\t\tconst socket = createConnection(resolveSocketTransportAddress(socketPath, process.platform, secret));\n\t\tif (secret) sendSocketHandshake(socket, secret);\n\t\tconst settle = (value: boolean): void => {\n\t\t\tsocket.destroy();\n\t\t\tresolve(value);\n\t\t};\n\t\tsocket.once(\"connect\", () => settle(true));\n\t\tsocket.once(\"error\", () => settle(false));\n\t});\n}\n\nfunction waitForConnect(socket: Socket, timeoutMs: number): Promise<void> {\n\treturn new Promise((resolve, reject) => {\n\t\tconst timer = setTimeout(() => {\n\t\t\tcleanup();\n\t\t\treject(new Error(`observer connection to internal host timed out after ${timeoutMs}ms`));\n\t\t}, timeoutMs);\n\t\tconst onConnect = (): void => {\n\t\t\tcleanup();\n\t\t\tresolve();\n\t\t};\n\t\tconst onError = (cause: Error): void => {\n\t\t\tcleanup();\n\t\t\treject(cause);\n\t\t};\n\t\tconst cleanup = (): void => {\n\t\t\tclearTimeout(timer);\n\t\t\tsocket.off(\"connect\", onConnect);\n\t\t\tsocket.off(\"error\", onError);\n\t\t};\n\t\tsocket.once(\"connect\", onConnect);\n\t\tsocket.once(\"error\", onError);\n\t});\n}\n\nasync function prepareSocketPath(socketPath: string): Promise<void> {\n\tif (process.platform === \"win32\") return;\n\tawait mkdir(dirname(socketPath), { recursive: true, mode: 0o700 });\n\ttry {\n\t\tawait access(socketPath);\n\t} catch (cause) {\n\t\tif (isNodeErrorCode(cause, \"ENOENT\")) return;\n\t\tthrow cause;\n\t}\n\tif (await canConnect(socketPath)) throw new Error(`${socketPath}: address already in use by a live server.`);\n\tawait unlink(socketPath);\n}\n\nfunction listen(server: Server, socketPath: string, secret?: Uint8Array): Promise<void> {\n\treturn new Promise((resolve, reject) => {\n\t\tserver.once(\"error\", reject);\n\t\tserver.listen(\n\t\t\t{\n\t\t\t\tpath: resolveSocketTransportAddress(socketPath, process.platform, secret),\n\t\t\t\treadableAll: false,\n\t\t\t\twritableAll: false,\n\t\t\t},\n\t\t\tasync () => {\n\t\t\t\tserver.off(\"error\", reject);\n\t\t\t\ttry {\n\t\t\t\t\tif (process.platform !== \"win32\" && !socketPath.startsWith(\"\\0\")) await chmod(socketPath, 0o600);\n\t\t\t\t\tresolve();\n\t\t\t\t} catch (cause) {\n\t\t\t\t\treject(cause);\n\t\t\t\t}\n\t\t\t},\n\t\t);\n\t});\n}\n\nfunction closeServer(server: Server): Promise<void> {\n\treturn new Promise((resolve) => {\n\t\tserver.close(() => resolve());\n\t});\n}\n\nfunction writeStderrLine(text: string): void {\n\t// A detached daemon exiting right after an async stderr.write to a file can\n\t// lose the output entirely; write synchronously so diagnostics always land.\n\ttry {\n\t\twriteSync(2, `${text}\\n`);\n\t} catch {\n\t\t/* fd 2 unavailable: nothing more we can do. */\n\t}\n}\n\nfunction delay(ms: number): Promise<void> {\n\treturn new Promise((resolveDelay) => setTimeout(resolveDelay, ms));\n}\n\nfunction errorMessage(cause: unknown): string {\n\treturn cause instanceof Error ? cause.message : String(cause);\n}\n\nfunction isNodeErrorCode(cause: unknown, code: string): boolean {\n\treturn cause instanceof Error && \"code\" in cause && cause.code === code;\n}\n\nfunction isRecord(value: unknown): value is Readonly<Record<string, unknown>> {\n\treturn typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction asOptionalString(value: unknown): string | undefined {\n\treturn typeof value === \"string\" ? value : typeof value === \"number\" ? String(value) : undefined;\n}\n\nfunction isEntryScript(): boolean {\n\tconst entry = process.argv[1];\n\tif (!entry) return false;\n\ttry {\n\t\treturn fileURLToPath(import.meta.url) === realpathSync(entry);\n\t} catch {\n\t\treturn false;\n\t}\n}\n\nif (isEntryScript()) {\n\tconst launch = parseSupervisorArgs(process.argv.slice(2));\n\tif (!launch) {\n\t\twriteStderrLine(\"usage: host-lifecycle.ts --socket <path> [host cli args...]\");\n\t\tprocess.exit(2);\n\t}\n\tvoid runHostSupervisor(launch);\n}\n"]}
@@ -5,7 +5,7 @@ export declare const HOST_SCRATCH_DIR_ENV = "SENPI_RPC_HOST_SCRATCH_DIR";
5
5
  /** Fallback binding when no inherited fd is available: poll this pid. */
6
6
  export declare const HOST_WATCH_PPID_ENV = "SENPI_RPC_HOST_WATCH_PPID";
7
7
  /** Poll cadence for the ppid fallback. */
8
- export declare const HOST_WATCH_PPID_INTERVAL_MS = 2000;
8
+ export declare const HOST_WATCH_PPID_INTERVAL_MS = 250;
9
9
  export declare const HOST_CLEANUP_PATHS_ENV = "SENPI_RPC_HOST_CLEANUP_PATHS";
10
10
  export interface HostWatchdogConfig {
11
11
  readonly fd?: number;
@@ -31,5 +31,5 @@ export declare function readHostWatchdogConfigFromBrandEnv(): HostWatchdogConfig
31
31
  * must not close it themselves. Returns a disarm function; a no-op when no
32
32
  * binding is configured.
33
33
  */
34
- export declare function armHostWatchdog(config: HostWatchdogConfig | undefined, onSupervisorGone: (reason: string) => void): () => void;
34
+ export declare function armHostWatchdog(config: HostWatchdogConfig | undefined, onSupervisorGone: (reason: string, cleanup?: Promise<void>) => void): () => void;
35
35
  //# sourceMappingURL=host-watchdog.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"host-watchdog.d.ts","sourceRoot":"","sources":["../../../src/modes/rpc/host-watchdog.ts"],"names":[],"mappings":"AAoBA,sFAAsF;AACtF,eAAO,MAAM,iBAAiB,4BAA4B,CAAC;AAC3D,gFAAgF;AAChF,eAAO,MAAM,oBAAoB,+BAA+B,CAAC;AACjE,yEAAyE;AACzE,eAAO,MAAM,mBAAmB,8BAA8B,CAAC;AAC/D,0CAA0C;AAC1C,eAAO,MAAM,2BAA2B,OAAQ,CAAC;AACjD,eAAO,MAAM,sBAAsB,iCAAiC,CAAC;AAErE,MAAM,WAAW,kBAAkB;IAClC,QAAQ,CAAC,EAAE,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,YAAY,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CAC1C;AAQD;;;;GAIG;AACH,wBAAgB,sBAAsB,CACrC,GAAG,GAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAe,GAC7D,kBAAkB,GAAG,SAAS,CAYhC;AAED,yEAAyE;AACzE,wBAAgB,kCAAkC,IAAI,kBAAkB,GAAG,SAAS,CAOnF;AAED;;;;;;;;;GASG;AACH,wBAAgB,eAAe,CAC9B,MAAM,EAAE,kBAAkB,GAAG,SAAS,EACtC,gBAAgB,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,GACxC,MAAM,IAAI,CAaZ"}
1
+ {"version":3,"file":"host-watchdog.d.ts","sourceRoot":"","sources":["../../../src/modes/rpc/host-watchdog.ts"],"names":[],"mappings":"AAqBA,sFAAsF;AACtF,eAAO,MAAM,iBAAiB,4BAA4B,CAAC;AAC3D,gFAAgF;AAChF,eAAO,MAAM,oBAAoB,+BAA+B,CAAC;AACjE,yEAAyE;AACzE,eAAO,MAAM,mBAAmB,8BAA8B,CAAC;AAC/D,0CAA0C;AAC1C,eAAO,MAAM,2BAA2B,MAAM,CAAC;AAG/C,eAAO,MAAM,sBAAsB,iCAAiC,CAAC;AAErE,MAAM,WAAW,kBAAkB;IAClC,QAAQ,CAAC,EAAE,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,YAAY,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CAC1C;AAQD;;;;GAIG;AACH,wBAAgB,sBAAsB,CACrC,GAAG,GAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAe,GAC7D,kBAAkB,GAAG,SAAS,CAYhC;AAED,yEAAyE;AACzE,wBAAgB,kCAAkC,IAAI,kBAAkB,GAAG,SAAS,CAWnF;AAED;;;;;;;;;GASG;AACH,wBAAgB,eAAe,CAC9B,MAAM,EAAE,kBAAkB,GAAG,SAAS,EACtC,gBAAgB,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,OAAO,CAAC,IAAI,CAAC,KAAK,IAAI,GACjE,MAAM,IAAI,CAqBZ"}