@schoolai/shipyard 3.22.0 → 3.23.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. package/dist/{auth-SRHTZ2JL.js → auth-OHZTVIQU.js} +3 -3
  2. package/dist/capability-detector-worker.js +8 -8
  3. package/dist/{chunk-TFWDJCUJ.js → chunk-2UE3TNY7.js} +2 -2
  4. package/dist/{chunk-WFBU4LXL.js → chunk-2YH743ND.js} +2 -2
  5. package/dist/{chunk-XEBCOG2U.js → chunk-7E6VXTEO.js} +4 -4
  6. package/dist/{chunk-MRD6526D.js → chunk-CA5PKTNJ.js} +2 -2
  7. package/dist/{chunk-JGFN3QI6.js → chunk-CGNWVGXL.js} +4 -4
  8. package/dist/{chunk-ABFHBWBF.js → chunk-HQTCVJRK.js} +2 -2
  9. package/dist/{chunk-TSJOSKN3.js → chunk-JD4WV327.js} +2 -2
  10. package/dist/{chunk-DE3IJ4E4.js → chunk-K7EXPNAD.js} +6 -6
  11. package/dist/{chunk-WPH74RMT.js → chunk-LRBG3X5U.js} +3 -3
  12. package/dist/{chunk-VOC55DTY.js → chunk-OCYT65KO.js} +7 -7
  13. package/dist/{chunk-6RJG24XI.js → chunk-ROEOOZOW.js} +2 -2
  14. package/dist/{chunk-UTL5PF43.js → chunk-SXXAWBW7.js} +5 -3
  15. package/dist/{chunk-UTL5PF43.js.map → chunk-SXXAWBW7.js.map} +1 -1
  16. package/dist/{chunk-TUQTEWK3.js → chunk-VSRWL5SP.js} +2 -2
  17. package/dist/{chunk-WCWHY4C3.js → chunk-W3EMVBWP.js} +4 -4
  18. package/dist/{chunk-VPJRM77V.js → chunk-Y4RRW6MA.js} +4 -4
  19. package/dist/cursor-runner.js +3 -3
  20. package/dist/electron-utility.js +6 -6
  21. package/dist/{git-repo-3OG3TPCC.js → git-repo-IVN2RQNY.js} +4 -4
  22. package/dist/index.js +10 -10
  23. package/dist/{logger-R3DVMU7P.js → logger-I6HU4VSX.js} +3 -3
  24. package/dist/{login-TKO7FQXH.js → login-WL5WEEGJ.js} +6 -6
  25. package/dist/{logout-23UJSTCS.js → logout-EZQ4UBLH.js} +5 -5
  26. package/dist/{mcp-servers-2QITAK3X.js → mcp-servers-52C67MDD.js} +4 -4
  27. package/dist/{plan-backfill-D6FJZ65E.js → plan-backfill-EF6KR6BE.js} +4 -4
  28. package/dist/{roi-E27VSQ7N.js → roi-GUUSTWXN.js} +3 -3
  29. package/dist/{serve-5D77VQ6J.js → serve-J3MG3WHK.js} +147 -56
  30. package/dist/{serve-5D77VQ6J.js.map → serve-J3MG3WHK.js.map} +1 -1
  31. package/dist/{skills-N4FXCXYQ.js → skills-XBREPCFU.js} +2 -2
  32. package/dist/{start-VQSOEMXG.js → start-TCI35UML.js} +11 -11
  33. package/dist/start-TCI35UML.js.map +1 -0
  34. package/package.json +1 -1
  35. package/dist/start-VQSOEMXG.js.map +0 -1
  36. /package/dist/{auth-SRHTZ2JL.js.map → auth-OHZTVIQU.js.map} +0 -0
  37. /package/dist/{chunk-TFWDJCUJ.js.map → chunk-2UE3TNY7.js.map} +0 -0
  38. /package/dist/{chunk-WFBU4LXL.js.map → chunk-2YH743ND.js.map} +0 -0
  39. /package/dist/{chunk-XEBCOG2U.js.map → chunk-7E6VXTEO.js.map} +0 -0
  40. /package/dist/{chunk-MRD6526D.js.map → chunk-CA5PKTNJ.js.map} +0 -0
  41. /package/dist/{chunk-JGFN3QI6.js.map → chunk-CGNWVGXL.js.map} +0 -0
  42. /package/dist/{chunk-ABFHBWBF.js.map → chunk-HQTCVJRK.js.map} +0 -0
  43. /package/dist/{chunk-TSJOSKN3.js.map → chunk-JD4WV327.js.map} +0 -0
  44. /package/dist/{chunk-DE3IJ4E4.js.map → chunk-K7EXPNAD.js.map} +0 -0
  45. /package/dist/{chunk-WPH74RMT.js.map → chunk-LRBG3X5U.js.map} +0 -0
  46. /package/dist/{chunk-VOC55DTY.js.map → chunk-OCYT65KO.js.map} +0 -0
  47. /package/dist/{chunk-6RJG24XI.js.map → chunk-ROEOOZOW.js.map} +0 -0
  48. /package/dist/{chunk-TUQTEWK3.js.map → chunk-VSRWL5SP.js.map} +0 -0
  49. /package/dist/{chunk-WCWHY4C3.js.map → chunk-W3EMVBWP.js.map} +0 -0
  50. /package/dist/{chunk-VPJRM77V.js.map → chunk-Y4RRW6MA.js.map} +0 -0
  51. /package/dist/{git-repo-3OG3TPCC.js.map → git-repo-IVN2RQNY.js.map} +0 -0
  52. /package/dist/{logger-R3DVMU7P.js.map → logger-I6HU4VSX.js.map} +0 -0
  53. /package/dist/{login-TKO7FQXH.js.map → login-WL5WEEGJ.js.map} +0 -0
  54. /package/dist/{logout-23UJSTCS.js.map → logout-EZQ4UBLH.js.map} +0 -0
  55. /package/dist/{mcp-servers-2QITAK3X.js.map → mcp-servers-52C67MDD.js.map} +0 -0
  56. /package/dist/{plan-backfill-D6FJZ65E.js.map → plan-backfill-EF6KR6BE.js.map} +0 -0
  57. /package/dist/{roi-E27VSQ7N.js.map → roi-GUUSTWXN.js.map} +0 -0
  58. /package/dist/{skills-N4FXCXYQ.js.map → skills-XBREPCFU.js.map} +0 -0
@@ -3,11 +3,11 @@ import {
3
3
  _resolveBucketForTesting,
4
4
  detectSkills,
5
5
  scopeEnvironmentsToActiveRepo
6
- } from "./chunk-6RJG24XI.js";
6
+ } from "./chunk-ROEOOZOW.js";
7
7
  import "./chunk-2H7UOFLK.js";
8
8
  export {
9
9
  _resolveBucketForTesting,
10
10
  detectSkills,
11
11
  scopeEnvironmentsToActiveRepo
12
12
  };
13
- //# sourceMappingURL=skills-N4FXCXYQ.js.map
13
+ //# sourceMappingURL=skills-XBREPCFU.js.map
@@ -3,18 +3,18 @@ import {
3
3
  createMetricsCollector,
4
4
  decideAction,
5
5
  makeInitialAttemptState
6
- } from "./chunk-XEBCOG2U.js";
6
+ } from "./chunk-7E6VXTEO.js";
7
7
  import {
8
8
  ensureAuthenticated,
9
9
  getSignalingUrl
10
- } from "./chunk-VPJRM77V.js";
10
+ } from "./chunk-Y4RRW6MA.js";
11
11
  import {
12
12
  print
13
- } from "./chunk-WFBU4LXL.js";
13
+ } from "./chunk-2YH743ND.js";
14
14
  import {
15
15
  loadAuthToken
16
- } from "./chunk-TFWDJCUJ.js";
17
- import "./chunk-WCWHY4C3.js";
16
+ } from "./chunk-2UE3TNY7.js";
17
+ import "./chunk-W3EMVBWP.js";
18
18
  import {
19
19
  CRASH_STDERR_DIRNAME,
20
20
  EXIT_RECORD_BASENAME,
@@ -23,7 +23,7 @@ import {
23
23
  writeExitRecordSync
24
24
  } from "./chunk-UNGAIUEX.js";
25
25
  import "./chunk-WW4UGZBY.js";
26
- import "./chunk-TUQTEWK3.js";
26
+ import "./chunk-VSRWL5SP.js";
27
27
  import "./chunk-ZFKJAYAN.js";
28
28
  import "./chunk-UESTOND6.js";
29
29
  import "./chunk-EHQITHQX.js";
@@ -32,11 +32,11 @@ import {
32
32
  } from "./chunk-X3MULCV5.js";
33
33
  import {
34
34
  logger
35
- } from "./chunk-MRD6526D.js";
35
+ } from "./chunk-CA5PKTNJ.js";
36
36
  import {
37
37
  getShipyardHome,
38
38
  validateEnv
39
- } from "./chunk-UTL5PF43.js";
39
+ } from "./chunk-SXXAWBW7.js";
40
40
  import "./chunk-JCEWPG3R.js";
41
41
  import "./chunk-2H7UOFLK.js";
42
42
 
@@ -47,7 +47,7 @@ import { join as join2 } from "path";
47
47
 
48
48
  // src/shared/daemon-heap-limit.ts
49
49
  var MIN_MB = 2048;
50
- var MAX_DEFAULT_MB = 4096;
50
+ var MAX_DEFAULT_MB = 8192;
51
51
  var FRACTION = 0.25;
52
52
  var MAX_OVERRIDE_MB = 65536;
53
53
  function resolveDaemonHeapLimitMb(totalMemBytes, overrideMb) {
@@ -515,7 +515,7 @@ async function runDaemonChild() {
515
515
  env.SHIPYARD_USER_ID = authResult.userId;
516
516
  env.SHIPYARD_USER_DISPLAY_NAME = authResult.displayName;
517
517
  env.SHIPYARD_SIGNALING_URL = authResult.signalingUrl;
518
- const { serve } = await import("./serve-5D77VQ6J.js");
518
+ const { serve } = await import("./serve-J3MG3WHK.js");
519
519
  return serve({ isDev: env.SHIPYARD_DEV, autoOpenBrowser: !authResult.deviceFlowRan });
520
520
  }
521
521
  async function runSupervisor() {
@@ -606,4 +606,4 @@ async function createSupervisorMetrics(env) {
606
606
  export {
607
607
  startCommand
608
608
  };
609
- //# sourceMappingURL=start-VQSOEMXG.js.map
609
+ //# sourceMappingURL=start-TCI35UML.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/shared/commands/start.ts","../src/shared/daemon-heap-limit.ts","../src/shared/commands/start-supervisor.ts","../src/shared/commands/supervisor-process-guards.ts"],"sourcesContent":["import { fork as childProcessFork } from 'node:child_process';\nimport { totalmem } from 'node:os';\nimport { join } from 'node:path';\nimport { loadAuthToken } from '../../services/bootstrap/auth.js';\nimport { createMetricsCollector } from '../../services/metrics/metrics-collector.js';\nimport { resolveDaemonHeapLimitMb } from '../daemon-heap-limit.js';\nimport { type Env, getShipyardHome, validateEnv } from '../env.js';\nimport { logger } from '../logger.js';\nimport { ensureAuthenticated, getSignalingUrl } from './login.js';\nimport { print } from './output.js';\nimport { runStartSupervisor } from './start-supervisor.js';\nimport {\n installSupervisorProcessGuards,\n type SupervisorProcessGuardEvent,\n serializeSupervisorProcessError,\n} from './supervisor-process-guards.js';\n\n/**\n * `shipyard start` -- the primary entry point for running the daemon.\n *\n * Two-layer process model (Commit 3 of the watcher-worker subprocess\n * rollout): the parent CLI process forks itself and supervises a daemon\n * child. The branch is gated on `SHIPYARD_DAEMON_CHILD=1` in the env so the\n * forked child re-enters this same function and runs the existing\n * `serve()` path verbatim. The parent monitors the child's exit and\n * respawns on abnormal exits (SIGABRT/SIGSEGV/SIGBUS/SIGKILL or non-zero\n * exit code), backed by `decideAction`'s pure backoff/circuit core\n * (third use site after `file-watcher-guard.ts`'s per-path circuit and\n * the watcher-worker supervisor's restart circuit).\n */\nexport async function startCommand(): Promise<void> {\n const env = validateEnv();\n if (env.SHIPYARD_DAEMON_CHILD) {\n return runDaemonChild();\n }\n return runSupervisor();\n}\n\nasync function runDaemonChild(): Promise<void> {\n const env = validateEnv();\n const signalingUrl = getSignalingUrl();\n\n const codeIdx = process.argv.indexOf('--code');\n const webCode = codeIdx !== -1 ? process.argv[codeIdx + 1] : undefined;\n\n print('Starting Shipyard daemon...\\n');\n\n const authResult = await ensureAuthenticated({ signalingUrl, webCode });\n\n env.SHIPYARD_USER_TOKEN = authResult.token;\n env.SHIPYARD_USER_ID = authResult.userId;\n env.SHIPYARD_USER_DISPLAY_NAME = authResult.displayName;\n env.SHIPYARD_SIGNALING_URL = authResult.signalingUrl;\n\n const { serve } = await import('../../services/serve.js');\n return serve({ isDev: env.SHIPYARD_DEV, autoOpenBrowser: !authResult.deviceFlowRan });\n}\n\nasync function runSupervisor(): Promise<void> {\n installSupervisorGuardsOnce();\n\n /**\n * Re-fork the same entrypoint that started us. `process.argv[1]` is the\n * Node script (or bundled binary) currently executing; the forked child\n * picks up `SHIPYARD_DAEMON_CHILD=1` and takes the `runDaemonChild()`\n * branch above.\n */\n const childModulePath = process.argv[1];\n if (!childModulePath) {\n throw new Error('shipyard start: cannot determine childModulePath from process.argv');\n }\n\n /**\n * Build the supervisor's own metrics collector. The daemon child constructs\n * a separate one in `serve.ts` once it's authenticated. We use the existing\n * cached auth token here without running the device flow — if the user has\n * never logged in, metrics is just `undefined` (the supervisor still runs).\n * This keeps option (a) of Commit 4's spec: supervisor parent gets its own\n * collector at startup, daemon child gets its own as today.\n */\n const env = validateEnv();\n const metrics = await createSupervisorMetrics(env);\n\n const heapLimitMb = resolveDaemonHeapLimitMb(totalmem(), env.SHIPYARD_DAEMON_MAX_OLD_SPACE_MB);\n const source = env.SHIPYARD_DAEMON_MAX_OLD_SPACE_MB !== undefined ? 'env' : 'auto';\n logger.info(\n { component: 'supervisor', event: 'daemon_heap_limit_resolved', limitMb: heapLimitMb, source },\n `supervisor: daemon_heap_limit_resolved`\n );\n\n /**\n * Read the wedge timeout from the validated env so the supervisor reuses\n * the same Zod-typed default as the daemon child. The daemon child runs in\n * a separate process and revalidates env itself; the only shared contract\n * is the env var name.\n */\n const { done } = runStartSupervisor({\n fork: childProcessFork,\n childModulePath,\n childArgs: process.argv.slice(2),\n /**\n * Route supervisor events (daemon_wedge_detected, daemon_supervisor_*,\n * etc.) through the same pino logger the daemon child uses so they land\n * in `~/.shipyard/logs/daemon.log` instead of going to stderr-only.\n * Stderr is preserved (pino's `pino/file destination:1` target writes to\n * it in production) so terminal output is unchanged. Before this, the\n * wedge / sigkill / respawn events were invisible in the log file —\n * confirmed via grep showing 0 matches across all rotation files.\n */\n log: (entry) =>\n logger.info({ component: 'supervisor', ...entry }, `supervisor: ${entry.event}`),\n metrics,\n now: () => Date.now(),\n setTimeout: (fn, ms) => setTimeout(fn, ms),\n clearTimeout: (timer) => {\n if (timer === null || timer === undefined) return;\n clearTimeout(timer as never);\n },\n onSignal: (sig, handler) => {\n process.on(sig, handler);\n },\n wedgeTimeoutMs: env.SHIPYARD_WEDGE_TIMEOUT_MS,\n dataDir: join(getShipyardHome(), env.SHIPYARD_DEV ? 'data-dev' : 'data'),\n captureCrashEvidence: env.SHIPYARD_CRASH_EVIDENCE,\n execArgvExtra: [`--max-old-space-size=${heapLimitMb}`],\n });\n\n const result = await done;\n /** Flush any pending metrics events before the supervisor exits. */\n metrics?.dispose();\n /**\n * Propagate the daemon child's exit code (or `1` for circuit-open) to\n * shell/CI. Exiting here also stops any non-trivial Node teardown that\n * the supervisor's signal handlers might otherwise block.\n */\n process.exit(result.exitCode);\n}\n\nlet supervisorGuardsInstalled = false;\n\nfunction installSupervisorGuardsOnce(): void {\n if (supervisorGuardsInstalled) return;\n supervisorGuardsInstalled = true;\n\n installSupervisorProcessGuards({\n log: logSupervisorProcessGuard,\n onUncaughtException: (handler) => {\n process.on('uncaughtException', handler);\n },\n onUnhandledRejection: (handler) => {\n process.on('unhandledRejection', handler);\n },\n });\n}\n\nfunction logSupervisorProcessGuard(entry: SupervisorProcessGuardEvent): void {\n logger.error({ component: 'supervisor', ...entry }, `supervisor: ${entry.event}`);\n}\n\nasync function createSupervisorMetrics(env: Env) {\n try {\n const auth = await loadAuthToken();\n return auth.status === 'ok'\n ? createMetricsCollector(\n env.SHIPYARD_METRICS_WORKER_URL,\n auth.token,\n env.SHIPYARD_TELEMETRY,\n (entry) => logger.warn(entry, entry.event)\n )\n : undefined;\n } catch (err) {\n logger.error(\n {\n component: 'supervisor',\n event: 'supervisor_metrics_setup_failed',\n err: serializeSupervisorProcessError(err),\n },\n 'supervisor: supervisor_metrics_setup_failed'\n );\n return undefined;\n }\n}\n","/**\n * Resolve a safe --max-old-space-size limit for the DAEMON PROCESS itself\n * (not the agent child subprocesses, which are handled by subprocess-memory.ts).\n *\n * Why this exists: the daemon orchestrates 40-60 concurrent tasks and runs at\n * the Electron utility-process default heap ceiling (~1.1 GB). When the live\n * heap set approaches that ceiling V8 triggers frequent major GCs, each\n * pausing the event loop for 2-5 s. Agent CHILD subprocesses already receive\n * an explicit 6144 MB via resolveNodeOptions in subprocess-memory.ts; the\n * daemon process itself got nothing until this helper was added.\n *\n * The automatic calculation uses 25 % of total system RAM, clamped to\n * [2048, 4096] MB — generous enough to eliminate GC thrash on 8 GB machines,\n * bounded enough to avoid starving other processes on 16 GB machines.\n */\n\n/** Minimum heap limit in MB (floor for machines with very little RAM). */\nconst MIN_MB = 2048;\n\n/**\n * Maximum automatic heap limit in MB. Raised from 4096 to 8192 after a 128 GB\n * workstation OOM-crash-looped the daemon at the old hard cap — 4 GB was too\n * tight for a machine orchestrating 40-60 concurrent tasks even though 96 GB+\n * of RAM sat idle. 8192 still leaves headroom below MAX_OVERRIDE_MB for\n * operators who need more via SHIPYARD_DAEMON_MAX_OLD_SPACE_MB or the\n * config.json `daemon.maxHeapGb` setting (apps/electron/src/main/\n * daemon-heap-limit-config.ts) — both bypass this auto-calculation cap\n * entirely and are clamped only by MAX_OVERRIDE_MB.\n */\nconst MAX_DEFAULT_MB = 8192;\n\n/** Fraction of total system RAM to use when computing the automatic limit. */\nconst FRACTION = 0.25;\n\n/**\n * Hard cap on the override value — prevents absurdly large values (e.g. a\n * typo that sets 999999 MB) from being passed to --max-old-space-size.\n */\nconst MAX_OVERRIDE_MB = 65536;\n\n/**\n * Resolve the --max-old-space-size value (in MB) for the daemon process.\n *\n * @param totalMemBytes - Total system memory in bytes (pass `os.totalmem()`).\n * @param overrideMb - Optional explicit override from env/config. If finite\n * and positive, it is honored (clamped to MAX_OVERRIDE_MB).\n */\nexport function resolveDaemonHeapLimitMb(\n totalMemBytes: number,\n overrideMb?: number | undefined\n): number {\n if (overrideMb !== undefined && Number.isFinite(overrideMb)) {\n const floored = Math.floor(overrideMb);\n if (floored >= 1) return Math.min(floored, MAX_OVERRIDE_MB);\n }\n const totalMb = Math.floor(totalMemBytes / (1024 * 1024));\n const auto = Math.floor(totalMb * FRACTION);\n return Math.max(MIN_MB, Math.min(auto, MAX_DEFAULT_MB));\n}\n","import type { ChildProcess } from 'node:child_process';\nimport { mkdirSync, writeFileSync } from 'node:fs';\nimport { join } from 'node:path';\nimport { assertNever } from '../assert-never.js';\nimport {\n buildCrashStderrFilename,\n CRASH_STDERR_DIRNAME,\n EXIT_RECORD_BASENAME,\n StderrTail,\n writeExitRecordSync,\n} from '../crash-evidence-record.js';\nimport { type AttemptState, decideAction, makeInitialAttemptState } from '../file-watcher-guard.js';\n\n/**\n * Mirrors the shape of `MetricsCapture` from\n * `apps/daemon/src/services/metrics/metrics-collector.ts`. Declared inline\n * (not imported) so the supervisor module stays in `apps/daemon/src/shared/`\n * with no upward dependency on `services/metrics/`. Production wiring in\n * `start.ts` constructs a `MetricsCollector` and passes it through.\n */\nexport interface StartSupervisorMetrics {\n capture(eventType: string, properties: Record<string, unknown>): void;\n}\n\n/**\n * Outer CLI supervisor: the parent `shipyard start` process forks itself and\n * supervises the daemon child. On abnormal exit (SIGABRT/SIGSEGV/SIGBUS/SIGKILL\n * or non-zero exit code) it applies the same backoff + circuit semantics as\n * the watcher worker supervisor (third use of `decideAction`'s pure core) and\n * respawns. On graceful exit it propagates the exit code.\n *\n * On supervisor SIGTERM/SIGINT it forwards `{cmd:'shutdown'}` over the IPC\n * channel that `child_process.fork` sets up automatically, then escalates\n * SIGTERM -> SIGKILL on the same shape as the watcher-worker supervisor.\n */\n\nexport interface StartSupervisorDeps {\n fork: typeof import('node:child_process').fork;\n /** Path to the daemon binary entrypoint (typically `process.argv[1]`). */\n childModulePath: string;\n /** Forwarded to the child verbatim (typically `process.argv.slice(2)`). */\n childArgs: string[];\n log: (entry: { event: string; [key: string]: unknown }) => void;\n /**\n * Optional metrics capture. Production wiring constructs a\n * `MetricsCollector` from `loadAuthToken()` config (the supervisor parent\n * runs before the daemon child constructs its own collector). When the\n * user has no saved auth token, the supervisor still runs — metrics is\n * just `undefined` and supervision events still surface via `log`.\n */\n metrics?: StartSupervisorMetrics;\n now: () => number;\n setTimeout: (fn: () => void, ms: number) => unknown;\n clearTimeout: (timer: unknown) => void;\n /**\n * Process signal subscription. Tests inject a stub so SIGTERM/SIGINT can be\n * driven without touching the real `process` global.\n */\n onSignal: (signal: NodeJS.Signals, handler: () => void) => void;\n /**\n * Wedge detection: declare the child wedged if no IPC heartbeat arrives\n * for this long. Default 30_000 (matches `SHIPYARD_WEDGE_TIMEOUT_MS`'s\n * Zod default). Pass 0 to disable wedge detection entirely (useful for\n * tests that don't exercise wedge semantics).\n */\n wedgeTimeoutMs?: number;\n /**\n * Data directory for native-crash evidence. On an abnormal child exit the\n * supervisor writes `.daemon-last-exit` (the exit signal/code the dying\n * child could not record itself) and `crash-stderr/*.log` (a bounded stderr\n * tail) here, for the next boot to fold into `daemon_catastrophic_restart`.\n */\n dataDir: string;\n /**\n * Master switch (SHIPYARD_CRASH_EVIDENCE). When false the supervisor keeps\n * the legacy `stdio: 'inherit'` and writes no evidence — a clean kill-switch\n * for the one behavior change to this critical path (piping the child's\n * stderr to tee + buffer it).\n */\n captureCrashEvidence: boolean;\n /**\n * Extra V8 flags to pass to the daemon child via `execArgv`. Production\n * wiring injects `--max-old-space-size=<N>` computed by\n * `resolveDaemonHeapLimitMb`. Tests pass `[]`. Required (not optional) so\n * callers cannot silently omit the heap flag.\n */\n execArgvExtra: string[];\n}\n\nexport type StartSupervisorReason = 'graceful' | 'circuit_open';\n\nexport interface StartSupervisorResult {\n /**\n * Resolves when the child exits cleanly OR the circuit opens. Callers can\n * await this from the entrypoint to keep the supervisor process alive\n * until the supervised daemon settles.\n */\n done: Promise<{ exitCode: number; reason: StartSupervisorReason }>;\n}\n\n/** Empirically: SIGSEGV -> 139, SIGBUS -> 138, SIGABRT -> 134 on POSIX. */\nconst ABNORMAL_SIGNALS = new Set<NodeJS.Signals>(['SIGABRT', 'SIGSEGV', 'SIGBUS', 'SIGKILL']);\n\nconst SHUTDOWN_GRACEFUL_MS = 5_000;\nconst SHUTDOWN_SIGTERM_MS = 2_000;\nconst DEFAULT_WEDGE_TIMEOUT_MS = 30_000;\n/**\n * Grace window between SIGUSR2 (capture profile) and SIGKILL (force exit).\n * The child's SIGUSR2 handler does a best-effort 500ms CPU profile capture;\n * 2s leaves enough headroom for the inspector to dump-and-flush, while\n * keeping the wedged daemon from blocking the user any longer than needed.\n */\nconst WEDGE_SIGUSR2_GRACE_MS = 2_000;\n/**\n * How often the supervisor checks for wedge. Frequent enough to catch within\n * ~1 check interval after the timeout expires, infrequent enough that the\n * check itself isn't a measurable cost. The supervisor's loop has almost no\n * work to do — this is the only periodic timer in the parent process.\n */\nconst WEDGE_CHECK_INTERVAL_MS = 5_000;\n\ninterface HeartbeatPayload {\n type: 'heartbeat';\n tick: number;\n eventLoopLagMs: number;\n}\n\n/**\n * Strip any inherited `--max-old-space-size` from a parent execArgv list,\n * including the space-separated `--max-old-space-size 8192` form where the\n * value is its own token. Removing only the flag string would leave a bare\n * `8192` in execArgv, which the forked node would misparse as a script path.\n * The daemon's own resolved flag is appended by the caller afterwards.\n */\nfunction withoutInheritedHeapFlag(argv: readonly string[]): string[] {\n const out: string[] = [];\n for (let i = 0; i < argv.length; i += 1) {\n const arg = argv[i];\n if (arg === undefined) continue;\n if (arg.startsWith('--max-old-space-size')) {\n const nextIsBareValue = !arg.includes('=') && /^\\d+$/.test(argv[i + 1] ?? '');\n if (nextIsBareValue) i += 1;\n continue;\n }\n out.push(arg);\n }\n return out;\n}\n\nfunction isHeartbeatPayload(msg: unknown): msg is HeartbeatPayload {\n if (msg === null || typeof msg !== 'object') return false;\n if (Reflect.get(msg, 'type') !== 'heartbeat') return false;\n const tick = Reflect.get(msg, 'tick');\n const lag = Reflect.get(msg, 'eventLoopLagMs');\n return typeof tick === 'number' && typeof lag === 'number';\n}\n\ninterface ChildHolder {\n process: ChildProcess;\n spawnedAt: number;\n exited: boolean;\n lastHeartbeatAt: number;\n lastHeartbeatLagMs: number;\n /** null = no wedge currently in flight. Set when SIGUSR2 was sent. */\n wedgeGraceStartedAt: number | null;\n /** Bounded tail of the child's stderr (B). null when crash capture is off. */\n stderrTail: StderrTail | null;\n}\n\nexport function runStartSupervisor(deps: StartSupervisorDeps): StartSupervisorResult {\n let child: ChildHolder | null = null;\n let restartState: AttemptState = makeInitialAttemptState();\n let restartTimer: unknown = null;\n let circuitLogged = false;\n let shutdownInitiated = false;\n let wedgeCheckTimer: unknown = null;\n\n const wedgeTimeoutMs = deps.wedgeTimeoutMs ?? DEFAULT_WEDGE_TIMEOUT_MS;\n const wedgeEnabled = wedgeTimeoutMs > 0;\n\n let resolveDone: (value: { exitCode: number; reason: StartSupervisorReason }) => void = () => {};\n const done = new Promise<{ exitCode: number; reason: StartSupervisorReason }>((resolve) => {\n resolveDone = resolve;\n });\n\n function captureMetric(eventType: string, properties: Record<string, unknown>): void {\n deps.metrics?.capture(eventType, properties);\n }\n\n function spawnChild(opts: { isRespawn: boolean }): void {\n const proc = deps.fork(deps.childModulePath, deps.childArgs, {\n env: { ...process.env, SHIPYARD_DAEMON_CHILD: '1' },\n /**\n * Drop any inherited --max-old-space-size from the parent's execArgv\n * before appending ours: Node honors the LAST occurrence, so leaving the\n * parent's flag in place would let it silently override the value we\n * resolved (env override + RAM scaling) when the supervisor itself was\n * launched with a heap flag. Other parent flags (--inspect, etc.) pass through.\n */\n execArgv: [...withoutInheritedHeapFlag(process.execArgv ?? []), ...deps.execArgvExtra],\n /**\n * Pipe stderr (keeping stdin/stdout inherited and the fork IPC channel)\n * only when capturing crash evidence, so we can tee + buffer the child's\n * stderr. `'ipc'` is listed explicitly because a custom stdio array\n * suppresses fork's automatic IPC channel, which the heartbeat + shutdown\n * messages require.\n */\n stdio: deps.captureCrashEvidence ? ['inherit', 'inherit', 'pipe', 'ipc'] : 'inherit',\n });\n const now = deps.now();\n const holder: ChildHolder = {\n process: proc,\n spawnedAt: now,\n exited: false,\n /**\n * Seed lastHeartbeatAt = spawnedAt so the wedge check has a sensible\n * baseline. The first real heartbeat overwrites this; until then, the\n * wedge timeout effectively gives the child wedgeTimeoutMs to come\n * alive and emit its first heartbeat (plus eventual SDK / capability\n * detect work). That's intentional — the alternative (subtract some\n * \"boot grace\" constant) is more code for no extra signal.\n */\n lastHeartbeatAt: now,\n lastHeartbeatLagMs: 0,\n wedgeGraceStartedAt: null,\n stderrTail: null,\n };\n child = holder;\n deps.log({\n event: 'daemon_supervisor_started',\n pid: proc.pid ?? null,\n deathCount: restartState.failureCount,\n });\n\n if (deps.captureCrashEvidence && proc.stderr) {\n const tail = new StderrTail();\n holder.stderrTail = tail;\n proc.stderr.on('data', (chunk: Buffer) => {\n tail.push(chunk);\n /** Tee back to our own stderr so inherited terminal/log output is unchanged. */\n process.stderr.write(chunk);\n });\n }\n\n if (opts.isRespawn) {\n emitRespawn(proc.pid ?? null);\n }\n\n proc.on('exit', (code, signal) => {\n handleChildExit(holder, code, signal);\n });\n proc.on('error', (err) => {\n deps.log({\n event: 'daemon_supervisor_child_error',\n err: err instanceof Error ? err.message : String(err),\n });\n });\n proc.on('message', (msg) => {\n /**\n * Drop stale messages from previous children. `proc.on('message')` is\n * attached to this `proc`, but the holder may have been retired (e.g.\n * concurrent kill + respawn race) before the message lands; ignore\n * anything that no longer belongs to the live `child`.\n */\n if (child !== holder) return;\n if (!isHeartbeatPayload(msg)) return;\n holder.lastHeartbeatAt = deps.now();\n holder.lastHeartbeatLagMs = msg.eventLoopLagMs;\n /**\n * If a wedge was just declared but the child recovered before the\n * SIGKILL window closed, clear the grace state so we don't kill a\n * now-healthy child. The grace window is only 2s; in practice this is\n * rare but cheap to be defensive about.\n */\n holder.wedgeGraceStartedAt = null;\n });\n }\n\n function handleChildExit(\n holder: ChildHolder,\n code: number | null,\n signal: NodeJS.Signals | null\n ): void {\n holder.exited = true;\n /** Drop stale exits — only the live child drives state. */\n if (child !== holder) return;\n child = null;\n\n const uptimeMs = deps.now() - holder.spawnedAt;\n\n if (shutdownInitiated) {\n deps.log({ event: 'daemon_supervisor_child_exited_during_shutdown', code, signal, uptimeMs });\n resolveDone({ exitCode: code ?? 0, reason: 'graceful' });\n return;\n }\n\n if (!isAbnormalExit(code, signal)) {\n deps.log({ event: 'daemon_supervisor_child_exited_clean', code, signal, uptimeMs });\n resolveDone({ exitCode: code ?? 0, reason: 'graceful' });\n return;\n }\n\n handleAbnormalChildExit(holder, code, signal, uptimeMs);\n }\n\n function handleAbnormalChildExit(\n holder: ChildHolder,\n code: number | null,\n signal: NodeJS.Signals | null,\n uptimeMs: number\n ): void {\n deps.log({ event: 'daemon_supervisor_child_died', code, signal, uptimeMs });\n flushCrashEvidence(holder, code, signal, uptimeMs);\n\n /**\n * Reuse the guard's pure restart core: 'subscribe_failure' drives the\n * same backoff + circuit logic per-process. Different state instance,\n * same primitive (third use site after guard's per-path circuit and the\n * watcher-worker supervisor's restart circuit).\n */\n const failureDecision = decideAction(restartState, { kind: 'subscribe_failure' }, deps.now());\n restartState = failureDecision.state;\n emitFailureSignals(failureDecision.signals, holder);\n\n if (restartState.circuitOpenedAt !== null) {\n /**\n * Per the spec for this layer: rather than half-open probe like the\n * watcher worker (which lives inside the daemon), the CLI supervisor\n * surfaces the failure to the user so they can investigate. The\n * supervisor terminates rather than continuing to thrash.\n */\n resolveDone({ exitCode: 1, reason: 'circuit_open' });\n return;\n }\n\n scheduleRespawn();\n }\n\n /**\n * Persist the native-crash evidence the dying child could not record itself\n * (no JS handler fires on a native abort). `.daemon-last-exit` carries the\n * exit signal/code; `crash-stderr/*.log` carries the buffered stderr tail.\n * Both are best-effort — a failed write logs but never blocks respawn.\n */\n function flushCrashEvidence(\n holder: ChildHolder,\n code: number | null,\n signal: NodeJS.Signals | null,\n uptimeMs: number\n ): void {\n if (!deps.captureCrashEvidence) return;\n const now = deps.now();\n const pid = holder.process.pid ?? null;\n if (pid === null || pid <= 0) {\n /** No usable pid (fork failed before exec): a record would fail the next-boot pid gate. */\n deps.log({ event: 'crash_evidence_skipped_no_pid', code, signal });\n return;\n }\n try {\n writeExitRecordSync(join(deps.dataDir, EXIT_RECORD_BASENAME), {\n pid,\n exitedAt: now,\n code,\n signal,\n uptimeMs,\n source: 'cli',\n });\n } catch (err: unknown) {\n deps.log({\n event: 'exit_record_write_failed',\n err: err instanceof Error ? err.message : String(err),\n });\n }\n flushStderrTail(holder, pid, now);\n }\n\n function flushStderrTail(holder: ChildHolder, pid: number, now: number): void {\n const tail = holder.stderrTail;\n if (!tail || tail.isEmpty) return;\n try {\n const dir = join(deps.dataDir, CRASH_STDERR_DIRNAME);\n mkdirSync(dir, { recursive: true });\n const filename = buildCrashStderrFilename(pid, new Date(now).toISOString());\n writeFileSync(join(dir, filename), tail.snapshot(), 'utf-8');\n } catch (err: unknown) {\n deps.log({\n event: 'crash_stderr_write_failed',\n err: err instanceof Error ? err.message : String(err),\n });\n }\n }\n\n function emitFailureSignals(\n signals: ReturnType<typeof decideAction>['signals'],\n holder: ChildHolder\n ): void {\n for (const sig of signals) {\n if (sig.kind === 'circuit_opened' && !circuitLogged) {\n circuitLogged = true;\n const windowMs = deps.now() - holder.spawnedAt;\n deps.log({\n event: 'daemon_supervisor_circuit_open',\n deathCount: restartState.failureCount,\n windowMs,\n });\n captureMetric('daemon_supervisor_circuit_open', {\n deathCount: restartState.failureCount,\n windowMs,\n });\n }\n }\n }\n\n function scheduleRespawn(): void {\n if (shutdownInitiated) return;\n if (restartState.circuitOpenedAt !== null) return;\n\n const requestDecision = decideAction(\n restartState,\n { kind: 'request_subscribe', reason: 'rescan', activeCount: 0 },\n deps.now()\n );\n restartState = requestDecision.state;\n deps.log({\n event: 'daemon_supervisor_respawn_scheduled',\n deathCount: restartState.failureCount,\n });\n\n switch (requestDecision.action.kind) {\n case 'wait': {\n restartTimer = deps.setTimeout(() => {\n restartTimer = null;\n if (shutdownInitiated) return;\n spawnChild({ isRespawn: true });\n }, requestDecision.action.ms);\n return;\n }\n case 'subscribe':\n case 'evict_and_subscribe':\n /**\n * `evict_and_subscribe` only fires when activeCount >= MAX_ACTIVE_WATCHERS;\n * we always pass activeCount: 0 so the pure core never returns it here.\n * Treating both as \"respawn now\" keeps the switch exhaustive without\n * coupling this layer to guard-internals.\n */\n spawnChild({ isRespawn: true });\n return;\n case 'reject_stub':\n /** Circuit-open path is handled by the caller before scheduleRespawn. */\n return;\n case 'noop':\n /** decideRequest never returns 'noop'. */\n return;\n default:\n assertNever(requestDecision.action);\n }\n }\n\n /**\n * Emit the `daemon_supervisor_respawned` log + metric. The metric carries\n * `newPid` (post-fork) plus `deathCount`. Called inline in `spawnChild` for\n * respawns; the initial spawn does not emit this event.\n */\n function emitRespawn(newPid: number | null): void {\n deps.log({ event: 'daemon_supervisor_respawned', deathCount: restartState.failureCount });\n captureMetric('daemon_supervisor_respawned', {\n newPid,\n deathCount: restartState.failureCount,\n });\n }\n\n function forwardShutdown(): void {\n if (shutdownInitiated) return;\n shutdownInitiated = true;\n\n if (restartTimer !== null) {\n deps.clearTimeout(restartTimer);\n restartTimer = null;\n }\n if (wedgeCheckTimer !== null) {\n deps.clearTimeout(wedgeCheckTimer);\n wedgeCheckTimer = null;\n }\n\n const holder = child;\n if (!holder) {\n /**\n * Either we never spawned, the previous child already exited, or the\n * circuit opened. Resolve with code 0 so the supervisor process exits.\n */\n deps.log({ event: 'daemon_supervisor_shutdown_no_child' });\n resolveDone({ exitCode: 0, reason: 'graceful' });\n return;\n }\n\n deps.log({ event: 'daemon_supervisor_shutdown_requested' });\n\n /**\n * Cooperative shutdown via the IPC channel that `fork()` sets up. The\n * child should listen for `process.on('message', ...)` and tear down\n * gracefully on `{cmd:'shutdown'}`.\n */\n try {\n holder.process.send?.({ cmd: 'shutdown' });\n } catch (err) {\n deps.log({\n event: 'daemon_supervisor_shutdown_send_failed',\n err: err instanceof Error ? err.message : String(err),\n });\n }\n\n /** SIGTERM after grace, SIGKILL after that. */\n deps.setTimeout(() => onSigtermDeadline(holder), SHUTDOWN_GRACEFUL_MS);\n }\n\n function onSigtermDeadline(holder: ChildHolder): void {\n if (holder.exited) return;\n deps.log({ event: 'daemon_supervisor_shutdown_sigterm' });\n try {\n holder.process.kill('SIGTERM');\n } catch (err) {\n deps.log({\n event: 'daemon_supervisor_kill_failed',\n signal: 'SIGTERM',\n err: err instanceof Error ? err.message : String(err),\n });\n }\n deps.setTimeout(() => onSigkillDeadline(holder), SHUTDOWN_SIGTERM_MS);\n }\n\n function onSigkillDeadline(holder: ChildHolder): void {\n if (holder.exited) return;\n deps.log({ event: 'daemon_supervisor_shutdown_sigkill' });\n try {\n holder.process.kill('SIGKILL');\n } catch (err) {\n deps.log({\n event: 'daemon_supervisor_kill_failed',\n signal: 'SIGKILL',\n err: err instanceof Error ? err.message : String(err),\n });\n /**\n * Safety net: SIGKILL throwing AND on-exit not firing is a paranoid\n * combination (zombie process, EPERM on a child we own), but if it\n * happens the `done` promise hangs forever and so does whoever\n * awaits it. Resolve here so the supervisor parent can exit.\n */\n resolveDone({ exitCode: 1, reason: 'graceful' });\n }\n }\n\n /**\n * Wedge detection loop. Runs in the SUPERVISOR PROCESS, which has almost\n * no work to do — it's a separate Node process from the daemon, so its\n * event loop is not subject to whatever's blocking the daemon child's.\n *\n * The check is a recurring `setTimeout` (not `setInterval`) so we only\n * need one timer-shape dep and so the test harness can drive it via\n * `advanceBy`. The chain self-cancels when `shutdownInitiated` flips true\n * or the function returns without rescheduling.\n */\n function scheduleWedgeCheck(): void {\n if (!wedgeEnabled) return;\n if (shutdownInitiated) return;\n wedgeCheckTimer = deps.setTimeout(() => {\n wedgeCheckTimer = null;\n runWedgeCheck();\n scheduleWedgeCheck();\n }, WEDGE_CHECK_INTERVAL_MS);\n }\n\n function runWedgeCheck(): void {\n if (shutdownInitiated) return;\n const holder = child;\n if (!holder || holder.exited) return;\n\n const now = deps.now();\n if (holder.wedgeGraceStartedAt !== null) {\n maybeFinishWedgeGrace(holder, now);\n return;\n }\n const silentMs = now - holder.lastHeartbeatAt;\n if (silentMs <= wedgeTimeoutMs) return;\n declareWedge(holder, now, silentMs);\n }\n\n /**\n * SIGUSR2 already sent; if the grace window has elapsed without a fresh\n * heartbeat clearing `wedgeGraceStartedAt`, escalate to SIGKILL. The OS\n * kill triggers Node's `exit` event with `signal: 'SIGKILL'`, which goes\n * through `handleChildExit` -> `handleAbnormalChildExit` -> the existing\n * `decideAction` respawn flow. Nothing else to do here.\n */\n function maybeFinishWedgeGrace(holder: ChildHolder, now: number): void {\n const graceStart = holder.wedgeGraceStartedAt;\n if (graceStart === null) return;\n const graceElapsed = now - graceStart;\n if (graceElapsed < WEDGE_SIGUSR2_GRACE_MS) return;\n\n deps.log({\n event: 'daemon_wedge_sigkill',\n pid: holder.process.pid ?? null,\n graceElapsedMs: graceElapsed,\n });\n captureMetric('daemon_wedge_sigkill', {\n pid: holder.process.pid ?? null,\n graceElapsedMs: graceElapsed,\n });\n safeKill(holder, 'SIGKILL');\n }\n\n /**\n * First wedge detection for this child. Log + send SIGUSR2 (to give the\n * daemon a chance to dump a CPU profile via the off-thread inspector)\n * and start the grace window.\n */\n function declareWedge(holder: ChildHolder, now: number, silentMs: number): void {\n deps.log({\n event: 'daemon_wedge_detected',\n pid: holder.process.pid ?? null,\n lastHeartbeatAt: holder.lastHeartbeatAt,\n silentMs,\n lastKnownLagMs: holder.lastHeartbeatLagMs,\n wedgeTimeoutMs,\n });\n captureMetric('daemon_wedge_detected', {\n pid: holder.process.pid ?? null,\n silentMs,\n lastKnownLagMs: holder.lastHeartbeatLagMs,\n });\n\n holder.wedgeGraceStartedAt = now;\n safeKill(holder, 'SIGUSR2');\n }\n\n function safeKill(holder: ChildHolder, signal: NodeJS.Signals): void {\n try {\n holder.process.kill(signal);\n } catch (err) {\n deps.log({\n event: 'daemon_supervisor_kill_failed',\n signal,\n err: err instanceof Error ? err.message : String(err),\n });\n }\n }\n\n /** Wire signal forwarding via injected hook so tests can drive deterministically. */\n deps.onSignal('SIGTERM', forwardShutdown);\n deps.onSignal('SIGINT', forwardShutdown);\n\n /** Spawn the initial child immediately. */\n spawnChild({ isRespawn: false });\n scheduleWedgeCheck();\n\n return { done };\n}\n\nfunction isAbnormalExit(code: number | null, signal: NodeJS.Signals | null): boolean {\n if (signal !== null && ABNORMAL_SIGNALS.has(signal)) return true;\n if (code !== null && code !== 0) return true;\n return false;\n}\n","export type SupervisorProcessGuardEvent =\n | {\n event: 'supervisor_uncaught_exception';\n err: SerializedSupervisorProcessError;\n origin: string;\n }\n | {\n event: 'supervisor_unhandled_rejection';\n reason: SerializedSupervisorProcessError;\n };\n\nexport interface SerializedSupervisorProcessError {\n kind: 'error' | 'non_error';\n name: string;\n message: string;\n stack?: string;\n cause?: SerializedSupervisorProcessError;\n}\n\nexport interface SupervisorProcessGuardDeps {\n log: (entry: SupervisorProcessGuardEvent) => void;\n onUncaughtException: (\n handler: (err: Error, origin: NodeJS.UncaughtExceptionOrigin) => void\n ) => void;\n onUnhandledRejection: (handler: (reason: unknown, promise: Promise<unknown>) => void) => void;\n}\n\nexport function installSupervisorProcessGuards(deps: SupervisorProcessGuardDeps): void {\n deps.onUncaughtException((err, origin) => {\n deps.log({\n event: 'supervisor_uncaught_exception',\n err: serializeSupervisorProcessError(err),\n origin,\n });\n });\n\n deps.onUnhandledRejection((reason) => {\n deps.log({\n event: 'supervisor_unhandled_rejection',\n reason: serializeSupervisorProcessError(reason),\n });\n });\n}\n\nexport function serializeSupervisorProcessError(\n value: unknown,\n depth = 0\n): SerializedSupervisorProcessError {\n if (depth >= 3) {\n return {\n kind: 'non_error',\n name: typeof value,\n message: '[Max serialization depth reached]',\n };\n }\n\n if (value instanceof Error) {\n const serialized: SerializedSupervisorProcessError = {\n kind: 'error',\n name: value.name || 'Error',\n message: value.message,\n };\n if (value.stack) {\n serialized.stack = value.stack;\n }\n const cause = value.cause;\n if (cause !== undefined) {\n serialized.cause = serializeSupervisorProcessError(cause, depth + 1);\n }\n return serialized;\n }\n\n return {\n kind: 'non_error',\n name: typeof value,\n message: stringifyUnknown(value),\n };\n}\n\nfunction stringifyUnknown(value: unknown): string {\n if (typeof value === 'string') return value;\n\n try {\n const json = JSON.stringify(value);\n if (json !== undefined) return json;\n } catch {\n return String(value);\n }\n\n return String(value);\n}\n"],"mappings":"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","names":["join","join"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@schoolai/shipyard",
3
- "version": "3.22.0",
3
+ "version": "3.23.0",
4
4
  "description": "Shipyard daemon - Claude Agent SDK + Loro CRDT sync",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/shared/commands/start.ts","../src/shared/daemon-heap-limit.ts","../src/shared/commands/start-supervisor.ts","../src/shared/commands/supervisor-process-guards.ts"],"sourcesContent":["import { fork as childProcessFork } from 'node:child_process';\nimport { totalmem } from 'node:os';\nimport { join } from 'node:path';\nimport { loadAuthToken } from '../../services/bootstrap/auth.js';\nimport { createMetricsCollector } from '../../services/metrics/metrics-collector.js';\nimport { resolveDaemonHeapLimitMb } from '../daemon-heap-limit.js';\nimport { type Env, getShipyardHome, validateEnv } from '../env.js';\nimport { logger } from '../logger.js';\nimport { ensureAuthenticated, getSignalingUrl } from './login.js';\nimport { print } from './output.js';\nimport { runStartSupervisor } from './start-supervisor.js';\nimport {\n installSupervisorProcessGuards,\n type SupervisorProcessGuardEvent,\n serializeSupervisorProcessError,\n} from './supervisor-process-guards.js';\n\n/**\n * `shipyard start` -- the primary entry point for running the daemon.\n *\n * Two-layer process model (Commit 3 of the watcher-worker subprocess\n * rollout): the parent CLI process forks itself and supervises a daemon\n * child. The branch is gated on `SHIPYARD_DAEMON_CHILD=1` in the env so the\n * forked child re-enters this same function and runs the existing\n * `serve()` path verbatim. The parent monitors the child's exit and\n * respawns on abnormal exits (SIGABRT/SIGSEGV/SIGBUS/SIGKILL or non-zero\n * exit code), backed by `decideAction`'s pure backoff/circuit core\n * (third use site after `file-watcher-guard.ts`'s per-path circuit and\n * the watcher-worker supervisor's restart circuit).\n */\nexport async function startCommand(): Promise<void> {\n const env = validateEnv();\n if (env.SHIPYARD_DAEMON_CHILD) {\n return runDaemonChild();\n }\n return runSupervisor();\n}\n\nasync function runDaemonChild(): Promise<void> {\n const env = validateEnv();\n const signalingUrl = getSignalingUrl();\n\n const codeIdx = process.argv.indexOf('--code');\n const webCode = codeIdx !== -1 ? process.argv[codeIdx + 1] : undefined;\n\n print('Starting Shipyard daemon...\\n');\n\n const authResult = await ensureAuthenticated({ signalingUrl, webCode });\n\n env.SHIPYARD_USER_TOKEN = authResult.token;\n env.SHIPYARD_USER_ID = authResult.userId;\n env.SHIPYARD_USER_DISPLAY_NAME = authResult.displayName;\n env.SHIPYARD_SIGNALING_URL = authResult.signalingUrl;\n\n const { serve } = await import('../../services/serve.js');\n return serve({ isDev: env.SHIPYARD_DEV, autoOpenBrowser: !authResult.deviceFlowRan });\n}\n\nasync function runSupervisor(): Promise<void> {\n installSupervisorGuardsOnce();\n\n /**\n * Re-fork the same entrypoint that started us. `process.argv[1]` is the\n * Node script (or bundled binary) currently executing; the forked child\n * picks up `SHIPYARD_DAEMON_CHILD=1` and takes the `runDaemonChild()`\n * branch above.\n */\n const childModulePath = process.argv[1];\n if (!childModulePath) {\n throw new Error('shipyard start: cannot determine childModulePath from process.argv');\n }\n\n /**\n * Build the supervisor's own metrics collector. The daemon child constructs\n * a separate one in `serve.ts` once it's authenticated. We use the existing\n * cached auth token here without running the device flow — if the user has\n * never logged in, metrics is just `undefined` (the supervisor still runs).\n * This keeps option (a) of Commit 4's spec: supervisor parent gets its own\n * collector at startup, daemon child gets its own as today.\n */\n const env = validateEnv();\n const metrics = await createSupervisorMetrics(env);\n\n const heapLimitMb = resolveDaemonHeapLimitMb(totalmem(), env.SHIPYARD_DAEMON_MAX_OLD_SPACE_MB);\n const source = env.SHIPYARD_DAEMON_MAX_OLD_SPACE_MB !== undefined ? 'env' : 'auto';\n logger.info(\n { component: 'supervisor', event: 'daemon_heap_limit_resolved', limitMb: heapLimitMb, source },\n `supervisor: daemon_heap_limit_resolved`\n );\n\n /**\n * Read the wedge timeout from the validated env so the supervisor reuses\n * the same Zod-typed default as the daemon child. The daemon child runs in\n * a separate process and revalidates env itself; the only shared contract\n * is the env var name.\n */\n const { done } = runStartSupervisor({\n fork: childProcessFork,\n childModulePath,\n childArgs: process.argv.slice(2),\n /**\n * Route supervisor events (daemon_wedge_detected, daemon_supervisor_*,\n * etc.) through the same pino logger the daemon child uses so they land\n * in `~/.shipyard/logs/daemon.log` instead of going to stderr-only.\n * Stderr is preserved (pino's `pino/file destination:1` target writes to\n * it in production) so terminal output is unchanged. Before this, the\n * wedge / sigkill / respawn events were invisible in the log file —\n * confirmed via grep showing 0 matches across all rotation files.\n */\n log: (entry) =>\n logger.info({ component: 'supervisor', ...entry }, `supervisor: ${entry.event}`),\n metrics,\n now: () => Date.now(),\n setTimeout: (fn, ms) => setTimeout(fn, ms),\n clearTimeout: (timer) => {\n if (timer === null || timer === undefined) return;\n clearTimeout(timer as never);\n },\n onSignal: (sig, handler) => {\n process.on(sig, handler);\n },\n wedgeTimeoutMs: env.SHIPYARD_WEDGE_TIMEOUT_MS,\n dataDir: join(getShipyardHome(), env.SHIPYARD_DEV ? 'data-dev' : 'data'),\n captureCrashEvidence: env.SHIPYARD_CRASH_EVIDENCE,\n execArgvExtra: [`--max-old-space-size=${heapLimitMb}`],\n });\n\n const result = await done;\n /** Flush any pending metrics events before the supervisor exits. */\n metrics?.dispose();\n /**\n * Propagate the daemon child's exit code (or `1` for circuit-open) to\n * shell/CI. Exiting here also stops any non-trivial Node teardown that\n * the supervisor's signal handlers might otherwise block.\n */\n process.exit(result.exitCode);\n}\n\nlet supervisorGuardsInstalled = false;\n\nfunction installSupervisorGuardsOnce(): void {\n if (supervisorGuardsInstalled) return;\n supervisorGuardsInstalled = true;\n\n installSupervisorProcessGuards({\n log: logSupervisorProcessGuard,\n onUncaughtException: (handler) => {\n process.on('uncaughtException', handler);\n },\n onUnhandledRejection: (handler) => {\n process.on('unhandledRejection', handler);\n },\n });\n}\n\nfunction logSupervisorProcessGuard(entry: SupervisorProcessGuardEvent): void {\n logger.error({ component: 'supervisor', ...entry }, `supervisor: ${entry.event}`);\n}\n\nasync function createSupervisorMetrics(env: Env) {\n try {\n const auth = await loadAuthToken();\n return auth.status === 'ok'\n ? createMetricsCollector(\n env.SHIPYARD_METRICS_WORKER_URL,\n auth.token,\n env.SHIPYARD_TELEMETRY,\n (entry) => logger.warn(entry, entry.event)\n )\n : undefined;\n } catch (err) {\n logger.error(\n {\n component: 'supervisor',\n event: 'supervisor_metrics_setup_failed',\n err: serializeSupervisorProcessError(err),\n },\n 'supervisor: supervisor_metrics_setup_failed'\n );\n return undefined;\n }\n}\n","/**\n * Resolve a safe --max-old-space-size limit for the DAEMON PROCESS itself\n * (not the agent child subprocesses, which are handled by subprocess-memory.ts).\n *\n * Why this exists: the daemon orchestrates 40-60 concurrent tasks and runs at\n * the Electron utility-process default heap ceiling (~1.1 GB). When the live\n * heap set approaches that ceiling V8 triggers frequent major GCs, each\n * pausing the event loop for 2-5 s. Agent CHILD subprocesses already receive\n * an explicit 6144 MB via resolveNodeOptions in subprocess-memory.ts; the\n * daemon process itself got nothing until this helper was added.\n *\n * The automatic calculation uses 25 % of total system RAM, clamped to\n * [2048, 4096] MB — generous enough to eliminate GC thrash on 8 GB machines,\n * bounded enough to avoid starving other processes on 16 GB machines.\n */\n\n/** Minimum heap limit in MB (floor for machines with very little RAM). */\nconst MIN_MB = 2048;\n\n/**\n * Maximum automatic heap limit in MB. We cap at 4096 so the daemon never\n * consumes more than 4 GB even on a 96 GB workstation — beyond that the\n * return from extra headroom is negligible and the cost (resident memory) is\n * real. An operator who wants more can set SHIPYARD_DAEMON_MAX_OLD_SPACE_MB.\n */\nconst MAX_DEFAULT_MB = 4096;\n\n/** Fraction of total system RAM to use when computing the automatic limit. */\nconst FRACTION = 0.25;\n\n/**\n * Hard cap on the override value — prevents absurdly large values (e.g. a\n * typo that sets 999999 MB) from being passed to --max-old-space-size.\n */\nconst MAX_OVERRIDE_MB = 65536;\n\n/**\n * Resolve the --max-old-space-size value (in MB) for the daemon process.\n *\n * @param totalMemBytes - Total system memory in bytes (pass `os.totalmem()`).\n * @param overrideMb - Optional explicit override from env/config. If finite\n * and positive, it is honored (clamped to MAX_OVERRIDE_MB).\n */\nexport function resolveDaemonHeapLimitMb(\n totalMemBytes: number,\n overrideMb?: number | undefined\n): number {\n if (overrideMb !== undefined && Number.isFinite(overrideMb)) {\n const floored = Math.floor(overrideMb);\n if (floored >= 1) return Math.min(floored, MAX_OVERRIDE_MB);\n }\n const totalMb = Math.floor(totalMemBytes / (1024 * 1024));\n const auto = Math.floor(totalMb * FRACTION);\n return Math.max(MIN_MB, Math.min(auto, MAX_DEFAULT_MB));\n}\n","import type { ChildProcess } from 'node:child_process';\nimport { mkdirSync, writeFileSync } from 'node:fs';\nimport { join } from 'node:path';\nimport { assertNever } from '../assert-never.js';\nimport {\n buildCrashStderrFilename,\n CRASH_STDERR_DIRNAME,\n EXIT_RECORD_BASENAME,\n StderrTail,\n writeExitRecordSync,\n} from '../crash-evidence-record.js';\nimport { type AttemptState, decideAction, makeInitialAttemptState } from '../file-watcher-guard.js';\n\n/**\n * Mirrors the shape of `MetricsCapture` from\n * `apps/daemon/src/services/metrics/metrics-collector.ts`. Declared inline\n * (not imported) so the supervisor module stays in `apps/daemon/src/shared/`\n * with no upward dependency on `services/metrics/`. Production wiring in\n * `start.ts` constructs a `MetricsCollector` and passes it through.\n */\nexport interface StartSupervisorMetrics {\n capture(eventType: string, properties: Record<string, unknown>): void;\n}\n\n/**\n * Outer CLI supervisor: the parent `shipyard start` process forks itself and\n * supervises the daemon child. On abnormal exit (SIGABRT/SIGSEGV/SIGBUS/SIGKILL\n * or non-zero exit code) it applies the same backoff + circuit semantics as\n * the watcher worker supervisor (third use of `decideAction`'s pure core) and\n * respawns. On graceful exit it propagates the exit code.\n *\n * On supervisor SIGTERM/SIGINT it forwards `{cmd:'shutdown'}` over the IPC\n * channel that `child_process.fork` sets up automatically, then escalates\n * SIGTERM -> SIGKILL on the same shape as the watcher-worker supervisor.\n */\n\nexport interface StartSupervisorDeps {\n fork: typeof import('node:child_process').fork;\n /** Path to the daemon binary entrypoint (typically `process.argv[1]`). */\n childModulePath: string;\n /** Forwarded to the child verbatim (typically `process.argv.slice(2)`). */\n childArgs: string[];\n log: (entry: { event: string; [key: string]: unknown }) => void;\n /**\n * Optional metrics capture. Production wiring constructs a\n * `MetricsCollector` from `loadAuthToken()` config (the supervisor parent\n * runs before the daemon child constructs its own collector). When the\n * user has no saved auth token, the supervisor still runs — metrics is\n * just `undefined` and supervision events still surface via `log`.\n */\n metrics?: StartSupervisorMetrics;\n now: () => number;\n setTimeout: (fn: () => void, ms: number) => unknown;\n clearTimeout: (timer: unknown) => void;\n /**\n * Process signal subscription. Tests inject a stub so SIGTERM/SIGINT can be\n * driven without touching the real `process` global.\n */\n onSignal: (signal: NodeJS.Signals, handler: () => void) => void;\n /**\n * Wedge detection: declare the child wedged if no IPC heartbeat arrives\n * for this long. Default 30_000 (matches `SHIPYARD_WEDGE_TIMEOUT_MS`'s\n * Zod default). Pass 0 to disable wedge detection entirely (useful for\n * tests that don't exercise wedge semantics).\n */\n wedgeTimeoutMs?: number;\n /**\n * Data directory for native-crash evidence. On an abnormal child exit the\n * supervisor writes `.daemon-last-exit` (the exit signal/code the dying\n * child could not record itself) and `crash-stderr/*.log` (a bounded stderr\n * tail) here, for the next boot to fold into `daemon_catastrophic_restart`.\n */\n dataDir: string;\n /**\n * Master switch (SHIPYARD_CRASH_EVIDENCE). When false the supervisor keeps\n * the legacy `stdio: 'inherit'` and writes no evidence — a clean kill-switch\n * for the one behavior change to this critical path (piping the child's\n * stderr to tee + buffer it).\n */\n captureCrashEvidence: boolean;\n /**\n * Extra V8 flags to pass to the daemon child via `execArgv`. Production\n * wiring injects `--max-old-space-size=<N>` computed by\n * `resolveDaemonHeapLimitMb`. Tests pass `[]`. Required (not optional) so\n * callers cannot silently omit the heap flag.\n */\n execArgvExtra: string[];\n}\n\nexport type StartSupervisorReason = 'graceful' | 'circuit_open';\n\nexport interface StartSupervisorResult {\n /**\n * Resolves when the child exits cleanly OR the circuit opens. Callers can\n * await this from the entrypoint to keep the supervisor process alive\n * until the supervised daemon settles.\n */\n done: Promise<{ exitCode: number; reason: StartSupervisorReason }>;\n}\n\n/** Empirically: SIGSEGV -> 139, SIGBUS -> 138, SIGABRT -> 134 on POSIX. */\nconst ABNORMAL_SIGNALS = new Set<NodeJS.Signals>(['SIGABRT', 'SIGSEGV', 'SIGBUS', 'SIGKILL']);\n\nconst SHUTDOWN_GRACEFUL_MS = 5_000;\nconst SHUTDOWN_SIGTERM_MS = 2_000;\nconst DEFAULT_WEDGE_TIMEOUT_MS = 30_000;\n/**\n * Grace window between SIGUSR2 (capture profile) and SIGKILL (force exit).\n * The child's SIGUSR2 handler does a best-effort 500ms CPU profile capture;\n * 2s leaves enough headroom for the inspector to dump-and-flush, while\n * keeping the wedged daemon from blocking the user any longer than needed.\n */\nconst WEDGE_SIGUSR2_GRACE_MS = 2_000;\n/**\n * How often the supervisor checks for wedge. Frequent enough to catch within\n * ~1 check interval after the timeout expires, infrequent enough that the\n * check itself isn't a measurable cost. The supervisor's loop has almost no\n * work to do — this is the only periodic timer in the parent process.\n */\nconst WEDGE_CHECK_INTERVAL_MS = 5_000;\n\ninterface HeartbeatPayload {\n type: 'heartbeat';\n tick: number;\n eventLoopLagMs: number;\n}\n\n/**\n * Strip any inherited `--max-old-space-size` from a parent execArgv list,\n * including the space-separated `--max-old-space-size 8192` form where the\n * value is its own token. Removing only the flag string would leave a bare\n * `8192` in execArgv, which the forked node would misparse as a script path.\n * The daemon's own resolved flag is appended by the caller afterwards.\n */\nfunction withoutInheritedHeapFlag(argv: readonly string[]): string[] {\n const out: string[] = [];\n for (let i = 0; i < argv.length; i += 1) {\n const arg = argv[i];\n if (arg === undefined) continue;\n if (arg.startsWith('--max-old-space-size')) {\n const nextIsBareValue = !arg.includes('=') && /^\\d+$/.test(argv[i + 1] ?? '');\n if (nextIsBareValue) i += 1;\n continue;\n }\n out.push(arg);\n }\n return out;\n}\n\nfunction isHeartbeatPayload(msg: unknown): msg is HeartbeatPayload {\n if (msg === null || typeof msg !== 'object') return false;\n if (Reflect.get(msg, 'type') !== 'heartbeat') return false;\n const tick = Reflect.get(msg, 'tick');\n const lag = Reflect.get(msg, 'eventLoopLagMs');\n return typeof tick === 'number' && typeof lag === 'number';\n}\n\ninterface ChildHolder {\n process: ChildProcess;\n spawnedAt: number;\n exited: boolean;\n lastHeartbeatAt: number;\n lastHeartbeatLagMs: number;\n /** null = no wedge currently in flight. Set when SIGUSR2 was sent. */\n wedgeGraceStartedAt: number | null;\n /** Bounded tail of the child's stderr (B). null when crash capture is off. */\n stderrTail: StderrTail | null;\n}\n\nexport function runStartSupervisor(deps: StartSupervisorDeps): StartSupervisorResult {\n let child: ChildHolder | null = null;\n let restartState: AttemptState = makeInitialAttemptState();\n let restartTimer: unknown = null;\n let circuitLogged = false;\n let shutdownInitiated = false;\n let wedgeCheckTimer: unknown = null;\n\n const wedgeTimeoutMs = deps.wedgeTimeoutMs ?? DEFAULT_WEDGE_TIMEOUT_MS;\n const wedgeEnabled = wedgeTimeoutMs > 0;\n\n let resolveDone: (value: { exitCode: number; reason: StartSupervisorReason }) => void = () => {};\n const done = new Promise<{ exitCode: number; reason: StartSupervisorReason }>((resolve) => {\n resolveDone = resolve;\n });\n\n function captureMetric(eventType: string, properties: Record<string, unknown>): void {\n deps.metrics?.capture(eventType, properties);\n }\n\n function spawnChild(opts: { isRespawn: boolean }): void {\n const proc = deps.fork(deps.childModulePath, deps.childArgs, {\n env: { ...process.env, SHIPYARD_DAEMON_CHILD: '1' },\n /**\n * Drop any inherited --max-old-space-size from the parent's execArgv\n * before appending ours: Node honors the LAST occurrence, so leaving the\n * parent's flag in place would let it silently override the value we\n * resolved (env override + RAM scaling) when the supervisor itself was\n * launched with a heap flag. Other parent flags (--inspect, etc.) pass through.\n */\n execArgv: [...withoutInheritedHeapFlag(process.execArgv ?? []), ...deps.execArgvExtra],\n /**\n * Pipe stderr (keeping stdin/stdout inherited and the fork IPC channel)\n * only when capturing crash evidence, so we can tee + buffer the child's\n * stderr. `'ipc'` is listed explicitly because a custom stdio array\n * suppresses fork's automatic IPC channel, which the heartbeat + shutdown\n * messages require.\n */\n stdio: deps.captureCrashEvidence ? ['inherit', 'inherit', 'pipe', 'ipc'] : 'inherit',\n });\n const now = deps.now();\n const holder: ChildHolder = {\n process: proc,\n spawnedAt: now,\n exited: false,\n /**\n * Seed lastHeartbeatAt = spawnedAt so the wedge check has a sensible\n * baseline. The first real heartbeat overwrites this; until then, the\n * wedge timeout effectively gives the child wedgeTimeoutMs to come\n * alive and emit its first heartbeat (plus eventual SDK / capability\n * detect work). That's intentional — the alternative (subtract some\n * \"boot grace\" constant) is more code for no extra signal.\n */\n lastHeartbeatAt: now,\n lastHeartbeatLagMs: 0,\n wedgeGraceStartedAt: null,\n stderrTail: null,\n };\n child = holder;\n deps.log({\n event: 'daemon_supervisor_started',\n pid: proc.pid ?? null,\n deathCount: restartState.failureCount,\n });\n\n if (deps.captureCrashEvidence && proc.stderr) {\n const tail = new StderrTail();\n holder.stderrTail = tail;\n proc.stderr.on('data', (chunk: Buffer) => {\n tail.push(chunk);\n /** Tee back to our own stderr so inherited terminal/log output is unchanged. */\n process.stderr.write(chunk);\n });\n }\n\n if (opts.isRespawn) {\n emitRespawn(proc.pid ?? null);\n }\n\n proc.on('exit', (code, signal) => {\n handleChildExit(holder, code, signal);\n });\n proc.on('error', (err) => {\n deps.log({\n event: 'daemon_supervisor_child_error',\n err: err instanceof Error ? err.message : String(err),\n });\n });\n proc.on('message', (msg) => {\n /**\n * Drop stale messages from previous children. `proc.on('message')` is\n * attached to this `proc`, but the holder may have been retired (e.g.\n * concurrent kill + respawn race) before the message lands; ignore\n * anything that no longer belongs to the live `child`.\n */\n if (child !== holder) return;\n if (!isHeartbeatPayload(msg)) return;\n holder.lastHeartbeatAt = deps.now();\n holder.lastHeartbeatLagMs = msg.eventLoopLagMs;\n /**\n * If a wedge was just declared but the child recovered before the\n * SIGKILL window closed, clear the grace state so we don't kill a\n * now-healthy child. The grace window is only 2s; in practice this is\n * rare but cheap to be defensive about.\n */\n holder.wedgeGraceStartedAt = null;\n });\n }\n\n function handleChildExit(\n holder: ChildHolder,\n code: number | null,\n signal: NodeJS.Signals | null\n ): void {\n holder.exited = true;\n /** Drop stale exits — only the live child drives state. */\n if (child !== holder) return;\n child = null;\n\n const uptimeMs = deps.now() - holder.spawnedAt;\n\n if (shutdownInitiated) {\n deps.log({ event: 'daemon_supervisor_child_exited_during_shutdown', code, signal, uptimeMs });\n resolveDone({ exitCode: code ?? 0, reason: 'graceful' });\n return;\n }\n\n if (!isAbnormalExit(code, signal)) {\n deps.log({ event: 'daemon_supervisor_child_exited_clean', code, signal, uptimeMs });\n resolveDone({ exitCode: code ?? 0, reason: 'graceful' });\n return;\n }\n\n handleAbnormalChildExit(holder, code, signal, uptimeMs);\n }\n\n function handleAbnormalChildExit(\n holder: ChildHolder,\n code: number | null,\n signal: NodeJS.Signals | null,\n uptimeMs: number\n ): void {\n deps.log({ event: 'daemon_supervisor_child_died', code, signal, uptimeMs });\n flushCrashEvidence(holder, code, signal, uptimeMs);\n\n /**\n * Reuse the guard's pure restart core: 'subscribe_failure' drives the\n * same backoff + circuit logic per-process. Different state instance,\n * same primitive (third use site after guard's per-path circuit and the\n * watcher-worker supervisor's restart circuit).\n */\n const failureDecision = decideAction(restartState, { kind: 'subscribe_failure' }, deps.now());\n restartState = failureDecision.state;\n emitFailureSignals(failureDecision.signals, holder);\n\n if (restartState.circuitOpenedAt !== null) {\n /**\n * Per the spec for this layer: rather than half-open probe like the\n * watcher worker (which lives inside the daemon), the CLI supervisor\n * surfaces the failure to the user so they can investigate. The\n * supervisor terminates rather than continuing to thrash.\n */\n resolveDone({ exitCode: 1, reason: 'circuit_open' });\n return;\n }\n\n scheduleRespawn();\n }\n\n /**\n * Persist the native-crash evidence the dying child could not record itself\n * (no JS handler fires on a native abort). `.daemon-last-exit` carries the\n * exit signal/code; `crash-stderr/*.log` carries the buffered stderr tail.\n * Both are best-effort — a failed write logs but never blocks respawn.\n */\n function flushCrashEvidence(\n holder: ChildHolder,\n code: number | null,\n signal: NodeJS.Signals | null,\n uptimeMs: number\n ): void {\n if (!deps.captureCrashEvidence) return;\n const now = deps.now();\n const pid = holder.process.pid ?? null;\n if (pid === null || pid <= 0) {\n /** No usable pid (fork failed before exec): a record would fail the next-boot pid gate. */\n deps.log({ event: 'crash_evidence_skipped_no_pid', code, signal });\n return;\n }\n try {\n writeExitRecordSync(join(deps.dataDir, EXIT_RECORD_BASENAME), {\n pid,\n exitedAt: now,\n code,\n signal,\n uptimeMs,\n source: 'cli',\n });\n } catch (err: unknown) {\n deps.log({\n event: 'exit_record_write_failed',\n err: err instanceof Error ? err.message : String(err),\n });\n }\n flushStderrTail(holder, pid, now);\n }\n\n function flushStderrTail(holder: ChildHolder, pid: number, now: number): void {\n const tail = holder.stderrTail;\n if (!tail || tail.isEmpty) return;\n try {\n const dir = join(deps.dataDir, CRASH_STDERR_DIRNAME);\n mkdirSync(dir, { recursive: true });\n const filename = buildCrashStderrFilename(pid, new Date(now).toISOString());\n writeFileSync(join(dir, filename), tail.snapshot(), 'utf-8');\n } catch (err: unknown) {\n deps.log({\n event: 'crash_stderr_write_failed',\n err: err instanceof Error ? err.message : String(err),\n });\n }\n }\n\n function emitFailureSignals(\n signals: ReturnType<typeof decideAction>['signals'],\n holder: ChildHolder\n ): void {\n for (const sig of signals) {\n if (sig.kind === 'circuit_opened' && !circuitLogged) {\n circuitLogged = true;\n const windowMs = deps.now() - holder.spawnedAt;\n deps.log({\n event: 'daemon_supervisor_circuit_open',\n deathCount: restartState.failureCount,\n windowMs,\n });\n captureMetric('daemon_supervisor_circuit_open', {\n deathCount: restartState.failureCount,\n windowMs,\n });\n }\n }\n }\n\n function scheduleRespawn(): void {\n if (shutdownInitiated) return;\n if (restartState.circuitOpenedAt !== null) return;\n\n const requestDecision = decideAction(\n restartState,\n { kind: 'request_subscribe', reason: 'rescan', activeCount: 0 },\n deps.now()\n );\n restartState = requestDecision.state;\n deps.log({\n event: 'daemon_supervisor_respawn_scheduled',\n deathCount: restartState.failureCount,\n });\n\n switch (requestDecision.action.kind) {\n case 'wait': {\n restartTimer = deps.setTimeout(() => {\n restartTimer = null;\n if (shutdownInitiated) return;\n spawnChild({ isRespawn: true });\n }, requestDecision.action.ms);\n return;\n }\n case 'subscribe':\n case 'evict_and_subscribe':\n /**\n * `evict_and_subscribe` only fires when activeCount >= MAX_ACTIVE_WATCHERS;\n * we always pass activeCount: 0 so the pure core never returns it here.\n * Treating both as \"respawn now\" keeps the switch exhaustive without\n * coupling this layer to guard-internals.\n */\n spawnChild({ isRespawn: true });\n return;\n case 'reject_stub':\n /** Circuit-open path is handled by the caller before scheduleRespawn. */\n return;\n case 'noop':\n /** decideRequest never returns 'noop'. */\n return;\n default:\n assertNever(requestDecision.action);\n }\n }\n\n /**\n * Emit the `daemon_supervisor_respawned` log + metric. The metric carries\n * `newPid` (post-fork) plus `deathCount`. Called inline in `spawnChild` for\n * respawns; the initial spawn does not emit this event.\n */\n function emitRespawn(newPid: number | null): void {\n deps.log({ event: 'daemon_supervisor_respawned', deathCount: restartState.failureCount });\n captureMetric('daemon_supervisor_respawned', {\n newPid,\n deathCount: restartState.failureCount,\n });\n }\n\n function forwardShutdown(): void {\n if (shutdownInitiated) return;\n shutdownInitiated = true;\n\n if (restartTimer !== null) {\n deps.clearTimeout(restartTimer);\n restartTimer = null;\n }\n if (wedgeCheckTimer !== null) {\n deps.clearTimeout(wedgeCheckTimer);\n wedgeCheckTimer = null;\n }\n\n const holder = child;\n if (!holder) {\n /**\n * Either we never spawned, the previous child already exited, or the\n * circuit opened. Resolve with code 0 so the supervisor process exits.\n */\n deps.log({ event: 'daemon_supervisor_shutdown_no_child' });\n resolveDone({ exitCode: 0, reason: 'graceful' });\n return;\n }\n\n deps.log({ event: 'daemon_supervisor_shutdown_requested' });\n\n /**\n * Cooperative shutdown via the IPC channel that `fork()` sets up. The\n * child should listen for `process.on('message', ...)` and tear down\n * gracefully on `{cmd:'shutdown'}`.\n */\n try {\n holder.process.send?.({ cmd: 'shutdown' });\n } catch (err) {\n deps.log({\n event: 'daemon_supervisor_shutdown_send_failed',\n err: err instanceof Error ? err.message : String(err),\n });\n }\n\n /** SIGTERM after grace, SIGKILL after that. */\n deps.setTimeout(() => onSigtermDeadline(holder), SHUTDOWN_GRACEFUL_MS);\n }\n\n function onSigtermDeadline(holder: ChildHolder): void {\n if (holder.exited) return;\n deps.log({ event: 'daemon_supervisor_shutdown_sigterm' });\n try {\n holder.process.kill('SIGTERM');\n } catch (err) {\n deps.log({\n event: 'daemon_supervisor_kill_failed',\n signal: 'SIGTERM',\n err: err instanceof Error ? err.message : String(err),\n });\n }\n deps.setTimeout(() => onSigkillDeadline(holder), SHUTDOWN_SIGTERM_MS);\n }\n\n function onSigkillDeadline(holder: ChildHolder): void {\n if (holder.exited) return;\n deps.log({ event: 'daemon_supervisor_shutdown_sigkill' });\n try {\n holder.process.kill('SIGKILL');\n } catch (err) {\n deps.log({\n event: 'daemon_supervisor_kill_failed',\n signal: 'SIGKILL',\n err: err instanceof Error ? err.message : String(err),\n });\n /**\n * Safety net: SIGKILL throwing AND on-exit not firing is a paranoid\n * combination (zombie process, EPERM on a child we own), but if it\n * happens the `done` promise hangs forever and so does whoever\n * awaits it. Resolve here so the supervisor parent can exit.\n */\n resolveDone({ exitCode: 1, reason: 'graceful' });\n }\n }\n\n /**\n * Wedge detection loop. Runs in the SUPERVISOR PROCESS, which has almost\n * no work to do — it's a separate Node process from the daemon, so its\n * event loop is not subject to whatever's blocking the daemon child's.\n *\n * The check is a recurring `setTimeout` (not `setInterval`) so we only\n * need one timer-shape dep and so the test harness can drive it via\n * `advanceBy`. The chain self-cancels when `shutdownInitiated` flips true\n * or the function returns without rescheduling.\n */\n function scheduleWedgeCheck(): void {\n if (!wedgeEnabled) return;\n if (shutdownInitiated) return;\n wedgeCheckTimer = deps.setTimeout(() => {\n wedgeCheckTimer = null;\n runWedgeCheck();\n scheduleWedgeCheck();\n }, WEDGE_CHECK_INTERVAL_MS);\n }\n\n function runWedgeCheck(): void {\n if (shutdownInitiated) return;\n const holder = child;\n if (!holder || holder.exited) return;\n\n const now = deps.now();\n if (holder.wedgeGraceStartedAt !== null) {\n maybeFinishWedgeGrace(holder, now);\n return;\n }\n const silentMs = now - holder.lastHeartbeatAt;\n if (silentMs <= wedgeTimeoutMs) return;\n declareWedge(holder, now, silentMs);\n }\n\n /**\n * SIGUSR2 already sent; if the grace window has elapsed without a fresh\n * heartbeat clearing `wedgeGraceStartedAt`, escalate to SIGKILL. The OS\n * kill triggers Node's `exit` event with `signal: 'SIGKILL'`, which goes\n * through `handleChildExit` -> `handleAbnormalChildExit` -> the existing\n * `decideAction` respawn flow. Nothing else to do here.\n */\n function maybeFinishWedgeGrace(holder: ChildHolder, now: number): void {\n const graceStart = holder.wedgeGraceStartedAt;\n if (graceStart === null) return;\n const graceElapsed = now - graceStart;\n if (graceElapsed < WEDGE_SIGUSR2_GRACE_MS) return;\n\n deps.log({\n event: 'daemon_wedge_sigkill',\n pid: holder.process.pid ?? null,\n graceElapsedMs: graceElapsed,\n });\n captureMetric('daemon_wedge_sigkill', {\n pid: holder.process.pid ?? null,\n graceElapsedMs: graceElapsed,\n });\n safeKill(holder, 'SIGKILL');\n }\n\n /**\n * First wedge detection for this child. Log + send SIGUSR2 (to give the\n * daemon a chance to dump a CPU profile via the off-thread inspector)\n * and start the grace window.\n */\n function declareWedge(holder: ChildHolder, now: number, silentMs: number): void {\n deps.log({\n event: 'daemon_wedge_detected',\n pid: holder.process.pid ?? null,\n lastHeartbeatAt: holder.lastHeartbeatAt,\n silentMs,\n lastKnownLagMs: holder.lastHeartbeatLagMs,\n wedgeTimeoutMs,\n });\n captureMetric('daemon_wedge_detected', {\n pid: holder.process.pid ?? null,\n silentMs,\n lastKnownLagMs: holder.lastHeartbeatLagMs,\n });\n\n holder.wedgeGraceStartedAt = now;\n safeKill(holder, 'SIGUSR2');\n }\n\n function safeKill(holder: ChildHolder, signal: NodeJS.Signals): void {\n try {\n holder.process.kill(signal);\n } catch (err) {\n deps.log({\n event: 'daemon_supervisor_kill_failed',\n signal,\n err: err instanceof Error ? err.message : String(err),\n });\n }\n }\n\n /** Wire signal forwarding via injected hook so tests can drive deterministically. */\n deps.onSignal('SIGTERM', forwardShutdown);\n deps.onSignal('SIGINT', forwardShutdown);\n\n /** Spawn the initial child immediately. */\n spawnChild({ isRespawn: false });\n scheduleWedgeCheck();\n\n return { done };\n}\n\nfunction isAbnormalExit(code: number | null, signal: NodeJS.Signals | null): boolean {\n if (signal !== null && ABNORMAL_SIGNALS.has(signal)) return true;\n if (code !== null && code !== 0) return true;\n return false;\n}\n","export type SupervisorProcessGuardEvent =\n | {\n event: 'supervisor_uncaught_exception';\n err: SerializedSupervisorProcessError;\n origin: string;\n }\n | {\n event: 'supervisor_unhandled_rejection';\n reason: SerializedSupervisorProcessError;\n };\n\nexport interface SerializedSupervisorProcessError {\n kind: 'error' | 'non_error';\n name: string;\n message: string;\n stack?: string;\n cause?: SerializedSupervisorProcessError;\n}\n\nexport interface SupervisorProcessGuardDeps {\n log: (entry: SupervisorProcessGuardEvent) => void;\n onUncaughtException: (\n handler: (err: Error, origin: NodeJS.UncaughtExceptionOrigin) => void\n ) => void;\n onUnhandledRejection: (handler: (reason: unknown, promise: Promise<unknown>) => void) => void;\n}\n\nexport function installSupervisorProcessGuards(deps: SupervisorProcessGuardDeps): void {\n deps.onUncaughtException((err, origin) => {\n deps.log({\n event: 'supervisor_uncaught_exception',\n err: serializeSupervisorProcessError(err),\n origin,\n });\n });\n\n deps.onUnhandledRejection((reason) => {\n deps.log({\n event: 'supervisor_unhandled_rejection',\n reason: serializeSupervisorProcessError(reason),\n });\n });\n}\n\nexport function serializeSupervisorProcessError(\n value: unknown,\n depth = 0\n): SerializedSupervisorProcessError {\n if (depth >= 3) {\n return {\n kind: 'non_error',\n name: typeof value,\n message: '[Max serialization depth reached]',\n };\n }\n\n if (value instanceof Error) {\n const serialized: SerializedSupervisorProcessError = {\n kind: 'error',\n name: value.name || 'Error',\n message: value.message,\n };\n if (value.stack) {\n serialized.stack = value.stack;\n }\n const cause = value.cause;\n if (cause !== undefined) {\n serialized.cause = serializeSupervisorProcessError(cause, depth + 1);\n }\n return serialized;\n }\n\n return {\n kind: 'non_error',\n name: typeof value,\n message: stringifyUnknown(value),\n };\n}\n\nfunction stringifyUnknown(value: unknown): string {\n if (typeof value === 'string') return value;\n\n try {\n const json = JSON.stringify(value);\n if (json !== undefined) return json;\n } catch {\n return String(value);\n }\n\n return String(value);\n}\n"],"mappings":"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","names":["join","join"]}