grok-bot-cli 0.4.0 → 0.4.2

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.
@@ -13884,6 +13884,140 @@ __webpack_require__.d(__webpack_exports__, {
13884
13884
  });
13885
13885
 
13886
13886
 
13887
+ },
13888
+ "./src/cli/codex/desktop-shim.tsx"(__unused_rspack_module, __webpack_exports__, __webpack_require__) {
13889
+ __webpack_require__.r(__webpack_exports__);
13890
+ /* import */ var react_jsx_runtime__rspack_import_0 = __webpack_require__("./node_modules/react/jsx-runtime.react-server.js");
13891
+ /* import */ var _agent_bundle_runtime__rspack_import_3 = __webpack_require__("./node_modules/@agent-bundle/runtime/dist/506.js");
13892
+ /* import */ var zod__rspack_import_2 = __webpack_require__("./node_modules/zod/v4/classic/schemas.js");
13893
+ /* import */ var _core_desktop_shim_js__rspack_import_1 = __webpack_require__("./src/core/desktop-shim.js");
13894
+ /* import */ var _core_format_js__rspack_import_4 = __webpack_require__("./src/core/format.js");
13895
+
13896
+
13897
+
13898
+
13899
+
13900
+ const config = {
13901
+ description: 'Install, remove, or check the ChatGPT Desktop shim: a CODEX_CLI_PATH wrapper that bridges Desktop stdio onto the managed Codex daemon (stock app-server proxy hangs). macOS persists via LaunchAgent; always fails open to real Codex.',
13902
+ exitCode: 'result',
13903
+ inputJsonSchema: {
13904
+ additionalProperties: false,
13905
+ properties: {
13906
+ action: {
13907
+ description: 'install | uninstall | status',
13908
+ enum: [
13909
+ 'install',
13910
+ 'uninstall',
13911
+ 'status'
13912
+ ],
13913
+ type: 'string'
13914
+ }
13915
+ },
13916
+ required: [
13917
+ 'action'
13918
+ ],
13919
+ type: 'object'
13920
+ },
13921
+ positionals: [
13922
+ 'action'
13923
+ ]
13924
+ };
13925
+ const inputSchema = zod__rspack_import_2/* .object */.Ikc({
13926
+ action: zod__rspack_import_2/* ["enum"] */.k5n([
13927
+ 'install',
13928
+ 'uninstall',
13929
+ 'status'
13930
+ ])
13931
+ }).strict();
13932
+ const resultSchema = zod__rspack_import_2/* .object */.Ikc({
13933
+ exitCode: zod__rspack_import_2/* .union */.KCZ([
13934
+ zod__rspack_import_2/* .literal */.euz(0),
13935
+ zod__rspack_import_2/* .literal */.euz(1)
13936
+ ])
13937
+ }).passthrough();
13938
+ const formatWarnings = (warnings)=>warnings.length === 0 ? '' : `\nwarnings:\n${warnings.map((w)=>` - ${String(w)}`).join('\n')}`;
13939
+ async function codexDesktopShim({ input }) {
13940
+ switch(input.action){
13941
+ case 'install':
13942
+ {
13943
+ let out;
13944
+ try {
13945
+ out = (0,_core_desktop_shim_js__rspack_import_1/* .installDesktopShim */.B0)();
13946
+ } catch (error) {
13947
+ const message = error instanceof Error ? error.message : String(error);
13948
+ return /*#__PURE__*/ (0,react_jsx_runtime__rspack_import_0.jsx)(_agent_bundle_runtime__rspack_import_3/* .Agent.Result */.g6.Result, {
13949
+ value: {
13950
+ action: 'install',
13951
+ error: message,
13952
+ exitCode: 1
13953
+ },
13954
+ children: /*#__PURE__*/ (0,react_jsx_runtime__rspack_import_0.jsx)(_agent_bundle_runtime__rspack_import_3/* .Agent.Text */.g6.Text, {
13955
+ children: `Desktop shim install failed: ${message}`
13956
+ })
13957
+ });
13958
+ }
13959
+ const text = `Installed ChatGPT Desktop shim:\n` + ` wrapper: ${out.wrapperPath}\n` + ` bridge: ${out.bridgePath}\n` + ` login env: ${out.envScriptPath}` + (out.plistPath ? `\n LaunchAgent: ${out.plistPath}` : '\n LaunchAgent: n/a (macOS-only)') + `\nFully quit and relaunch ChatGPT.app so it inherits CODEX_CLI_PATH; ` + `Desktop falls back to stock Codex if the shim is ever removed.` + formatWarnings(out.warnings);
13960
+ return /*#__PURE__*/ (0,react_jsx_runtime__rspack_import_0.jsx)(_agent_bundle_runtime__rspack_import_3/* .Agent.Result */.g6.Result, {
13961
+ value: out,
13962
+ children: /*#__PURE__*/ (0,react_jsx_runtime__rspack_import_0.jsx)(_agent_bundle_runtime__rspack_import_3/* .Agent.Text */.g6.Text, {
13963
+ children: text
13964
+ })
13965
+ });
13966
+ }
13967
+ case 'uninstall':
13968
+ {
13969
+ let out;
13970
+ try {
13971
+ out = (0,_core_desktop_shim_js__rspack_import_1/* .uninstallDesktopShim */.gM)();
13972
+ } catch (error) {
13973
+ const message = error instanceof Error ? error.message : String(error);
13974
+ return /*#__PURE__*/ (0,react_jsx_runtime__rspack_import_0.jsx)(_agent_bundle_runtime__rspack_import_3/* .Agent.Result */.g6.Result, {
13975
+ value: {
13976
+ action: 'uninstall',
13977
+ error: message,
13978
+ exitCode: 1
13979
+ },
13980
+ children: /*#__PURE__*/ (0,react_jsx_runtime__rspack_import_0.jsx)(_agent_bundle_runtime__rspack_import_3/* .Agent.Text */.g6.Text, {
13981
+ children: `Desktop shim uninstall failed: ${message}`
13982
+ })
13983
+ });
13984
+ }
13985
+ const removed = out.removed.length === 0 ? '(nothing installed)' : out.removed.join(', ');
13986
+ const text = `Removed ChatGPT Desktop shim: ${removed}. ` + `Desktop and Codex fall back to stock behavior; relaunch ChatGPT.app to pick it up.` + formatWarnings(out.warnings);
13987
+ return /*#__PURE__*/ (0,react_jsx_runtime__rspack_import_0.jsx)(_agent_bundle_runtime__rspack_import_3/* .Agent.Result */.g6.Result, {
13988
+ value: out,
13989
+ children: /*#__PURE__*/ (0,react_jsx_runtime__rspack_import_0.jsx)(_agent_bundle_runtime__rspack_import_3/* .Agent.Text */.g6.Text, {
13990
+ children: text
13991
+ })
13992
+ });
13993
+ }
13994
+ case 'status':
13995
+ {
13996
+ const out = (0,_core_desktop_shim_js__rspack_import_1/* .desktopShimStatus */.em)();
13997
+ return /*#__PURE__*/ (0,react_jsx_runtime__rspack_import_0.jsx)(_agent_bundle_runtime__rspack_import_3/* .Agent.Result */.g6.Result, {
13998
+ value: out,
13999
+ children: /*#__PURE__*/ (0,react_jsx_runtime__rspack_import_0.jsx)(_agent_bundle_runtime__rspack_import_3/* .Agent.Text */.g6.Text, {
14000
+ children: (0,_core_format_js__rspack_import_4/* .formatDesktopShimStatus */.fX)(out)
14001
+ })
14002
+ });
14003
+ }
14004
+ default:
14005
+ {
14006
+ const _exhaustive = input.action;
14007
+ throw new Error(`unknown desktop-shim action: ${String(_exhaustive)}`);
14008
+ }
14009
+ }
14010
+ }
14011
+
14012
+ __webpack_require__.d(__webpack_exports__, {
14013
+ "default": () => (codexDesktopShim)
14014
+ }, {
14015
+ config: config,
14016
+ inputSchema: inputSchema,
14017
+ resultSchema: resultSchema
14018
+ });
14019
+
14020
+
13887
14021
  },
13888
14022
  "./src/cli/codex/list-threads.tsx"(__unused_rspack_module, __webpack_exports__, __webpack_require__) {
13889
14023
  __webpack_require__.r(__webpack_exports__);
@@ -26303,6 +26437,9 @@ const textDecoder = new TextDecoder("utf-8", {
26303
26437
  });
26304
26438
  const pkg = (0,node_module__rspack_import_6.createRequire)(import.meta.url)("../../package.json");
26305
26439
  function codexSocketPath(env = process.env) {
26440
+ // Explicit socket wins so status/send/queue agree with a shim-installed or
26441
+ // operator-exported CODEX_APP_SERVER_SOCK; otherwise derive from CODEX_HOME.
26442
+ if (env.CODEX_APP_SERVER_SOCK) return env.CODEX_APP_SERVER_SOCK;
26306
26443
  const home = env.CODEX_HOME || (0,node_path__rspack_import_4.join)((0,node_os__rspack_import_3.homedir)(), ".codex");
26307
26444
  return (0,node_path__rspack_import_4.join)(home, "app-server-control", "app-server-control.sock");
26308
26445
  }
@@ -26319,7 +26456,15 @@ function codexSocketPath(env = process.env) {
26319
26456
  /** Single-line fields (ids, names, paths, cursors, header tokens): no line breaks or tabs survive. */ function singleLine(text) {
26320
26457
  return stripTerminalControls(text).replace(/[\t\n\r\u2028\u2029]+/g, " ");
26321
26458
  }
26322
- function unreachableMessage(path) {
26459
+ function unreachableMessage(path, desktopAttached = "unknown") {
26460
+ if (desktopAttached === "private-stdio") {
26461
+ return [
26462
+ "ChatGPT Desktop is running its private stdio app-server, which external clients cannot reach",
26463
+ "(" + UPSTREAM_DESKTOP_ISSUES.join(", ") + ").",
26464
+ "No Codex app-server control socket at " + path + ": start a managed standalone daemon with `codex app-server daemon start`.",
26465
+ "gbot codex targets daemon-managed threads only."
26466
+ ].join("\n");
26467
+ }
26323
26468
  return [
26324
26469
  "No Codex app-server control socket at " + path + ".",
26325
26470
  "Either no daemon is running (start one with `codex app-server daemon start`),",
@@ -26522,6 +26667,12 @@ function isObject(value) {
26522
26667
  const sendJson = (obj)=>write(0x1, Buffer.from(JSON.stringify(obj)));
26523
26668
  const client = {
26524
26669
  refused,
26670
+ // Server-initiated requests are only *answered* once our own turn/start
26671
+ // is in flight: anything earlier belongs to another client's turn
26672
+ // (notably Desktop's) and must never be rejected on their behalf. Early
26673
+ // requests are still recorded; the connection closes right after, so a
26674
+ // pending request simply dies with it instead of denying someone's approval.
26675
+ answerServerRequests: false,
26525
26676
  request (method, params) {
26526
26677
  const id = nextId++;
26527
26678
  return new Promise((res, rej)=>{
@@ -26585,11 +26736,14 @@ function isObject(value) {
26585
26736
  };
26586
26737
  const onMessage = (msg)=>{
26587
26738
  if (msg.id != null && msg.method) {
26739
+ const answered = client.answerServerRequests;
26588
26740
  refused.push({
26589
26741
  id: msg.id,
26590
26742
  method: msg.method,
26591
- params: msg.params
26743
+ params: msg.params,
26744
+ answered
26592
26745
  });
26746
+ if (!answered) return;
26593
26747
  sendJson({
26594
26748
  jsonrpc: "2.0",
26595
26749
  id: msg.id,
@@ -26793,32 +26947,84 @@ const CODEX_VERSION_PROBE_TIMEOUT_MS = 3000;
26793
26947
  probe: "error"
26794
26948
  };
26795
26949
  }
26950
+ /** Bounded `ps` snapshot for Desktop detection: process names only, never pipes or sockets. */ const DESKTOP_PROCESS_LIST_TIMEOUT_MS = 3000;
26951
+ function listDesktopProcesses(timeoutMs = DESKTOP_PROCESS_LIST_TIMEOUT_MS) {
26952
+ if (process.platform === "win32") return "";
26953
+ try {
26954
+ const out = (0,node_child_process__rspack_import_5.spawnSync)("ps", [
26955
+ "-eo",
26956
+ "args"
26957
+ ], {
26958
+ encoding: "utf8",
26959
+ timeout: timeoutMs
26960
+ });
26961
+ if (out.error || out.status !== 0 || typeof out.stdout !== "string") return "";
26962
+ return out.stdout;
26963
+ } catch {
26964
+ return "";
26965
+ }
26966
+ }
26967
+ /**
26968
+ * Pure Desktop private-stdio detector. Returns `"private-stdio"` when the process list
26969
+ * shows Desktop's bundled `.../ChatGPT.app/.../Resources/codex` running `app-server`
26970
+ * (the `codex_app` override corroborates, the Resources path alone suffices); `"unknown"`
26971
+ * otherwise. Never `"detached"`: absence of a match means "not observed", not "not running".
26972
+ * Windows stays `"unknown"` (unsupported route, unchanged).
26973
+ *
26974
+ * @param {{ platform?: string, listProcesses?: string | string[] | null }} [opts]
26975
+ */ function detectDesktopPrivateAppServer({ platform = process.platform, listProcesses = "" } = {}) {
26976
+ if (platform === "win32") return "unknown";
26977
+ const lines = Array.isArray(listProcesses) ? listProcesses : String(listProcesses ?? "").split(/\r?\n/);
26978
+ for (const line of lines){
26979
+ if (!/app-server/.test(line)) continue;
26980
+ // Desktop's bundled binary, Mac or Windows-style separators with optional .exe.
26981
+ if (/ChatGPT\.app[\\/].*Resources[\\/]codex(\.exe)?(["'\s]|$)/.test(line)) return "private-stdio";
26982
+ // Same app-server line owned by ChatGPT.app carrying the app-tools override.
26983
+ if (/ChatGPT\.app/.test(line) && /(codex_app|mcp_servers\.codex_app|codex-app-tools)/.test(line)) return "private-stdio";
26984
+ }
26985
+ return "unknown";
26986
+ }
26796
26987
  /**
26797
26988
  * Status contract: `reachable` is endpoint reachability only. `schema.compatibility` is
26798
26989
  * `exact` when the daemon reports the pinned version, otherwise `unverified` (methods
26799
- * usually survive upgrades) or `unknown`. Whether ChatGPT Desktop owns any thread is not
26800
- * observable from the socket, so `desktopAttached` is always `"unknown"`.
26801
- */ async function codexStatus(env = process.env) {
26990
+ * usually survive upgrades) or `unknown`. `desktopAttached` is `"private-stdio"` when a
26991
+ * Desktop-bundled app-server process is visible (see `detectDesktopPrivateAppServer`),
26992
+ * otherwise `"unknown"` — whether Desktop owns any thread is never observable from the
26993
+ * socket itself, and `"detached"` is never reported.
26994
+ *
26995
+ * @param {NodeJS.ProcessEnv} [env]
26996
+ * @param {{ listProcesses?: string | string[] }} [opts] injected process list for tests;
26997
+ * defaults to a live `ps` snapshot. Never reads pipes or connects to Desktop.
26998
+ */ async function codexStatus(env = process.env, { listProcesses } = {}) {
26802
26999
  const path = codexSocketPath(env);
26803
27000
  const cli = probeLocalCodexVersion();
27001
+ const desktopAttached = detectDesktopPrivateAppServer({
27002
+ platform: process.platform,
27003
+ listProcesses: listProcesses ?? listDesktopProcesses()
27004
+ });
26804
27005
  const base = {
26805
27006
  socketPath: path,
26806
27007
  socketState: socketState(path),
26807
27008
  pinnedVersion: PINNED_CODEX_VERSION,
26808
27009
  cliVersion: cli.version,
26809
27010
  cliVersionProbe: cli.probe,
26810
- desktopAttached: "unknown"
27011
+ desktopAttached
26811
27012
  };
26812
27013
  let session;
26813
27014
  try {
26814
27015
  session = await openSession(env);
26815
27016
  } catch (err) {
26816
- if (err instanceof CodexRouteError) return (0,_codex_contract_js__rspack_import_7/* .withStatusExitCode */.AQ)({
26817
- ...base,
26818
- reachable: false,
26819
- mode: err.mode,
26820
- message: err.message
26821
- });
27017
+ if (err instanceof CodexRouteError) {
27018
+ // Name the private-stdio case explicitly: Desktop is up but unreachable, so the
27019
+ // operator needs a managed standalone daemon, not a Desktop reconnect.
27020
+ const message = err.mode === "socket-absent" ? unreachableMessage(path, desktopAttached) : err.message;
27021
+ return (0,_codex_contract_js__rspack_import_7/* .withStatusExitCode */.AQ)({
27022
+ ...base,
27023
+ reachable: false,
27024
+ mode: err.mode,
27025
+ message
27026
+ });
27027
+ }
26822
27028
  // The endpoint answered; what it said does not match the pinned schema.
26823
27029
  if (err instanceof CodexProtocolError) return (0,_codex_contract_js__rspack_import_7/* .withStatusExitCode */.AQ)({
26824
27030
  ...base,
@@ -27204,6 +27410,12 @@ async function sendToCodexThreadInner(threadId, text, { env, envelope, whenBusy
27204
27410
  // the daemon exposes no compare-and-start request. Upgrade path: thread/queue/add + thread/queue/start once stable.
27205
27411
  // Scope refusals to this turn: server requests from earlier calls belong to another context.
27206
27412
  const seenRefused = client.refused.length;
27413
+ // Arm refusal replies only now that our own turn/start is in flight: an
27414
+ // approval arriving in this window plausibly belongs to our turn. Anything
27415
+ // recorded earlier (resume, busy reject, queue) stays unanswered so gbot
27416
+ // never rejects another client's approval. Residual race: a concurrent
27417
+ // foreign approval inside this window is indistinguishable from ours.
27418
+ client.answerServerRequests = true;
27207
27419
  let turn;
27208
27420
  try {
27209
27421
  turn = await client.request("turn/start", {
@@ -27238,7 +27450,7 @@ async function sendToCodexThreadInner(threadId, text, { env, envelope, whenBusy
27238
27450
  envelope
27239
27451
  });
27240
27452
  }
27241
- const freshRefused = client.refused.slice(seenRefused).filter((r)=>!r.params || r.params.threadId == null || r.params.threadId === threadId);
27453
+ const freshRefused = client.refused.slice(seenRefused).filter((r)=>r.answered && (!r.params || r.params.threadId == null || r.params.threadId === threadId));
27242
27454
  if (freshRefused.length) {
27243
27455
  const methods = freshRefused.map((r)=>r.method).join(", ");
27244
27456
  throw new CodexSendError("Turn " + turnId + " started on thread " + threadId + " but Codex asked for " + methods + ", which gbot refused. " + "Answer it in a Codex client, or set `approval_policy = \"never\"` in the daemon's config.toml for unattended sends.", {
@@ -27268,7 +27480,8 @@ __webpack_require__.d(__webpack_exports__, {
27268
27480
  X$: () => (listCodexThreads),
27269
27481
  ZS: () => (sendToCodexThread),
27270
27482
  nq: () => (buildEnvelope),
27271
- pF: () => (singleLine)
27483
+ pF: () => (singleLine),
27484
+ ql: () => (codexSocketPath)
27272
27485
  });
27273
27486
 
27274
27487
 
@@ -27474,6 +27687,534 @@ __webpack_require__.d(__webpack_exports__, {
27474
27687
  });
27475
27688
 
27476
27689
 
27690
+ },
27691
+ "./src/core/desktop-shim-bridge.js"(__unused_rspack___webpack_module__, __webpack_exports__, __webpack_require__) {
27692
+ // Stdio JSONL (Desktop) <-> WebSocket-over-unix bridge onto the managed
27693
+ // Codex app-server control socket. Vendored from uploads/codex-stdio-to-daemon-ws.py
27694
+ // (ChatGPT Desktop -> managed daemon shim) with fail-open deltas, marked below:
27695
+ // (1) ws_connect enforces one absolute monotonic deadline for connect + HTTP
27696
+ // upgrade (CODEX_BRIDGE_CONNECT_TIMEOUT, default 10s), validates the 101 status
27697
+ // and Sec-WebSocket-Accept, and retains bytes coalesced after the upgrade
27698
+ // headers instead of discarding the first data frame.
27699
+ // (2) read_message assembles continuation frames; control frames answer inline;
27700
+ // socket writes are serialized with a lock shared by both threads.
27701
+ // (3) A first-message deadline (CODEX_BRIDGE_FIRST_MESSAGE_TIMEOUT, default
27702
+ // 30s) bounds connect-to-first-daemon-message covering the first RPC; the
27703
+ // preflight (3s) + upgrade (10s) + first RPC (30s) budget stays far below a
27704
+ // daemon-lock hang. Exits are 0 served, 1 pre-stdio (wrapper falls back to
27705
+ // real Codex), 2 mid-session (wrapper exits so Desktop reconnects).
27706
+ // (4) Byte-precise commit: os.read into a userspace line buffer counts every
27707
+ // stdin byte (buffered readline could readahead past the commit point), so the
27708
+ // fallback only ever runs on a truly pristine stdio. The reader signals a done
27709
+ // event so WS close wakes the select loop; no path leaves a thread hung.
27710
+ // Desktop stdio hangs with stock `codex app-server proxy`, so this custom
27711
+ // bridge is required. Install writes it to the CODEX_HOME bin dir. Never reads
27712
+ // Desktop private pipes (CODEX_APP_TOOLS_PIPE_PATH, /tmp/codex-browser-use/).
27713
+ const BRIDGE_SOURCE = "#!/usr/bin/env python3\n\"\"\"Stdio JSONL (Desktop) <-> WebSocket-over-unix (managed app-server daemon).\nReversible: remove CODEX_CLI_PATH wrapper. Does not read Desktop private pipes.\n\"\"\"\nfrom __future__ import annotations\nimport base64, hashlib, json, os, select, socket, struct, sys, threading, time\n\nSOCK = os.environ.get(\n \"CODEX_APP_SERVER_SOCK\",\n os.path.expanduser(\"~/.codex/app-server-control/app-server-control.sock\"),\n)\nLOG = os.environ.get(\"CODEX_STDIO_BRIDGE_LOG\", os.path.expanduser(\"~/.codex/bin/codex-stdio-to-daemon-ws.log\"))\nWS_GUID = \"258EAFA5-E914-47DA-95CA-C5AB0DC85B11\"\n\n# Wrapper contract: 0 served the session, 1 failed before any stdin was\n# consumed (wrapper falls back to real Codex on pristine stdio), 2 failed\n# mid-session (wrapper exits promptly so Desktop reconnects; the fallback\n# must never run on half-consumed stdin).\nEXIT_SERVED = 0\nEXIT_PRE_STDIO = 1\nEXIT_MID_SESSION = 2\n\nCONNECT_TIMEOUT_S = float(os.environ.get(\"CODEX_BRIDGE_CONNECT_TIMEOUT\", \"10\"))\n# Bound from connect to the first daemon message: a daemon that completes the\n# upgrade but never answers the first RPC must not hold Desktop past this.\nFIRST_MESSAGE_TIMEOUT_S = float(os.environ.get(\"CODEX_BRIDGE_FIRST_MESSAGE_TIMEOUT\", \"30\"))\n\ndef log(msg: str) -> None:\n try:\n with open(LOG, \"a\") as f:\n f.write(time.strftime(\"%Y-%m-%dT%H:%M:%SZ\", time.gmtime()) + \" \" + msg + \"\\n\")\n except OSError:\n pass\n\ndef ws_connect(path: str, timeout: float = CONNECT_TIMEOUT_S):\n \"\"\"Connect + HTTP upgrade under one absolute monotonic deadline.\n\n Returns (socket, trailing) where trailing holds bytes coalesced after the\n upgrade headers (TCP may deliver the 101 and the first WS frame together;\n discarding them would lose the first message). Validates the 101 status\n and Sec-WebSocket-Accept so a non-WebSocket listener fails fast.\n \"\"\"\n deadline = time.monotonic() + timeout\n s = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)\n s.settimeout(timeout)\n try:\n s.connect(path)\n key = base64.b64encode(os.urandom(16)).decode()\n expected = base64.b64encode(hashlib.sha1((key + WS_GUID).encode()).digest()).decode()\n req = (\n f\"GET /rpc HTTP/1.1\\r\\nHost: localhost\\r\\nUpgrade: websocket\\r\\n\"\n f\"Connection: Upgrade\\r\\nSec-WebSocket-Key: {key}\\r\\nSec-WebSocket-Version: 13\\r\\n\\r\\n\"\n ).encode()\n s.sendall(req)\n buf = b\"\"\n while True:\n if b\"\\r\\n\\r\\n\" in buf:\n break\n remaining = deadline - time.monotonic()\n if remaining <= 0:\n raise TimeoutError(\"WebSocket upgrade timed out\")\n if len(buf) > 65536:\n raise ConnectionError(\"WS upgrade headers too large\")\n s.settimeout(remaining)\n chunk = s.recv(4096)\n if not chunk:\n raise ConnectionError(\"daemon closed during WS upgrade\")\n buf += chunk\n head, _, trailing = buf.partition(b\"\\r\\n\\r\\n\")\n lines = head.split(b\"\\r\\n\")\n if b\"101\" not in lines[0]:\n raise ConnectionError(f\"WS upgrade failed: {head[:200]!r}\")\n accept = None\n for line in lines[1:]:\n name, sep, value = line.partition(b\":\")\n if sep and name.strip().lower() == b\"sec-websocket-accept\":\n accept = value.strip().decode(\"latin-1\")\n if accept != expected:\n raise ConnectionError(\"WS upgrade accept mismatch\")\n except Exception:\n try:\n s.close()\n except OSError:\n pass\n raise\n s.settimeout(None)\n return s, trailing\n\ndef mask_send(sock: socket.socket, payload: bytes, opcode: int = 1) -> None:\n mask = os.urandom(4)\n ln = len(payload)\n if ln < 126:\n hdr = bytes([0x80 | opcode, 0x80 | ln])\n elif ln < 65536:\n hdr = bytes([0x80 | opcode, 0x80 | 126]) + struct.pack(\"!H\", ln)\n else:\n hdr = bytes([0x80 | opcode, 0x80 | 127]) + struct.pack(\"!Q\", ln)\n sock.sendall(hdr + mask + bytes(b ^ mask[i % 4] for i, b in enumerate(payload)))\n\ndef locked_send(sock: socket.socket, lock: threading.Lock, payload: bytes, opcode: int = 1) -> None:\n with lock:\n mask_send(sock, payload, opcode=opcode)\n\ndef _buffered_reader(sock: socket.socket, initial: bytes = b\"\"):\n buf = bytearray(initial)\n def recv(n):\n while len(buf) < n:\n chunk = sock.recv(n - len(buf))\n if not chunk:\n raise ConnectionError(\"eof\")\n buf.extend(chunk)\n out = bytes(buf[:n])\n del buf[:n]\n return out\n return recv\n\ndef read_frame(recv):\n hdr = recv(2)\n fin = bool(hdr[0] & 0x80)\n opcode = hdr[0] & 0x0F\n masked = bool(hdr[1] & 0x80)\n ln = hdr[1] & 0x7F\n if ln == 126:\n ln = struct.unpack(\"!H\", recv(2))[0]\n elif ln == 127:\n ln = struct.unpack(\"!Q\", recv(8))[0]\n mask = recv(4) if masked else b\"\"\n payload = recv(ln)\n if masked:\n payload = bytes(b ^ mask[i % 4] for i, b in enumerate(payload))\n return fin, opcode, payload\n\ndef read_message(recv, send_pong):\n \"\"\"Next complete data message, assembling continuation frames.\n\n Control frames are handled inline (pong answered, close reported) so a\n fragmented message split around a ping still reassembles.\n \"\"\"\n opcode = None\n parts = []\n while True:\n fin, op, payload = read_frame(recv)\n if op == 0x8:\n return (\"close\", None, b\"\")\n if op == 0x9:\n send_pong(payload)\n continue\n if op == 0xA:\n continue\n if op in (0x1, 0x2):\n if opcode is not None:\n raise ConnectionError(\"data frame inside fragmented message\")\n if fin:\n return (\"data\", op, payload)\n opcode = op\n parts.append(payload)\n continue\n if op == 0x0:\n if opcode is None:\n raise ConnectionError(\"stray continuation frame\")\n parts.append(payload)\n if fin:\n return (\"data\", opcode, b\"\".join(parts))\n continue\n raise ConnectionError(f\"unsupported opcode {op}\")\n\ndef stdout_writer(sock: socket.socket, recv, send_pong, done: threading.Event, first_msg: threading.Event) -> None:\n out = sys.stdout.buffer\n try:\n while True:\n kind, opcode, payload = read_message(recv, send_pong)\n if kind == \"close\":\n log(\"daemon WS close\")\n return\n if opcode == 0x1:\n # Desktop StdioConnection expects newline-delimited JSON text\n if not payload.endswith(b\"\\n\"):\n payload += b\"\\n\"\n out.write(payload)\n out.flush()\n else:\n out.write(payload)\n out.flush()\n first_msg.set()\n except Exception as e:\n log(f\"stdout_writer exit: {e}\")\n finally:\n done.set()\n\ndef main() -> int:\n log(f\"start sock={SOCK}\")\n try:\n sock, pending = ws_connect(SOCK)\n except Exception as e:\n log(f\"connect failed: {e}\")\n sys.stderr.write(f\"codex-stdio-to-daemon-ws: {e}\\n\")\n return EXIT_PRE_STDIO\n log(\"connected\")\n connected_at = time.monotonic()\n send_lock = threading.Lock()\n def send_pong(payload: bytes) -> None:\n locked_send(sock, send_lock, payload, opcode=0xA)\n recv = _buffered_reader(sock, pending)\n done = threading.Event()\n first_msg = threading.Event()\n t = threading.Thread(target=stdout_writer, args=(sock, recv, send_pong, done, first_msg), daemon=True)\n t.start()\n # Byte-precise commit point: the fallback may run only while zero stdin\n # bytes have left the pipe. Reads use os.read into a userspace line buffer\n # (buffered readline could readahead past the commit point), and every\n # byte read counts — even a blank line. first_msg bounds the first RPC.\n stdin_bytes = 0\n pending_in = b\"\"\n clean_eof = False\n try:\n fd = sys.stdin.fileno()\n while not done.is_set():\n if not first_msg.is_set() and time.monotonic() - connected_at > FIRST_MESSAGE_TIMEOUT_S:\n log(\"first daemon message timed out\")\n break\n ready, _, _ = select.select([fd], [], [], 0.5)\n if not ready:\n continue\n chunk = os.read(fd, 65536)\n if not chunk:\n clean_eof = True\n break\n stdin_bytes += len(chunk)\n pending_in += chunk\n while b\"\\n\" in pending_in:\n line, _, pending_in = pending_in.partition(b\"\\n\")\n line = line.strip()\n if not line:\n continue\n locked_send(sock, send_lock, line)\n except Exception as e:\n log(f\"stdin loop exit: {e}\")\n try:\n locked_send(sock, send_lock, b\"\", opcode=0x8)\n except Exception:\n pass\n if clean_eof:\n tail = pending_in.strip()\n if tail and not done.is_set():\n try:\n locked_send(sock, send_lock, tail)\n except Exception as e:\n log(f\"eof flush failed: {e}\")\n log(\"exit\")\n return EXIT_SERVED\n # Reader died, first RPC timed out, or stdin broke: fail open only if no\n # stdin byte was ever consumed.\n rc = EXIT_MID_SESSION if stdin_bytes else EXIT_PRE_STDIO\n log(f\"exit rc={rc}\")\n return rc\n\nif __name__ == \"__main__\":\n raise SystemExit(main())\n";
27714
+
27715
+ __webpack_require__.d(__webpack_exports__, {
27716
+ }, {
27717
+ w: BRIDGE_SOURCE
27718
+ });
27719
+
27720
+
27721
+ },
27722
+ "./src/core/desktop-shim.js"(__unused_rspack___webpack_module__, __webpack_exports__, __webpack_require__) {
27723
+ /* import */ var node_child_process__rspack_import_0 = __webpack_require__("node:child_process");
27724
+ /* import */ var node_fs__rspack_import_1 = __webpack_require__("node:fs");
27725
+ /* import */ var node_os__rspack_import_2 = __webpack_require__("node:os");
27726
+ /* import */ var node_path__rspack_import_3 = __webpack_require__("node:path");
27727
+ /* import */ var _desktop_shim_bridge_js__rspack_import_5 = __webpack_require__("./src/core/desktop-shim-bridge.js");
27728
+ /* import */ var _codex_bridge_js__rspack_import_4 = __webpack_require__("./src/core/codex-bridge.js");
27729
+
27730
+
27731
+
27732
+
27733
+
27734
+
27735
+ /**
27736
+ * ChatGPT Desktop -> managed Codex daemon shim (CODEX_CLI_PATH bridge).
27737
+ *
27738
+ * Desktop injects `codex_app` overrides so CODEX_APP_SERVER_USE_LOCAL_DAEMON=1
27739
+ * alone cannot select the managed daemon, and stock `codex app-server proxy`
27740
+ * hangs for Desktop stdio. The winning path is a wrapper on CODEX_CLI_PATH
27741
+ * that rewrites Desktop's `codex ... app-server` spawn into the stdio<->WS
27742
+ * bridge (desktop-shim-bridge.js) onto the managed control socket.
27743
+ * Provenance: uploads/codex-desktop-to-daemon + codex-desktop-shared-daemon-env.sh.
27744
+ *
27745
+ * Fail-open is the hard rule: the wrapper execs the real standalone `codex`
27746
+ * for non-app-server spawns and whenever the bridge/python/socket side is
27747
+ * missing or broken. Never touches Desktop binaries, /tmp/codex-browser-use/,
27748
+ * or CODEX_APP_TOOLS_PIPE_PATH. No protocol change: gbot already speaks the
27749
+ * managed control socket.
27750
+ */ const SHIM_LABEL = "com.zackjackson.codex-desktop-shared-daemon";
27751
+ const WRAPPER_FILENAME = "codex-desktop-to-daemon";
27752
+ const BRIDGE_FILENAME = "codex-stdio-to-daemon-ws.py";
27753
+ const ENV_SCRIPT_FILENAME = "codex-desktop-shared-daemon-env.sh";
27754
+ const BRIDGE_LOG_FILENAME = "codex-stdio-to-daemon-ws.log";
27755
+ const WRAPPER_LOG_FILENAME = "codex-desktop-to-daemon.log";
27756
+ const ENV_LOG_FILENAME = "codex-desktop-shared-daemon-env.log";
27757
+ const STANDALONE_REAL_SUFFIX = (0,node_path__rspack_import_3.join)("packages", "standalone", "current", "bin", "codex");
27758
+ function codexHomeDir(env = process.env) {
27759
+ return env.CODEX_HOME || join(env.HOME || homedir(), ".codex");
27760
+ }
27761
+ function userHomeDir(env = process.env) {
27762
+ return env.HOME || (0,node_os__rspack_import_2.homedir)();
27763
+ }
27764
+ function defaultPaths({ env = process.env, home = userHomeDir(env) } = {}) {
27765
+ const codexHome = env.CODEX_HOME || (0,node_path__rspack_import_3.join)(home, ".codex");
27766
+ const binDir = (0,node_path__rspack_import_3.join)(codexHome, "bin");
27767
+ return {
27768
+ binDir,
27769
+ bridgeLogPath: (0,node_path__rspack_import_3.join)(binDir, BRIDGE_LOG_FILENAME),
27770
+ bridgePath: (0,node_path__rspack_import_3.join)(binDir, BRIDGE_FILENAME),
27771
+ codexHome,
27772
+ envLogPath: (0,node_path__rspack_import_3.join)(binDir, ENV_LOG_FILENAME),
27773
+ envScriptPath: (0,node_path__rspack_import_3.join)(binDir, ENV_SCRIPT_FILENAME),
27774
+ label: SHIM_LABEL,
27775
+ launchAgentsDir: (0,node_path__rspack_import_3.join)(home, "Library", "LaunchAgents"),
27776
+ plistPath: (0,node_path__rspack_import_3.join)(home, "Library", "LaunchAgents", `${SHIM_LABEL}.plist`),
27777
+ realPath: (0,node_path__rspack_import_3.join)(codexHome, STANDALONE_REAL_SUFFIX),
27778
+ socketPath: (0,node_path__rspack_import_3.join)(codexHome, "app-server-control", "app-server-control.sock"),
27779
+ wrapperLogPath: (0,node_path__rspack_import_3.join)(binDir, WRAPPER_LOG_FILENAME),
27780
+ wrapperPath: (0,node_path__rspack_import_3.join)(binDir, WRAPPER_FILENAME)
27781
+ };
27782
+ }
27783
+ /**
27784
+ * Pure passthrough decision, mirroring the wrapper's argv scan. True only for
27785
+ * a bare `app-server` spawn: Desktop's private-stdio case. `daemon`, `proxy`,
27786
+ * and schema generations always exec the real Codex.
27787
+ */ function shouldBridge(argv) {
27788
+ let appServer = false;
27789
+ let daemon = false;
27790
+ let proxy = false;
27791
+ let generate = false;
27792
+ for (const arg of argv ?? []){
27793
+ if (arg === "app-server") appServer = true;
27794
+ else if (arg === "daemon") daemon = true;
27795
+ else if (arg === "proxy") proxy = true;
27796
+ else if (arg === "generate-ts" || arg === "generate-json-schema") generate = true;
27797
+ }
27798
+ return appServer && !daemon && !proxy && !generate;
27799
+ }
27800
+ function renderWrapperScript({ realPath, bridgePath, wrapperLogPath, codexHome, bridgeLogPath }) {
27801
+ return `#!/bin/bash
27802
+ # Installed by \`gbot codex desktop-shim install\`. Rewrites ChatGPT Desktop's
27803
+ # \`codex ... app-server\` spawn into a stdio<->WebSocket bridge onto the managed
27804
+ # daemon's control socket. Reversible: \`gbot codex desktop-shim uninstall\`.
27805
+ # The daemon is kept up by the LaunchAgent login script, not here: this hot path
27806
+ # never starts the daemon itself, so a wedged daemon lock cannot hang
27807
+ # Desktop. Fail-open runs ONLY before any stdin is consumed: an absent socket
27808
+ # fails the preflight and a pre-session bridge failure (exit 1) falls through
27809
+ # to the real standalone codex on pristine stdio. A mid-session bridge failure
27810
+ # (exit 2+) exits promptly so Desktop reconnects; the fallback never runs on
27811
+ # half-consumed stdin. Bridge exit 0 means it served the session. Never touches
27812
+ # Desktop binaries or its private tool pipe.
27813
+ set -u
27814
+ REAL="\${CODEX_DESKTOP_WRAPPER_REAL:-${realPath}}"
27815
+ BRIDGE="\${CODEX_DESKTOP_BRIDGE:-${bridgePath}}"
27816
+ export CODEX_HOME="\${CODEX_HOME:-${codexHome}}"
27817
+ SOCK="\${CODEX_APP_SERVER_SOCK:-$CODEX_HOME/app-server-control/app-server-control.sock}"
27818
+ BRIDGE_LOG="\${CODEX_STDIO_BRIDGE_LOG:-${bridgeLogPath}}"
27819
+ LOG="\${CODEX_DESKTOP_WRAPPER_LOG:-${wrapperLogPath}}"
27820
+ export CODEX_APP_SERVER_SOCK="$SOCK"
27821
+ export CODEX_STDIO_BRIDGE_LOG="$BRIDGE_LOG"
27822
+ ts() { date -u +%Y-%m-%dT%H:%M:%SZ; }
27823
+ echo "$(ts) argv: $*" >>"$LOG" 2>/dev/null || true
27824
+
27825
+ if [[ ! -x "$REAL" ]]; then
27826
+ FALLBACK="$(command -v codex 2>/dev/null || true)"
27827
+ if [[ -n "$FALLBACK" && -x "$FALLBACK" ]]; then
27828
+ REAL="$FALLBACK"
27829
+ fi
27830
+ fi
27831
+
27832
+ has_app_server=0; has_daemon=0; has_proxy=0; has_generate=0
27833
+ for a in "$@"; do
27834
+ case "$a" in
27835
+ app-server) has_app_server=1 ;;
27836
+ daemon) has_daemon=1 ;;
27837
+ proxy) has_proxy=1 ;;
27838
+ generate-ts|generate-json-schema) has_generate=1 ;;
27839
+ esac
27840
+ done
27841
+
27842
+ # Preflight the daemon socket with a short deadline: a refused/absent socket
27843
+ # means starting the bridge could never succeed, so skip straight to real codex.
27844
+ preflight() {
27845
+ python3 -c 'import os,socket,sys; s=socket.socket(socket.AF_UNIX,socket.SOCK_STREAM); s.settimeout(float(os.environ.get("CODEX_DESKTOP_PREFLIGHT_TIMEOUT","3"))); s.connect(sys.argv[1]); s.close()' "$SOCK" 2>/dev/null
27846
+ }
27847
+
27848
+ if [[ "$has_app_server" -eq 1 && "$has_daemon" -eq 0 && "$has_proxy" -eq 0 && "$has_generate" -eq 0 ]]; then
27849
+ if [[ -x "$REAL" && -f "$BRIDGE" ]] && command -v python3 >/dev/null 2>&1; then
27850
+ if preflight; then
27851
+ echo "$(ts) rewrite -> stdio-ws bridge" >>"$LOG" 2>/dev/null || true
27852
+ python3 "$BRIDGE"
27853
+ rc=$?
27854
+ case "$rc" in
27855
+ 0)
27856
+ echo "$(ts) bridge served session" >>"$LOG" 2>/dev/null || true
27857
+ exit 0
27858
+ ;;
27859
+ 1)
27860
+ echo "$(ts) bridge failed before session start, falling through to real codex" >>"$LOG" 2>/dev/null || true
27861
+ ;;
27862
+ *)
27863
+ echo "$(ts) bridge failed mid-session (rc=$rc); exiting so Desktop reconnects" >>"$LOG" 2>/dev/null || true
27864
+ exit "$rc"
27865
+ ;;
27866
+ esac
27867
+ else
27868
+ echo "$(ts) daemon socket unreachable, passthrough to real codex" >>"$LOG" 2>/dev/null || true
27869
+ fi
27870
+ else
27871
+ echo "$(ts) bridge unavailable, passthrough to real codex" >>"$LOG" 2>/dev/null || true
27872
+ fi
27873
+ fi
27874
+ if [[ -x "$REAL" ]]; then
27875
+ exec "$REAL" "$@"
27876
+ fi
27877
+ echo "codex-desktop-to-daemon: no runnable codex found" >&2
27878
+ exit 1
27879
+ `;
27880
+ }
27881
+ function renderEnvScript({ wrapperPath, realPath, envLogPath, codexHome }) {
27882
+ return `#!/bin/bash
27883
+ # Installed by \`gbot codex desktop-shim install\`. Re-applies the GUI-domain env
27884
+ # so ChatGPT.app inherits CODEX_CLI_PATH after login, then best-effort starts the
27885
+ # managed daemon (this login script — never Desktop's spawn hot path — owns
27886
+ # daemon upkeep). No -e: every step is best-effort so login never breaks.
27887
+ # Revert: \`gbot codex desktop-shim uninstall\`.
27888
+ set -u
27889
+ WRAPPER="${wrapperPath}"
27890
+ REAL="${realPath}"
27891
+ LOG="${envLogPath}"
27892
+ CODEX_HOME_DIR="${codexHome}"
27893
+ # One CODEX_HOME for the GUI domain and this script's own daemon start, so the
27894
+ # daemon that is kept up is the one the wrapper bridges to.
27895
+ export CODEX_HOME="$CODEX_HOME_DIR"
27896
+ ts() { date -u +%Y-%m-%dT%H:%M:%SZ; }
27897
+ {
27898
+ echo "$(ts) start"
27899
+ if [[ ! -x "$WRAPPER" ]]; then
27900
+ echo "$(ts) missing wrapper: $WRAPPER"
27901
+ exit 0
27902
+ fi
27903
+ # GUI domain setenv so ChatGPT.app inherits CODEX_CLI_PATH after login
27904
+ launchctl setenv CODEX_CLI_PATH "$WRAPPER"
27905
+ launchctl setenv CODEX_HOME "$CODEX_HOME_DIR"
27906
+ launchctl setenv CODEX_APP_SERVER_USE_LOCAL_DAEMON 1
27907
+ launchctl unsetenv CODEX_APP_SERVER_WS_URL 2>/dev/null || true
27908
+ echo "$(ts) CODEX_CLI_PATH=$(launchctl getenv CODEX_CLI_PATH)"
27909
+ if [[ -x "$REAL" ]]; then
27910
+ "$REAL" app-server daemon start >/dev/null 2>&1 || true
27911
+ echo "$(ts) daemon start attempted"
27912
+ fi
27913
+ echo "$(ts) done"
27914
+ } >>"$LOG" 2>&1
27915
+ `;
27916
+ }
27917
+ function renderPlist({ envScriptPath, label = SHIM_LABEL }) {
27918
+ return `<?xml version="1.0" encoding="UTF-8"?>
27919
+ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
27920
+ <plist version="1.0">
27921
+ <dict>
27922
+ \t<key>Label</key>
27923
+ \t<string>${label}</string>
27924
+ \t<key>ProgramArguments</key>
27925
+ \t<array>
27926
+ \t\t<string>/bin/bash</string>
27927
+ \t\t<string>${envScriptPath}</string>
27928
+ \t</array>
27929
+ \t<key>RunAtLoad</key>
27930
+ \t<true/>
27931
+ \t<key>LimitLoadToSessionType</key>
27932
+ \t<string>Aqua</string>
27933
+ </dict>
27934
+ </plist>
27935
+ `;
27936
+ }
27937
+ const defaultRunner = (file, args)=>{
27938
+ try {
27939
+ return (0,node_child_process__rspack_import_0.spawnSync)(file, args, {
27940
+ encoding: "utf8",
27941
+ timeout: 15000
27942
+ });
27943
+ } catch (error) {
27944
+ return {
27945
+ error,
27946
+ status: null
27947
+ };
27948
+ }
27949
+ };
27950
+ function runBestEffort(runner, warnings, what, file, args) {
27951
+ const out = runner(file, args);
27952
+ if (out && (out.error || typeof out.status === "number" && out.status !== 0)) {
27953
+ const detail = out.error && out.error.message || out.stderr && String(out.stderr).trim() || `exit ${out.status}`;
27954
+ warnings.push(`${what} failed (${detail}); continuing`);
27955
+ }
27956
+ return out;
27957
+ }
27958
+ function writeExecutable(path, content) {
27959
+ (0,node_fs__rspack_import_1.writeFileSync)(path, content, {
27960
+ mode: 493
27961
+ });
27962
+ (0,node_fs__rspack_import_1.chmodSync)(path, 493);
27963
+ }
27964
+ function isExecutable(path) {
27965
+ try {
27966
+ (0,node_fs__rspack_import_1.statSync)(path);
27967
+ } catch {
27968
+ return false;
27969
+ }
27970
+ try {
27971
+ // X_OK without throwing: accessSync is clearer; stat mode bit check is sync-safe.
27972
+ return ((0,node_fs__rspack_import_1.statSync)(path).mode & 73) !== 0;
27973
+ } catch {
27974
+ return false;
27975
+ }
27976
+ }
27977
+ function fileExists(path) {
27978
+ try {
27979
+ (0,node_fs__rspack_import_1.statSync)(path);
27980
+ return true;
27981
+ } catch {
27982
+ return false;
27983
+ }
27984
+ }
27985
+ /**
27986
+ * Copy the wrapper + bridge + login env script out of the package into durable
27987
+ * ~/.codex paths (never a git checkout), then persist CODEX_CLI_PATH for the
27988
+ * macOS Aqua session via LaunchAgent. Idempotent.
27989
+ */ function installDesktopShim({ env = process.env, home = userHomeDir(env), platform = process.platform, runner = defaultRunner } = {}) {
27990
+ const paths = defaultPaths({
27991
+ env,
27992
+ home
27993
+ });
27994
+ const warnings = [];
27995
+ (0,node_fs__rspack_import_1.mkdirSync)(paths.binDir, {
27996
+ recursive: true
27997
+ });
27998
+ writeExecutable(paths.wrapperPath, renderWrapperScript(paths));
27999
+ (0,node_fs__rspack_import_1.writeFileSync)(paths.bridgePath, _desktop_shim_bridge_js__rspack_import_5/* .BRIDGE_SOURCE.endsWith */.w.endsWith("\n") ? _desktop_shim_bridge_js__rspack_import_5/* .BRIDGE_SOURCE */.w : `${_desktop_shim_bridge_js__rspack_import_5/* .BRIDGE_SOURCE */.w}\n`, {
28000
+ mode: 420
28001
+ });
28002
+ writeExecutable(paths.envScriptPath, renderEnvScript(paths));
28003
+ let persisted = false;
28004
+ if (platform === "darwin") {
28005
+ (0,node_fs__rspack_import_1.mkdirSync)(paths.launchAgentsDir, {
28006
+ recursive: true
28007
+ });
28008
+ (0,node_fs__rspack_import_1.writeFileSync)(paths.plistPath, renderPlist({
28009
+ envScriptPath: paths.envScriptPath
28010
+ }), {
28011
+ mode: 420
28012
+ });
28013
+ const uid = typeof process.getuid === "function" ? process.getuid() : null;
28014
+ if (uid === null || uid === undefined) {
28015
+ warnings.push("could not determine uid; LaunchAgent file written but not bootstrapped — log out/in or bootstrap it manually");
28016
+ } else {
28017
+ const target = `gui/${uid}/${paths.label}`;
28018
+ runBestEffort(runner, warnings, "launchctl bootout (previous agent)", "launchctl", [
28019
+ "bootout",
28020
+ target
28021
+ ]);
28022
+ runBestEffort(runner, warnings, "launchctl bootstrap", "launchctl", [
28023
+ "bootstrap",
28024
+ `gui/${uid}`,
28025
+ paths.plistPath
28026
+ ]);
28027
+ }
28028
+ runBestEffort(runner, warnings, "launchctl setenv CODEX_CLI_PATH", "launchctl", [
28029
+ "setenv",
28030
+ "CODEX_CLI_PATH",
28031
+ paths.wrapperPath
28032
+ ]);
28033
+ runBestEffort(runner, warnings, "launchctl setenv CODEX_APP_SERVER_USE_LOCAL_DAEMON", "launchctl", [
28034
+ "setenv",
28035
+ "CODEX_APP_SERVER_USE_LOCAL_DAEMON",
28036
+ "1"
28037
+ ]);
28038
+ runBestEffort(runner, warnings, "launchctl unsetenv CODEX_APP_SERVER_WS_URL", "launchctl", [
28039
+ "unsetenv",
28040
+ "CODEX_APP_SERVER_WS_URL"
28041
+ ]);
28042
+ persisted = true;
28043
+ } else {
28044
+ warnings.push("LaunchAgent persistence is macOS-only; wrapper and bridge installed — export CODEX_CLI_PATH manually");
28045
+ }
28046
+ if (isExecutable(paths.realPath)) {
28047
+ runBestEffort(runner, warnings, "codex app-server daemon start", paths.realPath, [
28048
+ "app-server",
28049
+ "daemon",
28050
+ "start"
28051
+ ]);
28052
+ } else {
28053
+ warnings.push(`managed daemon not started: no executable at ${paths.realPath}`);
28054
+ }
28055
+ return {
28056
+ action: "install",
28057
+ bridgePath: paths.bridgePath,
28058
+ envScriptPath: paths.envScriptPath,
28059
+ exitCode: 0,
28060
+ persisted,
28061
+ plistPath: platform === "darwin" ? paths.plistPath : null,
28062
+ realPath: paths.realPath,
28063
+ warnings,
28064
+ wrapperPath: paths.wrapperPath
28065
+ };
28066
+ }
28067
+ /** Remove what install wrote and unset the GUI env; Desktop/Codex fall back to stock. */ function uninstallDesktopShim({ env = process.env, home = userHomeDir(env), platform = process.platform, runner = defaultRunner } = {}) {
28068
+ const paths = defaultPaths({
28069
+ env,
28070
+ home
28071
+ });
28072
+ const warnings = [];
28073
+ const removed = [];
28074
+ for (const path of [
28075
+ paths.wrapperPath,
28076
+ paths.bridgePath,
28077
+ paths.envScriptPath
28078
+ ]){
28079
+ try {
28080
+ if ((0,node_fs__rspack_import_1.rmSync)(path, {
28081
+ force: true
28082
+ }) === undefined && fileExists(path)) warnings.push(`could not remove ${path}`);
28083
+ else if (!fileExists(path)) removed.push(path);
28084
+ } catch (error) {
28085
+ warnings.push(`could not remove ${path} (${error instanceof Error ? error.message : String(error)})`);
28086
+ }
28087
+ }
28088
+ let plistRemoved = false;
28089
+ if (platform === "darwin") {
28090
+ const uid = typeof process.getuid === "function" ? process.getuid() : null;
28091
+ if (uid !== null && uid !== undefined) {
28092
+ runBestEffort(runner, warnings, "launchctl bootout", "launchctl", [
28093
+ "bootout",
28094
+ `gui/${uid}/${paths.label}`
28095
+ ]);
28096
+ }
28097
+ try {
28098
+ (0,node_fs__rspack_import_1.rmSync)(paths.plistPath, {
28099
+ force: true
28100
+ });
28101
+ plistRemoved = !fileExists(paths.plistPath);
28102
+ } catch (error) {
28103
+ warnings.push(`could not remove ${paths.plistPath} (${error instanceof Error ? error.message : String(error)})`);
28104
+ }
28105
+ runBestEffort(runner, warnings, "launchctl unsetenv CODEX_CLI_PATH", "launchctl", [
28106
+ "unsetenv",
28107
+ "CODEX_CLI_PATH"
28108
+ ]);
28109
+ runBestEffort(runner, warnings, "launchctl unsetenv CODEX_HOME", "launchctl", [
28110
+ "unsetenv",
28111
+ "CODEX_HOME"
28112
+ ]);
28113
+ runBestEffort(runner, warnings, "launchctl unsetenv CODEX_APP_SERVER_USE_LOCAL_DAEMON", "launchctl", [
28114
+ "unsetenv",
28115
+ "CODEX_APP_SERVER_USE_LOCAL_DAEMON"
28116
+ ]);
28117
+ runBestEffort(runner, warnings, "launchctl unsetenv CODEX_APP_SERVER_WS_URL", "launchctl", [
28118
+ "unsetenv",
28119
+ "CODEX_APP_SERVER_WS_URL"
28120
+ ]);
28121
+ }
28122
+ return {
28123
+ action: "uninstall",
28124
+ exitCode: 0,
28125
+ plistPath: platform === "darwin" ? paths.plistPath : null,
28126
+ plistRemoved,
28127
+ removed,
28128
+ warnings,
28129
+ wrapperPath: paths.wrapperPath
28130
+ };
28131
+ }
28132
+ function socketStateOf(path) {
28133
+ try {
28134
+ return (0,node_fs__rspack_import_1.statSync)(path).isSocket() ? "socket" : "not-a-socket";
28135
+ } catch (error) {
28136
+ return error && (error.code === "EACCES" || error.code === "EPERM") ? "permission-denied" : "absent";
28137
+ }
28138
+ }
28139
+ /**
28140
+ * Inspect the shim without touching Desktop, pipes, or sockets beyond a stat.
28141
+ * On macOS the Desktop-facing CODEX_CLI_PATH lives in launchd's GUI domain,
28142
+ * which a shell-spawned `gbot` does not inherit — so status queries
28143
+ * `launchctl getenv` there (via the injectable runner) and reports the caller
28144
+ * environment separately. Elsewhere the process env is the whole story.
28145
+ */ function desktopShimStatus({ env = process.env, home = userHomeDir(env), platform = process.platform, runner = defaultRunner } = {}) {
28146
+ const paths = defaultPaths({
28147
+ env,
28148
+ home
28149
+ });
28150
+ const warnings = [];
28151
+ const wrapperPresent = fileExists(paths.wrapperPath);
28152
+ const bridgePresent = fileExists(paths.bridgePath);
28153
+ const envScriptPresent = fileExists(paths.envScriptPath);
28154
+ const plistPresent = platform === "darwin" ? fileExists(paths.plistPath) : false;
28155
+ const cliPath = env.CODEX_CLI_PATH || null;
28156
+ let guiCliPath = null;
28157
+ if (platform === "darwin") {
28158
+ try {
28159
+ const out = runner("launchctl", [
28160
+ "getenv",
28161
+ "CODEX_CLI_PATH"
28162
+ ]);
28163
+ const value = out && typeof out.stdout === "string" ? out.stdout.trim() : "";
28164
+ guiCliPath = value || null;
28165
+ if (out && (out.error || typeof out.status === "number" && out.status !== 0)) {
28166
+ warnings.push("launchctl getenv CODEX_CLI_PATH failed; GUI-domain state unknown");
28167
+ guiCliPath = null;
28168
+ }
28169
+ } catch (error) {
28170
+ warnings.push(`launchctl getenv CODEX_CLI_PATH failed (${error instanceof Error ? error.message : String(error)})`);
28171
+ guiCliPath = null;
28172
+ }
28173
+ }
28174
+ // Desktop-facing value: the GUI domain on macOS, the caller env elsewhere.
28175
+ const desktopCliPath = platform === "darwin" ? guiCliPath : cliPath;
28176
+ const installed = wrapperPresent && isExecutable(paths.wrapperPath) && bridgePresent;
28177
+ // Effective socket, resolved exactly like gbot's own client so status and
28178
+ // send/queue/status never disagree: CODEX_APP_SERVER_SOCK wins, else CODEX_HOME.
28179
+ const socketPath = (0,_codex_bridge_js__rspack_import_4/* .codexSocketPath */.ql)({
28180
+ ...env,
28181
+ CODEX_HOME: paths.codexHome
28182
+ });
28183
+ return {
28184
+ action: "status",
28185
+ bridgePath: paths.bridgePath,
28186
+ bridgePresent,
28187
+ cliPath,
28188
+ codexHome: paths.codexHome,
28189
+ desktopCliPath,
28190
+ envScriptPath: paths.envScriptPath,
28191
+ envScriptPresent,
28192
+ exitCode: installed ? 0 : 1,
28193
+ guiCliPath,
28194
+ installed,
28195
+ persisted: platform === "darwin" ? plistPresent : null,
28196
+ platform,
28197
+ plistPath: platform === "darwin" ? paths.plistPath : null,
28198
+ plistPresent,
28199
+ realPath: paths.realPath,
28200
+ socketPath,
28201
+ socketSource: env.CODEX_APP_SERVER_SOCK ? "CODEX_APP_SERVER_SOCK" : "CODEX_HOME",
28202
+ socketState: socketStateOf(socketPath),
28203
+ warnings,
28204
+ wrapperExecutable: wrapperPresent && isExecutable(paths.wrapperPath),
28205
+ wrapperPath: paths.wrapperPath,
28206
+ wrapperPointsAtShim: desktopCliPath === paths.wrapperPath,
28207
+ wrapperPresent
28208
+ };
28209
+ }
28210
+
28211
+ __webpack_require__.d(__webpack_exports__, {
28212
+ B0: () => (installDesktopShim),
28213
+ em: () => (desktopShimStatus),
28214
+ gM: () => (uninstallDesktopShim)
28215
+ });
28216
+
28217
+
27477
28218
  },
27478
28219
  "./src/core/format.js"(__unused_rspack___webpack_module__, __webpack_exports__, __webpack_require__) {
27479
28220
  /* import */ var _transcript_js__rspack_import_0 = __webpack_require__("./src/core/transcript.js");
@@ -27553,7 +28294,7 @@ function formatCodexStatus(s) {
27553
28294
  lines.push("reachable: yes (daemon)");
27554
28295
  const cli = s.cliVersion ?? (s.cliVersionProbe === "ok" ? "unknown" : "unknown, probe " + s.cliVersionProbe);
27555
28296
  lines.push("daemon version: " + (s.daemonVersion ?? "unknown") + " cli version: " + cli + " pinned schema: " + s.pinnedVersion + " (" + s.schema.compatibility + ")");
27556
- lines.push("desktop attached: unknown (not observable from the socket)");
28297
+ lines.push(s.desktopAttached === "private-stdio" ? "desktop attached: private-stdio (ChatGPT Desktop runs its own private stdio app-server; start a managed daemon with `codex app-server daemon start`)" : "desktop attached: unknown (not observable from the socket)");
27557
28298
  if (s.versionMismatch) {
27558
28299
  lines.push("warning: daemon and CLI versions differ; `codex app-server daemon restart` picks up the installed CLI");
27559
28300
  }
@@ -27568,12 +28309,34 @@ function formatCodexThread(t) {
27568
28309
  const preview = t.preview ? "\n " + stripTerminalControls(String(t.preview).replace(/\s+/g, " ")).slice(0, 200) : "";
27569
28310
  return stripTerminalControls(t.id) + " " + stripTerminalControls(t.status) + title + "\n " + stripTerminalControls(t.cwd ?? "") + preview;
27570
28311
  }
28312
+ function formatDesktopShimStatus(s) {
28313
+ const mark = (ok)=>ok ? "yes" : "no";
28314
+ const cliLine = s.platform === "darwin" ? "CODEX_CLI_PATH: GUI domain " + (s.guiCliPath ?? "(unset)") + " / this shell " + (s.cliPath ?? "(unset)") + (s.wrapperPointsAtShim ? " (Desktop-facing value points at shim)" : "") : "CODEX_CLI_PATH: " + (s.cliPath ?? "(unset)") + (s.wrapperPointsAtShim ? " (points at shim)" : "");
28315
+ const lines = [
28316
+ "wrapper: " + s.wrapperPath + " (" + (s.wrapperExecutable ? "executable" : s.wrapperPresent ? "present, not executable" : "absent") + ")",
28317
+ "bridge: " + s.bridgePath + " (" + mark(s.bridgePresent) + ")",
28318
+ "login env: " + s.envScriptPath + " (" + mark(s.envScriptPresent) + ")",
28319
+ s.platform === "darwin" ? "LaunchAgent: " + s.plistPath + " (" + mark(s.plistPresent) + ")" : "LaunchAgent: n/a (macOS-only)",
28320
+ cliLine,
28321
+ "daemon socket: " + s.socketPath + " (" + s.socketState + ", from " + (s.socketSource ?? "CODEX_HOME") + ")"
28322
+ ];
28323
+ if (!s.installed) {
28324
+ lines.push("shim: not installed — run `gbot codex desktop-shim install` (Desktop keeps stock behavior until then)");
28325
+ } else if (!s.wrapperPointsAtShim) {
28326
+ lines.push("shim: installed but CODEX_CLI_PATH does not point at it — reinstall or relaunch ChatGPT.app after login");
28327
+ } else {
28328
+ lines.push("shim: active — Desktop app-server spawns bridge onto the managed daemon");
28329
+ }
28330
+ for (const warning of s.warnings ?? [])lines.push("warning: " + String(warning));
28331
+ return lines.join("\n");
28332
+ }
27571
28333
 
27572
28334
  __webpack_require__.d(__webpack_exports__, {
27573
28335
  P2: () => (formatCodexStatus),
27574
28336
  bM: () => (formatRecord),
27575
28337
  e_: () => (formatCodexQueue),
27576
28338
  eh: () => (summarize),
28339
+ fX: () => (formatDesktopShimStatus),
27577
28340
  nz: () => (formatCodexThread),
27578
28341
  oZ: () => (formatTranscript)
27579
28342
  });
@@ -28821,32 +29584,33 @@ __webpack_require__.r = (exports) => {
28821
29584
  var __webpack_exports__ = {};
28822
29585
  /* import */ var node_worker_threads__rspack_import_0 = __webpack_require__("node:worker_threads");
28823
29586
  /* import */ var react__rspack_import_1 = __webpack_require__("./node_modules/react/react.react-server.js");
28824
- /* import */ var _agent_bundle_runtime_flight_server__rspack_import_27 = __webpack_require__("./node_modules/@agent-bundle/runtime/dist/flight/server.js");
28825
- /* import */ var _agent_bundle_runtime__rspack_import_25 = __webpack_require__("./node_modules/@agent-bundle/runtime/dist/49.js");
28826
- /* import */ var _agent_bundle_runtime__rspack_import_26 = __webpack_require__("./node_modules/@agent-bundle/runtime/dist/736.js");
29587
+ /* import */ var _agent_bundle_runtime_flight_server__rspack_import_28 = __webpack_require__("./node_modules/@agent-bundle/runtime/dist/flight/server.js");
29588
+ /* import */ var _agent_bundle_runtime__rspack_import_26 = __webpack_require__("./node_modules/@agent-bundle/runtime/dist/49.js");
29589
+ /* import */ var _agent_bundle_runtime__rspack_import_27 = __webpack_require__("./node_modules/@agent-bundle/runtime/dist/736.js");
28827
29590
  /* import */ var node_url__rspack_import_2 = __webpack_require__("node:url");
28828
29591
  /* import */ var _home_runner_work_grok_bot_cli_grok_bot_cli_src_cli_bots_create_tsx__rspack_import_3 = __webpack_require__("./src/cli/bots/create.tsx");
28829
29592
  /* import */ var _home_runner_work_grok_bot_cli_grok_bot_cli_src_cli_bots_delete_tsx__rspack_import_4 = __webpack_require__("./src/cli/bots/delete.tsx");
28830
29593
  /* import */ var _home_runner_work_grok_bot_cli_grok_bot_cli_src_cli_bots_get_tsx__rspack_import_5 = __webpack_require__("./src/cli/bots/get.tsx");
28831
29594
  /* import */ var _home_runner_work_grok_bot_cli_grok_bot_cli_src_cli_bots_list_tsx__rspack_import_6 = __webpack_require__("./src/cli/bots/list.tsx");
28832
29595
  /* import */ var _home_runner_work_grok_bot_cli_grok_bot_cli_src_cli_bots_update_tsx__rspack_import_7 = __webpack_require__("./src/cli/bots/update.tsx");
28833
- /* import */ var _home_runner_work_grok_bot_cli_grok_bot_cli_src_cli_codex_list_threads_tsx__rspack_import_8 = __webpack_require__("./src/cli/codex/list-threads.tsx");
28834
- /* import */ var _home_runner_work_grok_bot_cli_grok_bot_cli_src_cli_codex_queue_tsx__rspack_import_9 = __webpack_require__("./src/cli/codex/queue.tsx");
28835
- /* import */ var _home_runner_work_grok_bot_cli_grok_bot_cli_src_cli_codex_send_tsx__rspack_import_10 = __webpack_require__("./src/cli/codex/send.tsx");
28836
- /* import */ var _home_runner_work_grok_bot_cli_grok_bot_cli_src_cli_codex_status_tsx__rspack_import_11 = __webpack_require__("./src/cli/codex/status.tsx");
28837
- /* import */ var _home_runner_work_grok_bot_cli_grok_bot_cli_src_cli_doctor_tsx__rspack_import_12 = __webpack_require__("./src/cli/doctor.tsx");
28838
- /* import */ var _home_runner_work_grok_bot_cli_grok_bot_cli_src_cli_groups_add_tsx__rspack_import_13 = __webpack_require__("./src/cli/groups/add.tsx");
28839
- /* import */ var _home_runner_work_grok_bot_cli_grok_bot_cli_src_cli_groups_create_tsx__rspack_import_14 = __webpack_require__("./src/cli/groups/create.tsx");
28840
- /* import */ var _home_runner_work_grok_bot_cli_grok_bot_cli_src_cli_groups_delete_tsx__rspack_import_15 = __webpack_require__("./src/cli/groups/delete.tsx");
28841
- /* import */ var _home_runner_work_grok_bot_cli_grok_bot_cli_src_cli_groups_get_tsx__rspack_import_16 = __webpack_require__("./src/cli/groups/get.tsx");
28842
- /* import */ var _home_runner_work_grok_bot_cli_grok_bot_cli_src_cli_groups_list_tsx__rspack_import_17 = __webpack_require__("./src/cli/groups/list.tsx");
28843
- /* import */ var _home_runner_work_grok_bot_cli_grok_bot_cli_src_cli_groups_members_tsx__rspack_import_18 = __webpack_require__("./src/cli/groups/members.tsx");
28844
- /* import */ var _home_runner_work_grok_bot_cli_grok_bot_cli_src_cli_groups_remove_tsx__rspack_import_19 = __webpack_require__("./src/cli/groups/remove.tsx");
28845
- /* import */ var _home_runner_work_grok_bot_cli_grok_bot_cli_src_cli_groups_set_tsx__rspack_import_20 = __webpack_require__("./src/cli/groups/set.tsx");
28846
- /* import */ var _home_runner_work_grok_bot_cli_grok_bot_cli_src_cli_groups_update_tsx__rspack_import_21 = __webpack_require__("./src/cli/groups/update.tsx");
28847
- /* import */ var _home_runner_work_grok_bot_cli_grok_bot_cli_src_cli_history_tsx__rspack_import_22 = __webpack_require__("./src/cli/history.tsx");
28848
- /* import */ var _home_runner_work_grok_bot_cli_grok_bot_cli_src_cli_send_tsx__rspack_import_23 = __webpack_require__("./src/cli/send.tsx");
28849
- /* import */ var _home_runner_work_grok_bot_cli_grok_bot_cli_src_cli_thread_tsx__rspack_import_24 = __webpack_require__("./src/cli/thread.tsx");
29596
+ /* import */ var _home_runner_work_grok_bot_cli_grok_bot_cli_src_cli_codex_desktop_shim_tsx__rspack_import_8 = __webpack_require__("./src/cli/codex/desktop-shim.tsx");
29597
+ /* import */ var _home_runner_work_grok_bot_cli_grok_bot_cli_src_cli_codex_list_threads_tsx__rspack_import_9 = __webpack_require__("./src/cli/codex/list-threads.tsx");
29598
+ /* import */ var _home_runner_work_grok_bot_cli_grok_bot_cli_src_cli_codex_queue_tsx__rspack_import_10 = __webpack_require__("./src/cli/codex/queue.tsx");
29599
+ /* import */ var _home_runner_work_grok_bot_cli_grok_bot_cli_src_cli_codex_send_tsx__rspack_import_11 = __webpack_require__("./src/cli/codex/send.tsx");
29600
+ /* import */ var _home_runner_work_grok_bot_cli_grok_bot_cli_src_cli_codex_status_tsx__rspack_import_12 = __webpack_require__("./src/cli/codex/status.tsx");
29601
+ /* import */ var _home_runner_work_grok_bot_cli_grok_bot_cli_src_cli_doctor_tsx__rspack_import_13 = __webpack_require__("./src/cli/doctor.tsx");
29602
+ /* import */ var _home_runner_work_grok_bot_cli_grok_bot_cli_src_cli_groups_add_tsx__rspack_import_14 = __webpack_require__("./src/cli/groups/add.tsx");
29603
+ /* import */ var _home_runner_work_grok_bot_cli_grok_bot_cli_src_cli_groups_create_tsx__rspack_import_15 = __webpack_require__("./src/cli/groups/create.tsx");
29604
+ /* import */ var _home_runner_work_grok_bot_cli_grok_bot_cli_src_cli_groups_delete_tsx__rspack_import_16 = __webpack_require__("./src/cli/groups/delete.tsx");
29605
+ /* import */ var _home_runner_work_grok_bot_cli_grok_bot_cli_src_cli_groups_get_tsx__rspack_import_17 = __webpack_require__("./src/cli/groups/get.tsx");
29606
+ /* import */ var _home_runner_work_grok_bot_cli_grok_bot_cli_src_cli_groups_list_tsx__rspack_import_18 = __webpack_require__("./src/cli/groups/list.tsx");
29607
+ /* import */ var _home_runner_work_grok_bot_cli_grok_bot_cli_src_cli_groups_members_tsx__rspack_import_19 = __webpack_require__("./src/cli/groups/members.tsx");
29608
+ /* import */ var _home_runner_work_grok_bot_cli_grok_bot_cli_src_cli_groups_remove_tsx__rspack_import_20 = __webpack_require__("./src/cli/groups/remove.tsx");
29609
+ /* import */ var _home_runner_work_grok_bot_cli_grok_bot_cli_src_cli_groups_set_tsx__rspack_import_21 = __webpack_require__("./src/cli/groups/set.tsx");
29610
+ /* import */ var _home_runner_work_grok_bot_cli_grok_bot_cli_src_cli_groups_update_tsx__rspack_import_22 = __webpack_require__("./src/cli/groups/update.tsx");
29611
+ /* import */ var _home_runner_work_grok_bot_cli_grok_bot_cli_src_cli_history_tsx__rspack_import_23 = __webpack_require__("./src/cli/history.tsx");
29612
+ /* import */ var _home_runner_work_grok_bot_cli_grok_bot_cli_src_cli_send_tsx__rspack_import_24 = __webpack_require__("./src/cli/send.tsx");
29613
+ /* import */ var _home_runner_work_grok_bot_cli_grok_bot_cli_src_cli_thread_tsx__rspack_import_25 = __webpack_require__("./src/cli/thread.tsx");
28850
29614
 
28851
29615
 
28852
29616
 
@@ -28863,40 +29627,42 @@ const route3 = Object.assign({}, Reflect.get(_home_runner_work_grok_bot_cli_grok
28863
29627
 
28864
29628
  const route4 = Object.assign({}, Reflect.get(_home_runner_work_grok_bot_cli_grok_bot_cli_src_cli_bots_update_tsx__rspack_import_7, 'default'), _home_runner_work_grok_bot_cli_grok_bot_cli_src_cli_bots_update_tsx__rspack_import_7);
28865
29629
 
28866
- const route5 = Object.assign({}, Reflect.get(_home_runner_work_grok_bot_cli_grok_bot_cli_src_cli_codex_list_threads_tsx__rspack_import_8, 'default'), _home_runner_work_grok_bot_cli_grok_bot_cli_src_cli_codex_list_threads_tsx__rspack_import_8);
29630
+ const route5 = Object.assign({}, Reflect.get(_home_runner_work_grok_bot_cli_grok_bot_cli_src_cli_codex_desktop_shim_tsx__rspack_import_8, 'default'), _home_runner_work_grok_bot_cli_grok_bot_cli_src_cli_codex_desktop_shim_tsx__rspack_import_8);
28867
29631
 
28868
- const route6 = Object.assign({}, Reflect.get(_home_runner_work_grok_bot_cli_grok_bot_cli_src_cli_codex_queue_tsx__rspack_import_9, 'default'), _home_runner_work_grok_bot_cli_grok_bot_cli_src_cli_codex_queue_tsx__rspack_import_9);
29632
+ const route6 = Object.assign({}, Reflect.get(_home_runner_work_grok_bot_cli_grok_bot_cli_src_cli_codex_list_threads_tsx__rspack_import_9, 'default'), _home_runner_work_grok_bot_cli_grok_bot_cli_src_cli_codex_list_threads_tsx__rspack_import_9);
28869
29633
 
28870
- const route7 = Object.assign({}, Reflect.get(_home_runner_work_grok_bot_cli_grok_bot_cli_src_cli_codex_send_tsx__rspack_import_10, 'default'), _home_runner_work_grok_bot_cli_grok_bot_cli_src_cli_codex_send_tsx__rspack_import_10);
29634
+ const route7 = Object.assign({}, Reflect.get(_home_runner_work_grok_bot_cli_grok_bot_cli_src_cli_codex_queue_tsx__rspack_import_10, 'default'), _home_runner_work_grok_bot_cli_grok_bot_cli_src_cli_codex_queue_tsx__rspack_import_10);
28871
29635
 
28872
- const route8 = Object.assign({}, Reflect.get(_home_runner_work_grok_bot_cli_grok_bot_cli_src_cli_codex_status_tsx__rspack_import_11, 'default'), _home_runner_work_grok_bot_cli_grok_bot_cli_src_cli_codex_status_tsx__rspack_import_11);
29636
+ const route8 = Object.assign({}, Reflect.get(_home_runner_work_grok_bot_cli_grok_bot_cli_src_cli_codex_send_tsx__rspack_import_11, 'default'), _home_runner_work_grok_bot_cli_grok_bot_cli_src_cli_codex_send_tsx__rspack_import_11);
28873
29637
 
28874
- const route9 = Object.assign({}, Reflect.get(_home_runner_work_grok_bot_cli_grok_bot_cli_src_cli_doctor_tsx__rspack_import_12, 'default'), _home_runner_work_grok_bot_cli_grok_bot_cli_src_cli_doctor_tsx__rspack_import_12);
29638
+ const route9 = Object.assign({}, Reflect.get(_home_runner_work_grok_bot_cli_grok_bot_cli_src_cli_codex_status_tsx__rspack_import_12, 'default'), _home_runner_work_grok_bot_cli_grok_bot_cli_src_cli_codex_status_tsx__rspack_import_12);
28875
29639
 
28876
- const route10 = Object.assign({}, Reflect.get(_home_runner_work_grok_bot_cli_grok_bot_cli_src_cli_groups_add_tsx__rspack_import_13, 'default'), _home_runner_work_grok_bot_cli_grok_bot_cli_src_cli_groups_add_tsx__rspack_import_13);
29640
+ const route10 = Object.assign({}, Reflect.get(_home_runner_work_grok_bot_cli_grok_bot_cli_src_cli_doctor_tsx__rspack_import_13, 'default'), _home_runner_work_grok_bot_cli_grok_bot_cli_src_cli_doctor_tsx__rspack_import_13);
28877
29641
 
28878
- const route11 = Object.assign({}, Reflect.get(_home_runner_work_grok_bot_cli_grok_bot_cli_src_cli_groups_create_tsx__rspack_import_14, 'default'), _home_runner_work_grok_bot_cli_grok_bot_cli_src_cli_groups_create_tsx__rspack_import_14);
29642
+ const route11 = Object.assign({}, Reflect.get(_home_runner_work_grok_bot_cli_grok_bot_cli_src_cli_groups_add_tsx__rspack_import_14, 'default'), _home_runner_work_grok_bot_cli_grok_bot_cli_src_cli_groups_add_tsx__rspack_import_14);
28879
29643
 
28880
- const route12 = Object.assign({}, Reflect.get(_home_runner_work_grok_bot_cli_grok_bot_cli_src_cli_groups_delete_tsx__rspack_import_15, 'default'), _home_runner_work_grok_bot_cli_grok_bot_cli_src_cli_groups_delete_tsx__rspack_import_15);
29644
+ const route12 = Object.assign({}, Reflect.get(_home_runner_work_grok_bot_cli_grok_bot_cli_src_cli_groups_create_tsx__rspack_import_15, 'default'), _home_runner_work_grok_bot_cli_grok_bot_cli_src_cli_groups_create_tsx__rspack_import_15);
28881
29645
 
28882
- const route13 = Object.assign({}, Reflect.get(_home_runner_work_grok_bot_cli_grok_bot_cli_src_cli_groups_get_tsx__rspack_import_16, 'default'), _home_runner_work_grok_bot_cli_grok_bot_cli_src_cli_groups_get_tsx__rspack_import_16);
29646
+ const route13 = Object.assign({}, Reflect.get(_home_runner_work_grok_bot_cli_grok_bot_cli_src_cli_groups_delete_tsx__rspack_import_16, 'default'), _home_runner_work_grok_bot_cli_grok_bot_cli_src_cli_groups_delete_tsx__rspack_import_16);
28883
29647
 
28884
- const route14 = Object.assign({}, Reflect.get(_home_runner_work_grok_bot_cli_grok_bot_cli_src_cli_groups_list_tsx__rspack_import_17, 'default'), _home_runner_work_grok_bot_cli_grok_bot_cli_src_cli_groups_list_tsx__rspack_import_17);
29648
+ const route14 = Object.assign({}, Reflect.get(_home_runner_work_grok_bot_cli_grok_bot_cli_src_cli_groups_get_tsx__rspack_import_17, 'default'), _home_runner_work_grok_bot_cli_grok_bot_cli_src_cli_groups_get_tsx__rspack_import_17);
28885
29649
 
28886
- const route15 = Object.assign({}, Reflect.get(_home_runner_work_grok_bot_cli_grok_bot_cli_src_cli_groups_members_tsx__rspack_import_18, 'default'), _home_runner_work_grok_bot_cli_grok_bot_cli_src_cli_groups_members_tsx__rspack_import_18);
29650
+ const route15 = Object.assign({}, Reflect.get(_home_runner_work_grok_bot_cli_grok_bot_cli_src_cli_groups_list_tsx__rspack_import_18, 'default'), _home_runner_work_grok_bot_cli_grok_bot_cli_src_cli_groups_list_tsx__rspack_import_18);
28887
29651
 
28888
- const route16 = Object.assign({}, Reflect.get(_home_runner_work_grok_bot_cli_grok_bot_cli_src_cli_groups_remove_tsx__rspack_import_19, 'default'), _home_runner_work_grok_bot_cli_grok_bot_cli_src_cli_groups_remove_tsx__rspack_import_19);
29652
+ const route16 = Object.assign({}, Reflect.get(_home_runner_work_grok_bot_cli_grok_bot_cli_src_cli_groups_members_tsx__rspack_import_19, 'default'), _home_runner_work_grok_bot_cli_grok_bot_cli_src_cli_groups_members_tsx__rspack_import_19);
28889
29653
 
28890
- const route17 = Object.assign({}, Reflect.get(_home_runner_work_grok_bot_cli_grok_bot_cli_src_cli_groups_set_tsx__rspack_import_20, 'default'), _home_runner_work_grok_bot_cli_grok_bot_cli_src_cli_groups_set_tsx__rspack_import_20);
29654
+ const route17 = Object.assign({}, Reflect.get(_home_runner_work_grok_bot_cli_grok_bot_cli_src_cli_groups_remove_tsx__rspack_import_20, 'default'), _home_runner_work_grok_bot_cli_grok_bot_cli_src_cli_groups_remove_tsx__rspack_import_20);
28891
29655
 
28892
- const route18 = Object.assign({}, Reflect.get(_home_runner_work_grok_bot_cli_grok_bot_cli_src_cli_groups_update_tsx__rspack_import_21, 'default'), _home_runner_work_grok_bot_cli_grok_bot_cli_src_cli_groups_update_tsx__rspack_import_21);
29656
+ const route18 = Object.assign({}, Reflect.get(_home_runner_work_grok_bot_cli_grok_bot_cli_src_cli_groups_set_tsx__rspack_import_21, 'default'), _home_runner_work_grok_bot_cli_grok_bot_cli_src_cli_groups_set_tsx__rspack_import_21);
28893
29657
 
28894
- const route19 = Object.assign({}, Reflect.get(_home_runner_work_grok_bot_cli_grok_bot_cli_src_cli_history_tsx__rspack_import_22, 'default'), _home_runner_work_grok_bot_cli_grok_bot_cli_src_cli_history_tsx__rspack_import_22);
29658
+ const route19 = Object.assign({}, Reflect.get(_home_runner_work_grok_bot_cli_grok_bot_cli_src_cli_groups_update_tsx__rspack_import_22, 'default'), _home_runner_work_grok_bot_cli_grok_bot_cli_src_cli_groups_update_tsx__rspack_import_22);
28895
29659
 
28896
- const route20 = Object.assign({}, Reflect.get(_home_runner_work_grok_bot_cli_grok_bot_cli_src_cli_send_tsx__rspack_import_23, 'default'), _home_runner_work_grok_bot_cli_grok_bot_cli_src_cli_send_tsx__rspack_import_23);
29660
+ const route20 = Object.assign({}, Reflect.get(_home_runner_work_grok_bot_cli_grok_bot_cli_src_cli_history_tsx__rspack_import_23, 'default'), _home_runner_work_grok_bot_cli_grok_bot_cli_src_cli_history_tsx__rspack_import_23);
28897
29661
 
28898
- const route21 = Object.assign({}, Reflect.get(_home_runner_work_grok_bot_cli_grok_bot_cli_src_cli_thread_tsx__rspack_import_24, 'default'), _home_runner_work_grok_bot_cli_grok_bot_cli_src_cli_thread_tsx__rspack_import_24);
28899
- const pluginRoot = (0,_agent_bundle_runtime__rspack_import_25/* .resolvePluginRoot */.E7)({
29662
+ const route21 = Object.assign({}, Reflect.get(_home_runner_work_grok_bot_cli_grok_bot_cli_src_cli_send_tsx__rspack_import_24, 'default'), _home_runner_work_grok_bot_cli_grok_bot_cli_src_cli_send_tsx__rspack_import_24);
29663
+
29664
+ const route22 = Object.assign({}, Reflect.get(_home_runner_work_grok_bot_cli_grok_bot_cli_src_cli_thread_tsx__rspack_import_25, 'default'), _home_runner_work_grok_bot_cli_grok_bot_cli_src_cli_thread_tsx__rspack_import_25);
29665
+ const pluginRoot = (0,_agent_bundle_runtime__rspack_import_26/* .resolvePluginRoot */.E7)({
28900
29666
  fallback: (0,node_url__rspack_import_2.fileURLToPath)(new URL('..', import.meta.url)),
28901
29667
  stateAnchor: 'user-data'
28902
29668
  });
@@ -28944,107 +29710,113 @@ const routes = Object.freeze({
28944
29710
  name: "bots update",
28945
29711
  module: route4
28946
29712
  }),
29713
+ "cli:codex/desktop-shim": Object.freeze({
29714
+ id: "cli:codex/desktop-shim",
29715
+ kind: "cli",
29716
+ name: "codex desktop-shim",
29717
+ module: route5
29718
+ }),
28947
29719
  "cli:codex/list-threads": Object.freeze({
28948
29720
  id: "cli:codex/list-threads",
28949
29721
  kind: "cli",
28950
29722
  name: "codex list-threads",
28951
- module: route5
29723
+ module: route6
28952
29724
  }),
28953
29725
  "cli:codex/queue": Object.freeze({
28954
29726
  id: "cli:codex/queue",
28955
29727
  kind: "cli",
28956
29728
  name: "codex queue",
28957
- module: route6
29729
+ module: route7
28958
29730
  }),
28959
29731
  "cli:codex/send": Object.freeze({
28960
29732
  id: "cli:codex/send",
28961
29733
  kind: "cli",
28962
29734
  name: "codex send",
28963
- module: route7
29735
+ module: route8
28964
29736
  }),
28965
29737
  "cli:codex/status": Object.freeze({
28966
29738
  id: "cli:codex/status",
28967
29739
  kind: "cli",
28968
29740
  name: "codex status",
28969
- module: route8
29741
+ module: route9
28970
29742
  }),
28971
29743
  "cli:doctor": Object.freeze({
28972
29744
  id: "cli:doctor",
28973
29745
  kind: "cli",
28974
29746
  name: "doctor",
28975
- module: route9
29747
+ module: route10
28976
29748
  }),
28977
29749
  "cli:groups/add": Object.freeze({
28978
29750
  id: "cli:groups/add",
28979
29751
  kind: "cli",
28980
29752
  name: "groups add",
28981
- module: route10
29753
+ module: route11
28982
29754
  }),
28983
29755
  "cli:groups/create": Object.freeze({
28984
29756
  id: "cli:groups/create",
28985
29757
  kind: "cli",
28986
29758
  name: "groups create",
28987
- module: route11
29759
+ module: route12
28988
29760
  }),
28989
29761
  "cli:groups/delete": Object.freeze({
28990
29762
  id: "cli:groups/delete",
28991
29763
  kind: "cli",
28992
29764
  name: "groups delete",
28993
- module: route12
29765
+ module: route13
28994
29766
  }),
28995
29767
  "cli:groups/get": Object.freeze({
28996
29768
  id: "cli:groups/get",
28997
29769
  kind: "cli",
28998
29770
  name: "groups get",
28999
- module: route13
29771
+ module: route14
29000
29772
  }),
29001
29773
  "cli:groups/list": Object.freeze({
29002
29774
  id: "cli:groups/list",
29003
29775
  kind: "cli",
29004
29776
  name: "groups list",
29005
- module: route14
29777
+ module: route15
29006
29778
  }),
29007
29779
  "cli:groups/members": Object.freeze({
29008
29780
  id: "cli:groups/members",
29009
29781
  kind: "cli",
29010
29782
  name: "groups members",
29011
- module: route15
29783
+ module: route16
29012
29784
  }),
29013
29785
  "cli:groups/remove": Object.freeze({
29014
29786
  id: "cli:groups/remove",
29015
29787
  kind: "cli",
29016
29788
  name: "groups remove",
29017
- module: route16
29789
+ module: route17
29018
29790
  }),
29019
29791
  "cli:groups/set": Object.freeze({
29020
29792
  id: "cli:groups/set",
29021
29793
  kind: "cli",
29022
29794
  name: "groups set",
29023
- module: route17
29795
+ module: route18
29024
29796
  }),
29025
29797
  "cli:groups/update": Object.freeze({
29026
29798
  id: "cli:groups/update",
29027
29799
  kind: "cli",
29028
29800
  name: "groups update",
29029
- module: route18
29801
+ module: route19
29030
29802
  }),
29031
29803
  "cli:history": Object.freeze({
29032
29804
  id: "cli:history",
29033
29805
  kind: "cli",
29034
29806
  name: "history",
29035
- module: route19
29807
+ module: route20
29036
29808
  }),
29037
29809
  "cli:send": Object.freeze({
29038
29810
  id: "cli:send",
29039
29811
  kind: "cli",
29040
29812
  name: "send",
29041
- module: route20
29813
+ module: route21
29042
29814
  }),
29043
29815
  "cli:thread": Object.freeze({
29044
29816
  id: "cli:thread",
29045
29817
  kind: "cli",
29046
29818
  name: "thread",
29047
- module: route21
29819
+ module: route22
29048
29820
  })
29049
29821
  });
29050
29822
  const requests = new Map();
@@ -29079,18 +29851,18 @@ const render = async (message)=>{
29079
29851
  };
29080
29852
  try {
29081
29853
  const cwd = process.cwd();
29082
- await (0,_agent_bundle_runtime__rspack_import_26/* .runAgentRequest */.iC)({
29854
+ await (0,_agent_bundle_runtime__rspack_import_27/* .runAgentRequest */.iC)({
29083
29855
  capabilities: {
29084
- command: (0,_agent_bundle_runtime__rspack_import_26/* .unavailable */.hU)(),
29085
- filesystem: (0,_agent_bundle_runtime__rspack_import_26/* .unavailable */.hU)(),
29086
- network: (0,_agent_bundle_runtime__rspack_import_26/* .unavailable */.hU)(),
29087
- projectRoot: (0,_agent_bundle_runtime__rspack_import_26/* .available */.qC)({
29856
+ command: (0,_agent_bundle_runtime__rspack_import_27/* .unavailable */.hU)(),
29857
+ filesystem: (0,_agent_bundle_runtime__rspack_import_27/* .unavailable */.hU)(),
29858
+ network: (0,_agent_bundle_runtime__rspack_import_27/* .unavailable */.hU)(),
29859
+ projectRoot: (0,_agent_bundle_runtime__rspack_import_27/* .available */.qC)({
29088
29860
  root: cwd
29089
29861
  }, 'derived')
29090
29862
  },
29091
- host: (0,_agent_bundle_runtime__rspack_import_26/* .unavailable */.hU)('unsupported-surface'),
29863
+ host: (0,_agent_bundle_runtime__rspack_import_27/* .unavailable */.hU)('unsupported-surface'),
29092
29864
  invocation: message.request,
29093
- lineage: (0,_agent_bundle_runtime__rspack_import_26/* .unavailable */.hU)('unsupported-surface'),
29865
+ lineage: (0,_agent_bundle_runtime__rspack_import_27/* .unavailable */.hU)('unsupported-surface'),
29094
29866
  plugin: pluginRoot.identity,
29095
29867
  progress: {
29096
29868
  report: async (update)=>{
@@ -29103,8 +29875,8 @@ const render = async (message)=>{
29103
29875
  },
29104
29876
  process: processHit,
29105
29877
  signal: controller.signal,
29106
- terminal: message.terminal === undefined ? (0,_agent_bundle_runtime__rspack_import_26/* .unavailable */.hU)('not-provided') : (0,_agent_bundle_runtime__rspack_import_26/* .available */.qC)(message.terminal, 'native'),
29107
- workspace: (0,_agent_bundle_runtime__rspack_import_26/* .available */.qC)({
29878
+ terminal: message.terminal === undefined ? (0,_agent_bundle_runtime__rspack_import_27/* .unavailable */.hU)('not-provided') : (0,_agent_bundle_runtime__rspack_import_27/* .available */.qC)(message.terminal, 'native'),
29879
+ workspace: (0,_agent_bundle_runtime__rspack_import_27/* .available */.qC)({
29108
29880
  root: cwd
29109
29881
  }, 'derived')
29110
29882
  }, async ()=>{
@@ -29113,7 +29885,7 @@ const render = async (message)=>{
29113
29885
  type: 'observed-render-start'
29114
29886
  });
29115
29887
  const renderStartedAt = performance.now();
29116
- const flight = (0,_agent_bundle_runtime_flight_server__rspack_import_27/* .renderAgentFlight */.y)(composeLayouts(observedRoute, {
29888
+ const flight = (0,_agent_bundle_runtime_flight_server__rspack_import_28/* .renderAgentFlight */.y)(composeLayouts(observedRoute, {
29117
29889
  ...message.props,
29118
29890
  signal: controller.signal
29119
29891
  }, controller.signal), {