{"version":3,"file":"serve.mjs","names":[],"sources":["../../../../../../cli/po/src/cli/server/processGuards.ts","../../../../../../cli/po/src/cli/server/restartPolicy.ts","../../../../../../cli/po/src/cli/server/supervise.ts","../../../../../../cli/po/src/bin/serve.ts"],"sourcesContent":["import fs from 'node:fs/promises';\nimport path from 'node:path';\nimport { fileURLToPath } from 'node:url';\n\n/** Exit code for an uncaught exception: software failure, so a supervisor applies crash backoff. */\nexport const UNCAUGHT_EXIT_CODE = 70;\n/** Longest graceful stop (telemetry flush included) before an uncaught exception exits anyway. */\nconst FATAL_STOP_DEADLINE_MS = 5_000;\n\nconst SNAPSHOT_ROOT = /(\\S*?)[\\\\/]node_modules[\\\\/]\\.po-snapshots[\\\\/]([^\\\\/\\s:)]+)[\\\\/]/;\nconst UPM_STORE = /[\\\\/]node_modules[\\\\/]\\.upm[\\\\/]/;\nconst PACKAGE_PATH = /[\\\\/]node_modules[\\\\/]((?:@[^\\\\/\\s]+[\\\\/])?[^\\\\/\\s:)]+)[\\\\/]/g;\n\nasync function packageNameAt(directory: string): Promise<string | undefined> {\n  try {\n    const manifest = JSON.parse(await fs.readFile(path.join(directory, 'package.json'), 'utf8')) as { name?: unknown };\n    return typeof manifest.name === 'string' ? manifest.name : undefined;\n  } catch {\n    // Best effort: an unreadable manifest only loses the attribution.\n    return undefined;\n  }\n}\n\n/**\n * Best-effort owner of an error: the Po package whose snapshot or upm store path appears\n * first in its stack. Snapshots carry their `package.json`, so their name is exact; a upm\n * path uses its innermost `node_modules/<name>` segment. Ordinary dependency frames are\n * ignored, so a library on the stack is never blamed for its caller.\n */\nexport async function attributePackage(error: unknown): Promise<string | undefined> {\n  const stack = error instanceof Error ? error.stack : undefined;\n  if (!stack) return undefined;\n  for (const line of stack.split('\\n')) {\n    const snapshot = SNAPSHOT_ROOT.exec(line);\n    if (snapshot) {\n      const location = snapshot[1]!.replace(/^\\(/, '');\n      const root = location.startsWith('file:') ? fileURLToPath(`${location}/`) : location;\n      const name = await packageNameAt(path.join(root, 'node_modules', '.po-snapshots', snapshot[2]!));\n      if (name) return name;\n    }\n    if (!UPM_STORE.test(line)) continue;\n    const names = [...line.matchAll(PACKAGE_PATH)].map((match) => match[1]!);\n    const name = names.at(-1);\n    if (name && !name.startsWith('.')) return name.replace(/\\\\/g, '/');\n  }\n  return undefined;\n}\n\nfunction describe(error: unknown): string {\n  return error instanceof Error ? (error.stack ?? error.message) : String(error);\n}\n\nexport interface ProcessGuardOptions {\n  readonly write: (message: string) => void;\n  /** Starts the server's graceful stop, which flushes telemetry and logs. */\n  readonly stop: (reason: 'crash') => Promise<unknown>;\n  readonly exit: (code: number) => void;\n  readonly stopDeadlineMs?: number;\n}\n\n/**\n * Keeps one bad extension from taking the server down.\n *\n * An unhandled rejection is logged with its package and the server keeps running: a\n * rejected promise has already unwound and leaves no broken state behind. An uncaught\n * exception may have interrupted any synchronous invariant, so the server stops\n * gracefully (bounded) and exits with `UNCAUGHT_EXIT_CODE`.\n */\nexport function installProcessGuards(options: ProcessGuardOptions, target: NodeJS.Process = process): () => void {\n  let fatal = false;\n  const onRejection = (reason: unknown): void => {\n    void attributePackage(reason)\n      .catch(() => undefined)\n      .then((owner) => {\n        // Attribution is optional; the original failure is still reported if it cannot be read.\n        options.write(`[po-server] unhandled rejection${owner ? ` from ${owner}` : ''}: ${describe(reason)}\\n`);\n      });\n  };\n  const onException = (error: unknown): void => {\n    // Always log the original crash before any optional disk read or shutdown can stall.\n    options.write(`[po-server] uncaught exception: ${describe(error)}\\n`);\n    if (fatal) return;\n    fatal = true;\n    let finished = false;\n    const finish = (): void => {\n      if (finished) return;\n      finished = true;\n      clearTimeout(deadline);\n      options.exit(UNCAUGHT_EXIT_CODE);\n    };\n    // Not unref'd: a stalled stop must exit 70, not drain to 0 without live handles.\n    const deadline = setTimeout(finish, options.stopDeadlineMs ?? FATAL_STOP_DEADLINE_MS);\n    void attributePackage(error)\n      .catch(() => undefined)\n      .then((owner) => {\n        // Best effort only: attribution never delays shutdown or writes after it finished.\n        if (owner && !finished) options.write(`[po-server] uncaught exception owner: ${owner}\\n`);\n      });\n    void options\n      .stop('crash')\n      .catch((stopError: unknown) => {\n        options.write(`[po-server] stop after uncaught exception failed: ${describe(stopError)}\\n`);\n      })\n      .finally(finish);\n  };\n  target.on('unhandledRejection', onRejection);\n  target.on('uncaughtException', onException);\n  return () => {\n    target.off('unhandledRejection', onRejection);\n    target.off('uncaughtException', onException);\n  };\n}\n","/** Exit code the server uses for a deliberate recycle; a crash exits with anything else. */\nexport const RECYCLE_EXIT_CODE = 75;\n/** Delay before restart attempt n (0-based), capped at the last entry. */\nconst RESTART_BACKOFF_MS = [250, 1_000, 4_000, 15_000];\n/** More unplanned exits than this inside the window is a crash loop; stop restarting. */\nconst CRASH_LOOP_LIMIT = 5;\nconst CRASH_LOOP_WINDOW_MS = 2 * 60_000;\n\nexport interface RestartPolicy {\n  backoffMs: readonly number[];\n  crashLoopLimit: number;\n  crashLoopWindowMs: number;\n}\n\nexport const DEFAULT_RESTART_POLICY: RestartPolicy = {\n  backoffMs: RESTART_BACKOFF_MS,\n  crashLoopLimit: CRASH_LOOP_LIMIT,\n  crashLoopWindowMs: CRASH_LOOP_WINDOW_MS,\n};\n\n/**\n * Decides whether a supervised child that just exited is restarted, and after how long.\n *\n * A recycle (exit 75) restarts at once and does not count toward the crash loop: the server\n * chose to restart at idle. Any other exit counts; too many inside the window stops restarting.\n */\nexport function nextRestart(\n  exitCode: number | null,\n  crashes: number[],\n  now: number,\n  policy: RestartPolicy = DEFAULT_RESTART_POLICY,\n): { delayMs: number; crashes: number[] } | undefined {\n  if (exitCode === RECYCLE_EXIT_CODE) return { delayMs: 0, crashes };\n  const recent = [...crashes.filter((at) => now - at < policy.crashLoopWindowMs), now];\n  if (recent.length > policy.crashLoopLimit) return undefined;\n  const index = Math.min(recent.length - 1, policy.backoffMs.length - 1);\n  return { delayMs: policy.backoffMs[index] ?? 0, crashes: recent };\n}\n","import { type ChildProcess, spawn } from 'node:child_process';\nimport { constants } from 'node:os';\n\nimport { nextRestart, type RestartPolicy } from './restartPolicy';\n\nconst STOP_TIMEOUT_MS = 10_000;\n\nexport interface ServerSupervisionOptions {\n  entry: string;\n  args: readonly string[];\n  environment: NodeJS.ProcessEnv;\n  execArgv?: readonly string[];\n  restart?: RestartPolicy;\n  signal?: AbortSignal;\n  notice: (message: string) => void;\n}\n\n/** Owns a direct server launch, including shutdown while waiting to restart. */\nexport async function superviseServer(options: ServerSupervisionOptions): Promise<number> {\n  let child: ChildProcess | undefined;\n  let stopping = false;\n  let crashes: number[] = [];\n  let stopTimer: NodeJS.Timeout | undefined;\n  let cancelDelay: (() => void) | undefined;\n  const stop = (signal: NodeJS.Signals = 'SIGTERM'): void => {\n    if (stopping) return;\n    stopping = true;\n    cancelDelay?.();\n    if (child && child.exitCode === null && child.signalCode === null) {\n      child.kill(signal);\n      stopTimer = setTimeout(() => child?.kill('SIGKILL'), STOP_TIMEOUT_MS);\n    }\n  };\n  const interrupt = (): void => stop('SIGINT');\n  const terminate = (): void => stop();\n  process.on('SIGINT', interrupt);\n  process.on('SIGTERM', terminate);\n  process.on('disconnect', terminate);\n  options.signal?.addEventListener('abort', terminate, { once: true });\n  if (options.signal?.aborted) stop();\n  try {\n    while (!stopping) {\n      const result = await new Promise<{ code: number | null; signal: NodeJS.Signals | null }>((resolve, reject) => {\n        const execArgv = options.execArgv ?? process.execArgv;\n        const hasHeapFlag =\n          /--max[-_]old[-_]space[-_]size/.test(options.environment.NODE_OPTIONS ?? '') ||\n          execArgv.some((arg) => /--max[-_]old[-_]space[-_]size/.test(arg));\n        child = spawn(\n          process.execPath,\n          [...(hasHeapFlag ? [] : ['--max-old-space-size=10240']), ...execArgv, options.entry, ...options.args],\n          {\n            env: { ...options.environment, PO_SERVER_SUPERVISED: '1' },\n            stdio: ['inherit', 'inherit', 'inherit', 'ipc'],\n          },\n        );\n        child.once('error', reject);\n        child.once('exit', (code, signal) => resolve({ code, signal }));\n      });\n      if (stopTimer) clearTimeout(stopTimer);\n      child = undefined;\n      const exitCode = result.code ?? (result.signal ? 128 + constants.signals[result.signal] : 1);\n      // A clean exit is intentional, including normal shutdown. Only failures and\n      // the explicit recycle code request another direct launch.\n      if (stopping || result.code === 0) return exitCode;\n      const decision = nextRestart(result.code, crashes, Date.now(), options.restart);\n      if (!decision) {\n        options.notice(`server keeps exiting (code ${String(result.code)}); not restarting it again`);\n        return exitCode;\n      }\n      crashes = decision.crashes;\n      options.notice(`server exited (code ${String(result.code)}, signal ${String(result.signal)}); restarting it`);\n      await new Promise<void>((resolve) => {\n        const timer = setTimeout(resolve, decision.delayMs);\n        cancelDelay = () => {\n          clearTimeout(timer);\n          resolve();\n        };\n      });\n      cancelDelay = undefined;\n    }\n    return 0;\n  } finally {\n    if (stopTimer) clearTimeout(stopTimer);\n    process.off('SIGINT', interrupt);\n    process.off('SIGTERM', terminate);\n    process.off('disconnect', terminate);\n    options.signal?.removeEventListener('abort', terminate);\n  }\n}\n","#!/usr/bin/env node\nimport { installProcessGuards } from '../cli/server/processGuards';\nimport { superviseServer } from '../cli/server/supervise';\n\n// The library finishes bounded cleanup first. A stale handle must not keep this\n// standalone CLI alive forever; an unreferenced deadline still lets output drain.\nfunction finish(code: number): void {\n  process.exitCode = code;\n  setTimeout(() => process.exit(code), 2_000).unref();\n}\n\nasync function main(): Promise<number> {\n  if (process.env.PO_SERVER_SUPERVISED !== '1') {\n    return superviseServer({\n      entry: process.argv[1]!,\n      args: process.argv.slice(2),\n      environment: process.env,\n      notice: (message) => void process.stderr.write(`[po-server] ${message}\\n`),\n    });\n  }\n\n  // Only the worker initializes configuration and imports the runtime.\n  const { initializeAgentDirectory } = await import('./agentDirectory');\n  await initializeAgentDirectory();\n  const { runServer } = await import('../cli/server/run');\n  const stopController = new AbortController();\n  let stopped: Promise<unknown> | undefined;\n  const server = runServer(process.argv.slice(2), stopController.signal);\n  installProcessGuards({\n    write: (message) => void process.stderr.write(message),\n    stop: (reason) => {\n      stopController.abort(reason);\n      // The failure itself is reported by the handler below; here it only ends the stop.\n      stopped ??= server.catch(() => undefined);\n      return stopped;\n    },\n    exit: (code) => process.exit(code),\n  });\n  return server;\n}\n\nmain().then(finish, (error: unknown) => {\n  process.stderr.write(`[po-server] ${error instanceof Error ? error.message : String(error)}\\n`);\n  finish(1);\n});\n"],"mappings":"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"}