gearbox-code 0.2.3 → 0.2.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/cli.mjs +91 -67
  2. package/package.json +1 -1
package/dist/cli.mjs CHANGED
@@ -138748,7 +138748,7 @@ var COMMANDS = [
138748
138748
  { name: "/retry", usage: "/retry", desc: "send your last message again", group: "chat" },
138749
138749
  { name: "/compact", usage: "/compact", desc: "shrink the conversation to free up room", group: "chat" },
138750
138750
  { name: "/context", usage: "/context", desc: "see what's loaded and how many tokens it uses", group: "chat" },
138751
- { name: "/ask", usage: "/ask <q>", desc: "ask about Gearbox itself answered from its own docs", group: "chat" },
138751
+ { name: "/ask", usage: "/ask <q>", desc: "ask about Gearbox itself · answered from its own docs", group: "chat" },
138752
138752
  { name: "/memory", usage: "/memory [note]", desc: "show or add facts to remember (or start a line with #)", group: "chat" },
138753
138753
  { name: "/account", usage: "/account", desc: "list accounts; /account <name> switches, /account login <name> re-auths, /account add adds one", group: "accounts" },
138754
138754
  { name: "/onboard", usage: "/onboard", desc: "first-run setup; provider list and import/add commands", group: "accounts" },
@@ -138853,10 +138853,10 @@ function formatAccounts(accounts, activeCliId, importable, statuses = {}) {
138853
138853
  lines.push(` ${st.detail}`);
138854
138854
  });
138855
138855
  if (!activeCliId)
138856
- lines.push("", " no subscription active your API keys auto-route per task");
138856
+ lines.push("", " no subscription active · your API keys auto-route per task");
138857
138857
  }
138858
138858
  if (importable.length) {
138859
- lines.push("", "found in your environment /account import to add:");
138859
+ lines.push("", "found in your environment · /account import to add:");
138860
138860
  for (const c of importable)
138861
138861
  lines.push(` + ${c.label} (${c.envVar})`);
138862
138862
  }
@@ -138936,16 +138936,16 @@ function formatModelList(currentId, showAll = false) {
138936
138936
  rows.push(line(m2));
138937
138937
  }
138938
138938
  if (hidden)
138939
- rows.push(` + ${hidden} more on your accounts /model all to list · /model <name> to pick`);
138939
+ rows.push(` + ${hidden} more on your accounts · /model all to list · /model <name> to pick`);
138940
138940
  } else {
138941
- rows.push("", "no accounts yet /account to add one");
138941
+ rows.push("", "no accounts yet · /account to add one");
138942
138942
  }
138943
138943
  if (showAll && rest2.length) {
138944
138944
  rows.push("", "needs an account");
138945
138945
  for (const m2 of rest2)
138946
138946
  rows.push(` ${glyph.off} ${m2.label.padEnd(18)} ${m2.provider}`);
138947
138947
  } else if (rest2.length) {
138948
- rows.push("", ` + ${rest2.length} more once you add a key /model all to list · /account to add one`);
138948
+ rows.push("", ` + ${rest2.length} more once you add a key · /model all to list · /account to add one`);
138949
138949
  }
138950
138950
  return rows.join(`
138951
138951
  `);
@@ -138957,20 +138957,20 @@ function resolveModelSwitch(query) {
138957
138957
  const MODELS2 = modelRegistry();
138958
138958
  const matches2 = MODELS2.filter((m3) => m3.label.toLowerCase().includes(q) || m3.id.toLowerCase().includes(q));
138959
138959
  if (matches2.length === 0)
138960
- return { ok: false, message: `no model matching “${query}” /model to list` };
138960
+ return { ok: false, message: `no model matching “${query}” · /model to list` };
138961
138961
  const exact = matches2.find((m3) => m3.label.toLowerCase() === q || m3.id.toLowerCase() === q);
138962
138962
  const available = matches2.filter((m3) => providerAvailable(m3.provider));
138963
138963
  if (exact) {
138964
138964
  if (!providerAvailable(exact.provider))
138965
- return { ok: false, message: `${exact.label}: no ${exact.provider} account yet /account add ${exact.provider} <key> or set ${envHint(exact.provider)}` };
138965
+ return { ok: false, message: `${exact.label}: no ${exact.provider} account yet · /account add ${exact.provider} <key> or set ${envHint(exact.provider)}` };
138966
138966
  return { ok: true, modelId: exact.id, message: `model → ${exact.label}` };
138967
138967
  }
138968
138968
  if (available.length === 0) {
138969
138969
  const m3 = matches2[0];
138970
- return { ok: false, message: `“${query}” matches ${m3.label} but no account for ${m3.provider} /accounts add ${m3.provider} <key> or set ${envHint(m3.provider)}` };
138970
+ return { ok: false, message: `“${query}” matches ${m3.label} but no account for ${m3.provider} · /accounts add ${m3.provider} <key> or set ${envHint(m3.provider)}` };
138971
138971
  }
138972
138972
  if (available.length > 1) {
138973
- return { ok: false, message: `“${query}” matches ${available.map((m3) => m3.label).join(", ")} be more specific` };
138973
+ return { ok: false, message: `“${query}” matches ${available.map((m3) => m3.label).join(", ")} · be more specific` };
138974
138974
  }
138975
138975
  const m2 = available[0];
138976
138976
  return { ok: true, modelId: m2.id, message: `model → ${m2.label}` };
@@ -143452,7 +143452,7 @@ function Panel({
143452
143452
  paddingX: 1,
143453
143453
  children: rows.length === 0 ? /* @__PURE__ */ jsx_dev_runtime12.jsxDEV(Text, {
143454
143454
  color: color.faint,
143455
- children: "no accounts yet /account add to add one"
143455
+ children: "no accounts yet · /account add to add one"
143456
143456
  }, undefined, false, undefined, this) : slice2.map((r2, i2) => {
143457
143457
  const sel = start + i2 === idx;
143458
143458
  return /* @__PURE__ */ jsx_dev_runtime12.jsxDEV(Text, {
@@ -146251,6 +146251,21 @@ async function runVerification(commands, opts) {
146251
146251
  }
146252
146252
  return results;
146253
146253
  }
146254
+ function nextStepFor(failures, changedFiles) {
146255
+ if (!failures.length)
146256
+ return changedFiles.length ? "commit changes" : "/context";
146257
+ const joined = failures.join(`
146258
+ `);
146259
+ if (/\bTS1185\b|merge conflict|conflict marker|<<<<<<<|>>>>>>>/i.test(joined)) {
146260
+ const m2 = joined.match(/([\w./-]+\.(?:ts|tsx|js|jsx|mjs|cjs))[(:]/);
146261
+ return m2 ? `resolve the conflict in ${m2[1]}` : "resolve the merge conflict";
146262
+ }
146263
+ const errFiles = [...joined.matchAll(/([\w./-]+\.(?:ts|tsx|js|jsx|mjs|cjs|py|go|rs))[(:]/g)].map((x2) => x2[1]);
146264
+ if (errFiles.length && errFiles.every((f3) => !changedFiles.some((c) => c === f3 || c.endsWith(f3) || f3.endsWith(c)))) {
146265
+ return "likely predates your change — check the repo state";
146266
+ }
146267
+ return "/retry";
146268
+ }
146254
146269
 
146255
146270
  // src/init.ts
146256
146271
  function readJson2(path) {
@@ -146651,27 +146666,27 @@ function transcriptMarkdown(items) {
146651
146666
  else if (it.kind === "assistant")
146652
146667
  out.push("## Gearbox", "", it.text, "");
146653
146668
  else if (it.kind === "tool")
146654
- out.push(`> \`${it.name}\` ${it.arg}${it.summary ? " " + it.summary : ""}`, "");
146669
+ out.push(`> \`${it.name}\` ${it.arg}${it.summary ? " · " + it.summary : ""}`, "");
146655
146670
  else if (it.kind === "notice")
146656
146671
  out.push(`_${it.text}_`, "");
146657
146672
  else if (it.kind === "accounts") {
146658
146673
  out.push("**accounts**", "", `current: ${it.view.current}`);
146659
146674
  for (const r2 of it.view.rows)
146660
- out.push(`- ${r2.name} (${r2.type}) ${r2.status} /account ${r2.alias}`);
146675
+ out.push(`- ${r2.name} (${r2.type}) · ${r2.status} · /account ${r2.alias}`);
146661
146676
  out.push("");
146662
146677
  } else if (it.kind === "usage") {
146663
146678
  out.push("**usage · spend & limits**", "");
146664
146679
  for (const a of it.view.subscriptions) {
146665
146680
  const limits = (a.limits ?? []).map((l) => `${l.label} ${l.pct}%`).join(" · ");
146666
- out.push(`- ${a.name} (subscription) ${a.turns} turns${limits ? ` · ${limits}` : ""}`);
146681
+ out.push(`- ${a.name} (subscription) · ${a.turns} turns${limits ? ` · ${limits}` : ""}`);
146667
146682
  }
146668
146683
  for (const a of it.view.apiKeys)
146669
- out.push(`- ${a.name} (API key) ${a.spend} · ${a.turns} turns · ${a.tok}`);
146684
+ out.push(`- ${a.name} (API key) · ${a.spend} · ${a.turns} turns · ${a.tok}`);
146670
146685
  out.push(`- total API spend ${it.view.totalApiSpend}`, "");
146671
146686
  } else if (it.kind === "context") {
146672
146687
  out.push("**context · what's loaded**", "");
146673
146688
  for (const r2 of it.view.rows)
146674
- out.push(`- ${r2.label.trim()} ${r2.display.trim()}`);
146689
+ out.push(`- ${r2.label.trim()} · ${r2.display.trim()}`);
146675
146690
  out.push(`- total ${it.view.total.trim()}${it.view.windowPct != null ? ` (${it.view.windowPct}% of ${it.view.windowLabel})` : ""}`, "");
146676
146691
  } else if (it.kind === "error")
146677
146692
  out.push(`**error:** ${it.text}`, "");
@@ -146681,7 +146696,7 @@ function transcriptMarkdown(items) {
146681
146696
  }
146682
146697
  function friendlyError(msg) {
146683
146698
  if (isNetworkError(msg))
146684
- return `can't reach the provider you appear to be offline. Check your connection, then /retry.`;
146699
+ return `can't reach the provider · you appear to be offline. Check your connection, then /retry.`;
146685
146700
  return msg;
146686
146701
  }
146687
146702
  function firstPath(text2) {
@@ -147152,7 +147167,7 @@ function App2({ selector: initialSelector, runner, fullscreen = false, resumeId
147152
147167
  } catch {}
147153
147168
  }
147154
147169
  if (learned)
147155
- notice(`loaded the real model list for ${learned} account${learned === 1 ? "" : "s"} /model to see them`);
147170
+ notice(`loaded the real model list for ${learned} account${learned === 1 ? "" : "s"} · /model to see them`);
147156
147171
  })();
147157
147172
  }, []);
147158
147173
  import_react26.useEffect(() => {
@@ -147622,7 +147637,7 @@ function App2({ selector: initialSelector, runner, fullscreen = false, resumeId
147622
147637
  rows2.push(" no named subscription models exposed yet");
147623
147638
  for (const m2 of models)
147624
147639
  rows2.push(` ${m2.id === currentId ? glyph.on : glyph.off} ${m2.label}`);
147625
- rows2.push("", `API models are hidden while a subscription is active /account off returns to API routing
147640
+ rows2.push("", `API models are hidden while a subscription is active · /account off returns to API routing
147626
147641
  tip: /model haiku (or any API model name) switches directly and leaves the subscription`);
147627
147642
  return rows2.join(`
147628
147643
  `);
@@ -147635,7 +147650,7 @@ function App2({ selector: initialSelector, runner, fullscreen = false, resumeId
147635
147650
  const exact = matches2.find((m3) => m3.label.toLowerCase() === q || m3.id.toLowerCase() === q);
147636
147651
  const m2 = exact ?? (matches2.length === 1 ? matches2[0] : undefined);
147637
147652
  if (!m2)
147638
- return { ok: false, message: `"${query}" matches ${matches2.map((x2) => x2.label).join(", ")} be more specific` };
147653
+ return { ok: false, message: `"${query}" matches ${matches2.map((x2) => x2.label).join(", ")} · be more specific` };
147639
147654
  return { ok: true, modelId: m2.id, label: m2.label };
147640
147655
  };
147641
147656
  const setActiveCliModelId = (modelId) => {
@@ -147757,12 +147772,12 @@ function App2({ selector: initialSelector, runner, fullscreen = false, resumeId
147757
147772
  if (exact.length === 1)
147758
147773
  return { account: exact[0].a };
147759
147774
  if (exact.length > 1)
147760
- return { error: `"${query}" matches ${exact.map(({ a }) => accountName(a)).join(", ")} use the full alias` };
147775
+ return { error: `"${query}" matches ${exact.map(({ a }) => accountName(a)).join(", ")} · use the full alias` };
147761
147776
  const fuzzy = accounts.map((a) => ({ a, aliases: [...accountAliases(a)] })).filter(({ aliases }) => aliases.some((x2) => x2.includes(q)));
147762
147777
  if (fuzzy.length === 1)
147763
147778
  return { account: fuzzy[0].a };
147764
147779
  if (fuzzy.length > 1)
147765
- return { error: `"${query}" matches ${fuzzy.map(({ a }) => accountName(a)).join(", ")} use the full alias` };
147780
+ return { error: `"${query}" matches ${fuzzy.map(({ a }) => accountName(a)).join(", ")} · use the full alias` };
147766
147781
  return { error: `no account matching "${query}"` };
147767
147782
  };
147768
147783
  const buildAccountView = (accounts, activeCliId, importable, statuses) => {
@@ -147823,7 +147838,7 @@ function App2({ selector: initialSelector, runner, fullscreen = false, resumeId
147823
147838
  const _cliEffortRaw = normalizeEffort(effortRef.current, efforts);
147824
147839
  if (_cliEffortRaw === null && effortRef.current !== "medium") {
147825
147840
  const { level: nearest } = clampEffort(effortRef.current, efforts);
147826
- const hint = efforts.length ? ` try /effort ${nearest}` : "";
147841
+ const hint = efforts.length ? ` · try /effort ${nearest}` : "";
147827
147842
  throw new Error(`effort "${effortRef.current}" is not supported by ${label ?? binary} (supports: ${efforts.join(", ") || "none"}${hint})`);
147828
147843
  }
147829
147844
  const cliEffort = _cliEffortRaw ?? undefined;
@@ -147875,12 +147890,12 @@ ${map4}
147875
147890
  if (isAsk) {
147876
147891
  const docs = loadGearboxDocs();
147877
147892
  if (!docs) {
147878
- onEvent({ type: "error", message: "Gearbox docs aren't bundled with this install can't answer from them." });
147893
+ onEvent({ type: "error", message: "Gearbox docs aren't bundled with this install · can't answer from them." });
147879
147894
  return { messages, usage: { inputTokens: 0, outputTokens: 0 } };
147880
147895
  }
147881
147896
  const choice3 = new RoutingSelector().select({ prompt, kind: "search" });
147882
147897
  if (choice3.backend?.kind === "cli") {
147883
- onEvent({ type: "error", message: "/ask needs an API-key account it can't run on a subscription. Add one with /account add <key>." });
147898
+ onEvent({ type: "error", message: "/ask needs an API-key account · it can't run on a subscription. Add one with /account add <key>." });
147884
147899
  return { messages, usage: { inputTokens: 0, outputTokens: 0 } };
147885
147900
  }
147886
147901
  routedRef.current = { model: choice3.model, reason: choice3.reason };
@@ -147981,7 +147996,7 @@ ${map4}
147981
147996
  if (_effortRaw === null && effortRef.current !== "medium") {
147982
147997
  const supported = effortLevels(choice3.model);
147983
147998
  const { level: nearest } = clampEffort(effortRef.current, supported);
147984
- const hint = supported.length ? ` try /effort ${nearest}` : "";
147999
+ const hint = supported.length ? ` · try /effort ${nearest}` : "";
147985
148000
  throw new Error(`effort "${effortRef.current}" is not supported by ${choice3.model.label} (supports: ${supported.join(", ") || "none"}${hint})`);
147986
148001
  }
147987
148002
  const r2 = await runTask({ model: choice3.model, messages: ctx, onEvent, signal, plan, system, creds, effort: _effortRaw ?? undefined, deferTerminal: true });
@@ -148042,9 +148057,9 @@ ${map4}
148042
148057
  return `compacted ${res.summarizedTurns} earlier turn${res.summarizedTurns > 1 ? "s" : ""} · ~${savedStr} tokens freed`;
148043
148058
  }, []);
148044
148059
  const MODE_NOTE = {
148045
- normal: "normal mode I'll ask before writes, edits, and shell",
148046
- "auto-accept": "auto-accept edits file writes/edits apply without asking (shell still gated)",
148047
- plan: "plan mode read-only; I'll propose a plan before changing anything"
148060
+ normal: "normal mode · I'll ask before writes, edits, and shell",
148061
+ "auto-accept": "auto-accept edits · file writes/edits apply without asking (shell still gated)",
148062
+ plan: "plan mode · read-only; I'll propose a plan before changing anything"
148048
148063
  };
148049
148064
  const setModeTo = (next) => {
148050
148065
  modeRef.current = next;
@@ -148076,8 +148091,8 @@ ${map4}
148076
148091
  effortRef.current = level;
148077
148092
  setEffortState(level);
148078
148093
  if (!allowed.length)
148079
- return ` effort reset to ${level} (no reasoning support)`;
148080
- return ` effort clamped: ${prev} → ${level} (${prev} not supported)`;
148094
+ return ` · effort reset to ${level} (no reasoning support)`;
148095
+ return ` · effort clamped: ${prev} → ${level} (${prev} not supported)`;
148081
148096
  };
148082
148097
  const setEffort = (raw) => {
148083
148098
  const target = effortTarget();
@@ -148092,7 +148107,7 @@ ${map4}
148092
148107
  }
148093
148108
  effortRef.current = level;
148094
148109
  setEffortState(level);
148095
- notice(`effort: ${level} ${target.label}`);
148110
+ notice(`effort: ${level} · ${target.label}`);
148096
148111
  };
148097
148112
  const runInteractive = (cmd, cmdArgs, env3) => {
148098
148113
  try {
@@ -148103,7 +148118,7 @@ ${map4}
148103
148118
  process.stdout.write("\x1B[?1049l");
148104
148119
  process.stdout.write("\x1B[?2004l\x1B[?25h");
148105
148120
  process.stdout.write(`
148106
- → running \`${cmd} ${cmdArgs.join(" ")}\` follow the prompts…
148121
+ → running \`${cmd} ${cmdArgs.join(" ")}\` · follow the prompts…
148107
148122
 
148108
148123
  `);
148109
148124
  const r2 = nodeSpawnSync2(cmd, cmdArgs, { stdio: ["inherit", "inherit", "inherit"], ...env3 ? { env: env3 } : {} });
@@ -148406,7 +148421,7 @@ ${fetched.join(`
148406
148421
  const changed = uniq2([...changedFiles]);
148407
148422
  const doneChecks = uniq2(checks4);
148408
148423
  const failed = uniq2(failures).slice(0, 4);
148409
- const next = failed.length ? "/retry" : changed.length && !doneChecks.length ? "run tests" : changed.length ? "commit changes" : "/context";
148424
+ const next = failed.length ? nextStepFor(failed, changed) : changed.length && !doneChecks.length ? "run tests" : changed.length ? "commit changes" : "/context";
148410
148425
  if (changed.length || doneChecks.length || failed.length) {
148411
148426
  push({ kind: "summary", id: idRef.current++, changed, checks: doneChecks, failures: failed, next });
148412
148427
  }
@@ -148526,7 +148541,7 @@ ${fetched.join(`
148526
148541
  return;
148527
148542
  }
148528
148543
  if (a && a.exec !== "cli") {
148529
- notice(`${accountName(a)} is an API-key account nothing to re-login. Use /account ${accountSlug(a)} to switch to it, or /account add ${a.provider} <key> to replace the key.`);
148544
+ notice(`${accountName(a)} is an API-key account · nothing to re-login. Use /account ${accountSlug(a)} to switch to it, or /account add ${a.provider} <key> to replace the key.`);
148530
148545
  return;
148531
148546
  }
148532
148547
  signInCli(arg2);
@@ -148560,13 +148575,13 @@ ${fetched.join(`
148560
148575
  }
148561
148576
  const rows2 = sessions.slice(0, 10).map((s2, i2) => ` ${i2 + 1}. ${new Date(s2.updatedAt).toLocaleString()} · ${s2.title || "(untitled)"} (${s2.items.length} msgs)`).join(`
148562
148577
  `);
148563
- notice(`resume a session /resume <n>:
148578
+ notice(`resume a session · /resume <n>:
148564
148579
  ` + rows2);
148565
148580
  return;
148566
148581
  }
148567
148582
  const pick3 = (resumeListRef.current.length ? resumeListRef.current : sessions)[parseInt(arg, 10) - 1];
148568
148583
  if (!pick3) {
148569
- notice(`no session ${arg} /resume to list`);
148584
+ notice(`no session ${arg} · /resume to list`);
148570
148585
  return;
148571
148586
  }
148572
148587
  loadInto(pick3);
@@ -148590,7 +148605,7 @@ ${fetched.join(`
148590
148605
  setEffort(arg);
148591
148606
  } else {
148592
148607
  const target = effortTarget();
148593
- notice(target?.efforts.length ? `effort: ${effortRef.current} ${target.label} supports ${target.efforts.join(", ")}` : "the active model does not expose reasoning efforts");
148608
+ notice(target?.efforts.length ? `effort: ${effortRef.current} · ${target.label} supports ${target.efforts.join(", ")}` : "the active model does not expose reasoning efforts");
148594
148609
  }
148595
148610
  return;
148596
148611
  }
@@ -148627,7 +148642,7 @@ ${fetched.join(`
148627
148642
  const on = vimRef.current === "off";
148628
148643
  setVim(on ? "insert" : "off");
148629
148644
  updatePrefs({ vim: on });
148630
- notice(on ? "vim mode on esc for normal, i to insert" : "vim mode off");
148645
+ notice(on ? "vim mode on · esc for normal, i to insert" : "vim mode off");
148631
148646
  return;
148632
148647
  }
148633
148648
  case "config": {
@@ -148646,10 +148661,10 @@ ${fetched.join(`
148646
148661
  if (key === "vim") {
148647
148662
  setVim(on ? "insert" : "off");
148648
148663
  updatePrefs({ vim: on });
148649
- notice(on ? "vim mode on esc for normal, i to insert" : "vim mode off");
148664
+ notice(on ? "vim mode on · esc for normal, i to insert" : "vim mode off");
148650
148665
  } else if (key === "inline") {
148651
148666
  updatePrefs({ fullscreen: !on });
148652
- notice(`inline mode ${on ? "on" : "off"} restart gearbox to apply`);
148667
+ notice(`inline mode ${on ? "on" : "off"} · restart gearbox to apply`);
148653
148668
  } else if (key === "notify") {
148654
148669
  notifyRef.current = on;
148655
148670
  updatePrefs({ notify: on });
@@ -148664,7 +148679,7 @@ ${fetched.join(`
148664
148679
  const next = !isYolo();
148665
148680
  setYolo(next);
148666
148681
  setYoloState(next);
148667
- notice(next ? "yolo mode ON all file writes and shell commands run without asking" : "yolo mode off back to asking before writes/edits/shell");
148682
+ notice(next ? "yolo mode ON · all file writes and shell commands run without asking" : "yolo mode off · back to asking before writes/edits/shell");
148668
148683
  return;
148669
148684
  }
148670
148685
  case "ghost": {
@@ -148673,7 +148688,7 @@ ${fetched.join(`
148673
148688
  if (arg) {
148674
148689
  const found = SKINS.find((s2) => s2 === arg.toLowerCase());
148675
148690
  if (!found) {
148676
- notice(`unknown mood: ${arg} try ${SKINS.join(", ")}`);
148691
+ notice(`unknown mood: ${arg} · try ${SKINS.join(", ")}`);
148677
148692
  return;
148678
148693
  }
148679
148694
  next = found;
@@ -148717,7 +148732,7 @@ ${fetched.join(`
148717
148732
  if (!arg || arg.toLowerCase() === "all") {
148718
148733
  const routing2 = selectorRef.current instanceof RoutingSelector;
148719
148734
  const activeSub = activeCliRef.current;
148720
- const mode3 = activeSub ? `now: ${activeSub.binary} subscription${activeCliModelRef.current ? ` · ${cliModelLabel(activeCliModelRef.current)}` : ""} /account off for API routing` : routing2 ? "now: routing on Gearbox picks per task" : `now: pinned to ${currentId ?? "one model"} /model auto to route`;
148735
+ const mode3 = activeSub ? `now: ${activeSub.binary} subscription${activeCliModelRef.current ? ` · ${cliModelLabel(activeCliModelRef.current)}` : ""} · /account off for API routing` : routing2 ? "now: routing on · Gearbox picks per task" : `now: pinned to ${currentId ?? "one model"} · /model auto to route`;
148721
148736
  const list2 = activeSub ? formatCliModelList(activeSub.binary, activeCliModelRef.current ?? null) : formatModelList(currentId, arg.toLowerCase() === "all");
148722
148737
  notice(list2 + `
148723
148738
 
@@ -148727,7 +148742,7 @@ ${fetched.join(`
148727
148742
  if (arg.toLowerCase() === "auto" || arg.toLowerCase() === "route") {
148728
148743
  if (activeCliRef.current) {
148729
148744
  setActiveCliModelId(undefined);
148730
- notice(`subscription model cleared ${activeCliRef.current.binary} will use its default. /account off for API routing`);
148745
+ notice(`subscription model cleared · ${activeCliRef.current.binary} will use its default. /account off for API routing`);
148731
148746
  return;
148732
148747
  }
148733
148748
  const left = leaveSubscription();
@@ -148735,7 +148750,7 @@ ${fetched.join(`
148735
148750
  setLastPick(null);
148736
148751
  routedRef.current = null;
148737
148752
  updatePrefs({ pinnedModel: undefined });
148738
- notice("routing on Gearbox now picks the model per task (the cheapest that can do the job)" + left);
148753
+ notice("routing on · Gearbox now picks the model per task (the cheapest that can do the job)" + left);
148739
148754
  return;
148740
148755
  }
148741
148756
  {
@@ -148752,7 +148767,7 @@ ${fetched.join(`
148752
148767
  updatePrefs({ pinnedModel: r3.modelId });
148753
148768
  const newSpec2 = findModel(r3.modelId);
148754
148769
  const effortSuffix2 = applyEffortClamp(newSpec2 ? effortLevels(newSpec2) : []);
148755
- notice(`${r3.message} pinned (left subscription).${left}${effortSuffix2}`);
148770
+ notice(`${r3.message} · pinned (left subscription).${left}${effortSuffix2}`);
148756
148771
  const kind = classify(lastPromptRef.current ?? "").replace("code", "code");
148757
148772
  push({ kind: "preference", id: idRef.current++, text: `Remember ${r3.modelId} for ${kind} tasks?`, acceptCommand: `/prefer ${kind} ${r3.modelId}` });
148758
148773
  return;
@@ -148769,7 +148784,7 @@ ${fetched.join(`
148769
148784
  updatePrefs({ pinnedModel: r3.modelId });
148770
148785
  const newSpec2 = findModel(r3.modelId);
148771
148786
  const effortSuffix2 = applyEffortClamp(newSpec2 ? effortLevels(newSpec2) : []);
148772
- notice(`${r3.message} pinned (left subscription).${left}${effortSuffix2}`);
148787
+ notice(`${r3.message} · pinned (left subscription).${left}${effortSuffix2}`);
148773
148788
  const kind = classify(lastPromptRef.current ?? "").replace("code", "code");
148774
148789
  push({ kind: "preference", id: idRef.current++, text: `Remember ${r3.modelId} for ${kind} tasks?`, acceptCommand: `/prefer ${kind} ${r3.modelId}` });
148775
148790
  return;
@@ -148780,7 +148795,7 @@ ${fetched.join(`
148780
148795
  setActiveCliModelId(cr.modelId);
148781
148796
  const newCliModel = cliModelChoices(cli.binary).find((m2) => m2.id === cr.modelId);
148782
148797
  const effortSuffix = applyEffortClamp(newCliModel?.efforts ?? []);
148783
- notice(`subscription model → ${cr.label} using ${cli.binary}; tools and permissions still owned by the subscription${effortSuffix}`);
148798
+ notice(`subscription model → ${cr.label} · using ${cli.binary}; tools and permissions still owned by the subscription${effortSuffix}`);
148784
148799
  return;
148785
148800
  }
148786
148801
  const r2 = resolveModelSwitch(arg);
@@ -148792,11 +148807,20 @@ ${fetched.join(`
148792
148807
  updatePrefs({ pinnedModel: r2.modelId });
148793
148808
  const newSpec = findModel(r2.modelId);
148794
148809
  const effortSuffix = applyEffortClamp(newSpec ? effortLevels(newSpec) : []);
148795
- notice(`${r2.message} pinned (persists across sessions). /model auto to route per task again.${left}${effortSuffix}`);
148810
+ notice(`${r2.message} · pinned (persists across sessions). /model auto to route per task again.${left}${effortSuffix}`);
148796
148811
  const kind = classify(lastPromptRef.current ?? "").replace("code", "code");
148797
148812
  push({ kind: "preference", id: idRef.current++, text: `Remember ${r2.modelId} for ${kind} tasks?`, acceptCommand: `/prefer ${kind} ${r2.modelId}` });
148798
148813
  } else {
148799
- notice(r2.message);
148814
+ const wanted = modelRegistry().find((m2) => [m2.id, m2.label].some((s2) => s2.toLowerCase() === arg.toLowerCase() || s2.toLowerCase().includes(arg.toLowerCase())));
148815
+ const fam = wanted && /claude|anthropic/i.test(`${wanted.provider} ${wanted.id}`) ? "claude-cli" : wanted && /openai|gpt|^o\d/i.test(`${wanted.provider} ${wanted.id}`) ? "codex-cli" : null;
148816
+ const sub = fam ? listAccounts().find((a) => a.provider === fam && a.enabled) : null;
148817
+ if (sub && wanted) {
148818
+ notice(`${r2.message}
148819
+
148820
+ you have a ${accountName(sub)} subscription · use it with /account ${accountSlug(sub)}, or add a key: /account add ${wanted.provider} <key>`);
148821
+ } else {
148822
+ notice(r2.message);
148823
+ }
148800
148824
  }
148801
148825
  }
148802
148826
  return;
@@ -148826,7 +148850,7 @@ ${fetched.join(`
148826
148850
  const keys2 = Object.keys(b);
148827
148851
  notice(keys2.length ? `budgets (estimates remaining = budget − tracked spend):
148828
148852
  ` + keys2.map((k) => ` ${k}: $${b[k].amountUSD} ${b[k].period}`).join(`
148829
- `) : "no budgets set. /budget <provider|account> <amount> [monthly|total] lets routing estimate remaining credit for providers that don't expose a balance");
148853
+ `) : "no budgets set. /budget <provider|account> <amount> [monthly|total] · lets routing estimate remaining credit for providers that don't expose a balance");
148830
148854
  return;
148831
148855
  }
148832
148856
  const [target, amountRaw, periodRaw] = parts;
@@ -148853,7 +148877,7 @@ ${fetched.join(`
148853
148877
  }
148854
148878
  const facts = loadFacts().trim();
148855
148879
  const it = { kind: "notice", id: idRef.current++, text: facts ? `remembered facts:
148856
- ` + facts : "no remembered facts yet add one with #<note> or /memory <note>" };
148880
+ ` + facts : "no remembered facts yet · add one with #<note> or /memory <note>" };
148857
148881
  if (openInfoPanel("memory", it))
148858
148882
  return;
148859
148883
  echo(text2);
@@ -148870,7 +148894,7 @@ ${fetched.join(`
148870
148894
  })();
148871
148895
  if (!m2) {
148872
148896
  echo(text2);
148873
- notice(`no model available add a provider first
148897
+ notice(`no model available · add a provider first
148874
148898
 
148875
148899
  ` + onboardingSummary(onboardingState));
148876
148900
  return;
@@ -148887,7 +148911,7 @@ ${fetched.join(`
148887
148911
  echo(text2);
148888
148912
  const sel = selectorRef.current;
148889
148913
  if (!sel.explain) {
148890
- notice("routing is off a model or subscription is pinned. Use /model auto to route per task, then /why.");
148914
+ notice("routing is off · a model or subscription is pinned. Use /model auto to route per task, then /why.");
148891
148915
  return;
148892
148916
  }
148893
148917
  try {
@@ -149011,7 +149035,7 @@ Example: /mcp add github npx -y @modelcontextprotocol/server-github`);
149011
149035
  const withHealth = listAccounts();
149012
149036
  pushAccounts(buildAccountView(withHealth, activeCliRef.current?.id ?? null, importableEnvCreds(), statuses));
149013
149037
  } catch (e2) {
149014
- notice(`couldn't check subscription accounts ${e2?.message ?? String(e2)}`);
149038
+ notice(`couldn't check subscription accounts · ${e2?.message ?? String(e2)}`);
149015
149039
  pushAccounts(buildAccountView(listAccounts(), activeCliRef.current?.id ?? null, importableEnvCreds(), accountStatusCacheRef.current));
149016
149040
  }
149017
149041
  })();
@@ -149065,7 +149089,7 @@ Example: /mcp add github npx -y @modelcontextprotocol/server-github`);
149065
149089
  cliSessionRef.current = undefined;
149066
149090
  setActiveCli(null);
149067
149091
  updatePrefs({ activeAccount: null });
149068
- notice("left the subscription back to your API keys");
149092
+ notice("left the subscription · back to your API keys");
149069
149093
  return;
149070
149094
  }
149071
149095
  if (subL === "login") {
@@ -149128,13 +149152,13 @@ Example: /mcp add github npx -y @modelcontextprotocol/server-github`);
149128
149152
  notice(res.message);
149129
149153
  return;
149130
149154
  }
149131
- notice(`${res.message} testing…`);
149155
+ notice(`${res.message} · testing…`);
149132
149156
  const t2 = await testAccount(res.account);
149133
149157
  notice(t2.ok ? `✓ added · ${t2.message}` : `added, but the key test failed: ${t2.message}`);
149134
149158
  const d = await discoverModels(res.account);
149135
149159
  if (d.models.length) {
149136
149160
  putAccount({ ...res.account, models: d.models });
149137
- notice(`found ${d.models.length} model${d.models.length === 1 ? "" : "s"} on this account /model to pick one`);
149161
+ notice(`found ${d.models.length} model${d.models.length === 1 ? "" : "s"} on this account · /model to pick one`);
149138
149162
  } else if (d.note) {
149139
149163
  notice(d.note);
149140
149164
  }
@@ -149166,7 +149190,7 @@ Example: /mcp add github npx -y @modelcontextprotocol/server-github`);
149166
149190
  const keys2 = importableEnvCreds();
149167
149191
  const cloud = importableCloudCreds();
149168
149192
  if (!keys2.length && !cloud.length) {
149169
- notice("nothing to import no new provider keys or cloud creds found");
149193
+ notice("nothing to import · no new provider keys or cloud creds found");
149170
149194
  return;
149171
149195
  }
149172
149196
  for (const c of keys2)
@@ -149181,7 +149205,7 @@ Example: /mcp add github npx -y @modelcontextprotocol/server-github`);
149181
149205
  (async () => {
149182
149206
  const targets = listAccounts().filter((a) => a.enabled && a.exec !== "cli");
149183
149207
  if (!targets.length) {
149184
- notice("no API/cloud accounts to refresh /account add to add one");
149208
+ notice("no API/cloud accounts to refresh · /account add to add one");
149185
149209
  return;
149186
149210
  }
149187
149211
  notice(`refreshing models for ${targets.length} account${targets.length === 1 ? "" : "s"}…`);
@@ -149250,7 +149274,7 @@ Example: /mcp add github npx -y @modelcontextprotocol/server-github`);
149250
149274
  case "compact": {
149251
149275
  echo(text2);
149252
149276
  if (busyRef.current) {
149253
- notice("busy try /compact once the current turn finishes");
149277
+ notice("busy · try /compact once the current turn finishes");
149254
149278
  return;
149255
149279
  }
149256
149280
  setBusy(true);
@@ -149274,7 +149298,7 @@ Example: /mcp add github npx -y @modelcontextprotocol/server-github`);
149274
149298
  case "init":
149275
149299
  if (busyRef.current) {
149276
149300
  echo(text2);
149277
- notice("busy try /init again once the current turn finishes");
149301
+ notice("busy · try /init again once the current turn finishes");
149278
149302
  return;
149279
149303
  }
149280
149304
  echo(text2);
@@ -149306,7 +149330,7 @@ Example: /mcp add github npx -y @modelcontextprotocol/server-github`);
149306
149330
  default: {
149307
149331
  echo(text2);
149308
149332
  const near = matchCommands(`/${name31}`).filter((c) => c.name !== `/${name31}`)[0];
149309
- notice(near ? `no /${name31} command did you mean ${near.name}? (/help for all)` : `no /${name31} command type /help to see what's available`);
149333
+ notice(near ? `no /${name31} command · did you mean ${near.name}? (/help for all)` : `no /${name31} command · type /help to see what's available`);
149310
149334
  return;
149311
149335
  }
149312
149336
  }
@@ -149335,7 +149359,7 @@ Example: /mcp add github npx -y @modelcontextprotocol/server-github`);
149335
149359
  const cmd = text2.slice(1).trim();
149336
149360
  echo(text2);
149337
149361
  if (!cmd) {
149338
- notice("run a shell command with !<command> e.g. !git status");
149362
+ notice("run a shell command with !<command> · e.g. !git status");
149339
149363
  return;
149340
149364
  }
149341
149365
  const id = idRef.current++;
@@ -149378,7 +149402,7 @@ Example: /mcp add github npx -y @modelcontextprotocol/server-github`);
149378
149402
  if (busyRef.current) {
149379
149403
  queueRef.current.push(text2);
149380
149404
  setQueued([...queueRef.current]);
149381
- notice(`queued (${queueRef.current.length}) sends when the current turn finishes`);
149405
+ notice(`queued (${queueRef.current.length}) · sends when the current turn finishes`);
149382
149406
  return;
149383
149407
  }
149384
149408
  if (looksLikeGearboxQuestion(text2)) {
@@ -149420,7 +149444,7 @@ Example: /mcp add github npx -y @modelcontextprotocol/server-github`);
149420
149444
  msgRef.current = ms.slice(0, mi);
149421
149445
  curAsstRef.current = null;
149422
149446
  setEdit({ value: userText, cursor: userText.length });
149423
- notice("rewound the last turn edit and resend");
149447
+ notice("rewound the last turn · edit and resend");
149424
149448
  };
149425
149449
  use_input_default((input, key) => {
149426
149450
  if (/\[<\d+;\d+;\d+[Mm]/.test(input))
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gearbox-code",
3
- "version": "0.2.3",
3
+ "version": "0.2.4",
4
4
  "description": "A beautiful multi-provider coding harness for the terminal. (Intelligent model routing lands on top of this soon.)",
5
5
  "type": "module",
6
6
  "license": "MIT",