@rallycry/conveyor-agent 10.13.13 → 10.13.14

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.
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/workbench/client.ts","../src/workbench/errors.ts","../src/workbench/remote-process.ts"],"sourcesContent":["/**\n * Client half of the workbench launcher protocol. Runs in the protected agent\n * container; every method opens one loopback connection, sends the request\n * frame, and adapts the stream back to the local signature it replaces\n * (runSetupCommand, runStartCommand, execFile, PtySpawn, snapshot build/\n * extract, workspace file reads). See server.ts / protocol.ts.\n */\n\nimport { createReadStream, createWriteStream } from \"node:fs\";\nimport { connect, type Socket } from \"node:net\";\nimport type { PtyProcess, PtySpawnOptions } from \"../harness/pty/pty-support.js\";\nimport type { SnapshotExtractResult } from \"../runner/work-preservation/snapshot-tar.js\";\nimport { WorkbenchError } from \"./errors.js\";\nimport { RemoteProcessHandle } from \"./remote-process.js\";\n\nexport { WorkbenchError } from \"./errors.js\";\nexport { RemoteProcessHandle } from \"./remote-process.js\";\nimport { workbenchPort, workbenchToken } from \"./mode.js\";\nimport {\n DEFAULT_WORKBENCH_PORT,\n FrameReader,\n writeFrame,\n type WorkbenchFrame,\n type WorkbenchRequest,\n} from \"./protocol.js\";\n\nexport interface WorkbenchClientOptions {\n port?: number;\n token?: string;\n host?: string;\n}\n\n/** Metadata for a snapshot built remotely and streamed to a local tar path. */\nexport interface RemoteSnapshotMeta {\n tarPath: string;\n sizeBytes: number;\n fileCount: number;\n deletionCount: number;\n capturedAt: number;\n}\n\n/** Omit that distributes over a discriminated union (plain Omit collapses\n * the union to its common properties). */\ntype DistributiveOmit<T, K extends PropertyKey> = T extends unknown ? Omit<T, K> : never;\n\nfunction frameError(frame: Extract<WorkbenchFrame, { t: \"error\" }>): WorkbenchError {\n return new WorkbenchError(frame.message, frame.code);\n}\n\nexport class WorkbenchClient {\n private readonly port: number;\n private readonly host: string;\n private readonly token: string;\n\n constructor(options: WorkbenchClientOptions = {}) {\n this.port = options.port ?? workbenchPort() ?? DEFAULT_WORKBENCH_PORT;\n this.host = options.host ?? \"127.0.0.1\";\n this.token = options.token ?? workbenchToken();\n }\n\n /** Open a connection, send the request, route response frames. */\n private open(\n request: DistributiveOmit<WorkbenchRequest, \"token\">,\n onFrame: (frame: WorkbenchFrame, socket: Socket) => void,\n onClose: (error?: Error) => void,\n ): Socket {\n const socket = connect(this.port, this.host);\n let sawError: Error | undefined;\n const reader = new FrameReader((raw) => {\n const frame = raw as unknown as WorkbenchFrame;\n if (frame.t === \"error\") {\n sawError = frameError(frame as Extract<WorkbenchFrame, { t: \"error\" }>);\n }\n onFrame(frame, socket);\n });\n socket.on(\"connect\", () => {\n writeFrame(socket, { ...request, token: this.token } as WorkbenchRequest);\n });\n socket.on(\"data\", (chunk) => reader.push(chunk));\n socket.on(\"error\", (err) => {\n sawError ??= err;\n });\n socket.on(\"close\", () => onClose(sawError));\n return socket;\n }\n\n ping(): Promise<string> {\n return new Promise((resolve, reject) => {\n let version: string | null = null;\n this.open(\n { op: \"ping\" },\n (frame) => {\n if (frame.t === \"pong\") version = frame.version;\n },\n (error) => {\n if (version === null) {\n reject(error ?? new WorkbenchError(\"connection closed before pong\"));\n } else {\n resolve(version);\n }\n },\n );\n });\n }\n\n /** Mirrors setup/commands.ts runSetupCommand (shell form, streamed output,\n * abort → graceful term-group kill, non-zero exit rejects). */\n runSetupCommand(\n cmd: string,\n cwd: string,\n onOutput: (stream: \"stdout\" | \"stderr\", data: string) => void,\n signal?: AbortSignal,\n ): Promise<void> {\n return new Promise((resolve, reject) => {\n if (signal?.aborted) {\n const error = new Error(\"Operation aborted\");\n error.name = \"AbortError\";\n reject(error);\n return;\n }\n let exitCode: number | null = null;\n let exited = false;\n let aborting = false;\n const socket = this.open(\n { op: \"exec\", command: cmd, cwd },\n (frame) => {\n if (frame.t === \"out\" && !aborting) {\n onOutput(frame.s, Buffer.from(frame.d, \"base64\").toString(\"utf8\"));\n } else if (frame.t === \"exit\") {\n exited = true;\n exitCode = frame.code;\n }\n },\n (error) => {\n signal?.removeEventListener(\"abort\", onAbort);\n if (aborting) {\n const abortError = new Error(\"Operation aborted\");\n abortError.name = \"AbortError\";\n reject(abortError);\n } else if (!exited) {\n reject(error ?? new WorkbenchError(\"connection closed before exit\"));\n } else if (exitCode === 0) {\n resolve();\n } else {\n reject(new Error(`Setup command exited with code ${exitCode}`));\n }\n },\n );\n const onAbort = (): void => {\n if (exited || aborting) return;\n aborting = true;\n writeFrame(socket, { t: \"signal\", mode: \"term-group\" });\n };\n signal?.addEventListener(\"abort\", onAbort, { once: true });\n });\n }\n\n /** Mirrors setup/commands.ts runStartCommand: returns a live handle that\n * emits exit/error and whose kill() runs the graceful term-group stop. */\n runStartCommand(\n cmd: string,\n cwd: string,\n onOutput: (stream: \"stdout\" | \"stderr\", data: string) => void,\n ): RemoteProcessHandle {\n let socket: Socket | undefined;\n const handle = new RemoteProcessHandle(() => {\n if (socket) writeFrame(socket, { t: \"signal\", mode: \"term-group\" });\n });\n let exited = false;\n socket = this.open(\n { op: \"exec\", command: cmd, cwd },\n (frame) => {\n if (frame.t === \"out\") {\n onOutput(frame.s, Buffer.from(frame.d, \"base64\").toString(\"utf8\"));\n } else if (frame.t === \"exit\") {\n exited = true;\n handle.exitCode = frame.code ?? (frame.signal ? null : 0);\n handle.emit(\"exit\", frame.code, frame.signal);\n }\n },\n (error) => {\n if (!exited) {\n // Connection died without an exit frame (launcher restart, network\n // teardown): surface as an error + synthetic exit so the supervisor\n // observes the process ending rather than hanging on it forever.\n exited = true;\n handle.exitCode = handle.exitCode ?? 1;\n handle.emit(\n \"error\",\n error ?? new WorkbenchError(\"workbench connection lost\", \"workbench_gone\"),\n );\n handle.emit(\"exit\", handle.exitCode, null);\n }\n },\n );\n return handle;\n }\n\n /** Mirrors promisified execFile (argv form, no shell): resolves stdout,\n * rejects with stderr-bearing error on non-zero exit. */\n execFile(\n file: string,\n args: string[],\n opts: { cwd?: string; timeout?: number; maxBuffer?: number } = {},\n ): Promise<{ stdout: string; stderr: string }> {\n return new Promise((resolve, reject) => {\n const stdout: Buffer[] = [];\n const stderr: Buffer[] = [];\n let exitCode: number | null = null;\n let exitSignal: string | null = null;\n let exited = false;\n let timedOut = false;\n const socket = this.open(\n { op: \"exec\", argv: [file, ...args], cwd: opts.cwd ?? process.cwd() },\n (frame) => {\n if (frame.t === \"out\") {\n (frame.s === \"stdout\" ? stdout : stderr).push(Buffer.from(frame.d, \"base64\"));\n } else if (frame.t === \"exit\") {\n exited = true;\n exitCode = frame.code;\n exitSignal = frame.signal;\n }\n },\n (error) => {\n if (timer) clearTimeout(timer);\n const out = Buffer.concat(stdout).toString(\"utf8\");\n const errText = Buffer.concat(stderr).toString(\"utf8\");\n if (!exited) {\n reject(error ?? new WorkbenchError(\"connection closed before exit\"));\n } else if (exitCode === 0) {\n resolve({ stdout: out, stderr: errText });\n } else {\n const failure = new Error(\n timedOut\n ? `Command timed out: ${file}`\n : `Command failed: ${file} ${args.join(\" \")}\\n${errText}`,\n ) as Error & { code?: number | null; signal?: string | null; stdout: string; stderr: string };\n failure.code = exitCode;\n failure.signal = exitSignal;\n failure.stdout = out;\n failure.stderr = errText;\n reject(failure);\n }\n },\n );\n const timer = opts.timeout\n ? setTimeout(() => {\n timedOut = true;\n writeFrame(socket, { t: \"signal\", mode: \"term-group\" });\n }, opts.timeout)\n : null;\n timer?.unref();\n });\n }\n\n /**\n * Synchronous PtySpawn adapter: returns a PtyProcess immediately; writes\n * and resizes are queued until the connection opens. Exit surfaces through\n * onExit exactly as node-pty's would (a lost connection = exit code 1 —\n * the session's finalizeOnExit path treats it as a crashed CLI).\n */\n spawnPty(file: string, args: string[], options: PtySpawnOptions): PtyProcess {\n const dataListeners: Array<(data: string) => void> = [];\n const exitListeners: Array<(event: { exitCode: number }) => void> = [];\n let connected = false;\n let exited = false;\n const preConnectQueue: WorkbenchFrame[] = [];\n\n const socket = this.open(\n {\n op: \"pty\",\n file,\n args,\n cwd: options.cwd,\n env: options.env,\n cols: options.cols,\n rows: options.rows,\n },\n (frame) => {\n if (frame.t === \"data\") {\n const text = Buffer.from(frame.d, \"base64\").toString(\"utf8\");\n for (const listener of dataListeners) listener(text);\n } else if (frame.t === \"exit\") {\n exited = true;\n for (const listener of exitListeners) listener({ exitCode: frame.code ?? 1 });\n }\n },\n () => {\n if (!exited) {\n exited = true;\n for (const listener of exitListeners) listener({ exitCode: 1 });\n }\n },\n );\n socket.on(\"connect\", () => {\n connected = true;\n for (const frame of preConnectQueue.splice(0)) writeFrame(socket, frame);\n });\n\n const send = (frame: WorkbenchFrame): void => {\n if (exited) return;\n if (connected) writeFrame(socket, frame);\n else preConnectQueue.push(frame);\n };\n\n return {\n onData: (listener) => dataListeners.push(listener),\n onExit: (listener) => exitListeners.push(listener),\n write: (data) => send({ t: \"input\", d: Buffer.from(data, \"utf8\").toString(\"base64\") }),\n resize: (cols, rows) => send({ t: \"resize\", cols, rows }),\n kill: (sig) => send({ t: \"kill\", ...(sig ? { sig } : {}) }),\n };\n }\n\n /** Build a snapshot of `cwd` in the workbench and stream the tar.gz to\n * `destPath` on the agent side (the upload path streams from disk). */\n buildSnapshot(cwd: string, destPath: string): Promise<RemoteSnapshotMeta> {\n return new Promise((resolve, reject) => {\n let meta: Omit<RemoteSnapshotMeta, \"tarPath\"> | null = null;\n let ended = false;\n const out = createWriteStream(destPath);\n let writeFailure: Error | null = null;\n out.on(\"error\", (err) => {\n writeFailure = err;\n });\n this.open(\n { op: \"snapshotBuild\", cwd },\n (frame) => {\n if (frame.t === \"meta\") {\n meta = {\n sizeBytes: frame.sizeBytes,\n fileCount: frame.fileCount,\n deletionCount: frame.deletionCount,\n capturedAt: frame.capturedAt,\n };\n } else if (frame.t === \"data\") {\n out.write(Buffer.from(frame.d, \"base64\"));\n } else if (frame.t === \"end\") {\n ended = true;\n }\n },\n (error) => {\n out.end(() => {\n if (writeFailure) reject(writeFailure);\n else if (error) reject(error);\n else if (!ended || !meta) {\n reject(new WorkbenchError(\"snapshot stream ended prematurely\"));\n } else resolve({ ...meta, tarPath: destPath });\n });\n },\n );\n });\n }\n\n /** Stream a local tar.gz up and extract it into `cwd` in the workbench. */\n extractSnapshot(cwd: string, tarPath: string): Promise<SnapshotExtractResult> {\n return new Promise((resolve, reject) => {\n let result: SnapshotExtractResult | null = null;\n const socket = this.open(\n { op: \"snapshotExtract\", cwd },\n (frame) => {\n if (frame.t === \"result\") result = frame.value as SnapshotExtractResult;\n },\n (error) => {\n if (result) resolve(result);\n else reject(error ?? new WorkbenchError(\"connection closed before result\"));\n },\n );\n socket.on(\"connect\", () => {\n const stream = createReadStream(tarPath, { highWaterMark: 64 * 1024 });\n stream.on(\"data\", (chunk) => {\n writeFrame(socket, { t: \"data\", d: Buffer.from(chunk).toString(\"base64\") });\n });\n stream.on(\"end\", () => writeFrame(socket, { t: \"end\" }));\n stream.on(\"error\", (err) => {\n socket.destroy(err);\n });\n });\n });\n }\n\n readFile(path: string): Promise<Buffer> {\n return new Promise((resolve, reject) => {\n const chunks: Buffer[] = [];\n let ended = false;\n this.open(\n { op: \"readFile\", path },\n (frame) => {\n if (frame.t === \"data\") chunks.push(Buffer.from(frame.d, \"base64\"));\n else if (frame.t === \"end\") ended = true;\n },\n (error) => {\n if (ended) resolve(Buffer.concat(chunks));\n else reject(error ?? new WorkbenchError(\"connection closed before end\"));\n },\n );\n });\n }\n\n stat(path: string): Promise<{\n exists: boolean;\n isFile: boolean;\n isDirectory: boolean;\n size: number;\n mtimeMs: number;\n }> {\n return new Promise((resolve, reject) => {\n let stat: {\n exists: boolean;\n isFile: boolean;\n isDirectory: boolean;\n size: number;\n mtimeMs: number;\n } | null = null;\n this.open(\n { op: \"stat\", path },\n (frame) => {\n if (frame.t === \"stat\") {\n stat = {\n exists: frame.exists,\n isFile: frame.isFile,\n isDirectory: frame.isDirectory,\n size: frame.size,\n mtimeMs: frame.mtimeMs,\n };\n }\n },\n (error) => {\n if (stat) resolve(stat);\n else reject(error ?? new WorkbenchError(\"connection closed before stat\"));\n },\n );\n });\n }\n\n readdir(path: string): Promise<string[]> {\n return new Promise((resolve, reject) => {\n let entries: string[] | null = null;\n this.open(\n { op: \"readdir\", path },\n (frame) => {\n if (frame.t === \"entries\") entries = frame.names;\n },\n (error) => {\n if (entries) resolve(entries);\n else reject(error ?? new WorkbenchError(\"connection closed before entries\"));\n },\n );\n });\n }\n}\n\nlet singleton: WorkbenchClient | null = null;\n\n/** Lazy env-configured client (split-mode pods). */\nexport function getWorkbenchClient(): WorkbenchClient {\n singleton ??= new WorkbenchClient();\n return singleton;\n}\n\n/** Test seam. */\nexport function resetWorkbenchClient(): void {\n singleton = null;\n}\n","/** Error surfaced by the workbench client for launcher-side failures; `code`\n * carries the remote error code (e.g. \"ENOENT\", \"unauthorized\") so callers'\n * existing errno handling keeps working across the container boundary. */\nexport class WorkbenchError extends Error {\n code?: string;\n constructor(message: string, code?: string) {\n super(message);\n this.name = \"WorkbenchError\";\n if (code) this.code = code;\n }\n}\n","import { EventEmitter } from \"node:events\";\n\n/**\n * Structural stand-in for the ChildProcess surface the workspace-command\n * supervisor actually uses (pid/exitCode/kill + exit/error events) — see\n * ManagedChildProcess in setup/commands.ts. kill() requests the launcher's\n * graceful term-group sequence regardless of the signal argument.\n */\nexport class RemoteProcessHandle extends EventEmitter {\n pid: number | undefined = undefined;\n exitCode: number | null = null;\n\n constructor(private readonly sendSignal: () => void) {\n super();\n }\n\n kill(_signal?: NodeJS.Signals | number): boolean {\n this.sendSignal();\n return true;\n }\n}\n"],"mappings":";;;;;;;;;;;AAQA,SAAS,kBAAkB,yBAAyB;AACpD,SAAS,eAA4B;;;ACN9B,IAAM,iBAAN,cAA6B,MAAM;AAAA,EACxC;AAAA,EACA,YAAY,SAAiB,MAAe;AAC1C,UAAM,OAAO;AACb,SAAK,OAAO;AACZ,QAAI,KAAM,MAAK,OAAO;AAAA,EACxB;AACF;;;ACVA,SAAS,oBAAoB;AAQtB,IAAM,sBAAN,cAAkC,aAAa;AAAA,EAIpD,YAA6B,YAAwB;AACnD,UAAM;AADqB;AAAA,EAE7B;AAAA,EAF6B;AAAA,EAH7B,MAA0B;AAAA,EAC1B,WAA0B;AAAA,EAM1B,KAAK,SAA4C;AAC/C,SAAK,WAAW;AAChB,WAAO;AAAA,EACT;AACF;;;AFyBA,SAAS,WAAW,OAAgE;AAClF,SAAO,IAAI,eAAe,MAAM,SAAS,MAAM,IAAI;AACrD;AAEO,IAAM,kBAAN,MAAsB;AAAA,EACV;AAAA,EACA;AAAA,EACA;AAAA,EAEjB,YAAY,UAAkC,CAAC,GAAG;AAChD,SAAK,OAAO,QAAQ,QAAQ,cAAc,KAAK;AAC/C,SAAK,OAAO,QAAQ,QAAQ;AAC5B,SAAK,QAAQ,QAAQ,SAAS,eAAe;AAAA,EAC/C;AAAA;AAAA,EAGQ,KACN,SACA,SACA,SACQ;AACR,UAAM,SAAS,QAAQ,KAAK,MAAM,KAAK,IAAI;AAC3C,QAAI;AACJ,UAAM,SAAS,IAAI,YAAY,CAAC,QAAQ;AACtC,YAAM,QAAQ;AACd,UAAI,MAAM,MAAM,SAAS;AACvB,mBAAW,WAAW,KAAgD;AAAA,MACxE;AACA,cAAQ,OAAO,MAAM;AAAA,IACvB,CAAC;AACD,WAAO,GAAG,WAAW,MAAM;AACzB,iBAAW,QAAQ,EAAE,GAAG,SAAS,OAAO,KAAK,MAAM,CAAqB;AAAA,IAC1E,CAAC;AACD,WAAO,GAAG,QAAQ,CAAC,UAAU,OAAO,KAAK,KAAK,CAAC;AAC/C,WAAO,GAAG,SAAS,CAAC,QAAQ;AAC1B,mBAAa;AAAA,IACf,CAAC;AACD,WAAO,GAAG,SAAS,MAAM,QAAQ,QAAQ,CAAC;AAC1C,WAAO;AAAA,EACT;AAAA,EAEA,OAAwB;AACtB,WAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AACtC,UAAI,UAAyB;AAC7B,WAAK;AAAA,QACH,EAAE,IAAI,OAAO;AAAA,QACb,CAAC,UAAU;AACT,cAAI,MAAM,MAAM,OAAQ,WAAU,MAAM;AAAA,QAC1C;AAAA,QACA,CAAC,UAAU;AACT,cAAI,YAAY,MAAM;AACpB,mBAAO,SAAS,IAAI,eAAe,+BAA+B,CAAC;AAAA,UACrE,OAAO;AACL,oBAAQ,OAAO;AAAA,UACjB;AAAA,QACF;AAAA,MACF;AAAA,IACF,CAAC;AAAA,EACH;AAAA;AAAA;AAAA,EAIA,gBACE,KACA,KACA,UACA,QACe;AACf,WAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AACtC,UAAI,QAAQ,SAAS;AACnB,cAAM,QAAQ,IAAI,MAAM,mBAAmB;AAC3C,cAAM,OAAO;AACb,eAAO,KAAK;AACZ;AAAA,MACF;AACA,UAAI,WAA0B;AAC9B,UAAI,SAAS;AACb,UAAI,WAAW;AACf,YAAM,SAAS,KAAK;AAAA,QAClB,EAAE,IAAI,QAAQ,SAAS,KAAK,IAAI;AAAA,QAChC,CAAC,UAAU;AACT,cAAI,MAAM,MAAM,SAAS,CAAC,UAAU;AAClC,qBAAS,MAAM,GAAG,OAAO,KAAK,MAAM,GAAG,QAAQ,EAAE,SAAS,MAAM,CAAC;AAAA,UACnE,WAAW,MAAM,MAAM,QAAQ;AAC7B,qBAAS;AACT,uBAAW,MAAM;AAAA,UACnB;AAAA,QACF;AAAA,QACA,CAAC,UAAU;AACT,kBAAQ,oBAAoB,SAAS,OAAO;AAC5C,cAAI,UAAU;AACZ,kBAAM,aAAa,IAAI,MAAM,mBAAmB;AAChD,uBAAW,OAAO;AAClB,mBAAO,UAAU;AAAA,UACnB,WAAW,CAAC,QAAQ;AAClB,mBAAO,SAAS,IAAI,eAAe,+BAA+B,CAAC;AAAA,UACrE,WAAW,aAAa,GAAG;AACzB,oBAAQ;AAAA,UACV,OAAO;AACL,mBAAO,IAAI,MAAM,kCAAkC,QAAQ,EAAE,CAAC;AAAA,UAChE;AAAA,QACF;AAAA,MACF;AACA,YAAM,UAAU,MAAY;AAC1B,YAAI,UAAU,SAAU;AACxB,mBAAW;AACX,mBAAW,QAAQ,EAAE,GAAG,UAAU,MAAM,aAAa,CAAC;AAAA,MACxD;AACA,cAAQ,iBAAiB,SAAS,SAAS,EAAE,MAAM,KAAK,CAAC;AAAA,IAC3D,CAAC;AAAA,EACH;AAAA;AAAA;AAAA,EAIA,gBACE,KACA,KACA,UACqB;AACrB,QAAI;AACJ,UAAM,SAAS,IAAI,oBAAoB,MAAM;AAC3C,UAAI,OAAQ,YAAW,QAAQ,EAAE,GAAG,UAAU,MAAM,aAAa,CAAC;AAAA,IACpE,CAAC;AACD,QAAI,SAAS;AACb,aAAS,KAAK;AAAA,MACZ,EAAE,IAAI,QAAQ,SAAS,KAAK,IAAI;AAAA,MAChC,CAAC,UAAU;AACT,YAAI,MAAM,MAAM,OAAO;AACrB,mBAAS,MAAM,GAAG,OAAO,KAAK,MAAM,GAAG,QAAQ,EAAE,SAAS,MAAM,CAAC;AAAA,QACnE,WAAW,MAAM,MAAM,QAAQ;AAC7B,mBAAS;AACT,iBAAO,WAAW,MAAM,SAAS,MAAM,SAAS,OAAO;AACvD,iBAAO,KAAK,QAAQ,MAAM,MAAM,MAAM,MAAM;AAAA,QAC9C;AAAA,MACF;AAAA,MACA,CAAC,UAAU;AACT,YAAI,CAAC,QAAQ;AAIX,mBAAS;AACT,iBAAO,WAAW,OAAO,YAAY;AACrC,iBAAO;AAAA,YACL;AAAA,YACA,SAAS,IAAI,eAAe,6BAA6B,gBAAgB;AAAA,UAC3E;AACA,iBAAO,KAAK,QAAQ,OAAO,UAAU,IAAI;AAAA,QAC3C;AAAA,MACF;AAAA,IACF;AACA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA,EAIA,SACE,MACA,MACA,OAA+D,CAAC,GACnB;AAC7C,WAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AACtC,YAAM,SAAmB,CAAC;AAC1B,YAAM,SAAmB,CAAC;AAC1B,UAAI,WAA0B;AAC9B,UAAI,aAA4B;AAChC,UAAI,SAAS;AACb,UAAI,WAAW;AACf,YAAM,SAAS,KAAK;AAAA,QAClB,EAAE,IAAI,QAAQ,MAAM,CAAC,MAAM,GAAG,IAAI,GAAG,KAAK,KAAK,OAAO,QAAQ,IAAI,EAAE;AAAA,QACpE,CAAC,UAAU;AACT,cAAI,MAAM,MAAM,OAAO;AACrB,aAAC,MAAM,MAAM,WAAW,SAAS,QAAQ,KAAK,OAAO,KAAK,MAAM,GAAG,QAAQ,CAAC;AAAA,UAC9E,WAAW,MAAM,MAAM,QAAQ;AAC7B,qBAAS;AACT,uBAAW,MAAM;AACjB,yBAAa,MAAM;AAAA,UACrB;AAAA,QACF;AAAA,QACA,CAAC,UAAU;AACT,cAAI,MAAO,cAAa,KAAK;AAC7B,gBAAM,MAAM,OAAO,OAAO,MAAM,EAAE,SAAS,MAAM;AACjD,gBAAM,UAAU,OAAO,OAAO,MAAM,EAAE,SAAS,MAAM;AACrD,cAAI,CAAC,QAAQ;AACX,mBAAO,SAAS,IAAI,eAAe,+BAA+B,CAAC;AAAA,UACrE,WAAW,aAAa,GAAG;AACzB,oBAAQ,EAAE,QAAQ,KAAK,QAAQ,QAAQ,CAAC;AAAA,UAC1C,OAAO;AACL,kBAAM,UAAU,IAAI;AAAA,cAClB,WACI,sBAAsB,IAAI,KAC1B,mBAAmB,IAAI,IAAI,KAAK,KAAK,GAAG,CAAC;AAAA,EAAK,OAAO;AAAA,YAC3D;AACA,oBAAQ,OAAO;AACf,oBAAQ,SAAS;AACjB,oBAAQ,SAAS;AACjB,oBAAQ,SAAS;AACjB,mBAAO,OAAO;AAAA,UAChB;AAAA,QACF;AAAA,MACF;AACA,YAAM,QAAQ,KAAK,UACf,WAAW,MAAM;AACf,mBAAW;AACX,mBAAW,QAAQ,EAAE,GAAG,UAAU,MAAM,aAAa,CAAC;AAAA,MACxD,GAAG,KAAK,OAAO,IACf;AACJ,aAAO,MAAM;AAAA,IACf,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,SAAS,MAAc,MAAgB,SAAsC;AAC3E,UAAM,gBAA+C,CAAC;AACtD,UAAM,gBAA8D,CAAC;AACrE,QAAI,YAAY;AAChB,QAAI,SAAS;AACb,UAAM,kBAAoC,CAAC;AAE3C,UAAM,SAAS,KAAK;AAAA,MAClB;AAAA,QACE,IAAI;AAAA,QACJ;AAAA,QACA;AAAA,QACA,KAAK,QAAQ;AAAA,QACb,KAAK,QAAQ;AAAA,QACb,MAAM,QAAQ;AAAA,QACd,MAAM,QAAQ;AAAA,MAChB;AAAA,MACA,CAAC,UAAU;AACT,YAAI,MAAM,MAAM,QAAQ;AACtB,gBAAM,OAAO,OAAO,KAAK,MAAM,GAAG,QAAQ,EAAE,SAAS,MAAM;AAC3D,qBAAW,YAAY,cAAe,UAAS,IAAI;AAAA,QACrD,WAAW,MAAM,MAAM,QAAQ;AAC7B,mBAAS;AACT,qBAAW,YAAY,cAAe,UAAS,EAAE,UAAU,MAAM,QAAQ,EAAE,CAAC;AAAA,QAC9E;AAAA,MACF;AAAA,MACA,MAAM;AACJ,YAAI,CAAC,QAAQ;AACX,mBAAS;AACT,qBAAW,YAAY,cAAe,UAAS,EAAE,UAAU,EAAE,CAAC;AAAA,QAChE;AAAA,MACF;AAAA,IACF;AACA,WAAO,GAAG,WAAW,MAAM;AACzB,kBAAY;AACZ,iBAAW,SAAS,gBAAgB,OAAO,CAAC,EAAG,YAAW,QAAQ,KAAK;AAAA,IACzE,CAAC;AAED,UAAM,OAAO,CAAC,UAAgC;AAC5C,UAAI,OAAQ;AACZ,UAAI,UAAW,YAAW,QAAQ,KAAK;AAAA,UAClC,iBAAgB,KAAK,KAAK;AAAA,IACjC;AAEA,WAAO;AAAA,MACL,QAAQ,CAAC,aAAa,cAAc,KAAK,QAAQ;AAAA,MACjD,QAAQ,CAAC,aAAa,cAAc,KAAK,QAAQ;AAAA,MACjD,OAAO,CAAC,SAAS,KAAK,EAAE,GAAG,SAAS,GAAG,OAAO,KAAK,MAAM,MAAM,EAAE,SAAS,QAAQ,EAAE,CAAC;AAAA,MACrF,QAAQ,CAAC,MAAM,SAAS,KAAK,EAAE,GAAG,UAAU,MAAM,KAAK,CAAC;AAAA,MACxD,MAAM,CAAC,QAAQ,KAAK,EAAE,GAAG,QAAQ,GAAI,MAAM,EAAE,IAAI,IAAI,CAAC,EAAG,CAAC;AAAA,IAC5D;AAAA,EACF;AAAA;AAAA;AAAA,EAIA,cAAc,KAAa,UAA+C;AACxE,WAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AACtC,UAAI,OAAmD;AACvD,UAAI,QAAQ;AACZ,YAAM,MAAM,kBAAkB,QAAQ;AACtC,UAAI,eAA6B;AACjC,UAAI,GAAG,SAAS,CAAC,QAAQ;AACvB,uBAAe;AAAA,MACjB,CAAC;AACD,WAAK;AAAA,QACH,EAAE,IAAI,iBAAiB,IAAI;AAAA,QAC3B,CAAC,UAAU;AACT,cAAI,MAAM,MAAM,QAAQ;AACtB,mBAAO;AAAA,cACL,WAAW,MAAM;AAAA,cACjB,WAAW,MAAM;AAAA,cACjB,eAAe,MAAM;AAAA,cACrB,YAAY,MAAM;AAAA,YACpB;AAAA,UACF,WAAW,MAAM,MAAM,QAAQ;AAC7B,gBAAI,MAAM,OAAO,KAAK,MAAM,GAAG,QAAQ,CAAC;AAAA,UAC1C,WAAW,MAAM,MAAM,OAAO;AAC5B,oBAAQ;AAAA,UACV;AAAA,QACF;AAAA,QACA,CAAC,UAAU;AACT,cAAI,IAAI,MAAM;AACZ,gBAAI,aAAc,QAAO,YAAY;AAAA,qBAC5B,MAAO,QAAO,KAAK;AAAA,qBACnB,CAAC,SAAS,CAAC,MAAM;AACxB,qBAAO,IAAI,eAAe,mCAAmC,CAAC;AAAA,YAChE,MAAO,SAAQ,EAAE,GAAG,MAAM,SAAS,SAAS,CAAC;AAAA,UAC/C,CAAC;AAAA,QACH;AAAA,MACF;AAAA,IACF,CAAC;AAAA,EACH;AAAA;AAAA,EAGA,gBAAgB,KAAa,SAAiD;AAC5E,WAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AACtC,UAAI,SAAuC;AAC3C,YAAM,SAAS,KAAK;AAAA,QAClB,EAAE,IAAI,mBAAmB,IAAI;AAAA,QAC7B,CAAC,UAAU;AACT,cAAI,MAAM,MAAM,SAAU,UAAS,MAAM;AAAA,QAC3C;AAAA,QACA,CAAC,UAAU;AACT,cAAI,OAAQ,SAAQ,MAAM;AAAA,cACrB,QAAO,SAAS,IAAI,eAAe,iCAAiC,CAAC;AAAA,QAC5E;AAAA,MACF;AACA,aAAO,GAAG,WAAW,MAAM;AACzB,cAAM,SAAS,iBAAiB,SAAS,EAAE,eAAe,KAAK,KAAK,CAAC;AACrE,eAAO,GAAG,QAAQ,CAAC,UAAU;AAC3B,qBAAW,QAAQ,EAAE,GAAG,QAAQ,GAAG,OAAO,KAAK,KAAK,EAAE,SAAS,QAAQ,EAAE,CAAC;AAAA,QAC5E,CAAC;AACD,eAAO,GAAG,OAAO,MAAM,WAAW,QAAQ,EAAE,GAAG,MAAM,CAAC,CAAC;AACvD,eAAO,GAAG,SAAS,CAAC,QAAQ;AAC1B,iBAAO,QAAQ,GAAG;AAAA,QACpB,CAAC;AAAA,MACH,CAAC;AAAA,IACH,CAAC;AAAA,EACH;AAAA,EAEA,SAAS,MAA+B;AACtC,WAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AACtC,YAAM,SAAmB,CAAC;AAC1B,UAAI,QAAQ;AACZ,WAAK;AAAA,QACH,EAAE,IAAI,YAAY,KAAK;AAAA,QACvB,CAAC,UAAU;AACT,cAAI,MAAM,MAAM,OAAQ,QAAO,KAAK,OAAO,KAAK,MAAM,GAAG,QAAQ,CAAC;AAAA,mBACzD,MAAM,MAAM,MAAO,SAAQ;AAAA,QACtC;AAAA,QACA,CAAC,UAAU;AACT,cAAI,MAAO,SAAQ,OAAO,OAAO,MAAM,CAAC;AAAA,cACnC,QAAO,SAAS,IAAI,eAAe,8BAA8B,CAAC;AAAA,QACzE;AAAA,MACF;AAAA,IACF,CAAC;AAAA,EACH;AAAA,EAEA,KAAK,MAMF;AACD,WAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AACtC,UAAI,OAMO;AACX,WAAK;AAAA,QACH,EAAE,IAAI,QAAQ,KAAK;AAAA,QACnB,CAAC,UAAU;AACT,cAAI,MAAM,MAAM,QAAQ;AACtB,mBAAO;AAAA,cACL,QAAQ,MAAM;AAAA,cACd,QAAQ,MAAM;AAAA,cACd,aAAa,MAAM;AAAA,cACnB,MAAM,MAAM;AAAA,cACZ,SAAS,MAAM;AAAA,YACjB;AAAA,UACF;AAAA,QACF;AAAA,QACA,CAAC,UAAU;AACT,cAAI,KAAM,SAAQ,IAAI;AAAA,cACjB,QAAO,SAAS,IAAI,eAAe,+BAA+B,CAAC;AAAA,QAC1E;AAAA,MACF;AAAA,IACF,CAAC;AAAA,EACH;AAAA,EAEA,QAAQ,MAAiC;AACvC,WAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AACtC,UAAI,UAA2B;AAC/B,WAAK;AAAA,QACH,EAAE,IAAI,WAAW,KAAK;AAAA,QACtB,CAAC,UAAU;AACT,cAAI,MAAM,MAAM,UAAW,WAAU,MAAM;AAAA,QAC7C;AAAA,QACA,CAAC,UAAU;AACT,cAAI,QAAS,SAAQ,OAAO;AAAA,cACvB,QAAO,SAAS,IAAI,eAAe,kCAAkC,CAAC;AAAA,QAC7E;AAAA,MACF;AAAA,IACF,CAAC;AAAA,EACH;AACF;AAEA,IAAI,YAAoC;AAGjC,SAAS,qBAAsC;AACpD,gBAAc,IAAI,gBAAgB;AAClC,SAAO;AACT;AAGO,SAAS,uBAA6B;AAC3C,cAAY;AACd;","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/workbench/server.ts"],"sourcesContent":["/**\n * The workbench launcher — PID 1 of the workbench container in split-mode\n * pods (CONVEYOR_MODE=workbench). A token-authed, loopback-only exec daemon:\n * the agent container drives every workspace-touching operation through it\n * (shell commands, the claude PTY, git, snapshot build/extract, file reads)\n * while staying insulated from workload OOMs in its own container cgroup.\n *\n * One connection = one operation. A dropped connection kills the operation's\n * process (group) — the agent dying, restarting, or timing out must never\n * leave orphans accumulating against the workbench memory budget.\n */\n\nimport { spawn, type ChildProcess } from \"node:child_process\";\nimport { createReadStream, createWriteStream } from \"node:fs\";\nimport { mkdtemp, readdir, readFile, rm, stat } from \"node:fs/promises\";\nimport { createServer, type Socket } from \"node:net\";\nimport { tmpdir } from \"node:os\";\nimport { join } from \"node:path\";\nimport { terminateProcessGroup } from \"../setup/commands.js\";\nimport { loadPtySpawn, type PtyProcess } from \"../harness/pty/pty-support.js\";\nimport { buildSnapshotTar, extractSnapshotTar } from \"../runner/work-preservation/snapshot-tar.js\";\nimport {\n FrameReader,\n timingSafeTokenEqual,\n writeFrame,\n type WorkbenchFrame,\n type WorkbenchRequest,\n} from \"./protocol.js\";\n\nconst TAR_CHUNK_BYTES = 64 * 1024;\n\nexport interface WorkbenchServerOptions {\n port: number;\n token: string;\n version: string;\n}\n\nexport interface WorkbenchServerHandle {\n port: number;\n close(): Promise<void>;\n}\n\nfunction errCode(err: unknown): string | undefined {\n return typeof (err as { code?: unknown })?.code === \"string\"\n ? (err as { code: string }).code\n : undefined;\n}\n\nfunction sendError(socket: Socket, err: unknown): void {\n const frame: WorkbenchFrame = {\n t: \"error\",\n message: err instanceof Error ? err.message : String(err),\n ...(errCode(err) ? { code: errCode(err) } : {}),\n };\n writeFrame(socket, frame);\n}\n\n/** Merge request env over the daemon's own (mirrors the local spawn paths,\n * which inherit process.env and let callers override). */\nfunction mergedEnv(overrides?: Record<string, string>): NodeJS.ProcessEnv {\n return overrides ? { ...process.env, ...overrides } : { ...process.env };\n}\n\n/**\n * Post-dispatch inbound frames for the connection's operation. Handlers\n * assign `onNext`; frames arriving before assignment are queued so an input\n * racing the (async) pty spawn is never dropped.\n */\nclass FrameSink {\n private pending: WorkbenchFrame[] = [];\n private handler: ((frame: WorkbenchFrame) => void) | null = null;\n\n push(frame: WorkbenchFrame): void {\n if (this.handler) this.handler(frame);\n else this.pending.push(frame);\n }\n\n setHandler(handler: (frame: WorkbenchFrame) => void): void {\n this.handler = handler;\n for (const frame of this.pending.splice(0)) handler(frame);\n }\n}\n\nexport async function startWorkbenchServer(\n opts: WorkbenchServerOptions,\n): Promise<WorkbenchServerHandle> {\n const server = createServer((socket) => handleConnection(socket, opts));\n await new Promise<void>((resolve, reject) => {\n server.once(\"error\", reject);\n server.listen(opts.port, \"127.0.0.1\", () => resolve());\n });\n const address = server.address();\n const port = typeof address === \"object\" && address ? address.port : opts.port;\n return {\n port,\n close: () =>\n new Promise<void>((resolve) => {\n server.close(() => resolve());\n }),\n };\n}\n\nfunction handleConnection(socket: Socket, opts: WorkbenchServerOptions): void {\n socket.on(\"error\", () => undefined);\n const sink = new FrameSink();\n let dispatched = false;\n const reader = new FrameReader((frame) => {\n if (dispatched) {\n sink.push(frame as unknown as WorkbenchFrame);\n return;\n }\n dispatched = true;\n dispatch(socket, frame as unknown as WorkbenchRequest, sink, opts);\n });\n socket.on(\"data\", (chunk: Buffer) => reader.push(chunk));\n}\n\nfunction dispatch(\n socket: Socket,\n req: WorkbenchRequest,\n sink: FrameSink,\n opts: WorkbenchServerOptions,\n): void {\n if (!req || typeof req !== \"object\" || !timingSafeTokenEqual(req.token ?? \"\", opts.token)) {\n writeFrame(socket, { t: \"error\", message: \"unauthorized\", code: \"unauthorized\" });\n socket.destroy();\n return;\n }\n switch (req.op) {\n case \"ping\":\n writeFrame(socket, { t: \"pong\", version: opts.version });\n socket.end();\n return;\n case \"exec\":\n runExec(socket, req, sink);\n return;\n case \"pty\":\n void runPty(socket, req, sink);\n return;\n case \"snapshotBuild\":\n void runSnapshotBuild(socket, req);\n return;\n case \"snapshotExtract\":\n void runSnapshotExtract(socket, req, sink);\n return;\n case \"readFile\":\n void runReadFile(socket, req);\n return;\n case \"stat\":\n void runStat(socket, req);\n return;\n case \"readdir\":\n void runReaddir(socket, req);\n return;\n default:\n writeFrame(socket, { t: \"error\", message: \"unknown op\", code: \"bad_request\" });\n socket.end();\n }\n}\n\nfunction runExec(\n socket: Socket,\n req: Extract<WorkbenchRequest, { op: \"exec\" }>,\n sink: FrameSink,\n): void {\n let child: ChildProcess;\n try {\n // Argv form (git and friends) spawns directly with no shell; shell form\n // (setup/start commands) mirrors the local `spawn(\"sh\", [\"-c\", cmd])`.\n const [argvFile, ...argvRest] = req.argv ?? [];\n child = argvFile\n ? spawn(argvFile, argvRest, {\n cwd: req.cwd,\n stdio: [\"ignore\", \"pipe\", \"pipe\"],\n detached: true,\n env: mergedEnv(req.env),\n })\n : spawn(\"sh\", [\"-c\", req.command ?? \"\"], {\n cwd: req.cwd,\n stdio: [\"ignore\", \"pipe\", \"pipe\"],\n detached: true,\n env: mergedEnv(req.env),\n });\n } catch (err) {\n sendError(socket, err);\n socket.end();\n return;\n }\n\n let settled = false;\n sink.setHandler((frame) => {\n if (frame.t === \"signal\" && frame.mode === \"term-group\" && !settled) {\n void terminateProcessGroup(child);\n }\n });\n child.stdout?.on(\"data\", (chunk: Buffer) => {\n writeFrame(socket, { t: \"out\", s: \"stdout\", d: chunk.toString(\"base64\") });\n });\n child.stderr?.on(\"data\", (chunk: Buffer) => {\n writeFrame(socket, { t: \"out\", s: \"stderr\", d: chunk.toString(\"base64\") });\n });\n child.on(\"close\", (code, signal) => {\n settled = true;\n writeFrame(socket, { t: \"exit\", code, signal });\n socket.end();\n });\n child.on(\"error\", (err) => {\n if (settled) return;\n settled = true;\n sendError(socket, err);\n socket.end();\n });\n // Agent gone (crash, timeout-abort, container death) → no orphans.\n socket.on(\"close\", () => {\n if (!settled) void terminateProcessGroup(child);\n });\n}\n\nasync function runPty(\n socket: Socket,\n req: Extract<WorkbenchRequest, { op: \"pty\" }>,\n sink: FrameSink,\n): Promise<void> {\n let pty: PtyProcess;\n try {\n const ptySpawn = await loadPtySpawn();\n pty = ptySpawn(req.file, req.args, {\n name: \"xterm-color\",\n cols: req.cols,\n rows: req.rows,\n cwd: req.cwd,\n env: req.env,\n });\n } catch (err) {\n sendError(socket, err);\n socket.end();\n return;\n }\n\n let exited = false;\n sink.setHandler((frame) => {\n try {\n if (frame.t === \"input\" && typeof frame.d === \"string\") {\n pty.write(Buffer.from(frame.d, \"base64\").toString(\"utf8\"));\n } else if (\n frame.t === \"resize\" &&\n typeof frame.cols === \"number\" &&\n typeof frame.rows === \"number\"\n ) {\n pty.resize(frame.cols, frame.rows);\n } else if (frame.t === \"kill\") {\n pty.kill(typeof frame.sig === \"string\" ? frame.sig : undefined);\n }\n } catch {\n /* pty already dead — exit handler owns teardown */\n }\n });\n pty.onData((data) => {\n writeFrame(socket, { t: \"data\", d: Buffer.from(data, \"utf8\").toString(\"base64\") });\n });\n pty.onExit((event) => {\n exited = true;\n writeFrame(socket, { t: \"exit\", code: event.exitCode, signal: null });\n socket.end();\n });\n socket.on(\"close\", () => {\n if (!exited) {\n try {\n pty.kill();\n } catch {\n /* already dead */\n }\n }\n });\n}\n\nasync function runSnapshotBuild(\n socket: Socket,\n req: Extract<WorkbenchRequest, { op: \"snapshotBuild\" }>,\n): Promise<void> {\n try {\n const result = await buildSnapshotTar(req.cwd);\n try {\n writeFrame(socket, {\n t: \"meta\",\n sizeBytes: result.sizeBytes,\n fileCount: result.fileCount,\n deletionCount: result.deletionCount,\n capturedAt: result.capturedAt,\n });\n await new Promise<void>((resolve, reject) => {\n const stream = createReadStream(result.tarPath, { highWaterMark: TAR_CHUNK_BYTES });\n stream.on(\"data\", (chunk) => {\n writeFrame(socket, { t: \"data\", d: Buffer.from(chunk).toString(\"base64\") });\n });\n stream.on(\"end\", () => resolve());\n stream.on(\"error\", reject);\n socket.on(\"close\", () => stream.destroy());\n });\n writeFrame(socket, { t: \"end\" });\n } finally {\n await result.cleanup();\n }\n } catch (err) {\n sendError(socket, err);\n }\n socket.end();\n}\n\nasync function runSnapshotExtract(\n socket: Socket,\n req: Extract<WorkbenchRequest, { op: \"snapshotExtract\" }>,\n sink: FrameSink,\n): Promise<void> {\n const staging = await mkdtemp(join(tmpdir(), \"conveyor-workbench-extract-\"));\n const tarPath = join(staging, \"snapshot.tar.gz\");\n const out = createWriteStream(tarPath);\n try {\n await new Promise<void>((resolve, reject) => {\n sink.setHandler((frame) => {\n if (frame.t === \"data\" && typeof frame.d === \"string\") {\n out.write(Buffer.from(frame.d, \"base64\"));\n } else if (frame.t === \"end\") {\n out.end(() => resolve());\n }\n });\n out.on(\"error\", reject);\n socket.on(\"close\", () => reject(new Error(\"connection closed before end frame\")));\n });\n const value = await extractSnapshotTar(req.cwd, tarPath);\n writeFrame(socket, { t: \"result\", value });\n } catch (err) {\n sendError(socket, err);\n } finally {\n await rm(staging, { recursive: true, force: true }).catch(() => undefined);\n socket.end();\n }\n}\n\nasync function runReadFile(\n socket: Socket,\n req: Extract<WorkbenchRequest, { op: \"readFile\" }>,\n): Promise<void> {\n try {\n const content = await readFile(req.path);\n for (let offset = 0; offset < content.length; offset += TAR_CHUNK_BYTES) {\n writeFrame(socket, {\n t: \"data\",\n d: content.subarray(offset, offset + TAR_CHUNK_BYTES).toString(\"base64\"),\n });\n }\n writeFrame(socket, { t: \"end\" });\n } catch (err) {\n sendError(socket, err);\n }\n socket.end();\n}\n\nasync function runStat(\n socket: Socket,\n req: Extract<WorkbenchRequest, { op: \"stat\" }>,\n): Promise<void> {\n try {\n const s = await stat(req.path);\n writeFrame(socket, {\n t: \"stat\",\n exists: true,\n isFile: s.isFile(),\n isDirectory: s.isDirectory(),\n size: s.size,\n mtimeMs: s.mtimeMs,\n });\n } catch (err) {\n if (errCode(err) === \"ENOENT\") {\n writeFrame(socket, {\n t: \"stat\",\n exists: false,\n isFile: false,\n isDirectory: false,\n size: 0,\n mtimeMs: 0,\n });\n } else {\n sendError(socket, err);\n }\n }\n socket.end();\n}\n\nasync function runReaddir(\n socket: Socket,\n req: Extract<WorkbenchRequest, { op: \"readdir\" }>,\n): Promise<void> {\n try {\n writeFrame(socket, { t: \"entries\", names: await readdir(req.path) });\n } catch (err) {\n sendError(socket, err);\n }\n socket.end();\n}\n"],"mappings":";;;;;;;;;;;;;AAYA,SAAS,aAAgC;AACzC,SAAS,kBAAkB,yBAAyB;AACpD,SAAS,SAAS,SAAS,UAAU,IAAI,YAAY;AACrD,SAAS,oBAAiC;AAC1C,SAAS,cAAc;AACvB,SAAS,YAAY;AAYrB,IAAM,kBAAkB,KAAK;AAa7B,SAAS,QAAQ,KAAkC;AACjD,SAAO,OAAQ,KAA4B,SAAS,WAC/C,IAAyB,OAC1B;AACN;AAEA,SAAS,UAAU,QAAgB,KAAoB;AACrD,QAAM,QAAwB;AAAA,IAC5B,GAAG;AAAA,IACH,SAAS,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAAA,IACxD,GAAI,QAAQ,GAAG,IAAI,EAAE,MAAM,QAAQ,GAAG,EAAE,IAAI,CAAC;AAAA,EAC/C;AACA,aAAW,QAAQ,KAAK;AAC1B;AAIA,SAAS,UAAU,WAAuD;AACxE,SAAO,YAAY,EAAE,GAAG,QAAQ,KAAK,GAAG,UAAU,IAAI,EAAE,GAAG,QAAQ,IAAI;AACzE;AAOA,IAAM,YAAN,MAAgB;AAAA,EACN,UAA4B,CAAC;AAAA,EAC7B,UAAoD;AAAA,EAE5D,KAAK,OAA6B;AAChC,QAAI,KAAK,QAAS,MAAK,QAAQ,KAAK;AAAA,QAC/B,MAAK,QAAQ,KAAK,KAAK;AAAA,EAC9B;AAAA,EAEA,WAAW,SAAgD;AACzD,SAAK,UAAU;AACf,eAAW,SAAS,KAAK,QAAQ,OAAO,CAAC,EAAG,SAAQ,KAAK;AAAA,EAC3D;AACF;AAEA,eAAsB,qBACpB,MACgC;AAChC,QAAM,SAAS,aAAa,CAAC,WAAW,iBAAiB,QAAQ,IAAI,CAAC;AACtE,QAAM,IAAI,QAAc,CAAC,SAAS,WAAW;AAC3C,WAAO,KAAK,SAAS,MAAM;AAC3B,WAAO,OAAO,KAAK,MAAM,aAAa,MAAM,QAAQ,CAAC;AAAA,EACvD,CAAC;AACD,QAAM,UAAU,OAAO,QAAQ;AAC/B,QAAM,OAAO,OAAO,YAAY,YAAY,UAAU,QAAQ,OAAO,KAAK;AAC1E,SAAO;AAAA,IACL;AAAA,IACA,OAAO,MACL,IAAI,QAAc,CAAC,YAAY;AAC7B,aAAO,MAAM,MAAM,QAAQ,CAAC;AAAA,IAC9B,CAAC;AAAA,EACL;AACF;AAEA,SAAS,iBAAiB,QAAgB,MAAoC;AAC5E,SAAO,GAAG,SAAS,MAAM,MAAS;AAClC,QAAM,OAAO,IAAI,UAAU;AAC3B,MAAI,aAAa;AACjB,QAAM,SAAS,IAAI,YAAY,CAAC,UAAU;AACxC,QAAI,YAAY;AACd,WAAK,KAAK,KAAkC;AAC5C;AAAA,IACF;AACA,iBAAa;AACb,aAAS,QAAQ,OAAsC,MAAM,IAAI;AAAA,EACnE,CAAC;AACD,SAAO,GAAG,QAAQ,CAAC,UAAkB,OAAO,KAAK,KAAK,CAAC;AACzD;AAEA,SAAS,SACP,QACA,KACA,MACA,MACM;AACN,MAAI,CAAC,OAAO,OAAO,QAAQ,YAAY,CAAC,qBAAqB,IAAI,SAAS,IAAI,KAAK,KAAK,GAAG;AACzF,eAAW,QAAQ,EAAE,GAAG,SAAS,SAAS,gBAAgB,MAAM,eAAe,CAAC;AAChF,WAAO,QAAQ;AACf;AAAA,EACF;AACA,UAAQ,IAAI,IAAI;AAAA,IACd,KAAK;AACH,iBAAW,QAAQ,EAAE,GAAG,QAAQ,SAAS,KAAK,QAAQ,CAAC;AACvD,aAAO,IAAI;AACX;AAAA,IACF,KAAK;AACH,cAAQ,QAAQ,KAAK,IAAI;AACzB;AAAA,IACF,KAAK;AACH,WAAK,OAAO,QAAQ,KAAK,IAAI;AAC7B;AAAA,IACF,KAAK;AACH,WAAK,iBAAiB,QAAQ,GAAG;AACjC;AAAA,IACF,KAAK;AACH,WAAK,mBAAmB,QAAQ,KAAK,IAAI;AACzC;AAAA,IACF,KAAK;AACH,WAAK,YAAY,QAAQ,GAAG;AAC5B;AAAA,IACF,KAAK;AACH,WAAK,QAAQ,QAAQ,GAAG;AACxB;AAAA,IACF,KAAK;AACH,WAAK,WAAW,QAAQ,GAAG;AAC3B;AAAA,IACF;AACE,iBAAW,QAAQ,EAAE,GAAG,SAAS,SAAS,cAAc,MAAM,cAAc,CAAC;AAC7E,aAAO,IAAI;AAAA,EACf;AACF;AAEA,SAAS,QACP,QACA,KACA,MACM;AACN,MAAI;AACJ,MAAI;AAGF,UAAM,CAAC,UAAU,GAAG,QAAQ,IAAI,IAAI,QAAQ,CAAC;AAC7C,YAAQ,WACJ,MAAM,UAAU,UAAU;AAAA,MACxB,KAAK,IAAI;AAAA,MACT,OAAO,CAAC,UAAU,QAAQ,MAAM;AAAA,MAChC,UAAU;AAAA,MACV,KAAK,UAAU,IAAI,GAAG;AAAA,IACxB,CAAC,IACD,MAAM,MAAM,CAAC,MAAM,IAAI,WAAW,EAAE,GAAG;AAAA,MACrC,KAAK,IAAI;AAAA,MACT,OAAO,CAAC,UAAU,QAAQ,MAAM;AAAA,MAChC,UAAU;AAAA,MACV,KAAK,UAAU,IAAI,GAAG;AAAA,IACxB,CAAC;AAAA,EACP,SAAS,KAAK;AACZ,cAAU,QAAQ,GAAG;AACrB,WAAO,IAAI;AACX;AAAA,EACF;AAEA,MAAI,UAAU;AACd,OAAK,WAAW,CAAC,UAAU;AACzB,QAAI,MAAM,MAAM,YAAY,MAAM,SAAS,gBAAgB,CAAC,SAAS;AACnE,WAAK,sBAAsB,KAAK;AAAA,IAClC;AAAA,EACF,CAAC;AACD,QAAM,QAAQ,GAAG,QAAQ,CAAC,UAAkB;AAC1C,eAAW,QAAQ,EAAE,GAAG,OAAO,GAAG,UAAU,GAAG,MAAM,SAAS,QAAQ,EAAE,CAAC;AAAA,EAC3E,CAAC;AACD,QAAM,QAAQ,GAAG,QAAQ,CAAC,UAAkB;AAC1C,eAAW,QAAQ,EAAE,GAAG,OAAO,GAAG,UAAU,GAAG,MAAM,SAAS,QAAQ,EAAE,CAAC;AAAA,EAC3E,CAAC;AACD,QAAM,GAAG,SAAS,CAAC,MAAM,WAAW;AAClC,cAAU;AACV,eAAW,QAAQ,EAAE,GAAG,QAAQ,MAAM,OAAO,CAAC;AAC9C,WAAO,IAAI;AAAA,EACb,CAAC;AACD,QAAM,GAAG,SAAS,CAAC,QAAQ;AACzB,QAAI,QAAS;AACb,cAAU;AACV,cAAU,QAAQ,GAAG;AACrB,WAAO,IAAI;AAAA,EACb,CAAC;AAED,SAAO,GAAG,SAAS,MAAM;AACvB,QAAI,CAAC,QAAS,MAAK,sBAAsB,KAAK;AAAA,EAChD,CAAC;AACH;AAEA,eAAe,OACb,QACA,KACA,MACe;AACf,MAAI;AACJ,MAAI;AACF,UAAM,WAAW,MAAM,aAAa;AACpC,UAAM,SAAS,IAAI,MAAM,IAAI,MAAM;AAAA,MACjC,MAAM;AAAA,MACN,MAAM,IAAI;AAAA,MACV,MAAM,IAAI;AAAA,MACV,KAAK,IAAI;AAAA,MACT,KAAK,IAAI;AAAA,IACX,CAAC;AAAA,EACH,SAAS,KAAK;AACZ,cAAU,QAAQ,GAAG;AACrB,WAAO,IAAI;AACX;AAAA,EACF;AAEA,MAAI,SAAS;AACb,OAAK,WAAW,CAAC,UAAU;AACzB,QAAI;AACF,UAAI,MAAM,MAAM,WAAW,OAAO,MAAM,MAAM,UAAU;AACtD,YAAI,MAAM,OAAO,KAAK,MAAM,GAAG,QAAQ,EAAE,SAAS,MAAM,CAAC;AAAA,MAC3D,WACE,MAAM,MAAM,YACZ,OAAO,MAAM,SAAS,YACtB,OAAO,MAAM,SAAS,UACtB;AACA,YAAI,OAAO,MAAM,MAAM,MAAM,IAAI;AAAA,MACnC,WAAW,MAAM,MAAM,QAAQ;AAC7B,YAAI,KAAK,OAAO,MAAM,QAAQ,WAAW,MAAM,MAAM,MAAS;AAAA,MAChE;AAAA,IACF,QAAQ;AAAA,IAER;AAAA,EACF,CAAC;AACD,MAAI,OAAO,CAAC,SAAS;AACnB,eAAW,QAAQ,EAAE,GAAG,QAAQ,GAAG,OAAO,KAAK,MAAM,MAAM,EAAE,SAAS,QAAQ,EAAE,CAAC;AAAA,EACnF,CAAC;AACD,MAAI,OAAO,CAAC,UAAU;AACpB,aAAS;AACT,eAAW,QAAQ,EAAE,GAAG,QAAQ,MAAM,MAAM,UAAU,QAAQ,KAAK,CAAC;AACpE,WAAO,IAAI;AAAA,EACb,CAAC;AACD,SAAO,GAAG,SAAS,MAAM;AACvB,QAAI,CAAC,QAAQ;AACX,UAAI;AACF,YAAI,KAAK;AAAA,MACX,QAAQ;AAAA,MAER;AAAA,IACF;AAAA,EACF,CAAC;AACH;AAEA,eAAe,iBACb,QACA,KACe;AACf,MAAI;AACF,UAAM,SAAS,MAAM,iBAAiB,IAAI,GAAG;AAC7C,QAAI;AACF,iBAAW,QAAQ;AAAA,QACjB,GAAG;AAAA,QACH,WAAW,OAAO;AAAA,QAClB,WAAW,OAAO;AAAA,QAClB,eAAe,OAAO;AAAA,QACtB,YAAY,OAAO;AAAA,MACrB,CAAC;AACD,YAAM,IAAI,QAAc,CAAC,SAAS,WAAW;AAC3C,cAAM,SAAS,iBAAiB,OAAO,SAAS,EAAE,eAAe,gBAAgB,CAAC;AAClF,eAAO,GAAG,QAAQ,CAAC,UAAU;AAC3B,qBAAW,QAAQ,EAAE,GAAG,QAAQ,GAAG,OAAO,KAAK,KAAK,EAAE,SAAS,QAAQ,EAAE,CAAC;AAAA,QAC5E,CAAC;AACD,eAAO,GAAG,OAAO,MAAM,QAAQ,CAAC;AAChC,eAAO,GAAG,SAAS,MAAM;AACzB,eAAO,GAAG,SAAS,MAAM,OAAO,QAAQ,CAAC;AAAA,MAC3C,CAAC;AACD,iBAAW,QAAQ,EAAE,GAAG,MAAM,CAAC;AAAA,IACjC,UAAE;AACA,YAAM,OAAO,QAAQ;AAAA,IACvB;AAAA,EACF,SAAS,KAAK;AACZ,cAAU,QAAQ,GAAG;AAAA,EACvB;AACA,SAAO,IAAI;AACb;AAEA,eAAe,mBACb,QACA,KACA,MACe;AACf,QAAM,UAAU,MAAM,QAAQ,KAAK,OAAO,GAAG,6BAA6B,CAAC;AAC3E,QAAM,UAAU,KAAK,SAAS,iBAAiB;AAC/C,QAAM,MAAM,kBAAkB,OAAO;AACrC,MAAI;AACF,UAAM,IAAI,QAAc,CAAC,SAAS,WAAW;AAC3C,WAAK,WAAW,CAAC,UAAU;AACzB,YAAI,MAAM,MAAM,UAAU,OAAO,MAAM,MAAM,UAAU;AACrD,cAAI,MAAM,OAAO,KAAK,MAAM,GAAG,QAAQ,CAAC;AAAA,QAC1C,WAAW,MAAM,MAAM,OAAO;AAC5B,cAAI,IAAI,MAAM,QAAQ,CAAC;AAAA,QACzB;AAAA,MACF,CAAC;AACD,UAAI,GAAG,SAAS,MAAM;AACtB,aAAO,GAAG,SAAS,MAAM,OAAO,IAAI,MAAM,oCAAoC,CAAC,CAAC;AAAA,IAClF,CAAC;AACD,UAAM,QAAQ,MAAM,mBAAmB,IAAI,KAAK,OAAO;AACvD,eAAW,QAAQ,EAAE,GAAG,UAAU,MAAM,CAAC;AAAA,EAC3C,SAAS,KAAK;AACZ,cAAU,QAAQ,GAAG;AAAA,EACvB,UAAE;AACA,UAAM,GAAG,SAAS,EAAE,WAAW,MAAM,OAAO,KAAK,CAAC,EAAE,MAAM,MAAM,MAAS;AACzE,WAAO,IAAI;AAAA,EACb;AACF;AAEA,eAAe,YACb,QACA,KACe;AACf,MAAI;AACF,UAAM,UAAU,MAAM,SAAS,IAAI,IAAI;AACvC,aAAS,SAAS,GAAG,SAAS,QAAQ,QAAQ,UAAU,iBAAiB;AACvE,iBAAW,QAAQ;AAAA,QACjB,GAAG;AAAA,QACH,GAAG,QAAQ,SAAS,QAAQ,SAAS,eAAe,EAAE,SAAS,QAAQ;AAAA,MACzE,CAAC;AAAA,IACH;AACA,eAAW,QAAQ,EAAE,GAAG,MAAM,CAAC;AAAA,EACjC,SAAS,KAAK;AACZ,cAAU,QAAQ,GAAG;AAAA,EACvB;AACA,SAAO,IAAI;AACb;AAEA,eAAe,QACb,QACA,KACe;AACf,MAAI;AACF,UAAM,IAAI,MAAM,KAAK,IAAI,IAAI;AAC7B,eAAW,QAAQ;AAAA,MACjB,GAAG;AAAA,MACH,QAAQ;AAAA,MACR,QAAQ,EAAE,OAAO;AAAA,MACjB,aAAa,EAAE,YAAY;AAAA,MAC3B,MAAM,EAAE;AAAA,MACR,SAAS,EAAE;AAAA,IACb,CAAC;AAAA,EACH,SAAS,KAAK;AACZ,QAAI,QAAQ,GAAG,MAAM,UAAU;AAC7B,iBAAW,QAAQ;AAAA,QACjB,GAAG;AAAA,QACH,QAAQ;AAAA,QACR,QAAQ;AAAA,QACR,aAAa;AAAA,QACb,MAAM;AAAA,QACN,SAAS;AAAA,MACX,CAAC;AAAA,IACH,OAAO;AACL,gBAAU,QAAQ,GAAG;AAAA,IACvB;AAAA,EACF;AACA,SAAO,IAAI;AACb;AAEA,eAAe,WACb,QACA,KACe;AACf,MAAI;AACF,eAAW,QAAQ,EAAE,GAAG,WAAW,OAAO,MAAM,QAAQ,IAAI,IAAI,EAAE,CAAC;AAAA,EACrE,SAAS,KAAK;AACZ,cAAU,QAAQ,GAAG;AAAA,EACvB;AACA,SAAO,IAAI;AACb;","names":[]}