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.
- package/dist/cli.mjs +116 -72
- 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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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}”
|
|
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
|
|
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}
|
|
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(", ")}
|
|
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
|
|
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 ? "
|
|
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})
|
|
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)
|
|
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)
|
|
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()}
|
|
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
|
|
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"}
|
|
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
|
|
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(", ")}
|
|
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(", ")}
|
|
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(", ")}
|
|
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 ? `
|
|
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
|
|
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
|
|
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 ? `
|
|
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
|
|
148045
|
-
"auto-accept": "auto-accept edits
|
|
148046
|
-
plan: "plan mode
|
|
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 `
|
|
148079
|
-
return `
|
|
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}
|
|
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(" ")}\`
|
|
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[?
|
|
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 ?
|
|
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
|
|
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
|
|
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}
|
|
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}
|
|
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
|
|
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
|
|
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"}
|
|
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
|
|
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}
|
|
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)}` : ""}
|
|
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
|
|
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
|
|
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}
|
|
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}
|
|
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}
|
|
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}
|
|
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
|
-
|
|
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]
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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}
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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>
|
|
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})
|
|
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
|
|
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 &&
|
|
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
|
|
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[?
|
|
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