grok-bot-cli 0.10.1 → 0.10.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.
package/dist/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "grok-bot-cli",
3
- "version": "0.10.1",
3
+ "version": "0.10.2",
4
4
  "description": "CLI and Agent Bundle plugin for Grok Bot agents and groups: create, update, message, inspect threads, and automate cleanup",
5
5
  "type": "module",
6
6
  "engines": {
@@ -46,7 +46,7 @@
46
46
  "@agent-bundle/runtime": "https://pkg.pr.new/ScriptedAlchemy/agent-bundle/@agent-bundle/runtime@899755dc6d",
47
47
  "@changesets/cli": "3.0.3",
48
48
  "@modelcontextprotocol/server": "2.1.0",
49
- "@rstest/core": "0.11.12",
49
+ "@rstest/core": "0.12.2",
50
50
  "@types/node": "^24.0.0",
51
51
  "@types/react": "^19.2.18",
52
52
  "agent-bundle": "https://pkg.pr.new/ScriptedAlchemy/agent-bundle/agent-bundle@899755dc6d",
package/dist/plugin.json CHANGED
@@ -1 +1 @@
1
- {"$schema":"https://agent-plugins.org/schemas/1.0.0/plugin.schema.json","author":{"name":"Zack Jackson","url":"https://github.com/ScriptedAlchemy"},"description":"Message Grok Bot from Codex, Claude Code, and Cursor. Codex/Claude tools use local sockets on the user's registered machines only (no remote transport); from the Grok Bot box, run gbot via Grok Bot Shell with a machineId.","homepage":"https://github.com/ScriptedAlchemy/grok-bot-cli#readme","keywords":["grok","grok-bot","grokbot","gbot","cursor","ai-agents","automation","terminal","cli","agent-bundle"],"license":"MIT","name":"gbot","repository":"https://github.com/ScriptedAlchemy/grok-bot-cli","version":"0.10.1"}
1
+ {"$schema":"https://agent-plugins.org/schemas/1.0.0/plugin.schema.json","author":{"name":"Zack Jackson","url":"https://github.com/ScriptedAlchemy"},"description":"Message Grok Bot from Codex, Claude Code, and Cursor. Codex/Claude tools use local sockets on the user's registered machines only (no remote transport); from the Grok Bot box, run gbot via Grok Bot Shell with a machineId.","homepage":"https://github.com/ScriptedAlchemy/grok-bot-cli#readme","keywords":["grok","grok-bot","grokbot","gbot","cursor","ai-agents","automation","terminal","cli","agent-bundle"],"license":"MIT","name":"gbot","repository":"https://github.com/ScriptedAlchemy/grok-bot-cli","version":"0.10.2"}
@@ -22135,7 +22135,7 @@ var __webpack_modules__ = {
22135
22135
  var _codex_contract_js__rspack_import_7 = __webpack_require__("./src/core/codex/contract.js");
22136
22136
  var _desktop_shim_js__rspack_import_8 = __webpack_require__("./src/core/desktop-shim.js");
22137
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";
22138
+ const PINNED_CODEX_VERSION = "0.158.0";
22139
22139
  const UPSTREAM_DESKTOP_ISSUES = [
22140
22140
  "https://github.com/openai/codex/issues/41014",
22141
22141
  "https://github.com/openai/codex/issues/41112"
@@ -22195,7 +22195,7 @@ var __webpack_modules__ = {
22195
22195
  "Either no daemon is running (start one with `codex app-server daemon start` or bootstrap),",
22196
22196
  "or ChatGPT Desktop is running a private stdio app-server that external clients cannot reach",
22197
22197
  "(" + UPSTREAM_DESKTOP_ISSUES.join(", ") + ").",
22198
- "gbot connects only to this machine's local socket; it has no remote transport.",
22198
+ "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
22199
  "gbot codex targets daemon-managed threads only."
22200
22200
  ].join("\n");
22201
22201
  }
@@ -22839,6 +22839,47 @@ var __webpack_modules__ = {
22839
22839
  };
22840
22840
  }
22841
22841
  const openSession = openCodexSession;
22842
+ async function startCodexThread({ cwd, expectedCwd, model, effort, message, env = process.env, signal } = {}) {
22843
+ validateModelEffort(model, effort);
22844
+ if (typeof cwd !== "string" || !cwd.trim()) throw new RangeError("--cwd is required for a new Codex thread");
22845
+ const resolvedCwd = realpathSync(cwd);
22846
+ if (expectedCwd !== undefined && realpathSync(expectedCwd) !== resolvedCwd) throw new RangeError("New Codex thread cwd does not match expectedCwd");
22847
+ if (message !== undefined && (typeof message !== "string" || !message.trim())) throw new RangeError("Message must contain text");
22848
+ const { client } = await openSession(env, {
22849
+ signal
22850
+ });
22851
+ let threadId, started;
22852
+ try {
22853
+ started = await client.request("thread/start", {
22854
+ cwd: resolvedCwd,
22855
+ ...model ? {
22856
+ model
22857
+ } : {},
22858
+ ...effort ? {
22859
+ config: {
22860
+ model_reasoning_effort: effort
22861
+ }
22862
+ } : {}
22863
+ });
22864
+ threadId = started?.thread?.id;
22865
+ if (typeof threadId !== "string" || !ID_PATTERN.test(threadId)) throw new CodexProtocolError("thread/start", "missing `thread.id`");
22866
+ } finally{
22867
+ client.close();
22868
+ }
22869
+ if (message === undefined) return {
22870
+ threadId,
22871
+ cwd: resolvedCwd,
22872
+ model: started.model ?? model,
22873
+ exitCode: 0
22874
+ };
22875
+ return await sendToCodexThread(threadId, message, {
22876
+ env,
22877
+ expectedCwd: resolvedCwd,
22878
+ model,
22879
+ effort,
22880
+ signal
22881
+ });
22882
+ }
22842
22883
  const CODEX_VERSION_PROBE_TIMEOUT_MS = 3000;
22843
22884
  function probeLocalCodexVersion(timeoutMs = CODEX_VERSION_PROBE_TIMEOUT_MS) {
22844
22885
  const out = spawnSync("codex", [
@@ -23137,7 +23178,7 @@ var __webpack_modules__ = {
23137
23178
  }
23138
23179
  function requireExperimental(env, what) {
23139
23180
  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 + ".", {
23181
+ 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
23182
  delivery: "rejected",
23142
23183
  reason: "experimental-disabled"
23143
23184
  });
@@ -23145,7 +23186,7 @@ var __webpack_modules__ = {
23145
23186
  function unsupportedOrRpc(err, method, threadId, envelope, turnId) {
23146
23187
  const guarded = method === "turn/steer";
23147
23188
  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."), {
23189
+ 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
23190
  delivery: "rejected",
23150
23191
  reason: "unsupported",
23151
23192
  threadId,
@@ -23202,7 +23243,7 @@ var __webpack_modules__ = {
23202
23243
  }
23203
23244
  async function sendToCodexThread(threadId, text, { env = process.env, envelope = buildEnvelope({
23204
23245
  env
23205
- }), whenBusy = "reject", session, expectedTurnId, expectedCwd, signal } = {}) {
23246
+ }), whenBusy = "reject", session, expectedTurnId, expectedCwd, model, effort, signal } = {}) {
23206
23247
  try {
23207
23248
  const receipt = await sendToCodexThreadInner(threadId, text, {
23208
23249
  env,
@@ -23211,6 +23252,8 @@ var __webpack_modules__ = {
23211
23252
  session,
23212
23253
  expectedTurnId,
23213
23254
  expectedCwd,
23255
+ model,
23256
+ effort,
23214
23257
  signal
23215
23258
  });
23216
23259
  return (0, _codex_contract_js__rspack_import_7.Dz)(receipt);
@@ -23222,7 +23265,19 @@ var __webpack_modules__ = {
23222
23265
  return (0, _codex_contract_js__rspack_import_7.DG)(err);
23223
23266
  }
23224
23267
  }
23225
- async function sendToCodexThreadInner(threadId, text, { env, envelope, whenBusy, session, expectedTurnId, expectedCwd, signal }) {
23268
+ function validateModelEffort(model, effort) {
23269
+ 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");
23270
+ if (effort !== undefined && ![
23271
+ "none",
23272
+ "minimal",
23273
+ "low",
23274
+ "medium",
23275
+ "high",
23276
+ "xhigh"
23277
+ ].includes(effort)) throw new RangeError("--effort must be none, minimal, low, medium, high, or xhigh");
23278
+ }
23279
+ async function sendToCodexThreadInner(threadId, text, { env, envelope, whenBusy, session, expectedTurnId, expectedCwd, model, effort, signal }) {
23280
+ validateModelEffort(model, effort);
23226
23281
  if (![
23227
23282
  "reject",
23228
23283
  "queue",
@@ -23268,7 +23323,15 @@ var __webpack_modules__ = {
23268
23323
  try {
23269
23324
  resumed = await client.request("thread/resume", {
23270
23325
  threadId,
23271
- excludeTurns: true
23326
+ excludeTurns: true,
23327
+ ...model ? {
23328
+ model
23329
+ } : {},
23330
+ ...effort ? {
23331
+ config: {
23332
+ model_reasoning_effort: effort
23333
+ }
23334
+ } : {}
23272
23335
  });
23273
23336
  } catch (err) {
23274
23337
  assertNotCancelled();
@@ -23401,7 +23464,13 @@ var __webpack_modules__ = {
23401
23464
  }
23402
23465
  ],
23403
23466
  clientUserMessageId: envelope.messageId,
23404
- turnTrigger: "gbot"
23467
+ turnTrigger: "gbot",
23468
+ ...model ? {
23469
+ model
23470
+ } : {},
23471
+ ...effort ? {
23472
+ effort
23473
+ } : {}
23405
23474
  });
23406
23475
  } catch (err) {
23407
23476
  if (err instanceof CodexSendError) throw err;
@@ -23670,10 +23739,10 @@ var __webpack_modules__ = {
23670
23739
  ];
23671
23740
  if (afterMessageId !== undefined) boundedInteger(anchors.length, 200, 'afterMessageId count');
23672
23741
  for (const anchor of anchors)conversationId(anchor, 'afterMessageId');
23673
- boundedInteger(timeoutMs, 600000, 'timeoutMs');
23742
+ boundedInteger(timeoutMs, 7200000, 'timeoutMs');
23674
23743
  boundedInteger(maxOutputBytes, BUDGET, 'maxOutputBytes');
23675
23744
  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;
23745
+ let done = false, status = acceptedTurns.has(turnId) ? 'inProgress' : undefined, error, historyError, itemBytes = 0, truncated = false;
23677
23746
  const items = new Map();
23678
23747
  const add = (item)=>{
23679
23748
  if (!item || typeof item.id !== 'string' || typeof item.type !== 'string') throw new Error('Invalid history item');
@@ -23720,6 +23789,7 @@ var __webpack_modules__ = {
23720
23789
  };
23721
23790
  const result = (state, detail)=>{
23722
23791
  const interactions = scan();
23792
+ const overflowUncertain = state === 'unknown' && /Notification coverage overflow/.test(detail ?? '');
23723
23793
  const candidates = [
23724
23794
  ...items.values()
23725
23795
  ].map((x)=>x.item);
@@ -23728,7 +23798,7 @@ var __webpack_modules__ = {
23728
23798
  const reply = {
23729
23799
  text: '',
23730
23800
  items: [],
23731
- truncated: truncated || overflow
23801
+ truncated: truncated || overflowUncertain
23732
23802
  };
23733
23803
  for (const item of selected){
23734
23804
  const text = reply.text ? `${reply.text}\n${item.text}` : item.text;
@@ -23761,7 +23831,7 @@ var __webpack_modules__ = {
23761
23831
  interactions
23762
23832
  };
23763
23833
  };
23764
- let timer, notify;
23834
+ let timer, pollTimer, notify;
23765
23835
  const abortSignals = [
23766
23836
  signal,
23767
23837
  waitSignal
@@ -23777,10 +23847,18 @@ var __webpack_modules__ = {
23777
23847
  'Codex connection closed'
23778
23848
  ]);
23779
23849
  };
23780
- timer = setTimeout(()=>resolve([
23850
+ timer = setTimeout(()=>resolve(overflow ? [
23851
+ 'unknown',
23852
+ 'Notification coverage overflow; pending interaction status is uncertain'
23853
+ ] : [
23781
23854
  'timeout',
23782
23855
  'Observation deadline reached'
23783
23856
  ]), timeoutMs);
23857
+ pollTimer = setInterval(()=>{
23858
+ for (const listener of [
23859
+ ...wake
23860
+ ])listener();
23861
+ }, 2000);
23784
23862
  for (const s of abortSignals)s.addEventListener('abort', notify, {
23785
23863
  once: true
23786
23864
  });
@@ -23851,19 +23929,51 @@ var __webpack_modules__ = {
23851
23929
  historyError
23852
23930
  ];
23853
23931
  }
23932
+ let lastPoll = 0;
23854
23933
  while(!done){
23855
23934
  const interactions = scan();
23856
23935
  if (terminal(status)) return [
23857
23936
  status,
23858
23937
  error ?? historyError
23859
23938
  ];
23860
- if (historyError || overflow) return [
23939
+ if (historyError) return [
23861
23940
  'unknown',
23862
- historyError ?? 'Notification coverage overflow'
23941
+ historyError
23863
23942
  ];
23864
23943
  if (interactions.length) return [
23865
23944
  'waiting-for-input'
23866
23945
  ];
23946
+ if (Date.now() - lastPoll >= 2000) {
23947
+ lastPoll = Date.now();
23948
+ try {
23949
+ await visitCodexHistory(session, threadId, 'thread/turns/list', {}, (data)=>{
23950
+ const turn = data.find((t)=>t?.id === turnId);
23951
+ if (!turn) return false;
23952
+ if (terminal(turn.status)) {
23953
+ status = turn.status;
23954
+ error = turn.error;
23955
+ }
23956
+ return true;
23957
+ }, {
23958
+ stopped: ()=>done
23959
+ });
23960
+ if (terminal(status)) {
23961
+ await visitCodexHistory(session, threadId, 'thread/items/list', {
23962
+ turnId,
23963
+ sortDirection: 'asc'
23964
+ }, (data)=>{
23965
+ for (const row of data)if (row?.turnId === turnId && row.item) add(row.item);
23966
+ return false;
23967
+ }, {
23968
+ stopped: ()=>done
23969
+ });
23970
+ continue;
23971
+ }
23972
+ } catch (err) {
23973
+ historyError = err.message;
23974
+ truncated = true;
23975
+ }
23976
+ }
23867
23977
  await new Promise((resolve)=>{
23868
23978
  const listener = ()=>{
23869
23979
  wake.delete(listener);
@@ -23886,6 +23996,7 @@ var __webpack_modules__ = {
23886
23996
  } finally{
23887
23997
  done = true;
23888
23998
  clearTimeout(timer);
23999
+ clearInterval(pollTimer);
23889
24000
  wake.delete(notify);
23890
24001
  for (const s of abortSignals)s.removeEventListener('abort', notify);
23891
24002
  for (const listener of [
@@ -23933,7 +24044,7 @@ var __webpack_modules__ = {
23933
24044
  close,
23934
24045
  async send (text, { envelope = (0, _codex_bridge_js__rspack_import_2.nq)({
23935
24046
  env
23936
- }), whenBusy = 'reject', expectedTurnId, signal: sendSignal } = {}) {
24047
+ }), whenBusy = 'reject', expectedTurnId, model, effort, signal: sendSignal } = {}) {
23937
24048
  if (closed) return (0, _contract_js__rspack_import_0.DG)(Object.assign(new Error('Conversation closed'), {
23938
24049
  delivery: 'rejected',
23939
24050
  reason: 'closed',
@@ -23952,6 +24063,8 @@ var __webpack_modules__ = {
23952
24063
  expectedTurnId,
23953
24064
  session,
23954
24065
  expectedCwd,
24066
+ model,
24067
+ effort,
23955
24068
  signal: submissionSignal
23956
24069
  });
23957
24070
  if (receipt.delivery === 'accepted' && receipt.turnId) {
@@ -25242,6 +25355,12 @@ ts() { date -u +%Y-%m-%dT%H:%M:%SZ; }
25242
25355
  whenBusy: active ? "steer" : "reject",
25243
25356
  ...active ? {
25244
25357
  expectedTurnId: active
25358
+ } : {},
25359
+ ...record.model ? {
25360
+ model: record.model
25361
+ } : {},
25362
+ ...record.effort ? {
25363
+ effort: record.effort
25245
25364
  } : {}
25246
25365
  });
25247
25366
  if (!active || receipt.delivery !== "rejected" || receipt.reason !== "rejected" || !/guard|expected.*turn|turn.*mismatch|stale/i.test(receipt.error ?? "")) return receipt;
@@ -26384,6 +26503,12 @@ ts() { date -u +%Y-%m-%dT%H:%M:%SZ; }
26384
26503
  threadId: r.threadId,
26385
26504
  expectedCwd: r.expectedCwd,
26386
26505
  busyPolicy: r.busyPolicy,
26506
+ ...input.model ? {
26507
+ model: input.model
26508
+ } : {},
26509
+ ...input.effort ? {
26510
+ effort: input.effort
26511
+ } : {},
26387
26512
  bindingId: r.bindingId ?? (r.id?.startsWith("binding:") ? r.id : null),
26388
26513
  text,
26389
26514
  sourceIds: input.sourceIds ?? [],
@@ -26476,6 +26601,15 @@ ts() { date -u +%Y-%m-%dT%H:%M:%SZ; }
26476
26601
  "steer",
26477
26602
  "reject"
26478
26603
  ]),
26604
+ model: zod__rspack_import_3.YjP().regex(/^[A-Za-z0-9][A-Za-z0-9._:/-]{0,127}$/).optional(),
26605
+ effort: zod__rspack_import_3.k5n([
26606
+ "none",
26607
+ "minimal",
26608
+ "low",
26609
+ "medium",
26610
+ "high",
26611
+ "xhigh"
26612
+ ]).optional(),
26479
26613
  bindingId: relayId.nullable(),
26480
26614
  text,
26481
26615
  sourceIds: zod__rspack_import_3.YOg(relayId).max(200),
@@ -27383,7 +27517,7 @@ ts() { date -u +%Y-%m-%dT%H:%M:%SZ; }
27383
27517
  "./src/core/user-machine-guidance.js" (__unused_rspack___webpack_module__, __webpack_exports__, __webpack_require__) {
27384
27518
  const USER_MACHINE_CODEX_CLAUDE_GUIDANCE = [
27385
27519
  "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.",
27520
+ "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
27521
  "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
27522
  "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
27523
  ].join("\n");
@@ -27403,7 +27537,7 @@ ts() { date -u +%Y-%m-%dT%H:%M:%SZ; }
27403
27537
  },
27404
27538
  "./package.json" (module) {
27405
27539
  module.exports = {
27406
- "rE": "0.10.1"
27540
+ "rE": "0.10.2"
27407
27541
  };
27408
27542
  }
27409
27543
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "grok-bot-cli",
3
- "version": "0.10.1",
3
+ "version": "0.10.2",
4
4
  "description": "CLI and Agent Bundle plugin for Grok Bot agents and groups: create, update, message, inspect threads, and automate cleanup",
5
5
  "type": "module",
6
6
  "bin": {
@@ -58,7 +58,7 @@
58
58
  "@agent-bundle/runtime": "https://pkg.pr.new/ScriptedAlchemy/agent-bundle/@agent-bundle/runtime@899755dc6d",
59
59
  "@changesets/cli": "3.0.3",
60
60
  "@modelcontextprotocol/server": "2.1.0",
61
- "@rstest/core": "0.11.12",
61
+ "@rstest/core": "0.12.2",
62
62
  "@types/node": "^24.0.0",
63
63
  "@types/react": "^19.2.18",
64
64
  "agent-bundle": "https://pkg.pr.new/ScriptedAlchemy/agent-bundle/agent-bundle@899755dc6d",