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.
- package/dist/cli.mjs +91 -67
- 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) {
|
|
@@ -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"}
|
|
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
|
|
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(", ")}
|
|
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(", ")}
|
|
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(", ")}
|
|
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 ? `
|
|
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
|
|
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
|
|
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 ? `
|
|
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
|
|
148046
|
-
"auto-accept": "auto-accept edits
|
|
148047
|
-
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"
|
|
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 `
|
|
148080
|
-
return `
|
|
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}
|
|
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(" ")}\`
|
|
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 ?
|
|
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
|
|
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
|
|
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}
|
|
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}
|
|
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
|
|
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
|
|
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"}
|
|
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
|
|
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}
|
|
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)}` : ""}
|
|
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
|
|
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
|
|
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}
|
|
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}
|
|
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}
|
|
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}
|
|
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
|
-
|
|
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]
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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}
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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>
|
|
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})
|
|
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
|
|
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