gearbox-code 0.1.3 → 0.1.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/README.md +5 -3
- package/dist/cli.mjs +294 -152
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -31,12 +31,14 @@ A beautiful, simple coding harness for the terminal. It reads, edits, and runs y
|
|
|
31
31
|
|
|
32
32
|
```bash
|
|
33
33
|
bun install
|
|
34
|
-
|
|
34
|
+
gearbox auth add <api-key> # paste-detects common providers when possible
|
|
35
|
+
# or: gearbox auth add <provider> <api-key>
|
|
36
|
+
# or: gearbox auth import # import keys from env/cloud credentials
|
|
35
37
|
bun start # or: bun run src/cli.tsx
|
|
36
38
|
bun start -- --model gemini-flash # pick a model
|
|
37
39
|
```
|
|
38
40
|
|
|
39
|
-
No
|
|
41
|
+
No provider configured? Gearbox opens a setup screen and will not run a fake model. Preview the look without running anything:
|
|
40
42
|
|
|
41
43
|
```bash
|
|
42
44
|
bun run scripts/preview.tsx
|
|
@@ -48,7 +50,7 @@ Requires [Bun](https://bun.sh). Clone the repo, then:
|
|
|
48
50
|
|
|
49
51
|
```bash
|
|
50
52
|
./install.sh # bun install + bun link → 'gearbox' on your PATH
|
|
51
|
-
|
|
53
|
+
gearbox auth add <api-key> # each person uses their own provider account
|
|
52
54
|
cd ~/any/project && gearbox # the current directory is the workspace
|
|
53
55
|
```
|
|
54
56
|
|
package/dist/cli.mjs
CHANGED
|
@@ -64171,6 +64171,104 @@ var init_detect = __esm(() => {
|
|
|
64171
64171
|
init_store();
|
|
64172
64172
|
});
|
|
64173
64173
|
|
|
64174
|
+
// src/accounts/onboarding.ts
|
|
64175
|
+
function normalizeProviderId(input) {
|
|
64176
|
+
const key = input.trim().toLowerCase().replace(/[_\s]+/g, "-");
|
|
64177
|
+
return ALIASES[key] ?? key;
|
|
64178
|
+
}
|
|
64179
|
+
function apiKeyProviders() {
|
|
64180
|
+
return CATALOG.filter((p) => (p.authKind === "api-key" || p.authKind === "openai-compat") && p.group !== "local" && (p.authKind !== "openai-compat" || Boolean(p.baseUrl)));
|
|
64181
|
+
}
|
|
64182
|
+
function featuredApiKeyProviders() {
|
|
64183
|
+
const providers = apiKeyProviders();
|
|
64184
|
+
const byId = new Map(providers.map((p) => [p.id, p]));
|
|
64185
|
+
const first = FEATURED.map((id) => byId.get(id)).filter((p) => Boolean(p));
|
|
64186
|
+
const rest2 = providers.filter((p) => !FEATURED.includes(p.id)).sort((a, b) => a.label.localeCompare(b.label));
|
|
64187
|
+
return [...first, ...rest2];
|
|
64188
|
+
}
|
|
64189
|
+
function needsOnboarding(state) {
|
|
64190
|
+
return state.configured.length === 0;
|
|
64191
|
+
}
|
|
64192
|
+
function onboardingSummary(state) {
|
|
64193
|
+
if (!needsOnboarding(state))
|
|
64194
|
+
return "ready";
|
|
64195
|
+
const lines = [
|
|
64196
|
+
"setup required",
|
|
64197
|
+
" Add any common provider API key:",
|
|
64198
|
+
...featuredApiKeyProviders().slice(0, 10).map((p) => ` /account add ${p.id} <api-key>`.padEnd(38) + `${p.label}`)
|
|
64199
|
+
];
|
|
64200
|
+
const more = featuredApiKeyProviders().length - 10;
|
|
64201
|
+
if (more > 0)
|
|
64202
|
+
lines.push(` /onboard providers show ${more} more providers`);
|
|
64203
|
+
if (state.importable.length || state.cloudImportable.length)
|
|
64204
|
+
lines.push("", " /account import import detected env/cloud credentials");
|
|
64205
|
+
lines.push(" /account add azure <endpoint> <api-key> Azure OpenAI / Foundry");
|
|
64206
|
+
if (state.hasClaudeCli)
|
|
64207
|
+
lines.push(" /account add claude use Claude subscription CLI");
|
|
64208
|
+
if (state.hasCodexCli)
|
|
64209
|
+
lines.push(" /account add codex use ChatGPT subscription CLI");
|
|
64210
|
+
lines.push("", "Paste-detect works for known key prefixes: /account add <api-key>");
|
|
64211
|
+
return lines.join(`
|
|
64212
|
+
`);
|
|
64213
|
+
}
|
|
64214
|
+
var ALIASES, FEATURED;
|
|
64215
|
+
var init_onboarding = __esm(() => {
|
|
64216
|
+
init_catalog();
|
|
64217
|
+
ALIASES = {
|
|
64218
|
+
anthropic: "anthropic",
|
|
64219
|
+
claude: "anthropic",
|
|
64220
|
+
openai: "openai",
|
|
64221
|
+
gpt: "openai",
|
|
64222
|
+
google: "google",
|
|
64223
|
+
gemini: "google",
|
|
64224
|
+
deepseek: "deepseek",
|
|
64225
|
+
grok: "xai",
|
|
64226
|
+
xai: "xai",
|
|
64227
|
+
"x-ai": "xai",
|
|
64228
|
+
mistral: "mistral",
|
|
64229
|
+
groq: "groq",
|
|
64230
|
+
together: "together",
|
|
64231
|
+
fireworks: "fireworks",
|
|
64232
|
+
deepinfra: "deepinfra",
|
|
64233
|
+
cerebras: "cerebras",
|
|
64234
|
+
perplexity: "perplexity",
|
|
64235
|
+
baseten: "baseten",
|
|
64236
|
+
moonshot: "moonshot",
|
|
64237
|
+
kimi: "moonshot",
|
|
64238
|
+
zai: "zai",
|
|
64239
|
+
zhipu: "zai",
|
|
64240
|
+
nebius: "nebius",
|
|
64241
|
+
hyperbolic: "hyperbolic",
|
|
64242
|
+
sambanova: "sambanova",
|
|
64243
|
+
novita: "novita",
|
|
64244
|
+
openrouter: "openrouter",
|
|
64245
|
+
requesty: "requesty",
|
|
64246
|
+
portkey: "portkey",
|
|
64247
|
+
litellm: "litellm",
|
|
64248
|
+
"vercel-gateway": "vercel-gateway",
|
|
64249
|
+
vercel: "vercel-gateway",
|
|
64250
|
+
"ai-gateway": "vercel-gateway",
|
|
64251
|
+
azure: "azure",
|
|
64252
|
+
"azure-foundry": "azure-foundry",
|
|
64253
|
+
foundry: "azure-foundry"
|
|
64254
|
+
};
|
|
64255
|
+
FEATURED = [
|
|
64256
|
+
"anthropic",
|
|
64257
|
+
"openai",
|
|
64258
|
+
"google",
|
|
64259
|
+
"deepseek",
|
|
64260
|
+
"openrouter",
|
|
64261
|
+
"xai",
|
|
64262
|
+
"mistral",
|
|
64263
|
+
"groq",
|
|
64264
|
+
"together",
|
|
64265
|
+
"fireworks",
|
|
64266
|
+
"perplexity",
|
|
64267
|
+
"cerebras",
|
|
64268
|
+
"requesty"
|
|
64269
|
+
];
|
|
64270
|
+
});
|
|
64271
|
+
|
|
64174
64272
|
// src/agent/cli-backend.ts
|
|
64175
64273
|
function newState() {
|
|
64176
64274
|
return { text: "", usage: { inputTokens: 0, outputTokens: 0 }, rates: new Map, toolNames: new Map };
|
|
@@ -64423,9 +64521,10 @@ import { mkdirSync as mkdirSync7 } from "node:fs";
|
|
|
64423
64521
|
import { join as join10 } from "node:path";
|
|
64424
64522
|
import { homedir as homedir8 } from "node:os";
|
|
64425
64523
|
async function addApiKeyAccount(provider, key, opts = {}) {
|
|
64524
|
+
provider = normalizeProviderId(provider);
|
|
64426
64525
|
const cat = catalogProvider(provider);
|
|
64427
64526
|
if (!cat)
|
|
64428
|
-
return { ok: false, message: `unknown provider "${provider}" —
|
|
64527
|
+
return { ok: false, message: `unknown provider "${provider}" — use /onboard providers` };
|
|
64429
64528
|
if (cat.group === "cli")
|
|
64430
64529
|
return { ok: false, message: `${cat.label} is a subscription account — use /login ${provider} (P3), not a key` };
|
|
64431
64530
|
if (cat.authKind !== "api-key" && cat.authKind !== "openai-compat") {
|
|
@@ -64638,6 +64737,7 @@ function shortId() {
|
|
|
64638
64737
|
var init_onboard = __esm(() => {
|
|
64639
64738
|
init_store();
|
|
64640
64739
|
init_catalog();
|
|
64740
|
+
init_onboarding();
|
|
64641
64741
|
init_resolve();
|
|
64642
64742
|
init_cli_backend();
|
|
64643
64743
|
init_proc();
|
|
@@ -118420,6 +118520,7 @@ var COMMANDS = [
|
|
|
118420
118520
|
{ name: "/context", usage: "/context", desc: "see what's loaded and how many tokens it uses", group: "chat" },
|
|
118421
118521
|
{ name: "/memory", usage: "/memory [note]", desc: "show or add facts to remember (or start a line with #)", group: "chat" },
|
|
118422
118522
|
{ name: "/account", usage: "/account", desc: "list accounts; /account <number> to switch, /account add to add one", group: "accounts" },
|
|
118523
|
+
{ name: "/onboard", usage: "/onboard", desc: "first-run setup; provider list and import/add commands", group: "accounts" },
|
|
118423
118524
|
{ name: "/cost", usage: "/cost", desc: "see what you've spent per account", group: "accounts" },
|
|
118424
118525
|
{ name: "/copy", usage: "/copy", desc: "copy the last reply to the clipboard", group: "output" },
|
|
118425
118526
|
{ name: "/export", usage: "/export [file]", desc: "save the conversation to a file", group: "output" },
|
|
@@ -121187,9 +121288,6 @@ function pickDefaultModel(preferredId) {
|
|
|
121187
121288
|
return wanted;
|
|
121188
121289
|
return MODELS.find((m2) => providerAvailable(m2.provider));
|
|
121189
121290
|
}
|
|
121190
|
-
function anyProviderAvailable() {
|
|
121191
|
-
return MODELS.some((m2) => providerAvailable(m2.provider));
|
|
121192
|
-
}
|
|
121193
121291
|
|
|
121194
121292
|
// src/model/selector.ts
|
|
121195
121293
|
class FixedSelector {
|
|
@@ -133121,6 +133219,7 @@ init_store();
|
|
|
133121
133219
|
init_detect();
|
|
133122
133220
|
init_onboard();
|
|
133123
133221
|
init_catalog();
|
|
133222
|
+
init_onboarding();
|
|
133124
133223
|
init_cli_backend();
|
|
133125
133224
|
|
|
133126
133225
|
// src/accounts/balance.ts
|
|
@@ -133233,72 +133332,6 @@ ${summary}` },
|
|
|
133233
133332
|
return { messages, summarizedTurns: old.length, before: before2, after: after2 };
|
|
133234
133333
|
}
|
|
133235
133334
|
|
|
133236
|
-
// src/agent/mock.ts
|
|
133237
|
-
var sleep = (ms) => new Promise((r2) => setTimeout(r2, ms));
|
|
133238
|
-
async function stream(text2, onEvent, chunk2 = 3, delay3 = 8) {
|
|
133239
|
-
for (let i2 = 0;i2 < text2.length; i2 += chunk2) {
|
|
133240
|
-
onEvent({ type: "text", text: text2.slice(i2, i2 + chunk2) });
|
|
133241
|
-
await sleep(delay3);
|
|
133242
|
-
}
|
|
133243
|
-
}
|
|
133244
|
-
async function streamWrite(id, path, content, onEvent, stop) {
|
|
133245
|
-
onEvent({ type: "tool-start", id, name: "write_file", arg: "" });
|
|
133246
|
-
onEvent({ type: "tool-stream", id, arg: path });
|
|
133247
|
-
for (let i2 = 0;i2 < content.length; i2 += 8) {
|
|
133248
|
-
if (stop())
|
|
133249
|
-
return;
|
|
133250
|
-
onEvent({ type: "tool-stream", id, delta: content.slice(i2, i2 + 8) });
|
|
133251
|
-
await sleep(16);
|
|
133252
|
-
}
|
|
133253
|
-
const diff2 = content.replace(/\n$/, "").split(`
|
|
133254
|
-
`).map((text2) => ({ sign: "+", text: text2 }));
|
|
133255
|
-
onEvent({ type: "tool-end", id, ok: true, summary: `wrote ${path} (+${diff2.length} −0)`, diff: diff2 });
|
|
133256
|
-
}
|
|
133257
|
-
async function runTaskMock(opts) {
|
|
133258
|
-
const { prompt, messages, onEvent, signal } = opts;
|
|
133259
|
-
const stop = () => signal?.aborted === true;
|
|
133260
|
-
await stream(`Sure — let me take a look around first.
|
|
133261
|
-
`, onEvent);
|
|
133262
|
-
if (stop())
|
|
133263
|
-
return done(messages, onEvent);
|
|
133264
|
-
onEvent({ type: "tool-start", id: "1", name: "list_dir", arg: "." });
|
|
133265
|
-
await sleep(260);
|
|
133266
|
-
if (stop())
|
|
133267
|
-
return done(messages, onEvent);
|
|
133268
|
-
onEvent({ type: "tool-end", id: "1", ok: true, summary: "src · package.json · README.md · 5 more" });
|
|
133269
|
-
onEvent({ type: "tool-start", id: "2", name: "read_file", arg: "src/cli.tsx" });
|
|
133270
|
-
await sleep(220);
|
|
133271
|
-
if (stop())
|
|
133272
|
-
return done(messages, onEvent);
|
|
133273
|
-
onEvent({ type: "tool-end", id: "2", ok: true, summary: "renders the Ink app · 38 lines" });
|
|
133274
|
-
await stream(`
|
|
133275
|
-
Here's a quick file — watch it stream in:
|
|
133276
|
-
`, onEvent);
|
|
133277
|
-
if (stop())
|
|
133278
|
-
return done(messages, onEvent);
|
|
133279
|
-
const demoFile = `# hello.py — written live in demo mode
|
|
133280
|
-
|
|
133281
|
-
def greet(name: str) -> str:
|
|
133282
|
-
return f"Hello, {name}!"
|
|
133283
|
-
|
|
133284
|
-
if __name__ == "__main__":
|
|
133285
|
-
for who in ("world", "gearbox", "Boo"):
|
|
133286
|
-
print(greet(who))
|
|
133287
|
-
`;
|
|
133288
|
-
await streamWrite("3", "hello.py", demoFile, onEvent, stop);
|
|
133289
|
-
if (stop())
|
|
133290
|
-
return done(messages, onEvent);
|
|
133291
|
-
await stream(`
|
|
133292
|
-
This is demo mode — no API key is set, so I'm not calling a real model. ` + `Set ANTHROPIC_API_KEY (or OPENAI / GOOGLE / DEEPSEEK) and I'll actually work on: "${prompt}".
|
|
133293
|
-
`, onEvent);
|
|
133294
|
-
return done(messages, onEvent);
|
|
133295
|
-
}
|
|
133296
|
-
function done(messages, onEvent) {
|
|
133297
|
-
const usage = { inputTokens: 0, outputTokens: 0 };
|
|
133298
|
-
onEvent({ type: "done", usage });
|
|
133299
|
-
return { messages, usage };
|
|
133300
|
-
}
|
|
133301
|
-
|
|
133302
133335
|
// src/ui/clipboard.ts
|
|
133303
133336
|
init_proc();
|
|
133304
133337
|
function osc52(text2) {
|
|
@@ -133653,11 +133686,11 @@ function ActivityRail({ items, width }) {
|
|
|
133653
133686
|
]
|
|
133654
133687
|
}, undefined, true, undefined, this);
|
|
133655
133688
|
}
|
|
133656
|
-
function App2({ selector: initialSelector,
|
|
133689
|
+
function App2({ selector: initialSelector, runner, fullscreen = false, resumeId }) {
|
|
133657
133690
|
const { exit } = use_app_default();
|
|
133658
133691
|
const { stdin, isRawModeSupported, setRawMode } = use_stdin_default();
|
|
133659
133692
|
const { columns, rows } = useTerminalSize();
|
|
133660
|
-
const online = useOnline(20000,
|
|
133693
|
+
const online = useOnline(20000, true);
|
|
133661
133694
|
const width = columns;
|
|
133662
133695
|
const splashSize = rows >= 24 && columns >= 42 ? "big" : rows >= 13 && columns >= 22 ? "mini" : "none";
|
|
133663
133696
|
const [items, setItems] = import_react26.useState([]);
|
|
@@ -133736,10 +133769,6 @@ function App2({ selector: initialSelector, demo, runner, fullscreen = false, res
|
|
|
133736
133769
|
const t2 = setInterval(() => setElapsed(Math.floor((Date.now() - start) / 1000)), 500);
|
|
133737
133770
|
return () => clearInterval(t2);
|
|
133738
133771
|
}, [busy]);
|
|
133739
|
-
import_react26.useEffect(() => {
|
|
133740
|
-
if (firstRunRef.current)
|
|
133741
|
-
updatePrefs({ onboarded: true });
|
|
133742
|
-
}, []);
|
|
133743
133772
|
import_react26.useEffect(() => {
|
|
133744
133773
|
const proj = basename2(process.cwd());
|
|
133745
133774
|
setTitle(busy ? `✳ ${proj} · working` : `${proj} · gearbox`);
|
|
@@ -133800,8 +133829,6 @@ function App2({ selector: initialSelector, demo, runner, fullscreen = false, res
|
|
|
133800
133829
|
setTimeout(pumpPerm, 0);
|
|
133801
133830
|
};
|
|
133802
133831
|
import_react26.useEffect(() => {
|
|
133803
|
-
if (demo)
|
|
133804
|
-
return;
|
|
133805
133832
|
const acctId = loadPrefs().activeAccount;
|
|
133806
133833
|
if (!acctId)
|
|
133807
133834
|
return;
|
|
@@ -133813,7 +133840,7 @@ function App2({ selector: initialSelector, demo, runner, fullscreen = false, res
|
|
|
133813
133840
|
setActiveCliModelId(undefined);
|
|
133814
133841
|
setActiveCli({ id: a.id, label: bin });
|
|
133815
133842
|
}
|
|
133816
|
-
}, [
|
|
133843
|
+
}, []);
|
|
133817
133844
|
import_react26.useEffect(() => {
|
|
133818
133845
|
setPermissionHandler((req) => new Promise((resolve11) => {
|
|
133819
133846
|
if (modeRef.current === "auto-accept" && (req.kind === "write" || req.kind === "edit")) {
|
|
@@ -134055,8 +134082,6 @@ function App2({ selector: initialSelector, demo, runner, fullscreen = false, res
|
|
|
134055
134082
|
};
|
|
134056
134083
|
}, [stdin, fullscreen, rows, scrollBy, copyWithFeedback]);
|
|
134057
134084
|
const persist = import_react26.useCallback(() => {
|
|
134058
|
-
if (demo)
|
|
134059
|
-
return;
|
|
134060
134085
|
const s2 = sessionRef.current;
|
|
134061
134086
|
if (!itemsRef.current.length)
|
|
134062
134087
|
return;
|
|
@@ -134070,7 +134095,7 @@ function App2({ selector: initialSelector, demo, runner, fullscreen = false, res
|
|
|
134070
134095
|
items: itemsRef.current,
|
|
134071
134096
|
turns: s2.turns
|
|
134072
134097
|
});
|
|
134073
|
-
}, [
|
|
134098
|
+
}, []);
|
|
134074
134099
|
const loadInto = (s2) => {
|
|
134075
134100
|
idRef.current = s2.items.reduce((m2, i2) => Math.max(m2, i2.id), 0) + 1;
|
|
134076
134101
|
setItems(s2.items);
|
|
@@ -134230,10 +134255,24 @@ function App2({ selector: initialSelector, demo, runner, fullscreen = false, res
|
|
|
134230
134255
|
const [lastPick, setLastPick] = import_react26.useState(null);
|
|
134231
134256
|
const [activeCli, setActiveCli] = import_react26.useState(null);
|
|
134232
134257
|
const [activeCliModel, setActiveCliModel] = import_react26.useState(null);
|
|
134258
|
+
const onboardingState = {
|
|
134259
|
+
configured: listAccounts(),
|
|
134260
|
+
importable: importableEnvCreds(),
|
|
134261
|
+
cloudImportable: importableCloudCreds().map((c) => ({ provider: c.provider, label: c.label, source: c.source })),
|
|
134262
|
+
hasClaudeCli: Boolean(which("claude")),
|
|
134263
|
+
hasCodexCli: Boolean(which("codex"))
|
|
134264
|
+
};
|
|
134265
|
+
const setupRequired = needsOnboarding(onboardingState);
|
|
134266
|
+
import_react26.useEffect(() => {
|
|
134267
|
+
if (!setupRequired && firstRunRef.current) {
|
|
134268
|
+
firstRunRef.current = false;
|
|
134269
|
+
updatePrefs({ onboarded: true });
|
|
134270
|
+
}
|
|
134271
|
+
}, [setupRequired]);
|
|
134233
134272
|
const model = lastPick?.model ?? choice?.model ?? null;
|
|
134234
|
-
const modelLabel =
|
|
134273
|
+
const modelLabel = setupRequired ? "setup required" : activeCli ? `${activeCli.label}${activeCliModel ? ` · ${activeCliModel}` : ""}` : model?.label ?? "none";
|
|
134235
134274
|
const subscription = activeCli ? activeCli.label : null;
|
|
134236
|
-
const routing =
|
|
134275
|
+
const routing = setupRequired || activeCli ? null : lastPick?.reason ?? choice?.reason ?? null;
|
|
134237
134276
|
const ctxPct = !activeCli && model && lastInput > 0 ? Math.round(lastInput / model.contextWindow * 100) : null;
|
|
134238
134277
|
const push = (it) => setItems((prev) => [...prev, it]);
|
|
134239
134278
|
const pushPhase = (label, detail) => {
|
|
@@ -134304,8 +134343,6 @@ function App2({ selector: initialSelector, demo, runner, fullscreen = false, res
|
|
|
134304
134343
|
};
|
|
134305
134344
|
};
|
|
134306
134345
|
const defaultRunner = import_react26.useCallback(async ({ prompt, messages, onEvent, selector: sel, signal }) => {
|
|
134307
|
-
if (demo)
|
|
134308
|
-
return runTaskMock({ prompt, messages, onEvent, signal });
|
|
134309
134346
|
const cli = activeCliRef.current;
|
|
134310
134347
|
if (cli) {
|
|
134311
134348
|
routedRef.current = null;
|
|
@@ -134338,10 +134375,8 @@ function App2({ selector: initialSelector, demo, runner, fullscreen = false, res
|
|
|
134338
134375
|
const produced = r2.messages.slice(ctx.length);
|
|
134339
134376
|
const ledger = sanitizeToolPairs([...messages, { role: "user", content: prompt }, ...produced]);
|
|
134340
134377
|
return { messages: ledger, usage: r2.usage };
|
|
134341
|
-
}, [
|
|
134378
|
+
}, []);
|
|
134342
134379
|
const compactNow = import_react26.useCallback(async (keepRecent, signal) => {
|
|
134343
|
-
if (demo)
|
|
134344
|
-
return "compaction needs a model (no key in demo)";
|
|
134345
134380
|
let model2;
|
|
134346
134381
|
try {
|
|
134347
134382
|
model2 = selectorRef.current.select({ prompt: "", kind: "summarize" }).model;
|
|
@@ -134355,7 +134390,7 @@ function App2({ selector: initialSelector, demo, runner, fullscreen = false, res
|
|
|
134355
134390
|
const saved = res.before - res.after;
|
|
134356
134391
|
const savedStr = saved >= 1000 ? `${(saved / 1000).toFixed(1)}k` : String(Math.max(0, saved));
|
|
134357
134392
|
return `compacted ${res.summarizedTurns} earlier turn${res.summarizedTurns > 1 ? "s" : ""} · ~${savedStr} tokens freed`;
|
|
134358
|
-
}, [
|
|
134393
|
+
}, []);
|
|
134359
134394
|
const MODE_NOTE = {
|
|
134360
134395
|
normal: "normal mode — I'll ask before writes, edits, and shell",
|
|
134361
134396
|
"auto-accept": "auto-accept edits — file writes/edits apply without asking (shell still gated)",
|
|
@@ -134603,7 +134638,7 @@ function App2({ selector: initialSelector, demo, runner, fullscreen = false, res
|
|
|
134603
134638
|
recordUsage({ accountId: acctId, inputTokens: r2.usage.inputTokens, outputTokens: r2.usage.outputTokens, costUSD: cost, estimated: cm?.costUSD == null });
|
|
134604
134639
|
if (cm?.rates?.length)
|
|
134605
134640
|
recordRateLimits(acctId, cm.rates);
|
|
134606
|
-
if (!
|
|
134641
|
+
if (!ac.signal.aborted) {
|
|
134607
134642
|
try {
|
|
134608
134643
|
const cm2 = selectorRef.current.select({ prompt: "", kind: "summarize" }).model;
|
|
134609
134644
|
const budget = Math.max(8000, cm2.contextWindow - 32000);
|
|
@@ -134981,13 +135016,26 @@ function App2({ selector: initialSelector, demo, runner, fullscreen = false, res
|
|
|
134981
135016
|
}
|
|
134982
135017
|
})();
|
|
134983
135018
|
if (!m2) {
|
|
134984
|
-
notice(
|
|
135019
|
+
notice(`no model available — add a provider first
|
|
135020
|
+
|
|
135021
|
+
` + onboardingSummary(onboardingState));
|
|
134985
135022
|
return;
|
|
134986
135023
|
}
|
|
134987
135024
|
const { sections } = buildContext({ history: msgRef.current, userText: lastPromptRef.current || "(your next message)", model: m2, plan: modeRef.current === "plan" });
|
|
134988
135025
|
push({ kind: "context", id: idRef.current++, view: buildContextView(sections, m2.contextWindow, process.cwd()) });
|
|
134989
135026
|
return;
|
|
134990
135027
|
}
|
|
135028
|
+
case "onboard": {
|
|
135029
|
+
echo(text2);
|
|
135030
|
+
if (arg.trim().toLowerCase() === "providers") {
|
|
135031
|
+
const rows2 = featuredApiKeyProviders().map((p) => ` ${p.id.padEnd(18)} ${p.label.padEnd(24)} ${p.envVars[0] ?? ""}`.trimEnd());
|
|
135032
|
+
notice(["providers you can add with /account add <provider> <api-key>", ...rows2, "", "Aliases work for common names, e.g. gemini -> google, grok -> xai, kimi -> moonshot."].join(`
|
|
135033
|
+
`));
|
|
135034
|
+
} else {
|
|
135035
|
+
notice(onboardingSummary(onboardingState));
|
|
135036
|
+
}
|
|
135037
|
+
return;
|
|
135038
|
+
}
|
|
134991
135039
|
case "accounts":
|
|
134992
135040
|
case "account": {
|
|
134993
135041
|
echo(text2);
|
|
@@ -135255,10 +135303,6 @@ function App2({ selector: initialSelector, demo, runner, fullscreen = false, res
|
|
|
135255
135303
|
notice("busy — try /compact once the current turn finishes");
|
|
135256
135304
|
return;
|
|
135257
135305
|
}
|
|
135258
|
-
if (demo) {
|
|
135259
|
-
notice("compaction needs a model (no key in demo)");
|
|
135260
|
-
return;
|
|
135261
|
-
}
|
|
135262
135306
|
setBusy(true);
|
|
135263
135307
|
setVerb("Compacting context");
|
|
135264
135308
|
setMascotState("thinking");
|
|
@@ -135296,7 +135340,7 @@ function App2({ selector: initialSelector, demo, runner, fullscreen = false, res
|
|
|
135296
135340
|
notice(`/${name31} hit an error: ${(e2?.message ?? String(e2)).split(`
|
|
135297
135341
|
`)[0]}`);
|
|
135298
135342
|
}
|
|
135299
|
-
}, [exit, runTurn]);
|
|
135343
|
+
}, [exit, runTurn, onboardingState]);
|
|
135300
135344
|
const submit = import_react26.useCallback((value) => {
|
|
135301
135345
|
let text2 = value.trim();
|
|
135302
135346
|
if (pasteStoreRef.current.size) {
|
|
@@ -135350,6 +135394,13 @@ function App2({ selector: initialSelector, demo, runner, fullscreen = false, res
|
|
|
135350
135394
|
handleCommand(text2);
|
|
135351
135395
|
return;
|
|
135352
135396
|
}
|
|
135397
|
+
if (setupRequired) {
|
|
135398
|
+
echo(text2);
|
|
135399
|
+
notice(`set up a provider before sending a task
|
|
135400
|
+
|
|
135401
|
+
` + onboardingSummary(onboardingState));
|
|
135402
|
+
return;
|
|
135403
|
+
}
|
|
135353
135404
|
if (busyRef.current) {
|
|
135354
135405
|
queueRef.current.push(text2);
|
|
135355
135406
|
setQueued([...queueRef.current]);
|
|
@@ -135357,7 +135408,7 @@ function App2({ selector: initialSelector, demo, runner, fullscreen = false, res
|
|
|
135357
135408
|
return;
|
|
135358
135409
|
}
|
|
135359
135410
|
runTurn(text2);
|
|
135360
|
-
}, [handleCommand, runTurn]);
|
|
135411
|
+
}, [handleCommand, runTurn, setupRequired, onboardingState]);
|
|
135361
135412
|
import_react26.useEffect(() => {
|
|
135362
135413
|
if (busy || queueRef.current.length === 0)
|
|
135363
135414
|
return;
|
|
@@ -135681,78 +135732,169 @@ function App2({ selector: initialSelector, demo, runner, fullscreen = false, res
|
|
|
135681
135732
|
skin: ghostSkin,
|
|
135682
135733
|
size: splashSize
|
|
135683
135734
|
}, undefined, false, undefined, this),
|
|
135684
|
-
/* @__PURE__ */ jsx_dev_runtime12.jsxDEV(Box_default, {
|
|
135735
|
+
setupRequired ? /* @__PURE__ */ jsx_dev_runtime12.jsxDEV(Box_default, {
|
|
135685
135736
|
marginTop: 1,
|
|
135737
|
+
flexDirection: "column",
|
|
135738
|
+
alignItems: "center",
|
|
135686
135739
|
children: [
|
|
135687
135740
|
/* @__PURE__ */ jsx_dev_runtime12.jsxDEV(Text, {
|
|
135688
|
-
color: color.
|
|
135689
|
-
children: "
|
|
135741
|
+
color: color.text,
|
|
135742
|
+
children: "setup required"
|
|
135690
135743
|
}, undefined, false, undefined, this),
|
|
135744
|
+
onboardingState.importable.length || onboardingState.cloudImportable.length ? /* @__PURE__ */ jsx_dev_runtime12.jsxDEV(Text, {
|
|
135745
|
+
color: color.faint,
|
|
135746
|
+
children: [
|
|
135747
|
+
"detected credentials: ",
|
|
135748
|
+
/* @__PURE__ */ jsx_dev_runtime12.jsxDEV(Text, {
|
|
135749
|
+
color: color.accent,
|
|
135750
|
+
children: "/account import"
|
|
135751
|
+
}, undefined, false, undefined, this)
|
|
135752
|
+
]
|
|
135753
|
+
}, undefined, true, undefined, this) : null,
|
|
135691
135754
|
/* @__PURE__ */ jsx_dev_runtime12.jsxDEV(Text, {
|
|
135692
135755
|
color: color.faint,
|
|
135693
135756
|
children: [
|
|
135694
|
-
|
|
135695
|
-
|
|
135757
|
+
"add any provider key: ",
|
|
135758
|
+
/* @__PURE__ */ jsx_dev_runtime12.jsxDEV(Text, {
|
|
135759
|
+
color: color.accent,
|
|
135760
|
+
children: "/account add <provider> <api-key>"
|
|
135761
|
+
}, undefined, false, undefined, this)
|
|
135696
135762
|
]
|
|
135697
135763
|
}, undefined, true, undefined, this),
|
|
135698
|
-
/* @__PURE__ */ jsx_dev_runtime12.jsxDEV(Text, {
|
|
135699
|
-
color: color.accentDim,
|
|
135700
|
-
children: "/"
|
|
135701
|
-
}, undefined, false, undefined, this),
|
|
135702
|
-
/* @__PURE__ */ jsx_dev_runtime12.jsxDEV(Text, {
|
|
135703
|
-
color: color.dim,
|
|
135704
|
-
children: "commands "
|
|
135705
|
-
}, undefined, false, undefined, this),
|
|
135706
|
-
/* @__PURE__ */ jsx_dev_runtime12.jsxDEV(Text, {
|
|
135707
|
-
color: color.accentDim,
|
|
135708
|
-
children: "@"
|
|
135709
|
-
}, undefined, false, undefined, this),
|
|
135710
|
-
/* @__PURE__ */ jsx_dev_runtime12.jsxDEV(Text, {
|
|
135711
|
-
color: color.dim,
|
|
135712
|
-
children: "files "
|
|
135713
|
-
}, undefined, false, undefined, this),
|
|
135714
|
-
/* @__PURE__ */ jsx_dev_runtime12.jsxDEV(Text, {
|
|
135715
|
-
color: color.accentDim,
|
|
135716
|
-
children: "!"
|
|
135717
|
-
}, undefined, false, undefined, this),
|
|
135718
|
-
/* @__PURE__ */ jsx_dev_runtime12.jsxDEV(Text, {
|
|
135719
|
-
color: color.dim,
|
|
135720
|
-
children: "shell"
|
|
135721
|
-
}, undefined, false, undefined, this)
|
|
135722
|
-
]
|
|
135723
|
-
}, undefined, true, undefined, this),
|
|
135724
|
-
firstRunRef.current ? /* @__PURE__ */ jsx_dev_runtime12.jsxDEV(Box_default, {
|
|
135725
|
-
marginTop: 1,
|
|
135726
|
-
flexDirection: "column",
|
|
135727
|
-
alignItems: "center",
|
|
135728
|
-
children: [
|
|
135729
135764
|
/* @__PURE__ */ jsx_dev_runtime12.jsxDEV(Text, {
|
|
135730
135765
|
color: color.faint,
|
|
135731
135766
|
children: [
|
|
135732
|
-
"
|
|
135767
|
+
"paste-detect: ",
|
|
135733
135768
|
/* @__PURE__ */ jsx_dev_runtime12.jsxDEV(Text, {
|
|
135734
135769
|
color: color.accent,
|
|
135735
|
-
children: "
|
|
135770
|
+
children: "/account add <api-key>"
|
|
135736
135771
|
}, undefined, false, undefined, this),
|
|
135737
|
-
"
|
|
135772
|
+
" · list: ",
|
|
135738
135773
|
/* @__PURE__ */ jsx_dev_runtime12.jsxDEV(Text, {
|
|
135739
135774
|
color: color.accent,
|
|
135740
|
-
children: "
|
|
135775
|
+
children: "/onboard providers"
|
|
135776
|
+
}, undefined, false, undefined, this)
|
|
135777
|
+
]
|
|
135778
|
+
}, undefined, true, undefined, this),
|
|
135779
|
+
/* @__PURE__ */ jsx_dev_runtime12.jsxDEV(Box_default, {
|
|
135780
|
+
marginTop: 1,
|
|
135781
|
+
flexDirection: "column",
|
|
135782
|
+
alignItems: "flex-start",
|
|
135783
|
+
children: [
|
|
135784
|
+
featuredApiKeyProviders().slice(0, 6).map((p) => /* @__PURE__ */ jsx_dev_runtime12.jsxDEV(Text, {
|
|
135785
|
+
color: color.dim,
|
|
135786
|
+
children: [
|
|
135787
|
+
" ",
|
|
135788
|
+
/* @__PURE__ */ jsx_dev_runtime12.jsxDEV(Text, {
|
|
135789
|
+
color: color.accent,
|
|
135790
|
+
children: [
|
|
135791
|
+
"/account add ",
|
|
135792
|
+
p.id,
|
|
135793
|
+
" <api-key>"
|
|
135794
|
+
]
|
|
135795
|
+
}, undefined, true, undefined, this),
|
|
135796
|
+
" ",
|
|
135797
|
+
p.label
|
|
135798
|
+
]
|
|
135799
|
+
}, p.id, true, undefined, this)),
|
|
135800
|
+
/* @__PURE__ */ jsx_dev_runtime12.jsxDEV(Text, {
|
|
135801
|
+
color: color.dim,
|
|
135802
|
+
children: [
|
|
135803
|
+
" ",
|
|
135804
|
+
/* @__PURE__ */ jsx_dev_runtime12.jsxDEV(Text, {
|
|
135805
|
+
color: color.accent,
|
|
135806
|
+
children: "/account add azure <endpoint> <api-key>"
|
|
135807
|
+
}, undefined, false, undefined, this),
|
|
135808
|
+
" Azure OpenAI / Foundry"
|
|
135809
|
+
]
|
|
135810
|
+
}, undefined, true, undefined, this)
|
|
135811
|
+
]
|
|
135812
|
+
}, undefined, true, undefined, this),
|
|
135813
|
+
onboardingState.hasClaudeCli || onboardingState.hasCodexCli ? /* @__PURE__ */ jsx_dev_runtime12.jsxDEV(Text, {
|
|
135814
|
+
color: color.faint,
|
|
135815
|
+
children: [
|
|
135816
|
+
onboardingState.hasClaudeCli ? "/account add claude" : "",
|
|
135817
|
+
onboardingState.hasClaudeCli && onboardingState.hasCodexCli ? " · " : "",
|
|
135818
|
+
onboardingState.hasCodexCli ? "/account add codex" : ""
|
|
135819
|
+
]
|
|
135820
|
+
}, undefined, true, undefined, this) : null
|
|
135821
|
+
]
|
|
135822
|
+
}, undefined, true, undefined, this) : /* @__PURE__ */ jsx_dev_runtime12.jsxDEV(jsx_dev_runtime12.Fragment, {
|
|
135823
|
+
children: [
|
|
135824
|
+
/* @__PURE__ */ jsx_dev_runtime12.jsxDEV(Box_default, {
|
|
135825
|
+
marginTop: 1,
|
|
135826
|
+
children: [
|
|
135827
|
+
/* @__PURE__ */ jsx_dev_runtime12.jsxDEV(Text, {
|
|
135828
|
+
color: color.dim,
|
|
135829
|
+
children: "talk or type "
|
|
135741
135830
|
}, undefined, false, undefined, this),
|
|
135742
|
-
" cycles modes · ",
|
|
135743
135831
|
/* @__PURE__ */ jsx_dev_runtime12.jsxDEV(Text, {
|
|
135744
|
-
color: color.
|
|
135745
|
-
children:
|
|
135832
|
+
color: color.faint,
|
|
135833
|
+
children: [
|
|
135834
|
+
glyph.bullet,
|
|
135835
|
+
" "
|
|
135836
|
+
]
|
|
135837
|
+
}, undefined, true, undefined, this),
|
|
135838
|
+
/* @__PURE__ */ jsx_dev_runtime12.jsxDEV(Text, {
|
|
135839
|
+
color: color.accentDim,
|
|
135840
|
+
children: "/"
|
|
135841
|
+
}, undefined, false, undefined, this),
|
|
135842
|
+
/* @__PURE__ */ jsx_dev_runtime12.jsxDEV(Text, {
|
|
135843
|
+
color: color.dim,
|
|
135844
|
+
children: "commands "
|
|
135845
|
+
}, undefined, false, undefined, this),
|
|
135846
|
+
/* @__PURE__ */ jsx_dev_runtime12.jsxDEV(Text, {
|
|
135847
|
+
color: color.accentDim,
|
|
135848
|
+
children: "@"
|
|
135849
|
+
}, undefined, false, undefined, this),
|
|
135850
|
+
/* @__PURE__ */ jsx_dev_runtime12.jsxDEV(Text, {
|
|
135851
|
+
color: color.dim,
|
|
135852
|
+
children: "files "
|
|
135746
135853
|
}, undefined, false, undefined, this),
|
|
135747
|
-
|
|
135854
|
+
/* @__PURE__ */ jsx_dev_runtime12.jsxDEV(Text, {
|
|
135855
|
+
color: color.accentDim,
|
|
135856
|
+
children: "!"
|
|
135857
|
+
}, undefined, false, undefined, this),
|
|
135858
|
+
/* @__PURE__ */ jsx_dev_runtime12.jsxDEV(Text, {
|
|
135859
|
+
color: color.dim,
|
|
135860
|
+
children: "shell"
|
|
135861
|
+
}, undefined, false, undefined, this)
|
|
135748
135862
|
]
|
|
135749
135863
|
}, undefined, true, undefined, this),
|
|
135750
|
-
/* @__PURE__ */ jsx_dev_runtime12.jsxDEV(
|
|
135751
|
-
|
|
135752
|
-
|
|
135753
|
-
|
|
135864
|
+
firstRunRef.current ? /* @__PURE__ */ jsx_dev_runtime12.jsxDEV(Box_default, {
|
|
135865
|
+
marginTop: 1,
|
|
135866
|
+
flexDirection: "column",
|
|
135867
|
+
alignItems: "center",
|
|
135868
|
+
children: [
|
|
135869
|
+
/* @__PURE__ */ jsx_dev_runtime12.jsxDEV(Text, {
|
|
135870
|
+
color: color.faint,
|
|
135871
|
+
children: [
|
|
135872
|
+
"new here? press ",
|
|
135873
|
+
/* @__PURE__ */ jsx_dev_runtime12.jsxDEV(Text, {
|
|
135874
|
+
color: color.accent,
|
|
135875
|
+
children: "?"
|
|
135876
|
+
}, undefined, false, undefined, this),
|
|
135877
|
+
" for shortcuts · ",
|
|
135878
|
+
/* @__PURE__ */ jsx_dev_runtime12.jsxDEV(Text, {
|
|
135879
|
+
color: color.accent,
|
|
135880
|
+
children: "shift+tab"
|
|
135881
|
+
}, undefined, false, undefined, this),
|
|
135882
|
+
" cycles modes · ",
|
|
135883
|
+
/* @__PURE__ */ jsx_dev_runtime12.jsxDEV(Text, {
|
|
135884
|
+
color: color.accent,
|
|
135885
|
+
children: "⌃Y"
|
|
135886
|
+
}, undefined, false, undefined, this),
|
|
135887
|
+
" copies the last reply"
|
|
135888
|
+
]
|
|
135889
|
+
}, undefined, true, undefined, this),
|
|
135890
|
+
/* @__PURE__ */ jsx_dev_runtime12.jsxDEV(Text, {
|
|
135891
|
+
color: color.faint,
|
|
135892
|
+
children: "/config inline on for terminal scrollback · /keys for shortcuts"
|
|
135893
|
+
}, undefined, false, undefined, this)
|
|
135894
|
+
]
|
|
135895
|
+
}, undefined, true, undefined, this) : null
|
|
135754
135896
|
]
|
|
135755
|
-
}, undefined, true, undefined, this)
|
|
135897
|
+
}, undefined, true, undefined, this)
|
|
135756
135898
|
]
|
|
135757
135899
|
}, undefined, true, undefined, this);
|
|
135758
135900
|
const paletteJsx = pickerRows.length || cmdMatches.length || fileMatches.length ? /* @__PURE__ */ jsx_dev_runtime12.jsxDEV(Box_default, {
|
|
@@ -135780,7 +135922,7 @@ function App2({ selector: initialSelector, demo, runner, fullscreen = false, res
|
|
|
135780
135922
|
value: edit2.value,
|
|
135781
135923
|
cursor: edit2.cursor,
|
|
135782
135924
|
selectionAnchor: edit2.selectionAnchor,
|
|
135783
|
-
placeholder: mode2 === "plan" ? "describe what to plan…" : "ask anything",
|
|
135925
|
+
placeholder: setupRequired ? "add a provider with /account add <provider> <api-key>" : mode2 === "plan" ? "describe what to plan…" : "ask anything",
|
|
135784
135926
|
suggestion,
|
|
135785
135927
|
busy,
|
|
135786
135928
|
width,
|
|
@@ -135996,8 +136138,10 @@ Options:
|
|
|
135996
136138
|
-v, --version print version
|
|
135997
136139
|
-h, --help this help
|
|
135998
136140
|
|
|
135999
|
-
Set at least one provider
|
|
136000
|
-
|
|
136141
|
+
Set up at least one provider first:
|
|
136142
|
+
gearbox auth add <api-key>
|
|
136143
|
+
gearbox auth add <provider> <api-key>
|
|
136144
|
+
gearbox auth import
|
|
136001
136145
|
|
|
136002
136146
|
Models: ${MODELS.map((m2) => m2.label).join(", ")}
|
|
136003
136147
|
In-app: / for commands, @ for files, !cmd for shell, shift+tab for plan mode.`);
|
|
@@ -136056,7 +136200,6 @@ Importable from your env (gearbox auth import): ${imp.map((c) => c.envVar).join(
|
|
|
136056
136200
|
}
|
|
136057
136201
|
var mi = args.indexOf("--model");
|
|
136058
136202
|
var preferred = mi >= 0 ? args[mi + 1] : undefined;
|
|
136059
|
-
var demo = !anyProviderAvailable();
|
|
136060
136203
|
var pinned = preferred ?? loadPrefs().pinnedModel;
|
|
136061
136204
|
var selector = pinned ? new FixedSelector(pinned) : new RoutingSelector;
|
|
136062
136205
|
if (args.includes("--yolo"))
|
|
@@ -136090,7 +136233,6 @@ if (mouse)
|
|
|
136090
136233
|
process.stdout.write("\x1B[?1000h\x1B[?1002h\x1B[?1006h");
|
|
136091
136234
|
var app = render_default(/* @__PURE__ */ jsx_dev_runtime13.jsxDEV(App2, {
|
|
136092
136235
|
selector,
|
|
136093
|
-
demo,
|
|
136094
136236
|
fullscreen,
|
|
136095
136237
|
resumeId
|
|
136096
136238
|
}, undefined, false, undefined, this), { exitOnCtrlC: false });
|
package/package.json
CHANGED