grok-bot-cli 0.10.1 → 0.11.0

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.
@@ -22133,17 +22133,20 @@ var __webpack_modules__ = {
22133
22133
  var node_child_process__rspack_import_5 = __webpack_require__("node:child_process");
22134
22134
  var _package_json__rspack_import_6 = __webpack_require__("./package.json");
22135
22135
  var _codex_contract_js__rspack_import_7 = __webpack_require__("./src/core/codex/contract.js");
22136
- var _desktop_shim_js__rspack_import_8 = __webpack_require__("./src/core/desktop-shim.js");
22137
- var _user_machine_guidance_js__rspack_import_9 = __webpack_require__("./src/core/user-machine-guidance.js");
22138
- const PINNED_CODEX_VERSION = "0.154.0";
22136
+ var _codex_remote_control_js__rspack_import_8 = __webpack_require__("./src/core/codex/remote-control.js");
22137
+ var _codex_thread_id_js__rspack_import_11 = __webpack_require__("./src/core/codex/thread-id.js");
22138
+ var _desktop_shim_js__rspack_import_9 = __webpack_require__("./src/core/desktop-shim.js");
22139
+ var _user_machine_guidance_js__rspack_import_10 = __webpack_require__("./src/core/user-machine-guidance.js");
22140
+ const PINNED_CODEX_VERSION = "0.158.0";
22139
22141
  const UPSTREAM_DESKTOP_ISSUES = [
22140
22142
  "https://github.com/openai/codex/issues/41014",
22141
22143
  "https://github.com/openai/codex/issues/41112"
22142
22144
  ];
22143
22145
  const WS_GUID = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
22144
22146
  const WS_MAX_HEADER_BYTES = 16 * 1024;
22145
- const WS_MAX_MESSAGE_BYTES = 4 * 1024 * 1024;
22146
- const WS_MAX_BUFFER_BYTES = 8 * 1024 * 1024;
22147
+ const WS_MAX_MESSAGE_BYTES = 16 * 1024 * 1024;
22148
+ const WS_MAX_BUFFER_BYTES = 32 * 1024 * 1024;
22149
+ const CODEX_SEND_MAX_BYTES = 4 * 1024 * 1024;
22147
22150
  const WS_MAX_WRITE_BYTES = 8 * 1024 * 1024;
22148
22151
  const CODEX_MAX_REQUESTS = 128;
22149
22152
  const CODEX_MAX_LISTENERS = 128;
@@ -22171,11 +22174,11 @@ var __webpack_modules__ = {
22171
22174
  function boxUnreachableMessage(path) {
22172
22175
  return [
22173
22176
  "No Codex app-server control socket at " + path + ".",
22174
- _user_machine_guidance_js__rspack_import_9.M
22177
+ _user_machine_guidance_js__rspack_import_10.M
22175
22178
  ].join("\n");
22176
22179
  }
22177
22180
  function unreachableMessage(path, desktopAttached = "unknown", env = process.env) {
22178
- if ((0, _user_machine_guidance_js__rspack_import_9.R)({
22181
+ if ((0, _user_machine_guidance_js__rspack_import_10.R)({
22179
22182
  path,
22180
22183
  env,
22181
22184
  home: env.HOME || (0, node_os__rspack_import_3.homedir)()
@@ -22195,7 +22198,7 @@ var __webpack_modules__ = {
22195
22198
  "Either no daemon is running (start one with `codex app-server daemon start` or bootstrap),",
22196
22199
  "or ChatGPT Desktop is running a private stdio app-server that external clients cannot reach",
22197
22200
  "(" + UPSTREAM_DESKTOP_ISSUES.join(", ") + ").",
22198
- "gbot connects only to this machine's local socket; it has no remote transport.",
22201
+ "Codex must run on the same machine as gbot. Set CODEX_APP_SERVER_SOCK to an existing local control socket if it is elsewhere; gbot has no remote transport.",
22199
22202
  "gbot codex targets daemon-managed threads only."
22200
22203
  ].join("\n");
22201
22204
  }
@@ -22839,6 +22842,47 @@ var __webpack_modules__ = {
22839
22842
  };
22840
22843
  }
22841
22844
  const openSession = openCodexSession;
22845
+ async function startCodexThread({ cwd, expectedCwd, model, effort, message, env = process.env, signal } = {}) {
22846
+ validateModelEffort(model, effort);
22847
+ if (typeof cwd !== "string" || !cwd.trim()) throw new RangeError("--cwd is required for a new Codex thread");
22848
+ const resolvedCwd = realpathSync(cwd);
22849
+ if (expectedCwd !== undefined && realpathSync(expectedCwd) !== resolvedCwd) throw new RangeError("New Codex thread cwd does not match expectedCwd");
22850
+ if (message !== undefined && (typeof message !== "string" || !message.trim())) throw new RangeError("Message must contain text");
22851
+ const { client } = await openSession(env, {
22852
+ signal
22853
+ });
22854
+ let threadId, started;
22855
+ try {
22856
+ started = await client.request("thread/start", {
22857
+ cwd: resolvedCwd,
22858
+ ...model ? {
22859
+ model
22860
+ } : {},
22861
+ ...effort ? {
22862
+ config: {
22863
+ model_reasoning_effort: effort
22864
+ }
22865
+ } : {}
22866
+ });
22867
+ threadId = started?.thread?.id;
22868
+ if (typeof threadId !== "string" || !ID_PATTERN.test(threadId)) throw new CodexProtocolError("thread/start", "missing `thread.id`");
22869
+ } finally{
22870
+ client.close();
22871
+ }
22872
+ if (message === undefined) return {
22873
+ threadId,
22874
+ cwd: resolvedCwd,
22875
+ model: started.model ?? model,
22876
+ exitCode: 0
22877
+ };
22878
+ return await sendToCodexThread(threadId, message, {
22879
+ env,
22880
+ expectedCwd: resolvedCwd,
22881
+ model,
22882
+ effort,
22883
+ signal
22884
+ });
22885
+ }
22842
22886
  const CODEX_VERSION_PROBE_TIMEOUT_MS = 3000;
22843
22887
  function probeLocalCodexVersion(timeoutMs = CODEX_VERSION_PROBE_TIMEOUT_MS) {
22844
22888
  const out = spawnSync("codex", [
@@ -22973,6 +23017,13 @@ var __webpack_modules__ = {
22973
23017
  if (value == null) return null;
22974
23018
  return typeof value === "string" ? singleLine(value) : value;
22975
23019
  }
23020
+ function summarizeSection(section) {
23021
+ if (!isObject(section) || typeof section.id !== "string" || !section.id) return null;
23022
+ return {
23023
+ id: singleLine(section.id),
23024
+ name: lineField(section.name)
23025
+ };
23026
+ }
22976
23027
  function summarizeThread(t) {
22977
23028
  if (!isObject(t) || typeof t.id !== "string" || !t.id) throw new CodexProtocolError("thread/list", "entry without a string `id`");
22978
23029
  const type = isObject(t.status) && typeof t.status.type === "string" ? t.status.type : "unknown";
@@ -22984,43 +23035,72 @@ var __webpack_modules__ = {
22984
23035
  preview: typeof t.preview === "string" ? stripTerminalControls(t.preview) : "",
22985
23036
  cwd: lineField(t.cwd),
22986
23037
  source: sourceField(t.source),
22987
- updatedAt: typeof t.updatedAt === "number" ? t.updatedAt : null
23038
+ createdAt: typeof t.createdAt === "number" ? t.createdAt : null,
23039
+ updatedAt: typeof t.updatedAt === "number" ? t.updatedAt : null,
23040
+ section: summarizeSection(t.section),
23041
+ projectId: lineField(t.projectId),
23042
+ modelProvider: lineField(t.modelProvider),
23043
+ model: lineField(t.model),
23044
+ originator: lineField(t.originator)
22988
23045
  };
22989
23046
  }
22990
23047
  const THREAD_LIST_MAX_LIMIT = 200;
22991
- async function listCodexThreads({ limit = 20, cursor, env = process.env } = {}) {
23048
+ async function listCodexThreads({ limit = 20, cursor, modelProviders = [], env = process.env } = {}) {
22992
23049
  if (!Number.isInteger(limit) || limit < 1 || limit > THREAD_LIST_MAX_LIMIT) {
22993
23050
  throw new RangeError("--limit must be an integer 1-" + THREAD_LIST_MAX_LIMIT);
22994
23051
  }
22995
23052
  if (cursor !== undefined && (typeof cursor !== "string" || !cursor)) throw new RangeError("--cursor must be a non-empty string");
23053
+ if (!Array.isArray(modelProviders) || modelProviders.some((p)=>typeof p !== "string")) {
23054
+ throw new RangeError("modelProviders must be an array of strings (empty = all providers)");
23055
+ }
22996
23056
  const { client } = await openSession(env);
22997
23057
  try {
22998
- const params = {
23058
+ const baseParams = {
22999
23059
  limit,
23000
- useStateDbOnly: true,
23060
+ modelProviders,
23001
23061
  ...cursor !== undefined ? {
23002
23062
  cursor
23003
23063
  } : {}
23004
23064
  };
23005
23065
  let out;
23066
+ let usedStateDbOnly = true;
23006
23067
  try {
23007
- out = await client.request("thread/list", params);
23068
+ out = await client.request("thread/list", {
23069
+ ...baseParams,
23070
+ useStateDbOnly: true
23071
+ });
23008
23072
  } catch (err) {
23009
23073
  throw transportError(err);
23010
23074
  }
23011
23075
  if (!isObject(out) || !Array.isArray(out.data)) throw new CodexProtocolError("thread/list", "missing `data` array");
23076
+ if (out.data.length === 0 && cursor === undefined && (out.nextCursor == null || out.nextCursor === "")) {
23077
+ try {
23078
+ out = await client.request("thread/list", {
23079
+ ...baseParams,
23080
+ useStateDbOnly: false
23081
+ });
23082
+ usedStateDbOnly = false;
23083
+ } catch (err) {
23084
+ throw transportError(err);
23085
+ }
23086
+ if (!isObject(out) || !Array.isArray(out.data)) throw new CodexProtocolError("thread/list", "missing `data` array");
23087
+ }
23012
23088
  if (out.nextCursor != null && typeof out.nextCursor !== "string") throw new CodexProtocolError("thread/list", "`nextCursor` is not a string");
23013
23089
  const threads = out.data.map(summarizeThread);
23014
23090
  return {
23015
23091
  threads,
23016
23092
  nextCursor: out.nextCursor ?? null,
23017
- limit
23093
+ limit,
23094
+ useStateDbOnly: usedStateDbOnly
23018
23095
  };
23019
23096
  } finally{
23020
23097
  client.close();
23021
23098
  }
23022
23099
  }
23023
- function explainSendError(err, threadId) {
23100
+ function explainSendError(err, threadId, env = process.env) {
23101
+ if (err instanceof _codex_remote_control_js__rspack_import_8.Rg) return err;
23102
+ const mapped = (0, _codex_remote_control_js__rspack_import_8.R3)(err, threadId, env);
23103
+ if (mapped instanceof _codex_remote_control_js__rspack_import_8.Rg) return mapped;
23024
23104
  if (!(err instanceof CodexRpcError)) return err;
23025
23105
  const msg = String(err.rpc && err.rpc.message || "");
23026
23106
  if (/no rollout found|thread not found/i.test(msg)) {
@@ -23095,12 +23175,19 @@ var __webpack_modules__ = {
23095
23175
  function assertThreadAllowed(threadId, env = process.env) {
23096
23176
  const raw = env.GROK_BOT_CODEX_THREADS;
23097
23177
  if (raw == null || raw.trim() === "") return;
23098
- const allowed = raw.split(",").map((s)=>s.trim()).filter(Boolean);
23099
- if (!allowed.includes(threadId)) {
23100
- throw new CodexSendError("Codex thread " + threadId + " is not in GROK_BOT_CODEX_THREADS; the operator allows only: " + allowed.join(", "), {
23178
+ const bare = (0, _codex_thread_id_js__rspack_import_11.SX)(threadId);
23179
+ const allowed = raw.split(",").map((s)=>{
23180
+ try {
23181
+ return (0, _codex_thread_id_js__rspack_import_11.SX)(s.trim());
23182
+ } catch {
23183
+ return s.trim();
23184
+ }
23185
+ }).filter(Boolean);
23186
+ if (!allowed.includes(bare)) {
23187
+ throw new CodexSendError("Codex thread " + bare + " is not in GROK_BOT_CODEX_THREADS; the operator allows only: " + allowed.join(", "), {
23101
23188
  delivery: "rejected",
23102
23189
  reason: "route-not-allowed",
23103
- threadId
23190
+ threadId: bare
23104
23191
  });
23105
23192
  }
23106
23193
  }
@@ -23137,7 +23224,7 @@ var __webpack_modules__ = {
23137
23224
  }
23138
23225
  function requireExperimental(env, what) {
23139
23226
  if (experimentalEnabled(env)) return;
23140
- throw new CodexSendError(what + " uses Codex's experimental app-server API (thread/queue/*), which is off by default. " + "Set GROK_BOT_CODEX_EXPERIMENTAL=1 to opt in; method names are pinned to Codex " + PINNED_CODEX_VERSION + ".", {
23227
+ throw new CodexSendError(what + " needs thread/queue/add, which is experimental and absent from Codex " + PINNED_CODEX_VERSION + "'s stable API. " + "Use --when-busy steer with an expected turn ID, wait until the thread is idle, or opt in with GROK_BOT_CODEX_EXPERIMENTAL=1 on a Codex daemon that supports the experimental queue API.", {
23141
23228
  delivery: "rejected",
23142
23229
  reason: "experimental-disabled"
23143
23230
  });
@@ -23145,7 +23232,7 @@ var __webpack_modules__ = {
23145
23232
  function unsupportedOrRpc(err, method, threadId, envelope, turnId) {
23146
23233
  const guarded = method === "turn/steer";
23147
23234
  if (err instanceof CodexRpcError && err.rpc && err.rpc.code === -32601) {
23148
- return new CodexSendError("Codex app-server does not offer " + method + " (daemon predates it, or experimentalApi was not granted). " + (guarded ? "Upgrade Codex before retrying guarded steering." : "Upgrade Codex or send without --when-busy queue."), {
23235
+ return new CodexSendError("Codex app-server does not offer " + method + " (daemon predates it, or experimentalApi was not granted). " + (guarded ? "Upgrade Codex before retrying guarded steering." : "Use --when-busy steer with an expected turn ID, wait for idle, or use a Codex daemon with experimental queue support and GROK_BOT_CODEX_EXPERIMENTAL=1."), {
23149
23236
  delivery: "rejected",
23150
23237
  reason: "unsupported",
23151
23238
  threadId,
@@ -23170,6 +23257,7 @@ var __webpack_modules__ = {
23170
23257
  }
23171
23258
  async function listCodexQueue(threadId, { env = process.env, limit = 50, cursor } = {}) {
23172
23259
  requireExperimental(env, "gbot codex queue");
23260
+ threadId = normalizeCodexThreadId(threadId);
23173
23261
  const { client } = await openSession(env, {
23174
23262
  experimental: true
23175
23263
  });
@@ -23200,9 +23288,67 @@ var __webpack_modules__ = {
23200
23288
  client.close();
23201
23289
  }
23202
23290
  }
23291
+ async function readCodexThread(threadId, { limit = 100, env = process.env } = {}) {
23292
+ if (!Number.isInteger(limit) || limit < 1 || limit > 2000) {
23293
+ throw new RangeError("limit must be an integer 1-2000");
23294
+ }
23295
+ const bare = normalizeCodexThreadId(threadId);
23296
+ const { client } = await openSession(env);
23297
+ try {
23298
+ let meta;
23299
+ try {
23300
+ meta = await client.request("thread/read", {
23301
+ threadId: bare
23302
+ });
23303
+ } catch (err) {
23304
+ const mapped = explainSendError(err, bare, env);
23305
+ if (mapped instanceof RemoteThreadNotLoadedError) throw mapped;
23306
+ throw transportError(err);
23307
+ }
23308
+ const turns = [];
23309
+ let cursor;
23310
+ const seen = new Set();
23311
+ for(let page = 0; page < 40 && turns.length < limit; page++){
23312
+ let out;
23313
+ try {
23314
+ out = await client.request("thread/turns/list", {
23315
+ threadId: bare,
23316
+ limit: Math.min(100, limit - turns.length),
23317
+ itemsView: "full",
23318
+ sortDirection: "desc",
23319
+ ...cursor !== undefined ? {
23320
+ cursor
23321
+ } : {}
23322
+ });
23323
+ } catch (err) {
23324
+ const mapped = explainSendError(err, bare, env);
23325
+ if (mapped instanceof RemoteThreadNotLoadedError) throw mapped;
23326
+ throw transportError(err);
23327
+ }
23328
+ if (!isObject(out) || !Array.isArray(out.data)) {
23329
+ throw new CodexProtocolError("thread/turns/list", "missing `data` array");
23330
+ }
23331
+ for (const row of out.data)turns.push(row);
23332
+ cursor = out.nextCursor ?? null;
23333
+ if (cursor === null) break;
23334
+ if (typeof cursor !== "string" || !cursor || seen.has(cursor)) {
23335
+ throw new CodexProtocolError("thread/turns/list", "invalid or repeated cursor");
23336
+ }
23337
+ seen.add(cursor);
23338
+ }
23339
+ return {
23340
+ threadId: bare,
23341
+ thread: isObject(meta) && isObject(meta.thread) ? meta.thread : null,
23342
+ turns: turns.slice(0, limit),
23343
+ nextCursor: cursor ?? null
23344
+ };
23345
+ } finally{
23346
+ client.close();
23347
+ }
23348
+ }
23203
23349
  async function sendToCodexThread(threadId, text, { env = process.env, envelope = buildEnvelope({
23204
23350
  env
23205
- }), whenBusy = "reject", session, expectedTurnId, expectedCwd, signal } = {}) {
23351
+ }), whenBusy = "reject", session, expectedTurnId, expectedCwd, model, effort, signal } = {}) {
23206
23352
  try {
23207
23353
  const receipt = await sendToCodexThreadInner(threadId, text, {
23208
23354
  env,
@@ -23211,6 +23357,8 @@ var __webpack_modules__ = {
23211
23357
  session,
23212
23358
  expectedTurnId,
23213
23359
  expectedCwd,
23360
+ model,
23361
+ effort,
23214
23362
  signal
23215
23363
  });
23216
23364
  return (0, _codex_contract_js__rspack_import_7.Dz)(receipt);
@@ -23222,7 +23370,19 @@ var __webpack_modules__ = {
23222
23370
  return (0, _codex_contract_js__rspack_import_7.DG)(err);
23223
23371
  }
23224
23372
  }
23225
- async function sendToCodexThreadInner(threadId, text, { env, envelope, whenBusy, session, expectedTurnId, expectedCwd, signal }) {
23373
+ function validateModelEffort(model, effort) {
23374
+ if (model !== undefined && (typeof model !== "string" || !/^[A-Za-z0-9][A-Za-z0-9._:/-]{0,127}$/.test(model))) throw new RangeError("--model must be a nonempty model ID");
23375
+ if (effort !== undefined && ![
23376
+ "none",
23377
+ "minimal",
23378
+ "low",
23379
+ "medium",
23380
+ "high",
23381
+ "xhigh"
23382
+ ].includes(effort)) throw new RangeError("--effort must be none, minimal, low, medium, high, or xhigh");
23383
+ }
23384
+ async function sendToCodexThreadInner(threadId, text, { env, envelope, whenBusy, session, expectedTurnId, expectedCwd, model, effort, signal }) {
23385
+ validateModelEffort(model, effort);
23226
23386
  if (![
23227
23387
  "reject",
23228
23388
  "queue",
@@ -23231,8 +23391,8 @@ var __webpack_modules__ = {
23231
23391
  ] : []
23232
23392
  ].includes(whenBusy)) throw new RangeError("--when-busy must be reject, queue, or persistent steer");
23233
23393
  if (whenBusy === "steer" && (typeof expectedTurnId !== "string" || !ID_PATTERN.test(expectedTurnId))) throw new RangeError("steer requires expectedTurnId");
23234
- if (typeof threadId !== "string" || !ID_PATTERN.test(threadId)) throw new RangeError("Invalid threadId");
23235
- if (typeof text !== "string" || !text.trim() || Buffer.byteLength(text) > WS_MAX_MESSAGE_BYTES) throw new RangeError("Message must contain text within 4 MiB");
23394
+ threadId = (0, _codex_thread_id_js__rspack_import_11.SX)(threadId);
23395
+ if (typeof text !== "string" || !text.trim() || Buffer.byteLength(text) > CODEX_SEND_MAX_BYTES) throw new RangeError("Message must contain text within 4 MiB");
23236
23396
  if (!envelope || typeof envelope.messageId !== "string" || !ID_PATTERN.test(envelope.messageId)) throw new RangeError("Invalid envelope messageId");
23237
23397
  const validated = buildEnvelope({
23238
23398
  correlationId: envelope.correlationId,
@@ -23268,12 +23428,22 @@ var __webpack_modules__ = {
23268
23428
  try {
23269
23429
  resumed = await client.request("thread/resume", {
23270
23430
  threadId,
23271
- excludeTurns: true
23431
+ excludeTurns: true,
23432
+ ...model ? {
23433
+ model
23434
+ } : {},
23435
+ ...effort ? {
23436
+ config: {
23437
+ model_reasoning_effort: effort
23438
+ }
23439
+ } : {}
23272
23440
  });
23273
23441
  } catch (err) {
23274
23442
  assertNotCancelled();
23275
- if (err instanceof CodexSendError) throw err;
23276
- throw new CodexSendError(explainSendError(err, threadId).message, {
23443
+ if (err instanceof CodexSendError || err instanceof _codex_remote_control_js__rspack_import_8.Rg) throw err;
23444
+ const explained = explainSendError(err, threadId, env);
23445
+ if (explained instanceof _codex_remote_control_js__rspack_import_8.Rg) throw explained;
23446
+ throw new CodexSendError(explained.message, {
23277
23447
  delivery: err instanceof CodexRpcError ? "rejected" : err && err.delivery || "unknown",
23278
23448
  reason: err instanceof CodexRpcError ? /no rollout found|thread not found/i.test(String(err.rpc && err.rpc.message)) ? "unknown-thread" : /active writer/i.test(String(err.rpc && err.rpc.message)) ? "external-owner" : "rejected" : "transport",
23279
23449
  threadId,
@@ -23401,7 +23571,13 @@ var __webpack_modules__ = {
23401
23571
  }
23402
23572
  ],
23403
23573
  clientUserMessageId: envelope.messageId,
23404
- turnTrigger: "gbot"
23574
+ turnTrigger: "gbot",
23575
+ ...model ? {
23576
+ model
23577
+ } : {},
23578
+ ...effort ? {
23579
+ effort
23580
+ } : {}
23405
23581
  });
23406
23582
  } catch (err) {
23407
23583
  if (err instanceof CodexSendError) throw err;
@@ -23498,7 +23674,11 @@ var __webpack_modules__ = {
23498
23674
  "messageId",
23499
23675
  "correlationId",
23500
23676
  "refused",
23501
- "hop"
23677
+ "hop",
23678
+ "hostId",
23679
+ "hostName",
23680
+ "hint",
23681
+ "code"
23502
23682
  ]){
23503
23683
  if (error[key] !== undefined) out[key] = error[key];
23504
23684
  }
@@ -23533,9 +23713,12 @@ var __webpack_modules__ = {
23533
23713
  var _contract_js__rspack_import_0 = __webpack_require__("./src/core/codex/contract.js");
23534
23714
  var node_fs__rspack_import_1 = __webpack_require__("node:fs");
23535
23715
  var _codex_bridge_js__rspack_import_2 = __webpack_require__("./src/core/codex-bridge.js");
23716
+ var _remote_control_js__rspack_import_3 = __webpack_require__("./src/core/codex/remote-control.js");
23717
+ var _thread_id_js__rspack_import_4 = __webpack_require__("./src/core/codex/thread-id.js");
23536
23718
  const ID = /^[A-Za-z0-9_.:-]{1,128}$/;
23537
23719
  const BUDGET = 4 * 1024 * 1024;
23538
23720
  function conversationId(value, name = 'threadId') {
23721
+ if (name === 'threadId') return (0, _thread_id_js__rspack_import_4.SX)(value);
23539
23722
  if (typeof value !== 'string' || !ID.test(value)) throw new RangeError(`${name} must be 1-128 identifier characters`);
23540
23723
  return value;
23541
23724
  }
@@ -23660,7 +23843,8 @@ var __webpack_modules__ = {
23660
23843
  if (expected !== undefined && (typeof cwd !== 'string' || (0, node_fs__rspack_import_1.realpathSync)(cwd) !== expected)) throw new Error('Codex thread cwd does not match expectedCwd');
23661
23844
  } catch (error) {
23662
23845
  await close();
23663
- throw error;
23846
+ if (error instanceof _remote_control_js__rspack_import_3.Rg) throw error;
23847
+ throw (0, _remote_control_js__rspack_import_3.R3)(error, threadId, env);
23664
23848
  }
23665
23849
  async function wait({ turnId, messageId, afterMessageId, timeoutMs = 120000, signal: waitSignal, maxOutputBytes = 1048576 }) {
23666
23850
  conversationId(turnId, 'turnId');
@@ -23670,10 +23854,10 @@ var __webpack_modules__ = {
23670
23854
  ];
23671
23855
  if (afterMessageId !== undefined) boundedInteger(anchors.length, 200, 'afterMessageId count');
23672
23856
  for (const anchor of anchors)conversationId(anchor, 'afterMessageId');
23673
- boundedInteger(timeoutMs, 600000, 'timeoutMs');
23857
+ boundedInteger(timeoutMs, 7200000, 'timeoutMs');
23674
23858
  boundedInteger(maxOutputBytes, BUDGET, 'maxOutputBytes');
23675
23859
  if (waitSignal !== undefined && !(waitSignal instanceof AbortSignal)) throw new TypeError('signal must be an AbortSignal');
23676
- let done = false, status = acceptedTurns.has(turnId) ? 'inProgress' : undefined, error, historyError, itemBytes = 0, truncated = overflow;
23860
+ let done = false, status = acceptedTurns.has(turnId) ? 'inProgress' : undefined, error, historyError, itemBytes = 0, truncated = false;
23677
23861
  const items = new Map();
23678
23862
  const add = (item)=>{
23679
23863
  if (!item || typeof item.id !== 'string' || typeof item.type !== 'string') throw new Error('Invalid history item');
@@ -23720,6 +23904,7 @@ var __webpack_modules__ = {
23720
23904
  };
23721
23905
  const result = (state, detail)=>{
23722
23906
  const interactions = scan();
23907
+ const overflowUncertain = state === 'unknown' && /Notification coverage overflow/.test(detail ?? '');
23723
23908
  const candidates = [
23724
23909
  ...items.values()
23725
23910
  ].map((x)=>x.item);
@@ -23728,7 +23913,7 @@ var __webpack_modules__ = {
23728
23913
  const reply = {
23729
23914
  text: '',
23730
23915
  items: [],
23731
- truncated: truncated || overflow
23916
+ truncated: truncated || overflowUncertain
23732
23917
  };
23733
23918
  for (const item of selected){
23734
23919
  const text = reply.text ? `${reply.text}\n${item.text}` : item.text;
@@ -23761,7 +23946,7 @@ var __webpack_modules__ = {
23761
23946
  interactions
23762
23947
  };
23763
23948
  };
23764
- let timer, notify;
23949
+ let timer, pollTimer, notify;
23765
23950
  const abortSignals = [
23766
23951
  signal,
23767
23952
  waitSignal
@@ -23777,10 +23962,18 @@ var __webpack_modules__ = {
23777
23962
  'Codex connection closed'
23778
23963
  ]);
23779
23964
  };
23780
- timer = setTimeout(()=>resolve([
23965
+ timer = setTimeout(()=>resolve(overflow ? [
23966
+ 'unknown',
23967
+ 'Notification coverage overflow; pending interaction status is uncertain'
23968
+ ] : [
23781
23969
  'timeout',
23782
23970
  'Observation deadline reached'
23783
23971
  ]), timeoutMs);
23972
+ pollTimer = setInterval(()=>{
23973
+ for (const listener of [
23974
+ ...wake
23975
+ ])listener();
23976
+ }, 2000);
23784
23977
  for (const s of abortSignals)s.addEventListener('abort', notify, {
23785
23978
  once: true
23786
23979
  });
@@ -23851,19 +24044,51 @@ var __webpack_modules__ = {
23851
24044
  historyError
23852
24045
  ];
23853
24046
  }
24047
+ let lastPoll = 0;
23854
24048
  while(!done){
23855
24049
  const interactions = scan();
23856
24050
  if (terminal(status)) return [
23857
24051
  status,
23858
24052
  error ?? historyError
23859
24053
  ];
23860
- if (historyError || overflow) return [
24054
+ if (historyError) return [
23861
24055
  'unknown',
23862
- historyError ?? 'Notification coverage overflow'
24056
+ historyError
23863
24057
  ];
23864
24058
  if (interactions.length) return [
23865
24059
  'waiting-for-input'
23866
24060
  ];
24061
+ if (Date.now() - lastPoll >= 2000) {
24062
+ lastPoll = Date.now();
24063
+ try {
24064
+ await visitCodexHistory(session, threadId, 'thread/turns/list', {}, (data)=>{
24065
+ const turn = data.find((t)=>t?.id === turnId);
24066
+ if (!turn) return false;
24067
+ if (terminal(turn.status)) {
24068
+ status = turn.status;
24069
+ error = turn.error;
24070
+ }
24071
+ return true;
24072
+ }, {
24073
+ stopped: ()=>done
24074
+ });
24075
+ if (terminal(status)) {
24076
+ await visitCodexHistory(session, threadId, 'thread/items/list', {
24077
+ turnId,
24078
+ sortDirection: 'asc'
24079
+ }, (data)=>{
24080
+ for (const row of data)if (row?.turnId === turnId && row.item) add(row.item);
24081
+ return false;
24082
+ }, {
24083
+ stopped: ()=>done
24084
+ });
24085
+ continue;
24086
+ }
24087
+ } catch (err) {
24088
+ historyError = err.message;
24089
+ truncated = true;
24090
+ }
24091
+ }
23867
24092
  await new Promise((resolve)=>{
23868
24093
  const listener = ()=>{
23869
24094
  wake.delete(listener);
@@ -23886,6 +24111,7 @@ var __webpack_modules__ = {
23886
24111
  } finally{
23887
24112
  done = true;
23888
24113
  clearTimeout(timer);
24114
+ clearInterval(pollTimer);
23889
24115
  wake.delete(notify);
23890
24116
  for (const s of abortSignals)s.removeEventListener('abort', notify);
23891
24117
  for (const listener of [
@@ -23933,7 +24159,7 @@ var __webpack_modules__ = {
23933
24159
  close,
23934
24160
  async send (text, { envelope = (0, _codex_bridge_js__rspack_import_2.nq)({
23935
24161
  env
23936
- }), whenBusy = 'reject', expectedTurnId, signal: sendSignal } = {}) {
24162
+ }), whenBusy = 'reject', expectedTurnId, model, effort, signal: sendSignal } = {}) {
23937
24163
  if (closed) return (0, _contract_js__rspack_import_0.DG)(Object.assign(new Error('Conversation closed'), {
23938
24164
  delivery: 'rejected',
23939
24165
  reason: 'closed',
@@ -23952,6 +24178,8 @@ var __webpack_modules__ = {
23952
24178
  expectedTurnId,
23953
24179
  session,
23954
24180
  expectedCwd,
24181
+ model,
24182
+ effort,
23955
24183
  signal: submissionSignal
23956
24184
  });
23957
24185
  if (receipt.delivery === 'accepted' && receipt.turnId) {
@@ -23967,6 +24195,264 @@ var __webpack_modules__ = {
23967
24195
  j: ()=>openCodexConversation
23968
24196
  });
23969
24197
  },
24198
+ "./src/core/codex/remote-control.js" (__unused_rspack___webpack_module__, __webpack_exports__, __webpack_require__) {
24199
+ var node_fs__rspack_import_0 = __webpack_require__("node:fs");
24200
+ var node_os__rspack_import_1 = __webpack_require__("node:os");
24201
+ var node_path__rspack_import_2 = __webpack_require__("node:path");
24202
+ var _thread_id_js__rspack_import_3 = __webpack_require__("./src/core/codex/thread-id.js");
24203
+ const REMOTE_SUMMARY_KEY = /^remote-thread-summaries-v3:(.+)$/;
24204
+ class RemoteThreadNotLoadedError1 extends Error {
24205
+ constructor(threadId, hostId = null, hostName = null){
24206
+ const hostLabel = hostName ? `${JSON.stringify(hostName)} (${JSON.stringify(hostId)})` : hostId ? JSON.stringify(hostId) : null;
24207
+ const owner = hostLabel ? `owned by remote-control host ${hostLabel}` : 'owned by a remote-control host (hostId unknown; check ~/.codex/.codex-global-state.json)';
24208
+ const hint = hostId ? `Read this thread via host ${JSON.stringify(hostId)}'s app-server` + (hostName ? ` (${hostName})` : '') + '. SSH remoting is not implemented in this adapter.' : "Read this thread via the owning host's app-server. SSH remoting is not implemented in this adapter.";
24209
+ super(`Codex thread ${JSON.stringify(threadId)} is not loaded on the local app-server; ${owner}. ${hint}`);
24210
+ this.name = 'RemoteThreadNotLoadedError';
24211
+ this.code = 'REMOTE_THREAD_NOT_LOADED';
24212
+ this.delivery = 'rejected';
24213
+ this.reason = 'remote-thread-not-loaded';
24214
+ this.threadId = threadId;
24215
+ this.hostId = hostId;
24216
+ this.hostName = hostName;
24217
+ this.hint = hint;
24218
+ }
24219
+ }
24220
+ function codexGlobalStatePath(env = process.env) {
24221
+ const home = env.CODEX_HOME || (0, node_path__rspack_import_2.join)((0, node_os__rspack_import_1.homedir)(), '.codex');
24222
+ return (0, node_path__rspack_import_2.join)(home, '.codex-global-state.json');
24223
+ }
24224
+ function loadCodexGlobalState(env = process.env) {
24225
+ let raw;
24226
+ try {
24227
+ raw = (0, node_fs__rspack_import_0.readFileSync)(codexGlobalStatePath(env), 'utf8');
24228
+ } catch {
24229
+ return null;
24230
+ }
24231
+ try {
24232
+ const data = JSON.parse(raw);
24233
+ if (!data || typeof data !== 'object' || Array.isArray(data)) return null;
24234
+ return data;
24235
+ } catch {
24236
+ return null;
24237
+ }
24238
+ }
24239
+ function codexStateEntries(data) {
24240
+ const nested = data?.['electron-persisted-atom-state'];
24241
+ return [
24242
+ nested,
24243
+ data
24244
+ ].filter((value)=>value && typeof value === 'object' && !Array.isArray(value));
24245
+ }
24246
+ function findRemoteThreadHost(threadId, env = process.env) {
24247
+ let bare;
24248
+ try {
24249
+ bare = (0, _thread_id_js__rspack_import_3.SX)(threadId);
24250
+ } catch {
24251
+ bare = typeof threadId === 'string' && threadId.startsWith("local:") ? threadId.slice("local:".length) : threadId;
24252
+ }
24253
+ if (!bare) return null;
24254
+ const data = loadCodexGlobalState(env);
24255
+ if (!data) return null;
24256
+ const hostNames = collectHostNames(data);
24257
+ for (const [key, value] of codexStateEntries(data).flatMap(Object.entries)){
24258
+ const match = REMOTE_SUMMARY_KEY.exec(key);
24259
+ if (!match?.[1]) continue;
24260
+ const hostId = match[1];
24261
+ const hostName = hostNames.get(hostId) ?? extractHostName(value) ?? null;
24262
+ for (const entry of extractThreadEntries(value)){
24263
+ const id = threadIdFromEntry(entry);
24264
+ if (!id) continue;
24265
+ const entryBare = id.startsWith("local:") ? id.slice("local:".length) : id;
24266
+ if (entryBare === bare) return {
24267
+ hostId,
24268
+ hostName
24269
+ };
24270
+ }
24271
+ }
24272
+ return null;
24273
+ }
24274
+ function mapRemoteThreadError(error, threadId, env = process.env) {
24275
+ const message = errorMessage(error);
24276
+ if (!/thread not loaded|not loaded|no rollout found|thread not found|invalid thread id/i.test(message)) {
24277
+ return error instanceof Error ? error : new Error(message || String(error));
24278
+ }
24279
+ const remote = findRemoteThreadHost(threadId, env);
24280
+ if (remote) {
24281
+ return new RemoteThreadNotLoadedError1(threadId, remote.hostId, remote.hostName);
24282
+ }
24283
+ if (/thread not loaded|not loaded/i.test(message)) {
24284
+ return new RemoteThreadNotLoadedError1(threadId, null, null);
24285
+ }
24286
+ return error instanceof Error ? error : new Error(message || String(error));
24287
+ }
24288
+ function collectHostNames(data) {
24289
+ const names = new Map();
24290
+ for (const [key, value] of codexStateEntries(data).flatMap(Object.entries)){
24291
+ if (!/remote-host|hosts|host-meta|host_directory|environments/i.test(key)) continue;
24292
+ if (!value || typeof value !== 'object') continue;
24293
+ if (Array.isArray(value)) {
24294
+ for (const entry of value){
24295
+ const pair = hostNameFromEntry(entry);
24296
+ if (pair && !names.has(pair.hostId)) names.set(pair.hostId, pair.hostName);
24297
+ }
24298
+ continue;
24299
+ }
24300
+ for (const [hostId, entry] of Object.entries(value)){
24301
+ const fromEntry = hostNameFromEntry(entry);
24302
+ if (fromEntry) {
24303
+ if (!names.has(fromEntry.hostId)) names.set(fromEntry.hostId, fromEntry.hostName);
24304
+ continue;
24305
+ }
24306
+ const label = stringField(entry, [
24307
+ 'name',
24308
+ 'hostName',
24309
+ 'displayName',
24310
+ 'envName',
24311
+ 'label',
24312
+ 'title'
24313
+ ]);
24314
+ if (label && !names.has(hostId)) names.set(hostId, label);
24315
+ }
24316
+ }
24317
+ return names;
24318
+ }
24319
+ function hostNameFromEntry(entry) {
24320
+ if (!entry || typeof entry !== 'object' || Array.isArray(entry)) return null;
24321
+ const hostId = stringField(entry, [
24322
+ 'hostId',
24323
+ 'id',
24324
+ 'host_id',
24325
+ 'uuid'
24326
+ ]);
24327
+ const hostName = stringField(entry, [
24328
+ 'name',
24329
+ 'hostName',
24330
+ 'displayName',
24331
+ 'envName',
24332
+ 'label',
24333
+ 'title'
24334
+ ]);
24335
+ if (!hostId || !hostName) return null;
24336
+ return {
24337
+ hostId,
24338
+ hostName
24339
+ };
24340
+ }
24341
+ function extractHostName(value) {
24342
+ if (!value || typeof value !== 'object' || Array.isArray(value)) return null;
24343
+ return stringField(value, [
24344
+ 'hostName',
24345
+ 'displayName',
24346
+ 'name',
24347
+ 'envName',
24348
+ 'label',
24349
+ 'title',
24350
+ 'friendlyName'
24351
+ ]);
24352
+ }
24353
+ function extractThreadEntries(value) {
24354
+ if (Array.isArray(value)) return value;
24355
+ if (!value || typeof value !== 'object') return [];
24356
+ const record = value;
24357
+ for (const key of [
24358
+ 'threads',
24359
+ 'summaries',
24360
+ 'items',
24361
+ 'data',
24362
+ 'conversations'
24363
+ ]){
24364
+ if (Array.isArray(record[key])) return record[key];
24365
+ }
24366
+ const entries = [];
24367
+ for (const [key, entry] of Object.entries(record)){
24368
+ if ([
24369
+ 'pinnedIds',
24370
+ 'pinned',
24371
+ 'pinnedThreadIds',
24372
+ 'hostName',
24373
+ 'displayName',
24374
+ 'name',
24375
+ 'envName',
24376
+ 'label',
24377
+ 'title',
24378
+ 'friendlyName',
24379
+ 'hostId',
24380
+ 'version'
24381
+ ].includes(key)) continue;
24382
+ if (typeof entry === 'string') continue;
24383
+ if (entry && typeof entry === 'object' && !Array.isArray(entry)) {
24384
+ const id = stringField(entry, [
24385
+ 'id',
24386
+ 'threadId',
24387
+ 'thread_id',
24388
+ 'conversationId'
24389
+ ]);
24390
+ entries.push(id ? entry : {
24391
+ ...entry,
24392
+ id: key
24393
+ });
24394
+ }
24395
+ }
24396
+ return entries;
24397
+ }
24398
+ function threadIdFromEntry(entry) {
24399
+ if (typeof entry === 'string' && entry) return entry;
24400
+ if (!entry || typeof entry !== 'object' || Array.isArray(entry)) return null;
24401
+ return stringField(entry, [
24402
+ 'id',
24403
+ 'threadId',
24404
+ 'thread_id',
24405
+ 'conversationId'
24406
+ ]);
24407
+ }
24408
+ function stringField(row, keys) {
24409
+ if (!row || typeof row !== 'object' || Array.isArray(row)) return null;
24410
+ for (const key of keys){
24411
+ const value = row[key];
24412
+ if (typeof value === 'string' && value.trim()) return value.trim();
24413
+ }
24414
+ return null;
24415
+ }
24416
+ function errorMessage(error) {
24417
+ if (!error) return '';
24418
+ if (typeof error === 'string') return error;
24419
+ if (error instanceof Error) return error.message;
24420
+ if (typeof error === 'object' && error && 'message' in error) return String(error.message);
24421
+ if (typeof error === 'object' && error && 'rpc' in error) {
24422
+ const rpc = error.rpc;
24423
+ if (rpc && typeof rpc.message === 'string') return rpc.message;
24424
+ }
24425
+ return String(error);
24426
+ }
24427
+ __webpack_require__.d(__webpack_exports__, {
24428
+ R3: ()=>mapRemoteThreadError,
24429
+ Rg: ()=>RemoteThreadNotLoadedError1
24430
+ });
24431
+ },
24432
+ "./src/core/codex/thread-id.js" (__unused_rspack___webpack_module__, __webpack_exports__, __webpack_require__) {
24433
+ const LOCAL_THREAD_ID_PREFIX = 'local:';
24434
+ const TEMP_THREAD_ID_PREFIX = 'local:client-new-thread:';
24435
+ const ID_PATTERN = /^[A-Za-z0-9_.:-]{1,128}$/;
24436
+ function isTemporaryDesktopThreadId(threadId) {
24437
+ return typeof threadId === 'string' && (threadId.startsWith(TEMP_THREAD_ID_PREFIX) || threadId.startsWith('client-new-thread:'));
24438
+ }
24439
+ function normalizeCodexThreadId1(threadId) {
24440
+ if (typeof threadId !== 'string' || !threadId) {
24441
+ throw new RangeError('Invalid threadId');
24442
+ }
24443
+ if (isTemporaryDesktopThreadId(threadId)) {
24444
+ throw new RangeError('Temporary Desktop thread id ' + JSON.stringify(threadId) + ' has no app-server mapping; wait for the real conversation id');
24445
+ }
24446
+ const bare = threadId.startsWith(LOCAL_THREAD_ID_PREFIX) ? threadId.slice(LOCAL_THREAD_ID_PREFIX.length) : threadId;
24447
+ if (!bare || !ID_PATTERN.test(bare)) {
24448
+ throw new RangeError('Invalid threadId');
24449
+ }
24450
+ return bare;
24451
+ }
24452
+ __webpack_require__.d(__webpack_exports__, {
24453
+ SX: ()=>normalizeCodexThreadId1
24454
+ });
24455
+ },
23970
24456
  "./src/core/desktop-shim.js" (__unused_rspack___webpack_module__, __unused_rspack___webpack_exports__, __webpack_require__) {
23971
24457
  var node_child_process__rspack_import_0 = __webpack_require__("node:child_process");
23972
24458
  var node_fs__rspack_import_1 = __webpack_require__("node:fs");
@@ -25242,6 +25728,12 @@ ts() { date -u +%Y-%m-%dT%H:%M:%SZ; }
25242
25728
  whenBusy: active ? "steer" : "reject",
25243
25729
  ...active ? {
25244
25730
  expectedTurnId: active
25731
+ } : {},
25732
+ ...record.model ? {
25733
+ model: record.model
25734
+ } : {},
25735
+ ...record.effort ? {
25736
+ effort: record.effort
25245
25737
  } : {}
25246
25738
  });
25247
25739
  if (!active || receipt.delivery !== "rejected" || receipt.reason !== "rejected" || !/guard|expected.*turn|turn.*mismatch|stale/i.test(receipt.error ?? "")) return receipt;
@@ -26384,6 +26876,12 @@ ts() { date -u +%Y-%m-%dT%H:%M:%SZ; }
26384
26876
  threadId: r.threadId,
26385
26877
  expectedCwd: r.expectedCwd,
26386
26878
  busyPolicy: r.busyPolicy,
26879
+ ...input.model ? {
26880
+ model: input.model
26881
+ } : {},
26882
+ ...input.effort ? {
26883
+ effort: input.effort
26884
+ } : {},
26387
26885
  bindingId: r.bindingId ?? (r.id?.startsWith("binding:") ? r.id : null),
26388
26886
  text,
26389
26887
  sourceIds: input.sourceIds ?? [],
@@ -26476,6 +26974,15 @@ ts() { date -u +%Y-%m-%dT%H:%M:%SZ; }
26476
26974
  "steer",
26477
26975
  "reject"
26478
26976
  ]),
26977
+ model: zod__rspack_import_3.YjP().regex(/^[A-Za-z0-9][A-Za-z0-9._:/-]{0,127}$/).optional(),
26978
+ effort: zod__rspack_import_3.k5n([
26979
+ "none",
26980
+ "minimal",
26981
+ "low",
26982
+ "medium",
26983
+ "high",
26984
+ "xhigh"
26985
+ ]).optional(),
26479
26986
  bindingId: relayId.nullable(),
26480
26987
  text,
26481
26988
  sourceIds: zod__rspack_import_3.YOg(relayId).max(200),
@@ -27383,7 +27890,7 @@ ts() { date -u +%Y-%m-%dT%H:%M:%SZ; }
27383
27890
  "./src/core/user-machine-guidance.js" (__unused_rspack___webpack_module__, __webpack_exports__, __webpack_require__) {
27384
27891
  const USER_MACHINE_CODEX_CLAUDE_GUIDANCE = [
27385
27892
  "Codex and Claude sessions live on the user's registered machines (for example their Linux desktop or Mac), not on the Grok Bot agent box (/home/box).",
27386
- "gbot connects only to a local Unix socket ($CODEX_HOME/app-server-control/app-server-control.sock, or CODEX_APP_SERVER_SOCK). There is no remote transport.",
27893
+ "Codex must run on the same machine as gbot. Set CODEX_APP_SERVER_SOCK to an existing local control socket, or use $CODEX_HOME/app-server-control/app-server-control.sock. There is no remote transport.",
27387
27894
  "When running on the box (HOME=/home/box), do not call codex_* or claude_send there. Run the gbot CLI on the user's machine through Grok Bot Shell with a machineId (the host's machine-targeted shell).",
27388
27895
  "On that machine, provide the socket with `codex app-server daemon start` (or bootstrap). Auth stays with each machine's native Codex or Claude login; gbot does not store or export credentials."
27389
27896
  ].join("\n");
@@ -27403,7 +27910,7 @@ ts() { date -u +%Y-%m-%dT%H:%M:%SZ; }
27403
27910
  },
27404
27911
  "./package.json" (module) {
27405
27912
  module.exports = {
27406
- "rE": "0.10.1"
27913
+ "rE": "0.11.0"
27407
27914
  };
27408
27915
  }
27409
27916
  };