gearbox-code 0.2.2 → 0.2.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/cli.mjs +116 -72
  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) {
@@ -146967,6 +146982,7 @@ function App2({ selector: initialSelector, runner, fullscreen = false, resumeId
146967
146982
  const notifyRef = import_react26.useRef(loadPrefs().notify !== false);
146968
146983
  const firstRunRef = import_react26.useRef(!loadPrefs().onboarded);
146969
146984
  const pasteStoreRef = import_react26.useRef(new Map);
146985
+ const pasteBufRef = import_react26.useRef(null);
146970
146986
  const pasteIdRef = import_react26.useRef(0);
146971
146987
  const copiedSelectionRef = import_react26.useRef("");
146972
146988
  const mouseAnchorRef = import_react26.useRef(null);
@@ -147151,7 +147167,7 @@ function App2({ selector: initialSelector, runner, fullscreen = false, resumeId
147151
147167
  } catch {}
147152
147168
  }
147153
147169
  if (learned)
147154
- 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`);
147155
147171
  })();
147156
147172
  }, []);
147157
147173
  import_react26.useEffect(() => {
@@ -147621,7 +147637,7 @@ function App2({ selector: initialSelector, runner, fullscreen = false, resumeId
147621
147637
  rows2.push(" no named subscription models exposed yet");
147622
147638
  for (const m2 of models)
147623
147639
  rows2.push(` ${m2.id === currentId ? glyph.on : glyph.off} ${m2.label}`);
147624
- 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
147625
147641
  tip: /model haiku (or any API model name) switches directly and leaves the subscription`);
147626
147642
  return rows2.join(`
147627
147643
  `);
@@ -147634,7 +147650,7 @@ function App2({ selector: initialSelector, runner, fullscreen = false, resumeId
147634
147650
  const exact = matches2.find((m3) => m3.label.toLowerCase() === q || m3.id.toLowerCase() === q);
147635
147651
  const m2 = exact ?? (matches2.length === 1 ? matches2[0] : undefined);
147636
147652
  if (!m2)
147637
- 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` };
147638
147654
  return { ok: true, modelId: m2.id, label: m2.label };
147639
147655
  };
147640
147656
  const setActiveCliModelId = (modelId) => {
@@ -147756,12 +147772,12 @@ function App2({ selector: initialSelector, runner, fullscreen = false, resumeId
147756
147772
  if (exact.length === 1)
147757
147773
  return { account: exact[0].a };
147758
147774
  if (exact.length > 1)
147759
- 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` };
147760
147776
  const fuzzy = accounts.map((a) => ({ a, aliases: [...accountAliases(a)] })).filter(({ aliases }) => aliases.some((x2) => x2.includes(q)));
147761
147777
  if (fuzzy.length === 1)
147762
147778
  return { account: fuzzy[0].a };
147763
147779
  if (fuzzy.length > 1)
147764
- 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` };
147765
147781
  return { error: `no account matching "${query}"` };
147766
147782
  };
147767
147783
  const buildAccountView = (accounts, activeCliId, importable, statuses) => {
@@ -147822,7 +147838,7 @@ function App2({ selector: initialSelector, runner, fullscreen = false, resumeId
147822
147838
  const _cliEffortRaw = normalizeEffort(effortRef.current, efforts);
147823
147839
  if (_cliEffortRaw === null && effortRef.current !== "medium") {
147824
147840
  const { level: nearest } = clampEffort(effortRef.current, efforts);
147825
- const hint = efforts.length ? ` try /effort ${nearest}` : "";
147841
+ const hint = efforts.length ? ` · try /effort ${nearest}` : "";
147826
147842
  throw new Error(`effort "${effortRef.current}" is not supported by ${label ?? binary} (supports: ${efforts.join(", ") || "none"}${hint})`);
147827
147843
  }
147828
147844
  const cliEffort = _cliEffortRaw ?? undefined;
@@ -147874,12 +147890,12 @@ ${map4}
147874
147890
  if (isAsk) {
147875
147891
  const docs = loadGearboxDocs();
147876
147892
  if (!docs) {
147877
- 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." });
147878
147894
  return { messages, usage: { inputTokens: 0, outputTokens: 0 } };
147879
147895
  }
147880
147896
  const choice3 = new RoutingSelector().select({ prompt, kind: "search" });
147881
147897
  if (choice3.backend?.kind === "cli") {
147882
- 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>." });
147883
147899
  return { messages, usage: { inputTokens: 0, outputTokens: 0 } };
147884
147900
  }
147885
147901
  routedRef.current = { model: choice3.model, reason: choice3.reason };
@@ -147980,7 +147996,7 @@ ${map4}
147980
147996
  if (_effortRaw === null && effortRef.current !== "medium") {
147981
147997
  const supported = effortLevels(choice3.model);
147982
147998
  const { level: nearest } = clampEffort(effortRef.current, supported);
147983
- const hint = supported.length ? ` try /effort ${nearest}` : "";
147999
+ const hint = supported.length ? ` · try /effort ${nearest}` : "";
147984
148000
  throw new Error(`effort "${effortRef.current}" is not supported by ${choice3.model.label} (supports: ${supported.join(", ") || "none"}${hint})`);
147985
148001
  }
147986
148002
  const r2 = await runTask({ model: choice3.model, messages: ctx, onEvent, signal, plan, system, creds, effort: _effortRaw ?? undefined, deferTerminal: true });
@@ -148041,9 +148057,9 @@ ${map4}
148041
148057
  return `compacted ${res.summarizedTurns} earlier turn${res.summarizedTurns > 1 ? "s" : ""} · ~${savedStr} tokens freed`;
148042
148058
  }, []);
148043
148059
  const MODE_NOTE = {
148044
- normal: "normal mode I'll ask before writes, edits, and shell",
148045
- "auto-accept": "auto-accept edits file writes/edits apply without asking (shell still gated)",
148046
- 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"
148047
148063
  };
148048
148064
  const setModeTo = (next) => {
148049
148065
  modeRef.current = next;
@@ -148075,8 +148091,8 @@ ${map4}
148075
148091
  effortRef.current = level;
148076
148092
  setEffortState(level);
148077
148093
  if (!allowed.length)
148078
- return ` effort reset to ${level} (no reasoning support)`;
148079
- 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)`;
148080
148096
  };
148081
148097
  const setEffort = (raw) => {
148082
148098
  const target = effortTarget();
@@ -148091,7 +148107,7 @@ ${map4}
148091
148107
  }
148092
148108
  effortRef.current = level;
148093
148109
  setEffortState(level);
148094
- notice(`effort: ${level} ${target.label}`);
148110
+ notice(`effort: ${level} · ${target.label}`);
148095
148111
  };
148096
148112
  const runInteractive = (cmd, cmdArgs, env3) => {
148097
148113
  try {
@@ -148102,7 +148118,7 @@ ${map4}
148102
148118
  process.stdout.write("\x1B[?1049l");
148103
148119
  process.stdout.write("\x1B[?2004l\x1B[?25h");
148104
148120
  process.stdout.write(`
148105
- → running \`${cmd} ${cmdArgs.join(" ")}\` follow the prompts…
148121
+ → running \`${cmd} ${cmdArgs.join(" ")}\` · follow the prompts…
148106
148122
 
148107
148123
  `);
148108
148124
  const r2 = nodeSpawnSync2(cmd, cmdArgs, { stdio: ["inherit", "inherit", "inherit"], ...env3 ? { env: env3 } : {} });
@@ -148114,7 +148130,7 @@ ${map4}
148114
148130
  process.stdout.write("\x1B[?1049h\x1B[2J\x1B[H");
148115
148131
  if (process.env.GEARBOX_MOUSE !== "0")
148116
148132
  process.stdout.write("\x1B[?1000h\x1B[?1002h\x1B[?1006h");
148117
- process.stdout.write("\x1B[?2004l\x1B[?25l");
148133
+ process.stdout.write("\x1B[?2004h\x1B[?25l");
148118
148134
  setRawMode?.(true);
148119
148135
  }
148120
148136
  };
@@ -148405,7 +148421,7 @@ ${fetched.join(`
148405
148421
  const changed = uniq2([...changedFiles]);
148406
148422
  const doneChecks = uniq2(checks4);
148407
148423
  const failed = uniq2(failures).slice(0, 4);
148408
- 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";
148409
148425
  if (changed.length || doneChecks.length || failed.length) {
148410
148426
  push({ kind: "summary", id: idRef.current++, changed, checks: doneChecks, failures: failed, next });
148411
148427
  }
@@ -148525,7 +148541,7 @@ ${fetched.join(`
148525
148541
  return;
148526
148542
  }
148527
148543
  if (a && a.exec !== "cli") {
148528
- 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.`);
148529
148545
  return;
148530
148546
  }
148531
148547
  signInCli(arg2);
@@ -148559,13 +148575,13 @@ ${fetched.join(`
148559
148575
  }
148560
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(`
148561
148577
  `);
148562
- notice(`resume a session /resume <n>:
148578
+ notice(`resume a session · /resume <n>:
148563
148579
  ` + rows2);
148564
148580
  return;
148565
148581
  }
148566
148582
  const pick3 = (resumeListRef.current.length ? resumeListRef.current : sessions)[parseInt(arg, 10) - 1];
148567
148583
  if (!pick3) {
148568
- notice(`no session ${arg} /resume to list`);
148584
+ notice(`no session ${arg} · /resume to list`);
148569
148585
  return;
148570
148586
  }
148571
148587
  loadInto(pick3);
@@ -148589,7 +148605,7 @@ ${fetched.join(`
148589
148605
  setEffort(arg);
148590
148606
  } else {
148591
148607
  const target = effortTarget();
148592
- 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");
148593
148609
  }
148594
148610
  return;
148595
148611
  }
@@ -148626,7 +148642,7 @@ ${fetched.join(`
148626
148642
  const on = vimRef.current === "off";
148627
148643
  setVim(on ? "insert" : "off");
148628
148644
  updatePrefs({ vim: on });
148629
- 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");
148630
148646
  return;
148631
148647
  }
148632
148648
  case "config": {
@@ -148645,10 +148661,10 @@ ${fetched.join(`
148645
148661
  if (key === "vim") {
148646
148662
  setVim(on ? "insert" : "off");
148647
148663
  updatePrefs({ vim: on });
148648
- 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");
148649
148665
  } else if (key === "inline") {
148650
148666
  updatePrefs({ fullscreen: !on });
148651
- notice(`inline mode ${on ? "on" : "off"} restart gearbox to apply`);
148667
+ notice(`inline mode ${on ? "on" : "off"} · restart gearbox to apply`);
148652
148668
  } else if (key === "notify") {
148653
148669
  notifyRef.current = on;
148654
148670
  updatePrefs({ notify: on });
@@ -148663,7 +148679,7 @@ ${fetched.join(`
148663
148679
  const next = !isYolo();
148664
148680
  setYolo(next);
148665
148681
  setYoloState(next);
148666
- 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");
148667
148683
  return;
148668
148684
  }
148669
148685
  case "ghost": {
@@ -148672,7 +148688,7 @@ ${fetched.join(`
148672
148688
  if (arg) {
148673
148689
  const found = SKINS.find((s2) => s2 === arg.toLowerCase());
148674
148690
  if (!found) {
148675
- notice(`unknown mood: ${arg} try ${SKINS.join(", ")}`);
148691
+ notice(`unknown mood: ${arg} · try ${SKINS.join(", ")}`);
148676
148692
  return;
148677
148693
  }
148678
148694
  next = found;
@@ -148716,7 +148732,7 @@ ${fetched.join(`
148716
148732
  if (!arg || arg.toLowerCase() === "all") {
148717
148733
  const routing2 = selectorRef.current instanceof RoutingSelector;
148718
148734
  const activeSub = activeCliRef.current;
148719
- 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`;
148720
148736
  const list2 = activeSub ? formatCliModelList(activeSub.binary, activeCliModelRef.current ?? null) : formatModelList(currentId, arg.toLowerCase() === "all");
148721
148737
  notice(list2 + `
148722
148738
 
@@ -148726,7 +148742,7 @@ ${fetched.join(`
148726
148742
  if (arg.toLowerCase() === "auto" || arg.toLowerCase() === "route") {
148727
148743
  if (activeCliRef.current) {
148728
148744
  setActiveCliModelId(undefined);
148729
- 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`);
148730
148746
  return;
148731
148747
  }
148732
148748
  const left = leaveSubscription();
@@ -148734,7 +148750,7 @@ ${fetched.join(`
148734
148750
  setLastPick(null);
148735
148751
  routedRef.current = null;
148736
148752
  updatePrefs({ pinnedModel: undefined });
148737
- 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);
148738
148754
  return;
148739
148755
  }
148740
148756
  {
@@ -148751,7 +148767,7 @@ ${fetched.join(`
148751
148767
  updatePrefs({ pinnedModel: r3.modelId });
148752
148768
  const newSpec2 = findModel(r3.modelId);
148753
148769
  const effortSuffix2 = applyEffortClamp(newSpec2 ? effortLevels(newSpec2) : []);
148754
- notice(`${r3.message} pinned (left subscription).${left}${effortSuffix2}`);
148770
+ notice(`${r3.message} · pinned (left subscription).${left}${effortSuffix2}`);
148755
148771
  const kind = classify(lastPromptRef.current ?? "").replace("code", "code");
148756
148772
  push({ kind: "preference", id: idRef.current++, text: `Remember ${r3.modelId} for ${kind} tasks?`, acceptCommand: `/prefer ${kind} ${r3.modelId}` });
148757
148773
  return;
@@ -148768,7 +148784,7 @@ ${fetched.join(`
148768
148784
  updatePrefs({ pinnedModel: r3.modelId });
148769
148785
  const newSpec2 = findModel(r3.modelId);
148770
148786
  const effortSuffix2 = applyEffortClamp(newSpec2 ? effortLevels(newSpec2) : []);
148771
- notice(`${r3.message} pinned (left subscription).${left}${effortSuffix2}`);
148787
+ notice(`${r3.message} · pinned (left subscription).${left}${effortSuffix2}`);
148772
148788
  const kind = classify(lastPromptRef.current ?? "").replace("code", "code");
148773
148789
  push({ kind: "preference", id: idRef.current++, text: `Remember ${r3.modelId} for ${kind} tasks?`, acceptCommand: `/prefer ${kind} ${r3.modelId}` });
148774
148790
  return;
@@ -148779,7 +148795,7 @@ ${fetched.join(`
148779
148795
  setActiveCliModelId(cr.modelId);
148780
148796
  const newCliModel = cliModelChoices(cli.binary).find((m2) => m2.id === cr.modelId);
148781
148797
  const effortSuffix = applyEffortClamp(newCliModel?.efforts ?? []);
148782
- 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}`);
148783
148799
  return;
148784
148800
  }
148785
148801
  const r2 = resolveModelSwitch(arg);
@@ -148791,11 +148807,20 @@ ${fetched.join(`
148791
148807
  updatePrefs({ pinnedModel: r2.modelId });
148792
148808
  const newSpec = findModel(r2.modelId);
148793
148809
  const effortSuffix = applyEffortClamp(newSpec ? effortLevels(newSpec) : []);
148794
- 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}`);
148795
148811
  const kind = classify(lastPromptRef.current ?? "").replace("code", "code");
148796
148812
  push({ kind: "preference", id: idRef.current++, text: `Remember ${r2.modelId} for ${kind} tasks?`, acceptCommand: `/prefer ${kind} ${r2.modelId}` });
148797
148813
  } else {
148798
- 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
+ }
148799
148824
  }
148800
148825
  }
148801
148826
  return;
@@ -148825,7 +148850,7 @@ ${fetched.join(`
148825
148850
  const keys2 = Object.keys(b);
148826
148851
  notice(keys2.length ? `budgets (estimates remaining = budget − tracked spend):
148827
148852
  ` + keys2.map((k) => ` ${k}: $${b[k].amountUSD} ${b[k].period}`).join(`
148828
- `) : "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");
148829
148854
  return;
148830
148855
  }
148831
148856
  const [target, amountRaw, periodRaw] = parts;
@@ -148852,7 +148877,7 @@ ${fetched.join(`
148852
148877
  }
148853
148878
  const facts = loadFacts().trim();
148854
148879
  const it = { kind: "notice", id: idRef.current++, text: facts ? `remembered facts:
148855
- ` + 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>" };
148856
148881
  if (openInfoPanel("memory", it))
148857
148882
  return;
148858
148883
  echo(text2);
@@ -148869,7 +148894,7 @@ ${fetched.join(`
148869
148894
  })();
148870
148895
  if (!m2) {
148871
148896
  echo(text2);
148872
- notice(`no model available add a provider first
148897
+ notice(`no model available · add a provider first
148873
148898
 
148874
148899
  ` + onboardingSummary(onboardingState));
148875
148900
  return;
@@ -148886,7 +148911,7 @@ ${fetched.join(`
148886
148911
  echo(text2);
148887
148912
  const sel = selectorRef.current;
148888
148913
  if (!sel.explain) {
148889
- 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.");
148890
148915
  return;
148891
148916
  }
148892
148917
  try {
@@ -149010,7 +149035,7 @@ Example: /mcp add github npx -y @modelcontextprotocol/server-github`);
149010
149035
  const withHealth = listAccounts();
149011
149036
  pushAccounts(buildAccountView(withHealth, activeCliRef.current?.id ?? null, importableEnvCreds(), statuses));
149012
149037
  } catch (e2) {
149013
- notice(`couldn't check subscription accounts ${e2?.message ?? String(e2)}`);
149038
+ notice(`couldn't check subscription accounts · ${e2?.message ?? String(e2)}`);
149014
149039
  pushAccounts(buildAccountView(listAccounts(), activeCliRef.current?.id ?? null, importableEnvCreds(), accountStatusCacheRef.current));
149015
149040
  }
149016
149041
  })();
@@ -149064,7 +149089,7 @@ Example: /mcp add github npx -y @modelcontextprotocol/server-github`);
149064
149089
  cliSessionRef.current = undefined;
149065
149090
  setActiveCli(null);
149066
149091
  updatePrefs({ activeAccount: null });
149067
- notice("left the subscription back to your API keys");
149092
+ notice("left the subscription · back to your API keys");
149068
149093
  return;
149069
149094
  }
149070
149095
  if (subL === "login") {
@@ -149127,13 +149152,13 @@ Example: /mcp add github npx -y @modelcontextprotocol/server-github`);
149127
149152
  notice(res.message);
149128
149153
  return;
149129
149154
  }
149130
- notice(`${res.message} testing…`);
149155
+ notice(`${res.message} · testing…`);
149131
149156
  const t2 = await testAccount(res.account);
149132
149157
  notice(t2.ok ? `✓ added · ${t2.message}` : `added, but the key test failed: ${t2.message}`);
149133
149158
  const d = await discoverModels(res.account);
149134
149159
  if (d.models.length) {
149135
149160
  putAccount({ ...res.account, models: d.models });
149136
- 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`);
149137
149162
  } else if (d.note) {
149138
149163
  notice(d.note);
149139
149164
  }
@@ -149165,7 +149190,7 @@ Example: /mcp add github npx -y @modelcontextprotocol/server-github`);
149165
149190
  const keys2 = importableEnvCreds();
149166
149191
  const cloud = importableCloudCreds();
149167
149192
  if (!keys2.length && !cloud.length) {
149168
- 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");
149169
149194
  return;
149170
149195
  }
149171
149196
  for (const c of keys2)
@@ -149180,7 +149205,7 @@ Example: /mcp add github npx -y @modelcontextprotocol/server-github`);
149180
149205
  (async () => {
149181
149206
  const targets = listAccounts().filter((a) => a.enabled && a.exec !== "cli");
149182
149207
  if (!targets.length) {
149183
- 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");
149184
149209
  return;
149185
149210
  }
149186
149211
  notice(`refreshing models for ${targets.length} account${targets.length === 1 ? "" : "s"}…`);
@@ -149249,7 +149274,7 @@ Example: /mcp add github npx -y @modelcontextprotocol/server-github`);
149249
149274
  case "compact": {
149250
149275
  echo(text2);
149251
149276
  if (busyRef.current) {
149252
- notice("busy try /compact once the current turn finishes");
149277
+ notice("busy · try /compact once the current turn finishes");
149253
149278
  return;
149254
149279
  }
149255
149280
  setBusy(true);
@@ -149273,7 +149298,7 @@ Example: /mcp add github npx -y @modelcontextprotocol/server-github`);
149273
149298
  case "init":
149274
149299
  if (busyRef.current) {
149275
149300
  echo(text2);
149276
- notice("busy try /init again once the current turn finishes");
149301
+ notice("busy · try /init again once the current turn finishes");
149277
149302
  return;
149278
149303
  }
149279
149304
  echo(text2);
@@ -149305,7 +149330,7 @@ Example: /mcp add github npx -y @modelcontextprotocol/server-github`);
149305
149330
  default: {
149306
149331
  echo(text2);
149307
149332
  const near = matchCommands(`/${name31}`).filter((c) => c.name !== `/${name31}`)[0];
149308
- 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`);
149309
149334
  return;
149310
149335
  }
149311
149336
  }
@@ -149334,7 +149359,7 @@ Example: /mcp add github npx -y @modelcontextprotocol/server-github`);
149334
149359
  const cmd = text2.slice(1).trim();
149335
149360
  echo(text2);
149336
149361
  if (!cmd) {
149337
- notice("run a shell command with !<command> e.g. !git status");
149362
+ notice("run a shell command with !<command> · e.g. !git status");
149338
149363
  return;
149339
149364
  }
149340
149365
  const id = idRef.current++;
@@ -149377,7 +149402,7 @@ Example: /mcp add github npx -y @modelcontextprotocol/server-github`);
149377
149402
  if (busyRef.current) {
149378
149403
  queueRef.current.push(text2);
149379
149404
  setQueued([...queueRef.current]);
149380
- notice(`queued (${queueRef.current.length}) sends when the current turn finishes`);
149405
+ notice(`queued (${queueRef.current.length}) · sends when the current turn finishes`);
149381
149406
  return;
149382
149407
  }
149383
149408
  if (looksLikeGearboxQuestion(text2)) {
@@ -149419,11 +149444,30 @@ Example: /mcp add github npx -y @modelcontextprotocol/server-github`);
149419
149444
  msgRef.current = ms.slice(0, mi);
149420
149445
  curAsstRef.current = null;
149421
149446
  setEdit({ value: userText, cursor: userText.length });
149422
- notice("rewound the last turn edit and resend");
149447
+ notice("rewound the last turn · edit and resend");
149423
149448
  };
149424
149449
  use_input_default((input, key) => {
149425
149450
  if (/\[<\d+;\d+;\d+[Mm]/.test(input))
149426
149451
  return;
149452
+ if (pasteBufRef.current !== null || input.includes("\x1B[200~")) {
149453
+ pasteBufRef.current = (pasteBufRef.current ?? "") + input;
149454
+ if (!pasteBufRef.current.includes("\x1B[201~"))
149455
+ return;
149456
+ const clean = sanitizeInputText(pasteBufRef.current.replace(/\x1b\[20[01]~/g, ""));
149457
+ pasteBufRef.current = null;
149458
+ const e2 = editRef.current;
149459
+ const lines2 = clean.split(`
149460
+ `).length;
149461
+ if (clean.length > 400 || lines2 > 4) {
149462
+ const id = ++pasteIdRef.current;
149463
+ const ph = `[Pasted #${id}: ${lines2} line${lines2 === 1 ? "" : "s"} · ${clean.length.toLocaleString()} chars]`;
149464
+ pasteStoreRef.current.set(ph, clean);
149465
+ setEdit({ value: e2.value.slice(0, e2.cursor) + ph + e2.value.slice(e2.cursor), cursor: e2.cursor + ph.length });
149466
+ } else {
149467
+ setEdit({ value: e2.value.slice(0, e2.cursor) + clean + e2.value.slice(e2.cursor), cursor: e2.cursor + clean.length });
149468
+ }
149469
+ return;
149470
+ }
149427
149471
  if (permRef.current) {
149428
149472
  if (input === "1")
149429
149473
  resolvePerm("once");
@@ -149669,14 +149713,14 @@ Example: /mcp add github npx -y @modelcontextprotocol/server-github`);
149669
149713
  return;
149670
149714
  }
149671
149715
  }
149672
- if (!busyRef.current && (input.includes("\x1B[200~") || input.length > 240 && input.includes(`
149673
- `))) {
149716
+ if (!busyRef.current && input.length > 240 && input.includes(`
149717
+ `)) {
149674
149718
  const clean = sanitizeInputText(input);
149675
149719
  const lines2 = clean.split(`
149676
149720
  `).length;
149677
149721
  if (lines2 > 4 || clean.length > 400) {
149678
149722
  const id = ++pasteIdRef.current;
149679
- const ph = `[Pasted #${id}: ${lines2} line${lines2 > 1 ? "s" : ""}]`;
149723
+ const ph = `[Pasted #${id}: ${lines2} line${lines2 === 1 ? "" : "s"} · ${clean.length.toLocaleString()} chars]`;
149680
149724
  pasteStoreRef.current.set(ph, clean);
149681
149725
  const e2 = editRef.current;
149682
149726
  setEdit({ value: e2.value.slice(0, e2.cursor) + ph + e2.value.slice(e2.cursor), cursor: e2.cursor + ph.length });
@@ -150628,7 +150672,7 @@ process.once("SIGTERM", () => {
150628
150672
  process.exit(0);
150629
150673
  });
150630
150674
  if (process.stdout.isTTY)
150631
- process.stdout.write("\x1B[?2004l\x1B[?25l");
150675
+ process.stdout.write("\x1B[?2004h\x1B[?25l");
150632
150676
  if (fullscreen)
150633
150677
  process.stdout.write("\x1B[?1049h\x1B[2J\x1B[H");
150634
150678
  if (mouse)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gearbox-code",
3
- "version": "0.2.2",
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",