@rallycry/conveyor-agent 10.13.65 → 10.13.67
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{boot-7OPX55AO.js → boot-UUPTBQ6R.js} +7 -8
- package/dist/{chunk-JIGG755T.js → chunk-6Q6LQBWO.js} +0 -1
- package/dist/{chunk-ULS4QPRE.js → chunk-6W6UZ4SJ.js} +0 -1
- package/dist/{chunk-AXA55U4Z.js → chunk-E2SHIH6Y.js} +3 -4
- package/dist/{chunk-QOJTJCYZ.js → chunk-EXQ6AHOY.js} +2 -3
- package/dist/{chunk-5OQQSDVT.js → chunk-IA45XHOA.js} +0 -1
- package/dist/{chunk-QZN6HVUY.js → chunk-KG4ORL3Y.js} +1 -2
- package/dist/{chunk-4VUQ2NPF.js → chunk-KMB3BU4S.js} +0 -1
- package/dist/{chunk-NAK6FY5U.js → chunk-LE6ZUDZT.js} +37 -6
- package/dist/{chunk-6GS5ADIY.js → chunk-R3FDJQL6.js} +0 -1
- package/dist/{chunk-BAQ2OAKB.js → chunk-XPZPR6NS.js} +591 -216
- package/dist/cli.js +35 -43
- package/dist/{client-LRVVHTNG.js → client-IG6C5F2G.js} +3 -4
- package/dist/heartbeat-worker.js +1 -2
- package/dist/index.d.ts +95 -13
- package/dist/index.js +7 -8
- package/dist/{mode-6RL3SVMV.js → mode-ZJSOSLGU.js} +1 -2
- package/dist/{oom-watchdog-U7JERHA2.js → oom-watchdog-PAC5OJJG.js} +1 -2
- package/dist/{protocol-QLVS5W6O.js → protocol-QBCYO4GI.js} +1 -2
- package/dist/server-US2DDQSW.js +9 -0
- package/package.json +2 -2
- package/dist/boot-7OPX55AO.js.map +0 -1
- package/dist/chunk-4VUQ2NPF.js.map +0 -1
- package/dist/chunk-5OQQSDVT.js.map +0 -1
- package/dist/chunk-6GS5ADIY.js.map +0 -1
- package/dist/chunk-AXA55U4Z.js.map +0 -1
- package/dist/chunk-BAQ2OAKB.js.map +0 -1
- package/dist/chunk-JIGG755T.js.map +0 -1
- package/dist/chunk-NAK6FY5U.js.map +0 -1
- package/dist/chunk-QOJTJCYZ.js.map +0 -1
- package/dist/chunk-QZN6HVUY.js.map +0 -1
- package/dist/chunk-ULS4QPRE.js.map +0 -1
- package/dist/cli.js.map +0 -1
- package/dist/client-LRVVHTNG.js.map +0 -1
- package/dist/heartbeat-worker.js.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/mode-6RL3SVMV.js.map +0 -1
- package/dist/oom-watchdog-U7JERHA2.js.map +0 -1
- package/dist/protocol-QLVS5W6O.js.map +0 -1
- package/dist/server-ZACB5T5S.js +0 -10
- package/dist/server-ZACB5T5S.js.map +0 -1
package/dist/cli.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/cli.ts","../src/setup/sidecars.ts","../src/setup/db-schema-sync.ts","../src/setup/deps-sync.ts","../src/setup/workspace-command-supervisor.ts","../src/utils/session-identity.ts","../src/utils/agent-exit.ts","../src/setup/project-identity.ts","../src/runner/project-session-runner.ts","../src/usage/multi-key-probe.ts","../src/runner/adhoc-session-runner.ts","../src/runner/review-child.ts","../src/runner/session-child.ts","../src/runner/shell-session-runner.ts","../src/runner/spawned-child-boot.ts","../src/runner/host-modes.ts"],"sourcesContent":["#!/usr/bin/env node\n/* oxlint-disable import/max-dependencies -- CLI entry point wires every runner variant (task/pm/code-review/adhoc) + setup; splitting would scatter the boot sequence */\nimport { readFileSync } from \"node:fs\";\nimport { join, dirname } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport { SessionRunner } from \"./runner/session-runner.js\";\nimport type { AgentRunnerStatus, RunnerMode } from \"@project/shared\";\nimport { createServiceLogger } from \"./utils/logger.js\";\nimport { applyBootstrapToEnv, fetchBootstrap, loadConveyorConfig } from \"./setup/index.js\";\nimport {\n startWorkspaceCommandsAfterConnect,\n stopWorkspaceCommands,\n WorkspaceCommandSupervisor,\n} from \"./setup/workspace-command-supervisor.js\";\nimport { checkSessionTaskIdentity } from \"./utils/session-identity.js\";\nimport { isPermissionDeniedError } from \"./connection/auth-errors.js\";\nimport {\n buildAgentExitLog,\n exitLogLevel,\n type AgentExitIdentity,\n type AgentExitReason,\n} from \"./utils/agent-exit.js\";\nimport { resolveProjectRunnerIdentity } from \"./setup/project-identity.js\";\nimport { ProjectSessionRunner } from \"./runner/project-session-runner.js\";\nimport { AdhocSessionRunner, resolveInitialPrompt } from \"./runner/adhoc-session-runner.js\";\nimport { ReviewChildSupervisor } from \"./runner/review-child.js\";\nimport { SessionChildSupervisor } from \"./runner/session-child.js\";\nimport { createSpawnedChildRunner } from \"./runner/spawned-child-boot.js\";\nimport { hostsSpawnedChildren } from \"./runner/host-modes.js\";\nimport { isLegacyEntrypointLaunch, TOMBSTONE_MESSAGE } from \"./boot/tombstone.js\";\n\n// vnext boot entry: `conveyor-agent boot [--preflight-update]`. Dispatched FIRST\n// (before --version, before every legacy branch) — the shim (Task 10) execs this.\nif (process.argv[2] === \"boot\") {\n const { runBoot } = await import(\"./boot/index.js\");\n process.exit(await runBoot(process.argv.slice(3)));\n}\n\n// Legacy-launch tombstone: a pod whose bash entrypoint launched `conveyor-agent`\n// directly (old image, no vnext handshake) must die loudly asking for a rebake,\n// before it can fall into the workbench Step 0 or any runner path below. vnext\n// children inherit CONVEYOR_BOOT_VNEXT=1 (buildChildEnv) → unaffected; codespaces\n// and local runs have no CLAUDESPACE_NAME → unaffected.\nif (isLegacyEntrypointLaunch(process.env)) {\n process.stderr.write(`${TOMBSTONE_MESSAGE}\\n`);\n process.exit(1);\n}\n\n// Handle --version flag before any other initialization\nif (process.argv.includes(\"--version\")) {\n const __dirname = dirname(fileURLToPath(import.meta.url));\n const pkgPath = join(__dirname, \"..\", \"package.json\");\n const pkg = JSON.parse(readFileSync(pkgPath, \"utf-8\"));\n process.stdout.write(pkg.version + \"\\n\");\n process.exit(0);\n}\n\nconst logger = createServiceLogger(\"CLI\");\n\n// Pod-exit observability. The reconciler can only infer *that* an agent stopped\n// (stale heartbeat → Stranded); it never sees *why*. We log the cause from the\n// pod side at every catchable exit, keyed on the same sessionId the API's\n// `session_stranded` line carries so the two ends can be joined. Populated once\n// env identity resolves below; the early crash handlers read it live. (SIGKILL /\n// OOM 137 is uncatchable — diagnosed from GKE kernel logs, not this line.)\nconst exitContext: AgentExitIdentity = {};\nlet exitLogged = false;\n// True once a SIGTERM/SIGINT shutdown has begun. An \"operation aborted\" error is\n// only *expected* while we're tearing down (the SDK/PTY abort controllers fire\n// during shutdown); before that, an abort is a genuine mid-run failure and must\n// NOT be swallowed. Declared before the crash handlers below so they can read it\n// without a temporal-dead-zone hazard.\nlet shuttingDown = false;\nfunction logAgentExit(\n reason: AgentExitReason,\n opts: { exitCode: number; signal?: string; finalState?: string },\n): void {\n // One line per process death; force_timeout is logged separately (it escalates\n // an already-logged signal shutdown) so it bypasses this guard at its call site.\n if (exitLogged) return;\n exitLogged = true;\n const payload = buildAgentExitLog({\n reason,\n exitCode: opts.exitCode,\n signal: opts.signal,\n finalState: opts.finalState,\n uptimeSec: process.uptime(),\n identity: exitContext,\n });\n logger[exitLogLevel(reason)](\"agent_exit\", payload as unknown as Record<string, unknown>);\n}\n\nasync function bootstrapFromCodespace(apiUrl: string, instanceName: string): Promise<void> {\n const bootstrapToken = process.env.CONVEYOR_BOOTSTRAP_TOKEN;\n const apiUrlFromEnv = Boolean(process.env.CONVEYOR_API_URL);\n logger.info(\"Bootstrapping from codespace\", {\n codespace: instanceName,\n apiUrl,\n apiUrlFromEnv,\n bootstrapTokenPresent: Boolean(bootstrapToken),\n });\n const result = await fetchBootstrap({\n apiUrl,\n instanceName,\n bootstrapToken,\n });\n if (!result.ok) {\n logger.error(\"Bootstrap failed after retries\", {\n reason: result.reason,\n attempts: result.attempts,\n status: result.status,\n detail: result.detail,\n apiUrl,\n apiUrlFromEnv,\n bootstrapTokenPresent: Boolean(bootstrapToken),\n hint: apiUrlFromEnv\n ? \"Verify the codespace was created by this Conveyor deployment and that the bootstrap token is current.\"\n : \"CONVEYOR_API_URL was not set as a codespace secret — agent fell back to the built-in default. Re-create the codespace, or push CONVEYOR_API_URL via project settings.\",\n });\n process.exit(1);\n }\n applyBootstrapToEnv(result.config);\n logger.info(\"Bootstrap complete\", {\n taskId: result.config.taskId,\n attempts: result.attempts,\n });\n}\n\n// Helper to detect expected abort errors from SDK cleanup\nfunction isExpectedAbortError(error: Error | NodeJS.ErrnoException): boolean {\n const message = error.message || \"\";\n const hasAbortMessage = /operation aborted/i.test(message) || /abort/i.test(message);\n const hasAbortCode = !(\"code\" in error) || error.code === undefined || error.code === \"ABORT_ERR\";\n return hasAbortMessage && hasAbortCode;\n}\n\n// A persistent authorization denial (the session user is not a project member)\n// makes every agent RPC fail ACL. Retrying or refreshing can never fix it, so\n// exit CLEANLY (code 0): the supervisor shuts the pod down without burning the\n// 3× crash-restart loop, and the workspace parks via the dead-pod janitor with\n// a user notification. session-runner.connect() already handles the common\n// (connectAgent) case gracefully; this is the belt-and-braces backstop for any\n// other startup RPC whose permission denial escapes as an uncaught error.\nfunction exitOnPermissionDenial(err: Error): boolean {\n if (!isPermissionDeniedError(err)) return false;\n logger.error(\"Not authorized for this project — parking instead of crash-looping\", {\n error: err.message,\n });\n logAgentExit(\"unauthorized\", { exitCode: 0 });\n process.exit(0);\n}\n\nprocess.on(\"uncaughtException\", (err: NodeJS.ErrnoException) => {\n if (err.code === \"EPIPE\") return;\n\n if (shuttingDown && isExpectedAbortError(err)) {\n logger.info(\"Ignored expected abort after shutdown\", { error: err.message, code: err.code });\n return;\n }\n\n if (exitOnPermissionDenial(err)) return;\n\n logger.error(\"Uncaught exception\", { error: err.message, code: err.code });\n logAgentExit(\"uncaught_exception\", { exitCode: 1 });\n process.exit(1);\n});\n\nprocess.on(\"unhandledRejection\", (reason: unknown) => {\n const err = reason instanceof Error ? reason : new Error(String(reason));\n\n if (shuttingDown && isExpectedAbortError(err)) {\n logger.info(\"Ignored expected abort rejection after shutdown\", { error: err.message });\n return;\n }\n\n if (exitOnPermissionDenial(err)) return;\n\n logger.error(\"Unhandled rejection\", { error: err.message });\n logAgentExit(\"unhandled_rejection\", { exitCode: 1 });\n process.exit(1);\n});\n\n// Step 0: workbench launcher (split-mode pods). The workbench container runs\n// ONLY the exec daemon — no task token, no bootstrap, no runner lifecycle.\n// Checked before everything so it never falls through to the task paths.\nif (process.env.CONVEYOR_MODE === \"workbench\") {\n const { startWorkbenchServer } = await import(\"./workbench/server.js\");\n const { oomWatchdogOptionsFromEnv } = await import(\"./workbench/oom-watchdog.js\");\n const { DEFAULT_WORKBENCH_PORT } = await import(\"./workbench/protocol.js\");\n const port = Number(process.env.CONVEYOR_WORKBENCH_PORT) || DEFAULT_WORKBENCH_PORT;\n const token = process.env.CONVEYOR_WORKBENCH_TOKEN ?? process.env.POD_BOOTSTRAP_TOKEN ?? \"\";\n if (!token) {\n logger.error(\"workbench mode requires POD_BOOTSTRAP_TOKEN (or CONVEYOR_WORKBENCH_TOKEN)\");\n process.exit(1);\n }\n const pkgDir = dirname(fileURLToPath(import.meta.url));\n const pkg = JSON.parse(readFileSync(join(pkgDir, \"..\", \"package.json\"), \"utf-8\")) as {\n version?: string;\n };\n const handle = await startWorkbenchServer({\n port,\n token,\n version: pkg.version ?? \"unknown\",\n oomWatchdog: oomWatchdogOptionsFromEnv({\n info: (m) => logger.info(m),\n warn: (m) => logger.warn(m),\n error: (m) => logger.error(m),\n }),\n });\n logger.info(`Workbench launcher listening on 127.0.0.1:${handle.port}`);\n // Park forever — the kubelet owns this container's lifecycle (native\n // sidecar, restartPolicy Always); SIGTERM just exits.\n process.on(\"SIGTERM\", () => process.exit(0));\n await new Promise(() => {});\n}\n\nconst DEFAULT_CONVEYOR_API_URL = \"https://api.conveyor.rallycryapp.com\";\nlet conveyorApiUrl = process.env.CONVEYOR_API_URL || DEFAULT_CONVEYOR_API_URL;\n\n// Step 1: Codespace bootstrap\nconst INSTANCE_NAME = process.env.CODESPACE_NAME || process.env.CLAUDESPACE_NAME;\nif (INSTANCE_NAME && !process.env.CONVEYOR_TASK_TOKEN) {\n if (!conveyorApiUrl) {\n logger.error(\"Could not resolve CONVEYOR_API_URL for codespace bootstrap\");\n process.exit(1);\n }\n await bootstrapFromCodespace(conveyorApiUrl, INSTANCE_NAME);\n conveyorApiUrl = process.env.CONVEYOR_API_URL ?? conveyorApiUrl;\n}\n\n// Step 2: Read env vars (bootstrap may have set them)\nconst CONVEYOR_TASK_TOKEN = process.env.CONVEYOR_TASK_TOKEN;\nconst CONVEYOR_TASK_ID = process.env.CONVEYOR_TASK_ID;\nconst CONVEYOR_WORKSPACE = process.env.CONVEYOR_WORKSPACE ?? process.cwd();\nconst CONVEYOR_MODE = (process.env.CONVEYOR_MODE ?? \"task\") as RunnerMode;\nconst CONVEYOR_AGENT_MODE = process.env.CONVEYOR_AGENT_MODE || undefined;\nconst CONVEYOR_IS_AUTO = CONVEYOR_AGENT_MODE\n ? CONVEYOR_AGENT_MODE === \"auto\"\n : process.env.CONVEYOR_IS_AUTO === \"true\";\n\n// Seed the pod-exit identity now that env is resolved (the specific runner\n// branches below refine sessionId/workspaceId to their own session).\nexitContext.taskId = CONVEYOR_TASK_ID;\nexitContext.workspaceId = process.env.CONVEYOR_WORKSPACE_ID;\nexitContext.runnerMode = CONVEYOR_MODE;\nexitContext.sessionId = process.env.CONVEYOR_SESSION_ID ?? CONVEYOR_TASK_ID;\n\n// Step 2.5: task-less PROJECT pods (Claudespace v3 project runners). The\n// bundle's session JWT carries {projectId, sessionId} and NO taskId; the\n// entrypoint exports CONVEYOR_PROJECT_ID (no CONVEYOR_TASK_ID) and sets\n// CONVEYOR_MODE=pm. Boot the project runner: connect + register session +\n// heartbeat + idle awaiting project-scoped messages. Never falls through to\n// the task lifecycle below.\nconst projectIdentity = resolveProjectRunnerIdentity(process.env);\n\n// Task-less ADHOC pods (Sessions view scratch pods). Same task-less identity as\n// a project pod (projectId + sessionId, no taskId), distinguished by\n// CONVEYOR_MODE=adhoc. Runs an interactive `claude` TUI relayed to the web\n// terminal — NOT the autonomous pm project runner below. Checked first so an\n// adhoc session never falls through to pm.\nif (!CONVEYOR_TASK_ID && projectIdentity && CONVEYOR_MODE === \"adhoc\") {\n logger.info(\"Starting ad-hoc agent\", { projectId: projectIdentity.projectId });\n const adhocRunner = new AdhocSessionRunner(\n {\n connection: {\n apiUrl: conveyorApiUrl ?? \"\",\n taskToken: projectIdentity.taskToken,\n sessionId: projectIdentity.sessionId,\n runnerMode: \"adhoc\",\n },\n projectId: projectIdentity.projectId,\n workspaceId: projectIdentity.workspaceId,\n workspaceDir: CONVEYOR_WORKSPACE,\n // Headless sessions: un-submitted audit instructions from the bundle.\n // Resolved ONLY here — spawned same-pod tabs must not inherit them.\n initialPrompt: resolveInitialPrompt(process.env),\n ...(process.env.CLAUDESPACE_NAME ? { lifecycle: { idleTimeoutMs: 60 * 60 * 1000 } } : {}),\n },\n {\n onEvent: (event) => {\n logger.info(\"Ad-hoc runner event\", { eventType: event.type as string });\n },\n },\n );\n exitContext.sessionId = projectIdentity.sessionId;\n exitContext.workspaceId = projectIdentity.workspaceId;\n exitContext.runnerMode = \"adhoc\";\n process.on(\"SIGTERM\", () => {\n shuttingDown = true;\n adhocRunner.stop();\n });\n process.on(\"SIGINT\", () => {\n shuttingDown = true;\n adhocRunner.stop();\n });\n await adhocRunner.run();\n const adhocError = adhocRunner.finalState === \"error\";\n logAgentExit(adhocError ? \"error\" : \"clean\", {\n exitCode: adhocError ? 1 : 0,\n finalState: adhocRunner.finalState ?? undefined,\n });\n process.exit(adhocError ? 1 : 0);\n}\n\nif (!CONVEYOR_TASK_ID && projectIdentity) {\n logger.info(\"Starting project agent\", { projectId: projectIdentity.projectId });\n const projectRunner = new ProjectSessionRunner(\n {\n connection: {\n apiUrl: conveyorApiUrl ?? \"\",\n taskToken: projectIdentity.taskToken,\n sessionId: projectIdentity.sessionId,\n runnerMode: \"pm\",\n },\n projectId: projectIdentity.projectId,\n // Same extended idle window claudespace task pods get.\n ...(process.env.CLAUDESPACE_NAME ? { lifecycle: { idleTimeoutMs: 60 * 60 * 1000 } } : {}),\n },\n {\n onEvent: (event) => {\n logger.info(\"Project runner event\", { eventType: event.type as string });\n },\n },\n );\n exitContext.sessionId = projectIdentity.sessionId;\n exitContext.workspaceId = projectIdentity.workspaceId;\n exitContext.runnerMode = \"pm\";\n process.on(\"SIGTERM\", () => {\n shuttingDown = true;\n projectRunner.stop();\n });\n process.on(\"SIGINT\", () => {\n shuttingDown = true;\n projectRunner.stop();\n });\n await projectRunner.run();\n const projectError = projectRunner.finalState === \"error\";\n logAgentExit(projectError ? \"error\" : \"clean\", {\n exitCode: projectError ? 1 : 0,\n finalState: projectRunner.finalState ?? undefined,\n });\n process.exit(projectError ? 1 : 0);\n}\n\nif (!CONVEYOR_TASK_TOKEN || !CONVEYOR_TASK_ID) {\n logger.error(\"Missing required environment variables\");\n logger.error(\" CONVEYOR_TASK_TOKEN - JWT token for task authentication\");\n logger.error(\" CONVEYOR_TASK_ID - ID of the task to execute\");\n logger.error(\"\");\n logger.error(\"CONVEYOR_API_URL is provided via codespace secret or bootstrap.\");\n logger.error(\"\");\n logger.error(\"Optional:\");\n logger.error(\" CONVEYOR_MODE - Runner mode: 'task' (default), 'pack', or 'pm'\");\n logger.error(\" CONVEYOR_WORKSPACE - Working directory (defaults to cwd)\");\n logger.error(\n \" Project pods instead require CONVEYOR_PROJECT_ID + CONVEYOR_SESSION_ID + CONVEYOR_MODE=pm\",\n );\n process.exit(1);\n}\n\nif (\n CONVEYOR_MODE !== \"task\" &&\n CONVEYOR_MODE !== \"pm\" &&\n CONVEYOR_MODE !== \"code-review\" &&\n CONVEYOR_MODE !== \"adhoc\" &&\n CONVEYOR_MODE !== \"pack\" &&\n CONVEYOR_MODE !== \"shell\"\n) {\n logger.error(\"Invalid CONVEYOR_MODE\", {\n mode: CONVEYOR_MODE,\n expected: [\"task\", \"pm\", \"code-review\", \"adhoc\", \"pack\", \"shell\"],\n });\n process.exit(1);\n}\n\n// Same-pod spawned children (session:spawnTui): TASK-BOUND extra tabs on the\n// builder's pod — a second Claude TUI (mode \"adhoc\" + a task id, unlike the\n// task-less Sessions-view branch above) or a raw login shell (mode \"shell\").\n// Both bind their own WorkspaceSession via env overrides set by\n// SessionChildSupervisor and never fall through to the task SessionRunner.\nif (CONVEYOR_MODE === \"shell\" || CONVEYOR_MODE === \"adhoc\") {\n const spawnedSessionId = process.env.CONVEYOR_SESSION_ID;\n if (!spawnedSessionId) {\n logger.error(\"Spawned child requires CONVEYOR_SESSION_ID\", { mode: CONVEYOR_MODE });\n process.exit(1);\n }\n exitContext.sessionId = spawnedSessionId;\n exitContext.runnerMode = CONVEYOR_MODE;\n\n const childRunner = createSpawnedChildRunner({\n mode: CONVEYOR_MODE,\n apiUrl: conveyorApiUrl ?? \"\",\n taskToken: CONVEYOR_TASK_TOKEN,\n sessionId: spawnedSessionId,\n workspaceDir: CONVEYOR_WORKSPACE,\n projectId: process.env.CONVEYOR_PROJECT_ID ?? \"\",\n });\n logger.info(\"Starting spawned session child\", {\n mode: CONVEYOR_MODE,\n sessionId: spawnedSessionId,\n });\n process.on(\"SIGTERM\", () => {\n shuttingDown = true;\n childRunner.stop();\n });\n process.on(\"SIGINT\", () => {\n shuttingDown = true;\n childRunner.stop();\n });\n await childRunner.run();\n const childError = childRunner.finalState === \"error\";\n logAgentExit(childError ? \"error\" : \"clean\", {\n exitCode: childError ? 1 : 0,\n finalState: childRunner.finalState ?? undefined,\n });\n process.exit(childError ? 1 : 0);\n}\n\nlogger.info(\"Starting agent\", { mode: CONVEYOR_MODE });\n\n// Claudespace pods: longer idle timeout to stay alive for incoming messages.\n// Non-claudespace environments (local, workspace, GitHub Codespaces) have\n// persistent state and don't need the periodic WIP commit safety net, so\n// disable the git flush timer for them.\nconst lifecycleOverrides = process.env.CLAUDESPACE_NAME\n ? { idleTimeoutMs: 60 * 60 * 1000 }\n : { gitFlushIntervalMs: 0 };\n\nconst runner = new SessionRunner(\n {\n connection: {\n apiUrl: conveyorApiUrl ?? \"\",\n taskToken: CONVEYOR_TASK_TOKEN,\n // CONVEYOR_SESSION_ID is the CodespaceSession ID for BaseService ACL.\n // Falls back to CONVEYOR_TASK_ID for backward compat (codespace bootstrap sets only task ID).\n sessionId: process.env.CONVEYOR_SESSION_ID ?? CONVEYOR_TASK_ID,\n runnerMode: CONVEYOR_MODE,\n },\n runnerMode: CONVEYOR_MODE,\n isAuto: CONVEYOR_IS_AUTO,\n workspaceDir: CONVEYOR_WORKSPACE,\n agentMode: CONVEYOR_AGENT_MODE as import(\"@project/shared\").AgentMode | undefined,\n lifecycle: lifecycleOverrides,\n },\n {\n onStatusChange: (status: AgentRunnerStatus) => {\n logger.info(\"Status changed\", { status });\n },\n onEvent: (event: Record<string, unknown>) => {\n const detail =\n (event.message as string) ?? (event.content as string) ?? (event.summary as string) ?? \"\";\n if (detail) {\n logger.info(detail, { eventType: event.type as string });\n }\n },\n },\n);\n\n// Same-pod review children (session:spawnReview). Wired only for the builder\n// (\"task\") runner mode below — a review child must never recursively spawn.\nconst reviewChildren = new ReviewChildSupervisor(runner.connection, CONVEYOR_WORKSPACE);\n\n// Same-pod TUI/shell children (session:spawnTui). Wired for builder-shaped\n// runners (task + pack) below — spawned children run adhoc/shell modes, which\n// exit above before this block, so recursion is impossible.\nconst sessionChildren = new SessionChildSupervisor(runner.connection, CONVEYOR_WORKSPACE);\n\nlet shutdownSignal: \"SIGTERM\" | \"SIGINT\" | undefined;\nlet workspaceCommandSupervisor: WorkspaceCommandSupervisor | null = null;\nlet shutdownCompletion: Promise<void> | null = null;\n\nconst shutdownAgent = (signal: \"SIGTERM\" | \"SIGINT\") => {\n shuttingDown = true;\n logger.info(`Received ${signal}, flushing git and stopping agent`);\n const commandShutdown = stopWorkspaceCommands(workspaceCommandSupervisor);\n // Recorded (not logged yet) so the final agent_exit line — emitted once the\n // real exit code is known below — can still attribute the cause to this\n // signal. A graceful SIGTERM resolves runner.run() with finalState=\"finished\"\n // and exits 0, so guessing exitCode here up front would misreport it as 1.\n shutdownSignal = signal;\n // Flush WIP commit + push BEFORE stop() tears down the connection, since\n // the token-refresh RPC needs a live socket. Then stop the runner.\n shutdownCompletion ??= (async () => {\n try {\n await Promise.all([reviewChildren.stopAll(), sessionChildren.stopAll()]);\n } catch {\n /* best-effort */\n }\n try {\n await runner.flushGitOnShutdown();\n } finally {\n await commandShutdown;\n runner.stop();\n }\n })();\n void shutdownCompletion;\n setTimeout(() => {\n logger.warn(`Forcing exit after ${signal} timeout`);\n // The graceful flush/stop hung past the watchdog — emit directly (bypassing\n // the one-line guard in logAgentExit) since run() will never resolve to log\n // this exit itself.\n logger.warn(\n \"agent_exit\",\n buildAgentExitLog({\n reason: \"force_timeout\",\n exitCode: 1,\n signal,\n finalState: runner.finalState ?? undefined,\n uptimeSec: process.uptime(),\n identity: exitContext,\n }) as unknown as Record<string, unknown>,\n );\n process.exit(1);\n }, 45_000).unref();\n};\n\nprocess.on(\"SIGTERM\", () => shutdownAgent(\"SIGTERM\"));\nprocess.on(\"SIGINT\", () => shutdownAgent(\"SIGINT\"));\n\n// Connect first so setup/start output is forwarded to the API. The helper does\n// not release commands until preview discovery has captured its baseline and\n// re-checks synchronous shutdown intent after that await.\nworkspaceCommandSupervisor = await startWorkspaceCommandsAfterConnect({\n connect: () => runner.connect(),\n isShuttingDown: () => shutdownSignal !== undefined,\n create: () =>\n new WorkspaceCommandSupervisor({\n config: loadConveyorConfig(),\n workspaceDir: CONVEYOR_WORKSPACE,\n connection: runner.connection,\n }),\n});\nif (!workspaceCommandSupervisor) {\n logger.info(\"Agent stopped before workspace commands were started\");\n if (shutdownCompletion) await shutdownCompletion;\n logAgentExit(shutdownSignal ? \"signal\" : \"clean\", {\n exitCode: 0,\n signal: shutdownSignal,\n finalState: runner.finalState ?? undefined,\n });\n process.exit(0);\n}\n\n// Hold the supervisor's start-command launch until the core loop signals it's\n// live (session-runner.ts run(), just before the core-loop while) — see\n// workspace-command-supervisor.ts's loopReady gate.\nrunner.setWorkspaceCommands(workspaceCommandSupervisor);\n\n// Defense-in-depth: warn loudly if CONVEYOR_SESSION_ID decodes to a different\n// task than CONVEYOR_TASK_ID. Authoritative checks are server-side\n// (requireTaskAuth + partial-unique index on active CodespaceSessions). This\n// is a visibility net in case those regress — see the session-identity postmortem in\n// .claude/rules/agent-codespace.md.\nvoid checkSessionTaskIdentity({\n sessionId: process.env.CONVEYOR_SESSION_ID,\n taskId: CONVEYOR_TASK_ID,\n fetchSessionTaskId: async (sessionId) => {\n const ctx = await runner.connection.call(\"getTaskContext\", { sessionId });\n return ctx.id;\n },\n logger,\n});\n\n// Same-pod review: builder-shaped runners (task + pack) host review children.\n// The push arrives on the BUILDER's session room; the child binds the review\n// session via env overrides (its own JWT/sessionId, CONVEYOR_MODE=code-review).\nif (hostsSpawnedChildren(CONVEYOR_MODE)) {\n runner.connection.onSpawnReview((data) => {\n void reviewChildren.spawn(data).catch((err: unknown) => {\n logger.error(\"Review child spawn threw\", {\n error: err instanceof Error ? err.message : String(err),\n });\n runner.connection.reportReviewSpawnFailure(\n data.sessionId,\n err instanceof Error ? err.message : String(err),\n );\n });\n });\n}\n\n// Same-pod TUI/shell tabs: builder-shaped runners (task + pack) host spawned\n// children. The push arrives on the BUILDER's session room; each child binds\n// its own session via env overrides (JWT/sessionId, CONVEYOR_MODE=adhoc|shell).\nif (hostsSpawnedChildren(CONVEYOR_MODE)) {\n runner.connection.onSpawnTui((data) => {\n void sessionChildren.spawn(data).catch((err: unknown) => {\n logger.error(\"Session child spawn threw\", {\n error: err instanceof Error ? err.message : String(err),\n });\n runner.connection.reportSessionSpawnFailure(\n data.sessionId,\n err instanceof Error ? err.message : String(err),\n );\n });\n });\n}\n\n// Start the main agent lifecycle immediately in parallel with setup\n// (context fetch, mode resolution, core loop).\nrunner\n .run()\n .then(async () => {\n await stopWorkspaceCommands(workspaceCommandSupervisor);\n // Exit with code 0 for clean shutdown (entrypoint won't restart),\n // code 1 for errors (entrypoint will restart). A SIGTERM-initiated shutdown\n // resolves run() too (finalState=\"finished\"), so tag it \"signal\" rather\n // than \"clean\" — but the exit code still follows the real finalState, not\n // a guess made back when the signal first arrived.\n const errored = runner.finalState === \"error\";\n const reason: AgentExitReason = shutdownSignal ? \"signal\" : errored ? \"error\" : \"clean\";\n logAgentExit(reason, {\n exitCode: errored ? 1 : 0,\n signal: shutdownSignal,\n finalState: runner.finalState ?? undefined,\n });\n process.exit(errored ? 1 : 0);\n })\n .catch(async (error: unknown) => {\n await stopWorkspaceCommands(workspaceCommandSupervisor);\n const msg = error instanceof Error ? error.message : String(error);\n logger.error(\"Agent runner failed\", { error: msg });\n logAgentExit(\"error\", { exitCode: 1, finalState: runner.finalState ?? undefined });\n process.exit(1);\n });\n","import net from \"node:net\";\n\n/**\n * Sidecar readiness gate.\n *\n * Previously the pod entrypoint blocked on postgres/firebase coming up BEFORE it\n * launched the agent, so the agent's thinking loop paid for up to ~60s of\n * sidecar boot it never needed. That wait now lives here and runs inside the\n * agent's background setup IIFE — it gates only `startCommand` (which\n * genuinely needs a warm postgres), never the agent loop.\n *\n * Semantics deliberately match the old entrypoint: best-effort, NON-FATAL on\n * timeout (log a warning and continue), and a no-op when no sidecar env vars are\n * present. Per-target timeouts mirror what the entrypoint learned the hard way —\n * the firebase auth emulator cold-boots slowly and doesn't bind 9099 until ~50s\n * after its container starts, so it gets 60s.\n *\n * Postgres gets 120s: on a durable-sleep/pool pod the postgres sidecar restores\n * prior state, and an ungraceful previous pod death (e.g. OOMKill) leaves a torn\n * WAL that triggers crash recovery on boot. Cold boot + WAL replay routinely runs\n * past 30s, so the old deadline expired before postgres bound 5432 — setup's seed\n * then hit `DatabaseNotReachable` (P1001) and the whole dev env came up broken.\n */\n\nexport interface SidecarTarget {\n /** Human label for logs (e.g. \"postgres\"). */\n name: string;\n host: string;\n port: number;\n /** Per-target readiness deadline in ms (overridden by an explicit opts.timeoutMs). */\n timeoutMs?: number;\n}\n\nexport interface WaitForSidecarsOptions {\n /** Env to read targets from. Defaults to `process.env`. */\n env?: NodeJS.ProcessEnv;\n /** Progress sink (one line per message, no trailing newline). */\n onLog?: (message: string) => void;\n /** Force a single deadline for every target, overriding per-target defaults. */\n timeoutMs?: number;\n /** Delay between probe attempts in ms. */\n pollIntervalMs?: number;\n /** TCP probe seam — returns true once the target accepts a connection. */\n probe?: (target: SidecarTarget, signal?: AbortSignal) => Promise<boolean>;\n /** Optional shutdown signal. Aborting rejects with AbortError. */\n signal?: AbortSignal;\n}\n\nconst POSTGRES_TIMEOUT_MS = 120_000;\nconst FIREBASE_TIMEOUT_MS = 60_000;\nconst FALLBACK_TIMEOUT_MS = 30_000;\nconst DEFAULT_SIDECAR_POLL_INTERVAL_MS = 1_000;\nconst DEFAULT_PROBE_TIMEOUT_MS = 2_000;\n\nconst POSTGRES_DEFAULT_PORT = 5432;\nconst FIREBASE_DEFAULT_PORT = 9099;\n\nfunction parseHostPort(value: string, defaultPort: number): { host: string; port: number } | null {\n const trimmed = value.trim().replace(/^[a-z]+:\\/\\//i, \"\");\n if (!trimmed) return null;\n const idx = trimmed.lastIndexOf(\":\");\n if (idx === -1) {\n return { host: trimmed, port: defaultPort };\n }\n const host = trimmed.slice(0, idx) || \"localhost\";\n const port = Number(trimmed.slice(idx + 1));\n return { host, port: Number.isFinite(port) ? port : defaultPort };\n}\n\n/**\n * Resolve the sidecar targets the agent should wait for from env. Mirrors the\n * entrypoint's conditions: postgres when `DATABASE_URL` is set, firebase auth\n * emulator when `FIREBASE_AUTH_EMULATOR_HOST` is set.\n */\nexport function resolveSidecarTargets(env: NodeJS.ProcessEnv = process.env): SidecarTarget[] {\n const targets: SidecarTarget[] = [];\n\n const databaseUrl = env.DATABASE_URL;\n if (databaseUrl) {\n try {\n const url = new URL(databaseUrl);\n const host = url.hostname || \"localhost\";\n const port = url.port ? Number(url.port) : POSTGRES_DEFAULT_PORT;\n if (Number.isFinite(port)) {\n targets.push({ name: \"postgres\", host, port, timeoutMs: POSTGRES_TIMEOUT_MS });\n }\n } catch {\n // Unparseable DATABASE_URL — skip rather than crash the setup path.\n }\n }\n\n const firebaseHost = env.FIREBASE_AUTH_EMULATOR_HOST;\n if (firebaseHost) {\n const parsed = parseHostPort(firebaseHost, FIREBASE_DEFAULT_PORT);\n if (parsed) {\n targets.push({\n name: \"firebase auth emulator\",\n host: parsed.host,\n port: parsed.port,\n timeoutMs: FIREBASE_TIMEOUT_MS,\n });\n }\n }\n\n return targets;\n}\n\nfunction abortError(): Error {\n const error = new Error(\"Operation aborted\");\n error.name = \"AbortError\";\n return error;\n}\n\nfunction throwIfAborted(signal?: AbortSignal): void {\n if (signal?.aborted) throw abortError();\n}\n\nfunction defaultProbe(target: SidecarTarget, signal?: AbortSignal): Promise<boolean> {\n throwIfAborted(signal);\n return new Promise((resolve) => {\n let settled = false;\n const socket = net.createConnection({ host: target.host, port: target.port });\n const done = (ok: boolean) => {\n if (settled) return;\n settled = true;\n socket.destroy();\n signal?.removeEventListener(\"abort\", onAbort);\n resolve(ok);\n };\n const onAbort = (): void => done(false);\n socket.once(\"connect\", () => done(true));\n socket.once(\"error\", () => done(false));\n socket.setTimeout(DEFAULT_PROBE_TIMEOUT_MS, () => done(false));\n signal?.addEventListener(\"abort\", onAbort, { once: true });\n });\n}\n\nconst delay = (ms: number, signal?: AbortSignal): Promise<void> => {\n throwIfAborted(signal);\n return new Promise((resolve, reject) => {\n const timer = setTimeout(() => {\n signal?.removeEventListener(\"abort\", onAbort);\n resolve();\n }, ms);\n const onAbort = (): void => {\n clearTimeout(timer);\n reject(abortError());\n };\n signal?.addEventListener(\"abort\", onAbort, { once: true });\n });\n};\n\nfunction raceWithAbort<T>(promise: Promise<T>, signal?: AbortSignal): Promise<T> {\n if (!signal) return promise;\n throwIfAborted(signal);\n return new Promise((resolve, reject) => {\n const onAbort = (): void => reject(abortError());\n signal.addEventListener(\"abort\", onAbort, { once: true });\n void promise.then(\n (value) => {\n signal.removeEventListener(\"abort\", onAbort);\n resolve(value);\n },\n (error: unknown) => {\n signal.removeEventListener(\"abort\", onAbort);\n reject(error);\n },\n );\n });\n}\n\nasync function waitForTarget(\n target: SidecarTarget,\n opts: {\n onLog: (message: string) => void;\n timeoutMs?: number;\n pollIntervalMs: number;\n probe: (target: SidecarTarget, signal?: AbortSignal) => Promise<boolean>;\n signal?: AbortSignal;\n },\n): Promise<void> {\n const { onLog, pollIntervalMs, probe, signal } = opts;\n const timeoutMs = opts.timeoutMs ?? target.timeoutMs ?? FALLBACK_TIMEOUT_MS;\n const deadline = Date.now() + timeoutMs;\n onLog(`Waiting for ${target.name} on ${target.host}:${target.port}...`);\n\n while (true) {\n throwIfAborted(signal);\n if (await raceWithAbort(probe(target, signal), signal)) {\n onLog(`${target.name} is ready`);\n return;\n }\n if (Date.now() >= deadline) {\n onLog(\n `WARNING: ${target.name} not ready after ${Math.round(timeoutMs / 1000)}s, continuing anyway`,\n );\n return;\n }\n await delay(pollIntervalMs, signal);\n }\n}\n\n/**\n * Block until every configured sidecar is reachable (or its per-target deadline\n * elapses). Resolves immediately when no sidecar env vars are set. Readiness\n * failures remain non-fatal; an explicit shutdown abort rejects with AbortError.\n */\nexport async function waitForSidecars(opts: WaitForSidecarsOptions = {}): Promise<void> {\n const {\n env = process.env,\n onLog = () => {},\n timeoutMs,\n pollIntervalMs = DEFAULT_SIDECAR_POLL_INTERVAL_MS,\n probe = defaultProbe,\n signal,\n } = opts;\n\n throwIfAborted(signal);\n\n const targets = resolveSidecarTargets(env);\n if (targets.length === 0) return;\n\n await Promise.all(\n targets.map((target) =>\n waitForTarget(target, { onLog, timeoutMs, pollIntervalMs, probe, signal }),\n ),\n );\n}\n","import { basename, dirname, join } from \"node:path\";\nimport { workspacePathExists } from \"../workbench/fs.js\";\n\n/**\n * Reconcile the pod's local database with the schema in the checked-out tree.\n *\n * A pod's Postgres is provisioned at IMAGE-BAKE time by the project's\n * `setupCommand` and then carried in the image/checkpoint\n * (`claudespace/methods/build-steps.ts`). Nothing on the boot path used to\n * reconcile that database against the schema in the freshly checked-out repo,\n * so every pod booted between a migration merging and the next bake came up\n * broken: the app 500s on every query touching the new column, and the board\n * renders \"Displaying 0 results\" with no error. Observed 2026-07-29 —\n * `tasks.parent_branch_merged_at` on a pod baked 75 minutes after the\n * migration merged; the in-pod database had no `_prisma_migrations` table at\n * all, so there was no record of which schema it corresponded to.\n *\n * `prisma db push` diffs against the live database and applies exactly the\n * delta, so an already-current pod pays one short command (~500ms measured\n * in-pod) and a stale one is repaired before the app ever starts. This is the\n * same treatment release 07.128 gave `scripts/reset-dev.sh` for the\n * developer-local database.\n *\n * Ordering matters: this must run AFTER the agent's authoritative task-branch\n * checkout (`ensureOnTaskBranch`) — git prep only refreshes the origin remote,\n * so a pre-checkout sync would push the *baked* schema and fix nothing — and\n * BEFORE the start command, so the app never boots against a stale database.\n */\n\nexport type SchemaSyncOutcome = \"skipped\" | \"synced\" | \"failed\";\n\nexport interface SchemaSyncPlan {\n /** Shell command, run through the same executor as the start command. */\n command: string;\n /** Absolute cwd the command runs in. */\n cwd: string;\n /** Why this plan was chosen — a boot-log breadcrumb. */\n source: \"override\" | \"prisma\";\n}\n\nexport type ShellCommandRunner = (\n command: string,\n cwd: string,\n onOutput: (stream: \"stdout\" | \"stderr\", data: string) => void,\n signal?: AbortSignal,\n) => Promise<void>;\n\n/** Repo layouts we know how to sync, most specific first. */\nconst PRISMA_SCHEMA_CANDIDATES = [\n \"packages/db/prisma/schema.prisma\",\n \"prisma/schema.prisma\",\n \"apps/api/prisma/schema.prisma\",\n \"packages/db/schema.prisma\",\n];\n\n/**\n * Deliberately WITHOUT `--accept-data-loss`, unlike `reset:dev`. Two reasons,\n * both verified in-pod:\n * - The additive case this exists for (a column added since the bake) needs no\n * such flag; a destructive diff means the pod database drifted in a way a\n * human should see, and failing loudly beats dropping columns unattended.\n * - Prisma's AI-agent guard refuses `--accept-data-loss` outright when the\n * process env carries Claude Code's markers. Plain `db push` is not gated,\n * so this stays working however the boot path inherits its env — no\n * marker-scrubbing, no consent variable.\n * Non-interactive is safe either way: prisma exits non-zero with a message\n * rather than blocking on a prompt when it detects data loss.\n */\nconst PRISMA_DB_PUSH = \"bunx prisma db push\";\n\n/** Generous: a cold `bunx` fetch plus a multi-table push. Bounded so a wedged\n * command can never hold the start command hostage. */\nexport const SCHEMA_SYNC_TIMEOUT_MS = 180_000;\n\nfunction depsInclude(rawDeps: string | undefined, dep: string): boolean {\n return (rawDeps ?? \"\")\n .split(\",\")\n .map((entry) => entry.trim())\n .includes(dep);\n}\n\nfunction isDisabled(env: NodeJS.ProcessEnv): boolean {\n const flag = env.CONVEYOR_DB_SCHEMA_SYNC?.trim().toLowerCase();\n return flag === \"0\" || flag === \"false\";\n}\n\n/** The prisma CLI resolves `prisma/schema.prisma` relative to its cwd, so run\n * from the package root — one level up from a `prisma/` dir, otherwise the\n * directory holding the schema. */\nfunction packageRootForSchema(schemaPath: string): string {\n const dir = dirname(schemaPath);\n return basename(dir) === \"prisma\" ? dirname(dir) : dir;\n}\n\nexport interface ResolveSchemaSyncPlanOptions {\n workspaceDir: string;\n env: NodeJS.ProcessEnv;\n /** Injected for tests; defaults to the workbench-aware existence check so\n * split-mode pods probe the container that actually holds the repo. */\n pathExists?: (path: string) => Promise<boolean>;\n}\n\n/**\n * Decide what (if anything) to run. Returns null — a silent skip — for every\n * environment that isn't a database-backed pod: GitHub Codespaces (no\n * `CONVEYOR_DEPS`, and `codespace-setup.sh` already pushes), pods without the\n * `postgresql` dep, and repos with no prisma schema we recognize.\n */\nexport async function resolveSchemaSyncPlan(\n options: ResolveSchemaSyncPlanOptions,\n): Promise<SchemaSyncPlan | null> {\n const { workspaceDir, env } = options;\n const pathExists = options.pathExists ?? workspacePathExists;\n if (isDisabled(env)) return null;\n\n // Escape hatch for projects whose sync isn't `prisma db push` (or that need\n // it wrapped, e.g. in an env loader). Trusted like startCommand: it is\n // project settings, not agent-authored.\n const override = env.CONVEYOR_DB_SCHEMA_SYNC_COMMAND?.trim();\n if (override) return { command: override, cwd: workspaceDir, source: \"override\" };\n\n if (!depsInclude(env.CONVEYOR_DEPS, \"postgresql\")) return null;\n // Without a target there is nothing to push to, and prisma would fail on\n // every boot. Every claudespace pod carrying the postgresql dep has one.\n if (!env.DATABASE_URL?.trim()) return null;\n\n for (const relative of PRISMA_SCHEMA_CANDIDATES) {\n const schemaPath = join(workspaceDir, relative);\n if (await pathExists(schemaPath)) {\n return { command: PRISMA_DB_PUSH, cwd: packageRootForSchema(schemaPath), source: \"prisma\" };\n }\n }\n return null;\n}\n\nexport interface RunDbSchemaSyncOptions extends ResolveSchemaSyncPlanOptions {\n runCommand: ShellCommandRunner;\n onOutput: (stream: \"stdout\" | \"stderr\", data: string) => void;\n /** Supervisor shutdown — aborts the command's process group. */\n signal?: AbortSignal;\n timeoutMs?: number;\n}\n\n/**\n * Resolve and run the sync. Never throws and never rejects: a failure here\n * must not stop the start command from launching (a stale database is bad, no\n * app at all is worse), so the outcome is returned for the caller to surface.\n */\nexport async function runDbSchemaSync(options: RunDbSchemaSyncOptions): Promise<SchemaSyncOutcome> {\n let plan: SchemaSyncPlan | null = null;\n try {\n plan = await resolveSchemaSyncPlan(options);\n } catch {\n return \"skipped\";\n }\n if (!plan) return \"skipped\";\n\n const { onOutput, runCommand } = options;\n onOutput(\"stdout\", `[db] syncing schema (${plan.source}): ${plan.command}\\n`);\n const controller = new AbortController();\n const abort = (): void => controller.abort();\n options.signal?.addEventListener(\"abort\", abort, { once: true });\n const timer = setTimeout(abort, options.timeoutMs ?? SCHEMA_SYNC_TIMEOUT_MS);\n timer.unref();\n try {\n await runCommand(plan.command, plan.cwd, onOutput, controller.signal);\n onOutput(\"stdout\", \"[db] schema in sync\\n\");\n return \"synced\";\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n onOutput(\"stderr\", `[db] schema sync failed: ${message}\\n`);\n return \"failed\";\n } finally {\n clearTimeout(timer);\n options.signal?.removeEventListener(\"abort\", abort);\n }\n}\n","import { join } from \"node:path\";\nimport { readWorkspaceBytes, statWorkspacePath, workspacePathExists } from \"../workbench/fs.js\";\n\n/**\n * Reconcile the pod's installed dependencies with the checked-out tree.\n *\n * A pod's `node_modules` is produced at IMAGE-BAKE time and carried in the\n * image/checkpoint. Nothing on the boot path used to check that it survived,\n * so a pod whose baked tree was missing (or shadowed by a fresh clone landing\n * over it) came up with no dependencies at all. The only signal was the start\n * command's generic `start command exited with code 1`, and every agent then\n * rediscovered the cause and hand-installed 4000+ packages before it could do\n * any work — observed on three consecutive pods, 2026-08-12.\n *\n * This is the dependency twin of `db-schema-sync.ts`, and it runs in the same\n * window for the same reason: AFTER the agent's authoritative task-branch\n * checkout (which `loopReady` implies) so it compares against the real tree,\n * and BEFORE the start command so the app never boots without its\n * dependencies.\n *\n * Two conditions trigger an install, and both name themselves in the log:\n *\n * - **`missing_node_modules`** — there is a `package.json` but no\n * `node_modules`. This is the observed failure; no fingerprint is needed to\n * know it is broken.\n * - **`lockfile_drift`** — `.conveyor/prebake-cache.json` carries the\n * `bunLockCrc` sentinel the bake stamps (`cksum bun.lock` →\n * `\"<crc>:<bytes>\"`, `scripts/conveyor-prebake-cache.sh`) and the\n * checked-out `bun.lock` no longer matches it. The sentinel was\n * written-but-never-read until now; reading it is what turns \"the bake is\n * older than this branch\" from an agent's guess into a boot-time fact.\n *\n * Best-effort by design, exactly like the schema sync: a failed install must\n * not stop the start command from launching, so the outcome is returned for\n * the caller to announce rather than thrown.\n */\n\nexport type DepsSyncOutcome = \"skipped\" | \"installed\" | \"failed\";\n\n/** Why an install was scheduled. Surfaced verbatim in the boot log. A project\n * override replaces the COMMAND only, never the trigger, so it is not a\n * reason of its own. */\nexport type DepsSyncReason = \"missing_node_modules\" | \"lockfile_drift\";\n\nexport interface DepsSyncPlan {\n /** Shell command, run through the same executor as the schema sync. */\n command: string;\n /** Absolute cwd the command runs in — always the workspace root. */\n cwd: string;\n /** The condition that scheduled this install. */\n reason: DepsSyncReason;\n /** One line a human can act on, without reading the install output. */\n detail: string;\n}\n\nexport type ShellCommandRunner = (\n command: string,\n cwd: string,\n onOutput: (stream: \"stdout\" | \"stderr\", data: string) => void,\n signal?: AbortSignal,\n) => Promise<void>;\n\n/**\n * A repo-local installer wrapper is preferred over a bare `bun install`\n * because it owns the registry-auth step a private scope needs (Conveyor's\n * `scripts/install-deps.sh` writes `.npmrc`/`bunfig.toml` from Secret Manager\n * before installing). Most specific first.\n */\nconst INSTALLER_SCRIPT_CANDIDATES = [\"scripts/install-deps.sh\"];\n\n/** The fallback when a repo ships no installer wrapper. Frozen so a boot-time\n * repair can never rewrite the lockfile under the agent. */\nconst BUN_INSTALL = \"bun install --frozen-lockfile\";\n\n/** A from-scratch install of a large monorepo (~4000 packages, native builds\n * included) measured in minutes, so this is deliberately generous. Bounded so\n * a wedged install can never hold the start command hostage forever. */\nexport const DEPS_SYNC_TIMEOUT_MS = 900_000;\n\n/** The env var the baked `.npmrc` interpolates for the private Artifact\n * Registry pull-through cache that serves `@fortawesome`. Without it a\n * from-scratch install 403s on those packages — the exact secondary failure\n * every hand-install hit. */\nconst REGISTRY_KEY_ENV = \"NPM_CACHE_READER_KEY\";\n\nfunction isDisabled(env: NodeJS.ProcessEnv): boolean {\n const flag = env.CONVEYOR_DEPS_SYNC?.trim().toLowerCase();\n return flag === \"0\" || flag === \"false\";\n}\n\n/**\n * POSIX `cksum`: CRC-32 over the bytes with the byte length folded in, then\n * complemented. Reimplemented rather than shelled out so the fingerprint check\n * costs no process spawn and works identically in split-mode pods, where the\n * repo is only reachable through the workbench file API.\n */\nconst CKSUM_POLYNOMIAL = 0x04c11db7;\n\nconst CKSUM_TABLE = ((): Uint32Array => {\n const table = new Uint32Array(256);\n for (let index = 0; index < 256; index++) {\n let value = index << 24;\n for (let bit = 0; bit < 8; bit++) {\n value = value & 0x80000000 ? ((value << 1) ^ CKSUM_POLYNOMIAL) >>> 0 : (value << 1) >>> 0;\n }\n table[index] = value >>> 0;\n }\n return table;\n})();\n\nexport function posixCksum(bytes: Uint8Array): number {\n let crc = 0;\n for (const byte of bytes) {\n crc = ((crc << 8) ^ (CKSUM_TABLE[((crc >>> 24) ^ byte) & 0xff] as number)) >>> 0;\n }\n for (let length = bytes.length; length > 0; length >>>= 8) {\n crc = ((crc << 8) ^ (CKSUM_TABLE[((crc >>> 24) ^ (length & 0xff)) & 0xff] as number)) >>> 0;\n }\n return ~crc >>> 0;\n}\n\n/** The exact string the bake stamps into the sentinel. */\nexport function bunLockFingerprint(bytes: Uint8Array): string {\n return `${posixCksum(bytes)}:${bytes.length}`;\n}\n\nexport interface ResolveDepsSyncPlanOptions {\n workspaceDir: string;\n env: NodeJS.ProcessEnv;\n /** Injected for tests; defaults to the workbench-aware existence check so\n * split-mode pods probe the container that actually holds the repo. */\n pathExists?: (path: string) => Promise<boolean>;\n /** Injected for tests; defaults to the workbench-aware directory check. A\n * `node_modules` that exists as something other than a directory is as\n * broken as one that is absent. */\n dirExists?: (path: string) => Promise<boolean>;\n /** Injected for tests; defaults to the workbench-aware byte read. */\n readBytes?: (path: string) => Promise<Uint8Array>;\n}\n\nasync function defaultDirExists(path: string): Promise<boolean> {\n return (await statWorkspacePath(path)).isDirectory;\n}\n\n/** The bake sentinel's `bunLockCrc`, or null when there is no sentinel, no\n * lockfile, or the sentinel predates the field. Never throws — an unreadable\n * or malformed sentinel means \"no fingerprint to compare\", not \"reinstall\". */\nasync function readLockDrift(\n options: Required<Pick<ResolveDepsSyncPlanOptions, \"workspaceDir\">> & {\n readBytes: (path: string) => Promise<Uint8Array>;\n },\n): Promise<{ baked: string; actual: string } | null> {\n const { workspaceDir, readBytes } = options;\n let baked: string;\n try {\n const raw = await readBytes(join(workspaceDir, \".conveyor/prebake-cache.json\"));\n const parsed: unknown = JSON.parse(Buffer.from(raw).toString(\"utf8\"));\n const value = (parsed as { bunLockCrc?: unknown } | null)?.bunLockCrc;\n if (typeof value !== \"string\" || !value) return null;\n baked = value;\n } catch {\n return null;\n }\n\n try {\n const actual = bunLockFingerprint(await readBytes(join(workspaceDir, \"bun.lock\")));\n return actual === baked ? null : { baked, actual };\n } catch {\n return null;\n }\n}\n\n/**\n * Decide what (if anything) to install. Returns null — a silent skip — for\n * every healthy tree and for every environment that is not a JS repo. The\n * common case pays two stat calls plus one 300KB read, all local.\n */\nexport async function resolveDepsSyncPlan(\n options: ResolveDepsSyncPlanOptions,\n): Promise<DepsSyncPlan | null> {\n const { workspaceDir, env } = options;\n const pathExists = options.pathExists ?? workspacePathExists;\n const dirExists = options.dirExists ?? defaultDirExists;\n const readBytes = options.readBytes ?? readWorkspaceBytes;\n if (isDisabled(env)) return null;\n\n // Nothing to reconcile in a repo with no JS package manifest.\n if (!(await pathExists(join(workspaceDir, \"package.json\")))) return null;\n\n // Escape hatch for projects whose install isn't bun-shaped (or that need it\n // wrapped, e.g. in an env loader). Trusted like startCommand: it is project\n // settings, not agent-authored. It only replaces the COMMAND — the\n // conditions below still decide whether an install happens at all.\n const override = env.CONVEYOR_DEPS_SYNC_COMMAND?.trim();\n\n const resolveCommand = async (): Promise<string> => {\n if (override) return override;\n for (const relative of INSTALLER_SCRIPT_CANDIDATES) {\n if (await pathExists(join(workspaceDir, relative))) return `bash ${relative}`;\n }\n return BUN_INSTALL;\n };\n\n if (!(await dirExists(join(workspaceDir, \"node_modules\")))) {\n return {\n command: await resolveCommand(),\n cwd: workspaceDir,\n reason: \"missing_node_modules\",\n detail: \"the pod booted with no node_modules — the baked dependency tree is absent\",\n };\n }\n\n const drift = await readLockDrift({ workspaceDir, readBytes });\n if (drift) {\n return {\n command: await resolveCommand(),\n cwd: workspaceDir,\n reason: \"lockfile_drift\",\n detail: `bun.lock changed since the image bake (baked ${drift.baked}, checked out ${drift.actual})`,\n };\n }\n\n return null;\n}\n\nexport interface RunDepsSyncOptions extends ResolveDepsSyncPlanOptions {\n runCommand: ShellCommandRunner;\n onOutput: (stream: \"stdout\" | \"stderr\", data: string) => void;\n /** Supervisor shutdown — aborts the command's process group. */\n signal?: AbortSignal;\n timeoutMs?: number;\n}\n\nexport interface DepsSyncResult {\n outcome: DepsSyncOutcome;\n /** Set when `outcome` is \"failed\" — a complete, actionable sentence for the\n * card's setup log. Never a bare exit code. */\n message?: string;\n}\n\n/**\n * Build the failure message. The point of this whole module is that a broken\n * pod says WHY, so the message always carries the trigger, the command, and\n * the underlying error — plus the one missing-credential cause that produced a\n * confusing second failure on every hand-install.\n */\nfunction describeFailure(plan: DepsSyncPlan, error: unknown, env: NodeJS.ProcessEnv): string {\n const cause = error instanceof Error ? error.message : String(error);\n const parts = [\n `Dependency install failed (${plan.reason}): ${plan.detail}.`,\n `Ran \\`${plan.command}\\` in ${plan.cwd} — ${cause}.`,\n ];\n if (!env[REGISTRY_KEY_ENV]?.trim()) {\n parts.push(\n `${REGISTRY_KEY_ENV} is not set on this pod, so packages on the private registry cache cannot be fetched — set it as a project secret.`,\n );\n }\n return parts.join(\" \");\n}\n\n/**\n * Resolve and run the install. Never throws and never rejects: a failure here\n * must not stop the start command from launching (a pod with a precise error\n * on the card is recoverable, a pod with no app at all and no explanation is\n * what this replaces).\n */\nexport async function runDepsSync(options: RunDepsSyncOptions): Promise<DepsSyncResult> {\n let plan: DepsSyncPlan | null = null;\n try {\n plan = await resolveDepsSyncPlan(options);\n } catch {\n return { outcome: \"skipped\" };\n }\n if (!plan) return { outcome: \"skipped\" };\n\n const { onOutput, runCommand, env } = options;\n onOutput(\"stdout\", `[deps] ${plan.detail}\\n`);\n onOutput(\"stdout\", `[deps] installing (${plan.reason}): ${plan.command}\\n`);\n const controller = new AbortController();\n const abort = (): void => controller.abort();\n options.signal?.addEventListener(\"abort\", abort, { once: true });\n const timer = setTimeout(abort, options.timeoutMs ?? DEPS_SYNC_TIMEOUT_MS);\n timer.unref();\n try {\n await runCommand(plan.command, plan.cwd, onOutput, controller.signal);\n onOutput(\"stdout\", \"[deps] dependencies installed\\n\");\n return { outcome: \"installed\" };\n } catch (error) {\n const message = describeFailure(plan, error, env);\n onOutput(\"stderr\", `[deps] ${message}\\n`);\n return { outcome: \"failed\", message };\n } finally {\n clearTimeout(timer);\n options.signal?.removeEventListener(\"abort\", abort);\n }\n}\n","import {\n buildSessionPreviewPorts,\n loadForwardPorts,\n type ConveyorConfig,\n type ForwardPortsResult,\n} from \"./config.js\";\nimport { awaitGitReady, type GitReadyState } from \"./git-ready.js\";\nimport {\n runSetupCommand,\n runStartCommand,\n terminateProcessGroup,\n type ManagedChildProcess,\n} from \"./commands.js\";\nimport {\n runDbSchemaSync,\n type SchemaSyncOutcome,\n type ShellCommandRunner,\n} from \"./db-schema-sync.js\";\nimport { runDepsSync, type DepsSyncResult } from \"./deps-sync.js\";\nimport { waitForSidecars } from \"./sidecars.js\";\nimport { workbenchEnabled } from \"../workbench/mode.js\";\nimport { getWorkbenchClient } from \"../workbench/client.js\";\nimport { reportBootMilestone, type PodReportableBootStep } from \"./boot-milestone.js\";\n\ntype OutputStream = \"stdout\" | \"stderr\";\ntype StartCommandChild = ManagedChildProcess;\n\n/**\n * Split-mode pods run every workspace command in the workbench container;\n * everywhere else the local spawn paths are used unchanged. Resolved per\n * supervisor construction (not import) so tests can flip the env.\n */\nfunction defaultCommandExecutors(): {\n runStartCommand: (\n cmd: string,\n cwd: string,\n onOutput: (stream: OutputStream, data: string) => void,\n ) => StartCommandChild;\n /** Awaited, streamed shell exec — the schema sync's runner. NOT the\n * project's setupCommand, which is bake-only and never runs in a pod. */\n runShellCommand: ShellCommandRunner;\n} {\n if (workbenchEnabled()) {\n const client = getWorkbenchClient();\n return {\n runStartCommand: (cmd, cwd, onOutput) => client.runStartCommand(cmd, cwd, onOutput),\n runShellCommand: (cmd, cwd, onOutput, signal) =>\n client.runSetupCommand(cmd, cwd, onOutput, signal),\n };\n }\n return { runStartCommand, runShellCommand: runSetupCommand };\n}\n\nexport interface WorkspaceCommandConnection {\n sendEvent(event: { type: string; [key: string]: unknown }): void;\n onRunStartCommand(callback: () => void): void;\n}\n\nexport interface WorkspaceCommandSupervisorOptions {\n config: ConveyorConfig | null;\n workspaceDir: string;\n connection: WorkspaceCommandConnection;\n env?: NodeJS.ProcessEnv;\n awaitGitReady?: (options: {\n onLog: (message: string) => void;\n signal: AbortSignal;\n }) => Promise<GitReadyState>;\n waitForSidecars?: (options: {\n onLog: (message: string) => void;\n signal: AbortSignal;\n }) => Promise<void>;\n runStartCommand?: (\n cmd: string,\n cwd: string,\n onOutput: (stream: OutputStream, data: string) => void,\n ) => StartCommandChild;\n /** Reconcile the pod's baked database with the checked-out schema. Injected\n * for tests; the default resolves a plan from the env + repo layout. */\n syncDbSchema?: (options: {\n onOutput: (stream: OutputStream, data: string) => void;\n signal: AbortSignal;\n }) => Promise<SchemaSyncOutcome>;\n /** Reconcile the pod's baked node_modules with the checked-out tree.\n * Injected for tests; the default resolves a plan from the repo layout. */\n syncDeps?: (options: {\n onOutput: (stream: OutputStream, data: string) => void;\n signal: AbortSignal;\n }) => Promise<DepsSyncResult>;\n loadForwardPorts?: (workspaceDir: string) => Promise<ForwardPortsResult>;\n writeOutput?: (stream: OutputStream, data: string) => void;\n terminateStartCommand?: (child: StartCommandChild) => void | Promise<void>;\n /** Report a pod-observed boot milestone to the API. Injected for tests. */\n reportBootMilestone?: (key: PodReportableBootStep) => void;\n}\n\nconst defaultWriteOutput = (stream: OutputStream, data: string): void => {\n (stream === \"stderr\" ? process.stderr : process.stdout).write(data);\n};\n\nexport function stopWorkspaceCommands(\n supervisor: { stop(): Promise<void> } | null | undefined,\n): Promise<void> {\n return supervisor?.stop() ?? Promise.resolve();\n}\n\nexport interface WorkspaceCommandStartupOptions<T extends { start(): void }> {\n connect: () => Promise<boolean>;\n isShuttingDown: () => boolean;\n create: () => T;\n}\n\n/**\n * Holds workspace commands behind both the runner's connection/baseline gate\n * and the CLI's synchronous shutdown intent. A signal can arrive while\n * connect() is awaiting discovery but before runner.stop() runs after the\n * graceful git flush; checking shutdown intent after the await closes that\n * window without constructing a supervisor.\n */\nexport async function startWorkspaceCommandsAfterConnect<T extends { start(): void }>(\n options: WorkspaceCommandStartupOptions<T>,\n): Promise<T | null> {\n const connected = await options.connect();\n if (!connected || options.isShuttingDown()) return null;\n const supervisor = options.create();\n supervisor.start();\n return supervisor;\n}\n\n/**\n * Owns setup and long-running workspace commands independently of the runner\n * that hosts them. start() is intentionally fire-and-forget: command failures\n * are user-visible events and never terminate the agent lifecycle.\n */\nexport class WorkspaceCommandSupervisor {\n private readonly abortController = new AbortController();\n private readonly expectedStartCommandStops = new WeakSet<StartCommandChild>();\n private readonly config: ConveyorConfig | null;\n private readonly workspaceDir: string;\n private readonly connection: WorkspaceCommandConnection;\n private readonly env: NodeJS.ProcessEnv;\n private readonly awaitGitReadyFn: NonNullable<WorkspaceCommandSupervisorOptions[\"awaitGitReady\"]>;\n private readonly waitForSidecarsFn: NonNullable<\n WorkspaceCommandSupervisorOptions[\"waitForSidecars\"]\n >;\n private readonly runStartCommandFn: NonNullable<\n WorkspaceCommandSupervisorOptions[\"runStartCommand\"]\n >;\n private readonly syncDbSchemaFn: NonNullable<WorkspaceCommandSupervisorOptions[\"syncDbSchema\"]>;\n private readonly syncDepsFn: NonNullable<WorkspaceCommandSupervisorOptions[\"syncDeps\"]>;\n private readonly loadForwardPortsFn: (workspaceDir: string) => Promise<ForwardPortsResult>;\n private readonly writeOutput: (stream: OutputStream, data: string) => void;\n private readonly terminateStartCommand: (child: StartCommandChild) => void | Promise<void>;\n private readonly reportBootMilestoneFn: (key: PodReportableBootStep) => void;\n\n private startCommandChild: StartCommandChild | null = null;\n private readonly liveStartCommandChildren = new Set<StartCommandChild>();\n private readonly startCommandTerminations = new WeakMap<StartCommandChild, Promise<void>>();\n private readonly startCommandEndPromises = new WeakMap<StartCommandChild, Promise<void>>();\n private readonly resolveStartCommandEnd = new WeakMap<StartCommandChild, () => void>();\n private readonly backgroundTasks = new Set<Promise<void>>();\n private startCommandQueue: Promise<void> = Promise.resolve();\n private shutdownPromise: Promise<void> | null = null;\n private startCommandLaunchRequested = false;\n private started = false;\n private stopped = false;\n /** Resolved by notifyLoopReady() once the PTY is live — the runner fires it\n * on the first harness event of the initial query (or when a prefill\n * parks), NOT after the first turn completes, so the app's start command\n * isn't held behind a long working turn. Also resolved by stop() if\n * shutdown arrives first — either way unblocks the awaiter in\n * runSetupAndStart so a supervisor stopped before the loop ever signals\n * doesn't hang its background task (and therefore stop()) forever. */\n private resolveLoopReady!: () => void;\n private readonly loopReady = new Promise<void>((resolve) => {\n this.resolveLoopReady = resolve;\n });\n\n constructor(options: WorkspaceCommandSupervisorOptions) {\n this.config = options.config;\n this.workspaceDir = options.workspaceDir;\n this.connection = options.connection;\n this.env = options.env ?? process.env;\n this.awaitGitReadyFn =\n options.awaitGitReady ??\n ((opts) =>\n awaitGitReady({\n onLog: opts.onLog,\n signal: opts.signal,\n }));\n this.waitForSidecarsFn =\n options.waitForSidecars ??\n ((opts) => waitForSidecars({ onLog: opts.onLog, signal: opts.signal }));\n const executors = defaultCommandExecutors();\n this.runStartCommandFn = options.runStartCommand ?? executors.runStartCommand;\n this.syncDbSchemaFn =\n options.syncDbSchema ??\n ((opts) =>\n runDbSchemaSync({\n workspaceDir: this.workspaceDir,\n env: this.env,\n runCommand: executors.runShellCommand,\n onOutput: opts.onOutput,\n signal: opts.signal,\n }));\n this.syncDepsFn =\n options.syncDeps ??\n ((opts) =>\n runDepsSync({\n workspaceDir: this.workspaceDir,\n env: this.env,\n runCommand: executors.runShellCommand,\n onOutput: opts.onOutput,\n signal: opts.signal,\n }));\n this.loadForwardPortsFn = options.loadForwardPorts ?? loadForwardPorts;\n this.writeOutput = options.writeOutput ?? defaultWriteOutput;\n this.terminateStartCommand = options.terminateStartCommand ?? terminateProcessGroup;\n this.reportBootMilestoneFn =\n options.reportBootMilestone ??\n ((key) => {\n // Fire-and-forget: never let a boot-meter report delay setup/start.\n void reportBootMilestone({ key, env: this.env });\n });\n }\n\n start(): void {\n if (this.started || this.stopped) return;\n this.started = true;\n this.connection.onRunStartCommand(() => this.restartStartCommand());\n\n if (this.config) {\n this.trackBackgroundTask(\n this.runSetupAndStart().catch((error: unknown) => this.reportUnexpectedError(error)),\n );\n }\n }\n\n /** Release the start-command launch — called once the runner's core loop\n * (the PTY) is live. Idempotent; resolving an already-settled promise is a\n * no-op, so a late/duplicate call (or one after stop() already resolved\n * it) is harmless. */\n notifyLoopReady(): void {\n this.resolveLoopReady();\n }\n\n stop(): Promise<void> {\n if (this.shutdownPromise) return this.shutdownPromise;\n this.stopped = true;\n // Unblock a runSetupAndStart() background task parked on `await\n // this.loopReady` — without this, stop() would await backgroundTasks\n // forever whenever shutdown lands before the loop ever signals ready.\n this.resolveLoopReady();\n this.abortController.abort();\n const backgroundTasks = [...this.backgroundTasks];\n const termination = this.terminateAllStartCommands();\n this.shutdownPromise = (async () => {\n await Promise.allSettled([termination, this.startCommandQueue, ...backgroundTasks]);\n await this.terminateAllStartCommands();\n })();\n return this.shutdownPromise;\n }\n\n private async runSetupAndStart(): Promise<void> {\n const gitState = await this.awaitGitReadyFn({\n onLog: (message) => this.forwardSetupOutput(\"stdout\", `[git] ${message}\\n`),\n signal: this.abortController.signal,\n });\n if (this.stopped) return;\n if (gitState === \"failed\" || gitState === \"timeout\") {\n this.connection.sendEvent({\n type: \"setup_error\",\n message: \"Workspace not ready — skipping setup/start\",\n });\n return;\n }\n // Repo is up to date. This used to report a \"git_ready\" milestone itself;\n // that's now the workbench's own \"repo_synced\" report (see\n // workbench-side reporting) — the supervisor no longer reports here.\n\n await this.waitForSidecarsFn({\n onLog: (message) => this.forwardSetupOutput(\"stdout\", `[sidecars] ${message}\\n`),\n signal: this.abortController.signal,\n });\n if (this.stopped) return;\n this.reportBootMilestoneFn(\"sidecars_ready\");\n\n // Hold the app until the PTY is live — Task 9: launching the start\n // command in parallel with agent boot let it win the CPU/git-lock race\n // against the agent during startup. Released on the first harness event\n // of the initial query (or a parked prefill), not at end of turn. See\n // notifyLoopReady().\n await this.loopReady;\n if (this.stopped) return;\n\n // Repair a dependency tree that the image bake never delivered, or that the\n // checked-out branch has since outgrown. Runs BEFORE the schema sync, which\n // needs an installed prisma, and before the start command, which is what\n // used to discover the problem — as a bare exit 1 that told nobody why.\n await this.syncDeps();\n if (this.stopped) return;\n\n // Repair a database baked before the checked-out tree's migrations landed.\n // Deliberately here and not earlier: git prep only refreshes the origin\n // remote, so before the agent's authoritative checkout (which loopReady\n // implies — SessionRunner step 3.5b) the schema on disk is still the baked\n // one and a sync would be a no-op. Best-effort by design — a stale\n // database is bad, no app at all is worse.\n await this.syncDbSchema();\n if (this.stopped) return;\n\n // The project's setupCommand runs at image-bake time (server-side Cloud\n // Build) and is never delivered to pods — the pod goes straight from\n // sidecars to start.\n const startCommandRunning = this.config?.startCommand\n ? await this.ensureStartCommandLaunched(this.config.startCommand)\n : false;\n if (this.stopped) return;\n // Start command launched (or there was none to launch) — the last boot\n // milestone the pod observes. Fires unconditionally so it stays the\n // terminal step for every project.\n this.reportBootMilestoneFn(\"start_command_launched\");\n\n const forwardPorts = await this.loadForwardPortsFn(this.workspaceDir);\n if (this.stopped) return;\n const previewPorts = buildSessionPreviewPorts(forwardPorts);\n this.connection.sendEvent({\n type: \"setup_complete\",\n startCommandRunning,\n ...(previewPorts.length > 0 ? { previewPorts } : {}),\n });\n }\n\n /** Run the dependency sync, forwarding its output as setup output so it lands\n * in the card's setup log. A failure is announced with its own cause rather\n * than thrown: the start command still launches, but the card now carries\n * the reason instead of a generic `start command exited with code 1`. */\n private async syncDeps(): Promise<void> {\n const result = await this.syncDepsFn({\n onOutput: (stream, data) => this.forwardSetupOutput(stream, data),\n signal: this.abortController.signal,\n });\n if (result.outcome !== \"failed\" || this.stopped) return;\n this.connection.sendEvent({\n type: \"setup_error\",\n message:\n result.message ??\n \"Dependency install failed — the start command will fail until dependencies are installed (see pod logs)\",\n });\n }\n\n /** Run the schema sync, forwarding its output as setup output so it lands in\n * the card's setup log. A failure is announced rather than thrown: it is the\n * exact condition that used to render as a silent \"Displaying 0 results\". */\n private async syncDbSchema(): Promise<void> {\n const outcome = await this.syncDbSchemaFn({\n onOutput: (stream, data) => this.forwardSetupOutput(stream, data),\n signal: this.abortController.signal,\n });\n if (outcome !== \"failed\" || this.stopped) return;\n this.connection.sendEvent({\n type: \"setup_error\",\n message:\n \"Database schema sync failed — the app may error on queries touching recently added columns (see pod logs)\",\n });\n }\n\n private restartStartCommand(): void {\n if (this.stopped || !this.config?.startCommand) return;\n this.connection.sendEvent({\n type: \"start_command_output\",\n stream: \"stdout\",\n data: \"[conveyor-agent] Restarting start command...\\n\",\n });\n void this.enqueueStartCommandReplacement(this.config.startCommand);\n }\n\n private async ensureStartCommandLaunched(command: string): Promise<boolean> {\n if (!this.startCommandLaunchRequested) {\n return this.enqueueStartCommandReplacement(command);\n }\n await this.startCommandQueue;\n return !this.stopped && this.liveStartCommandChildren.size > 0;\n }\n\n private enqueueStartCommandReplacement(command: string): Promise<boolean> {\n this.startCommandLaunchRequested = true;\n const operation = this.startCommandQueue.then(async () => {\n if (this.stopped) return false;\n await this.terminateAllStartCommands();\n if (this.stopped) return false;\n return this.launchStartCommand(command);\n });\n this.startCommandQueue = operation.then(\n () => undefined,\n () => undefined,\n );\n return operation;\n }\n\n private launchStartCommand(command: string): boolean {\n if (this.stopped) return false;\n this.connection.sendEvent({ type: \"start_command_started\" });\n try {\n const child = this.runStartCommandFn(command, this.workspaceDir, (stream, data) => {\n if (this.stopped) return;\n this.connection.sendEvent({ type: \"start_command_output\", stream, data });\n this.writeOutput(stream, data);\n });\n this.liveStartCommandChildren.add(child);\n const ended = new Promise<void>((resolve) => {\n this.resolveStartCommandEnd.set(child, resolve);\n });\n this.startCommandEndPromises.set(child, ended);\n if (this.stopped) {\n void this.terminateStartCommandChild(child);\n return false;\n }\n this.startCommandChild = child;\n child.on(\"exit\", (code, signal) => {\n if (this.startCommandChild === child) this.startCommandChild = null;\n this.liveStartCommandChildren.delete(child);\n this.settleStartCommandEnd(child);\n if (this.stopped || this.expectedStartCommandStops.has(child)) return;\n const message = `start command exited${code === null ? \"\" : ` with code ${code}`}${signal ? ` (signal: ${signal})` : \"\"}`;\n this.connection.sendEvent({ type: \"start_command_exited\", code, signal, message });\n if (code !== null && code !== 0) {\n this.connection.sendEvent({\n type: \"start_command_error\",\n message: `start command exited with code ${code}${signal ? ` (signal: ${signal})` : \"\"}`,\n });\n }\n });\n child.on(\"error\", (error) => {\n if (child.pid === undefined) {\n if (this.startCommandChild === child) this.startCommandChild = null;\n this.liveStartCommandChildren.delete(child);\n this.settleStartCommandEnd(child);\n this.startCommandTerminations.delete(child);\n }\n if (this.stopped) return;\n this.connection.sendEvent({ type: \"start_command_error\", message: error.message });\n });\n return true;\n } catch (error) {\n if (!this.stopped) {\n this.connection.sendEvent({\n type: \"start_command_error\",\n message: error instanceof Error ? error.message : String(error),\n });\n }\n return false;\n }\n }\n\n private terminateStartCommandChild(child: StartCommandChild): Promise<void> {\n const existing = this.startCommandTerminations.get(child);\n if (existing) return existing;\n this.expectedStartCommandStops.add(child);\n const processTermination = Promise.resolve(this.terminateStartCommand(child));\n const ended = this.startCommandEndPromises.get(child);\n const termination = (ended ? Promise.race([processTermination, ended]) : processTermination)\n .then(() => undefined)\n .finally(() => this.startCommandTerminations.delete(child));\n this.startCommandTerminations.set(child, termination);\n return termination;\n }\n\n private async terminateAllStartCommands(): Promise<void> {\n const live = [...this.liveStartCommandChildren].filter((child) => child.exitCode === null);\n await Promise.all(live.map((child) => this.terminateStartCommandChild(child)));\n }\n\n private settleStartCommandEnd(child: StartCommandChild): void {\n this.resolveStartCommandEnd.get(child)?.();\n this.resolveStartCommandEnd.delete(child);\n this.startCommandEndPromises.delete(child);\n }\n\n private trackBackgroundTask(task: Promise<void>): void {\n this.backgroundTasks.add(task);\n void task.finally(() => this.backgroundTasks.delete(task));\n }\n\n private forwardSetupOutput(stream: OutputStream, data: string): void {\n if (this.stopped) return;\n this.connection.sendEvent({ type: \"setup_output\", stream, data });\n this.writeOutput(stream, data);\n }\n\n private reportUnexpectedError(error: unknown): void {\n if (this.stopped) return;\n this.connection.sendEvent({\n type: \"setup_error\",\n message: error instanceof Error ? error.message : String(error),\n });\n }\n}\n","// Defense-in-depth startup check. The authoritative guarantee that a session is\n// bound to the right task lives server-side (requireTaskAuth + the Postgres\n// partial-unique index on active CodespaceSessions). This check exists so that\n// if those invariants ever regress, a human sees a loud WARN immediately\n// instead of the symptoms the session-identity bug produced (multiple agents silently clobbering\n// the same branch).\nexport interface SessionIdentityLogger {\n warn(message: string, data?: Record<string, unknown>): void;\n info?(message: string, data?: Record<string, unknown>): void;\n}\n\nexport interface CheckSessionTaskIdentityParams {\n sessionId: string | undefined;\n taskId: string;\n fetchSessionTaskId: (sessionId: string) => Promise<string>;\n logger: SessionIdentityLogger;\n}\n\nexport async function checkSessionTaskIdentity(\n params: CheckSessionTaskIdentityParams,\n): Promise<\"match\" | \"mismatch\" | \"skipped\" | \"error\"> {\n const { sessionId, taskId, fetchSessionTaskId, logger } = params;\n if (!sessionId || sessionId === taskId) return \"skipped\";\n let sessionTaskId: string;\n try {\n sessionTaskId = await fetchSessionTaskId(sessionId);\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n logger.warn(\"Could not verify session/task identity — continuing (defense-in-depth only)\", {\n sessionId,\n taskId,\n error: message,\n });\n return \"error\";\n }\n if (sessionTaskId !== taskId) {\n logger.warn(\n \"!!! CONVEYOR_SESSION_ID is bound to a different task than CONVEYOR_TASK_ID — server-side guards should still block mutations, but this indicates a misconfiguration or replayed token.\",\n { sessionId, envTaskId: taskId, sessionTaskId },\n );\n return \"mismatch\";\n }\n return \"match\";\n}\n","/**\n * Structured pod-exit log payload. The control plane (workspace reconciler) can\n * only ever infer *that* an agent stopped — it sees a stale heartbeat and marks\n * the session Stranded/Ended. It cannot see *why*. This log closes that gap from\n * the pod side: emitted at every catchable exit path so the claudespace pod logs\n * record the cause (teardown signal vs clean finish vs crash) alongside the\n * `sessionId` that joins to the API's `session_stranded` / reconcile logs.\n *\n * Caveat: an OOMKill (SIGKILL / 137) is uncatchable, so it never reaches here —\n * those are diagnosed from GKE kernel OOM logs, not this line.\n */\n// - signal: SIGTERM/SIGINT — teardown or a reaper asked us to stop\n// - clean: runner.run() resolved normally\n// - error: runner finalState=error, or run() rejected\n// - force_timeout: graceful-shutdown watchdog fired\nexport type AgentExitReason =\n | \"signal\"\n | \"clean\"\n | \"error\"\n | \"uncaught_exception\"\n | \"unhandled_rejection\"\n | \"force_timeout\"\n // Persistent authorization denial — the session user lacks project access.\n // Exits cleanly (code 0) so the supervisor parks the pod instead of burning\n // the 3× crash-restart loop on an outcome that never changes.\n | \"unauthorized\";\n\nexport interface AgentExitIdentity {\n sessionId?: string | undefined;\n taskId?: string | undefined;\n workspaceId?: string | undefined;\n runnerMode?: string | undefined;\n}\n\nexport interface AgentExitLog extends AgentExitIdentity {\n event: \"agent_exit\";\n reason: AgentExitReason;\n exitCode: number;\n signal?: string;\n finalState?: string;\n uptimeSec: number;\n}\n\n/** Clean shutdowns are routine (info); every other exit is worth a warn so it\n * surfaces in severity-filtered log queries. */\nexport function exitLogLevel(reason: AgentExitReason): \"info\" | \"warn\" {\n return reason === \"clean\" ? \"info\" : \"warn\";\n}\n\n/**\n * Build the `agent_exit` payload, dropping any undefined optional/identity keys\n * so the serialized log line stays tidy (no `\"workspaceId\":undefined` noise).\n */\nexport function buildAgentExitLog(args: {\n reason: AgentExitReason;\n exitCode: number;\n uptimeSec: number;\n signal?: string | undefined;\n finalState?: string | undefined;\n identity?: AgentExitIdentity | undefined;\n}): AgentExitLog {\n const log: AgentExitLog = {\n event: \"agent_exit\",\n reason: args.reason,\n exitCode: args.exitCode,\n uptimeSec: Math.round(args.uptimeSec * 10) / 10,\n };\n if (args.signal !== undefined) log.signal = args.signal;\n if (args.finalState !== undefined) log.finalState = args.finalState;\n const id = args.identity;\n if (id) {\n if (id.sessionId !== undefined) log.sessionId = id.sessionId;\n if (id.taskId !== undefined) log.taskId = id.taskId;\n if (id.workspaceId !== undefined) log.workspaceId = id.workspaceId;\n if (id.runnerMode !== undefined) log.runnerMode = id.runnerMode;\n }\n return log;\n}\n","/**\n * Task-less pod identity detection (Claudespace v3 project runners AND adhoc\n * scratch pods).\n *\n * A v3 task-less pod's bootstrap bundle carries a session JWT with\n * {projectId, workspaceId, sessionId, role} and NO taskId claim; the entrypoint\n * exports CONVEYOR_PROJECT_ID / CONVEYOR_SESSION_ID / CONVEYOR_WORKSPACE_ID from\n * the claims, does NOT export CONVEYOR_TASK_ID, and sets CONVEYOR_MODE to \"pm\"\n * (project runner) or \"adhoc\" (interactive scratch TUI). Both share this\n * identity shape — cli.ts branches on CONVEYOR_MODE afterward to pick the\n * runner. Every condition below is required — anything else falls through to\n * the task-runner path, which fail-closed exits without a task id.\n *\n * `workspaceId` is the stable `Workspace` row id — unlike `sessionId` (the\n * `WorkspaceSession` row), it survives a sleep/wake cycle: a user-initiated\n * wake mints a brand-new writer `WorkspaceSession` (fresh-session semantics,\n * see `ensure-adhoc.ts`), so `sessionId` changes on every wake. The adhoc\n * runner keys its Claude session lineage on `workspaceId` for exactly this\n * reason — keying on `sessionId` would never resume the prior transcript.\n */\n\nexport interface ProjectRunnerIdentity {\n projectId: string;\n sessionId: string;\n workspaceId: string;\n taskToken: string;\n}\n\nexport function resolveProjectRunnerIdentity(\n env: Record<string, string | undefined>,\n): ProjectRunnerIdentity | null {\n // A task id always wins: this is a task pod, never a project runner.\n if (env.CONVEYOR_TASK_ID) return null;\n if (!env.CONVEYOR_TASK_TOKEN) return null;\n if (!env.CONVEYOR_PROJECT_ID || !env.CONVEYOR_SESSION_ID || !env.CONVEYOR_WORKSPACE_ID) {\n return null;\n }\n // Task-less identity is shared by the project runner (\"pm\") and the adhoc\n // scratch-pod TUI (\"adhoc\"); cli.ts branches on CONVEYOR_MODE afterward to\n // pick the runner. Any OTHER mode (reader/review/task/absent) is not a valid\n // task-less identity. NOTE: the adhoc branch in cli.ts gates on THIS resolver\n // returning non-null AND CONVEYOR_MODE === \"adhoc\" — omitting \"adhoc\" here\n // makes that branch unreachable and crash-loops every adhoc pod at the\n // task-mode fall-through.\n if (env.CONVEYOR_MODE !== \"pm\" && env.CONVEYOR_MODE !== \"adhoc\") return null;\n\n return {\n projectId: env.CONVEYOR_PROJECT_ID,\n sessionId: env.CONVEYOR_SESSION_ID,\n workspaceId: env.CONVEYOR_WORKSPACE_ID,\n taskToken: env.CONVEYOR_TASK_TOKEN,\n };\n}\n","/**\n * ProjectSessionRunner — the task-less PROJECT pod agent loop (Claudespace v3\n * project runners).\n *\n * What a project agent does today: connect, register its WorkspaceSession\n * (connectAgent), heartbeat (lease renewal via the server's v3 fallthrough),\n * and idle awaiting project-scoped messages. It deliberately does NOT run the\n * task-shaped SessionRunner lifecycle — getTaskContext, git branch sync, the\n * QueryBridge prompt loop and WIP flushing are all keyed on a Task, and the\n * server-side pm-conversation surface for project workspaces does not exist\n * yet (project chat is served by the server-side ProjectAgentService\n * responder). When that surface lands (project context RPC + project-keyed\n * message routing), this runner grows the message->query loop; until then an\n * inbound message is logged and acknowledged as activity only.\n */\nimport {\n AgentConnection,\n type AgentConnectionConfig,\n type IncomingMessage,\n} from \"../connection/agent-connection.js\";\nimport { Lifecycle, DEFAULT_LIFECYCLE_CONFIG, type LifecycleConfig } from \"./lifecycle.js\";\nimport { sampleKeyUsage } from \"../execution/usage-sampler.js\";\n\nexport interface ProjectSessionRunnerConfig {\n connection: AgentConnectionConfig;\n projectId: string;\n lifecycle?: Partial<LifecycleConfig>;\n}\n\nexport interface ProjectSessionRunnerCallbacks {\n onEvent?: (event: Record<string, unknown>) => void;\n}\n\n/** The AgentConnection surface the project runner uses (injectable for tests). */\nexport interface ProjectRunnerConnection {\n connect(): Promise<void>;\n disconnect(): void;\n call(\n method: \"connectAgent\",\n payload: { sessionId: string },\n ): Promise<{ sessionId: string; taskId: string | null; pendingMessages: unknown[] }>;\n sendEvent(event: { type: string; [key: string]: unknown }): void;\n sendHeartbeat(): void;\n emitStatus(status: string): Promise<void>;\n onMessage(callback: (msg: IncomingMessage) => void): void;\n onStop(callback: () => void): void;\n refreshTaskTokenFromBootstrap(): Promise<boolean>;\n}\n\nexport class ProjectSessionRunner {\n readonly connection: ProjectRunnerConnection;\n readonly lifecycle: Lifecycle;\n\n private readonly config: ProjectSessionRunnerConfig;\n private readonly callbacks: ProjectSessionRunnerCallbacks;\n private stopped = false;\n private stopResolver: (() => void) | null = null;\n private _finalState: \"finished\" | \"error\" | null = null;\n\n constructor(\n config: ProjectSessionRunnerConfig,\n callbacks: ProjectSessionRunnerCallbacks = {},\n connection?: ProjectRunnerConnection,\n ) {\n this.config = config;\n this.callbacks = callbacks;\n this.connection = connection ?? new AgentConnection(config.connection);\n this.lifecycle = new Lifecycle(\n // No git flush: the project runner does not (yet) mutate the checkout,\n // and the WIP snapshot machinery is branch/task-shaped.\n { ...DEFAULT_LIFECYCLE_CONFIG, gitFlushIntervalMs: 0, ...config.lifecycle },\n {\n onHeartbeat: () => this.connection.sendHeartbeat(),\n onIdleTimeout: () => {\n process.stderr.write(\"[conveyor-agent] Project runner idle timeout, shutting down\\n\");\n this.requestStop();\n },\n onDormantTimeout: () => this.requestStop(),\n // v3 credential refresh: re-poll the pod bootstrap route (session JWT,\n // GitHub token, keys are all swapped in place). The task-scoped\n // refreshGithubToken RPC does not apply to a task-less session.\n onTokenRefresh: () => void this.connection.refreshTaskTokenFromBootstrap().catch(() => {}),\n onGitFlush: () => {},\n onUsageSample: () => void this.sampleAndReportKeyUsage(),\n },\n );\n }\n\n get finalState(): \"finished\" | \"error\" | null {\n return this._finalState;\n }\n\n get isStopped(): boolean {\n return this.stopped;\n }\n\n /** Connect, register the session, then idle until stopped or idle-timeout. */\n async run(): Promise<void> {\n try {\n await this.connection.connect();\n this.connection.sendEvent({\n type: \"connected\",\n sessionId: this.config.connection.sessionId,\n projectId: this.config.projectId,\n });\n\n this.connection.onStop(() => this.requestStop());\n this.connection.onMessage((msg) => this.handleMessage(msg));\n this.lifecycle.startHeartbeat();\n this.lifecycle.startTokenRefresh();\n this.lifecycle.startUsageSample();\n\n // Join the session room + activate the lease (server v3 fallthrough).\n await this.connection.call(\"connectAgent\", {\n sessionId: this.config.connection.sessionId,\n });\n\n process.stderr.write(\n `[conveyor-agent] Project runner connected (project: ${this.config.projectId}) — idling\\n`,\n );\n await this.connection.emitStatus(\"idle\");\n this.callbacks.onEvent?.({ type: \"project_runner_idle\", projectId: this.config.projectId });\n\n this.lifecycle.startIdleTimer();\n await this.waitUntilStopped();\n this._finalState = \"finished\";\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n process.stderr.write(`[conveyor-agent] Project runner failed: ${message}\\n`);\n this.connection.sendEvent({ type: \"error\", message });\n this._finalState = \"error\";\n } finally {\n this.shutdown();\n }\n }\n\n /**\n * The pm-conversation surface is a follow-up: no server path routes chat to\n * a task-less session yet, so any message that does arrive is surfaced in\n * the logs and treated as activity (idle timer restarts) — never executed.\n */\n private handleMessage(msg: IncomingMessage): void {\n const preview = msg.content.length > 120 ? `${msg.content.slice(0, 120)}…` : msg.content;\n process.stderr.write(\n `[conveyor-agent] Project runner received message (pm surface not wired yet): \"${preview.replace(/\\n/g, \"\\\\n\")}\"\\n`,\n );\n this.callbacks.onEvent?.({ type: \"project_message_received\", content: msg.content });\n if (!this.stopped) this.lifecycle.startIdleTimer();\n }\n\n /** External stop (SIGTERM/SIGINT or server session:stop). */\n stop(): void {\n this.requestStop();\n }\n\n private requestStop(): void {\n if (this.stopped) return;\n this.stopped = true;\n if (this.stopResolver) {\n const resolve = this.stopResolver;\n this.stopResolver = null;\n resolve();\n }\n }\n\n private waitUntilStopped(): Promise<void> {\n if (this.stopped) return Promise.resolve();\n return new Promise<void>((resolve) => {\n this.stopResolver = resolve;\n });\n }\n\n /** Report the running subscription key's rate-limit utilization (same path as\n * the task runner). Best-effort — never throws, no-op without an OAuth token. */\n private async sampleAndReportKeyUsage(): Promise<void> {\n if (this.stopped) return;\n const samples = await sampleKeyUsage(process.env.CLAUDE_CODE_OAUTH_TOKEN);\n for (const sample of samples) {\n this.connection.sendEvent({\n type: \"rate_limit_update\",\n rateLimitType: sample.rateLimitType,\n utilization: sample.utilization,\n status: sample.status,\n resetsAt: sample.resetsAt ?? undefined,\n gauges: sample.gauges,\n });\n }\n }\n\n private shutdown(): void {\n this.stopped = true;\n this.lifecycle.destroy();\n this.connection.sendEvent({ type: \"shutdown\", reason: this._finalState ?? \"finished\" });\n this.connection.disconnect();\n }\n}\n","/**\n * Multi-key `/usage` probe — the on-demand \"refresh all keys from one box\" path.\n *\n * The normal sampler (`usage-sampler.ts`) can only report the ONE key the pod\n * booted under: it reads the pod's shared `~/.claude/.credentials.json` and an\n * attribution guard refuses to write another account's gauges. This module\n * instead probes an explicit list of keys, isolating EACH one in its own\n * temporary `CLAUDE_CONFIG_DIR` so the pod's shared credentials file (read by\n * the user's other concurrent pods on the GCS-FUSE mount) is never mutated.\n *\n * For each key: a temp config dir gets a synthesized `.credentials.json` for the\n * key's token plus a copy of the pod's onboarded `.claude.json` (so trust /\n * onboarding / model-cache carry over and the `/usage` panel renders without\n * parking at a first-run dialog). The `claude` CLI is then driven under a PTY\n * (`runUsageProbe`) with `CLAUDE_CONFIG_DIR` pointed at that dir.\n *\n * Best-effort throughout: a key whose probe fails or yields no gauges is simply\n * omitted — this never throws.\n */\nimport { mkdtemp, writeFile, copyFile, rm } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport { buildSynthesizedCredentials, claudeJsonPath } from \"../harness/pty/credentials.js\";\nimport { sessionTempBase } from \"../harness/pty/pty-support.js\";\nimport { createServiceLogger } from \"../utils/logger.js\";\nimport { parseUsageGauges } from \"./parse-usage.js\";\nimport { runUsageProbe } from \"./run-probe.js\";\nimport type { KeyUsageSample } from \"../execution/usage-sampler.js\";\n\nconst logger = createServiceLogger(\"multi-key-probe\");\n\nexport interface ProbeKeyInput {\n codingAgentKeyId: string;\n /** Decrypted subscription OAuth token for this key. */\n oauthToken: string;\n}\n\nexport interface ProbedKeyUsage {\n codingAgentKeyId: string;\n samples: KeyUsageSample[];\n}\n\nexport interface MultiKeyProbeDeps {\n /**\n * Isolated single-key probe: prepare credentials for `token` and return the\n * raw `/usage` panel text. Injectable so the sequencing/mapping is testable\n * without spawning a PTY or touching the filesystem.\n */\n probeOne?: (token: string) => Promise<string>;\n now?: () => number;\n}\n\n/** Map a parsed `/usage` panel to rate-limit samples (mirrors usage-sampler). */\nfunction gaugesToSamples(stdout: string): KeyUsageSample[] {\n const { sessionUsage, weeklyUsage, sessionResetsAt, weeklyResetsAt, gauges } =\n parseUsageGauges(stdout);\n const samples: KeyUsageSample[] = [];\n if (sessionUsage !== null) {\n samples.push({\n rateLimitType: \"five_hour\",\n utilization: sessionUsage,\n status: \"allowed\",\n resetsAt: sessionResetsAt,\n gauges,\n });\n }\n if (weeklyUsage !== null) {\n samples.push({\n rateLimitType: \"seven_day\",\n utilization: weeklyUsage,\n status: \"allowed\",\n resetsAt: weeklyResetsAt,\n gauges,\n });\n }\n return samples;\n}\n\n/**\n * Default `probeOne`: build an isolated config dir for `token`, run the probe\n * under it, and clean up. Best-effort — resolves \"\" on any failure.\n */\nasync function isolatedProbe(token: string, now: number): Promise<string> {\n let dir: string | null = null;\n try {\n // sessionTempBase, not tmpdir: in split-mode pods the probe CLI runs in the\n // workbench container, which can only see this dir on the shared emptyDir.\n dir = await mkdtemp(join(sessionTempBase(), \"conveyor-usage-\"));\n await writeFile(join(dir, \".credentials.json\"), buildSynthesizedCredentials(token, now), {\n encoding: \"utf8\",\n mode: 0o600,\n });\n // Carry the pod's onboarding/trust/model-cache into the isolated dir so the\n // /usage panel renders instead of parking at a first-run dialog. Best-effort:\n // a missing source file just means a fresh config (the CLI onboards silently\n // for a read-only /usage panel).\n await copyFile(claudeJsonPath(), join(dir, \".claude.json\")).catch(() => {});\n return await runUsageProbe({ env: { ...process.env, CLAUDE_CONFIG_DIR: dir } });\n } catch (error) {\n logger.info(\"isolated usage probe failed\", {\n error: error instanceof Error ? error.message : String(error),\n });\n return \"\";\n } finally {\n if (dir) await rm(dir, { recursive: true, force: true }).catch(() => {});\n }\n}\n\n/**\n * Probe each key's `/usage` sequentially (avoid concurrent PTYs) and return the\n * samples per key. Keys that yield no gauges are omitted. Never throws.\n */\nexport async function probeKeysUsage(\n keys: ProbeKeyInput[],\n deps: MultiKeyProbeDeps = {},\n): Promise<ProbedKeyUsage[]> {\n const now = deps.now ?? Date.now;\n const probeOne = deps.probeOne ?? ((token: string) => isolatedProbe(token, now()));\n\n const results: ProbedKeyUsage[] = [];\n for (const key of keys) {\n if (!key.oauthToken) continue;\n try {\n const stdout = await probeOne(key.oauthToken);\n const samples = gaugesToSamples(stdout);\n if (samples.length > 0) {\n results.push({ codingAgentKeyId: key.codingAgentKeyId, samples });\n }\n } catch (error) {\n logger.info(\"usage probe for key failed\", {\n codingAgentKeyId: key.codingAgentKeyId,\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n return results;\n}\n","/* oxlint-disable import/max-dependencies -- cohesive ad-hoc runner lifecycle wiring */\n/**\n * AdhocSessionRunner — the task-less USER SCRATCH pod agent loop (Sessions view\n * \"Launch ad-hoc session\"). Claudespace v3, `Workspace.purpose = \"adhoc\"`.\n *\n * Unlike the ProjectSessionRunner (autonomous pm) it runs NO autonomous loop:\n * it spawns the `claude` CLI under a pseudo-terminal in interactive/prefill mode\n * (empty input box, no auto-submit) and relays raw terminal I/O to the S2 relay,\n * so the web Sessions terminal (S5) renders it and forwards keystrokes back. The\n * human drives it directly — there is no task, plan, or Conveyor MCP tool\n * surface. Connect / register / heartbeat / idle are shared with the project\n * runner; the difference is the interactive PTY spawn.\n *\n * Idle-sleep is server-owned (decideFate + activity/tunnel holds): an idle\n * adhoc pod sleeps after the idle window like any workspace; the human wakes it\n * from the Sessions list. The agent's own idle timer is the secondary backstop.\n */\nimport { AgentConnection, type AgentConnectionConfig } from \"../connection/agent-connection.js\";\nimport { Lifecycle, DEFAULT_LIFECYCLE_CONFIG, type LifecycleConfig } from \"./lifecycle.js\";\nimport { resolveSessionStart } from \"../execution/query-executor.js\";\nimport { resolvePlaywrightMcpServer } from \"../execution/playwright-mcp.js\";\nimport { sampleKeyUsage } from \"../execution/usage-sampler.js\";\nimport { probeKeysUsage } from \"../usage/multi-key-probe.js\";\nimport { PtyHarness } from \"../harness/pty/index.js\";\nimport { resolveTuiAdapter, resolveTuiKindFromEnv } from \"../harness/pty/adapters/index.js\";\nimport type { TuiKind } from \"../harness/pty/adapters/types.js\";\nimport type {\n AgentHarness,\n HarnessMcpServer,\n HarnessQueryOptions,\n PtyBridge,\n} from \"../harness/types.js\";\nimport { PortDiscovery } from \"./port-discovery.js\";\nimport { CodespacePortVisibility } from \"./codespace-port-visibility.js\";\nimport { loadConveyorConfig } from \"../setup/config.js\";\nimport { WorkspaceCommandSupervisor } from \"../setup/workspace-command-supervisor.js\";\nimport { buildProjectTools } from \"../tools/project-tools.js\";\nimport {\n DEFAULT_SONNET_MODEL,\n type AgentSessionServiceMethods,\n type PtyChatEventPayload,\n type WorkspaceDiscoveredPort,\n} from \"@project/shared\";\n\nconst ADHOC_SYSTEM_NOTE =\n \"You are running in an ad-hoc Conveyor scratch pod — an interactive terminal \" +\n \"on the project's repository checked out at its default branch. There is no \" +\n \"task or plan; help the human with whatever they ask directly.\";\n\nconst HEADLESS_SYSTEM_NOTE =\n \"You are running a HEADLESS Conveyor session on the project's repository — \" +\n \"your instructions were auto-submitted as the first message. Work them to \" +\n \"completion autonomously and never wait for user input; a human may attach \" +\n \"to this terminal to watch or interject, but none is required.\";\n\n/**\n * Headless sessions: the bootstrap bundle carries the server-assembled\n * instructions as base64 (only while un-submitted — see\n * build-bootstrap-bundle.ts). Absent/blank/undecodable → interactive ad-hoc.\n */\nexport function resolveInitialPrompt(env: NodeJS.ProcessEnv = process.env): string | null {\n const b64 = env.CONVEYOR_INITIAL_PROMPT_B64;\n if (!b64) return null;\n try {\n const decoded = Buffer.from(b64, \"base64\").toString(\"utf8\").trim();\n return decoded.length > 0 ? decoded : null;\n } catch {\n return null;\n }\n}\n\nexport interface AdhocSessionRunnerConfig {\n connection: AgentConnectionConfig;\n projectId: string;\n /**\n * Stable `Workspace` row id — the Claude session lineage key. Deliberately\n * NOT `connection.sessionId`: that's the `WorkspaceSession` row, which is\n * re-minted (fresh-session semantics) on every user-initiated wake, so\n * keying resume on it would never find the prior GCS-FUSE transcript.\n */\n workspaceId: string;\n /** Repo checkout the interactive CLI runs in. */\n workspaceDir: string;\n /** Model override; falls back to CONVEYOR_ADHOC_MODEL env, then the default. */\n model?: string;\n /**\n * Headless sessions: instructions to auto-submit as the first message\n * (flips prompt delivery to \"submit\" and mounts the project tool surface).\n * ONLY the top-level adhoc boot (cli.ts) resolves this from the bundle env —\n * spawned same-pod tabs must never inherit it, or a \"New Claude tab\" on a\n * headless pod would re-run the audit.\n */\n initialPrompt?: string | null;\n lifecycle?: Partial<LifecycleConfig>;\n}\n\nexport interface AdhocSessionRunnerCallbacks {\n onEvent?: (event: Record<string, unknown>) => void;\n}\n\n/** AgentConnection surface the adhoc runner needs (injectable for tests). */\nexport interface AdhocRunnerConnection {\n connect(): Promise<void>;\n disconnect(): void;\n call<M extends keyof AgentSessionServiceMethods>(\n method: M,\n payload: AgentSessionServiceMethods[M][\"payload\"],\n ): Promise<AgentSessionServiceMethods[M][\"response\"]>;\n sendEvent(event: { type: string; [key: string]: unknown }): void;\n sendHeartbeat(): void;\n emitStatus(status: string): Promise<void>;\n onStop(callback: () => void): void;\n refreshTaskTokenFromBootstrap(): Promise<boolean>;\n sendPtyOutput(data: string, dims?: { cols: number; rows: number }): void;\n sendPtyChatEvent(event: PtyChatEventPayload): void;\n onPtyInput(handler: (data: string) => void): () => void;\n onPtyResize(handler: (cols: number, rows: number) => void): () => void;\n reportDiscoveredPorts(ports: WorkspaceDiscoveredPort[]): Promise<void>;\n onRunStartCommand(callback: () => void): void;\n onProbeUsage(callback: () => void): void;\n}\n\nexport interface AdhocPortDiscovery {\n start(): Promise<void>;\n stop(): void;\n}\n\nexport interface AdhocWorkspaceCommandSupervisor {\n start(): void;\n stop(): Promise<void>;\n /** WorkspaceCommandSupervisor now holds its start-command launch behind a\n * loopReady signal (see workspace-command-supervisor.ts). Ad-hoc pods have\n * no separate core-loop boundary to gate on — the interactive TUI IS the\n * loop — so we release it immediately, right where start() used to launch\n * it unconditionally, preserving pre-existing behavior. Optional so\n * existing/simplified test doubles don't need updating. */\n notifyLoopReady?(): void;\n}\n\n/** Which TUI this adhoc pod runs — from the bootstrap bundle's CONVEYOR_TUI.\n *\n * Alias of `resolveTuiKindFromEnv`, which the task/card path shares. Kept as a\n * named export so the adhoc call site and its tests keep reading in adhoc\n * terms; there is exactly one implementation of the contract. */\nexport const resolveAdhocTui: (env: NodeJS.ProcessEnv) => TuiKind = resolveTuiKindFromEnv;\n\n/** Adapt an AdhocRunnerConnection into the harness-neutral PtyBridge.\n * `onInputActivity` fires on every relayed keystroke so the caller can re-arm\n * the idle backstop — the harness owns the connection's single onPtyInput slot,\n * so this wrap is the only seam to observe input without clobbering it. */\nexport function buildAdhocPtyBridge(\n connection: AdhocRunnerConnection,\n onInputActivity?: () => void,\n): PtyBridge {\n return {\n sendOutput: (data, dims) => connection.sendPtyOutput(data, dims),\n sendChatEvent: (event) => connection.sendPtyChatEvent(event),\n onInput: (handler) =>\n connection.onPtyInput((data) => {\n onInputActivity?.();\n handler(data);\n }),\n onResize: (handler) => connection.onPtyResize(handler),\n };\n}\n\n/** The interactive-spawn options for an ad-hoc scratch TUI (no task context). */\nexport function buildAdhocQueryOptions(\n workspaceDir: string,\n model: string,\n abortController: AbortController,\n // Deterministic session start (fresh `sessionId` or `resume` target). Without\n // one, PtySession.start() throws \"requires options.sessionId or a resume\n // target\" and the pool crash-loops the runner — the interactive PTY never\n // spawns. Mutually exclusive: exactly one of the two is ever set.\n session?: { sessionId?: string; resume?: string },\n // Environment for PATH-based binary resolution (playwright-mcp). Injectable\n // so tests are deterministic regardless of what the host has baked on PATH\n // (claudespace pods ship /usr/local/bin/playwright-mcp; dev machines don't).\n env: NodeJS.ProcessEnv = process.env,\n // Headless mode: an initial prompt flips delivery to auto-submit and mounts\n // the project-scoped Conveyor tool surface (interactive adhoc gets neither).\n headless?: { initialPrompt: string; conveyorMcpServer?: HarnessMcpServer },\n): HarnessQueryOptions {\n const systemNote = headless ? HEADLESS_SYSTEM_NOTE : ADHOC_SYSTEM_NOTE;\n return {\n model,\n systemPrompt: { type: \"preset\", preset: \"claude_code\", append: systemNote },\n appendSystemPrompt: systemNote,\n cwd: workspaceDir,\n // Human-driven interactive shell — no plan-mode gating. (Headless audit\n // runs keep the same bypass: they must finish with no one at the terminal.)\n permissionMode: \"bypassPermissions\",\n allowDangerouslySkipPermissions: true,\n tools: { type: \"preset\", preset: \"claude_code\" },\n mcpServers: (() => {\n const playwright = resolvePlaywrightMcpServer(env);\n return {\n ...(playwright ? { playwright } : {}),\n ...(headless?.conveyorMcpServer ? { conveyor: headless.conveyorMcpServer } : {}),\n };\n })(),\n settingSources: [\"user\", \"project\"],\n // Interactive: empty box, unsubmitted — the human types the first prompt.\n // Headless: paste + submit the server-assembled instructions immediately.\n promptDelivery: headless ? \"submit\" : \"prefill\",\n abortController,\n ...(session?.sessionId ? { sessionId: session.sessionId } : {}),\n ...(session?.resume ? { resume: session.resume } : {}),\n };\n}\n\nexport class AdhocSessionRunner {\n readonly connection: AdhocRunnerConnection;\n readonly lifecycle: Lifecycle;\n private readonly harness: AgentHarness;\n private readonly portDiscovery: AdhocPortDiscovery;\n private readonly commandSupervisor: AdhocWorkspaceCommandSupervisor;\n\n private readonly config: AdhocSessionRunnerConfig;\n private readonly callbacks: AdhocSessionRunnerCallbacks;\n private readonly abortController = new AbortController();\n private stopped = false;\n private stopResolver: (() => void) | null = null;\n private _finalState: \"finished\" | \"error\" | null = null;\n\n constructor(\n config: AdhocSessionRunnerConfig,\n callbacks: AdhocSessionRunnerCallbacks = {},\n deps?: {\n connection?: AdhocRunnerConnection;\n harness?: AgentHarness;\n portDiscovery?: AdhocPortDiscovery;\n commandSupervisor?: AdhocWorkspaceCommandSupervisor;\n },\n ) {\n this.config = config;\n this.callbacks = callbacks;\n this.connection = deps?.connection ?? new AgentConnection(config.connection);\n this.harness =\n deps?.harness ??\n new PtyHarness(\n // A keystroke is real human activity — re-arm the idle backstop so an\n // actively-typing human (or a >60-min audit run) is never hard-stopped\n // by the idle timer, mirroring ShellSessionRunner. `this.lifecycle` is\n // assigned later in this constructor but is always set by the time a\n // keystroke can arrive at runtime.\n buildAdhocPtyBridge(this.connection, () => this.lifecycle.startIdleTimer()),\n resolveTuiAdapter(resolveAdhocTui(process.env)),\n );\n // Same codespace forwarded-port visibility flip as the task runner (no-op\n // on a GKE pod, where nothing is forwarded through GitHub).\n const portVisibility = new CodespacePortVisibility();\n this.portDiscovery =\n deps?.portDiscovery ??\n new PortDiscovery({\n report: (ports) => this.connection.reportDiscoveredPorts(ports),\n onReported: (ports) => portVisibility.ensureVisible(ports.map(({ port }) => port)),\n });\n this.commandSupervisor =\n deps?.commandSupervisor ??\n new WorkspaceCommandSupervisor({\n config: loadConveyorConfig(),\n workspaceDir: config.workspaceDir,\n connection: this.connection,\n });\n this.lifecycle = new Lifecycle(\n // No git flush: the WIP snapshot machinery is branch/task-shaped; the human\n // commits/pushes explicitly from the interactive shell.\n { ...DEFAULT_LIFECYCLE_CONFIG, gitFlushIntervalMs: 0, ...config.lifecycle },\n {\n onHeartbeat: () => this.connection.sendHeartbeat(),\n onIdleTimeout: () => this.requestStop(),\n onDormantTimeout: () => this.requestStop(),\n onTokenRefresh: () => void this.connection.refreshTaskTokenFromBootstrap().catch(() => {}),\n onGitFlush: () => {},\n onUsageSample: () => void this.sampleAndReportAllKeys(),\n },\n );\n }\n\n get finalState(): \"finished\" | \"error\" | null {\n return this._finalState;\n }\n\n get isStopped(): boolean {\n return this.stopped;\n }\n\n /** Connect, register, spawn the interactive TUI, and relay it until stopped. */\n async run(): Promise<void> {\n try {\n await this.connection.connect();\n this.connection.sendEvent({\n type: \"connected\",\n sessionId: this.config.connection.sessionId,\n projectId: this.config.projectId,\n });\n this.connection.onStop(() => this.requestStop());\n // On-demand \"Refresh usage\" push (server → pod): re-sample every key now.\n this.connection.onProbeUsage(() => void this.sampleAndReportAllKeys());\n this.lifecycle.startHeartbeat();\n this.lifecycle.startTokenRefresh();\n this.lifecycle.startUsageSample();\n\n await this.connection.call(\"connectAgent\", {\n sessionId: this.config.connection.sessionId,\n });\n await this.portDiscovery.start().catch(() => {});\n if (this.stopped) {\n this._finalState = \"finished\";\n return;\n }\n this.commandSupervisor.start();\n // No boot-race to gate here (unlike the task/pack SessionRunner) — the\n // interactive TUI is about to become the loop, so release the start\n // command immediately rather than leaving it parked on loopReady forever.\n this.commandSupervisor.notifyLoopReady?.();\n await this.connection.emitStatus(\"running\");\n this.callbacks.onEvent?.({ type: \"adhoc_runner_started\", projectId: this.config.projectId });\n this.lifecycle.startIdleTimer();\n\n await this.runInteractiveTui();\n this._finalState = \"finished\";\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n process.stderr.write(`[conveyor-agent] Ad-hoc runner failed: ${message}\\n`);\n this.connection.sendEvent({ type: \"error\", message });\n this._finalState = \"error\";\n } finally {\n await this.shutdown();\n }\n }\n\n /**\n * Drive the `claude` CLI under a PTY. The bridge relays raw stdout to S2/S5\n * and forwards keystrokes back, so consuming the event stream is enough — the\n * loop blocks (keeping the pod alive) until the human exits or stop() aborts.\n */\n private async runInteractiveTui(): Promise<void> {\n const model =\n this.config.model ??\n process.env.CONVEYOR_AGENT_MODEL ??\n process.env.CONVEYOR_ADHOC_MODEL ??\n DEFAULT_SONNET_MODEL;\n // Key the CLI session on the stable workspace id (NOT connection.sessionId\n // — see the field doc on AdhocSessionRunnerConfig.workspaceId): a fresh\n // pod spawns a new session, a woken pod resumes the GCS-FUSE-persisted\n // transcript.\n const session = resolveSessionStart(this.config.workspaceId, this.config.workspaceDir);\n // Headless: the bundle delivered un-submitted audit instructions — mount\n // the project tool surface and auto-submit them as the first message.\n const initialPrompt = this.config.initialPrompt ?? null;\n const headless = initialPrompt\n ? {\n initialPrompt,\n conveyorMcpServer: this.harness.createMcpServer({\n name: \"conveyor\",\n tools: buildProjectTools(\n this.connection,\n this.config.projectId,\n this.config.workspaceDir,\n ),\n }),\n }\n : undefined;\n const options = buildAdhocQueryOptions(\n this.config.workspaceDir,\n model,\n this.abortController,\n session,\n process.env,\n headless,\n );\n let promptMarked = false;\n try {\n for await (const event of this.harness.executeQuery({\n prompt: initialPrompt ?? \"\",\n options,\n })) {\n if (this.stopped) break;\n if (initialPrompt && !promptMarked) {\n // First harness event = the CLI spawned and the submit landed. Mark\n // the prompt consumed so a sleep→wake (or pod replacement) boots\n // plain-interactive instead of re-running the audit. Best-effort:\n // the server-side gate is idempotent and a missed mark only risks a\n // re-run, never a crash.\n promptMarked = true;\n void this.connection\n .call(\"markInitialPromptSubmitted\", { sessionId: this.config.connection.sessionId })\n .catch(() => {});\n }\n if (event.type === \"result\" && event.subtype === \"error\") {\n // Raw-mode adapters surface spawn/exit failures as a result error —\n // fail the run loudly so the Sessions UI shows the reason.\n throw new Error(event.errors.join(\"\\n\"));\n }\n }\n } catch (error) {\n // An aborted interactive session is the normal stop path, not a failure.\n if (!this.stopped) throw error;\n }\n }\n\n stop(): void {\n this.requestStop();\n }\n\n private requestStop(): void {\n if (this.stopped) return;\n this.stopped = true;\n this.portDiscovery.stop();\n void this.commandSupervisor.stop();\n this.abortController.abort();\n if (this.stopResolver) {\n const resolve = this.stopResolver;\n this.stopResolver = null;\n resolve();\n }\n }\n\n /**\n * Multi-key usage refresh: ask the server for every subscription key the\n * OWNER has, probe each one's `/usage` from THIS pod (isolated per key), and\n * report each key's gauges tagged with its explicit `codingAgentKeyId`. Falls\n * back to the single-key self-sample when the owner has no probeable keys\n * (e.g. API-key-only, or all decrypts failed). Best-effort — never throws.\n */\n private async sampleAndReportAllKeys(): Promise<void> {\n if (this.stopped) return;\n let keys: { codingAgentKeyId: string; oauthToken: string }[] = [];\n try {\n const res = await this.connection.call(\"listKeysToProbe\", {\n sessionId: this.config.connection.sessionId,\n });\n keys = res?.keys ?? [];\n } catch {\n // Server unreachable / method unavailable — fall back to the self-sample.\n }\n if (keys.length === 0) {\n await this.sampleAndReportOwnKey();\n return;\n }\n const probed = await probeKeysUsage(keys);\n for (const { codingAgentKeyId, samples } of probed) {\n for (const sample of samples) {\n this.connection.sendEvent({\n type: \"rate_limit_update\",\n rateLimitType: sample.rateLimitType,\n utilization: sample.utilization,\n status: sample.status,\n resetsAt: sample.resetsAt ?? undefined,\n gauges: sample.gauges,\n codingAgentKeyId,\n });\n }\n }\n }\n\n /** Single-key fallback: sample only the key this pod booted under. */\n private async sampleAndReportOwnKey(): Promise<void> {\n if (this.stopped) return;\n const samples = await sampleKeyUsage(process.env.CLAUDE_CODE_OAUTH_TOKEN);\n for (const sample of samples) {\n this.connection.sendEvent({\n type: \"rate_limit_update\",\n rateLimitType: sample.rateLimitType,\n utilization: sample.utilization,\n status: sample.status,\n resetsAt: sample.resetsAt ?? undefined,\n gauges: sample.gauges,\n });\n }\n }\n\n private async shutdown(): Promise<void> {\n this.stopped = true;\n this.portDiscovery.stop();\n await this.commandSupervisor.stop();\n this.lifecycle.destroy();\n this.connection.sendEvent({ type: \"shutdown\", reason: this._finalState ?? \"finished\" });\n this.connection.disconnect();\n }\n}\n","/**\n * Same-pod review child supervisor. When the API parks a review session on\n * this (builder) pod and pushes `session:spawnReview`, the supervisor spawns a\n * SECOND conveyor-agent process — same CLI binary, same repo checkout — bound\n * to the review session via env overrides. The child owns its own\n * AgentConnection/PTY stream, so the card's \"Reviewer\" terminal tab appears\n * through the normal multi-session relay with no relay changes.\n *\n * Single-slot: a new spawn (re-review of a fresh push) kills and replaces the\n * previous child. Spawn failures are reported back to the API\n * (`reportReviewSpawnFailure`), which Ends the orphaned session and falls back\n * to a dedicated review pod.\n *\n * Shared-checkout caveat (v1, deliberate): the reviewer reads the builder's\n * working tree. At review time the builder is parked (ReviewPR + CI green),\n * so contention is low; a best-effort ff-only fetch freshens the branch. A\n * human typing in the builder TUI mid-review can still dirty the tree —\n * worktree isolation is a deferred follow-up.\n */\nimport { spawn as nodeSpawn, execFile, type ChildProcess } from \"node:child_process\";\nimport { promisify } from \"node:util\";\nimport type { SpawnReviewData } from \"../connection/agent-connection.js\";\nimport { createServiceLogger } from \"../utils/logger.js\";\n\nconst execFileAsync = promisify(execFile);\nconst logger = createServiceLogger(\"ReviewChild\");\n\n/** Exit inside this window (non-zero) is treated as a spawn failure. */\nexport const SPAWN_FAILURE_GRACE_MS = 15_000;\n/** How long to wait for a SIGTERM'd child before SIGKILL. */\nexport const KILL_WAIT_MS = 5_000;\n\nexport interface ReviewChildConnection {\n reportReviewSpawnFailure(reviewSessionId: string, error?: string): void;\n}\n\nexport type SpawnFn = (\n command: string,\n args: string[],\n options: {\n cwd: string;\n env: NodeJS.ProcessEnv;\n stdio: [\"ignore\", \"pipe\", \"pipe\"];\n },\n) => ChildProcess;\n\n/**\n * Build the child env from the builder's env. The child is the same CLI in\n * `code-review` mode, so it reuses the pod's credentials (git, Anthropic)\n * while swapping in the review session's identity.\n */\nexport function buildReviewChildEnv(\n baseEnv: NodeJS.ProcessEnv,\n data: SpawnReviewData,\n): NodeJS.ProcessEnv {\n const env: NodeJS.ProcessEnv = { ...baseEnv };\n // The review session's identity: its own JWT + sessionId, review runner\n // mode. CONVEYOR_TASK_ID stays the parent's. The server derives task identity\n // from the JWT.\n env.CONVEYOR_TASK_TOKEN = data.sessionJwt;\n env.CONVEYOR_SESSION_ID = data.sessionId;\n env.CONVEYOR_MODE = \"code-review\";\n\n // On workbench-split pods every workspace op (the git-ready gate, every\n // git() call, worktrees, the PTY spawn itself) is proxied to the workbench\n // daemon, which authenticates with the pod bootstrap token. workbenchToken()\n // resolves CONVEYOR_WORKBENCH_TOKEN ?? POD_BOOTSTRAP_TOKEN, so the child's\n // auth must be carried over under the CONVEYOR_WORKBENCH_TOKEN name —\n // deliberately one the bootstrap-refresh path below never reads. Without\n // this the child sends an empty token, the daemon answers \"unauthorized\",\n // and the child wedges in the git gate. `??=` so an explicit workbench token\n // in the base env still wins.\n env.CONVEYOR_WORKBENCH_TOKEN ??= baseEnv.POD_BOOTSTRAP_TOKEN;\n\n // The bootstrap-refresh path would replace the child's review JWT with the\n // BUILDER's writer JWT (findBundleSession prefers the live writer), silently\n // re-identifying the child as the builder. Reviews finish well inside the\n // 24h JWT TTL, so the child never needs a refresh — remove the tokens.\n delete env.POD_BOOTSTRAP_TOKEN;\n delete env.CONVEYOR_BOOTSTRAP_TOKEN;\n\n // The builder already launched (or is launching) the start command on this\n // shared workspace — the child must never spawn a second dev server.\n delete env.CONVEYOR_START_COMMAND;\n\n // Git readiness is workbench-daemon state now (see setup/git-ready.ts),\n // polled over the gitStatus op — there is no marker env to gate on. Strip\n // any stale value defensively (a not-yet-updated entrypoint may still set\n // it) so it can never be mistaken for a live signal downstream.\n delete env.CONVEYOR_GIT_READY;\n delete env.CONVEYOR_GIT_READY_MARKER;\n\n // The code-review runner forces its own mode (review + auto); a stale\n // builder agent-mode hint must not leak in.\n delete env.CONVEYOR_AGENT_MODE;\n delete env.CONVEYOR_IS_AUTO;\n\n // Belt-and-braces with resolveCardTui()'s code-review pin (query-bridge.ts):\n // the reviewer's verdict rides MCP tools that only mount on a structured-\n // events adapter, so a builder's CONVEYOR_TUI=opencode must never reach the\n // review child. Stripping it here means the child resolves the claude-code\n // default even if the pin is ever refactored away.\n delete env.CONVEYOR_TUI;\n return env;\n}\n\nexport class ReviewChildSupervisor {\n private child: ChildProcess | null = null;\n private childSessionId: string | null = null;\n\n constructor(\n private readonly connection: ReviewChildConnection,\n private readonly workspaceDir: string,\n private readonly spawnFn: SpawnFn = nodeSpawn as SpawnFn,\n ) {}\n\n /** Spawn (or replace) the review child for a `session:spawnReview` push. */\n async spawn(data: SpawnReviewData): Promise<void> {\n logger.info(\"Spawning same-pod review child\", {\n reviewSessionId: data.sessionId,\n branch: data.branch ?? undefined,\n prNumber: data.prNumber ?? undefined,\n });\n await this.stopCurrent(\"superseded by new review spawn\");\n await this.refreshCheckout(data.branch ?? null);\n\n const env = buildReviewChildEnv(process.env, data);\n const cliPath = process.argv[1];\n if (!cliPath) {\n this.connection.reportReviewSpawnFailure(data.sessionId, \"cannot resolve CLI entry path\");\n return;\n }\n\n let child: ChildProcess;\n try {\n child = this.spawnFn(process.execPath, [cliPath], {\n cwd: this.workspaceDir,\n env,\n stdio: [\"ignore\", \"pipe\", \"pipe\"],\n });\n } catch (err) {\n this.connection.reportReviewSpawnFailure(\n data.sessionId,\n err instanceof Error ? err.message : String(err),\n );\n return;\n }\n\n this.child = child;\n this.childSessionId = data.sessionId;\n const spawnedAt = Date.now();\n let reported = false;\n const reportOnce = (message: string): void => {\n if (reported) return;\n reported = true;\n this.connection.reportReviewSpawnFailure(data.sessionId, message);\n };\n\n // Child output lands in the pod log (the entrypoint tees our stdio),\n // prefixed so builder and reviewer streams stay distinguishable.\n child.stdout?.on(\"data\", (chunk: Buffer) => {\n process.stdout.write(`[review-child] ${chunk.toString()}`);\n });\n child.stderr?.on(\"data\", (chunk: Buffer) => {\n process.stderr.write(`[review-child] ${chunk.toString()}`);\n });\n\n child.on(\"error\", (err) => {\n logger.error(\"Review child spawn error\", { error: err.message });\n if (this.child === child) {\n this.child = null;\n this.childSessionId = null;\n }\n reportOnce(err.message);\n });\n\n child.on(\"exit\", (code, signal) => {\n const wasCurrent = this.child === child;\n if (wasCurrent) {\n this.child = null;\n this.childSessionId = null;\n }\n logger.info(\"Review child exited\", { code, signal, reviewSessionId: data.sessionId });\n // A non-zero exit right after launch means the child never became the\n // review agent — recover via the dedicated-pod fallback. Later exits\n // (review finished, server-sent session:stop, supersede kill) are\n // normal lifecycle: the server owns the session state there.\n const withinGrace = Date.now() - spawnedAt < SPAWN_FAILURE_GRACE_MS;\n if (wasCurrent && withinGrace && code !== null && code !== 0) {\n reportOnce(`review child exited with code ${code} within startup grace`);\n }\n });\n }\n\n /** Stop any live child (parent shutdown / supersede). Best-effort. */\n async stopAll(): Promise<void> {\n await this.stopCurrent(\"parent shutting down\");\n }\n\n private async stopCurrent(reason: string): Promise<void> {\n const child = this.child;\n if (!child || child.exitCode !== null || child.killed) {\n this.child = null;\n this.childSessionId = null;\n return;\n }\n logger.info(\"Stopping review child\", { reason, reviewSessionId: this.childSessionId });\n // Detach bookkeeping first so the exit handler treats this as expected.\n this.child = null;\n this.childSessionId = null;\n\n await new Promise<void>((resolve) => {\n const timer = setTimeout(() => {\n try {\n child.kill(\"SIGKILL\");\n } catch {\n /* already gone */\n }\n resolve();\n }, KILL_WAIT_MS);\n timer.unref();\n child.once(\"exit\", () => {\n clearTimeout(timer);\n resolve();\n });\n try {\n child.kill(\"SIGTERM\");\n } catch {\n clearTimeout(timer);\n resolve();\n }\n });\n }\n\n /**\n * Best-effort branch freshen before the review reads the tree: fetch the PR\n * branch and fast-forward only (never clobber local work — the builder's\n * checkout is the source of truth on conflict). Failures are logged and\n * skipped; the reviewer still reads the diff via the GitHub API.\n */\n private async refreshCheckout(branch: string | null): Promise<void> {\n if (!branch) return;\n try {\n await execFileAsync(\"git\", [\"fetch\", \"origin\", branch], {\n cwd: this.workspaceDir,\n timeout: 60_000,\n });\n await execFileAsync(\"git\", [\"merge\", \"--ff-only\", `origin/${branch}`], {\n cwd: this.workspaceDir,\n timeout: 30_000,\n });\n } catch (err) {\n logger.warn(\"Review checkout freshen skipped\", {\n branch,\n error: err instanceof Error ? err.message : String(err),\n });\n }\n }\n}\n","/**\n * Same-pod TUI/shell child supervisor. When the API parks an extra interactive\n * session on this (builder) pod and pushes `session:spawnTui`, the supervisor\n * spawns another conveyor-agent process — same CLI binary, same repo checkout —\n * bound to it via env overrides (CONVEYOR_MODE \"adhoc\" = a second Claude TUI,\n * \"shell\" = a raw login shell). Each child owns its own AgentConnection/PTY\n * stream, so a new terminal tab appears through the normal multi-session relay\n * with no relay changes.\n *\n * Multi-slot (unlike ReviewChildSupervisor): tabs are additive — several TUI/\n * shell children can coexist, keyed by their sessionId. The server caps how\n * many it will park per workspace. Spawn failures are reported back\n * (`reportSessionSpawnFailure`), which Ends the orphaned session; there is no\n * fallback pod (a spawned tab only makes sense on this pod).\n *\n * Shared-checkout caveat (deliberate, same as the review child): children\n * operate on the builder's working tree. They never run setup/start commands\n * and never touch git themselves on spawn.\n */\nimport { spawn as nodeSpawn, type ChildProcess } from \"node:child_process\";\nimport type { SpawnTuiData } from \"../connection/agent-connection.js\";\nimport { createServiceLogger } from \"../utils/logger.js\";\nimport { KILL_WAIT_MS, SPAWN_FAILURE_GRACE_MS, type SpawnFn } from \"./review-child.js\";\n\nconst logger = createServiceLogger(\"SessionChild\");\n\nexport interface SessionChildConnection {\n reportSessionSpawnFailure(spawnedSessionId: string, error?: string): void;\n}\n\n/**\n * Build the child env from the builder's env. The child is the same CLI in\n * adhoc/shell mode, so it reuses the pod's credentials while swapping in the\n * spawned session's identity.\n */\nexport function buildSpawnedChildEnv(\n baseEnv: NodeJS.ProcessEnv,\n data: SpawnTuiData,\n): NodeJS.ProcessEnv {\n const env: NodeJS.ProcessEnv = { ...baseEnv };\n // The spawned session's identity: its own JWT + sessionId + runner mode.\n // CONVEYOR_TASK_ID stays the parent's. The server derives task identity from\n // the JWT. CONVEYOR_PROJECT_ID feeds the adhoc runner's\n // connected-event payload.\n env.CONVEYOR_TASK_TOKEN = data.sessionJwt;\n env.CONVEYOR_SESSION_ID = data.sessionId;\n env.CONVEYOR_MODE = data.mode;\n env.CONVEYOR_PROJECT_ID = data.projectId;\n\n // The bootstrap-refresh path would replace the child's JWT with the\n // BUILDER's writer JWT (findBundleSession prefers the live writer), silently\n // re-identifying the child as the builder — remove the tokens (same as the\n // review child; the 24h JWT TTL outlives any tab).\n delete env.POD_BOOTSTRAP_TOKEN;\n delete env.CONVEYOR_BOOTSTRAP_TOKEN;\n\n // The builder already launched (or is launching) the start command on this\n // shared workspace — the child must never spawn a second dev server.\n delete env.CONVEYOR_START_COMMAND;\n\n // Adhoc/shell runners have no agent-mode axis; a stale builder hint must\n // not leak in.\n delete env.CONVEYOR_AGENT_MODE;\n delete env.CONVEYOR_IS_AUTO;\n return env;\n}\n\nexport class SessionChildSupervisor {\n private readonly children = new Map<string, ChildProcess>();\n\n constructor(\n private readonly connection: SessionChildConnection,\n private readonly workspaceDir: string,\n private readonly spawnFn: SpawnFn = nodeSpawn as SpawnFn,\n ) {}\n\n /** Live child count (for tests/diagnostics). */\n get size(): number {\n return this.children.size;\n }\n\n /** Spawn a TUI/shell child for a `session:spawnTui` push. Additive per session. */\n async spawn(data: SpawnTuiData): Promise<void> {\n logger.info(\"Spawning same-pod session child\", {\n spawnedSessionId: data.sessionId,\n mode: data.mode,\n });\n // A duplicate push for the same session replaces its own slot only.\n await this.stopChild(data.sessionId, \"superseded by duplicate spawn\");\n\n const env = buildSpawnedChildEnv(process.env, data);\n const cliPath = process.argv[1];\n if (!cliPath) {\n this.connection.reportSessionSpawnFailure(data.sessionId, \"cannot resolve CLI entry path\");\n return;\n }\n\n let child: ChildProcess;\n try {\n child = this.spawnFn(process.execPath, [cliPath], {\n cwd: this.workspaceDir,\n env,\n stdio: [\"ignore\", \"pipe\", \"pipe\"],\n });\n } catch (err) {\n this.connection.reportSessionSpawnFailure(\n data.sessionId,\n err instanceof Error ? err.message : String(err),\n );\n return;\n }\n\n this.children.set(data.sessionId, child);\n const spawnedAt = Date.now();\n let reported = false;\n const reportOnce = (message: string): void => {\n if (reported) return;\n reported = true;\n this.connection.reportSessionSpawnFailure(data.sessionId, message);\n };\n\n // Child output lands in the pod log (the entrypoint tees our stdio),\n // prefixed so builder and tab streams stay distinguishable.\n const prefix = `[${data.mode}-child]`;\n child.stdout?.on(\"data\", (chunk: Buffer) => {\n process.stdout.write(`${prefix} ${chunk.toString()}`);\n });\n child.stderr?.on(\"data\", (chunk: Buffer) => {\n process.stderr.write(`${prefix} ${chunk.toString()}`);\n });\n\n child.on(\"error\", (err) => {\n logger.error(\"Session child spawn error\", { error: err.message });\n if (this.children.get(data.sessionId) === child) {\n this.children.delete(data.sessionId);\n }\n reportOnce(err.message);\n });\n\n child.on(\"exit\", (code, signal) => {\n const wasCurrent = this.children.get(data.sessionId) === child;\n if (wasCurrent) this.children.delete(data.sessionId);\n logger.info(\"Session child exited\", {\n code,\n signal,\n spawnedSessionId: data.sessionId,\n mode: data.mode,\n });\n // A non-zero exit right after launch means the child never became the\n // tab's agent — End the orphaned session server-side. Later exits (user\n // typed `exit`, server-sent session:stop, supersede kill) are normal\n // lifecycle: the server owns the session state there.\n const withinGrace = Date.now() - spawnedAt < SPAWN_FAILURE_GRACE_MS;\n if (wasCurrent && withinGrace && code !== null && code !== 0) {\n reportOnce(`session child exited with code ${code} within startup grace`);\n }\n });\n }\n\n /** Stop every live child (parent shutdown). Best-effort. */\n async stopAll(): Promise<void> {\n const ids = [...this.children.keys()];\n await Promise.all(ids.map((id) => this.stopChild(id, \"parent shutting down\")));\n }\n\n private async stopChild(sessionId: string, reason: string): Promise<void> {\n const child = this.children.get(sessionId);\n this.children.delete(sessionId);\n if (!child || child.exitCode !== null || child.killed) return;\n logger.info(\"Stopping session child\", { reason, spawnedSessionId: sessionId });\n\n await new Promise<void>((resolve) => {\n const timer = setTimeout(() => {\n try {\n child.kill(\"SIGKILL\");\n } catch {\n /* already gone */\n }\n resolve();\n }, KILL_WAIT_MS);\n timer.unref();\n child.once(\"exit\", () => {\n clearTimeout(timer);\n resolve();\n });\n try {\n child.kill(\"SIGTERM\");\n } catch {\n clearTimeout(timer);\n resolve();\n }\n });\n }\n}\n","/**\n * ShellSessionRunner — a raw login shell relayed as a terminal tab. Spawned as\n * a same-pod child (`session:spawnTui` with mode \"shell\") so a human can poke\n * around the workspace manually from the card's App/terminal tabs.\n *\n * The sibling of AdhocSessionRunner minus the Claude harness: connect →\n * register → spawn `$SHELL -l` under node-pty in the workspace checkout →\n * relay raw bytes over the S2 relay (ptyOutput/ptyInput/ptyResize). The tab\n * ends when the human exits the shell, the roster kill sends session:stop, or\n * the pod goes down. Idle-sleep stays server-owned; the runner's own idle\n * timer is the backstop, re-armed on every keystroke so an actively-used\n * shell never trips it.\n */\nimport { AgentConnection, type AgentConnectionConfig } from \"../connection/agent-connection.js\";\nimport { Lifecycle, DEFAULT_LIFECYCLE_CONFIG, type LifecycleConfig } from \"./lifecycle.js\";\nimport {\n resolvePtySpawn,\n inheritedEnv,\n type PtyProcess,\n type PtySpawn,\n} from \"../harness/pty/pty-support.js\";\n\nconst DEFAULT_COLS = 80;\nconst DEFAULT_ROWS = 24;\n\nexport interface ShellSessionRunnerConfig {\n connection: AgentConnectionConfig;\n /** Repo checkout the shell starts in. */\n workspaceDir: string;\n /** Shell binary override; falls back to $SHELL, then bash. */\n shell?: string;\n lifecycle?: Partial<LifecycleConfig>;\n}\n\n/** AgentConnection surface the shell runner needs (injectable for tests). */\nexport interface ShellRunnerConnection {\n connect(): Promise<void>;\n disconnect(): void;\n call(method: \"connectAgent\", payload: { sessionId: string }): Promise<unknown>;\n sendEvent(event: { type: string; [key: string]: unknown }): void;\n sendHeartbeat(): void;\n emitStatus(status: string): Promise<void>;\n onStop(callback: () => void): void;\n refreshTaskTokenFromBootstrap(): Promise<boolean>;\n sendPtyOutput(data: string, dims?: { cols: number; rows: number }): void;\n sendPtyEnded(): void;\n onPtyInput(handler: (data: string) => void): () => void;\n onPtyResize(handler: (cols: number, rows: number) => void): () => void;\n}\n\n/**\n * The shell's env: the pod env minus this session's Conveyor identity. The\n * human at the prompt doesn't need the session JWT sitting in `env` output —\n * and a copied token must not leak task authority into pasted shell logs.\n */\nexport function buildShellEnv(baseEnv: Record<string, string>): Record<string, string> {\n const env = { ...baseEnv };\n delete env.CONVEYOR_TASK_TOKEN;\n delete env.CONVEYOR_SESSION_ID;\n return env;\n}\n\nexport class ShellSessionRunner {\n readonly connection: ShellRunnerConnection;\n readonly lifecycle: Lifecycle;\n\n private readonly config: ShellSessionRunnerConfig;\n private readonly loadSpawn: () => Promise<PtySpawn>;\n private pty: PtyProcess | null = null;\n private dims = { cols: DEFAULT_COLS, rows: DEFAULT_ROWS };\n private stopped = false;\n private _finalState: \"finished\" | \"error\" | null = null;\n\n constructor(\n config: ShellSessionRunnerConfig,\n deps?: { connection?: ShellRunnerConnection; loadSpawn?: () => Promise<PtySpawn> },\n ) {\n this.config = config;\n this.connection = deps?.connection ?? new AgentConnection(config.connection);\n // resolvePtySpawn, not loadPtySpawn: the human's shell must run in the\n // workbench container (next to the real checkout) in split-mode pods, not\n // in the 1Gi agent sidecar whose repo copy is a stale bake artifact.\n this.loadSpawn = deps?.loadSpawn ?? resolvePtySpawn;\n this.lifecycle = new Lifecycle(\n // No git flush — the human commits/pushes explicitly from the shell.\n { ...DEFAULT_LIFECYCLE_CONFIG, gitFlushIntervalMs: 0, ...config.lifecycle },\n {\n onHeartbeat: () => this.connection.sendHeartbeat(),\n onIdleTimeout: () => this.requestStop(),\n onDormantTimeout: () => this.requestStop(),\n onTokenRefresh: () => void this.connection.refreshTaskTokenFromBootstrap().catch(() => {}),\n onGitFlush: () => {},\n onUsageSample: () => {},\n },\n );\n }\n\n get finalState(): \"finished\" | \"error\" | null {\n return this._finalState;\n }\n\n get isStopped(): boolean {\n return this.stopped;\n }\n\n /** Connect, register, spawn the shell, and relay it until exit or stop. */\n async run(): Promise<void> {\n try {\n await this.connection.connect();\n this.connection.sendEvent({\n type: \"connected\",\n sessionId: this.config.connection.sessionId,\n });\n this.connection.onStop(() => this.requestStop());\n this.lifecycle.startHeartbeat();\n this.lifecycle.startTokenRefresh();\n\n await this.connection.call(\"connectAgent\", {\n sessionId: this.config.connection.sessionId,\n });\n await this.connection.emitStatus(\"running\");\n this.lifecycle.startIdleTimer();\n\n await this.runShell();\n this._finalState = \"finished\";\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n process.stderr.write(`[conveyor-agent] Shell runner failed: ${message}\\n`);\n this.connection.sendEvent({ type: \"error\", message });\n this._finalState = \"error\";\n } finally {\n this.shutdown();\n }\n }\n\n /** Spawn the login shell under a PTY and block until it exits or stop(). */\n private async runShell(): Promise<void> {\n const spawn = await this.loadSpawn();\n const shell = this.config.shell ?? process.env.SHELL ?? \"bash\";\n const pty = spawn(shell, [\"-l\"], {\n name: \"xterm-256color\",\n cols: this.dims.cols,\n rows: this.dims.rows,\n cwd: this.config.workspaceDir,\n env: buildShellEnv(inheritedEnv()),\n });\n this.pty = pty;\n\n const unsubInput = this.connection.onPtyInput((data) => {\n // A keystroke is real human activity — re-arm the idle backstop.\n this.lifecycle.startIdleTimer();\n pty.write(data);\n });\n const unsubResize = this.connection.onPtyResize((cols, rows) => {\n this.dims = { cols, rows };\n pty.resize(cols, rows);\n });\n pty.onData((data) => this.connection.sendPtyOutput(data, this.dims));\n\n try {\n await new Promise<void>((resolve) => {\n pty.onExit(() => resolve());\n });\n } finally {\n unsubInput();\n unsubResize();\n this.pty = null;\n // The shell is gone and no respawn is coming — hide the tab now instead\n // of waiting for the lease to lapse.\n this.connection.sendPtyEnded();\n }\n }\n\n stop(): void {\n this.requestStop();\n }\n\n private requestStop(): void {\n if (this.stopped) return;\n this.stopped = true;\n try {\n this.pty?.kill();\n } catch {\n /* already gone */\n }\n }\n\n private shutdown(): void {\n this.stopped = true;\n this.lifecycle.destroy();\n this.connection.sendEvent({ type: \"shutdown\", reason: this._finalState ?? \"finished\" });\n this.connection.disconnect();\n }\n}\n","/**\n * Boot factory for same-pod spawned children (session:spawnTui). Keeps the\n * CLI entry lean: given the env-derived identity, constructs the right runner\n * — an interactive Claude TUI (mode \"adhoc\" WITH a task id, unlike the\n * task-less Sessions-view adhoc pods) or a raw login shell (mode \"shell\").\n */\nimport { createServiceLogger } from \"../utils/logger.js\";\nimport { AdhocSessionRunner } from \"./adhoc-session-runner.js\";\nimport { ShellSessionRunner } from \"./shell-session-runner.js\";\n\nconst logger = createServiceLogger(\"SpawnedChildBoot\");\n\nexport interface SpawnedChildInputs {\n mode: \"adhoc\" | \"shell\";\n apiUrl: string;\n taskToken: string;\n /** The spawned WorkspaceSession id (CONVEYOR_SESSION_ID on the child). */\n sessionId: string;\n workspaceDir: string;\n /** For the adhoc runner's connected-event payload (CONVEYOR_PROJECT_ID). */\n projectId: string;\n}\n\nexport interface SpawnedChildRunner {\n run(): Promise<void>;\n stop(): void;\n readonly finalState: \"finished\" | \"error\" | null;\n}\n\nexport function createSpawnedChildRunner(inputs: SpawnedChildInputs): SpawnedChildRunner {\n if (inputs.mode === \"shell\") {\n return new ShellSessionRunner({\n connection: {\n apiUrl: inputs.apiUrl,\n taskToken: inputs.taskToken,\n sessionId: inputs.sessionId,\n runnerMode: \"shell\",\n },\n workspaceDir: inputs.workspaceDir,\n });\n }\n return new AdhocSessionRunner(\n {\n connection: {\n apiUrl: inputs.apiUrl,\n taskToken: inputs.taskToken,\n sessionId: inputs.sessionId,\n runnerMode: \"adhoc\",\n },\n projectId: inputs.projectId,\n // Session lineage key. NOT the inherited CONVEYOR_WORKSPACE_ID — that's\n // the builder's lineage; concurrent tabs must each be their own Claude\n // conversation, so key on the spawned session id.\n workspaceId: inputs.sessionId,\n workspaceDir: inputs.workspaceDir,\n },\n {\n onEvent: (event) => {\n logger.info(\"Spawned TUI event\", { eventType: event.type as string });\n },\n },\n );\n}\n","import type { RunnerMode } from \"../types.js\";\n\n/**\n * Runner modes that act as a \"builder\" pod and therefore host same-pod spawned\n * children — review children (`session:spawnReview`) and TUI/shell tabs\n * (`session:spawnTui`).\n *\n * `pack` MUST be here alongside `task`. The server's same-pod router picks the\n * task's PRIMARY workspace writer regardless of whether that writer is a task\n * or pack builder, so a pack pod that ignored `session:spawnReview` silently\n * dropped every review pushed to it: the review session sat undelivered until\n * the 10-minute boot grace expired and the stale sweep reclaimed the claim.\n */\nexport function hostsSpawnedChildren(mode: RunnerMode): boolean {\n return mode === \"task\" || mode === \"pack\";\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAEA,SAAS,oBAAoB;AAC7B,SAAS,QAAAA,OAAM,WAAAC,gBAAe;AAC9B,SAAS,qBAAqB;;;ACJ9B,OAAO,SAAS;AAgDhB,IAAM,sBAAsB;AAC5B,IAAM,sBAAsB;AAC5B,IAAM,sBAAsB;AAC5B,IAAM,mCAAmC;AACzC,IAAM,2BAA2B;AAEjC,IAAM,wBAAwB;AAC9B,IAAM,wBAAwB;AAE9B,SAAS,cAAc,OAAe,aAA4D;AAChG,QAAM,UAAU,MAAM,KAAK,EAAE,QAAQ,iBAAiB,EAAE;AACxD,MAAI,CAAC,QAAS,QAAO;AACrB,QAAM,MAAM,QAAQ,YAAY,GAAG;AACnC,MAAI,QAAQ,IAAI;AACd,WAAO,EAAE,MAAM,SAAS,MAAM,YAAY;AAAA,EAC5C;AACA,QAAM,OAAO,QAAQ,MAAM,GAAG,GAAG,KAAK;AACtC,QAAM,OAAO,OAAO,QAAQ,MAAM,MAAM,CAAC,CAAC;AAC1C,SAAO,EAAE,MAAM,MAAM,OAAO,SAAS,IAAI,IAAI,OAAO,YAAY;AAClE;AAOO,SAAS,sBAAsB,MAAyB,QAAQ,KAAsB;AAC3F,QAAM,UAA2B,CAAC;AAElC,QAAM,cAAc,IAAI;AACxB,MAAI,aAAa;AACf,QAAI;AACF,YAAM,MAAM,IAAI,IAAI,WAAW;AAC/B,YAAM,OAAO,IAAI,YAAY;AAC7B,YAAM,OAAO,IAAI,OAAO,OAAO,IAAI,IAAI,IAAI;AAC3C,UAAI,OAAO,SAAS,IAAI,GAAG;AACzB,gBAAQ,KAAK,EAAE,MAAM,YAAY,MAAM,MAAM,WAAW,oBAAoB,CAAC;AAAA,MAC/E;AAAA,IACF,QAAQ;AAAA,IAER;AAAA,EACF;AAEA,QAAM,eAAe,IAAI;AACzB,MAAI,cAAc;AAChB,UAAM,SAAS,cAAc,cAAc,qBAAqB;AAChE,QAAI,QAAQ;AACV,cAAQ,KAAK;AAAA,QACX,MAAM;AAAA,QACN,MAAM,OAAO;AAAA,QACb,MAAM,OAAO;AAAA,QACb,WAAW;AAAA,MACb,CAAC;AAAA,IACH;AAAA,EACF;AAEA,SAAO;AACT;AAEA,SAAS,aAAoB;AAC3B,QAAM,QAAQ,IAAI,MAAM,mBAAmB;AAC3C,QAAM,OAAO;AACb,SAAO;AACT;AAEA,SAAS,eAAe,QAA4B;AAClD,MAAI,QAAQ,QAAS,OAAM,WAAW;AACxC;AAEA,SAAS,aAAa,QAAuB,QAAwC;AACnF,iBAAe,MAAM;AACrB,SAAO,IAAI,QAAQ,CAAC,YAAY;AAC9B,QAAI,UAAU;AACd,UAAM,SAAS,IAAI,iBAAiB,EAAE,MAAM,OAAO,MAAM,MAAM,OAAO,KAAK,CAAC;AAC5E,UAAM,OAAO,CAAC,OAAgB;AAC5B,UAAI,QAAS;AACb,gBAAU;AACV,aAAO,QAAQ;AACf,cAAQ,oBAAoB,SAAS,OAAO;AAC5C,cAAQ,EAAE;AAAA,IACZ;AACA,UAAM,UAAU,MAAY,KAAK,KAAK;AACtC,WAAO,KAAK,WAAW,MAAM,KAAK,IAAI,CAAC;AACvC,WAAO,KAAK,SAAS,MAAM,KAAK,KAAK,CAAC;AACtC,WAAO,WAAW,0BAA0B,MAAM,KAAK,KAAK,CAAC;AAC7D,YAAQ,iBAAiB,SAAS,SAAS,EAAE,MAAM,KAAK,CAAC;AAAA,EAC3D,CAAC;AACH;AAEA,IAAM,QAAQ,CAAC,IAAY,WAAwC;AACjE,iBAAe,MAAM;AACrB,SAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AACtC,UAAM,QAAQ,WAAW,MAAM;AAC7B,cAAQ,oBAAoB,SAAS,OAAO;AAC5C,cAAQ;AAAA,IACV,GAAG,EAAE;AACL,UAAM,UAAU,MAAY;AAC1B,mBAAa,KAAK;AAClB,aAAO,WAAW,CAAC;AAAA,IACrB;AACA,YAAQ,iBAAiB,SAAS,SAAS,EAAE,MAAM,KAAK,CAAC;AAAA,EAC3D,CAAC;AACH;AAEA,SAAS,cAAiB,SAAqB,QAAkC;AAC/E,MAAI,CAAC,OAAQ,QAAO;AACpB,iBAAe,MAAM;AACrB,SAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AACtC,UAAM,UAAU,MAAY,OAAO,WAAW,CAAC;AAC/C,WAAO,iBAAiB,SAAS,SAAS,EAAE,MAAM,KAAK,CAAC;AACxD,SAAK,QAAQ;AAAA,MACX,CAAC,UAAU;AACT,eAAO,oBAAoB,SAAS,OAAO;AAC3C,gBAAQ,KAAK;AAAA,MACf;AAAA,MACA,CAAC,UAAmB;AAClB,eAAO,oBAAoB,SAAS,OAAO;AAC3C,eAAO,KAAK;AAAA,MACd;AAAA,IACF;AAAA,EACF,CAAC;AACH;AAEA,eAAe,cACb,QACA,MAOe;AACf,QAAM,EAAE,OAAO,gBAAgB,OAAO,OAAO,IAAI;AACjD,QAAM,YAAY,KAAK,aAAa,OAAO,aAAa;AACxD,QAAM,WAAW,KAAK,IAAI,IAAI;AAC9B,QAAM,eAAe,OAAO,IAAI,OAAO,OAAO,IAAI,IAAI,OAAO,IAAI,KAAK;AAEtE,SAAO,MAAM;AACX,mBAAe,MAAM;AACrB,QAAI,MAAM,cAAc,MAAM,QAAQ,MAAM,GAAG,MAAM,GAAG;AACtD,YAAM,GAAG,OAAO,IAAI,WAAW;AAC/B;AAAA,IACF;AACA,QAAI,KAAK,IAAI,KAAK,UAAU;AAC1B;AAAA,QACE,YAAY,OAAO,IAAI,oBAAoB,KAAK,MAAM,YAAY,GAAI,CAAC;AAAA,MACzE;AACA;AAAA,IACF;AACA,UAAM,MAAM,gBAAgB,MAAM;AAAA,EACpC;AACF;AAOA,eAAsB,gBAAgB,OAA+B,CAAC,GAAkB;AACtF,QAAM;AAAA,IACJ,MAAM,QAAQ;AAAA,IACd,QAAQ,MAAM;AAAA,IAAC;AAAA,IACf;AAAA,IACA,iBAAiB;AAAA,IACjB,QAAQ;AAAA,IACR;AAAA,EACF,IAAI;AAEJ,iBAAe,MAAM;AAErB,QAAM,UAAU,sBAAsB,GAAG;AACzC,MAAI,QAAQ,WAAW,EAAG;AAE1B,QAAM,QAAQ;AAAA,IACZ,QAAQ;AAAA,MAAI,CAAC,WACX,cAAc,QAAQ,EAAE,OAAO,WAAW,gBAAgB,OAAO,OAAO,CAAC;AAAA,IAC3E;AAAA,EACF;AACF;;;ACnOA,SAAS,UAAU,SAAS,YAAY;AAgDxC,IAAM,2BAA2B;AAAA,EAC/B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAeA,IAAM,iBAAiB;AAIhB,IAAM,yBAAyB;AAEtC,SAAS,YAAY,SAA6B,KAAsB;AACtE,UAAQ,WAAW,IAChB,MAAM,GAAG,EACT,IAAI,CAAC,UAAU,MAAM,KAAK,CAAC,EAC3B,SAAS,GAAG;AACjB;AAEA,SAAS,WAAW,KAAiC;AACnD,QAAM,OAAO,IAAI,yBAAyB,KAAK,EAAE,YAAY;AAC7D,SAAO,SAAS,OAAO,SAAS;AAClC;AAKA,SAAS,qBAAqB,YAA4B;AACxD,QAAM,MAAM,QAAQ,UAAU;AAC9B,SAAO,SAAS,GAAG,MAAM,WAAW,QAAQ,GAAG,IAAI;AACrD;AAgBA,eAAsB,sBACpB,SACgC;AAChC,QAAM,EAAE,cAAc,IAAI,IAAI;AAC9B,QAAM,aAAa,QAAQ,cAAc;AACzC,MAAI,WAAW,GAAG,EAAG,QAAO;AAK5B,QAAM,WAAW,IAAI,iCAAiC,KAAK;AAC3D,MAAI,SAAU,QAAO,EAAE,SAAS,UAAU,KAAK,cAAc,QAAQ,WAAW;AAEhF,MAAI,CAAC,YAAY,IAAI,eAAe,YAAY,EAAG,QAAO;AAG1D,MAAI,CAAC,IAAI,cAAc,KAAK,EAAG,QAAO;AAEtC,aAAW,YAAY,0BAA0B;AAC/C,UAAM,aAAa,KAAK,cAAc,QAAQ;AAC9C,QAAI,MAAM,WAAW,UAAU,GAAG;AAChC,aAAO,EAAE,SAAS,gBAAgB,KAAK,qBAAqB,UAAU,GAAG,QAAQ,SAAS;AAAA,IAC5F;AAAA,EACF;AACA,SAAO;AACT;AAeA,eAAsB,gBAAgB,SAA6D;AACjG,MAAI,OAA8B;AAClC,MAAI;AACF,WAAO,MAAM,sBAAsB,OAAO;AAAA,EAC5C,QAAQ;AACN,WAAO;AAAA,EACT;AACA,MAAI,CAAC,KAAM,QAAO;AAElB,QAAM,EAAE,UAAU,WAAW,IAAI;AACjC,WAAS,UAAU,wBAAwB,KAAK,MAAM,MAAM,KAAK,OAAO;AAAA,CAAI;AAC5E,QAAM,aAAa,IAAI,gBAAgB;AACvC,QAAM,QAAQ,MAAY,WAAW,MAAM;AAC3C,UAAQ,QAAQ,iBAAiB,SAAS,OAAO,EAAE,MAAM,KAAK,CAAC;AAC/D,QAAM,QAAQ,WAAW,OAAO,QAAQ,aAAa,sBAAsB;AAC3E,QAAM,MAAM;AACZ,MAAI;AACF,UAAM,WAAW,KAAK,SAAS,KAAK,KAAK,UAAU,WAAW,MAAM;AACpE,aAAS,UAAU,uBAAuB;AAC1C,WAAO;AAAA,EACT,SAAS,OAAO;AACd,UAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AACrE,aAAS,UAAU,4BAA4B,OAAO;AAAA,CAAI;AAC1D,WAAO;AAAA,EACT,UAAE;AACA,iBAAa,KAAK;AAClB,YAAQ,QAAQ,oBAAoB,SAAS,KAAK;AAAA,EACpD;AACF;;;AChLA,SAAS,QAAAC,aAAY;AAoErB,IAAM,8BAA8B,CAAC,yBAAyB;AAI9D,IAAM,cAAc;AAKb,IAAM,uBAAuB;AAMpC,IAAM,mBAAmB;AAEzB,SAASC,YAAW,KAAiC;AACnD,QAAM,OAAO,IAAI,oBAAoB,KAAK,EAAE,YAAY;AACxD,SAAO,SAAS,OAAO,SAAS;AAClC;AAQA,IAAM,mBAAmB;AAEzB,IAAM,eAAe,MAAmB;AACtC,QAAM,QAAQ,IAAI,YAAY,GAAG;AACjC,WAAS,QAAQ,GAAG,QAAQ,KAAK,SAAS;AACxC,QAAI,QAAQ,SAAS;AACrB,aAAS,MAAM,GAAG,MAAM,GAAG,OAAO;AAChC,cAAQ,QAAQ,cAAe,SAAS,IAAK,sBAAsB,IAAK,SAAS,MAAO;AAAA,IAC1F;AACA,UAAM,KAAK,IAAI,UAAU;AAAA,EAC3B;AACA,SAAO;AACT,GAAG;AAEI,SAAS,WAAW,OAA2B;AACpD,MAAI,MAAM;AACV,aAAW,QAAQ,OAAO;AACxB,WAAQ,OAAO,IAAM,aAAc,QAAQ,KAAM,QAAQ,GAAI,OAAkB;AAAA,EACjF;AACA,WAAS,SAAS,MAAM,QAAQ,SAAS,GAAG,YAAY,GAAG;AACzD,WAAQ,OAAO,IAAM,aAAc,QAAQ,KAAO,SAAS,OAAS,GAAI,OAAkB;AAAA,EAC5F;AACA,SAAO,CAAC,QAAQ;AAClB;AAGO,SAAS,mBAAmB,OAA2B;AAC5D,SAAO,GAAG,WAAW,KAAK,CAAC,IAAI,MAAM,MAAM;AAC7C;AAgBA,eAAe,iBAAiB,MAAgC;AAC9D,UAAQ,MAAM,kBAAkB,IAAI,GAAG;AACzC;AAKA,eAAe,cACb,SAGmD;AACnD,QAAM,EAAE,cAAc,UAAU,IAAI;AACpC,MAAI;AACJ,MAAI;AACF,UAAM,MAAM,MAAM,UAAUC,MAAK,cAAc,8BAA8B,CAAC;AAC9E,UAAM,SAAkB,KAAK,MAAM,OAAO,KAAK,GAAG,EAAE,SAAS,MAAM,CAAC;AACpE,UAAM,QAAS,QAA4C;AAC3D,QAAI,OAAO,UAAU,YAAY,CAAC,MAAO,QAAO;AAChD,YAAQ;AAAA,EACV,QAAQ;AACN,WAAO;AAAA,EACT;AAEA,MAAI;AACF,UAAM,SAAS,mBAAmB,MAAM,UAAUA,MAAK,cAAc,UAAU,CAAC,CAAC;AACjF,WAAO,WAAW,QAAQ,OAAO,EAAE,OAAO,OAAO;AAAA,EACnD,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAOA,eAAsB,oBACpB,SAC8B;AAC9B,QAAM,EAAE,cAAc,IAAI,IAAI;AAC9B,QAAM,aAAa,QAAQ,cAAc;AACzC,QAAM,YAAY,QAAQ,aAAa;AACvC,QAAM,YAAY,QAAQ,aAAa;AACvC,MAAID,YAAW,GAAG,EAAG,QAAO;AAG5B,MAAI,CAAE,MAAM,WAAWC,MAAK,cAAc,cAAc,CAAC,EAAI,QAAO;AAMpE,QAAM,WAAW,IAAI,4BAA4B,KAAK;AAEtD,QAAM,iBAAiB,YAA6B;AAClD,QAAI,SAAU,QAAO;AACrB,eAAW,YAAY,6BAA6B;AAClD,UAAI,MAAM,WAAWA,MAAK,cAAc,QAAQ,CAAC,EAAG,QAAO,QAAQ,QAAQ;AAAA,IAC7E;AACA,WAAO;AAAA,EACT;AAEA,MAAI,CAAE,MAAM,UAAUA,MAAK,cAAc,cAAc,CAAC,GAAI;AAC1D,WAAO;AAAA,MACL,SAAS,MAAM,eAAe;AAAA,MAC9B,KAAK;AAAA,MACL,QAAQ;AAAA,MACR,QAAQ;AAAA,IACV;AAAA,EACF;AAEA,QAAM,QAAQ,MAAM,cAAc,EAAE,cAAc,UAAU,CAAC;AAC7D,MAAI,OAAO;AACT,WAAO;AAAA,MACL,SAAS,MAAM,eAAe;AAAA,MAC9B,KAAK;AAAA,MACL,QAAQ;AAAA,MACR,QAAQ,gDAAgD,MAAM,KAAK,iBAAiB,MAAM,MAAM;AAAA,IAClG;AAAA,EACF;AAEA,SAAO;AACT;AAuBA,SAAS,gBAAgB,MAAoB,OAAgB,KAAgC;AAC3F,QAAM,QAAQ,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AACnE,QAAM,QAAQ;AAAA,IACZ,8BAA8B,KAAK,MAAM,MAAM,KAAK,MAAM;AAAA,IAC1D,SAAS,KAAK,OAAO,SAAS,KAAK,GAAG,WAAM,KAAK;AAAA,EACnD;AACA,MAAI,CAAC,IAAI,gBAAgB,GAAG,KAAK,GAAG;AAClC,UAAM;AAAA,MACJ,GAAG,gBAAgB;AAAA,IACrB;AAAA,EACF;AACA,SAAO,MAAM,KAAK,GAAG;AACvB;AAQA,eAAsB,YAAY,SAAsD;AACtF,MAAI,OAA4B;AAChC,MAAI;AACF,WAAO,MAAM,oBAAoB,OAAO;AAAA,EAC1C,QAAQ;AACN,WAAO,EAAE,SAAS,UAAU;AAAA,EAC9B;AACA,MAAI,CAAC,KAAM,QAAO,EAAE,SAAS,UAAU;AAEvC,QAAM,EAAE,UAAU,YAAY,IAAI,IAAI;AACtC,WAAS,UAAU,UAAU,KAAK,MAAM;AAAA,CAAI;AAC5C,WAAS,UAAU,sBAAsB,KAAK,MAAM,MAAM,KAAK,OAAO;AAAA,CAAI;AAC1E,QAAM,aAAa,IAAI,gBAAgB;AACvC,QAAM,QAAQ,MAAY,WAAW,MAAM;AAC3C,UAAQ,QAAQ,iBAAiB,SAAS,OAAO,EAAE,MAAM,KAAK,CAAC;AAC/D,QAAM,QAAQ,WAAW,OAAO,QAAQ,aAAa,oBAAoB;AACzE,QAAM,MAAM;AACZ,MAAI;AACF,UAAM,WAAW,KAAK,SAAS,KAAK,KAAK,UAAU,WAAW,MAAM;AACpE,aAAS,UAAU,iCAAiC;AACpD,WAAO,EAAE,SAAS,YAAY;AAAA,EAChC,SAAS,OAAO;AACd,UAAM,UAAU,gBAAgB,MAAM,OAAO,GAAG;AAChD,aAAS,UAAU,UAAU,OAAO;AAAA,CAAI;AACxC,WAAO,EAAE,SAAS,UAAU,QAAQ;AAAA,EACtC,UAAE;AACA,iBAAa,KAAK;AAClB,YAAQ,QAAQ,oBAAoB,SAAS,KAAK;AAAA,EACpD;AACF;;;ACvQA,SAAS,0BASP;AACA,MAAI,iBAAiB,GAAG;AACtB,UAAM,SAAS,mBAAmB;AAClC,WAAO;AAAA,MACL,iBAAiB,CAAC,KAAK,KAAK,aAAa,OAAO,gBAAgB,KAAK,KAAK,QAAQ;AAAA,MAClF,iBAAiB,CAAC,KAAK,KAAK,UAAU,WACpC,OAAO,gBAAgB,KAAK,KAAK,UAAU,MAAM;AAAA,IACrD;AAAA,EACF;AACA,SAAO,EAAE,iBAAiB,iBAAiB,gBAAgB;AAC7D;AA4CA,IAAM,qBAAqB,CAAC,QAAsB,SAAuB;AACvE,GAAC,WAAW,WAAW,QAAQ,SAAS,QAAQ,QAAQ,MAAM,IAAI;AACpE;AAEO,SAAS,sBACd,YACe;AACf,SAAO,YAAY,KAAK,KAAK,QAAQ,QAAQ;AAC/C;AAeA,eAAsB,mCACpB,SACmB;AACnB,QAAM,YAAY,MAAM,QAAQ,QAAQ;AACxC,MAAI,CAAC,aAAa,QAAQ,eAAe,EAAG,QAAO;AACnD,QAAM,aAAa,QAAQ,OAAO;AAClC,aAAW,MAAM;AACjB,SAAO;AACT;AAOO,IAAM,6BAAN,MAAiC;AAAA,EACrB,kBAAkB,IAAI,gBAAgB;AAAA,EACtC,4BAA4B,oBAAI,QAA2B;AAAA,EAC3D;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EAGA;AAAA,EAGA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EAET,oBAA8C;AAAA,EACrC,2BAA2B,oBAAI,IAAuB;AAAA,EACtD,2BAA2B,oBAAI,QAA0C;AAAA,EACzE,0BAA0B,oBAAI,QAA0C;AAAA,EACxE,yBAAyB,oBAAI,QAAuC;AAAA,EACpE,kBAAkB,oBAAI,IAAmB;AAAA,EAClD,oBAAmC,QAAQ,QAAQ;AAAA,EACnD,kBAAwC;AAAA,EACxC,8BAA8B;AAAA,EAC9B,UAAU;AAAA,EACV,UAAU;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQV;AAAA,EACS,YAAY,IAAI,QAAc,CAAC,YAAY;AAC1D,SAAK,mBAAmB;AAAA,EAC1B,CAAC;AAAA,EAED,YAAY,SAA4C;AACtD,SAAK,SAAS,QAAQ;AACtB,SAAK,eAAe,QAAQ;AAC5B,SAAK,aAAa,QAAQ;AAC1B,SAAK,MAAM,QAAQ,OAAO,QAAQ;AAClC,SAAK,kBACH,QAAQ,kBACP,CAAC,SACA,cAAc;AAAA,MACZ,OAAO,KAAK;AAAA,MACZ,QAAQ,KAAK;AAAA,IACf,CAAC;AACL,SAAK,oBACH,QAAQ,oBACP,CAAC,SAAS,gBAAgB,EAAE,OAAO,KAAK,OAAO,QAAQ,KAAK,OAAO,CAAC;AACvE,UAAM,YAAY,wBAAwB;AAC1C,SAAK,oBAAoB,QAAQ,mBAAmB,UAAU;AAC9D,SAAK,iBACH,QAAQ,iBACP,CAAC,SACA,gBAAgB;AAAA,MACd,cAAc,KAAK;AAAA,MACnB,KAAK,KAAK;AAAA,MACV,YAAY,UAAU;AAAA,MACtB,UAAU,KAAK;AAAA,MACf,QAAQ,KAAK;AAAA,IACf,CAAC;AACL,SAAK,aACH,QAAQ,aACP,CAAC,SACA,YAAY;AAAA,MACV,cAAc,KAAK;AAAA,MACnB,KAAK,KAAK;AAAA,MACV,YAAY,UAAU;AAAA,MACtB,UAAU,KAAK;AAAA,MACf,QAAQ,KAAK;AAAA,IACf,CAAC;AACL,SAAK,qBAAqB,QAAQ,oBAAoB;AACtD,SAAK,cAAc,QAAQ,eAAe;AAC1C,SAAK,wBAAwB,QAAQ,yBAAyB;AAC9D,SAAK,wBACH,QAAQ,wBACP,CAAC,QAAQ;AAER,WAAK,oBAAoB,EAAE,KAAK,KAAK,KAAK,IAAI,CAAC;AAAA,IACjD;AAAA,EACJ;AAAA,EAEA,QAAc;AACZ,QAAI,KAAK,WAAW,KAAK,QAAS;AAClC,SAAK,UAAU;AACf,SAAK,WAAW,kBAAkB,MAAM,KAAK,oBAAoB,CAAC;AAElE,QAAI,KAAK,QAAQ;AACf,WAAK;AAAA,QACH,KAAK,iBAAiB,EAAE,MAAM,CAAC,UAAmB,KAAK,sBAAsB,KAAK,CAAC;AAAA,MACrF;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,kBAAwB;AACtB,SAAK,iBAAiB;AAAA,EACxB;AAAA,EAEA,OAAsB;AACpB,QAAI,KAAK,gBAAiB,QAAO,KAAK;AACtC,SAAK,UAAU;AAIf,SAAK,iBAAiB;AACtB,SAAK,gBAAgB,MAAM;AAC3B,UAAM,kBAAkB,CAAC,GAAG,KAAK,eAAe;AAChD,UAAM,cAAc,KAAK,0BAA0B;AACnD,SAAK,mBAAmB,YAAY;AAClC,YAAM,QAAQ,WAAW,CAAC,aAAa,KAAK,mBAAmB,GAAG,eAAe,CAAC;AAClF,YAAM,KAAK,0BAA0B;AAAA,IACvC,GAAG;AACH,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,MAAc,mBAAkC;AAC9C,UAAM,WAAW,MAAM,KAAK,gBAAgB;AAAA,MAC1C,OAAO,CAAC,YAAY,KAAK,mBAAmB,UAAU,SAAS,OAAO;AAAA,CAAI;AAAA,MAC1E,QAAQ,KAAK,gBAAgB;AAAA,IAC/B,CAAC;AACD,QAAI,KAAK,QAAS;AAClB,QAAI,aAAa,YAAY,aAAa,WAAW;AACnD,WAAK,WAAW,UAAU;AAAA,QACxB,MAAM;AAAA,QACN,SAAS;AAAA,MACX,CAAC;AACD;AAAA,IACF;AAKA,UAAM,KAAK,kBAAkB;AAAA,MAC3B,OAAO,CAAC,YAAY,KAAK,mBAAmB,UAAU,cAAc,OAAO;AAAA,CAAI;AAAA,MAC/E,QAAQ,KAAK,gBAAgB;AAAA,IAC/B,CAAC;AACD,QAAI,KAAK,QAAS;AAClB,SAAK,sBAAsB,gBAAgB;AAO3C,UAAM,KAAK;AACX,QAAI,KAAK,QAAS;AAMlB,UAAM,KAAK,SAAS;AACpB,QAAI,KAAK,QAAS;AAQlB,UAAM,KAAK,aAAa;AACxB,QAAI,KAAK,QAAS;AAKlB,UAAM,sBAAsB,KAAK,QAAQ,eACrC,MAAM,KAAK,2BAA2B,KAAK,OAAO,YAAY,IAC9D;AACJ,QAAI,KAAK,QAAS;AAIlB,SAAK,sBAAsB,wBAAwB;AAEnD,UAAM,eAAe,MAAM,KAAK,mBAAmB,KAAK,YAAY;AACpE,QAAI,KAAK,QAAS;AAClB,UAAM,eAAe,yBAAyB,YAAY;AAC1D,SAAK,WAAW,UAAU;AAAA,MACxB,MAAM;AAAA,MACN;AAAA,MACA,GAAI,aAAa,SAAS,IAAI,EAAE,aAAa,IAAI,CAAC;AAAA,IACpD,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAc,WAA0B;AACtC,UAAM,SAAS,MAAM,KAAK,WAAW;AAAA,MACnC,UAAU,CAAC,QAAQ,SAAS,KAAK,mBAAmB,QAAQ,IAAI;AAAA,MAChE,QAAQ,KAAK,gBAAgB;AAAA,IAC/B,CAAC;AACD,QAAI,OAAO,YAAY,YAAY,KAAK,QAAS;AACjD,SAAK,WAAW,UAAU;AAAA,MACxB,MAAM;AAAA,MACN,SACE,OAAO,WACP;AAAA,IACJ,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA,EAKA,MAAc,eAA8B;AAC1C,UAAM,UAAU,MAAM,KAAK,eAAe;AAAA,MACxC,UAAU,CAAC,QAAQ,SAAS,KAAK,mBAAmB,QAAQ,IAAI;AAAA,MAChE,QAAQ,KAAK,gBAAgB;AAAA,IAC/B,CAAC;AACD,QAAI,YAAY,YAAY,KAAK,QAAS;AAC1C,SAAK,WAAW,UAAU;AAAA,MACxB,MAAM;AAAA,MACN,SACE;AAAA,IACJ,CAAC;AAAA,EACH;AAAA,EAEQ,sBAA4B;AAClC,QAAI,KAAK,WAAW,CAAC,KAAK,QAAQ,aAAc;AAChD,SAAK,WAAW,UAAU;AAAA,MACxB,MAAM;AAAA,MACN,QAAQ;AAAA,MACR,MAAM;AAAA,IACR,CAAC;AACD,SAAK,KAAK,+BAA+B,KAAK,OAAO,YAAY;AAAA,EACnE;AAAA,EAEA,MAAc,2BAA2B,SAAmC;AAC1E,QAAI,CAAC,KAAK,6BAA6B;AACrC,aAAO,KAAK,+BAA+B,OAAO;AAAA,IACpD;AACA,UAAM,KAAK;AACX,WAAO,CAAC,KAAK,WAAW,KAAK,yBAAyB,OAAO;AAAA,EAC/D;AAAA,EAEQ,+BAA+B,SAAmC;AACxE,SAAK,8BAA8B;AACnC,UAAM,YAAY,KAAK,kBAAkB,KAAK,YAAY;AACxD,UAAI,KAAK,QAAS,QAAO;AACzB,YAAM,KAAK,0BAA0B;AACrC,UAAI,KAAK,QAAS,QAAO;AACzB,aAAO,KAAK,mBAAmB,OAAO;AAAA,IACxC,CAAC;AACD,SAAK,oBAAoB,UAAU;AAAA,MACjC,MAAM;AAAA,MACN,MAAM;AAAA,IACR;AACA,WAAO;AAAA,EACT;AAAA,EAEQ,mBAAmB,SAA0B;AACnD,QAAI,KAAK,QAAS,QAAO;AACzB,SAAK,WAAW,UAAU,EAAE,MAAM,wBAAwB,CAAC;AAC3D,QAAI;AACF,YAAM,QAAQ,KAAK,kBAAkB,SAAS,KAAK,cAAc,CAAC,QAAQ,SAAS;AACjF,YAAI,KAAK,QAAS;AAClB,aAAK,WAAW,UAAU,EAAE,MAAM,wBAAwB,QAAQ,KAAK,CAAC;AACxE,aAAK,YAAY,QAAQ,IAAI;AAAA,MAC/B,CAAC;AACD,WAAK,yBAAyB,IAAI,KAAK;AACvC,YAAM,QAAQ,IAAI,QAAc,CAAC,YAAY;AAC3C,aAAK,uBAAuB,IAAI,OAAO,OAAO;AAAA,MAChD,CAAC;AACD,WAAK,wBAAwB,IAAI,OAAO,KAAK;AAC7C,UAAI,KAAK,SAAS;AAChB,aAAK,KAAK,2BAA2B,KAAK;AAC1C,eAAO;AAAA,MACT;AACA,WAAK,oBAAoB;AACzB,YAAM,GAAG,QAAQ,CAAC,MAAM,WAAW;AACjC,YAAI,KAAK,sBAAsB,MAAO,MAAK,oBAAoB;AAC/D,aAAK,yBAAyB,OAAO,KAAK;AAC1C,aAAK,sBAAsB,KAAK;AAChC,YAAI,KAAK,WAAW,KAAK,0BAA0B,IAAI,KAAK,EAAG;AAC/D,cAAM,UAAU,uBAAuB,SAAS,OAAO,KAAK,cAAc,IAAI,EAAE,GAAG,SAAS,aAAa,MAAM,MAAM,EAAE;AACvH,aAAK,WAAW,UAAU,EAAE,MAAM,wBAAwB,MAAM,QAAQ,QAAQ,CAAC;AACjF,YAAI,SAAS,QAAQ,SAAS,GAAG;AAC/B,eAAK,WAAW,UAAU;AAAA,YACxB,MAAM;AAAA,YACN,SAAS,kCAAkC,IAAI,GAAG,SAAS,aAAa,MAAM,MAAM,EAAE;AAAA,UACxF,CAAC;AAAA,QACH;AAAA,MACF,CAAC;AACD,YAAM,GAAG,SAAS,CAAC,UAAU;AAC3B,YAAI,MAAM,QAAQ,QAAW;AAC3B,cAAI,KAAK,sBAAsB,MAAO,MAAK,oBAAoB;AAC/D,eAAK,yBAAyB,OAAO,KAAK;AAC1C,eAAK,sBAAsB,KAAK;AAChC,eAAK,yBAAyB,OAAO,KAAK;AAAA,QAC5C;AACA,YAAI,KAAK,QAAS;AAClB,aAAK,WAAW,UAAU,EAAE,MAAM,uBAAuB,SAAS,MAAM,QAAQ,CAAC;AAAA,MACnF,CAAC;AACD,aAAO;AAAA,IACT,SAAS,OAAO;AACd,UAAI,CAAC,KAAK,SAAS;AACjB,aAAK,WAAW,UAAU;AAAA,UACxB,MAAM;AAAA,UACN,SAAS,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AAAA,QAChE,CAAC;AAAA,MACH;AACA,aAAO;AAAA,IACT;AAAA,EACF;AAAA,EAEQ,2BAA2B,OAAyC;AAC1E,UAAM,WAAW,KAAK,yBAAyB,IAAI,KAAK;AACxD,QAAI,SAAU,QAAO;AACrB,SAAK,0BAA0B,IAAI,KAAK;AACxC,UAAM,qBAAqB,QAAQ,QAAQ,KAAK,sBAAsB,KAAK,CAAC;AAC5E,UAAM,QAAQ,KAAK,wBAAwB,IAAI,KAAK;AACpD,UAAM,eAAe,QAAQ,QAAQ,KAAK,CAAC,oBAAoB,KAAK,CAAC,IAAI,oBACtE,KAAK,MAAM,MAAS,EACpB,QAAQ,MAAM,KAAK,yBAAyB,OAAO,KAAK,CAAC;AAC5D,SAAK,yBAAyB,IAAI,OAAO,WAAW;AACpD,WAAO;AAAA,EACT;AAAA,EAEA,MAAc,4BAA2C;AACvD,UAAM,OAAO,CAAC,GAAG,KAAK,wBAAwB,EAAE,OAAO,CAAC,UAAU,MAAM,aAAa,IAAI;AACzF,UAAM,QAAQ,IAAI,KAAK,IAAI,CAAC,UAAU,KAAK,2BAA2B,KAAK,CAAC,CAAC;AAAA,EAC/E;AAAA,EAEQ,sBAAsB,OAAgC;AAC5D,SAAK,uBAAuB,IAAI,KAAK,IAAI;AACzC,SAAK,uBAAuB,OAAO,KAAK;AACxC,SAAK,wBAAwB,OAAO,KAAK;AAAA,EAC3C;AAAA,EAEQ,oBAAoB,MAA2B;AACrD,SAAK,gBAAgB,IAAI,IAAI;AAC7B,SAAK,KAAK,QAAQ,MAAM,KAAK,gBAAgB,OAAO,IAAI,CAAC;AAAA,EAC3D;AAAA,EAEQ,mBAAmB,QAAsB,MAAoB;AACnE,QAAI,KAAK,QAAS;AAClB,SAAK,WAAW,UAAU,EAAE,MAAM,gBAAgB,QAAQ,KAAK,CAAC;AAChE,SAAK,YAAY,QAAQ,IAAI;AAAA,EAC/B;AAAA,EAEQ,sBAAsB,OAAsB;AAClD,QAAI,KAAK,QAAS;AAClB,SAAK,WAAW,UAAU;AAAA,MACxB,MAAM;AAAA,MACN,SAAS,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AAAA,IAChE,CAAC;AAAA,EACH;AACF;;;AC9dA,eAAsB,yBACpB,QACqD;AACrD,QAAM,EAAE,WAAW,QAAQ,oBAAoB,QAAAC,QAAO,IAAI;AAC1D,MAAI,CAAC,aAAa,cAAc,OAAQ,QAAO;AAC/C,MAAI;AACJ,MAAI;AACF,oBAAgB,MAAM,mBAAmB,SAAS;AAAA,EACpD,SAAS,KAAK;AACZ,UAAM,UAAU,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAC/D,IAAAA,QAAO,KAAK,oFAA+E;AAAA,MACzF;AAAA,MACA;AAAA,MACA,OAAO;AAAA,IACT,CAAC;AACD,WAAO;AAAA,EACT;AACA,MAAI,kBAAkB,QAAQ;AAC5B,IAAAA,QAAO;AAAA,MACL;AAAA,MACA,EAAE,WAAW,WAAW,QAAQ,cAAc;AAAA,IAChD;AACA,WAAO;AAAA,EACT;AACA,SAAO;AACT;;;ACEO,SAAS,aAAa,QAA0C;AACrE,SAAO,WAAW,UAAU,SAAS;AACvC;AAMO,SAAS,kBAAkB,MAOjB;AACf,QAAM,MAAoB;AAAA,IACxB,OAAO;AAAA,IACP,QAAQ,KAAK;AAAA,IACb,UAAU,KAAK;AAAA,IACf,WAAW,KAAK,MAAM,KAAK,YAAY,EAAE,IAAI;AAAA,EAC/C;AACA,MAAI,KAAK,WAAW,OAAW,KAAI,SAAS,KAAK;AACjD,MAAI,KAAK,eAAe,OAAW,KAAI,aAAa,KAAK;AACzD,QAAM,KAAK,KAAK;AAChB,MAAI,IAAI;AACN,QAAI,GAAG,cAAc,OAAW,KAAI,YAAY,GAAG;AACnD,QAAI,GAAG,WAAW,OAAW,KAAI,SAAS,GAAG;AAC7C,QAAI,GAAG,gBAAgB,OAAW,KAAI,cAAc,GAAG;AACvD,QAAI,GAAG,eAAe,OAAW,KAAI,aAAa,GAAG;AAAA,EACvD;AACA,SAAO;AACT;;;ACjDO,SAAS,6BACd,KAC8B;AAE9B,MAAI,IAAI,iBAAkB,QAAO;AACjC,MAAI,CAAC,IAAI,oBAAqB,QAAO;AACrC,MAAI,CAAC,IAAI,uBAAuB,CAAC,IAAI,uBAAuB,CAAC,IAAI,uBAAuB;AACtF,WAAO;AAAA,EACT;AAQA,MAAI,IAAI,kBAAkB,QAAQ,IAAI,kBAAkB,QAAS,QAAO;AAExE,SAAO;AAAA,IACL,WAAW,IAAI;AAAA,IACf,WAAW,IAAI;AAAA,IACf,aAAa,IAAI;AAAA,IACjB,WAAW,IAAI;AAAA,EACjB;AACF;;;ACHO,IAAM,uBAAN,MAA2B;AAAA,EACvB;AAAA,EACA;AAAA,EAEQ;AAAA,EACA;AAAA,EACT,UAAU;AAAA,EACV,eAAoC;AAAA,EACpC,cAA2C;AAAA,EAEnD,YACE,QACA,YAA2C,CAAC,GAC5C,YACA;AACA,SAAK,SAAS;AACd,SAAK,YAAY;AACjB,SAAK,aAAa,cAAc,IAAI,gBAAgB,OAAO,UAAU;AACrE,SAAK,YAAY,IAAI;AAAA;AAAA;AAAA,MAGnB,EAAE,GAAG,0BAA0B,oBAAoB,GAAG,GAAG,OAAO,UAAU;AAAA,MAC1E;AAAA,QACE,aAAa,MAAM,KAAK,WAAW,cAAc;AAAA,QACjD,eAAe,MAAM;AACnB,kBAAQ,OAAO,MAAM,+DAA+D;AACpF,eAAK,YAAY;AAAA,QACnB;AAAA,QACA,kBAAkB,MAAM,KAAK,YAAY;AAAA;AAAA;AAAA;AAAA,QAIzC,gBAAgB,MAAM,KAAK,KAAK,WAAW,8BAA8B,EAAE,MAAM,MAAM;AAAA,QAAC,CAAC;AAAA,QACzF,YAAY,MAAM;AAAA,QAAC;AAAA,QACnB,eAAe,MAAM,KAAK,KAAK,wBAAwB;AAAA,MACzD;AAAA,IACF;AAAA,EACF;AAAA,EAEA,IAAI,aAA0C;AAC5C,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,IAAI,YAAqB;AACvB,WAAO,KAAK;AAAA,EACd;AAAA;AAAA,EAGA,MAAM,MAAqB;AACzB,QAAI;AACF,YAAM,KAAK,WAAW,QAAQ;AAC9B,WAAK,WAAW,UAAU;AAAA,QACxB,MAAM;AAAA,QACN,WAAW,KAAK,OAAO,WAAW;AAAA,QAClC,WAAW,KAAK,OAAO;AAAA,MACzB,CAAC;AAED,WAAK,WAAW,OAAO,MAAM,KAAK,YAAY,CAAC;AAC/C,WAAK,WAAW,UAAU,CAAC,QAAQ,KAAK,cAAc,GAAG,CAAC;AAC1D,WAAK,UAAU,eAAe;AAC9B,WAAK,UAAU,kBAAkB;AACjC,WAAK,UAAU,iBAAiB;AAGhC,YAAM,KAAK,WAAW,KAAK,gBAAgB;AAAA,QACzC,WAAW,KAAK,OAAO,WAAW;AAAA,MACpC,CAAC;AAED,cAAQ,OAAO;AAAA,QACb,uDAAuD,KAAK,OAAO,SAAS;AAAA;AAAA,MAC9E;AACA,YAAM,KAAK,WAAW,WAAW,MAAM;AACvC,WAAK,UAAU,UAAU,EAAE,MAAM,uBAAuB,WAAW,KAAK,OAAO,UAAU,CAAC;AAE1F,WAAK,UAAU,eAAe;AAC9B,YAAM,KAAK,iBAAiB;AAC5B,WAAK,cAAc;AAAA,IACrB,SAAS,OAAO;AACd,YAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AACrE,cAAQ,OAAO,MAAM,2CAA2C,OAAO;AAAA,CAAI;AAC3E,WAAK,WAAW,UAAU,EAAE,MAAM,SAAS,QAAQ,CAAC;AACpD,WAAK,cAAc;AAAA,IACrB,UAAE;AACA,WAAK,SAAS;AAAA,IAChB;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOQ,cAAc,KAA4B;AAChD,UAAM,UAAU,IAAI,QAAQ,SAAS,MAAM,GAAG,IAAI,QAAQ,MAAM,GAAG,GAAG,CAAC,WAAM,IAAI;AACjF,YAAQ,OAAO;AAAA,MACb,iFAAiF,QAAQ,QAAQ,OAAO,KAAK,CAAC;AAAA;AAAA,IAChH;AACA,SAAK,UAAU,UAAU,EAAE,MAAM,4BAA4B,SAAS,IAAI,QAAQ,CAAC;AACnF,QAAI,CAAC,KAAK,QAAS,MAAK,UAAU,eAAe;AAAA,EACnD;AAAA;AAAA,EAGA,OAAa;AACX,SAAK,YAAY;AAAA,EACnB;AAAA,EAEQ,cAAoB;AAC1B,QAAI,KAAK,QAAS;AAClB,SAAK,UAAU;AACf,QAAI,KAAK,cAAc;AACrB,YAAM,UAAU,KAAK;AACrB,WAAK,eAAe;AACpB,cAAQ;AAAA,IACV;AAAA,EACF;AAAA,EAEQ,mBAAkC;AACxC,QAAI,KAAK,QAAS,QAAO,QAAQ,QAAQ;AACzC,WAAO,IAAI,QAAc,CAAC,YAAY;AACpC,WAAK,eAAe;AAAA,IACtB,CAAC;AAAA,EACH;AAAA;AAAA;AAAA,EAIA,MAAc,0BAAyC;AACrD,QAAI,KAAK,QAAS;AAClB,UAAM,UAAU,MAAM,eAAe,QAAQ,IAAI,uBAAuB;AACxE,eAAW,UAAU,SAAS;AAC5B,WAAK,WAAW,UAAU;AAAA,QACxB,MAAM;AAAA,QACN,eAAe,OAAO;AAAA,QACtB,aAAa,OAAO;AAAA,QACpB,QAAQ,OAAO;AAAA,QACf,UAAU,OAAO,YAAY;AAAA,QAC7B,QAAQ,OAAO;AAAA,MACjB,CAAC;AAAA,IACH;AAAA,EACF;AAAA,EAEQ,WAAiB;AACvB,SAAK,UAAU;AACf,SAAK,UAAU,QAAQ;AACvB,SAAK,WAAW,UAAU,EAAE,MAAM,YAAY,QAAQ,KAAK,eAAe,WAAW,CAAC;AACtF,SAAK,WAAW,WAAW;AAAA,EAC7B;AACF;;;AChLA,SAAS,SAAS,WAAW,UAAU,UAAU;AACjD,SAAS,QAAAC,aAAY;AAQrB,IAAM,SAAS,oBAAoB,iBAAiB;AAwBpD,SAAS,gBAAgB,QAAkC;AACzD,QAAM,EAAE,cAAc,aAAa,iBAAiB,gBAAgB,OAAO,IACzE,iBAAiB,MAAM;AACzB,QAAM,UAA4B,CAAC;AACnC,MAAI,iBAAiB,MAAM;AACzB,YAAQ,KAAK;AAAA,MACX,eAAe;AAAA,MACf,aAAa;AAAA,MACb,QAAQ;AAAA,MACR,UAAU;AAAA,MACV;AAAA,IACF,CAAC;AAAA,EACH;AACA,MAAI,gBAAgB,MAAM;AACxB,YAAQ,KAAK;AAAA,MACX,eAAe;AAAA,MACf,aAAa;AAAA,MACb,QAAQ;AAAA,MACR,UAAU;AAAA,MACV;AAAA,IACF,CAAC;AAAA,EACH;AACA,SAAO;AACT;AAMA,eAAe,cAAc,OAAe,KAA8B;AACxE,MAAI,MAAqB;AACzB,MAAI;AAGF,UAAM,MAAM,QAAQC,MAAK,gBAAgB,GAAG,iBAAiB,CAAC;AAC9D,UAAM,UAAUA,MAAK,KAAK,mBAAmB,GAAG,4BAA4B,OAAO,GAAG,GAAG;AAAA,MACvF,UAAU;AAAA,MACV,MAAM;AAAA,IACR,CAAC;AAKD,UAAM,SAAS,eAAe,GAAGA,MAAK,KAAK,cAAc,CAAC,EAAE,MAAM,MAAM;AAAA,IAAC,CAAC;AAC1E,WAAO,MAAM,cAAc,EAAE,KAAK,EAAE,GAAG,QAAQ,KAAK,mBAAmB,IAAI,EAAE,CAAC;AAAA,EAChF,SAAS,OAAO;AACd,WAAO,KAAK,+BAA+B;AAAA,MACzC,OAAO,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AAAA,IAC9D,CAAC;AACD,WAAO;AAAA,EACT,UAAE;AACA,QAAI,IAAK,OAAM,GAAG,KAAK,EAAE,WAAW,MAAM,OAAO,KAAK,CAAC,EAAE,MAAM,MAAM;AAAA,IAAC,CAAC;AAAA,EACzE;AACF;AAMA,eAAsB,eACpB,MACA,OAA0B,CAAC,GACA;AAC3B,QAAM,MAAM,KAAK,OAAO,KAAK;AAC7B,QAAM,WAAW,KAAK,aAAa,CAAC,UAAkB,cAAc,OAAO,IAAI,CAAC;AAEhF,QAAM,UAA4B,CAAC;AACnC,aAAW,OAAO,MAAM;AACtB,QAAI,CAAC,IAAI,WAAY;AACrB,QAAI;AACF,YAAM,SAAS,MAAM,SAAS,IAAI,UAAU;AAC5C,YAAM,UAAU,gBAAgB,MAAM;AACtC,UAAI,QAAQ,SAAS,GAAG;AACtB,gBAAQ,KAAK,EAAE,kBAAkB,IAAI,kBAAkB,QAAQ,CAAC;AAAA,MAClE;AAAA,IACF,SAAS,OAAO;AACd,aAAO,KAAK,8BAA8B;AAAA,QACxC,kBAAkB,IAAI;AAAA,QACtB,OAAO,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AAAA,MAC9D,CAAC;AAAA,IACH;AAAA,EACF;AACA,SAAO;AACT;;;AC3FA,IAAM,oBACJ;AAIF,IAAM,uBACJ;AAUK,SAAS,qBAAqB,MAAyB,QAAQ,KAAoB;AACxF,QAAM,MAAM,IAAI;AAChB,MAAI,CAAC,IAAK,QAAO;AACjB,MAAI;AACF,UAAM,UAAU,OAAO,KAAK,KAAK,QAAQ,EAAE,SAAS,MAAM,EAAE,KAAK;AACjE,WAAO,QAAQ,SAAS,IAAI,UAAU;AAAA,EACxC,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AA2EO,IAAM,kBAAuD;AAM7D,SAAS,oBACd,YACA,iBACW;AACX,SAAO;AAAA,IACL,YAAY,CAAC,MAAM,SAAS,WAAW,cAAc,MAAM,IAAI;AAAA,IAC/D,eAAe,CAAC,UAAU,WAAW,iBAAiB,KAAK;AAAA,IAC3D,SAAS,CAAC,YACR,WAAW,WAAW,CAAC,SAAS;AAC9B,wBAAkB;AAClB,cAAQ,IAAI;AAAA,IACd,CAAC;AAAA,IACH,UAAU,CAAC,YAAY,WAAW,YAAY,OAAO;AAAA,EACvD;AACF;AAGO,SAAS,uBACd,cACA,OACA,iBAKA,SAIA,MAAyB,QAAQ,KAGjC,UACqB;AACrB,QAAM,aAAa,WAAW,uBAAuB;AACrD,SAAO;AAAA,IACL;AAAA,IACA,cAAc,EAAE,MAAM,UAAU,QAAQ,eAAe,QAAQ,WAAW;AAAA,IAC1E,oBAAoB;AAAA,IACpB,KAAK;AAAA;AAAA;AAAA,IAGL,gBAAgB;AAAA,IAChB,iCAAiC;AAAA,IACjC,OAAO,EAAE,MAAM,UAAU,QAAQ,cAAc;AAAA,IAC/C,aAAa,MAAM;AACjB,YAAM,aAAa,2BAA2B,GAAG;AACjD,aAAO;AAAA,QACL,GAAI,aAAa,EAAE,WAAW,IAAI,CAAC;AAAA,QACnC,GAAI,UAAU,oBAAoB,EAAE,UAAU,SAAS,kBAAkB,IAAI,CAAC;AAAA,MAChF;AAAA,IACF,GAAG;AAAA,IACH,gBAAgB,CAAC,QAAQ,SAAS;AAAA;AAAA;AAAA,IAGlC,gBAAgB,WAAW,WAAW;AAAA,IACtC;AAAA,IACA,GAAI,SAAS,YAAY,EAAE,WAAW,QAAQ,UAAU,IAAI,CAAC;AAAA,IAC7D,GAAI,SAAS,SAAS,EAAE,QAAQ,QAAQ,OAAO,IAAI,CAAC;AAAA,EACtD;AACF;AAEO,IAAM,qBAAN,MAAyB;AAAA,EACrB;AAAA,EACA;AAAA,EACQ;AAAA,EACA;AAAA,EACA;AAAA,EAEA;AAAA,EACA;AAAA,EACA,kBAAkB,IAAI,gBAAgB;AAAA,EAC/C,UAAU;AAAA,EACV,eAAoC;AAAA,EACpC,cAA2C;AAAA,EAEnD,YACE,QACA,YAAyC,CAAC,GAC1C,MAMA;AACA,SAAK,SAAS;AACd,SAAK,YAAY;AACjB,SAAK,aAAa,MAAM,cAAc,IAAI,gBAAgB,OAAO,UAAU;AAC3E,SAAK,UACH,MAAM,WACN,IAAI;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAMF,oBAAoB,KAAK,YAAY,MAAM,KAAK,UAAU,eAAe,CAAC;AAAA,MAC1E,kBAAkB,gBAAgB,QAAQ,GAAG,CAAC;AAAA,IAChD;AAGF,UAAM,iBAAiB,IAAI,wBAAwB;AACnD,SAAK,gBACH,MAAM,iBACN,IAAI,cAAc;AAAA,MAChB,QAAQ,CAAC,UAAU,KAAK,WAAW,sBAAsB,KAAK;AAAA,MAC9D,YAAY,CAAC,UAAU,eAAe,cAAc,MAAM,IAAI,CAAC,EAAE,KAAK,MAAM,IAAI,CAAC;AAAA,IACnF,CAAC;AACH,SAAK,oBACH,MAAM,qBACN,IAAI,2BAA2B;AAAA,MAC7B,QAAQ,mBAAmB;AAAA,MAC3B,cAAc,OAAO;AAAA,MACrB,YAAY,KAAK;AAAA,IACnB,CAAC;AACH,SAAK,YAAY,IAAI;AAAA;AAAA;AAAA,MAGnB,EAAE,GAAG,0BAA0B,oBAAoB,GAAG,GAAG,OAAO,UAAU;AAAA,MAC1E;AAAA,QACE,aAAa,MAAM,KAAK,WAAW,cAAc;AAAA,QACjD,eAAe,MAAM,KAAK,YAAY;AAAA,QACtC,kBAAkB,MAAM,KAAK,YAAY;AAAA,QACzC,gBAAgB,MAAM,KAAK,KAAK,WAAW,8BAA8B,EAAE,MAAM,MAAM;AAAA,QAAC,CAAC;AAAA,QACzF,YAAY,MAAM;AAAA,QAAC;AAAA,QACnB,eAAe,MAAM,KAAK,KAAK,uBAAuB;AAAA,MACxD;AAAA,IACF;AAAA,EACF;AAAA,EAEA,IAAI,aAA0C;AAC5C,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,IAAI,YAAqB;AACvB,WAAO,KAAK;AAAA,EACd;AAAA;AAAA,EAGA,MAAM,MAAqB;AACzB,QAAI;AACF,YAAM,KAAK,WAAW,QAAQ;AAC9B,WAAK,WAAW,UAAU;AAAA,QACxB,MAAM;AAAA,QACN,WAAW,KAAK,OAAO,WAAW;AAAA,QAClC,WAAW,KAAK,OAAO;AAAA,MACzB,CAAC;AACD,WAAK,WAAW,OAAO,MAAM,KAAK,YAAY,CAAC;AAE/C,WAAK,WAAW,aAAa,MAAM,KAAK,KAAK,uBAAuB,CAAC;AACrE,WAAK,UAAU,eAAe;AAC9B,WAAK,UAAU,kBAAkB;AACjC,WAAK,UAAU,iBAAiB;AAEhC,YAAM,KAAK,WAAW,KAAK,gBAAgB;AAAA,QACzC,WAAW,KAAK,OAAO,WAAW;AAAA,MACpC,CAAC;AACD,YAAM,KAAK,cAAc,MAAM,EAAE,MAAM,MAAM;AAAA,MAAC,CAAC;AAC/C,UAAI,KAAK,SAAS;AAChB,aAAK,cAAc;AACnB;AAAA,MACF;AACA,WAAK,kBAAkB,MAAM;AAI7B,WAAK,kBAAkB,kBAAkB;AACzC,YAAM,KAAK,WAAW,WAAW,SAAS;AAC1C,WAAK,UAAU,UAAU,EAAE,MAAM,wBAAwB,WAAW,KAAK,OAAO,UAAU,CAAC;AAC3F,WAAK,UAAU,eAAe;AAE9B,YAAM,KAAK,kBAAkB;AAC7B,WAAK,cAAc;AAAA,IACrB,SAAS,OAAO;AACd,YAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AACrE,cAAQ,OAAO,MAAM,0CAA0C,OAAO;AAAA,CAAI;AAC1E,WAAK,WAAW,UAAU,EAAE,MAAM,SAAS,QAAQ,CAAC;AACpD,WAAK,cAAc;AAAA,IACrB,UAAE;AACA,YAAM,KAAK,SAAS;AAAA,IACtB;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAc,oBAAmC;AAC/C,UAAM,QACJ,KAAK,OAAO,SACZ,QAAQ,IAAI,wBACZ,QAAQ,IAAI,wBACZ;AAKF,UAAM,UAAU,oBAAoB,KAAK,OAAO,aAAa,KAAK,OAAO,YAAY;AAGrF,UAAM,gBAAgB,KAAK,OAAO,iBAAiB;AACnD,UAAM,WAAW,gBACb;AAAA,MACE;AAAA,MACA,mBAAmB,KAAK,QAAQ,gBAAgB;AAAA,QAC9C,MAAM;AAAA,QACN,OAAO;AAAA,UACL,KAAK;AAAA,UACL,KAAK,OAAO;AAAA,UACZ,KAAK,OAAO;AAAA,QACd;AAAA,MACF,CAAC;AAAA,IACH,IACA;AACJ,UAAM,UAAU;AAAA,MACd,KAAK,OAAO;AAAA,MACZ;AAAA,MACA,KAAK;AAAA,MACL;AAAA,MACA,QAAQ;AAAA,MACR;AAAA,IACF;AACA,QAAI,eAAe;AACnB,QAAI;AACF,uBAAiB,SAAS,KAAK,QAAQ,aAAa;AAAA,QAClD,QAAQ,iBAAiB;AAAA,QACzB;AAAA,MACF,CAAC,GAAG;AACF,YAAI,KAAK,QAAS;AAClB,YAAI,iBAAiB,CAAC,cAAc;AAMlC,yBAAe;AACf,eAAK,KAAK,WACP,KAAK,8BAA8B,EAAE,WAAW,KAAK,OAAO,WAAW,UAAU,CAAC,EAClF,MAAM,MAAM;AAAA,UAAC,CAAC;AAAA,QACnB;AACA,YAAI,MAAM,SAAS,YAAY,MAAM,YAAY,SAAS;AAGxD,gBAAM,IAAI,MAAM,MAAM,OAAO,KAAK,IAAI,CAAC;AAAA,QACzC;AAAA,MACF;AAAA,IACF,SAAS,OAAO;AAEd,UAAI,CAAC,KAAK,QAAS,OAAM;AAAA,IAC3B;AAAA,EACF;AAAA,EAEA,OAAa;AACX,SAAK,YAAY;AAAA,EACnB;AAAA,EAEQ,cAAoB;AAC1B,QAAI,KAAK,QAAS;AAClB,SAAK,UAAU;AACf,SAAK,cAAc,KAAK;AACxB,SAAK,KAAK,kBAAkB,KAAK;AACjC,SAAK,gBAAgB,MAAM;AAC3B,QAAI,KAAK,cAAc;AACrB,YAAM,UAAU,KAAK;AACrB,WAAK,eAAe;AACpB,cAAQ;AAAA,IACV;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,MAAc,yBAAwC;AACpD,QAAI,KAAK,QAAS;AAClB,QAAI,OAA2D,CAAC;AAChE,QAAI;AACF,YAAM,MAAM,MAAM,KAAK,WAAW,KAAK,mBAAmB;AAAA,QACxD,WAAW,KAAK,OAAO,WAAW;AAAA,MACpC,CAAC;AACD,aAAO,KAAK,QAAQ,CAAC;AAAA,IACvB,QAAQ;AAAA,IAER;AACA,QAAI,KAAK,WAAW,GAAG;AACrB,YAAM,KAAK,sBAAsB;AACjC;AAAA,IACF;AACA,UAAM,SAAS,MAAM,eAAe,IAAI;AACxC,eAAW,EAAE,kBAAkB,QAAQ,KAAK,QAAQ;AAClD,iBAAW,UAAU,SAAS;AAC5B,aAAK,WAAW,UAAU;AAAA,UACxB,MAAM;AAAA,UACN,eAAe,OAAO;AAAA,UACtB,aAAa,OAAO;AAAA,UACpB,QAAQ,OAAO;AAAA,UACf,UAAU,OAAO,YAAY;AAAA,UAC7B,QAAQ,OAAO;AAAA,UACf;AAAA,QACF,CAAC;AAAA,MACH;AAAA,IACF;AAAA,EACF;AAAA;AAAA,EAGA,MAAc,wBAAuC;AACnD,QAAI,KAAK,QAAS;AAClB,UAAM,UAAU,MAAM,eAAe,QAAQ,IAAI,uBAAuB;AACxE,eAAW,UAAU,SAAS;AAC5B,WAAK,WAAW,UAAU;AAAA,QACxB,MAAM;AAAA,QACN,eAAe,OAAO;AAAA,QACtB,aAAa,OAAO;AAAA,QACpB,QAAQ,OAAO;AAAA,QACf,UAAU,OAAO,YAAY;AAAA,QAC7B,QAAQ,OAAO;AAAA,MACjB,CAAC;AAAA,IACH;AAAA,EACF;AAAA,EAEA,MAAc,WAA0B;AACtC,SAAK,UAAU;AACf,SAAK,cAAc,KAAK;AACxB,UAAM,KAAK,kBAAkB,KAAK;AAClC,SAAK,UAAU,QAAQ;AACvB,SAAK,WAAW,UAAU,EAAE,MAAM,YAAY,QAAQ,KAAK,eAAe,WAAW,CAAC;AACtF,SAAK,WAAW,WAAW;AAAA,EAC7B;AACF;;;AChdA,SAAS,SAAS,WAAW,gBAAmC;AAChE,SAAS,iBAAiB;AAI1B,IAAM,gBAAgB,UAAU,QAAQ;AACxC,IAAMC,UAAS,oBAAoB,aAAa;AAGzC,IAAM,yBAAyB;AAE/B,IAAM,eAAe;AAqBrB,SAAS,oBACd,SACA,MACmB;AACnB,QAAM,MAAyB,EAAE,GAAG,QAAQ;AAI5C,MAAI,sBAAsB,KAAK;AAC/B,MAAI,sBAAsB,KAAK;AAC/B,MAAI,gBAAgB;AAWpB,MAAI,6BAA6B,QAAQ;AAMzC,SAAO,IAAI;AACX,SAAO,IAAI;AAIX,SAAO,IAAI;AAMX,SAAO,IAAI;AACX,SAAO,IAAI;AAIX,SAAO,IAAI;AACX,SAAO,IAAI;AAOX,SAAO,IAAI;AACX,SAAO;AACT;AAEO,IAAM,wBAAN,MAA4B;AAAA,EAIjC,YACmB,YACA,cACA,UAAmB,WACpC;AAHiB;AACA;AACA;AAAA,EAChB;AAAA,EAHgB;AAAA,EACA;AAAA,EACA;AAAA,EANX,QAA6B;AAAA,EAC7B,iBAAgC;AAAA;AAAA,EASxC,MAAM,MAAM,MAAsC;AAChD,IAAAA,QAAO,KAAK,kCAAkC;AAAA,MAC5C,iBAAiB,KAAK;AAAA,MACtB,QAAQ,KAAK,UAAU;AAAA,MACvB,UAAU,KAAK,YAAY;AAAA,IAC7B,CAAC;AACD,UAAM,KAAK,YAAY,gCAAgC;AACvD,UAAM,KAAK,gBAAgB,KAAK,UAAU,IAAI;AAE9C,UAAM,MAAM,oBAAoB,QAAQ,KAAK,IAAI;AACjD,UAAM,UAAU,QAAQ,KAAK,CAAC;AAC9B,QAAI,CAAC,SAAS;AACZ,WAAK,WAAW,yBAAyB,KAAK,WAAW,+BAA+B;AACxF;AAAA,IACF;AAEA,QAAI;AACJ,QAAI;AACF,cAAQ,KAAK,QAAQ,QAAQ,UAAU,CAAC,OAAO,GAAG;AAAA,QAChD,KAAK,KAAK;AAAA,QACV;AAAA,QACA,OAAO,CAAC,UAAU,QAAQ,MAAM;AAAA,MAClC,CAAC;AAAA,IACH,SAAS,KAAK;AACZ,WAAK,WAAW;AAAA,QACd,KAAK;AAAA,QACL,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAAA,MACjD;AACA;AAAA,IACF;AAEA,SAAK,QAAQ;AACb,SAAK,iBAAiB,KAAK;AAC3B,UAAM,YAAY,KAAK,IAAI;AAC3B,QAAI,WAAW;AACf,UAAM,aAAa,CAAC,YAA0B;AAC5C,UAAI,SAAU;AACd,iBAAW;AACX,WAAK,WAAW,yBAAyB,KAAK,WAAW,OAAO;AAAA,IAClE;AAIA,UAAM,QAAQ,GAAG,QAAQ,CAAC,UAAkB;AAC1C,cAAQ,OAAO,MAAM,kBAAkB,MAAM,SAAS,CAAC,EAAE;AAAA,IAC3D,CAAC;AACD,UAAM,QAAQ,GAAG,QAAQ,CAAC,UAAkB;AAC1C,cAAQ,OAAO,MAAM,kBAAkB,MAAM,SAAS,CAAC,EAAE;AAAA,IAC3D,CAAC;AAED,UAAM,GAAG,SAAS,CAAC,QAAQ;AACzB,MAAAA,QAAO,MAAM,4BAA4B,EAAE,OAAO,IAAI,QAAQ,CAAC;AAC/D,UAAI,KAAK,UAAU,OAAO;AACxB,aAAK,QAAQ;AACb,aAAK,iBAAiB;AAAA,MACxB;AACA,iBAAW,IAAI,OAAO;AAAA,IACxB,CAAC;AAED,UAAM,GAAG,QAAQ,CAAC,MAAM,WAAW;AACjC,YAAM,aAAa,KAAK,UAAU;AAClC,UAAI,YAAY;AACd,aAAK,QAAQ;AACb,aAAK,iBAAiB;AAAA,MACxB;AACA,MAAAA,QAAO,KAAK,uBAAuB,EAAE,MAAM,QAAQ,iBAAiB,KAAK,UAAU,CAAC;AAKpF,YAAM,cAAc,KAAK,IAAI,IAAI,YAAY;AAC7C,UAAI,cAAc,eAAe,SAAS,QAAQ,SAAS,GAAG;AAC5D,mBAAW,iCAAiC,IAAI,uBAAuB;AAAA,MACzE;AAAA,IACF,CAAC;AAAA,EACH;AAAA;AAAA,EAGA,MAAM,UAAyB;AAC7B,UAAM,KAAK,YAAY,sBAAsB;AAAA,EAC/C;AAAA,EAEA,MAAc,YAAY,QAA+B;AACvD,UAAM,QAAQ,KAAK;AACnB,QAAI,CAAC,SAAS,MAAM,aAAa,QAAQ,MAAM,QAAQ;AACrD,WAAK,QAAQ;AACb,WAAK,iBAAiB;AACtB;AAAA,IACF;AACA,IAAAA,QAAO,KAAK,yBAAyB,EAAE,QAAQ,iBAAiB,KAAK,eAAe,CAAC;AAErF,SAAK,QAAQ;AACb,SAAK,iBAAiB;AAEtB,UAAM,IAAI,QAAc,CAAC,YAAY;AACnC,YAAM,QAAQ,WAAW,MAAM;AAC7B,YAAI;AACF,gBAAM,KAAK,SAAS;AAAA,QACtB,QAAQ;AAAA,QAER;AACA,gBAAQ;AAAA,MACV,GAAG,YAAY;AACf,YAAM,MAAM;AACZ,YAAM,KAAK,QAAQ,MAAM;AACvB,qBAAa,KAAK;AAClB,gBAAQ;AAAA,MACV,CAAC;AACD,UAAI;AACF,cAAM,KAAK,SAAS;AAAA,MACtB,QAAQ;AACN,qBAAa,KAAK;AAClB,gBAAQ;AAAA,MACV;AAAA,IACF,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,MAAc,gBAAgB,QAAsC;AAClE,QAAI,CAAC,OAAQ;AACb,QAAI;AACF,YAAM,cAAc,OAAO,CAAC,SAAS,UAAU,MAAM,GAAG;AAAA,QACtD,KAAK,KAAK;AAAA,QACV,SAAS;AAAA,MACX,CAAC;AACD,YAAM,cAAc,OAAO,CAAC,SAAS,aAAa,UAAU,MAAM,EAAE,GAAG;AAAA,QACrE,KAAK,KAAK;AAAA,QACV,SAAS;AAAA,MACX,CAAC;AAAA,IACH,SAAS,KAAK;AACZ,MAAAA,QAAO,KAAK,mCAAmC;AAAA,QAC7C;AAAA,QACA,OAAO,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAAA,MACxD,CAAC;AAAA,IACH;AAAA,EACF;AACF;;;AC/OA,SAAS,SAASC,kBAAoC;AAKtD,IAAMC,UAAS,oBAAoB,cAAc;AAW1C,SAAS,qBACd,SACA,MACmB;AACnB,QAAM,MAAyB,EAAE,GAAG,QAAQ;AAK5C,MAAI,sBAAsB,KAAK;AAC/B,MAAI,sBAAsB,KAAK;AAC/B,MAAI,gBAAgB,KAAK;AACzB,MAAI,sBAAsB,KAAK;AAM/B,SAAO,IAAI;AACX,SAAO,IAAI;AAIX,SAAO,IAAI;AAIX,SAAO,IAAI;AACX,SAAO,IAAI;AACX,SAAO;AACT;AAEO,IAAM,yBAAN,MAA6B;AAAA,EAGlC,YACmB,YACA,cACA,UAAmBC,YACpC;AAHiB;AACA;AACA;AAAA,EAChB;AAAA,EAHgB;AAAA,EACA;AAAA,EACA;AAAA,EALF,WAAW,oBAAI,IAA0B;AAAA;AAAA,EAS1D,IAAI,OAAe;AACjB,WAAO,KAAK,SAAS;AAAA,EACvB;AAAA;AAAA,EAGA,MAAM,MAAM,MAAmC;AAC7C,IAAAD,QAAO,KAAK,mCAAmC;AAAA,MAC7C,kBAAkB,KAAK;AAAA,MACvB,MAAM,KAAK;AAAA,IACb,CAAC;AAED,UAAM,KAAK,UAAU,KAAK,WAAW,+BAA+B;AAEpE,UAAM,MAAM,qBAAqB,QAAQ,KAAK,IAAI;AAClD,UAAM,UAAU,QAAQ,KAAK,CAAC;AAC9B,QAAI,CAAC,SAAS;AACZ,WAAK,WAAW,0BAA0B,KAAK,WAAW,+BAA+B;AACzF;AAAA,IACF;AAEA,QAAI;AACJ,QAAI;AACF,cAAQ,KAAK,QAAQ,QAAQ,UAAU,CAAC,OAAO,GAAG;AAAA,QAChD,KAAK,KAAK;AAAA,QACV;AAAA,QACA,OAAO,CAAC,UAAU,QAAQ,MAAM;AAAA,MAClC,CAAC;AAAA,IACH,SAAS,KAAK;AACZ,WAAK,WAAW;AAAA,QACd,KAAK;AAAA,QACL,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAAA,MACjD;AACA;AAAA,IACF;AAEA,SAAK,SAAS,IAAI,KAAK,WAAW,KAAK;AACvC,UAAM,YAAY,KAAK,IAAI;AAC3B,QAAI,WAAW;AACf,UAAM,aAAa,CAAC,YAA0B;AAC5C,UAAI,SAAU;AACd,iBAAW;AACX,WAAK,WAAW,0BAA0B,KAAK,WAAW,OAAO;AAAA,IACnE;AAIA,UAAM,SAAS,IAAI,KAAK,IAAI;AAC5B,UAAM,QAAQ,GAAG,QAAQ,CAAC,UAAkB;AAC1C,cAAQ,OAAO,MAAM,GAAG,MAAM,IAAI,MAAM,SAAS,CAAC,EAAE;AAAA,IACtD,CAAC;AACD,UAAM,QAAQ,GAAG,QAAQ,CAAC,UAAkB;AAC1C,cAAQ,OAAO,MAAM,GAAG,MAAM,IAAI,MAAM,SAAS,CAAC,EAAE;AAAA,IACtD,CAAC;AAED,UAAM,GAAG,SAAS,CAAC,QAAQ;AACzB,MAAAA,QAAO,MAAM,6BAA6B,EAAE,OAAO,IAAI,QAAQ,CAAC;AAChE,UAAI,KAAK,SAAS,IAAI,KAAK,SAAS,MAAM,OAAO;AAC/C,aAAK,SAAS,OAAO,KAAK,SAAS;AAAA,MACrC;AACA,iBAAW,IAAI,OAAO;AAAA,IACxB,CAAC;AAED,UAAM,GAAG,QAAQ,CAAC,MAAM,WAAW;AACjC,YAAM,aAAa,KAAK,SAAS,IAAI,KAAK,SAAS,MAAM;AACzD,UAAI,WAAY,MAAK,SAAS,OAAO,KAAK,SAAS;AACnD,MAAAA,QAAO,KAAK,wBAAwB;AAAA,QAClC;AAAA,QACA;AAAA,QACA,kBAAkB,KAAK;AAAA,QACvB,MAAM,KAAK;AAAA,MACb,CAAC;AAKD,YAAM,cAAc,KAAK,IAAI,IAAI,YAAY;AAC7C,UAAI,cAAc,eAAe,SAAS,QAAQ,SAAS,GAAG;AAC5D,mBAAW,kCAAkC,IAAI,uBAAuB;AAAA,MAC1E;AAAA,IACF,CAAC;AAAA,EACH;AAAA;AAAA,EAGA,MAAM,UAAyB;AAC7B,UAAM,MAAM,CAAC,GAAG,KAAK,SAAS,KAAK,CAAC;AACpC,UAAM,QAAQ,IAAI,IAAI,IAAI,CAAC,OAAO,KAAK,UAAU,IAAI,sBAAsB,CAAC,CAAC;AAAA,EAC/E;AAAA,EAEA,MAAc,UAAU,WAAmB,QAA+B;AACxE,UAAM,QAAQ,KAAK,SAAS,IAAI,SAAS;AACzC,SAAK,SAAS,OAAO,SAAS;AAC9B,QAAI,CAAC,SAAS,MAAM,aAAa,QAAQ,MAAM,OAAQ;AACvD,IAAAA,QAAO,KAAK,0BAA0B,EAAE,QAAQ,kBAAkB,UAAU,CAAC;AAE7E,UAAM,IAAI,QAAc,CAAC,YAAY;AACnC,YAAM,QAAQ,WAAW,MAAM;AAC7B,YAAI;AACF,gBAAM,KAAK,SAAS;AAAA,QACtB,QAAQ;AAAA,QAER;AACA,gBAAQ;AAAA,MACV,GAAG,YAAY;AACf,YAAM,MAAM;AACZ,YAAM,KAAK,QAAQ,MAAM;AACvB,qBAAa,KAAK;AAClB,gBAAQ;AAAA,MACV,CAAC;AACD,UAAI;AACF,cAAM,KAAK,SAAS;AAAA,MACtB,QAAQ;AACN,qBAAa,KAAK;AAClB,gBAAQ;AAAA,MACV;AAAA,IACF,CAAC;AAAA,EACH;AACF;;;AC3KA,IAAM,eAAe;AACrB,IAAM,eAAe;AAgCd,SAAS,cAAc,SAAyD;AACrF,QAAM,MAAM,EAAE,GAAG,QAAQ;AACzB,SAAO,IAAI;AACX,SAAO,IAAI;AACX,SAAO;AACT;AAEO,IAAM,qBAAN,MAAyB;AAAA,EACrB;AAAA,EACA;AAAA,EAEQ;AAAA,EACA;AAAA,EACT,MAAyB;AAAA,EACzB,OAAO,EAAE,MAAM,cAAc,MAAM,aAAa;AAAA,EAChD,UAAU;AAAA,EACV,cAA2C;AAAA,EAEnD,YACE,QACA,MACA;AACA,SAAK,SAAS;AACd,SAAK,aAAa,MAAM,cAAc,IAAI,gBAAgB,OAAO,UAAU;AAI3E,SAAK,YAAY,MAAM,aAAa;AACpC,SAAK,YAAY,IAAI;AAAA;AAAA,MAEnB,EAAE,GAAG,0BAA0B,oBAAoB,GAAG,GAAG,OAAO,UAAU;AAAA,MAC1E;AAAA,QACE,aAAa,MAAM,KAAK,WAAW,cAAc;AAAA,QACjD,eAAe,MAAM,KAAK,YAAY;AAAA,QACtC,kBAAkB,MAAM,KAAK,YAAY;AAAA,QACzC,gBAAgB,MAAM,KAAK,KAAK,WAAW,8BAA8B,EAAE,MAAM,MAAM;AAAA,QAAC,CAAC;AAAA,QACzF,YAAY,MAAM;AAAA,QAAC;AAAA,QACnB,eAAe,MAAM;AAAA,QAAC;AAAA,MACxB;AAAA,IACF;AAAA,EACF;AAAA,EAEA,IAAI,aAA0C;AAC5C,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,IAAI,YAAqB;AACvB,WAAO,KAAK;AAAA,EACd;AAAA;AAAA,EAGA,MAAM,MAAqB;AACzB,QAAI;AACF,YAAM,KAAK,WAAW,QAAQ;AAC9B,WAAK,WAAW,UAAU;AAAA,QACxB,MAAM;AAAA,QACN,WAAW,KAAK,OAAO,WAAW;AAAA,MACpC,CAAC;AACD,WAAK,WAAW,OAAO,MAAM,KAAK,YAAY,CAAC;AAC/C,WAAK,UAAU,eAAe;AAC9B,WAAK,UAAU,kBAAkB;AAEjC,YAAM,KAAK,WAAW,KAAK,gBAAgB;AAAA,QACzC,WAAW,KAAK,OAAO,WAAW;AAAA,MACpC,CAAC;AACD,YAAM,KAAK,WAAW,WAAW,SAAS;AAC1C,WAAK,UAAU,eAAe;AAE9B,YAAM,KAAK,SAAS;AACpB,WAAK,cAAc;AAAA,IACrB,SAAS,OAAO;AACd,YAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AACrE,cAAQ,OAAO,MAAM,yCAAyC,OAAO;AAAA,CAAI;AACzE,WAAK,WAAW,UAAU,EAAE,MAAM,SAAS,QAAQ,CAAC;AACpD,WAAK,cAAc;AAAA,IACrB,UAAE;AACA,WAAK,SAAS;AAAA,IAChB;AAAA,EACF;AAAA;AAAA,EAGA,MAAc,WAA0B;AACtC,UAAM,QAAQ,MAAM,KAAK,UAAU;AACnC,UAAM,QAAQ,KAAK,OAAO,SAAS,QAAQ,IAAI,SAAS;AACxD,UAAM,MAAM,MAAM,OAAO,CAAC,IAAI,GAAG;AAAA,MAC/B,MAAM;AAAA,MACN,MAAM,KAAK,KAAK;AAAA,MAChB,MAAM,KAAK,KAAK;AAAA,MAChB,KAAK,KAAK,OAAO;AAAA,MACjB,KAAK,cAAc,aAAa,CAAC;AAAA,IACnC,CAAC;AACD,SAAK,MAAM;AAEX,UAAM,aAAa,KAAK,WAAW,WAAW,CAAC,SAAS;AAEtD,WAAK,UAAU,eAAe;AAC9B,UAAI,MAAM,IAAI;AAAA,IAChB,CAAC;AACD,UAAM,cAAc,KAAK,WAAW,YAAY,CAAC,MAAM,SAAS;AAC9D,WAAK,OAAO,EAAE,MAAM,KAAK;AACzB,UAAI,OAAO,MAAM,IAAI;AAAA,IACvB,CAAC;AACD,QAAI,OAAO,CAAC,SAAS,KAAK,WAAW,cAAc,MAAM,KAAK,IAAI,CAAC;AAEnE,QAAI;AACF,YAAM,IAAI,QAAc,CAAC,YAAY;AACnC,YAAI,OAAO,MAAM,QAAQ,CAAC;AAAA,MAC5B,CAAC;AAAA,IACH,UAAE;AACA,iBAAW;AACX,kBAAY;AACZ,WAAK,MAAM;AAGX,WAAK,WAAW,aAAa;AAAA,IAC/B;AAAA,EACF;AAAA,EAEA,OAAa;AACX,SAAK,YAAY;AAAA,EACnB;AAAA,EAEQ,cAAoB;AAC1B,QAAI,KAAK,QAAS;AAClB,SAAK,UAAU;AACf,QAAI;AACF,WAAK,KAAK,KAAK;AAAA,IACjB,QAAQ;AAAA,IAER;AAAA,EACF;AAAA,EAEQ,WAAiB;AACvB,SAAK,UAAU;AACf,SAAK,UAAU,QAAQ;AACvB,SAAK,WAAW,UAAU,EAAE,MAAM,YAAY,QAAQ,KAAK,eAAe,WAAW,CAAC;AACtF,SAAK,WAAW,WAAW;AAAA,EAC7B;AACF;;;ACvLA,IAAME,UAAS,oBAAoB,kBAAkB;AAmB9C,SAAS,yBAAyB,QAAgD;AACvF,MAAI,OAAO,SAAS,SAAS;AAC3B,WAAO,IAAI,mBAAmB;AAAA,MAC5B,YAAY;AAAA,QACV,QAAQ,OAAO;AAAA,QACf,WAAW,OAAO;AAAA,QAClB,WAAW,OAAO;AAAA,QAClB,YAAY;AAAA,MACd;AAAA,MACA,cAAc,OAAO;AAAA,IACvB,CAAC;AAAA,EACH;AACA,SAAO,IAAI;AAAA,IACT;AAAA,MACE,YAAY;AAAA,QACV,QAAQ,OAAO;AAAA,QACf,WAAW,OAAO;AAAA,QAClB,WAAW,OAAO;AAAA,QAClB,YAAY;AAAA,MACd;AAAA,MACA,WAAW,OAAO;AAAA;AAAA;AAAA;AAAA,MAIlB,aAAa,OAAO;AAAA,MACpB,cAAc,OAAO;AAAA,IACvB;AAAA,IACA;AAAA,MACE,SAAS,CAAC,UAAU;AAClB,QAAAA,QAAO,KAAK,qBAAqB,EAAE,WAAW,MAAM,KAAe,CAAC;AAAA,MACtE;AAAA,IACF;AAAA,EACF;AACF;;;ACjDO,SAAS,qBAAqB,MAA2B;AAC9D,SAAO,SAAS,UAAU,SAAS;AACrC;;;AfkBA,IAAI,QAAQ,KAAK,CAAC,MAAM,QAAQ;AAC9B,QAAM,EAAE,QAAQ,IAAI,MAAM,OAAO,oBAAiB;AAClD,UAAQ,KAAK,MAAM,QAAQ,QAAQ,KAAK,MAAM,CAAC,CAAC,CAAC;AACnD;AAOA,IAAI,yBAAyB,QAAQ,GAAG,GAAG;AACzC,UAAQ,OAAO,MAAM,GAAG,iBAAiB;AAAA,CAAI;AAC7C,UAAQ,KAAK,CAAC;AAChB;AAGA,IAAI,QAAQ,KAAK,SAAS,WAAW,GAAG;AACtC,QAAM,YAAYC,SAAQ,cAAc,YAAY,GAAG,CAAC;AACxD,QAAM,UAAUC,MAAK,WAAW,MAAM,cAAc;AACpD,QAAM,MAAM,KAAK,MAAM,aAAa,SAAS,OAAO,CAAC;AACrD,UAAQ,OAAO,MAAM,IAAI,UAAU,IAAI;AACvC,UAAQ,KAAK,CAAC;AAChB;AAEA,IAAMC,UAAS,oBAAoB,KAAK;AAQxC,IAAM,cAAiC,CAAC;AACxC,IAAI,aAAa;AAMjB,IAAI,eAAe;AACnB,SAAS,aACP,QACA,MACM;AAGN,MAAI,WAAY;AAChB,eAAa;AACb,QAAM,UAAU,kBAAkB;AAAA,IAChC;AAAA,IACA,UAAU,KAAK;AAAA,IACf,QAAQ,KAAK;AAAA,IACb,YAAY,KAAK;AAAA,IACjB,WAAW,QAAQ,OAAO;AAAA,IAC1B,UAAU;AAAA,EACZ,CAAC;AACD,EAAAA,QAAO,aAAa,MAAM,CAAC,EAAE,cAAc,OAA6C;AAC1F;AAEA,eAAe,uBAAuB,QAAgB,cAAqC;AACzF,QAAM,iBAAiB,QAAQ,IAAI;AACnC,QAAM,gBAAgB,QAAQ,QAAQ,IAAI,gBAAgB;AAC1D,EAAAA,QAAO,KAAK,gCAAgC;AAAA,IAC1C,WAAW;AAAA,IACX;AAAA,IACA;AAAA,IACA,uBAAuB,QAAQ,cAAc;AAAA,EAC/C,CAAC;AACD,QAAM,SAAS,MAAM,eAAe;AAAA,IAClC;AAAA,IACA;AAAA,IACA;AAAA,EACF,CAAC;AACD,MAAI,CAAC,OAAO,IAAI;AACd,IAAAA,QAAO,MAAM,kCAAkC;AAAA,MAC7C,QAAQ,OAAO;AAAA,MACf,UAAU,OAAO;AAAA,MACjB,QAAQ,OAAO;AAAA,MACf,QAAQ,OAAO;AAAA,MACf;AAAA,MACA;AAAA,MACA,uBAAuB,QAAQ,cAAc;AAAA,MAC7C,MAAM,gBACF,0GACA;AAAA,IACN,CAAC;AACD,YAAQ,KAAK,CAAC;AAAA,EAChB;AACA,sBAAoB,OAAO,MAAM;AACjC,EAAAA,QAAO,KAAK,sBAAsB;AAAA,IAChC,QAAQ,OAAO,OAAO;AAAA,IACtB,UAAU,OAAO;AAAA,EACnB,CAAC;AACH;AAGA,SAAS,qBAAqB,OAA+C;AAC3E,QAAM,UAAU,MAAM,WAAW;AACjC,QAAM,kBAAkB,qBAAqB,KAAK,OAAO,KAAK,SAAS,KAAK,OAAO;AACnF,QAAM,eAAe,EAAE,UAAU,UAAU,MAAM,SAAS,UAAa,MAAM,SAAS;AACtF,SAAO,mBAAmB;AAC5B;AASA,SAAS,uBAAuB,KAAqB;AACnD,MAAI,CAAC,wBAAwB,GAAG,EAAG,QAAO;AAC1C,EAAAA,QAAO,MAAM,2EAAsE;AAAA,IACjF,OAAO,IAAI;AAAA,EACb,CAAC;AACD,eAAa,gBAAgB,EAAE,UAAU,EAAE,CAAC;AAC5C,UAAQ,KAAK,CAAC;AAChB;AAEA,QAAQ,GAAG,qBAAqB,CAAC,QAA+B;AAC9D,MAAI,IAAI,SAAS,QAAS;AAE1B,MAAI,gBAAgB,qBAAqB,GAAG,GAAG;AAC7C,IAAAA,QAAO,KAAK,yCAAyC,EAAE,OAAO,IAAI,SAAS,MAAM,IAAI,KAAK,CAAC;AAC3F;AAAA,EACF;AAEA,MAAI,uBAAuB,GAAG,EAAG;AAEjC,EAAAA,QAAO,MAAM,sBAAsB,EAAE,OAAO,IAAI,SAAS,MAAM,IAAI,KAAK,CAAC;AACzE,eAAa,sBAAsB,EAAE,UAAU,EAAE,CAAC;AAClD,UAAQ,KAAK,CAAC;AAChB,CAAC;AAED,QAAQ,GAAG,sBAAsB,CAAC,WAAoB;AACpD,QAAM,MAAM,kBAAkB,QAAQ,SAAS,IAAI,MAAM,OAAO,MAAM,CAAC;AAEvE,MAAI,gBAAgB,qBAAqB,GAAG,GAAG;AAC7C,IAAAA,QAAO,KAAK,mDAAmD,EAAE,OAAO,IAAI,QAAQ,CAAC;AACrF;AAAA,EACF;AAEA,MAAI,uBAAuB,GAAG,EAAG;AAEjC,EAAAA,QAAO,MAAM,uBAAuB,EAAE,OAAO,IAAI,QAAQ,CAAC;AAC1D,eAAa,uBAAuB,EAAE,UAAU,EAAE,CAAC;AACnD,UAAQ,KAAK,CAAC;AAChB,CAAC;AAKD,IAAI,QAAQ,IAAI,kBAAkB,aAAa;AAC7C,QAAM,EAAE,qBAAqB,IAAI,MAAM,OAAO,sBAAuB;AACrE,QAAM,EAAE,0BAA0B,IAAI,MAAM,OAAO,4BAA6B;AAChF,QAAM,EAAE,uBAAuB,IAAI,MAAM,OAAO,wBAAyB;AACzE,QAAM,OAAO,OAAO,QAAQ,IAAI,uBAAuB,KAAK;AAC5D,QAAM,QAAQ,QAAQ,IAAI,4BAA4B,QAAQ,IAAI,uBAAuB;AACzF,MAAI,CAAC,OAAO;AACV,IAAAA,QAAO,MAAM,2EAA2E;AACxF,YAAQ,KAAK,CAAC;AAAA,EAChB;AACA,QAAM,SAASF,SAAQ,cAAc,YAAY,GAAG,CAAC;AACrD,QAAM,MAAM,KAAK,MAAM,aAAaC,MAAK,QAAQ,MAAM,cAAc,GAAG,OAAO,CAAC;AAGhF,QAAM,SAAS,MAAM,qBAAqB;AAAA,IACxC;AAAA,IACA;AAAA,IACA,SAAS,IAAI,WAAW;AAAA,IACxB,aAAa,0BAA0B;AAAA,MACrC,MAAM,CAAC,MAAMC,QAAO,KAAK,CAAC;AAAA,MAC1B,MAAM,CAAC,MAAMA,QAAO,KAAK,CAAC;AAAA,MAC1B,OAAO,CAAC,MAAMA,QAAO,MAAM,CAAC;AAAA,IAC9B,CAAC;AAAA,EACH,CAAC;AACD,EAAAA,QAAO,KAAK,6CAA6C,OAAO,IAAI,EAAE;AAGtE,UAAQ,GAAG,WAAW,MAAM,QAAQ,KAAK,CAAC,CAAC;AAC3C,QAAM,IAAI,QAAQ,MAAM;AAAA,EAAC,CAAC;AAC5B;AAEA,IAAM,2BAA2B;AACjC,IAAI,iBAAiB,QAAQ,IAAI,oBAAoB;AAGrD,IAAM,gBAAgB,QAAQ,IAAI,kBAAkB,QAAQ,IAAI;AAChE,IAAI,iBAAiB,CAAC,QAAQ,IAAI,qBAAqB;AACrD,MAAI,CAAC,gBAAgB;AACnB,IAAAA,QAAO,MAAM,4DAA4D;AACzE,YAAQ,KAAK,CAAC;AAAA,EAChB;AACA,QAAM,uBAAuB,gBAAgB,aAAa;AAC1D,mBAAiB,QAAQ,IAAI,oBAAoB;AACnD;AAGA,IAAM,sBAAsB,QAAQ,IAAI;AACxC,IAAM,mBAAmB,QAAQ,IAAI;AACrC,IAAM,qBAAqB,QAAQ,IAAI,sBAAsB,QAAQ,IAAI;AACzE,IAAM,gBAAiB,QAAQ,IAAI,iBAAiB;AACpD,IAAM,sBAAsB,QAAQ,IAAI,uBAAuB;AAC/D,IAAM,mBAAmB,sBACrB,wBAAwB,SACxB,QAAQ,IAAI,qBAAqB;AAIrC,YAAY,SAAS;AACrB,YAAY,cAAc,QAAQ,IAAI;AACtC,YAAY,aAAa;AACzB,YAAY,YAAY,QAAQ,IAAI,uBAAuB;AAQ3D,IAAM,kBAAkB,6BAA6B,QAAQ,GAAG;AAOhE,IAAI,CAAC,oBAAoB,mBAAmB,kBAAkB,SAAS;AACrE,EAAAA,QAAO,KAAK,yBAAyB,EAAE,WAAW,gBAAgB,UAAU,CAAC;AAC7E,QAAM,cAAc,IAAI;AAAA,IACtB;AAAA,MACE,YAAY;AAAA,QACV,QAAQ,kBAAkB;AAAA,QAC1B,WAAW,gBAAgB;AAAA,QAC3B,WAAW,gBAAgB;AAAA,QAC3B,YAAY;AAAA,MACd;AAAA,MACA,WAAW,gBAAgB;AAAA,MAC3B,aAAa,gBAAgB;AAAA,MAC7B,cAAc;AAAA;AAAA;AAAA,MAGd,eAAe,qBAAqB,QAAQ,GAAG;AAAA,MAC/C,GAAI,QAAQ,IAAI,mBAAmB,EAAE,WAAW,EAAE,eAAe,KAAK,KAAK,IAAK,EAAE,IAAI,CAAC;AAAA,IACzF;AAAA,IACA;AAAA,MACE,SAAS,CAAC,UAAU;AAClB,QAAAA,QAAO,KAAK,uBAAuB,EAAE,WAAW,MAAM,KAAe,CAAC;AAAA,MACxE;AAAA,IACF;AAAA,EACF;AACA,cAAY,YAAY,gBAAgB;AACxC,cAAY,cAAc,gBAAgB;AAC1C,cAAY,aAAa;AACzB,UAAQ,GAAG,WAAW,MAAM;AAC1B,mBAAe;AACf,gBAAY,KAAK;AAAA,EACnB,CAAC;AACD,UAAQ,GAAG,UAAU,MAAM;AACzB,mBAAe;AACf,gBAAY,KAAK;AAAA,EACnB,CAAC;AACD,QAAM,YAAY,IAAI;AACtB,QAAM,aAAa,YAAY,eAAe;AAC9C,eAAa,aAAa,UAAU,SAAS;AAAA,IAC3C,UAAU,aAAa,IAAI;AAAA,IAC3B,YAAY,YAAY,cAAc;AAAA,EACxC,CAAC;AACD,UAAQ,KAAK,aAAa,IAAI,CAAC;AACjC;AAEA,IAAI,CAAC,oBAAoB,iBAAiB;AACxC,EAAAA,QAAO,KAAK,0BAA0B,EAAE,WAAW,gBAAgB,UAAU,CAAC;AAC9E,QAAM,gBAAgB,IAAI;AAAA,IACxB;AAAA,MACE,YAAY;AAAA,QACV,QAAQ,kBAAkB;AAAA,QAC1B,WAAW,gBAAgB;AAAA,QAC3B,WAAW,gBAAgB;AAAA,QAC3B,YAAY;AAAA,MACd;AAAA,MACA,WAAW,gBAAgB;AAAA;AAAA,MAE3B,GAAI,QAAQ,IAAI,mBAAmB,EAAE,WAAW,EAAE,eAAe,KAAK,KAAK,IAAK,EAAE,IAAI,CAAC;AAAA,IACzF;AAAA,IACA;AAAA,MACE,SAAS,CAAC,UAAU;AAClB,QAAAA,QAAO,KAAK,wBAAwB,EAAE,WAAW,MAAM,KAAe,CAAC;AAAA,MACzE;AAAA,IACF;AAAA,EACF;AACA,cAAY,YAAY,gBAAgB;AACxC,cAAY,cAAc,gBAAgB;AAC1C,cAAY,aAAa;AACzB,UAAQ,GAAG,WAAW,MAAM;AAC1B,mBAAe;AACf,kBAAc,KAAK;AAAA,EACrB,CAAC;AACD,UAAQ,GAAG,UAAU,MAAM;AACzB,mBAAe;AACf,kBAAc,KAAK;AAAA,EACrB,CAAC;AACD,QAAM,cAAc,IAAI;AACxB,QAAM,eAAe,cAAc,eAAe;AAClD,eAAa,eAAe,UAAU,SAAS;AAAA,IAC7C,UAAU,eAAe,IAAI;AAAA,IAC7B,YAAY,cAAc,cAAc;AAAA,EAC1C,CAAC;AACD,UAAQ,KAAK,eAAe,IAAI,CAAC;AACnC;AAEA,IAAI,CAAC,uBAAuB,CAAC,kBAAkB;AAC7C,EAAAA,QAAO,MAAM,wCAAwC;AACrD,EAAAA,QAAO,MAAM,2DAA2D;AACxE,EAAAA,QAAO,MAAM,gDAAgD;AAC7D,EAAAA,QAAO,MAAM,EAAE;AACf,EAAAA,QAAO,MAAM,iEAAiE;AAC9E,EAAAA,QAAO,MAAM,EAAE;AACf,EAAAA,QAAO,MAAM,WAAW;AACxB,EAAAA,QAAO,MAAM,kEAAkE;AAC/E,EAAAA,QAAO,MAAM,4DAA4D;AACzE,EAAAA,QAAO;AAAA,IACL;AAAA,EACF;AACA,UAAQ,KAAK,CAAC;AAChB;AAEA,IACE,kBAAkB,UAClB,kBAAkB,QAClB,kBAAkB,iBAClB,kBAAkB,WAClB,kBAAkB,UAClB,kBAAkB,SAClB;AACA,EAAAA,QAAO,MAAM,yBAAyB;AAAA,IACpC,MAAM;AAAA,IACN,UAAU,CAAC,QAAQ,MAAM,eAAe,SAAS,QAAQ,OAAO;AAAA,EAClE,CAAC;AACD,UAAQ,KAAK,CAAC;AAChB;AAOA,IAAI,kBAAkB,WAAW,kBAAkB,SAAS;AAC1D,QAAM,mBAAmB,QAAQ,IAAI;AACrC,MAAI,CAAC,kBAAkB;AACrB,IAAAA,QAAO,MAAM,8CAA8C,EAAE,MAAM,cAAc,CAAC;AAClF,YAAQ,KAAK,CAAC;AAAA,EAChB;AACA,cAAY,YAAY;AACxB,cAAY,aAAa;AAEzB,QAAM,cAAc,yBAAyB;AAAA,IAC3C,MAAM;AAAA,IACN,QAAQ,kBAAkB;AAAA,IAC1B,WAAW;AAAA,IACX,WAAW;AAAA,IACX,cAAc;AAAA,IACd,WAAW,QAAQ,IAAI,uBAAuB;AAAA,EAChD,CAAC;AACD,EAAAA,QAAO,KAAK,kCAAkC;AAAA,IAC5C,MAAM;AAAA,IACN,WAAW;AAAA,EACb,CAAC;AACD,UAAQ,GAAG,WAAW,MAAM;AAC1B,mBAAe;AACf,gBAAY,KAAK;AAAA,EACnB,CAAC;AACD,UAAQ,GAAG,UAAU,MAAM;AACzB,mBAAe;AACf,gBAAY,KAAK;AAAA,EACnB,CAAC;AACD,QAAM,YAAY,IAAI;AACtB,QAAM,aAAa,YAAY,eAAe;AAC9C,eAAa,aAAa,UAAU,SAAS;AAAA,IAC3C,UAAU,aAAa,IAAI;AAAA,IAC3B,YAAY,YAAY,cAAc;AAAA,EACxC,CAAC;AACD,UAAQ,KAAK,aAAa,IAAI,CAAC;AACjC;AAEAA,QAAO,KAAK,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAMrD,IAAM,qBAAqB,QAAQ,IAAI,mBACnC,EAAE,eAAe,KAAK,KAAK,IAAK,IAChC,EAAE,oBAAoB,EAAE;AAE5B,IAAM,SAAS,IAAI;AAAA,EACjB;AAAA,IACE,YAAY;AAAA,MACV,QAAQ,kBAAkB;AAAA,MAC1B,WAAW;AAAA;AAAA;AAAA,MAGX,WAAW,QAAQ,IAAI,uBAAuB;AAAA,MAC9C,YAAY;AAAA,IACd;AAAA,IACA,YAAY;AAAA,IACZ,QAAQ;AAAA,IACR,cAAc;AAAA,IACd,WAAW;AAAA,IACX,WAAW;AAAA,EACb;AAAA,EACA;AAAA,IACE,gBAAgB,CAAC,WAA8B;AAC7C,MAAAA,QAAO,KAAK,kBAAkB,EAAE,OAAO,CAAC;AAAA,IAC1C;AAAA,IACA,SAAS,CAAC,UAAmC;AAC3C,YAAM,SACH,MAAM,WAAuB,MAAM,WAAuB,MAAM,WAAsB;AACzF,UAAI,QAAQ;AACV,QAAAA,QAAO,KAAK,QAAQ,EAAE,WAAW,MAAM,KAAe,CAAC;AAAA,MACzD;AAAA,IACF;AAAA,EACF;AACF;AAIA,IAAM,iBAAiB,IAAI,sBAAsB,OAAO,YAAY,kBAAkB;AAKtF,IAAM,kBAAkB,IAAI,uBAAuB,OAAO,YAAY,kBAAkB;AAExF,IAAI;AACJ,IAAI,6BAAgE;AACpE,IAAI,qBAA2C;AAE/C,IAAM,gBAAgB,CAAC,WAAiC;AACtD,iBAAe;AACf,EAAAA,QAAO,KAAK,YAAY,MAAM,mCAAmC;AACjE,QAAM,kBAAkB,sBAAsB,0BAA0B;AAKxE,mBAAiB;AAGjB,0BAAwB,YAAY;AAClC,QAAI;AACF,YAAM,QAAQ,IAAI,CAAC,eAAe,QAAQ,GAAG,gBAAgB,QAAQ,CAAC,CAAC;AAAA,IACzE,QAAQ;AAAA,IAER;AACA,QAAI;AACF,YAAM,OAAO,mBAAmB;AAAA,IAClC,UAAE;AACA,YAAM;AACN,aAAO,KAAK;AAAA,IACd;AAAA,EACF,GAAG;AACH,OAAK;AACL,aAAW,MAAM;AACf,IAAAA,QAAO,KAAK,sBAAsB,MAAM,UAAU;AAIlD,IAAAA,QAAO;AAAA,MACL;AAAA,MACA,kBAAkB;AAAA,QAChB,QAAQ;AAAA,QACR,UAAU;AAAA,QACV;AAAA,QACA,YAAY,OAAO,cAAc;AAAA,QACjC,WAAW,QAAQ,OAAO;AAAA,QAC1B,UAAU;AAAA,MACZ,CAAC;AAAA,IACH;AACA,YAAQ,KAAK,CAAC;AAAA,EAChB,GAAG,IAAM,EAAE,MAAM;AACnB;AAEA,QAAQ,GAAG,WAAW,MAAM,cAAc,SAAS,CAAC;AACpD,QAAQ,GAAG,UAAU,MAAM,cAAc,QAAQ,CAAC;AAKlD,6BAA6B,MAAM,mCAAmC;AAAA,EACpE,SAAS,MAAM,OAAO,QAAQ;AAAA,EAC9B,gBAAgB,MAAM,mBAAmB;AAAA,EACzC,QAAQ,MACN,IAAI,2BAA2B;AAAA,IAC7B,QAAQ,mBAAmB;AAAA,IAC3B,cAAc;AAAA,IACd,YAAY,OAAO;AAAA,EACrB,CAAC;AACL,CAAC;AACD,IAAI,CAAC,4BAA4B;AAC/B,EAAAA,QAAO,KAAK,sDAAsD;AAClE,MAAI,mBAAoB,OAAM;AAC9B,eAAa,iBAAiB,WAAW,SAAS;AAAA,IAChD,UAAU;AAAA,IACV,QAAQ;AAAA,IACR,YAAY,OAAO,cAAc;AAAA,EACnC,CAAC;AACD,UAAQ,KAAK,CAAC;AAChB;AAKA,OAAO,qBAAqB,0BAA0B;AAOtD,KAAK,yBAAyB;AAAA,EAC5B,WAAW,QAAQ,IAAI;AAAA,EACvB,QAAQ;AAAA,EACR,oBAAoB,OAAO,cAAc;AACvC,UAAM,MAAM,MAAM,OAAO,WAAW,KAAK,kBAAkB,EAAE,UAAU,CAAC;AACxE,WAAO,IAAI;AAAA,EACb;AAAA,EACA,QAAAA;AACF,CAAC;AAKD,IAAI,qBAAqB,aAAa,GAAG;AACvC,SAAO,WAAW,cAAc,CAAC,SAAS;AACxC,SAAK,eAAe,MAAM,IAAI,EAAE,MAAM,CAAC,QAAiB;AACtD,MAAAA,QAAO,MAAM,4BAA4B;AAAA,QACvC,OAAO,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAAA,MACxD,CAAC;AACD,aAAO,WAAW;AAAA,QAChB,KAAK;AAAA,QACL,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAAA,MACjD;AAAA,IACF,CAAC;AAAA,EACH,CAAC;AACH;AAKA,IAAI,qBAAqB,aAAa,GAAG;AACvC,SAAO,WAAW,WAAW,CAAC,SAAS;AACrC,SAAK,gBAAgB,MAAM,IAAI,EAAE,MAAM,CAAC,QAAiB;AACvD,MAAAA,QAAO,MAAM,6BAA6B;AAAA,QACxC,OAAO,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAAA,MACxD,CAAC;AACD,aAAO,WAAW;AAAA,QAChB,KAAK;AAAA,QACL,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAAA,MACjD;AAAA,IACF,CAAC;AAAA,EACH,CAAC;AACH;AAIA,OACG,IAAI,EACJ,KAAK,YAAY;AAChB,QAAM,sBAAsB,0BAA0B;AAMtD,QAAM,UAAU,OAAO,eAAe;AACtC,QAAM,SAA0B,iBAAiB,WAAW,UAAU,UAAU;AAChF,eAAa,QAAQ;AAAA,IACnB,UAAU,UAAU,IAAI;AAAA,IACxB,QAAQ;AAAA,IACR,YAAY,OAAO,cAAc;AAAA,EACnC,CAAC;AACD,UAAQ,KAAK,UAAU,IAAI,CAAC;AAC9B,CAAC,EACA,MAAM,OAAO,UAAmB;AAC/B,QAAM,sBAAsB,0BAA0B;AACtD,QAAM,MAAM,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AACjE,EAAAA,QAAO,MAAM,uBAAuB,EAAE,OAAO,IAAI,CAAC;AAClD,eAAa,SAAS,EAAE,UAAU,GAAG,YAAY,OAAO,cAAc,OAAU,CAAC;AACjF,UAAQ,KAAK,CAAC;AAChB,CAAC;","names":["join","dirname","join","isDisabled","join","logger","join","join","logger","nodeSpawn","logger","nodeSpawn","logger","dirname","join","logger"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/connection/heartbeat-worker.ts"],"sourcesContent":["/**\n * Starvation-proof heartbeat: a worker thread with its OWN event loop and its\n * OWN Socket.IO connection, so a stalled/starved main loop cannot silence the\n * session's liveness signal.\n *\n * Why this exists: the v3 lease chain (heartbeat → renewSessionLease, TTL\n * 150s + 120s stranded grace) reaps a session whose agent goes quiet for\n * ~4.5 minutes. A main-loop stall during a heavy gate used to do exactly\n * that — the session was declared stranded and the restart tore down the\n * in-flight run. This worker keeps beating through such stalls, reporting\n * `loopLagMs` (staleness of the main loop's shared tick) so the API can tell\n * \"alive but busy\" (renew the lease) from \"wedged\" (stop renewing past the\n * wedge ceiling and let the normal recovery run). The main loop still sends\n * its richer heartbeat when healthy — duplicate renewals are idempotent.\n *\n * Deliberately minimal: no bootstrap token refresh (the main thread posts\n * rotated tokens via postMessage), no reconnect ceremony beyond Socket.IO's\n * built-in retry, and it never throws — a broken worker just means heartbeats\n * degrade to main-loop-only, which is yesterday's behavior.\n */\nimport { parentPort, workerData } from \"node:worker_threads\";\nimport { io } from \"socket.io-client\";\nimport { buildConveyorSocketOptions } from \"@project/shared/socket-core\";\nimport { heartbeatStatusFor, lagFromBuffer, statusFromBuffer } from \"./loop-lag.js\";\n\ninterface HeartbeatWorkerData {\n apiUrl: string;\n taskToken: string;\n sessionId: string;\n runnerMode: string;\n sharedBuffer: SharedArrayBuffer;\n intervalMs: number;\n}\n\nconst data = workerData as HeartbeatWorkerData;\nconst view = new Float64Array(data.sharedBuffer);\nlet taskToken = data.taskToken;\n\nconst socket = io(\n data.apiUrl,\n buildConveyorSocketOptions((cb) => cb({ taskToken, runnerMode: data.runnerMode })),\n);\n\n// The main thread posts rotated task tokens (bootstrap refresh) so the worker\n// socket survives token expiry. The next (re)connect picks it up via the auth\n// callback above; a server-initiated disconnect needs a manual nudge.\nparentPort?.on(\"message\", (msg: { taskToken?: string }) => {\n if (msg?.taskToken) taskToken = msg.taskToken;\n});\n\nsocket.on(\"disconnect\", (reason: string) => {\n if (reason === \"io server disconnect\" || reason === \"server namespace disconnect\") {\n socket.connect();\n }\n});\n\nfunction beat(): void {\n if (!socket.connected) return;\n socket.emit(\n \"agentSessionService:heartbeat\",\n {\n sessionId: data.sessionId,\n timestamp: new Date().toISOString(),\n // `waiting` (runner idle, background work still running in the pod)\n // goes out as `active` — see heartbeatStatusFor.\n status: heartbeatStatusFor(statusFromBuffer(view)),\n loopLagMs: Math.round(lagFromBuffer(view)),\n },\n // Ack intentionally ignored: a missed beat self-heals on the next tick,\n // and the worker must never accumulate state or throw.\n () => {},\n );\n}\n\nsetInterval(beat, data.intervalMs);\n"],"mappings":";;;;;;;;AAoBA,SAAS,YAAY,kBAAkB;AACvC,SAAS,UAAU;AAanB,IAAM,OAAO;AACb,IAAM,OAAO,IAAI,aAAa,KAAK,YAAY;AAC/C,IAAI,YAAY,KAAK;AAErB,IAAM,SAAS;AAAA,EACb,KAAK;AAAA,EACL,2BAA2B,CAAC,OAAO,GAAG,EAAE,WAAW,YAAY,KAAK,WAAW,CAAC,CAAC;AACnF;AAKA,YAAY,GAAG,WAAW,CAAC,QAAgC;AACzD,MAAI,KAAK,UAAW,aAAY,IAAI;AACtC,CAAC;AAED,OAAO,GAAG,cAAc,CAAC,WAAmB;AAC1C,MAAI,WAAW,0BAA0B,WAAW,+BAA+B;AACjF,WAAO,QAAQ;AAAA,EACjB;AACF,CAAC;AAED,SAAS,OAAa;AACpB,MAAI,CAAC,OAAO,UAAW;AACvB,SAAO;AAAA,IACL;AAAA,IACA;AAAA,MACE,WAAW,KAAK;AAAA,MAChB,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA;AAAA;AAAA,MAGlC,QAAQ,mBAAmB,iBAAiB,IAAI,CAAC;AAAA,MACjD,WAAW,KAAK,MAAM,cAAc,IAAI,CAAC;AAAA,IAC3C;AAAA;AAAA;AAAA,IAGA,MAAM;AAAA,IAAC;AAAA,EACT;AACF;AAEA,YAAY,MAAM,KAAK,UAAU;","names":[]}
|
package/dist/index.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/runner/worktree.ts"],"sourcesContent":["import { execFile } from \"node:child_process\";\nimport { join } from \"node:path\";\nimport { promisify } from \"node:util\";\nimport { GIT_TIMEOUT_MS, hasUncommittedChanges } from \"./git-utils.js\";\nimport { getWorkbenchClient } from \"../workbench/client.js\";\nimport { workbenchEnabled } from \"../workbench/mode.js\";\nimport { workspacePathExists } from \"../workbench/fs.js\";\n\n// Async git (execFile, no shell) — synchronous child processes freeze the\n// agent's event loop and starve the socket heartbeat; see git-utils.ts.\n// Split-mode pods route over the launcher (the repo lives in the workbench).\nconst execFileAsync = promisify(execFile);\n\nasync function git(cwd: string, args: string[]): Promise<string> {\n if (workbenchEnabled()) {\n const { stdout } = await getWorkbenchClient().execFile(\"git\", args, {\n cwd,\n timeout: GIT_TIMEOUT_MS,\n });\n return stdout;\n }\n const { stdout } = await execFileAsync(\"git\", args, { cwd, timeout: GIT_TIMEOUT_MS });\n return stdout.toString();\n}\n\nconst WORKTREE_DIR = \".worktrees\";\n\nexport async function ensureWorktree(\n projectDir: string,\n taskId: string,\n branch?: string,\n): Promise<string> {\n if (projectDir.includes(`/${WORKTREE_DIR}/`)) {\n return projectDir;\n }\n\n const worktreePath = join(projectDir, WORKTREE_DIR, taskId);\n\n if (await workspacePathExists(worktreePath)) {\n if (branch) {\n if (await hasUncommittedChanges(worktreePath)) {\n return worktreePath;\n }\n try {\n await git(worktreePath, [\"checkout\", \"--detach\", `origin/${branch}`]);\n } catch {\n /* branch doesn't exist on remote yet */\n }\n }\n return worktreePath;\n }\n\n const ref = branch ? `origin/${branch}` : \"HEAD\";\n await git(projectDir, [\"worktree\", \"add\", \"--detach\", worktreePath, ref]);\n\n return worktreePath;\n}\n\n/**\n * Detach any task worktree that has `branch` checked out, releasing the branch lock\n * so the main project directory can check it out. Only touches worktrees inside\n * `.worktrees/` — never the main project directory.\n */\nexport async function detachWorktreeBranch(projectDir: string, branch: string): Promise<void> {\n try {\n const output = await git(projectDir, [\"worktree\", \"list\", \"--porcelain\"]);\n const entries = output.split(\"\\n\\n\");\n for (const entry of entries) {\n const lines = entry.trim().split(\"\\n\");\n const worktreeLine = lines.find((l) => l.startsWith(\"worktree \"));\n const branchLine = lines.find((l) => l.startsWith(\"branch \"));\n if (!worktreeLine || branchLine !== `branch refs/heads/${branch}`) continue;\n\n const worktreePath = worktreeLine.replace(\"worktree \", \"\");\n if (!worktreePath.includes(`/${WORKTREE_DIR}/`)) continue;\n\n try {\n await git(worktreePath, [\"checkout\", \"--detach\"]);\n } catch {\n /* best effort */\n }\n }\n } catch {\n /* best effort */\n }\n}\n\n/**\n * Force-remove is intentional: this runs after task completion or explicit stop.\n * Any uncommitted changes at this point are scratch artifacts, not valuable work.\n */\nexport async function removeWorktree(projectDir: string, taskId: string): Promise<void> {\n const worktreePath = join(projectDir, WORKTREE_DIR, taskId);\n if (!(await workspacePathExists(worktreePath))) return;\n try {\n await git(projectDir, [\"worktree\", \"remove\", worktreePath, \"--force\"]);\n } catch {\n /* best effort */\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,SAAS,gBAAgB;AACzB,SAAS,YAAY;AACrB,SAAS,iBAAiB;AAS1B,IAAM,gBAAgB,UAAU,QAAQ;AAExC,eAAe,IAAI,KAAa,MAAiC;AAC/D,MAAI,iBAAiB,GAAG;AACtB,UAAM,EAAE,QAAAA,QAAO,IAAI,MAAM,mBAAmB,EAAE,SAAS,OAAO,MAAM;AAAA,MAClE;AAAA,MACA,SAAS;AAAA,IACX,CAAC;AACD,WAAOA;AAAA,EACT;AACA,QAAM,EAAE,OAAO,IAAI,MAAM,cAAc,OAAO,MAAM,EAAE,KAAK,SAAS,eAAe,CAAC;AACpF,SAAO,OAAO,SAAS;AACzB;AAEA,IAAM,eAAe;AAErB,eAAsB,eACpB,YACA,QACA,QACiB;AACjB,MAAI,WAAW,SAAS,IAAI,YAAY,GAAG,GAAG;AAC5C,WAAO;AAAA,EACT;AAEA,QAAM,eAAe,KAAK,YAAY,cAAc,MAAM;AAE1D,MAAI,MAAM,oBAAoB,YAAY,GAAG;AAC3C,QAAI,QAAQ;AACV,UAAI,MAAM,sBAAsB,YAAY,GAAG;AAC7C,eAAO;AAAA,MACT;AACA,UAAI;AACF,cAAM,IAAI,cAAc,CAAC,YAAY,YAAY,UAAU,MAAM,EAAE,CAAC;AAAA,MACtE,QAAQ;AAAA,MAER;AAAA,IACF;AACA,WAAO;AAAA,EACT;AAEA,QAAM,MAAM,SAAS,UAAU,MAAM,KAAK;AAC1C,QAAM,IAAI,YAAY,CAAC,YAAY,OAAO,YAAY,cAAc,GAAG,CAAC;AAExE,SAAO;AACT;AAOA,eAAsB,qBAAqB,YAAoB,QAA+B;AAC5F,MAAI;AACF,UAAM,SAAS,MAAM,IAAI,YAAY,CAAC,YAAY,QAAQ,aAAa,CAAC;AACxE,UAAM,UAAU,OAAO,MAAM,MAAM;AACnC,eAAW,SAAS,SAAS;AAC3B,YAAM,QAAQ,MAAM,KAAK,EAAE,MAAM,IAAI;AACrC,YAAM,eAAe,MAAM,KAAK,CAAC,MAAM,EAAE,WAAW,WAAW,CAAC;AAChE,YAAM,aAAa,MAAM,KAAK,CAAC,MAAM,EAAE,WAAW,SAAS,CAAC;AAC5D,UAAI,CAAC,gBAAgB,eAAe,qBAAqB,MAAM,GAAI;AAEnE,YAAM,eAAe,aAAa,QAAQ,aAAa,EAAE;AACzD,UAAI,CAAC,aAAa,SAAS,IAAI,YAAY,GAAG,EAAG;AAEjD,UAAI;AACF,cAAM,IAAI,cAAc,CAAC,YAAY,UAAU,CAAC;AAAA,MAClD,QAAQ;AAAA,MAER;AAAA,IACF;AAAA,EACF,QAAQ;AAAA,EAER;AACF;AAMA,eAAsB,eAAe,YAAoB,QAA+B;AACtF,QAAM,eAAe,KAAK,YAAY,cAAc,MAAM;AAC1D,MAAI,CAAE,MAAM,oBAAoB,YAAY,EAAI;AAChD,MAAI;AACF,UAAM,IAAI,YAAY,CAAC,YAAY,UAAU,cAAc,SAAS,CAAC;AAAA,EACvE,QAAQ;AAAA,EAER;AACF;","names":["stdout"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|
package/dist/server-ZACB5T5S.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|