@hua-labs/tap 0.2.2 → 0.2.4

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.
@@ -4,7 +4,7 @@ import { resolve } from "path";
4
4
  import { pathToFileURL } from "url";
5
5
  import { timingSafeEqual } from "crypto";
6
6
  import { WebSocket, WebSocketServer } from "ws";
7
- var AUTH_QUERY_PARAM = "tap_token";
7
+ var AUTH_SUBPROTOCOL_PREFIX = "tap-auth-";
8
8
  var CLOSE_UNAUTHORIZED = 4401;
9
9
  var CLOSE_UPSTREAM_ERROR = 1013;
10
10
  function normalizeUrl(value) {
@@ -105,7 +105,9 @@ async function main() {
105
105
  const host = listen.hostname === "localhost" ? "127.0.0.1" : listen.hostname;
106
106
  const port = Number.parseInt(listen.port, 10);
107
107
  if (!Number.isFinite(port) || port <= 0) {
108
- throw new Error(`Gateway listen URL must include a valid port: ${options.listenUrl}`);
108
+ throw new Error(
109
+ `Gateway listen URL must include a valid port: ${options.listenUrl}`
110
+ );
109
111
  }
110
112
  const server = new WebSocketServer({
111
113
  host,
@@ -114,8 +116,14 @@ async function main() {
114
116
  perMessageDeflate: false
115
117
  });
116
118
  server.on("connection", (client, request) => {
119
+ const protocols = request.headers["sec-websocket-protocol"]?.split(",").map((s) => s.trim()) ?? [];
120
+ const authProtocol = protocols.find(
121
+ (p) => p.startsWith(AUTH_SUBPROTOCOL_PREFIX)
122
+ );
123
+ const subprotocolToken = authProtocol?.slice(AUTH_SUBPROTOCOL_PREFIX.length) ?? null;
117
124
  const requestUrl = new URL(request.url ?? "/", options.listenUrl);
118
- const presentedToken = requestUrl.searchParams.get(AUTH_QUERY_PARAM);
125
+ const queryToken = requestUrl.searchParams.get("tap_token");
126
+ const presentedToken = subprotocolToken ?? queryToken;
119
127
  if (!tokensMatch(presentedToken, options.token)) {
120
128
  closeSocket(client, CLOSE_UNAUTHORIZED, "Unauthorized");
121
129
  return;
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/bridges/codex-app-server-auth-gateway.ts"],"sourcesContent":["import type { IncomingMessage } from \"node:http\";\nimport { readFileSync } from \"node:fs\";\nimport { resolve } from \"node:path\";\nimport { pathToFileURL } from \"node:url\";\nimport { timingSafeEqual } from \"node:crypto\";\nimport { WebSocket, WebSocketServer, type RawData } from \"ws\";\n\nconst AUTH_QUERY_PARAM = \"tap_token\";\nconst CLOSE_UNAUTHORIZED = 4401;\nconst CLOSE_UPSTREAM_ERROR = 1013;\n\ninterface GatewayOptions {\n listenUrl: string;\n upstreamUrl: string;\n token: string;\n}\n\nfunction normalizeUrl(value: string): string {\n return value.replace(/\\/$/, \"\");\n}\n\nfunction closeSocket(\n socket: Pick<WebSocket, \"readyState\" | \"close\">,\n code: number,\n reason: string,\n): void {\n if (\n socket.readyState === WebSocket.CLOSING ||\n socket.readyState === WebSocket.CLOSED\n ) {\n return;\n }\n\n try {\n socket.close(code, reason);\n } catch {\n // Best-effort cleanup only.\n }\n}\n\nfunction readFlagValue(argv: string[], index: number, flag: string): string {\n const current = argv[index] ?? \"\";\n const eqIndex = current.indexOf(\"=\");\n if (eqIndex >= 0) {\n return current.slice(eqIndex + 1);\n }\n\n const next = argv[index + 1];\n if (!next || next.startsWith(\"--\")) {\n throw new Error(`Missing value for ${flag}`);\n }\n return next;\n}\n\nexport function buildGatewayOptions(argv: string[]): GatewayOptions {\n let listenUrl = process.env.TAP_GATEWAY_LISTEN_URL?.trim() || \"\";\n let upstreamUrl = process.env.TAP_GATEWAY_UPSTREAM_URL?.trim() || \"\";\n let tokenFile = process.env.TAP_GATEWAY_TOKEN_FILE?.trim() || \"\";\n let token = process.env.TAP_GATEWAY_TOKEN?.trim() || \"\";\n\n for (let index = 0; index < argv.length; index += 1) {\n const flag = argv[index] ?? \"\";\n const consumesNext = !flag.includes(\"=\");\n\n if (flag.startsWith(\"--listen-url\")) {\n listenUrl = readFlagValue(argv, index, \"--listen-url\").trim();\n if (consumesNext) index += 1;\n continue;\n }\n\n if (flag.startsWith(\"--upstream-url\")) {\n upstreamUrl = readFlagValue(argv, index, \"--upstream-url\").trim();\n if (consumesNext) index += 1;\n continue;\n }\n\n if (flag.startsWith(\"--token\")) {\n token = readFlagValue(argv, index, \"--token\").trim();\n if (consumesNext) index += 1;\n continue;\n }\n\n if (flag.startsWith(\"--token-file\")) {\n tokenFile = readFlagValue(argv, index, \"--token-file\").trim();\n if (consumesNext) index += 1;\n continue;\n }\n }\n\n if (tokenFile) {\n token = readFileSync(tokenFile, \"utf8\").trim();\n }\n\n if (!listenUrl) {\n throw new Error(\"Missing gateway listen URL\");\n }\n if (!upstreamUrl) {\n throw new Error(\"Missing gateway upstream URL\");\n }\n if (!token) {\n throw new Error(\"Missing gateway auth token\");\n }\n\n const listen = new URL(listenUrl);\n const upstream = new URL(upstreamUrl);\n if (!/^wss?:$/.test(listen.protocol)) {\n throw new Error(`Unsupported gateway listen protocol: ${listen.protocol}`);\n }\n if (!/^wss?:$/.test(upstream.protocol)) {\n throw new Error(\n `Unsupported gateway upstream protocol: ${upstream.protocol}`,\n );\n }\n\n return {\n listenUrl: normalizeUrl(listen.toString()),\n upstreamUrl: normalizeUrl(upstream.toString()),\n token,\n };\n}\n\nfunction tokensMatch(presentedToken: string | null, expectedToken: string): boolean {\n if (!presentedToken) {\n return false;\n }\n\n const presented = Buffer.from(presentedToken, \"utf8\");\n const expected = Buffer.from(expectedToken, \"utf8\");\n if (presented.length !== expected.length) {\n return false;\n }\n\n return timingSafeEqual(presented, expected);\n}\n\nasync function main(): Promise<void> {\n const options = buildGatewayOptions(process.argv.slice(2));\n const listen = new URL(options.listenUrl);\n const host = listen.hostname === \"localhost\" ? \"127.0.0.1\" : listen.hostname;\n const port = Number.parseInt(listen.port, 10);\n if (!Number.isFinite(port) || port <= 0) {\n throw new Error(`Gateway listen URL must include a valid port: ${options.listenUrl}`);\n }\n\n const server = new WebSocketServer({\n host,\n port,\n path: listen.pathname === \"/\" ? undefined : listen.pathname,\n perMessageDeflate: false,\n });\n\n server.on(\"connection\", (client: WebSocket, request: IncomingMessage) => {\n const requestUrl = new URL(request.url ?? \"/\", options.listenUrl);\n const presentedToken = requestUrl.searchParams.get(AUTH_QUERY_PARAM);\n if (!tokensMatch(presentedToken, options.token)) {\n closeSocket(client, CLOSE_UNAUTHORIZED, \"Unauthorized\");\n return;\n }\n\n const upstream = new WebSocket(options.upstreamUrl, {\n perMessageDeflate: false,\n });\n\n upstream.on(\"message\", (data: RawData, isBinary: boolean) => {\n if (client.readyState === WebSocket.OPEN) {\n client.send(data, { binary: isBinary });\n }\n });\n\n client.on(\"message\", (data: RawData, isBinary: boolean) => {\n if (upstream.readyState === WebSocket.OPEN) {\n upstream.send(data, { binary: isBinary });\n }\n });\n\n upstream.on(\"close\", (code: number, reasonBuffer: Buffer) => {\n const reason = reasonBuffer.toString() || \"Upstream closed\";\n closeSocket(client, code || 1000, reason);\n });\n\n client.on(\"close\", (code: number, reasonBuffer: Buffer) => {\n const reason = reasonBuffer.toString() || \"Client closed\";\n closeSocket(upstream, code || 1000, reason);\n });\n\n upstream.on(\"error\", (error: Error) => {\n console.error(`[auth-gateway] upstream error: ${String(error)}`);\n closeSocket(client, CLOSE_UPSTREAM_ERROR, \"Upstream unavailable\");\n closeSocket(upstream, CLOSE_UPSTREAM_ERROR, \"Upstream unavailable\");\n });\n\n client.on(\"error\", (error: Error) => {\n console.error(`[auth-gateway] client error: ${String(error)}`);\n closeSocket(upstream, 1011, \"Client error\");\n });\n });\n\n server.on(\"listening\", () => {\n console.log(\n `[auth-gateway] listening ${options.listenUrl} -> ${options.upstreamUrl}`,\n );\n });\n\n const shutdown = () => {\n server.close(() => {\n process.exit(0);\n });\n };\n\n process.on(\"SIGINT\", shutdown);\n process.on(\"SIGTERM\", shutdown);\n}\n\nfunction isDirectExecution(): boolean {\n const entry = process.argv[1];\n if (!entry) return false;\n return import.meta.url === pathToFileURL(resolve(entry)).href;\n}\n\nif (isDirectExecution()) {\n main().catch((error) => {\n console.error(\n error instanceof Error ? (error.stack ?? error.message) : String(error),\n );\n process.exit(1);\n });\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../src/bridges/codex-app-server-auth-gateway.ts"],"sourcesContent":["import type { IncomingMessage } from \"node:http\";\nimport { readFileSync } from \"node:fs\";\nimport { resolve } from \"node:path\";\nimport { pathToFileURL } from \"node:url\";\nimport { timingSafeEqual } from \"node:crypto\";\nimport { WebSocket, WebSocketServer, type RawData } from \"ws\";\n\nconst AUTH_SUBPROTOCOL_PREFIX = \"tap-auth-\";\nconst CLOSE_UNAUTHORIZED = 4401;\nconst CLOSE_UPSTREAM_ERROR = 1013;\n\ninterface GatewayOptions {\n listenUrl: string;\n upstreamUrl: string;\n token: string;\n}\n\nfunction normalizeUrl(value: string): string {\n return value.replace(/\\/$/, \"\");\n}\n\nfunction closeSocket(\n socket: Pick<WebSocket, \"readyState\" | \"close\">,\n code: number,\n reason: string,\n): void {\n if (\n socket.readyState === WebSocket.CLOSING ||\n socket.readyState === WebSocket.CLOSED\n ) {\n return;\n }\n\n try {\n socket.close(code, reason);\n } catch {\n // Best-effort cleanup only.\n }\n}\n\nfunction readFlagValue(argv: string[], index: number, flag: string): string {\n const current = argv[index] ?? \"\";\n const eqIndex = current.indexOf(\"=\");\n if (eqIndex >= 0) {\n return current.slice(eqIndex + 1);\n }\n\n const next = argv[index + 1];\n if (!next || next.startsWith(\"--\")) {\n throw new Error(`Missing value for ${flag}`);\n }\n return next;\n}\n\nexport function buildGatewayOptions(argv: string[]): GatewayOptions {\n let listenUrl = process.env.TAP_GATEWAY_LISTEN_URL?.trim() || \"\";\n let upstreamUrl = process.env.TAP_GATEWAY_UPSTREAM_URL?.trim() || \"\";\n let tokenFile = process.env.TAP_GATEWAY_TOKEN_FILE?.trim() || \"\";\n let token = process.env.TAP_GATEWAY_TOKEN?.trim() || \"\";\n\n for (let index = 0; index < argv.length; index += 1) {\n const flag = argv[index] ?? \"\";\n const consumesNext = !flag.includes(\"=\");\n\n if (flag.startsWith(\"--listen-url\")) {\n listenUrl = readFlagValue(argv, index, \"--listen-url\").trim();\n if (consumesNext) index += 1;\n continue;\n }\n\n if (flag.startsWith(\"--upstream-url\")) {\n upstreamUrl = readFlagValue(argv, index, \"--upstream-url\").trim();\n if (consumesNext) index += 1;\n continue;\n }\n\n if (flag.startsWith(\"--token\")) {\n token = readFlagValue(argv, index, \"--token\").trim();\n if (consumesNext) index += 1;\n continue;\n }\n\n if (flag.startsWith(\"--token-file\")) {\n tokenFile = readFlagValue(argv, index, \"--token-file\").trim();\n if (consumesNext) index += 1;\n continue;\n }\n }\n\n if (tokenFile) {\n token = readFileSync(tokenFile, \"utf8\").trim();\n }\n\n if (!listenUrl) {\n throw new Error(\"Missing gateway listen URL\");\n }\n if (!upstreamUrl) {\n throw new Error(\"Missing gateway upstream URL\");\n }\n if (!token) {\n throw new Error(\"Missing gateway auth token\");\n }\n\n const listen = new URL(listenUrl);\n const upstream = new URL(upstreamUrl);\n if (!/^wss?:$/.test(listen.protocol)) {\n throw new Error(`Unsupported gateway listen protocol: ${listen.protocol}`);\n }\n if (!/^wss?:$/.test(upstream.protocol)) {\n throw new Error(\n `Unsupported gateway upstream protocol: ${upstream.protocol}`,\n );\n }\n\n return {\n listenUrl: normalizeUrl(listen.toString()),\n upstreamUrl: normalizeUrl(upstream.toString()),\n token,\n };\n}\n\nfunction tokensMatch(\n presentedToken: string | null,\n expectedToken: string,\n): boolean {\n if (!presentedToken) {\n return false;\n }\n\n const presented = Buffer.from(presentedToken, \"utf8\");\n const expected = Buffer.from(expectedToken, \"utf8\");\n if (presented.length !== expected.length) {\n return false;\n }\n\n return timingSafeEqual(presented, expected);\n}\n\nasync function main(): Promise<void> {\n const options = buildGatewayOptions(process.argv.slice(2));\n const listen = new URL(options.listenUrl);\n const host = listen.hostname === \"localhost\" ? \"127.0.0.1\" : listen.hostname;\n const port = Number.parseInt(listen.port, 10);\n if (!Number.isFinite(port) || port <= 0) {\n throw new Error(\n `Gateway listen URL must include a valid port: ${options.listenUrl}`,\n );\n }\n\n const server = new WebSocketServer({\n host,\n port,\n path: listen.pathname === \"/\" ? undefined : listen.pathname,\n perMessageDeflate: false,\n });\n\n server.on(\"connection\", (client: WebSocket, request: IncomingMessage) => {\n // Extract token from Sec-WebSocket-Protocol header (subprotocol auth).\n // Client sends: WebSocket(url, [\"tap-auth-<token>\"])\n // Falls back to query param for backward compatibility during migration.\n const protocols =\n request.headers[\"sec-websocket-protocol\"]\n ?.split(\",\")\n .map((s) => s.trim()) ?? [];\n const authProtocol = protocols.find((p) =>\n p.startsWith(AUTH_SUBPROTOCOL_PREFIX),\n );\n const subprotocolToken =\n authProtocol?.slice(AUTH_SUBPROTOCOL_PREFIX.length) ?? null;\n\n // Legacy fallback: query param (will be removed in future version)\n const requestUrl = new URL(request.url ?? \"/\", options.listenUrl);\n const queryToken = requestUrl.searchParams.get(\"tap_token\");\n\n const presentedToken = subprotocolToken ?? queryToken;\n if (!tokensMatch(presentedToken, options.token)) {\n closeSocket(client, CLOSE_UNAUTHORIZED, \"Unauthorized\");\n return;\n }\n\n const upstream = new WebSocket(options.upstreamUrl, {\n perMessageDeflate: false,\n });\n\n upstream.on(\"message\", (data: RawData, isBinary: boolean) => {\n if (client.readyState === WebSocket.OPEN) {\n client.send(data, { binary: isBinary });\n }\n });\n\n client.on(\"message\", (data: RawData, isBinary: boolean) => {\n if (upstream.readyState === WebSocket.OPEN) {\n upstream.send(data, { binary: isBinary });\n }\n });\n\n upstream.on(\"close\", (code: number, reasonBuffer: Buffer) => {\n const reason = reasonBuffer.toString() || \"Upstream closed\";\n closeSocket(client, code || 1000, reason);\n });\n\n client.on(\"close\", (code: number, reasonBuffer: Buffer) => {\n const reason = reasonBuffer.toString() || \"Client closed\";\n closeSocket(upstream, code || 1000, reason);\n });\n\n upstream.on(\"error\", (error: Error) => {\n console.error(`[auth-gateway] upstream error: ${String(error)}`);\n closeSocket(client, CLOSE_UPSTREAM_ERROR, \"Upstream unavailable\");\n closeSocket(upstream, CLOSE_UPSTREAM_ERROR, \"Upstream unavailable\");\n });\n\n client.on(\"error\", (error: Error) => {\n console.error(`[auth-gateway] client error: ${String(error)}`);\n closeSocket(upstream, 1011, \"Client error\");\n });\n });\n\n server.on(\"listening\", () => {\n console.log(\n `[auth-gateway] listening ${options.listenUrl} -> ${options.upstreamUrl}`,\n );\n });\n\n const shutdown = () => {\n server.close(() => {\n process.exit(0);\n });\n };\n\n process.on(\"SIGINT\", shutdown);\n process.on(\"SIGTERM\", shutdown);\n}\n\nfunction isDirectExecution(): boolean {\n const entry = process.argv[1];\n if (!entry) return false;\n return import.meta.url === pathToFileURL(resolve(entry)).href;\n}\n\nif (isDirectExecution()) {\n main().catch((error) => {\n console.error(\n error instanceof Error ? (error.stack ?? error.message) : String(error),\n );\n process.exit(1);\n });\n}\n"],"mappings":"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","names":[]}
@@ -14,6 +14,7 @@ interface Options {
14
14
  waitAfterDispatchSeconds: number;
15
15
  appServerUrl: string;
16
16
  connectAppServerUrl: string;
17
+ gatewayToken: string | null;
17
18
  gatewayTokenFile: string | null;
18
19
  busyMode: BusyMode;
19
20
  threadId: string | null;
@@ -16,7 +16,7 @@ import { isAbsolute, join, resolve } from "path";
16
16
  import { pathToFileURL } from "url";
17
17
  var DEFAULT_AGENT = String.fromCharCode(50728);
18
18
  var DEFAULT_APP_SERVER_URL = "ws://127.0.0.1:4501";
19
- var APP_SERVER_AUTH_QUERY_PARAM = "tap_token";
19
+ var AUTH_SUBPROTOCOL_PREFIX = "tap-auth-";
20
20
  var PLACEHOLDER_AGENT_VALUES = /* @__PURE__ */ new Set([
21
21
  "unknown",
22
22
  "unnamed",
@@ -316,11 +316,6 @@ function persistAgentName(stateDir, agentName) {
316
316
  writeFileSync(join(stateDir, "agent-name.txt"), `${agentName}
317
317
  `, "utf8");
318
318
  }
319
- function buildProtectedAppServerUrl(appServerUrl, token) {
320
- const url = new URL(appServerUrl);
321
- url.searchParams.set(APP_SERVER_AUTH_QUERY_PARAM, token);
322
- return url.toString().replace(/\/(?=\?|$)/, "");
323
- }
324
319
  function readGatewayTokenFile(tokenFile) {
325
320
  const token = readFileSync(tokenFile, "utf8").trim();
326
321
  if (!token) {
@@ -712,6 +707,7 @@ async function readSocketData(data) {
712
707
  var AppServerClient = class {
713
708
  socket = null;
714
709
  url;
710
+ gatewayToken;
715
711
  logger;
716
712
  nextId = 1;
717
713
  pending = /* @__PURE__ */ new Map();
@@ -725,15 +721,20 @@ var AppServerClient = class {
725
721
  lastError = null;
726
722
  lastSuccessfulAppServerAt = null;
727
723
  lastSuccessfulAppServerMethod = null;
728
- constructor(url, logger) {
724
+ constructor(url, logger, gatewayToken) {
729
725
  this.url = url;
730
726
  this.logger = logger;
727
+ this.gatewayToken = gatewayToken ?? null;
731
728
  }
732
729
  async connect() {
733
730
  if (this.connected && this.socket?.readyState === WebSocket.OPEN) {
734
731
  return;
735
732
  }
736
- this.socket = new WebSocket(this.url);
733
+ const wsOptions = {};
734
+ if (this.gatewayToken) {
735
+ wsOptions.protocols = [`${AUTH_SUBPROTOCOL_PREFIX}${this.gatewayToken}`];
736
+ }
737
+ this.socket = new WebSocket(this.url, wsOptions);
737
738
  await new Promise((resolvePromise, rejectPromise) => {
738
739
  let settled = false;
739
740
  const resolveOnce = () => {
@@ -1219,10 +1220,8 @@ function buildOptions(argv) {
1219
1220
  runOnce: parsed.runOnce,
1220
1221
  waitAfterDispatchSeconds: parsed.waitAfterDispatchSeconds ?? 0,
1221
1222
  appServerUrl,
1222
- connectAppServerUrl: gatewayTokenFile ? buildProtectedAppServerUrl(
1223
- appServerUrl,
1224
- readGatewayTokenFile(gatewayTokenFile)
1225
- ) : appServerUrl,
1223
+ connectAppServerUrl: appServerUrl,
1224
+ gatewayToken: gatewayTokenFile ? readGatewayTokenFile(gatewayTokenFile) : null,
1226
1225
  gatewayTokenFile,
1227
1226
  busyMode: parsed.busyMode ?? "steer",
1228
1227
  threadId: parsed.threadId?.trim() || null,
@@ -1267,7 +1266,11 @@ async function main() {
1267
1266
  try {
1268
1267
  if (!options.dryRun) {
1269
1268
  if (!client || !client.connected) {
1270
- client = new AppServerClient(options.connectAppServerUrl, logStatus);
1269
+ client = new AppServerClient(
1270
+ options.connectAppServerUrl,
1271
+ logStatus,
1272
+ options.gatewayToken
1273
+ );
1271
1274
  await client.connect();
1272
1275
  const threadId = await client.ensureThread(
1273
1276
  options.threadId,
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/bridges/codex-app-server-bridge.ts","../../../../scripts/codex-app-server-bridge.ts"],"sourcesContent":["import { pathToFileURL } from \"node:url\";\nimport { resolve } from \"node:path\";\nimport { main } from \"../../../../scripts/codex-app-server-bridge.js\";\n\nexport * from \"../../../../scripts/codex-app-server-bridge.js\";\n\nfunction isDirectExecution(): boolean {\n const entry = process.argv[1];\n if (!entry) return false;\n return import.meta.url === pathToFileURL(resolve(entry)).href;\n}\n\nif (isDirectExecution()) {\n main().catch((error) => {\n console.error(\n error instanceof Error ? (error.stack ?? error.message) : String(error),\n );\n process.exitCode = 1;\n });\n}\n","#!/usr/bin/env node --experimental-strip-types\n\nimport { createHash } from \"crypto\";\nimport {\n existsSync,\n mkdirSync,\n readdirSync,\n readFileSync,\n statSync,\n writeFileSync,\n} from \"fs\";\nimport { isAbsolute, join, resolve } from \"path\";\nimport { pathToFileURL } from \"url\";\n\ntype BusyMode = \"wait\" | \"steer\";\n\ninterface Options {\n repoRoot: string;\n commsDir: string;\n agentId: string;\n agentName: string;\n stateDir: string;\n pollSeconds: number;\n reconnectSeconds: number;\n messageLookbackMinutes: number;\n processExistingMessages: boolean;\n dryRun: boolean;\n runOnce: boolean;\n waitAfterDispatchSeconds: number;\n appServerUrl: string;\n connectAppServerUrl: string;\n gatewayTokenFile: string | null;\n busyMode: BusyMode;\n threadId: string | null;\n ephemeral: boolean;\n}\n\ninterface InboxRoute {\n sender: string;\n recipient: string;\n subject: string;\n}\n\ninterface Candidate {\n markerId: string;\n filePath: string;\n fileName: string;\n sender: string;\n recipient: string;\n subject: string;\n body: string;\n mtimeMs: number;\n}\n\ninterface ThreadStateRecord {\n threadId: string;\n updatedAt: string;\n appServerUrl: string;\n ephemeral: boolean;\n}\n\ninterface HeartbeatRecord {\n pid: number;\n agent: string;\n updatedAt: string;\n pollSeconds: number;\n appServerUrl: string;\n connected: boolean;\n initialized: boolean;\n threadId: string | null;\n activeTurnId: string | null;\n lastTurnStatus: string | null;\n lastNotificationMethod: string | null;\n lastNotificationAt: string | null;\n lastError: string | null;\n lastSuccessfulAppServerAt: string | null;\n lastSuccessfulAppServerMethod: string | null;\n consecutiveFailureCount: number;\n busyMode: BusyMode;\n}\n\ninterface BridgeHealthState {\n consecutiveFailureCount: number;\n}\n\nexport interface HeadlessWarmupClient {\n activeTurnId: string | null;\n lastTurnStatus: string | null;\n startTurn(inputText: string): Promise<string | null>;\n refreshCurrentThreadState(): Promise<void>;\n}\n\ninterface RequestRecord {\n jsonrpc: \"2.0\";\n id: number;\n method: string;\n params: unknown;\n}\n\ninterface HeartbeatStoreRecord {\n id?: string;\n agent?: string;\n}\n\ntype HeartbeatStore = Record<string, HeartbeatStoreRecord>;\n\ninterface JsonRpcResponse {\n id?: number;\n result?: any;\n error?: {\n code?: number;\n message?: string;\n data?: unknown;\n };\n method?: string;\n params?: any;\n}\n\nconst DEFAULT_AGENT = String.fromCharCode(0xc628);\nconst DEFAULT_APP_SERVER_URL = \"ws://127.0.0.1:4501\";\nconst APP_SERVER_AUTH_QUERY_PARAM = \"tap_token\";\nconst PLACEHOLDER_AGENT_VALUES = new Set([\n \"unknown\",\n \"unnamed\",\n \"<set-per-session>\",\n]);\nexport const HEADLESS_WARMUP_PROMPT = [\n \"You are a tap worker agent connected via the tap-comms inbox.\",\n \"This is a one-time warmup turn for headless bridge startup.\",\n \"Do not take any external actions.\",\n \"Reply briefly, then wait for future inbox instructions.\",\n].join(\" \");\nconst HEADLESS_WARMUP_TIMEOUT_MS = 30_000;\nconst TURN_COMPLETION_POLL_MS = 250;\nconst TURN_COMPLETION_REFRESH_MS = 1_000;\n\nfunction printHelp(): void {\n console.log(`Codex App Server bridge\n\nUsage:\n node --experimental-strip-types scripts/codex-app-server-bridge.ts [options]\n\nOptions:\n --repo-root=<path>\n --comms-dir=<path>\n --agent-name=<name>\n --state-dir=<path>\n --poll-seconds=<n>\n --reconnect-seconds=<n>\n --message-lookback-minutes=<n>\n --process-existing-messages\n --dry-run\n --run-once\n --wait-after-dispatch-seconds=<n>\n --app-server-url=<ws-url>\n --gateway-token-file=<path>\n --busy-mode=wait|steer\n --thread-id=<id>\n --ephemeral\n --help\n`);\n}\n\nfunction parseNumber(value: string, flag: string): number {\n const parsed = Number(value);\n if (!Number.isFinite(parsed) || parsed < 0) {\n throw new Error(`Invalid ${flag}: ${value}`);\n }\n return parsed;\n}\n\nfunction readFlagValue(argv: string[], index: number, flag: string): string {\n const current = argv[index];\n const eqIndex = current.indexOf(\"=\");\n if (eqIndex >= 0) {\n return current.slice(eqIndex + 1);\n }\n\n const next = argv[index + 1];\n if (!next || next.startsWith(\"--\")) {\n throw new Error(`Missing value for ${flag}`);\n }\n return next;\n}\n\nfunction parseArgs(argv: string[]): {\n repoRoot?: string;\n commsDir?: string;\n agentName?: string;\n stateDir?: string;\n pollSeconds?: number;\n reconnectSeconds?: number;\n messageLookbackMinutes?: number;\n processExistingMessages: boolean;\n dryRun: boolean;\n runOnce: boolean;\n waitAfterDispatchSeconds?: number;\n appServerUrl?: string;\n gatewayTokenFile?: string;\n busyMode?: BusyMode;\n threadId?: string;\n ephemeral: boolean;\n} {\n const parsed = {\n processExistingMessages: false,\n dryRun: false,\n runOnce: false,\n ephemeral: false,\n } as {\n repoRoot?: string;\n commsDir?: string;\n agentName?: string;\n stateDir?: string;\n pollSeconds?: number;\n reconnectSeconds?: number;\n messageLookbackMinutes?: number;\n processExistingMessages: boolean;\n dryRun: boolean;\n runOnce: boolean;\n waitAfterDispatchSeconds?: number;\n appServerUrl?: string;\n gatewayTokenFile?: string;\n busyMode?: BusyMode;\n threadId?: string;\n ephemeral: boolean;\n };\n\n for (let index = 0; index < argv.length; index += 1) {\n const flag = argv[index];\n const consumesNext = !flag.includes(\"=\");\n\n if (flag === \"--help\") {\n printHelp();\n process.exit(0);\n }\n\n if (flag === \"--process-existing-messages\") {\n parsed.processExistingMessages = true;\n continue;\n }\n\n if (flag === \"--dry-run\") {\n parsed.dryRun = true;\n continue;\n }\n\n if (flag === \"--run-once\") {\n parsed.runOnce = true;\n continue;\n }\n\n if (flag === \"--ephemeral\") {\n parsed.ephemeral = true;\n continue;\n }\n\n if (flag.startsWith(\"--repo-root\")) {\n parsed.repoRoot = readFlagValue(argv, index, \"--repo-root\");\n if (consumesNext) {\n index += 1;\n }\n continue;\n }\n\n if (flag.startsWith(\"--comms-dir\")) {\n parsed.commsDir = readFlagValue(argv, index, \"--comms-dir\");\n if (consumesNext) {\n index += 1;\n }\n continue;\n }\n\n if (flag.startsWith(\"--agent-name\")) {\n parsed.agentName = readFlagValue(argv, index, \"--agent-name\");\n if (consumesNext) {\n index += 1;\n }\n continue;\n }\n\n if (flag.startsWith(\"--state-dir\")) {\n parsed.stateDir = readFlagValue(argv, index, \"--state-dir\");\n if (consumesNext) {\n index += 1;\n }\n continue;\n }\n\n if (flag.startsWith(\"--poll-seconds\")) {\n parsed.pollSeconds = parseNumber(\n readFlagValue(argv, index, \"--poll-seconds\"),\n \"--poll-seconds\",\n );\n if (consumesNext) {\n index += 1;\n }\n continue;\n }\n\n if (flag.startsWith(\"--reconnect-seconds\")) {\n parsed.reconnectSeconds = parseNumber(\n readFlagValue(argv, index, \"--reconnect-seconds\"),\n \"--reconnect-seconds\",\n );\n if (consumesNext) {\n index += 1;\n }\n continue;\n }\n\n if (flag.startsWith(\"--message-lookback-minutes\")) {\n parsed.messageLookbackMinutes = parseNumber(\n readFlagValue(argv, index, \"--message-lookback-minutes\"),\n \"--message-lookback-minutes\",\n );\n if (consumesNext) {\n index += 1;\n }\n continue;\n }\n\n if (flag.startsWith(\"--app-server-url\")) {\n parsed.appServerUrl = readFlagValue(argv, index, \"--app-server-url\");\n if (consumesNext) {\n index += 1;\n }\n continue;\n }\n\n if (flag.startsWith(\"--gateway-token-file\")) {\n parsed.gatewayTokenFile = readFlagValue(\n argv,\n index,\n \"--gateway-token-file\",\n );\n if (consumesNext) {\n index += 1;\n }\n continue;\n }\n\n if (flag.startsWith(\"--wait-after-dispatch-seconds\")) {\n parsed.waitAfterDispatchSeconds = parseNumber(\n readFlagValue(argv, index, \"--wait-after-dispatch-seconds\"),\n \"--wait-after-dispatch-seconds\",\n );\n if (consumesNext) {\n index += 1;\n }\n continue;\n }\n\n if (flag.startsWith(\"--busy-mode\")) {\n const value = readFlagValue(argv, index, \"--busy-mode\");\n if (value !== \"wait\" && value !== \"steer\") {\n throw new Error(`Invalid --busy-mode: ${value}`);\n }\n parsed.busyMode = value;\n if (consumesNext) {\n index += 1;\n }\n continue;\n }\n\n if (flag.startsWith(\"--thread-id\")) {\n parsed.threadId = readFlagValue(argv, index, \"--thread-id\");\n if (consumesNext) {\n index += 1;\n }\n continue;\n }\n\n throw new Error(`Unknown argument: ${flag}`);\n }\n\n return parsed;\n}\n\nfunction timestamp(): string {\n return new Date().toISOString().replace(\"T\", \" \").replace(\"Z\", \" UTC\");\n}\n\nfunction logStatus(message: string): void {\n console.log(`[${timestamp()}] ${message}`);\n}\n\nfunction ensureDir(target: string): string {\n if (!existsSync(target)) {\n mkdirSync(target, { recursive: true });\n }\n return resolve(target);\n}\n\nfunction convertTapPath(input: string): string {\n const trimmed = input.trim().replace(/^[\"'`]+|[\"'`]+$/g, \"\");\n if (/^[A-Za-z]:\\\\/.test(trimmed)) {\n return trimmed;\n }\n\n const match = trimmed.match(/^\\/([A-Za-z])\\/(.*)$/);\n if (match) {\n return `${match[1].toUpperCase()}:\\\\${match[2].replace(/\\//g, \"\\\\\")}`;\n }\n\n return trimmed;\n}\n\nfunction resolveRepoRoot(explicit?: string): string {\n if (explicit) {\n return resolve(explicit);\n }\n\n return process.cwd();\n}\n\nfunction resolveCommsDir(repoRoot: string, explicit?: string): string {\n if (explicit) {\n return resolve(convertTapPath(explicit));\n }\n\n const tapConfigPath = join(repoRoot, \".tap-config\");\n if (!existsSync(tapConfigPath)) {\n throw new Error(\n \"Unable to resolve comms directory. Pass --comms-dir explicitly.\",\n );\n }\n\n const configText = readFileSync(tapConfigPath, \"utf8\");\n const match = configText.match(/^TAP_COMMS_DIR=\"?(.*?)\"?$/m);\n if (!match?.[1]) {\n throw new Error(\n \"Unable to resolve comms directory. Pass --comms-dir explicitly.\",\n );\n }\n\n return resolveTapConfigPath(repoRoot, match[1]);\n}\n\nfunction resolvePreferredAgentName(requested?: string): string | null {\n if (requested?.trim()) {\n return requested.trim();\n }\n\n for (const envName of [\"TAP_AGENT_NAME\", \"CODEX_TAP_AGENT_NAME\"]) {\n const candidate = process.env[envName];\n if (candidate?.trim()) {\n return candidate.trim();\n }\n }\n\n return null;\n}\n\nfunction normalizeAgentToken(value?: string | null): string | null {\n const normalized = value?.trim();\n if (!normalized || PLACEHOLDER_AGENT_VALUES.has(normalized)) {\n return null;\n }\n\n return normalized;\n}\n\nexport function resolveAgentId(preferredAgentName?: string | null): string {\n return (\n normalizeAgentToken(process.env.TAP_AGENT_ID) ??\n normalizeAgentToken(preferredAgentName) ??\n \"unknown\"\n );\n}\n\nfunction sanitizeStateSegment(agentName: string): string {\n const normalized = agentName\n .trim()\n .replace(/[<>:\"/\\\\|?*\\x00-\\x1f]/g, \"-\")\n .replace(/[. ]+$/g, \"\");\n\n return normalized || \"agent\";\n}\n\nfunction buildDefaultStateDir(\n repoRoot: string,\n preferredAgentName?: string | null,\n): string {\n const suffix = preferredAgentName?.trim()\n ? `-${sanitizeStateSegment(preferredAgentName)}`\n : \"\";\n return resolve(join(repoRoot, \".tmp\", `codex-app-server-bridge${suffix}`));\n}\n\nfunction resolveStateDir(\n repoRoot: string,\n explicit?: string,\n preferredAgentName?: string | null,\n): string {\n const root = explicit\n ? resolve(explicit)\n : buildDefaultStateDir(repoRoot, preferredAgentName);\n\n ensureDir(root);\n ensureDir(join(root, \"processed\"));\n ensureDir(join(root, \"logs\"));\n return root;\n}\n\nfunction resolveAgentName(\n preferredAgentName: string | null,\n stateDir: string,\n): string {\n if (preferredAgentName?.trim()) {\n return preferredAgentName.trim();\n }\n\n const agentFile = join(stateDir, \"agent-name.txt\");\n if (existsSync(agentFile)) {\n const candidate = readFileSync(agentFile, \"utf8\").trim();\n if (candidate) {\n return candidate;\n }\n }\n\n return DEFAULT_AGENT;\n}\n\nfunction persistAgentName(stateDir: string, agentName: string): void {\n writeFileSync(join(stateDir, \"agent-name.txt\"), `${agentName}\\n`, \"utf8\");\n}\n\nfunction buildProtectedAppServerUrl(\n appServerUrl: string,\n token: string,\n): string {\n const url = new URL(appServerUrl);\n url.searchParams.set(APP_SERVER_AUTH_QUERY_PARAM, token);\n return url.toString().replace(/\\/(?=\\?|$)/, \"\");\n}\n\nfunction readGatewayTokenFile(tokenFile: string): string {\n const token = readFileSync(tokenFile, \"utf8\").trim();\n if (!token) {\n throw new Error(`Gateway token file is empty: ${tokenFile}`);\n }\n return token;\n}\n\nfunction resolveTapConfigPath(repoRoot: string, input: string): string {\n const converted = convertTapPath(input);\n return isAbsolute(converted)\n ? resolve(converted)\n : resolve(repoRoot, converted);\n}\n\nfunction readThreadState(stateDir: string): ThreadStateRecord | null {\n const threadPath = join(stateDir, \"thread.json\");\n if (!existsSync(threadPath)) {\n return null;\n }\n\n try {\n const parsed = JSON.parse(\n readFileSync(threadPath, \"utf8\"),\n ) as ThreadStateRecord;\n if (parsed.threadId) {\n return parsed;\n }\n } catch {\n return null;\n }\n\n return null;\n}\n\nfunction persistThreadState(\n stateDir: string,\n threadId: string,\n appServerUrl: string,\n ephemeral: boolean,\n): void {\n const payload: ThreadStateRecord = {\n threadId,\n updatedAt: new Date().toISOString(),\n appServerUrl,\n ephemeral,\n };\n writeFileSync(\n join(stateDir, \"thread.json\"),\n `${JSON.stringify(payload, null, 2)}\\n`,\n \"utf8\",\n );\n}\n\nfunction getGeneralInboxCutoff(\n stateDir: string,\n lookbackMinutes: number,\n processExistingMessages: boolean,\n): Date {\n if (processExistingMessages) {\n return new Date(0);\n }\n\n if (lookbackMinutes > 0) {\n return new Date(Date.now() - lookbackMinutes * 60_000);\n }\n\n const cutoffPath = join(stateDir, \"general-inbox-cutoff.txt\");\n if (existsSync(cutoffPath)) {\n try {\n return new Date(readFileSync(cutoffPath, \"utf8\").trim());\n } catch {\n return new Date();\n }\n }\n\n const cutoff = new Date();\n writeFileSync(cutoffPath, `${cutoff.toISOString()}\\n`, \"utf8\");\n return cutoff;\n}\n\nexport function recipientMatchesAgent(\n recipient: string,\n agentId: string,\n agentName: string,\n): boolean {\n const normalizedRecipient = recipient.trim();\n if (!normalizedRecipient) {\n return false;\n }\n\n return (\n normalizedRecipient === \"전체\" ||\n normalizedRecipient === \"all\" ||\n normalizedRecipient === agentId ||\n normalizedRecipient === agentName\n );\n}\n\nexport function isOwnMessageSender(\n sender: string,\n agentId: string,\n agentName: string,\n): boolean {\n const normalizedSender = sender.trim();\n if (!normalizedSender) {\n return false;\n }\n\n return normalizedSender === agentId || normalizedSender === agentName;\n}\n\nfunction getInboxRoute(fileName: string): InboxRoute {\n const stem = fileName.replace(/\\.md$/i, \"\");\n const parts = stem.split(\"-\");\n let offset = 0;\n if (parts[0] && /^\\d{8}$/.test(parts[0])) {\n offset = 1;\n }\n\n return {\n sender: parts[offset] ?? \"\",\n recipient: parts[offset + 1] ?? \"\",\n subject: parts.slice(offset + 2).join(\"-\"),\n };\n}\n\nfunction buildMarkerId(filePath: string, mtimeMs: number): string {\n return createHash(\"sha1\").update(`${filePath}|${mtimeMs}`).digest(\"hex\");\n}\n\nfunction getProcessedMarkerPath(stateDir: string, markerId: string): string {\n return join(stateDir, \"processed\", `${markerId}.done`);\n}\n\nfunction loadHeartbeats(commsDir: string): HeartbeatStore {\n try {\n return JSON.parse(readFileSync(join(commsDir, \"heartbeats.json\"), \"utf8\"));\n } catch {\n return {};\n }\n}\n\nfunction formatAgentLabel(\n agentIdOrName: string,\n displayName?: string | null,\n): string {\n const normalizedId = agentIdOrName.trim();\n const normalizedName = displayName?.trim();\n\n if (!normalizedId) {\n return normalizedName ?? agentIdOrName;\n }\n\n if (!normalizedName || normalizedName === normalizedId) {\n return normalizedId;\n }\n\n return `${normalizedName} [${normalizedId}]`;\n}\n\nexport function resolveAddressLabel(\n address: string,\n heartbeats: HeartbeatStore,\n): string {\n const normalized = address.trim();\n if (!normalized || normalized === \"전체\" || normalized === \"all\") {\n return address;\n }\n\n const direct = heartbeats[normalized];\n if (direct?.agent?.trim()) {\n return formatAgentLabel(normalized, direct.agent);\n }\n\n for (const [agentId, heartbeat] of Object.entries(heartbeats)) {\n if (heartbeat.agent?.trim() === normalized) {\n return formatAgentLabel(agentId, heartbeat.agent);\n }\n }\n\n return normalized;\n}\n\nexport function resolveCurrentAgentName(\n agentId: string,\n fallbackAgentName: string,\n heartbeats: HeartbeatStore,\n): string {\n const currentName = heartbeats[agentId]?.agent?.trim();\n if (currentName) {\n return currentName;\n }\n\n for (const heartbeat of Object.values(heartbeats)) {\n if (heartbeat.id?.trim() === agentId && heartbeat.agent?.trim()) {\n return heartbeat.agent.trim();\n }\n }\n\n return fallbackAgentName;\n}\n\nfunction refreshAgentIdentity(\n options: Options,\n heartbeats: HeartbeatStore,\n): string {\n const nextAgentName = resolveCurrentAgentName(\n options.agentId,\n options.agentName,\n heartbeats,\n );\n\n if (nextAgentName !== options.agentName) {\n options.agentName = nextAgentName;\n persistAgentName(options.stateDir, nextAgentName);\n }\n\n return nextAgentName;\n}\n\n// When running in headless reviewer mode, review-request files are handled\n// by the headless loop (engine/headless-loop.ts), not the generic bridge.\n// Skip them here to prevent race conditions.\nconst HEADLESS_SKIP_PATTERNS = [\n /리뷰\\s*요청/,\n /review[- ]?request/i,\n /재리뷰/,\n /re-?review/i,\n];\n\nfunction shouldSkipInHeadlessMode(fileName: string, body: string): boolean {\n if (process.env.TAP_HEADLESS !== \"true\") return false;\n const combined = `${fileName}\\n${body}`;\n return HEADLESS_SKIP_PATTERNS.some((p) => p.test(combined));\n}\n\nfunction collectCandidates(\n inboxDir: string,\n agentId: string,\n agentName: string,\n): Candidate[] {\n const entries = readdirSync(inboxDir, { withFileTypes: true })\n .filter(\n (entry) => entry.isFile() && entry.name.toLowerCase().endsWith(\".md\"),\n )\n .map((entry) => {\n const filePath = join(inboxDir, entry.name);\n const stats = statSync(filePath);\n return { entry, filePath, stats };\n })\n .sort((left, right) => left.stats.mtimeMs - right.stats.mtimeMs);\n\n const candidates: Candidate[] = [];\n for (const item of entries) {\n const route = getInboxRoute(item.entry.name);\n if (!recipientMatchesAgent(route.recipient, agentId, agentName)) {\n continue;\n }\n\n if (isOwnMessageSender(route.sender, agentId, agentName)) {\n continue;\n }\n\n const body = readFileSync(item.filePath, \"utf8\");\n\n // In headless mode, skip review-request files — handled by headless loop\n if (shouldSkipInHeadlessMode(item.entry.name, body)) {\n continue;\n }\n\n candidates.push({\n markerId: buildMarkerId(item.filePath, item.stats.mtimeMs),\n filePath: item.filePath,\n fileName: item.entry.name,\n sender: route.sender,\n recipient: route.recipient,\n subject: route.subject,\n body,\n mtimeMs: item.stats.mtimeMs,\n });\n }\n\n return candidates;\n}\n\nfunction getPendingCandidates(\n options: Options,\n cutoff: Date,\n): {\n heartbeats: HeartbeatStore;\n candidates: Candidate[];\n} {\n const inboxDir = join(options.commsDir, \"inbox\");\n if (!existsSync(inboxDir)) {\n throw new Error(`Inbox directory not found: ${inboxDir}`);\n }\n\n const heartbeats = loadHeartbeats(options.commsDir);\n const agentName = refreshAgentIdentity(options, heartbeats);\n const cutoffMs = cutoff.getTime();\n const candidates = collectCandidates(\n inboxDir,\n options.agentId,\n agentName,\n ).filter((candidate) => {\n if (candidate.mtimeMs < cutoffMs) {\n return false;\n }\n\n return !existsSync(\n getProcessedMarkerPath(options.stateDir, candidate.markerId),\n );\n });\n\n return { heartbeats, candidates };\n}\n\nexport function buildUserInput(\n candidate: Candidate,\n agentName: string,\n heartbeats: HeartbeatStore,\n): string {\n const sender = resolveAddressLabel(candidate.sender || \"unknown\", heartbeats);\n const recipient = resolveAddressLabel(\n candidate.recipient || agentName,\n heartbeats,\n );\n const subject = candidate.subject || \"(none)\";\n const body = candidate.body.trim();\n\n return [\n `Tap-comms inbox message for ${agentName}.`,\n `Sender: ${sender}`,\n `Recipient: ${recipient}`,\n `Subject: ${subject}`,\n `File: ${candidate.fileName}`,\n \"\",\n \"Message body:\",\n body || \"(empty)\",\n \"\",\n \"---\",\n \"Instructions: Read the message above and respond using the tap_reply tool.\",\n `Use tap_reply(to: \"${candidate.sender || \"unknown\"}\", subject: \"<your-subject>\", content: \"<your-response>\") to send your response.`,\n \"If the message is a review request, perform the review and reply with your findings.\",\n \"If the message is informational, acknowledge briefly via tap_reply.\",\n \"Do NOT respond with plain text only — you MUST use the tap_reply tool.\",\n ].join(\"\\n\");\n}\n\nfunction writeProcessedMarker(\n stateDir: string,\n candidate: Candidate,\n dispatchMode: \"start\" | \"steer\",\n threadId: string | null,\n turnId: string | null,\n): void {\n const payload = {\n requestFile: candidate.filePath,\n requestName: candidate.fileName,\n sender: candidate.sender,\n recipient: candidate.recipient,\n subject: candidate.subject,\n dispatchMode,\n threadId,\n turnId,\n markedAt: new Date().toISOString(),\n };\n writeFileSync(\n getProcessedMarkerPath(stateDir, candidate.markerId),\n `${JSON.stringify(payload, null, 2)}\\n`,\n \"utf8\",\n );\n}\n\nfunction writeLastDispatch(\n stateDir: string,\n candidate: Candidate,\n dispatchMode: \"start\" | \"steer\",\n threadId: string | null,\n turnId: string | null,\n): void {\n const payload = {\n requestFile: candidate.filePath,\n requestName: candidate.fileName,\n markerId: candidate.markerId,\n sender: candidate.sender,\n recipient: candidate.recipient,\n subject: candidate.subject,\n dispatchMode,\n threadId,\n turnId,\n dispatchedAt: new Date().toISOString(),\n };\n writeFileSync(\n join(stateDir, \"last-dispatch.json\"),\n `${JSON.stringify(payload, null, 2)}\\n`,\n \"utf8\",\n );\n}\n\nfunction formatJsonRpcError(error: JsonRpcResponse[\"error\"]): string {\n if (!error) {\n return \"Unknown App Server error\";\n }\n\n return JSON.stringify(\n {\n code: error.code,\n message: error.message,\n data: error.data,\n },\n null,\n 2,\n );\n}\n\nfunction delay(ms: number): Promise<void> {\n return new Promise((resolvePromise) => {\n setTimeout(resolvePromise, ms);\n });\n}\n\nexport async function waitForTurnCompletion(\n client: Pick<\n HeadlessWarmupClient,\n \"activeTurnId\" | \"lastTurnStatus\" | \"refreshCurrentThreadState\"\n >,\n turnId: string,\n timeoutMs: number,\n): Promise<string | null> {\n const deadline = Date.now() + timeoutMs;\n let nextRefreshAt = Date.now();\n\n while (Date.now() < deadline) {\n if (!client.activeTurnId || client.activeTurnId !== turnId) {\n return client.lastTurnStatus;\n }\n\n if (Date.now() >= nextRefreshAt) {\n await client.refreshCurrentThreadState().catch(() => undefined);\n if (!client.activeTurnId || client.activeTurnId !== turnId) {\n return client.lastTurnStatus;\n }\n nextRefreshAt = Date.now() + TURN_COMPLETION_REFRESH_MS;\n }\n\n await delay(\n Math.min(TURN_COMPLETION_POLL_MS, Math.max(deadline - Date.now(), 0)),\n );\n }\n\n await client.refreshCurrentThreadState().catch(() => undefined);\n if (!client.activeTurnId || client.activeTurnId !== turnId) {\n return client.lastTurnStatus;\n }\n\n throw new Error(`Timed out waiting for turn ${turnId} to complete`);\n}\n\nexport async function maybeBootstrapHeadlessTurn(\n options: Options,\n cutoff: Date,\n client: HeadlessWarmupClient,\n): Promise<boolean> {\n if (process.env.TAP_HEADLESS !== \"true\") {\n return false;\n }\n\n const { candidates } = getPendingCandidates(options, cutoff);\n if (\n candidates.length > 0 ||\n client.activeTurnId ||\n client.lastTurnStatus !== null\n ) {\n return false;\n }\n\n logStatus(\"headless cold-start: sending warmup turn\");\n const turnId = await client.startTurn(HEADLESS_WARMUP_PROMPT);\n if (!turnId) {\n throw new Error(\n \"Headless cold-start warmup failed: turn/start did not return a turn id. \" +\n \"Run: npx @hua-labs/tap doctor\",\n );\n }\n\n try {\n const status = await waitForTurnCompletion(\n client,\n turnId,\n HEADLESS_WARMUP_TIMEOUT_MS,\n );\n if (status !== \"completed\") {\n throw new Error(\n `turn ${turnId} finished with status ${status ?? \"unknown\"}`,\n );\n }\n\n logStatus(`headless cold-start warmup completed (${status})`);\n return true;\n } catch (error) {\n const reason = error instanceof Error ? error.message : String(error);\n throw new Error(\n `Headless cold-start warmup failed: ${reason}. ` +\n \"Run: npx @hua-labs/tap doctor\",\n );\n }\n}\n\nfunction shouldRetrySteerAsStart(error: unknown): boolean {\n if (!(error instanceof Error)) {\n return false;\n }\n\n const message = error.message.toLowerCase();\n return (\n message.includes(\"no active turn\") ||\n message.includes(\"expectedturnid\") ||\n (message.includes(\"turn/steer failed\") &&\n (message.includes(\"active turn\") || message.includes(\"not found\")))\n );\n}\n\nasync function readSocketData(data: unknown): Promise<string> {\n if (typeof data === \"string\") {\n return data;\n }\n\n if (data instanceof ArrayBuffer) {\n return Buffer.from(data).toString(\"utf8\");\n }\n\n if (ArrayBuffer.isView(data)) {\n return Buffer.from(data.buffer, data.byteOffset, data.byteLength).toString(\n \"utf8\",\n );\n }\n\n if (typeof Blob !== \"undefined\" && data instanceof Blob) {\n return await data.text();\n }\n\n return String(data);\n}\n\nclass AppServerClient {\n private socket: WebSocket | null = null;\n private readonly url: string;\n private readonly logger: (message: string) => void;\n private nextId = 1;\n private pending = new Map<\n number,\n {\n resolve: (value: any) => void;\n reject: (reason?: unknown) => void;\n method: string;\n }\n >();\n\n connected = false;\n initialized = false;\n threadId: string | null = null;\n activeTurnId: string | null = null;\n lastTurnStatus: string | null = null;\n lastNotificationMethod: string | null = null;\n lastNotificationAt: string | null = null;\n lastError: string | null = null;\n lastSuccessfulAppServerAt: string | null = null;\n lastSuccessfulAppServerMethod: string | null = null;\n\n constructor(url: string, logger: (message: string) => void) {\n this.url = url;\n this.logger = logger;\n }\n\n async connect(): Promise<void> {\n if (this.connected && this.socket?.readyState === WebSocket.OPEN) {\n return;\n }\n\n this.socket = new WebSocket(this.url);\n\n await new Promise<void>((resolvePromise, rejectPromise) => {\n let settled = false;\n\n const resolveOnce = () => {\n if (settled) {\n return;\n }\n settled = true;\n resolvePromise();\n };\n\n const rejectOnce = (error: Error) => {\n if (settled) {\n return;\n }\n settled = true;\n rejectPromise(error);\n };\n\n this.socket?.addEventListener(\n \"open\",\n () => {\n this.connected = true;\n resolveOnce();\n },\n { once: true },\n );\n\n this.socket?.addEventListener(\"error\", () => {\n const error = new Error(\n `Failed to connect to App Server at ${this.url}`,\n );\n this.lastError = error.message;\n rejectOnce(error);\n });\n\n this.socket?.addEventListener(\"close\", () => {\n this.connected = false;\n this.initialized = false;\n this.activeTurnId = null;\n this.rejectPending(new Error(\"App Server connection closed\"));\n });\n\n this.socket?.addEventListener(\"message\", (event) => {\n void this.handleMessage(event.data);\n });\n });\n\n await this.request(\"initialize\", {\n clientInfo: {\n name: \"tap-app-server-bridge\",\n title: \"tap app-server bridge\",\n version: \"0.1.0\",\n },\n capabilities: {\n experimentalApi: false,\n },\n });\n this.initialized = true;\n }\n\n async disconnect(): Promise<void> {\n if (!this.socket) {\n return;\n }\n\n this.socket.close();\n this.connected = false;\n this.initialized = false;\n this.socket = null;\n }\n\n async ensureThread(\n explicitThreadId: string | null,\n resumeThreadId: string | null,\n cwd: string,\n ephemeral: boolean,\n ): Promise<string> {\n if (explicitThreadId) {\n try {\n const resumeResponse = await this.request(\"thread/resume\", {\n threadId: explicitThreadId,\n persistExtendedHistory: false,\n });\n const resumedThreadId = resumeResponse?.thread?.id ?? explicitThreadId;\n await this.refreshThreadState(resumedThreadId);\n this.logger(\n `resumed thread ${resumedThreadId}${\n this.activeTurnId ? ` (active turn ${this.activeTurnId})` : \"\"\n }`,\n );\n return resumedThreadId;\n } catch (error) {\n this.logger(\n `thread resume failed for ${explicitThreadId}; starting a fresh thread (${String(error)})`,\n );\n }\n }\n\n const loadedThreadId = await this.findLoadedThread(cwd);\n if (loadedThreadId) {\n return loadedThreadId;\n }\n\n if (resumeThreadId) {\n try {\n const resumeResponse = await this.request(\"thread/resume\", {\n threadId: resumeThreadId,\n persistExtendedHistory: false,\n });\n const resumedThreadId = resumeResponse?.thread?.id ?? resumeThreadId;\n await this.refreshThreadState(resumedThreadId);\n this.logger(\n `resumed saved thread ${resumedThreadId}${\n this.activeTurnId ? ` (active turn ${this.activeTurnId})` : \"\"\n }`,\n );\n return resumedThreadId;\n } catch (error) {\n this.logger(\n `saved thread resume failed for ${resumeThreadId}; starting a fresh thread (${String(error)})`,\n );\n }\n }\n\n const startResponse = await this.request(\"thread/start\", {\n cwd,\n ephemeral,\n experimentalRawEvents: false,\n persistExtendedHistory: false,\n });\n\n const startedThreadId = startResponse?.thread?.id;\n if (!startedThreadId) {\n throw new Error(\"thread/start did not return a thread id\");\n }\n\n this.threadId = startedThreadId;\n this.activeTurnId = null;\n this.lastTurnStatus = null;\n this.logger(`started thread ${startedThreadId}`);\n return startedThreadId;\n }\n\n async findLoadedThread(cwd: string): Promise<string | null> {\n const response = await this.request(\"thread/loaded/list\", {\n limit: 20,\n });\n const threadIds = Array.isArray(response?.data)\n ? response.data.filter(\n (value: unknown): value is string => typeof value === \"string\",\n )\n : [];\n\n if (threadIds.length === 0) {\n return null;\n }\n\n const threads: Array<{\n id: string;\n cwd: string;\n updatedAt: number;\n statusType: string | null;\n thread: any;\n }> = [];\n\n for (const threadId of threadIds) {\n try {\n const threadResponse = await this.request(\"thread/read\", {\n threadId,\n includeTurns: true,\n });\n const thread = threadResponse?.thread;\n if (!thread?.id) {\n continue;\n }\n threads.push({\n id: thread.id,\n cwd: typeof thread.cwd === \"string\" ? thread.cwd : \"\",\n updatedAt:\n typeof thread.updatedAt === \"number\" ? thread.updatedAt : 0,\n statusType: thread.status?.type ?? null,\n thread,\n });\n } catch {\n continue;\n }\n }\n\n const matching = threads.filter((thread) => thread.cwd === cwd);\n const candidates = matching.length > 0 ? matching : threads;\n if (candidates.length === 0) {\n return null;\n }\n\n candidates.sort((left, right) => {\n const leftActive = left.statusType === \"active\" ? 1 : 0;\n const rightActive = right.statusType === \"active\" ? 1 : 0;\n if (leftActive !== rightActive) {\n return rightActive - leftActive;\n }\n return right.updatedAt - left.updatedAt;\n });\n\n const chosen = candidates[0];\n this.syncThreadStateFromThread(chosen.thread);\n this.logger(\n `attached to loaded thread ${chosen.id}${\n this.activeTurnId ? ` (active turn ${this.activeTurnId})` : \"\"\n }`,\n );\n return chosen.id;\n }\n\n async startTurn(inputText: string): Promise<string | null> {\n const threadId = this.requireThreadId();\n const response = await this.request(\"turn/start\", {\n threadId,\n input: [\n {\n type: \"text\",\n text: inputText,\n text_elements: [],\n },\n ],\n });\n\n const turnId = response?.turn?.id ?? null;\n if (turnId) {\n this.activeTurnId = turnId;\n }\n return turnId;\n }\n\n async steerTurn(inputText: string): Promise<string> {\n const threadId = this.requireThreadId();\n const turnId = this.requireActiveTurnId();\n\n await this.request(\"turn/steer\", {\n threadId,\n expectedTurnId: turnId,\n input: [\n {\n type: \"text\",\n text: inputText,\n text_elements: [],\n },\n ],\n });\n\n return turnId;\n }\n\n isBusy(): boolean {\n return Boolean(this.activeTurnId);\n }\n\n async refreshCurrentThreadState(): Promise<void> {\n if (!this.threadId) {\n return;\n }\n\n await this.refreshThreadState(this.threadId);\n }\n\n private requireThreadId(): string {\n if (!this.threadId) {\n throw new Error(\"No active App Server thread is available\");\n }\n return this.threadId;\n }\n\n private requireActiveTurnId(): string {\n if (!this.activeTurnId) {\n throw new Error(\"No active turn is available for turn/steer\");\n }\n return this.activeTurnId;\n }\n\n private async refreshThreadState(threadId: string): Promise<void> {\n const threadResponse = await this.request(\"thread/read\", {\n threadId,\n includeTurns: true,\n });\n this.syncThreadStateFromThread(threadResponse?.thread);\n }\n\n private syncThreadStateFromThread(thread: any): void {\n if (typeof thread?.id === \"string\") {\n this.threadId = thread.id;\n }\n\n let activeTurnId: string | null = null;\n let lastTurnStatus: string | null = null;\n const turns = Array.isArray(thread?.turns) ? thread.turns : [];\n for (const turn of turns) {\n if (typeof turn?.status === \"string\") {\n lastTurnStatus = turn.status;\n }\n if (turn?.status === \"inProgress\" && typeof turn.id === \"string\") {\n activeTurnId = turn.id;\n }\n }\n\n this.activeTurnId = activeTurnId;\n this.lastTurnStatus = lastTurnStatus;\n }\n\n private async handleMessage(data: unknown): Promise<void> {\n const text = await readSocketData(data);\n const message = JSON.parse(text) as JsonRpcResponse;\n\n if (\n typeof message.id === \"number\" &&\n (Object.hasOwn(message, \"result\") || Object.hasOwn(message, \"error\"))\n ) {\n const pending = this.pending.get(message.id);\n if (!pending) {\n return;\n }\n\n this.pending.delete(message.id);\n if (message.error) {\n const errorText = formatJsonRpcError(message.error);\n this.lastError = errorText;\n pending.reject(new Error(`${pending.method} failed: ${errorText}`));\n return;\n }\n\n pending.resolve(message.result);\n this.lastSuccessfulAppServerAt = new Date().toISOString();\n this.lastSuccessfulAppServerMethod = pending.method;\n this.lastError = null;\n return;\n }\n\n if (!message.method) {\n return;\n }\n\n this.lastNotificationMethod = message.method;\n this.lastNotificationAt = new Date().toISOString();\n this.handleNotification(message.method, message.params);\n }\n\n private handleNotification(method: string, params: any): void {\n switch (method) {\n case \"thread/started\":\n if (params?.thread?.id) {\n this.threadId = params.thread.id;\n }\n this.logger(`thread started ${params?.thread?.id ?? \"\"}`.trim());\n break;\n case \"thread/status/changed\":\n this.logger(\n `thread status changed (${params?.thread?.status?.type ?? params?.status?.type ?? \"unknown\"})`,\n );\n break;\n case \"turn/started\":\n if (params?.turn?.id) {\n this.activeTurnId = params.turn.id;\n this.logger(`turn started ${params.turn.id}`);\n }\n break;\n case \"turn/completed\":\n this.lastTurnStatus = params?.turn?.status ?? null;\n this.activeTurnId = null;\n this.logger(`turn completed (${this.lastTurnStatus ?? \"unknown\"})`);\n break;\n case \"error\":\n this.lastError = JSON.stringify(params ?? {}, null, 2);\n this.logger(`app-server error notification: ${this.lastError}`);\n break;\n default:\n break;\n }\n }\n\n private request(method: string, params: unknown): Promise<any> {\n if (!this.socket || this.socket.readyState !== WebSocket.OPEN) {\n throw new Error(`Cannot call ${method}; App Server socket is not open`);\n }\n\n const id = this.nextId;\n this.nextId += 1;\n\n const request: RequestRecord = {\n jsonrpc: \"2.0\",\n id,\n method,\n params,\n };\n\n return new Promise((resolvePromise, rejectPromise) => {\n this.pending.set(id, {\n resolve: resolvePromise,\n reject: rejectPromise,\n method,\n });\n this.socket?.send(JSON.stringify(request));\n });\n }\n\n private rejectPending(error: Error): void {\n for (const pending of this.pending.values()) {\n pending.reject(error);\n }\n this.pending.clear();\n }\n}\n\nfunction writeHeartbeat(\n options: Options,\n client: AppServerClient | null,\n health: BridgeHealthState,\n): void {\n const payload: HeartbeatRecord = {\n pid: process.pid,\n agent: options.agentName,\n updatedAt: new Date().toISOString(),\n pollSeconds: options.pollSeconds,\n appServerUrl: options.appServerUrl,\n connected: client?.connected ?? false,\n initialized: client?.initialized ?? false,\n threadId: client?.threadId ?? null,\n activeTurnId: client?.activeTurnId ?? null,\n lastTurnStatus: client?.lastTurnStatus ?? null,\n lastNotificationMethod: client?.lastNotificationMethod ?? null,\n lastNotificationAt: client?.lastNotificationAt ?? null,\n lastError: client?.lastError ?? null,\n lastSuccessfulAppServerAt: client?.lastSuccessfulAppServerAt ?? null,\n lastSuccessfulAppServerMethod:\n client?.lastSuccessfulAppServerMethod ?? null,\n consecutiveFailureCount: health.consecutiveFailureCount,\n busyMode: options.busyMode,\n };\n\n writeFileSync(\n join(options.stateDir, \"heartbeat.json\"),\n `${JSON.stringify(payload, null, 2)}\\n`,\n \"utf8\",\n );\n}\n\nasync function dispatchCandidate(\n client: AppServerClient,\n options: Options,\n candidate: Candidate,\n heartbeats: HeartbeatStore,\n): Promise<boolean> {\n const input = buildUserInput(candidate, options.agentName, heartbeats);\n\n if (client.isBusy()) {\n if (options.busyMode !== \"steer\") {\n return false;\n }\n\n try {\n const turnId = await client.steerTurn(input);\n writeProcessedMarker(\n options.stateDir,\n candidate,\n \"steer\",\n client.threadId,\n turnId,\n );\n writeLastDispatch(\n options.stateDir,\n candidate,\n \"steer\",\n client.threadId,\n turnId,\n );\n logStatus(`steered active turn with ${candidate.fileName}`);\n return true;\n } catch (error) {\n await client.refreshCurrentThreadState().catch(() => undefined);\n\n if (!client.isBusy()) {\n return dispatchCandidate(client, options, candidate, heartbeats);\n }\n\n if (shouldRetrySteerAsStart(error)) {\n client.activeTurnId = null;\n logStatus(\n `steer fallback -> start for ${candidate.fileName} (${String(error)})`,\n );\n return dispatchCandidate(client, options, candidate, heartbeats);\n }\n\n throw error;\n }\n }\n\n const turnId = await client.startTurn(input);\n writeProcessedMarker(\n options.stateDir,\n candidate,\n \"start\",\n client.threadId,\n turnId,\n );\n writeLastDispatch(\n options.stateDir,\n candidate,\n \"start\",\n client.threadId,\n turnId,\n );\n logStatus(`dispatched ${candidate.fileName} to thread ${client.threadId}`);\n return true;\n}\n\nasync function runScan(\n options: Options,\n cutoff: Date,\n client: AppServerClient | null,\n): Promise<boolean> {\n const { heartbeats, candidates } = getPendingCandidates(options, cutoff);\n for (const candidate of candidates) {\n if (options.dryRun) {\n logStatus(`dry-run candidate ${candidate.fileName}`);\n continue;\n }\n\n if (!client) {\n throw new Error(\"App Server client is not available\");\n }\n\n const dispatched = await dispatchCandidate(\n client,\n options,\n candidate,\n heartbeats,\n );\n if (!dispatched && options.busyMode === \"wait\") {\n return false;\n }\n return true;\n }\n\n return false;\n}\n\nasync function waitForTurnDrain(\n options: Options,\n client: AppServerClient,\n health: BridgeHealthState,\n): Promise<void> {\n const deadline = Date.now() + options.waitAfterDispatchSeconds * 1_000;\n while (Date.now() < deadline) {\n writeHeartbeat(options, client, health);\n if (!client.activeTurnId) {\n return;\n }\n await delay(1_000);\n }\n}\n\nexport function buildOptions(argv: string[]): Options {\n const parsed = parseArgs(argv);\n const repoRoot = resolveRepoRoot(parsed.repoRoot);\n const commsDir = resolveCommsDir(repoRoot, parsed.commsDir);\n const preferredAgentName = resolvePreferredAgentName(parsed.agentName);\n const stateDir = resolveStateDir(\n repoRoot,\n parsed.stateDir,\n preferredAgentName,\n );\n const agentName = resolveAgentName(preferredAgentName, stateDir);\n const agentId = resolveAgentId(agentName);\n persistAgentName(stateDir, agentName);\n const gatewayTokenFile =\n parsed.gatewayTokenFile?.trim() ||\n process.env.TAP_GATEWAY_TOKEN_FILE?.trim() ||\n null;\n const appServerUrl =\n parsed.appServerUrl?.trim() ||\n process.env.CODEX_APP_SERVER_URL ||\n DEFAULT_APP_SERVER_URL;\n\n return {\n repoRoot,\n commsDir,\n agentId,\n stateDir,\n agentName,\n pollSeconds: parsed.pollSeconds ?? 5,\n reconnectSeconds: parsed.reconnectSeconds ?? 5,\n messageLookbackMinutes: parsed.messageLookbackMinutes ?? 10,\n processExistingMessages: parsed.processExistingMessages,\n dryRun: parsed.dryRun,\n runOnce: parsed.runOnce,\n waitAfterDispatchSeconds: parsed.waitAfterDispatchSeconds ?? 0,\n appServerUrl,\n connectAppServerUrl: gatewayTokenFile\n ? buildProtectedAppServerUrl(\n appServerUrl,\n readGatewayTokenFile(gatewayTokenFile),\n )\n : appServerUrl,\n gatewayTokenFile,\n busyMode: parsed.busyMode ?? \"steer\",\n threadId: parsed.threadId?.trim() || null,\n ephemeral: parsed.ephemeral,\n };\n}\n\nexport async function main(): Promise<void> {\n const options = buildOptions(process.argv.slice(2));\n const cutoff = getGeneralInboxCutoff(\n options.stateDir,\n options.messageLookbackMinutes,\n options.processExistingMessages,\n );\n const savedThread = readThreadState(options.stateDir);\n\n logStatus(\"codex app-server bridge ready\");\n console.log(` repo: ${options.repoRoot}`);\n console.log(` comms: ${options.commsDir}`);\n console.log(` agent: ${options.agentName}`);\n console.log(` state: ${options.stateDir}`);\n console.log(` app-server: ${options.appServerUrl}`);\n console.log(` busy-mode: ${options.busyMode}`);\n if (options.waitAfterDispatchSeconds > 0) {\n console.log(\n ` wait: ${options.waitAfterDispatchSeconds}s after dispatch`,\n );\n }\n console.log(\n ` lookback: ${\n options.processExistingMessages\n ? \"existing messages\"\n : `${options.messageLookbackMinutes} minute(s)`\n }`,\n );\n if (options.threadId || savedThread?.threadId) {\n console.log(` thread: ${options.threadId ?? savedThread?.threadId}`);\n }\n if (options.dryRun) {\n logStatus(\"dry-run mode enabled\");\n }\n\n let client: AppServerClient | null = null;\n let savedThreadId = savedThread?.threadId ?? null;\n const health: BridgeHealthState = {\n consecutiveFailureCount: 0,\n };\n\n while (true) {\n try {\n if (!options.dryRun) {\n if (!client || !client.connected) {\n client = new AppServerClient(options.connectAppServerUrl, logStatus);\n await client.connect();\n\n const threadId = await client.ensureThread(\n options.threadId,\n savedThreadId,\n options.repoRoot,\n options.ephemeral,\n );\n persistThreadState(\n options.stateDir,\n threadId,\n options.appServerUrl,\n options.ephemeral,\n );\n savedThreadId = threadId;\n writeHeartbeat(options, client, health);\n const bootstrapped = await maybeBootstrapHeadlessTurn(\n options,\n cutoff,\n client,\n );\n if (bootstrapped) {\n writeHeartbeat(options, client, health);\n }\n }\n }\n\n const dispatched = await runScan(options, cutoff, client);\n if (dispatched && client && options.waitAfterDispatchSeconds > 0) {\n await waitForTurnDrain(options, client, health);\n }\n health.consecutiveFailureCount = 0;\n writeHeartbeat(options, client, health);\n\n if (options.runOnce) {\n break;\n }\n\n await delay(options.pollSeconds * 1_000);\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n logStatus(`bridge error: ${message}`);\n if (client) {\n client.lastError = message;\n }\n health.consecutiveFailureCount += 1;\n writeHeartbeat(options, client, health);\n\n if (options.runOnce) {\n throw error;\n }\n\n client?.disconnect().catch(() => undefined);\n client = null;\n await delay(options.reconnectSeconds * 1_000);\n }\n }\n\n await client?.disconnect();\n}\n\nfunction isDirectExecution(): boolean {\n const entry = process.argv[1];\n if (!entry) return false;\n return import.meta.url === pathToFileURL(resolve(entry)).href;\n}\n\nif (isDirectExecution()) {\n main().catch((error) => {\n console.error(\n error instanceof Error ? (error.stack ?? error.message) : String(error),\n );\n process.exitCode = 1;\n });\n}\n"],"mappings":"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","names":["pathToFileURL","resolve","turnId","isDirectExecution","pathToFileURL","resolve"]}
1
+ {"version":3,"sources":["../../src/bridges/codex-app-server-bridge.ts","../../../../scripts/codex-app-server-bridge.ts"],"sourcesContent":["import { pathToFileURL } from \"node:url\";\nimport { resolve } from \"node:path\";\nimport { main } from \"../../../../scripts/codex-app-server-bridge.js\";\n\nexport * from \"../../../../scripts/codex-app-server-bridge.js\";\n\nfunction isDirectExecution(): boolean {\n const entry = process.argv[1];\n if (!entry) return false;\n return import.meta.url === pathToFileURL(resolve(entry)).href;\n}\n\nif (isDirectExecution()) {\n main().catch((error) => {\n console.error(\n error instanceof Error ? (error.stack ?? error.message) : String(error),\n );\n process.exitCode = 1;\n });\n}\n","#!/usr/bin/env node --experimental-strip-types\n\nimport { createHash } from \"crypto\";\nimport {\n existsSync,\n mkdirSync,\n readdirSync,\n readFileSync,\n statSync,\n writeFileSync,\n} from \"fs\";\nimport { isAbsolute, join, resolve } from \"path\";\nimport { pathToFileURL } from \"url\";\n\ntype BusyMode = \"wait\" | \"steer\";\n\ninterface Options {\n repoRoot: string;\n commsDir: string;\n agentId: string;\n agentName: string;\n stateDir: string;\n pollSeconds: number;\n reconnectSeconds: number;\n messageLookbackMinutes: number;\n processExistingMessages: boolean;\n dryRun: boolean;\n runOnce: boolean;\n waitAfterDispatchSeconds: number;\n appServerUrl: string;\n connectAppServerUrl: string;\n gatewayToken: string | null;\n gatewayTokenFile: string | null;\n busyMode: BusyMode;\n threadId: string | null;\n ephemeral: boolean;\n}\n\ninterface InboxRoute {\n sender: string;\n recipient: string;\n subject: string;\n}\n\ninterface Candidate {\n markerId: string;\n filePath: string;\n fileName: string;\n sender: string;\n recipient: string;\n subject: string;\n body: string;\n mtimeMs: number;\n}\n\ninterface ThreadStateRecord {\n threadId: string;\n updatedAt: string;\n appServerUrl: string;\n ephemeral: boolean;\n}\n\ninterface HeartbeatRecord {\n pid: number;\n agent: string;\n updatedAt: string;\n pollSeconds: number;\n appServerUrl: string;\n connected: boolean;\n initialized: boolean;\n threadId: string | null;\n activeTurnId: string | null;\n lastTurnStatus: string | null;\n lastNotificationMethod: string | null;\n lastNotificationAt: string | null;\n lastError: string | null;\n lastSuccessfulAppServerAt: string | null;\n lastSuccessfulAppServerMethod: string | null;\n consecutiveFailureCount: number;\n busyMode: BusyMode;\n}\n\ninterface BridgeHealthState {\n consecutiveFailureCount: number;\n}\n\nexport interface HeadlessWarmupClient {\n activeTurnId: string | null;\n lastTurnStatus: string | null;\n startTurn(inputText: string): Promise<string | null>;\n refreshCurrentThreadState(): Promise<void>;\n}\n\ninterface RequestRecord {\n jsonrpc: \"2.0\";\n id: number;\n method: string;\n params: unknown;\n}\n\ninterface HeartbeatStoreRecord {\n id?: string;\n agent?: string;\n}\n\ntype HeartbeatStore = Record<string, HeartbeatStoreRecord>;\n\ninterface JsonRpcResponse {\n id?: number;\n result?: any;\n error?: {\n code?: number;\n message?: string;\n data?: unknown;\n };\n method?: string;\n params?: any;\n}\n\nconst DEFAULT_AGENT = String.fromCharCode(0xc628);\nconst DEFAULT_APP_SERVER_URL = \"ws://127.0.0.1:4501\";\nconst AUTH_SUBPROTOCOL_PREFIX = \"tap-auth-\";\nconst PLACEHOLDER_AGENT_VALUES = new Set([\n \"unknown\",\n \"unnamed\",\n \"<set-per-session>\",\n]);\nexport const HEADLESS_WARMUP_PROMPT = [\n \"You are a tap worker agent connected via the tap-comms inbox.\",\n \"This is a one-time warmup turn for headless bridge startup.\",\n \"Do not take any external actions.\",\n \"Reply briefly, then wait for future inbox instructions.\",\n].join(\" \");\nconst HEADLESS_WARMUP_TIMEOUT_MS = 30_000;\nconst TURN_COMPLETION_POLL_MS = 250;\nconst TURN_COMPLETION_REFRESH_MS = 1_000;\n\nfunction printHelp(): void {\n console.log(`Codex App Server bridge\n\nUsage:\n node --experimental-strip-types scripts/codex-app-server-bridge.ts [options]\n\nOptions:\n --repo-root=<path>\n --comms-dir=<path>\n --agent-name=<name>\n --state-dir=<path>\n --poll-seconds=<n>\n --reconnect-seconds=<n>\n --message-lookback-minutes=<n>\n --process-existing-messages\n --dry-run\n --run-once\n --wait-after-dispatch-seconds=<n>\n --app-server-url=<ws-url>\n --gateway-token-file=<path>\n --busy-mode=wait|steer\n --thread-id=<id>\n --ephemeral\n --help\n`);\n}\n\nfunction parseNumber(value: string, flag: string): number {\n const parsed = Number(value);\n if (!Number.isFinite(parsed) || parsed < 0) {\n throw new Error(`Invalid ${flag}: ${value}`);\n }\n return parsed;\n}\n\nfunction readFlagValue(argv: string[], index: number, flag: string): string {\n const current = argv[index];\n const eqIndex = current.indexOf(\"=\");\n if (eqIndex >= 0) {\n return current.slice(eqIndex + 1);\n }\n\n const next = argv[index + 1];\n if (!next || next.startsWith(\"--\")) {\n throw new Error(`Missing value for ${flag}`);\n }\n return next;\n}\n\nfunction parseArgs(argv: string[]): {\n repoRoot?: string;\n commsDir?: string;\n agentName?: string;\n stateDir?: string;\n pollSeconds?: number;\n reconnectSeconds?: number;\n messageLookbackMinutes?: number;\n processExistingMessages: boolean;\n dryRun: boolean;\n runOnce: boolean;\n waitAfterDispatchSeconds?: number;\n appServerUrl?: string;\n gatewayTokenFile?: string;\n busyMode?: BusyMode;\n threadId?: string;\n ephemeral: boolean;\n} {\n const parsed = {\n processExistingMessages: false,\n dryRun: false,\n runOnce: false,\n ephemeral: false,\n } as {\n repoRoot?: string;\n commsDir?: string;\n agentName?: string;\n stateDir?: string;\n pollSeconds?: number;\n reconnectSeconds?: number;\n messageLookbackMinutes?: number;\n processExistingMessages: boolean;\n dryRun: boolean;\n runOnce: boolean;\n waitAfterDispatchSeconds?: number;\n appServerUrl?: string;\n gatewayTokenFile?: string;\n busyMode?: BusyMode;\n threadId?: string;\n ephemeral: boolean;\n };\n\n for (let index = 0; index < argv.length; index += 1) {\n const flag = argv[index];\n const consumesNext = !flag.includes(\"=\");\n\n if (flag === \"--help\") {\n printHelp();\n process.exit(0);\n }\n\n if (flag === \"--process-existing-messages\") {\n parsed.processExistingMessages = true;\n continue;\n }\n\n if (flag === \"--dry-run\") {\n parsed.dryRun = true;\n continue;\n }\n\n if (flag === \"--run-once\") {\n parsed.runOnce = true;\n continue;\n }\n\n if (flag === \"--ephemeral\") {\n parsed.ephemeral = true;\n continue;\n }\n\n if (flag.startsWith(\"--repo-root\")) {\n parsed.repoRoot = readFlagValue(argv, index, \"--repo-root\");\n if (consumesNext) {\n index += 1;\n }\n continue;\n }\n\n if (flag.startsWith(\"--comms-dir\")) {\n parsed.commsDir = readFlagValue(argv, index, \"--comms-dir\");\n if (consumesNext) {\n index += 1;\n }\n continue;\n }\n\n if (flag.startsWith(\"--agent-name\")) {\n parsed.agentName = readFlagValue(argv, index, \"--agent-name\");\n if (consumesNext) {\n index += 1;\n }\n continue;\n }\n\n if (flag.startsWith(\"--state-dir\")) {\n parsed.stateDir = readFlagValue(argv, index, \"--state-dir\");\n if (consumesNext) {\n index += 1;\n }\n continue;\n }\n\n if (flag.startsWith(\"--poll-seconds\")) {\n parsed.pollSeconds = parseNumber(\n readFlagValue(argv, index, \"--poll-seconds\"),\n \"--poll-seconds\",\n );\n if (consumesNext) {\n index += 1;\n }\n continue;\n }\n\n if (flag.startsWith(\"--reconnect-seconds\")) {\n parsed.reconnectSeconds = parseNumber(\n readFlagValue(argv, index, \"--reconnect-seconds\"),\n \"--reconnect-seconds\",\n );\n if (consumesNext) {\n index += 1;\n }\n continue;\n }\n\n if (flag.startsWith(\"--message-lookback-minutes\")) {\n parsed.messageLookbackMinutes = parseNumber(\n readFlagValue(argv, index, \"--message-lookback-minutes\"),\n \"--message-lookback-minutes\",\n );\n if (consumesNext) {\n index += 1;\n }\n continue;\n }\n\n if (flag.startsWith(\"--app-server-url\")) {\n parsed.appServerUrl = readFlagValue(argv, index, \"--app-server-url\");\n if (consumesNext) {\n index += 1;\n }\n continue;\n }\n\n if (flag.startsWith(\"--gateway-token-file\")) {\n parsed.gatewayTokenFile = readFlagValue(\n argv,\n index,\n \"--gateway-token-file\",\n );\n if (consumesNext) {\n index += 1;\n }\n continue;\n }\n\n if (flag.startsWith(\"--wait-after-dispatch-seconds\")) {\n parsed.waitAfterDispatchSeconds = parseNumber(\n readFlagValue(argv, index, \"--wait-after-dispatch-seconds\"),\n \"--wait-after-dispatch-seconds\",\n );\n if (consumesNext) {\n index += 1;\n }\n continue;\n }\n\n if (flag.startsWith(\"--busy-mode\")) {\n const value = readFlagValue(argv, index, \"--busy-mode\");\n if (value !== \"wait\" && value !== \"steer\") {\n throw new Error(`Invalid --busy-mode: ${value}`);\n }\n parsed.busyMode = value;\n if (consumesNext) {\n index += 1;\n }\n continue;\n }\n\n if (flag.startsWith(\"--thread-id\")) {\n parsed.threadId = readFlagValue(argv, index, \"--thread-id\");\n if (consumesNext) {\n index += 1;\n }\n continue;\n }\n\n throw new Error(`Unknown argument: ${flag}`);\n }\n\n return parsed;\n}\n\nfunction timestamp(): string {\n return new Date().toISOString().replace(\"T\", \" \").replace(\"Z\", \" UTC\");\n}\n\nfunction logStatus(message: string): void {\n console.log(`[${timestamp()}] ${message}`);\n}\n\nfunction ensureDir(target: string): string {\n if (!existsSync(target)) {\n mkdirSync(target, { recursive: true });\n }\n return resolve(target);\n}\n\nfunction convertTapPath(input: string): string {\n const trimmed = input.trim().replace(/^[\"'`]+|[\"'`]+$/g, \"\");\n if (/^[A-Za-z]:\\\\/.test(trimmed)) {\n return trimmed;\n }\n\n const match = trimmed.match(/^\\/([A-Za-z])\\/(.*)$/);\n if (match) {\n return `${match[1].toUpperCase()}:\\\\${match[2].replace(/\\//g, \"\\\\\")}`;\n }\n\n return trimmed;\n}\n\nfunction resolveRepoRoot(explicit?: string): string {\n if (explicit) {\n return resolve(explicit);\n }\n\n return process.cwd();\n}\n\nfunction resolveCommsDir(repoRoot: string, explicit?: string): string {\n if (explicit) {\n return resolve(convertTapPath(explicit));\n }\n\n const tapConfigPath = join(repoRoot, \".tap-config\");\n if (!existsSync(tapConfigPath)) {\n throw new Error(\n \"Unable to resolve comms directory. Pass --comms-dir explicitly.\",\n );\n }\n\n const configText = readFileSync(tapConfigPath, \"utf8\");\n const match = configText.match(/^TAP_COMMS_DIR=\"?(.*?)\"?$/m);\n if (!match?.[1]) {\n throw new Error(\n \"Unable to resolve comms directory. Pass --comms-dir explicitly.\",\n );\n }\n\n return resolveTapConfigPath(repoRoot, match[1]);\n}\n\nfunction resolvePreferredAgentName(requested?: string): string | null {\n if (requested?.trim()) {\n return requested.trim();\n }\n\n for (const envName of [\"TAP_AGENT_NAME\", \"CODEX_TAP_AGENT_NAME\"]) {\n const candidate = process.env[envName];\n if (candidate?.trim()) {\n return candidate.trim();\n }\n }\n\n return null;\n}\n\nfunction normalizeAgentToken(value?: string | null): string | null {\n const normalized = value?.trim();\n if (!normalized || PLACEHOLDER_AGENT_VALUES.has(normalized)) {\n return null;\n }\n\n return normalized;\n}\n\nexport function resolveAgentId(preferredAgentName?: string | null): string {\n return (\n normalizeAgentToken(process.env.TAP_AGENT_ID) ??\n normalizeAgentToken(preferredAgentName) ??\n \"unknown\"\n );\n}\n\nfunction sanitizeStateSegment(agentName: string): string {\n const normalized = agentName\n .trim()\n .replace(/[<>:\"/\\\\|?*\\x00-\\x1f]/g, \"-\")\n .replace(/[. ]+$/g, \"\");\n\n return normalized || \"agent\";\n}\n\nfunction buildDefaultStateDir(\n repoRoot: string,\n preferredAgentName?: string | null,\n): string {\n const suffix = preferredAgentName?.trim()\n ? `-${sanitizeStateSegment(preferredAgentName)}`\n : \"\";\n return resolve(join(repoRoot, \".tmp\", `codex-app-server-bridge${suffix}`));\n}\n\nfunction resolveStateDir(\n repoRoot: string,\n explicit?: string,\n preferredAgentName?: string | null,\n): string {\n const root = explicit\n ? resolve(explicit)\n : buildDefaultStateDir(repoRoot, preferredAgentName);\n\n ensureDir(root);\n ensureDir(join(root, \"processed\"));\n ensureDir(join(root, \"logs\"));\n return root;\n}\n\nfunction resolveAgentName(\n preferredAgentName: string | null,\n stateDir: string,\n): string {\n if (preferredAgentName?.trim()) {\n return preferredAgentName.trim();\n }\n\n const agentFile = join(stateDir, \"agent-name.txt\");\n if (existsSync(agentFile)) {\n const candidate = readFileSync(agentFile, \"utf8\").trim();\n if (candidate) {\n return candidate;\n }\n }\n\n return DEFAULT_AGENT;\n}\n\nfunction persistAgentName(stateDir: string, agentName: string): void {\n writeFileSync(join(stateDir, \"agent-name.txt\"), `${agentName}\\n`, \"utf8\");\n}\n\n// buildProtectedAppServerUrl removed — subprotocol auth replaces query-param tokens.\n\nfunction readGatewayTokenFile(tokenFile: string): string {\n const token = readFileSync(tokenFile, \"utf8\").trim();\n if (!token) {\n throw new Error(`Gateway token file is empty: ${tokenFile}`);\n }\n return token;\n}\n\nfunction resolveTapConfigPath(repoRoot: string, input: string): string {\n const converted = convertTapPath(input);\n return isAbsolute(converted)\n ? resolve(converted)\n : resolve(repoRoot, converted);\n}\n\nfunction readThreadState(stateDir: string): ThreadStateRecord | null {\n const threadPath = join(stateDir, \"thread.json\");\n if (!existsSync(threadPath)) {\n return null;\n }\n\n try {\n const parsed = JSON.parse(\n readFileSync(threadPath, \"utf8\"),\n ) as ThreadStateRecord;\n if (parsed.threadId) {\n return parsed;\n }\n } catch {\n return null;\n }\n\n return null;\n}\n\nfunction persistThreadState(\n stateDir: string,\n threadId: string,\n appServerUrl: string,\n ephemeral: boolean,\n): void {\n const payload: ThreadStateRecord = {\n threadId,\n updatedAt: new Date().toISOString(),\n appServerUrl,\n ephemeral,\n };\n writeFileSync(\n join(stateDir, \"thread.json\"),\n `${JSON.stringify(payload, null, 2)}\\n`,\n \"utf8\",\n );\n}\n\nfunction getGeneralInboxCutoff(\n stateDir: string,\n lookbackMinutes: number,\n processExistingMessages: boolean,\n): Date {\n if (processExistingMessages) {\n return new Date(0);\n }\n\n if (lookbackMinutes > 0) {\n return new Date(Date.now() - lookbackMinutes * 60_000);\n }\n\n const cutoffPath = join(stateDir, \"general-inbox-cutoff.txt\");\n if (existsSync(cutoffPath)) {\n try {\n return new Date(readFileSync(cutoffPath, \"utf8\").trim());\n } catch {\n return new Date();\n }\n }\n\n const cutoff = new Date();\n writeFileSync(cutoffPath, `${cutoff.toISOString()}\\n`, \"utf8\");\n return cutoff;\n}\n\nexport function recipientMatchesAgent(\n recipient: string,\n agentId: string,\n agentName: string,\n): boolean {\n const normalizedRecipient = recipient.trim();\n if (!normalizedRecipient) {\n return false;\n }\n\n return (\n normalizedRecipient === \"전체\" ||\n normalizedRecipient === \"all\" ||\n normalizedRecipient === agentId ||\n normalizedRecipient === agentName\n );\n}\n\nexport function isOwnMessageSender(\n sender: string,\n agentId: string,\n agentName: string,\n): boolean {\n const normalizedSender = sender.trim();\n if (!normalizedSender) {\n return false;\n }\n\n return normalizedSender === agentId || normalizedSender === agentName;\n}\n\nfunction getInboxRoute(fileName: string): InboxRoute {\n const stem = fileName.replace(/\\.md$/i, \"\");\n const parts = stem.split(\"-\");\n let offset = 0;\n if (parts[0] && /^\\d{8}$/.test(parts[0])) {\n offset = 1;\n }\n\n return {\n sender: parts[offset] ?? \"\",\n recipient: parts[offset + 1] ?? \"\",\n subject: parts.slice(offset + 2).join(\"-\"),\n };\n}\n\nfunction buildMarkerId(filePath: string, mtimeMs: number): string {\n return createHash(\"sha1\").update(`${filePath}|${mtimeMs}`).digest(\"hex\");\n}\n\nfunction getProcessedMarkerPath(stateDir: string, markerId: string): string {\n return join(stateDir, \"processed\", `${markerId}.done`);\n}\n\nfunction loadHeartbeats(commsDir: string): HeartbeatStore {\n try {\n return JSON.parse(readFileSync(join(commsDir, \"heartbeats.json\"), \"utf8\"));\n } catch {\n return {};\n }\n}\n\nfunction formatAgentLabel(\n agentIdOrName: string,\n displayName?: string | null,\n): string {\n const normalizedId = agentIdOrName.trim();\n const normalizedName = displayName?.trim();\n\n if (!normalizedId) {\n return normalizedName ?? agentIdOrName;\n }\n\n if (!normalizedName || normalizedName === normalizedId) {\n return normalizedId;\n }\n\n return `${normalizedName} [${normalizedId}]`;\n}\n\nexport function resolveAddressLabel(\n address: string,\n heartbeats: HeartbeatStore,\n): string {\n const normalized = address.trim();\n if (!normalized || normalized === \"전체\" || normalized === \"all\") {\n return address;\n }\n\n const direct = heartbeats[normalized];\n if (direct?.agent?.trim()) {\n return formatAgentLabel(normalized, direct.agent);\n }\n\n for (const [agentId, heartbeat] of Object.entries(heartbeats)) {\n if (heartbeat.agent?.trim() === normalized) {\n return formatAgentLabel(agentId, heartbeat.agent);\n }\n }\n\n return normalized;\n}\n\nexport function resolveCurrentAgentName(\n agentId: string,\n fallbackAgentName: string,\n heartbeats: HeartbeatStore,\n): string {\n const currentName = heartbeats[agentId]?.agent?.trim();\n if (currentName) {\n return currentName;\n }\n\n for (const heartbeat of Object.values(heartbeats)) {\n if (heartbeat.id?.trim() === agentId && heartbeat.agent?.trim()) {\n return heartbeat.agent.trim();\n }\n }\n\n return fallbackAgentName;\n}\n\nfunction refreshAgentIdentity(\n options: Options,\n heartbeats: HeartbeatStore,\n): string {\n const nextAgentName = resolveCurrentAgentName(\n options.agentId,\n options.agentName,\n heartbeats,\n );\n\n if (nextAgentName !== options.agentName) {\n options.agentName = nextAgentName;\n persistAgentName(options.stateDir, nextAgentName);\n }\n\n return nextAgentName;\n}\n\n// When running in headless reviewer mode, review-request files are handled\n// by the headless loop (engine/headless-loop.ts), not the generic bridge.\n// Skip them here to prevent race conditions.\nconst HEADLESS_SKIP_PATTERNS = [\n /리뷰\\s*요청/,\n /review[- ]?request/i,\n /재리뷰/,\n /re-?review/i,\n];\n\nfunction shouldSkipInHeadlessMode(fileName: string, body: string): boolean {\n if (process.env.TAP_HEADLESS !== \"true\") return false;\n const combined = `${fileName}\\n${body}`;\n return HEADLESS_SKIP_PATTERNS.some((p) => p.test(combined));\n}\n\nfunction collectCandidates(\n inboxDir: string,\n agentId: string,\n agentName: string,\n): Candidate[] {\n const entries = readdirSync(inboxDir, { withFileTypes: true })\n .filter(\n (entry) => entry.isFile() && entry.name.toLowerCase().endsWith(\".md\"),\n )\n .map((entry) => {\n const filePath = join(inboxDir, entry.name);\n const stats = statSync(filePath);\n return { entry, filePath, stats };\n })\n .sort((left, right) => left.stats.mtimeMs - right.stats.mtimeMs);\n\n const candidates: Candidate[] = [];\n for (const item of entries) {\n const route = getInboxRoute(item.entry.name);\n if (!recipientMatchesAgent(route.recipient, agentId, agentName)) {\n continue;\n }\n\n if (isOwnMessageSender(route.sender, agentId, agentName)) {\n continue;\n }\n\n const body = readFileSync(item.filePath, \"utf8\");\n\n // In headless mode, skip review-request files — handled by headless loop\n if (shouldSkipInHeadlessMode(item.entry.name, body)) {\n continue;\n }\n\n candidates.push({\n markerId: buildMarkerId(item.filePath, item.stats.mtimeMs),\n filePath: item.filePath,\n fileName: item.entry.name,\n sender: route.sender,\n recipient: route.recipient,\n subject: route.subject,\n body,\n mtimeMs: item.stats.mtimeMs,\n });\n }\n\n return candidates;\n}\n\nfunction getPendingCandidates(\n options: Options,\n cutoff: Date,\n): {\n heartbeats: HeartbeatStore;\n candidates: Candidate[];\n} {\n const inboxDir = join(options.commsDir, \"inbox\");\n if (!existsSync(inboxDir)) {\n throw new Error(`Inbox directory not found: ${inboxDir}`);\n }\n\n const heartbeats = loadHeartbeats(options.commsDir);\n const agentName = refreshAgentIdentity(options, heartbeats);\n const cutoffMs = cutoff.getTime();\n const candidates = collectCandidates(\n inboxDir,\n options.agentId,\n agentName,\n ).filter((candidate) => {\n if (candidate.mtimeMs < cutoffMs) {\n return false;\n }\n\n return !existsSync(\n getProcessedMarkerPath(options.stateDir, candidate.markerId),\n );\n });\n\n return { heartbeats, candidates };\n}\n\nexport function buildUserInput(\n candidate: Candidate,\n agentName: string,\n heartbeats: HeartbeatStore,\n): string {\n const sender = resolveAddressLabel(candidate.sender || \"unknown\", heartbeats);\n const recipient = resolveAddressLabel(\n candidate.recipient || agentName,\n heartbeats,\n );\n const subject = candidate.subject || \"(none)\";\n const body = candidate.body.trim();\n\n return [\n `Tap-comms inbox message for ${agentName}.`,\n `Sender: ${sender}`,\n `Recipient: ${recipient}`,\n `Subject: ${subject}`,\n `File: ${candidate.fileName}`,\n \"\",\n \"Message body:\",\n body || \"(empty)\",\n \"\",\n \"---\",\n \"Instructions: Read the message above and respond using the tap_reply tool.\",\n `Use tap_reply(to: \"${candidate.sender || \"unknown\"}\", subject: \"<your-subject>\", content: \"<your-response>\") to send your response.`,\n \"If the message is a review request, perform the review and reply with your findings.\",\n \"If the message is informational, acknowledge briefly via tap_reply.\",\n \"Do NOT respond with plain text only — you MUST use the tap_reply tool.\",\n ].join(\"\\n\");\n}\n\nfunction writeProcessedMarker(\n stateDir: string,\n candidate: Candidate,\n dispatchMode: \"start\" | \"steer\",\n threadId: string | null,\n turnId: string | null,\n): void {\n const payload = {\n requestFile: candidate.filePath,\n requestName: candidate.fileName,\n sender: candidate.sender,\n recipient: candidate.recipient,\n subject: candidate.subject,\n dispatchMode,\n threadId,\n turnId,\n markedAt: new Date().toISOString(),\n };\n writeFileSync(\n getProcessedMarkerPath(stateDir, candidate.markerId),\n `${JSON.stringify(payload, null, 2)}\\n`,\n \"utf8\",\n );\n}\n\nfunction writeLastDispatch(\n stateDir: string,\n candidate: Candidate,\n dispatchMode: \"start\" | \"steer\",\n threadId: string | null,\n turnId: string | null,\n): void {\n const payload = {\n requestFile: candidate.filePath,\n requestName: candidate.fileName,\n markerId: candidate.markerId,\n sender: candidate.sender,\n recipient: candidate.recipient,\n subject: candidate.subject,\n dispatchMode,\n threadId,\n turnId,\n dispatchedAt: new Date().toISOString(),\n };\n writeFileSync(\n join(stateDir, \"last-dispatch.json\"),\n `${JSON.stringify(payload, null, 2)}\\n`,\n \"utf8\",\n );\n}\n\nfunction formatJsonRpcError(error: JsonRpcResponse[\"error\"]): string {\n if (!error) {\n return \"Unknown App Server error\";\n }\n\n return JSON.stringify(\n {\n code: error.code,\n message: error.message,\n data: error.data,\n },\n null,\n 2,\n );\n}\n\nfunction delay(ms: number): Promise<void> {\n return new Promise((resolvePromise) => {\n setTimeout(resolvePromise, ms);\n });\n}\n\nexport async function waitForTurnCompletion(\n client: Pick<\n HeadlessWarmupClient,\n \"activeTurnId\" | \"lastTurnStatus\" | \"refreshCurrentThreadState\"\n >,\n turnId: string,\n timeoutMs: number,\n): Promise<string | null> {\n const deadline = Date.now() + timeoutMs;\n let nextRefreshAt = Date.now();\n\n while (Date.now() < deadline) {\n if (!client.activeTurnId || client.activeTurnId !== turnId) {\n return client.lastTurnStatus;\n }\n\n if (Date.now() >= nextRefreshAt) {\n await client.refreshCurrentThreadState().catch(() => undefined);\n if (!client.activeTurnId || client.activeTurnId !== turnId) {\n return client.lastTurnStatus;\n }\n nextRefreshAt = Date.now() + TURN_COMPLETION_REFRESH_MS;\n }\n\n await delay(\n Math.min(TURN_COMPLETION_POLL_MS, Math.max(deadline - Date.now(), 0)),\n );\n }\n\n await client.refreshCurrentThreadState().catch(() => undefined);\n if (!client.activeTurnId || client.activeTurnId !== turnId) {\n return client.lastTurnStatus;\n }\n\n throw new Error(`Timed out waiting for turn ${turnId} to complete`);\n}\n\nexport async function maybeBootstrapHeadlessTurn(\n options: Options,\n cutoff: Date,\n client: HeadlessWarmupClient,\n): Promise<boolean> {\n if (process.env.TAP_HEADLESS !== \"true\") {\n return false;\n }\n\n const { candidates } = getPendingCandidates(options, cutoff);\n if (\n candidates.length > 0 ||\n client.activeTurnId ||\n client.lastTurnStatus !== null\n ) {\n return false;\n }\n\n logStatus(\"headless cold-start: sending warmup turn\");\n const turnId = await client.startTurn(HEADLESS_WARMUP_PROMPT);\n if (!turnId) {\n throw new Error(\n \"Headless cold-start warmup failed: turn/start did not return a turn id. \" +\n \"Run: npx @hua-labs/tap doctor\",\n );\n }\n\n try {\n const status = await waitForTurnCompletion(\n client,\n turnId,\n HEADLESS_WARMUP_TIMEOUT_MS,\n );\n if (status !== \"completed\") {\n throw new Error(\n `turn ${turnId} finished with status ${status ?? \"unknown\"}`,\n );\n }\n\n logStatus(`headless cold-start warmup completed (${status})`);\n return true;\n } catch (error) {\n const reason = error instanceof Error ? error.message : String(error);\n throw new Error(\n `Headless cold-start warmup failed: ${reason}. ` +\n \"Run: npx @hua-labs/tap doctor\",\n );\n }\n}\n\nfunction shouldRetrySteerAsStart(error: unknown): boolean {\n if (!(error instanceof Error)) {\n return false;\n }\n\n const message = error.message.toLowerCase();\n return (\n message.includes(\"no active turn\") ||\n message.includes(\"expectedturnid\") ||\n (message.includes(\"turn/steer failed\") &&\n (message.includes(\"active turn\") || message.includes(\"not found\")))\n );\n}\n\nasync function readSocketData(data: unknown): Promise<string> {\n if (typeof data === \"string\") {\n return data;\n }\n\n if (data instanceof ArrayBuffer) {\n return Buffer.from(data).toString(\"utf8\");\n }\n\n if (ArrayBuffer.isView(data)) {\n return Buffer.from(data.buffer, data.byteOffset, data.byteLength).toString(\n \"utf8\",\n );\n }\n\n if (typeof Blob !== \"undefined\" && data instanceof Blob) {\n return await data.text();\n }\n\n return String(data);\n}\n\nclass AppServerClient {\n private socket: WebSocket | null = null;\n private readonly url: string;\n private readonly gatewayToken: string | null;\n private readonly logger: (message: string) => void;\n private nextId = 1;\n private pending = new Map<\n number,\n {\n resolve: (value: any) => void;\n reject: (reason?: unknown) => void;\n method: string;\n }\n >();\n\n connected = false;\n initialized = false;\n threadId: string | null = null;\n activeTurnId: string | null = null;\n lastTurnStatus: string | null = null;\n lastNotificationMethod: string | null = null;\n lastNotificationAt: string | null = null;\n lastError: string | null = null;\n lastSuccessfulAppServerAt: string | null = null;\n lastSuccessfulAppServerMethod: string | null = null;\n\n constructor(\n url: string,\n logger: (message: string) => void,\n gatewayToken?: string | null,\n ) {\n this.url = url;\n this.logger = logger;\n this.gatewayToken = gatewayToken ?? null;\n }\n\n async connect(): Promise<void> {\n if (this.connected && this.socket?.readyState === WebSocket.OPEN) {\n return;\n }\n\n // Authenticate via WebSocket subprotocol instead of URL query param.\n // Token stays out of URLs (no log/referer/history leakage).\n const wsOptions: { protocols?: string[] } = {};\n if (this.gatewayToken) {\n wsOptions.protocols = [`${AUTH_SUBPROTOCOL_PREFIX}${this.gatewayToken}`];\n }\n this.socket = new WebSocket(this.url, wsOptions);\n\n await new Promise<void>((resolvePromise, rejectPromise) => {\n let settled = false;\n\n const resolveOnce = () => {\n if (settled) {\n return;\n }\n settled = true;\n resolvePromise();\n };\n\n const rejectOnce = (error: Error) => {\n if (settled) {\n return;\n }\n settled = true;\n rejectPromise(error);\n };\n\n this.socket?.addEventListener(\n \"open\",\n () => {\n this.connected = true;\n resolveOnce();\n },\n { once: true },\n );\n\n this.socket?.addEventListener(\"error\", () => {\n const error = new Error(\n `Failed to connect to App Server at ${this.url}`,\n );\n this.lastError = error.message;\n rejectOnce(error);\n });\n\n this.socket?.addEventListener(\"close\", () => {\n this.connected = false;\n this.initialized = false;\n this.activeTurnId = null;\n this.rejectPending(new Error(\"App Server connection closed\"));\n });\n\n this.socket?.addEventListener(\"message\", (event) => {\n void this.handleMessage(event.data);\n });\n });\n\n await this.request(\"initialize\", {\n clientInfo: {\n name: \"tap-app-server-bridge\",\n title: \"tap app-server bridge\",\n version: \"0.1.0\",\n },\n capabilities: {\n experimentalApi: false,\n },\n });\n this.initialized = true;\n }\n\n async disconnect(): Promise<void> {\n if (!this.socket) {\n return;\n }\n\n this.socket.close();\n this.connected = false;\n this.initialized = false;\n this.socket = null;\n }\n\n async ensureThread(\n explicitThreadId: string | null,\n resumeThreadId: string | null,\n cwd: string,\n ephemeral: boolean,\n ): Promise<string> {\n if (explicitThreadId) {\n try {\n const resumeResponse = await this.request(\"thread/resume\", {\n threadId: explicitThreadId,\n persistExtendedHistory: false,\n });\n const resumedThreadId = resumeResponse?.thread?.id ?? explicitThreadId;\n await this.refreshThreadState(resumedThreadId);\n this.logger(\n `resumed thread ${resumedThreadId}${\n this.activeTurnId ? ` (active turn ${this.activeTurnId})` : \"\"\n }`,\n );\n return resumedThreadId;\n } catch (error) {\n this.logger(\n `thread resume failed for ${explicitThreadId}; starting a fresh thread (${String(error)})`,\n );\n }\n }\n\n const loadedThreadId = await this.findLoadedThread(cwd);\n if (loadedThreadId) {\n return loadedThreadId;\n }\n\n if (resumeThreadId) {\n try {\n const resumeResponse = await this.request(\"thread/resume\", {\n threadId: resumeThreadId,\n persistExtendedHistory: false,\n });\n const resumedThreadId = resumeResponse?.thread?.id ?? resumeThreadId;\n await this.refreshThreadState(resumedThreadId);\n this.logger(\n `resumed saved thread ${resumedThreadId}${\n this.activeTurnId ? ` (active turn ${this.activeTurnId})` : \"\"\n }`,\n );\n return resumedThreadId;\n } catch (error) {\n this.logger(\n `saved thread resume failed for ${resumeThreadId}; starting a fresh thread (${String(error)})`,\n );\n }\n }\n\n const startResponse = await this.request(\"thread/start\", {\n cwd,\n ephemeral,\n experimentalRawEvents: false,\n persistExtendedHistory: false,\n });\n\n const startedThreadId = startResponse?.thread?.id;\n if (!startedThreadId) {\n throw new Error(\"thread/start did not return a thread id\");\n }\n\n this.threadId = startedThreadId;\n this.activeTurnId = null;\n this.lastTurnStatus = null;\n this.logger(`started thread ${startedThreadId}`);\n return startedThreadId;\n }\n\n async findLoadedThread(cwd: string): Promise<string | null> {\n const response = await this.request(\"thread/loaded/list\", {\n limit: 20,\n });\n const threadIds = Array.isArray(response?.data)\n ? response.data.filter(\n (value: unknown): value is string => typeof value === \"string\",\n )\n : [];\n\n if (threadIds.length === 0) {\n return null;\n }\n\n const threads: Array<{\n id: string;\n cwd: string;\n updatedAt: number;\n statusType: string | null;\n thread: any;\n }> = [];\n\n for (const threadId of threadIds) {\n try {\n const threadResponse = await this.request(\"thread/read\", {\n threadId,\n includeTurns: true,\n });\n const thread = threadResponse?.thread;\n if (!thread?.id) {\n continue;\n }\n threads.push({\n id: thread.id,\n cwd: typeof thread.cwd === \"string\" ? thread.cwd : \"\",\n updatedAt:\n typeof thread.updatedAt === \"number\" ? thread.updatedAt : 0,\n statusType: thread.status?.type ?? null,\n thread,\n });\n } catch {\n continue;\n }\n }\n\n const matching = threads.filter((thread) => thread.cwd === cwd);\n const candidates = matching.length > 0 ? matching : threads;\n if (candidates.length === 0) {\n return null;\n }\n\n candidates.sort((left, right) => {\n const leftActive = left.statusType === \"active\" ? 1 : 0;\n const rightActive = right.statusType === \"active\" ? 1 : 0;\n if (leftActive !== rightActive) {\n return rightActive - leftActive;\n }\n return right.updatedAt - left.updatedAt;\n });\n\n const chosen = candidates[0];\n this.syncThreadStateFromThread(chosen.thread);\n this.logger(\n `attached to loaded thread ${chosen.id}${\n this.activeTurnId ? ` (active turn ${this.activeTurnId})` : \"\"\n }`,\n );\n return chosen.id;\n }\n\n async startTurn(inputText: string): Promise<string | null> {\n const threadId = this.requireThreadId();\n const response = await this.request(\"turn/start\", {\n threadId,\n input: [\n {\n type: \"text\",\n text: inputText,\n text_elements: [],\n },\n ],\n });\n\n const turnId = response?.turn?.id ?? null;\n if (turnId) {\n this.activeTurnId = turnId;\n }\n return turnId;\n }\n\n async steerTurn(inputText: string): Promise<string> {\n const threadId = this.requireThreadId();\n const turnId = this.requireActiveTurnId();\n\n await this.request(\"turn/steer\", {\n threadId,\n expectedTurnId: turnId,\n input: [\n {\n type: \"text\",\n text: inputText,\n text_elements: [],\n },\n ],\n });\n\n return turnId;\n }\n\n isBusy(): boolean {\n return Boolean(this.activeTurnId);\n }\n\n async refreshCurrentThreadState(): Promise<void> {\n if (!this.threadId) {\n return;\n }\n\n await this.refreshThreadState(this.threadId);\n }\n\n private requireThreadId(): string {\n if (!this.threadId) {\n throw new Error(\"No active App Server thread is available\");\n }\n return this.threadId;\n }\n\n private requireActiveTurnId(): string {\n if (!this.activeTurnId) {\n throw new Error(\"No active turn is available for turn/steer\");\n }\n return this.activeTurnId;\n }\n\n private async refreshThreadState(threadId: string): Promise<void> {\n const threadResponse = await this.request(\"thread/read\", {\n threadId,\n includeTurns: true,\n });\n this.syncThreadStateFromThread(threadResponse?.thread);\n }\n\n private syncThreadStateFromThread(thread: any): void {\n if (typeof thread?.id === \"string\") {\n this.threadId = thread.id;\n }\n\n let activeTurnId: string | null = null;\n let lastTurnStatus: string | null = null;\n const turns = Array.isArray(thread?.turns) ? thread.turns : [];\n for (const turn of turns) {\n if (typeof turn?.status === \"string\") {\n lastTurnStatus = turn.status;\n }\n if (turn?.status === \"inProgress\" && typeof turn.id === \"string\") {\n activeTurnId = turn.id;\n }\n }\n\n this.activeTurnId = activeTurnId;\n this.lastTurnStatus = lastTurnStatus;\n }\n\n private async handleMessage(data: unknown): Promise<void> {\n const text = await readSocketData(data);\n const message = JSON.parse(text) as JsonRpcResponse;\n\n if (\n typeof message.id === \"number\" &&\n (Object.hasOwn(message, \"result\") || Object.hasOwn(message, \"error\"))\n ) {\n const pending = this.pending.get(message.id);\n if (!pending) {\n return;\n }\n\n this.pending.delete(message.id);\n if (message.error) {\n const errorText = formatJsonRpcError(message.error);\n this.lastError = errorText;\n pending.reject(new Error(`${pending.method} failed: ${errorText}`));\n return;\n }\n\n pending.resolve(message.result);\n this.lastSuccessfulAppServerAt = new Date().toISOString();\n this.lastSuccessfulAppServerMethod = pending.method;\n this.lastError = null;\n return;\n }\n\n if (!message.method) {\n return;\n }\n\n this.lastNotificationMethod = message.method;\n this.lastNotificationAt = new Date().toISOString();\n this.handleNotification(message.method, message.params);\n }\n\n private handleNotification(method: string, params: any): void {\n switch (method) {\n case \"thread/started\":\n if (params?.thread?.id) {\n this.threadId = params.thread.id;\n }\n this.logger(`thread started ${params?.thread?.id ?? \"\"}`.trim());\n break;\n case \"thread/status/changed\":\n this.logger(\n `thread status changed (${params?.thread?.status?.type ?? params?.status?.type ?? \"unknown\"})`,\n );\n break;\n case \"turn/started\":\n if (params?.turn?.id) {\n this.activeTurnId = params.turn.id;\n this.logger(`turn started ${params.turn.id}`);\n }\n break;\n case \"turn/completed\":\n this.lastTurnStatus = params?.turn?.status ?? null;\n this.activeTurnId = null;\n this.logger(`turn completed (${this.lastTurnStatus ?? \"unknown\"})`);\n break;\n case \"error\":\n this.lastError = JSON.stringify(params ?? {}, null, 2);\n this.logger(`app-server error notification: ${this.lastError}`);\n break;\n default:\n break;\n }\n }\n\n private request(method: string, params: unknown): Promise<any> {\n if (!this.socket || this.socket.readyState !== WebSocket.OPEN) {\n throw new Error(`Cannot call ${method}; App Server socket is not open`);\n }\n\n const id = this.nextId;\n this.nextId += 1;\n\n const request: RequestRecord = {\n jsonrpc: \"2.0\",\n id,\n method,\n params,\n };\n\n return new Promise((resolvePromise, rejectPromise) => {\n this.pending.set(id, {\n resolve: resolvePromise,\n reject: rejectPromise,\n method,\n });\n this.socket?.send(JSON.stringify(request));\n });\n }\n\n private rejectPending(error: Error): void {\n for (const pending of this.pending.values()) {\n pending.reject(error);\n }\n this.pending.clear();\n }\n}\n\nfunction writeHeartbeat(\n options: Options,\n client: AppServerClient | null,\n health: BridgeHealthState,\n): void {\n const payload: HeartbeatRecord = {\n pid: process.pid,\n agent: options.agentName,\n updatedAt: new Date().toISOString(),\n pollSeconds: options.pollSeconds,\n appServerUrl: options.appServerUrl,\n connected: client?.connected ?? false,\n initialized: client?.initialized ?? false,\n threadId: client?.threadId ?? null,\n activeTurnId: client?.activeTurnId ?? null,\n lastTurnStatus: client?.lastTurnStatus ?? null,\n lastNotificationMethod: client?.lastNotificationMethod ?? null,\n lastNotificationAt: client?.lastNotificationAt ?? null,\n lastError: client?.lastError ?? null,\n lastSuccessfulAppServerAt: client?.lastSuccessfulAppServerAt ?? null,\n lastSuccessfulAppServerMethod:\n client?.lastSuccessfulAppServerMethod ?? null,\n consecutiveFailureCount: health.consecutiveFailureCount,\n busyMode: options.busyMode,\n };\n\n writeFileSync(\n join(options.stateDir, \"heartbeat.json\"),\n `${JSON.stringify(payload, null, 2)}\\n`,\n \"utf8\",\n );\n}\n\nasync function dispatchCandidate(\n client: AppServerClient,\n options: Options,\n candidate: Candidate,\n heartbeats: HeartbeatStore,\n): Promise<boolean> {\n const input = buildUserInput(candidate, options.agentName, heartbeats);\n\n if (client.isBusy()) {\n if (options.busyMode !== \"steer\") {\n return false;\n }\n\n try {\n const turnId = await client.steerTurn(input);\n writeProcessedMarker(\n options.stateDir,\n candidate,\n \"steer\",\n client.threadId,\n turnId,\n );\n writeLastDispatch(\n options.stateDir,\n candidate,\n \"steer\",\n client.threadId,\n turnId,\n );\n logStatus(`steered active turn with ${candidate.fileName}`);\n return true;\n } catch (error) {\n await client.refreshCurrentThreadState().catch(() => undefined);\n\n if (!client.isBusy()) {\n return dispatchCandidate(client, options, candidate, heartbeats);\n }\n\n if (shouldRetrySteerAsStart(error)) {\n client.activeTurnId = null;\n logStatus(\n `steer fallback -> start for ${candidate.fileName} (${String(error)})`,\n );\n return dispatchCandidate(client, options, candidate, heartbeats);\n }\n\n throw error;\n }\n }\n\n const turnId = await client.startTurn(input);\n writeProcessedMarker(\n options.stateDir,\n candidate,\n \"start\",\n client.threadId,\n turnId,\n );\n writeLastDispatch(\n options.stateDir,\n candidate,\n \"start\",\n client.threadId,\n turnId,\n );\n logStatus(`dispatched ${candidate.fileName} to thread ${client.threadId}`);\n return true;\n}\n\nasync function runScan(\n options: Options,\n cutoff: Date,\n client: AppServerClient | null,\n): Promise<boolean> {\n const { heartbeats, candidates } = getPendingCandidates(options, cutoff);\n for (const candidate of candidates) {\n if (options.dryRun) {\n logStatus(`dry-run candidate ${candidate.fileName}`);\n continue;\n }\n\n if (!client) {\n throw new Error(\"App Server client is not available\");\n }\n\n const dispatched = await dispatchCandidate(\n client,\n options,\n candidate,\n heartbeats,\n );\n if (!dispatched && options.busyMode === \"wait\") {\n return false;\n }\n return true;\n }\n\n return false;\n}\n\nasync function waitForTurnDrain(\n options: Options,\n client: AppServerClient,\n health: BridgeHealthState,\n): Promise<void> {\n const deadline = Date.now() + options.waitAfterDispatchSeconds * 1_000;\n while (Date.now() < deadline) {\n writeHeartbeat(options, client, health);\n if (!client.activeTurnId) {\n return;\n }\n await delay(1_000);\n }\n}\n\nexport function buildOptions(argv: string[]): Options {\n const parsed = parseArgs(argv);\n const repoRoot = resolveRepoRoot(parsed.repoRoot);\n const commsDir = resolveCommsDir(repoRoot, parsed.commsDir);\n const preferredAgentName = resolvePreferredAgentName(parsed.agentName);\n const stateDir = resolveStateDir(\n repoRoot,\n parsed.stateDir,\n preferredAgentName,\n );\n const agentName = resolveAgentName(preferredAgentName, stateDir);\n const agentId = resolveAgentId(agentName);\n persistAgentName(stateDir, agentName);\n const gatewayTokenFile =\n parsed.gatewayTokenFile?.trim() ||\n process.env.TAP_GATEWAY_TOKEN_FILE?.trim() ||\n null;\n const appServerUrl =\n parsed.appServerUrl?.trim() ||\n process.env.CODEX_APP_SERVER_URL ||\n DEFAULT_APP_SERVER_URL;\n\n return {\n repoRoot,\n commsDir,\n agentId,\n stateDir,\n agentName,\n pollSeconds: parsed.pollSeconds ?? 5,\n reconnectSeconds: parsed.reconnectSeconds ?? 5,\n messageLookbackMinutes: parsed.messageLookbackMinutes ?? 10,\n processExistingMessages: parsed.processExistingMessages,\n dryRun: parsed.dryRun,\n runOnce: parsed.runOnce,\n waitAfterDispatchSeconds: parsed.waitAfterDispatchSeconds ?? 0,\n appServerUrl,\n connectAppServerUrl: appServerUrl,\n gatewayToken: gatewayTokenFile\n ? readGatewayTokenFile(gatewayTokenFile)\n : null,\n gatewayTokenFile,\n busyMode: parsed.busyMode ?? \"steer\",\n threadId: parsed.threadId?.trim() || null,\n ephemeral: parsed.ephemeral,\n };\n}\n\nexport async function main(): Promise<void> {\n const options = buildOptions(process.argv.slice(2));\n const cutoff = getGeneralInboxCutoff(\n options.stateDir,\n options.messageLookbackMinutes,\n options.processExistingMessages,\n );\n const savedThread = readThreadState(options.stateDir);\n\n logStatus(\"codex app-server bridge ready\");\n console.log(` repo: ${options.repoRoot}`);\n console.log(` comms: ${options.commsDir}`);\n console.log(` agent: ${options.agentName}`);\n console.log(` state: ${options.stateDir}`);\n console.log(` app-server: ${options.appServerUrl}`);\n console.log(` busy-mode: ${options.busyMode}`);\n if (options.waitAfterDispatchSeconds > 0) {\n console.log(\n ` wait: ${options.waitAfterDispatchSeconds}s after dispatch`,\n );\n }\n console.log(\n ` lookback: ${\n options.processExistingMessages\n ? \"existing messages\"\n : `${options.messageLookbackMinutes} minute(s)`\n }`,\n );\n if (options.threadId || savedThread?.threadId) {\n console.log(` thread: ${options.threadId ?? savedThread?.threadId}`);\n }\n if (options.dryRun) {\n logStatus(\"dry-run mode enabled\");\n }\n\n let client: AppServerClient | null = null;\n let savedThreadId = savedThread?.threadId ?? null;\n const health: BridgeHealthState = {\n consecutiveFailureCount: 0,\n };\n\n while (true) {\n try {\n if (!options.dryRun) {\n if (!client || !client.connected) {\n client = new AppServerClient(\n options.connectAppServerUrl,\n logStatus,\n options.gatewayToken,\n );\n await client.connect();\n\n const threadId = await client.ensureThread(\n options.threadId,\n savedThreadId,\n options.repoRoot,\n options.ephemeral,\n );\n persistThreadState(\n options.stateDir,\n threadId,\n options.appServerUrl,\n options.ephemeral,\n );\n savedThreadId = threadId;\n writeHeartbeat(options, client, health);\n const bootstrapped = await maybeBootstrapHeadlessTurn(\n options,\n cutoff,\n client,\n );\n if (bootstrapped) {\n writeHeartbeat(options, client, health);\n }\n }\n }\n\n const dispatched = await runScan(options, cutoff, client);\n if (dispatched && client && options.waitAfterDispatchSeconds > 0) {\n await waitForTurnDrain(options, client, health);\n }\n health.consecutiveFailureCount = 0;\n writeHeartbeat(options, client, health);\n\n if (options.runOnce) {\n break;\n }\n\n await delay(options.pollSeconds * 1_000);\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n logStatus(`bridge error: ${message}`);\n if (client) {\n client.lastError = message;\n }\n health.consecutiveFailureCount += 1;\n writeHeartbeat(options, client, health);\n\n if (options.runOnce) {\n throw error;\n }\n\n client?.disconnect().catch(() => undefined);\n client = null;\n await delay(options.reconnectSeconds * 1_000);\n }\n }\n\n await client?.disconnect();\n}\n\nfunction isDirectExecution(): boolean {\n const entry = process.argv[1];\n if (!entry) return false;\n return import.meta.url === pathToFileURL(resolve(entry)).href;\n}\n\nif (isDirectExecution()) {\n main().catch((error) => {\n console.error(\n error instanceof Error ? (error.stack ?? error.message) : String(error),\n );\n process.exitCode = 1;\n });\n}\n"],"mappings":"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","names":["pathToFileURL","resolve","turnId","isDirectExecution","pathToFileURL","resolve"]}