gearbox-code 0.1.2 → 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.
Files changed (3) hide show
  1. package/README.md +5 -3
  2. package/dist/cli.mjs +549 -1209
  3. package/package.json +1 -1
package/dist/cli.mjs CHANGED
@@ -1,5 +1,4 @@
1
- #!/usr/bin/env bun
2
- // @bun
1
+ #!/usr/bin/env node
3
2
  import { createRequire } from "node:module";
4
3
  var __create = Object.create;
5
4
  var __getProtoOf = Object.getPrototypeOf;
@@ -61639,6 +61638,23 @@ var require_src5 = __commonJS((exports) => {
61639
61638
  });
61640
61639
 
61641
61640
  // src/accounts/store.ts
61641
+ var exports_store = {};
61642
+ __export(exports_store, {
61643
+ setSecret: () => setSecret,
61644
+ setDefaultAccount: () => setDefaultAccount,
61645
+ secretRefs: () => secretRefs,
61646
+ saveAccounts: () => saveAccounts,
61647
+ removeAccount: () => removeAccount,
61648
+ putAccount: () => putAccount,
61649
+ markUsed: () => markUsed,
61650
+ loadAccounts: () => loadAccounts,
61651
+ listAccounts: () => listAccounts,
61652
+ getSecret: () => getSecret,
61653
+ getAccount: () => getAccount,
61654
+ deleteSecret: () => deleteSecret,
61655
+ defaultAccount: () => defaultAccount,
61656
+ accountsForProvider: () => accountsForProvider
61657
+ });
61642
61658
  import { createCipheriv, createDecipheriv, randomBytes } from "node:crypto";
61643
61659
  import { readFileSync as readFileSync3, writeFileSync as writeFileSync2, mkdirSync as mkdirSync2, existsSync as existsSync2 } from "node:fs";
61644
61660
  import { join as join3 } from "node:path";
@@ -61819,6 +61835,12 @@ var SERVICE = "gearbox", home2 = () => process.env.GEARBOX_HOME || join3(homedir
61819
61835
  var init_store = () => {};
61820
61836
 
61821
61837
  // src/accounts/catalog.ts
61838
+ var exports_catalog = {};
61839
+ __export(exports_catalog, {
61840
+ detectProviderByKey: () => detectProviderByKey,
61841
+ catalogProvider: () => catalogProvider,
61842
+ CATALOG: () => CATALOG
61843
+ });
61822
61844
  function catalogProvider(id) {
61823
61845
  return BY_ID.get(id);
61824
61846
  }
@@ -64032,6 +64054,221 @@ var init_resolve = __esm(() => {
64032
64054
  init_catalog();
64033
64055
  });
64034
64056
 
64057
+ // src/accounts/detect.ts
64058
+ var exports_detect = {};
64059
+ __export(exports_detect, {
64060
+ importableEnvCreds: () => importableEnvCreds,
64061
+ importableCloudCreds: () => importableCloudCreds,
64062
+ importEnvCred: () => importEnvCred,
64063
+ importCloudCred: () => importCloudCred,
64064
+ detectEnvCreds: () => detectEnvCreds,
64065
+ detectCloudCreds: () => detectCloudCreds
64066
+ });
64067
+ import { readFileSync as readFileSync11, existsSync as existsSync6 } from "node:fs";
64068
+ import { join as join9 } from "node:path";
64069
+ import { homedir as homedir7 } from "node:os";
64070
+ function detectEnvCreds() {
64071
+ const out = [];
64072
+ for (const p of CATALOG) {
64073
+ if (p.authKind !== "api-key" && p.authKind !== "openai-compat")
64074
+ continue;
64075
+ for (const ev of p.envVars) {
64076
+ const v = process.env[ev];
64077
+ if (v) {
64078
+ out.push({ provider: p.id, label: p.label, envVar: ev, value: v });
64079
+ break;
64080
+ }
64081
+ }
64082
+ }
64083
+ return out;
64084
+ }
64085
+ async function importEnvCred(c) {
64086
+ const id = `${c.provider}-env`;
64087
+ const ref = `${id}:api-key`;
64088
+ await setSecret(ref, c.value);
64089
+ const cat = CATALOG.find((p) => p.id === c.provider);
64090
+ const account = {
64091
+ id,
64092
+ label: `${c.label} (from ${c.envVar})`,
64093
+ provider: c.provider,
64094
+ exec: "in-loop",
64095
+ auth: cat.authKind === "openai-compat" ? { kind: "openai-compat", ref } : { kind: "api-key", ref },
64096
+ baseUrl: cat.baseUrl,
64097
+ enabled: true,
64098
+ addedAt: Date.now()
64099
+ };
64100
+ putAccount(account);
64101
+ return account;
64102
+ }
64103
+ function importableEnvCreds() {
64104
+ return detectEnvCreds().filter((c) => !getAccount(`${c.provider}-env`));
64105
+ }
64106
+ function awsIni(file5, profile = "default") {
64107
+ if (!existsSync6(file5))
64108
+ return {};
64109
+ const out = {};
64110
+ let cur = "";
64111
+ for (const raw of readFileSync11(file5, "utf8").split(`
64112
+ `)) {
64113
+ const line = raw.trim();
64114
+ if (line.startsWith("["))
64115
+ cur = line.slice(1, -1).replace(/^profile\s+/, "");
64116
+ else if (cur === profile && line.includes("=")) {
64117
+ const i2 = line.indexOf("=");
64118
+ out[line.slice(0, i2).trim().toLowerCase()] = line.slice(i2 + 1).trim();
64119
+ }
64120
+ }
64121
+ return out;
64122
+ }
64123
+ function detectCloudCreds() {
64124
+ const out = [];
64125
+ const home5 = homedir7();
64126
+ const creds = awsIni(join9(home5, ".aws", "credentials"));
64127
+ const conf = awsIni(join9(home5, ".aws", "config"));
64128
+ const akid = process.env.AWS_ACCESS_KEY_ID ?? creds.aws_access_key_id;
64129
+ const secret = process.env.AWS_SECRET_ACCESS_KEY ?? creds.aws_secret_access_key;
64130
+ const region = process.env.AWS_REGION ?? process.env.AWS_DEFAULT_REGION ?? conf.region;
64131
+ if (akid && secret) {
64132
+ out.push({
64133
+ provider: "bedrock",
64134
+ label: "Amazon Bedrock",
64135
+ source: process.env.AWS_ACCESS_KEY_ID ? "env" : "~/.aws/credentials",
64136
+ aws: { accessKeyId: akid, secretAccessKey: secret, sessionToken: process.env.AWS_SESSION_TOKEN ?? creds.aws_session_token, region: region ?? "us-east-1" }
64137
+ });
64138
+ }
64139
+ if (process.env.AZURE_API_KEY && process.env.AZURE_RESOURCE_NAME) {
64140
+ out.push({ provider: "azure", label: "Azure OpenAI", source: "env", azure: { resourceName: process.env.AZURE_RESOURCE_NAME, apiKey: process.env.AZURE_API_KEY } });
64141
+ }
64142
+ if (process.env.GOOGLE_VERTEX_PROJECT) {
64143
+ out.push({ provider: "vertex", label: "Google Vertex AI", source: "env", vertex: { project: process.env.GOOGLE_VERTEX_PROJECT, location: process.env.GOOGLE_VERTEX_LOCATION ?? "us-central1" } });
64144
+ }
64145
+ return out;
64146
+ }
64147
+ async function importCloudCred(c) {
64148
+ const id = `${c.provider}-import`;
64149
+ let auth;
64150
+ if (c.aws) {
64151
+ await setSecret(`${id}:akid`, c.aws.accessKeyId);
64152
+ await setSecret(`${id}:secret`, c.aws.secretAccessKey);
64153
+ if (c.aws.sessionToken)
64154
+ await setSecret(`${id}:token`, c.aws.sessionToken);
64155
+ auth = { kind: "aws", accessKeyIdRef: `${id}:akid`, secretKeyRef: `${id}:secret`, sessionTokenRef: c.aws.sessionToken ? `${id}:token` : undefined, region: c.aws.region };
64156
+ } else if (c.azure) {
64157
+ await setSecret(`${id}:api-key`, c.azure.apiKey);
64158
+ auth = { kind: "azure", resourceName: c.azure.resourceName, ref: `${id}:api-key` };
64159
+ } else {
64160
+ auth = { kind: "vertex", project: c.vertex.project, location: c.vertex.location, adc: true };
64161
+ }
64162
+ const account = { id, label: `${c.label} (from ${c.source})`, provider: c.provider, exec: "in-loop", auth, enabled: true, addedAt: Date.now() };
64163
+ putAccount(account);
64164
+ return account;
64165
+ }
64166
+ function importableCloudCreds() {
64167
+ return detectCloudCreds().filter((c) => !getAccount(`${c.provider}-import`));
64168
+ }
64169
+ var init_detect = __esm(() => {
64170
+ init_catalog();
64171
+ init_store();
64172
+ });
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
+
64035
64272
  // src/agent/cli-backend.ts
64036
64273
  function newState() {
64037
64274
  return { text: "", usage: { inputTokens: 0, outputTokens: 0 }, rates: new Map, toolNames: new Map };
@@ -64267,354 +64504,33 @@ var init_cli_backend = __esm(() => {
64267
64504
  CONFIG_DIR_VAR = { claude: "CLAUDE_CONFIG_DIR", codex: "CODEX_HOME" };
64268
64505
  });
64269
64506
 
64270
- // node_modules/react/jsx-dev-runtime.js
64271
- var require_jsx_dev_runtime2 = __commonJS((exports, module) => {
64272
- var react_jsx_dev_runtime_development = __toESM(require_react_jsx_dev_runtime_development());
64273
- if (false) {} else {
64274
- module.exports = react_jsx_dev_runtime_development;
64275
- }
64276
- });
64277
-
64278
- // src/accounts/store.ts
64279
- var exports_store = {};
64280
- __export(exports_store, {
64281
- setSecret: () => setSecret2,
64282
- setDefaultAccount: () => setDefaultAccount2,
64283
- secretRefs: () => secretRefs2,
64284
- saveAccounts: () => saveAccounts2,
64285
- removeAccount: () => removeAccount2,
64286
- putAccount: () => putAccount2,
64287
- markUsed: () => markUsed2,
64288
- loadAccounts: () => loadAccounts3,
64289
- listAccounts: () => listAccounts2,
64290
- getSecret: () => getSecret2,
64291
- getAccount: () => getAccount2,
64292
- deleteSecret: () => deleteSecret2,
64293
- defaultAccount: () => defaultAccount2,
64294
- accountsForProvider: () => accountsForProvider2
64295
- });
64296
- import { createCipheriv as createCipheriv2, createDecipheriv as createDecipheriv2, randomBytes as randomBytes2 } from "node:crypto";
64297
- import { readFileSync as readFileSync15, writeFileSync as writeFileSync9, mkdirSync as mkdirSync10, existsSync as existsSync8 } from "node:fs";
64298
- import { join as join13 } from "node:path";
64299
- import { homedir as homedir11 } from "node:os";
64300
- async function setSecret2(ref, value) {
64301
- if (typeof Bun !== "undefined" && mode2() !== "file") {
64302
- try {
64303
- await Bun.secrets.set({ service: SERVICE2, name: ref, value });
64304
- return;
64305
- } catch (e2) {
64306
- if (mode2() === "keychain")
64307
- throw e2;
64308
- }
64309
- }
64310
- fileSet2(ref, value);
64311
- }
64312
- async function getSecret2(ref) {
64313
- if (typeof Bun !== "undefined" && mode2() !== "file") {
64314
- try {
64315
- const v = await Bun.secrets.get({ service: SERVICE2, name: ref });
64316
- if (v != null)
64317
- return v;
64318
- } catch {
64319
- if (mode2() === "keychain")
64320
- return null;
64321
- }
64322
- }
64323
- return fileGet2(ref);
64324
- }
64325
- async function deleteSecret2(ref) {
64326
- if (typeof Bun !== "undefined" && mode2() !== "file") {
64327
- try {
64328
- await Bun.secrets.delete({ service: SERVICE2, name: ref });
64329
- } catch {}
64330
- }
64331
- fileDelete2(ref);
64332
- }
64333
- function masterKey2() {
64334
- ensure3();
64335
- if (existsSync8(keyFile2()))
64336
- return Buffer.from(readFileSync15(keyFile2(), "utf8").trim(), "base64");
64337
- const k = randomBytes2(32);
64338
- writeFileSync9(keyFile2(), k.toString("base64"), { mode: 384 });
64339
- return k;
64340
- }
64341
- function encrypt2(plain) {
64342
- const iv = randomBytes2(12);
64343
- const c = createCipheriv2("aes-256-gcm", masterKey2(), iv);
64344
- const data = Buffer.concat([c.update(plain, "utf8"), c.final()]);
64345
- return [iv.toString("base64"), c.getAuthTag().toString("base64"), data.toString("base64")].join(".");
64346
- }
64347
- function decrypt2(blob) {
64348
- try {
64349
- const [iv, tag2, data] = blob.split(".").map((x2) => Buffer.from(x2, "base64"));
64350
- const d = createDecipheriv2("aes-256-gcm", masterKey2(), iv);
64351
- d.setAuthTag(tag2);
64352
- return Buffer.concat([d.update(data), d.final()]).toString("utf8");
64353
- } catch {
64354
- return null;
64355
- }
64356
- }
64357
- function readEnc2() {
64358
- try {
64359
- return JSON.parse(readFileSync15(encFile2(), "utf8"));
64360
- } catch {
64361
- return {};
64362
- }
64363
- }
64364
- function writeEnc2(m2) {
64365
- ensure3();
64366
- writeFileSync9(encFile2(), JSON.stringify(m2), { mode: 384 });
64367
- }
64368
- function fileSet2(ref, v) {
64369
- const m2 = readEnc2();
64370
- m2[ref] = encrypt2(v);
64371
- writeEnc2(m2);
64372
- }
64373
- function fileGet2(ref) {
64374
- const blob = readEnc2()[ref];
64375
- return blob ? decrypt2(blob) : null;
64376
- }
64377
- function fileDelete2(ref) {
64378
- const m2 = readEnc2();
64379
- delete m2[ref];
64380
- writeEnc2(m2);
64381
- }
64382
- function loadAccounts3() {
64383
- try {
64384
- const f3 = JSON.parse(readFileSync15(accountsFile2(), "utf8"));
64385
- if (f3 && Array.isArray(f3.accounts))
64386
- return { version: 1, defaults: {}, ...f3 };
64387
- } catch {}
64388
- return { version: 1, accounts: [], defaults: {} };
64389
- }
64390
- function saveAccounts2(f3) {
64391
- try {
64392
- ensure3();
64393
- writeFileSync9(accountsFile2(), JSON.stringify(f3, null, 2), { mode: 384 });
64394
- } catch {}
64395
- }
64396
- function listAccounts2() {
64397
- return loadAccounts3().accounts;
64398
- }
64399
- function accountsForProvider2(provider) {
64400
- return listAccounts2().filter((a) => a.provider === provider && a.enabled);
64401
- }
64402
- function getAccount2(id) {
64403
- return listAccounts2().find((a) => a.id === id);
64404
- }
64405
- function putAccount2(account) {
64406
- const f3 = loadAccounts3();
64407
- const i2 = f3.accounts.findIndex((a) => a.id === account.id);
64408
- if (i2 >= 0)
64409
- f3.accounts[i2] = account;
64410
- else
64411
- f3.accounts.push(account);
64412
- if (!f3.defaults[account.provider])
64413
- f3.defaults[account.provider] = account.id;
64414
- saveAccounts2(f3);
64415
- }
64416
- async function removeAccount2(id) {
64417
- const f3 = loadAccounts3();
64418
- const acc = f3.accounts.find((a) => a.id === id);
64419
- f3.accounts = f3.accounts.filter((a) => a.id !== id);
64420
- for (const [p, aid] of Object.entries(f3.defaults)) {
64421
- if (aid === id) {
64422
- const next = f3.accounts.find((a) => a.provider === p);
64423
- if (next)
64424
- f3.defaults[p] = next.id;
64425
- else
64426
- delete f3.defaults[p];
64427
- }
64428
- }
64429
- saveAccounts2(f3);
64430
- if (acc)
64431
- for (const ref of secretRefs2(acc))
64432
- await deleteSecret2(ref);
64433
- }
64434
- function setDefaultAccount2(provider, id) {
64435
- const f3 = loadAccounts3();
64436
- if (!f3.accounts.some((a) => a.id === id && a.provider === provider))
64437
- return;
64438
- f3.defaults[provider] = id;
64439
- saveAccounts2(f3);
64440
- }
64441
- function defaultAccount2(provider) {
64442
- const f3 = loadAccounts3();
64443
- const id = f3.defaults[provider];
64444
- const byDefault = id ? f3.accounts.find((a) => a.id === id && a.enabled) : undefined;
64445
- return byDefault ?? f3.accounts.find((a) => a.provider === provider && a.enabled);
64446
- }
64447
- function markUsed2(id) {
64448
- const f3 = loadAccounts3();
64449
- const a = f3.accounts.find((x2) => x2.id === id);
64450
- if (a) {
64451
- a.lastUsedAt = Date.now();
64452
- saveAccounts2(f3);
64453
- }
64454
- }
64455
- function secretRefs2(a) {
64456
- const refs = [];
64457
- const auth = a.auth;
64458
- if (auth.kind === "api-key" || auth.kind === "azure" || auth.kind === "openai-compat")
64459
- refs.push(auth.ref);
64460
- if (auth.kind === "aws") {
64461
- refs.push(auth.accessKeyIdRef, auth.secretKeyRef);
64462
- if (auth.sessionTokenRef)
64463
- refs.push(auth.sessionTokenRef);
64464
- }
64465
- if (auth.kind === "vertex" && auth.serviceAccountRef)
64466
- refs.push(auth.serviceAccountRef);
64467
- return refs;
64468
- }
64469
- var SERVICE2 = "gearbox", home5 = () => process.env.GEARBOX_HOME || join13(homedir11(), ".gearbox"), ensure3 = () => mkdirSync10(home5(), { recursive: true }), mode2 = () => {
64470
- const m2 = process.env.GEARBOX_SECRET_STORE;
64471
- return m2 === "file" || m2 === "keychain" ? m2 : "auto";
64472
- }, encFile2 = () => join13(home5(), "credentials.enc"), keyFile2 = () => join13(home5(), ".enckey"), accountsFile2 = () => join13(home5(), "accounts.json");
64473
- var init_store2 = () => {};
64474
-
64475
- // src/accounts/detect.ts
64476
- var exports_detect = {};
64477
- __export(exports_detect, {
64478
- importableEnvCreds: () => importableEnvCreds2,
64479
- importableCloudCreds: () => importableCloudCreds2,
64480
- importEnvCred: () => importEnvCred2,
64481
- importCloudCred: () => importCloudCred2,
64482
- detectEnvCreds: () => detectEnvCreds2,
64483
- detectCloudCreds: () => detectCloudCreds2
64484
- });
64485
- import { readFileSync as readFileSync16, existsSync as existsSync9 } from "node:fs";
64486
- import { join as join14 } from "node:path";
64487
- import { homedir as homedir12 } from "node:os";
64488
- function detectEnvCreds2() {
64489
- const out = [];
64490
- for (const p of CATALOG) {
64491
- if (p.authKind !== "api-key" && p.authKind !== "openai-compat")
64492
- continue;
64493
- for (const ev of p.envVars) {
64494
- const v = process.env[ev];
64495
- if (v) {
64496
- out.push({ provider: p.id, label: p.label, envVar: ev, value: v });
64497
- break;
64498
- }
64499
- }
64500
- }
64501
- return out;
64502
- }
64503
- async function importEnvCred2(c) {
64504
- const id = `${c.provider}-env`;
64505
- const ref = `${id}:api-key`;
64506
- await setSecret(ref, c.value);
64507
- const cat = CATALOG.find((p) => p.id === c.provider);
64508
- const account = {
64509
- id,
64510
- label: `${c.label} (from ${c.envVar})`,
64511
- provider: c.provider,
64512
- exec: "in-loop",
64513
- auth: cat.authKind === "openai-compat" ? { kind: "openai-compat", ref } : { kind: "api-key", ref },
64514
- baseUrl: cat.baseUrl,
64515
- enabled: true,
64516
- addedAt: Date.now()
64517
- };
64518
- putAccount(account);
64519
- return account;
64520
- }
64521
- function importableEnvCreds2() {
64522
- return detectEnvCreds2().filter((c) => !getAccount(`${c.provider}-env`));
64523
- }
64524
- function awsIni2(file6, profile = "default") {
64525
- if (!existsSync9(file6))
64526
- return {};
64527
- const out = {};
64528
- let cur = "";
64529
- for (const raw of readFileSync16(file6, "utf8").split(`
64530
- `)) {
64531
- const line = raw.trim();
64532
- if (line.startsWith("["))
64533
- cur = line.slice(1, -1).replace(/^profile\s+/, "");
64534
- else if (cur === profile && line.includes("=")) {
64535
- const i2 = line.indexOf("=");
64536
- out[line.slice(0, i2).trim().toLowerCase()] = line.slice(i2 + 1).trim();
64537
- }
64538
- }
64539
- return out;
64540
- }
64541
- function detectCloudCreds2() {
64542
- const out = [];
64543
- const home6 = homedir12();
64544
- const creds = awsIni2(join14(home6, ".aws", "credentials"));
64545
- const conf = awsIni2(join14(home6, ".aws", "config"));
64546
- const akid = process.env.AWS_ACCESS_KEY_ID ?? creds.aws_access_key_id;
64547
- const secret = process.env.AWS_SECRET_ACCESS_KEY ?? creds.aws_secret_access_key;
64548
- const region = process.env.AWS_REGION ?? process.env.AWS_DEFAULT_REGION ?? conf.region;
64549
- if (akid && secret) {
64550
- out.push({
64551
- provider: "bedrock",
64552
- label: "Amazon Bedrock",
64553
- source: process.env.AWS_ACCESS_KEY_ID ? "env" : "~/.aws/credentials",
64554
- aws: { accessKeyId: akid, secretAccessKey: secret, sessionToken: process.env.AWS_SESSION_TOKEN ?? creds.aws_session_token, region: region ?? "us-east-1" }
64555
- });
64556
- }
64557
- if (process.env.AZURE_API_KEY && process.env.AZURE_RESOURCE_NAME) {
64558
- out.push({ provider: "azure", label: "Azure OpenAI", source: "env", azure: { resourceName: process.env.AZURE_RESOURCE_NAME, apiKey: process.env.AZURE_API_KEY } });
64559
- }
64560
- if (process.env.GOOGLE_VERTEX_PROJECT) {
64561
- out.push({ provider: "vertex", label: "Google Vertex AI", source: "env", vertex: { project: process.env.GOOGLE_VERTEX_PROJECT, location: process.env.GOOGLE_VERTEX_LOCATION ?? "us-central1" } });
64562
- }
64563
- return out;
64564
- }
64565
- async function importCloudCred2(c) {
64566
- const id = `${c.provider}-import`;
64567
- let auth;
64568
- if (c.aws) {
64569
- await setSecret(`${id}:akid`, c.aws.accessKeyId);
64570
- await setSecret(`${id}:secret`, c.aws.secretAccessKey);
64571
- if (c.aws.sessionToken)
64572
- await setSecret(`${id}:token`, c.aws.sessionToken);
64573
- auth = { kind: "aws", accessKeyIdRef: `${id}:akid`, secretKeyRef: `${id}:secret`, sessionTokenRef: c.aws.sessionToken ? `${id}:token` : undefined, region: c.aws.region };
64574
- } else if (c.azure) {
64575
- await setSecret(`${id}:api-key`, c.azure.apiKey);
64576
- auth = { kind: "azure", resourceName: c.azure.resourceName, ref: `${id}:api-key` };
64577
- } else {
64578
- auth = { kind: "vertex", project: c.vertex.project, location: c.vertex.location, adc: true };
64579
- }
64580
- const account = { id, label: `${c.label} (from ${c.source})`, provider: c.provider, exec: "in-loop", auth, enabled: true, addedAt: Date.now() };
64581
- putAccount(account);
64582
- return account;
64583
- }
64584
- function importableCloudCreds2() {
64585
- return detectCloudCreds2().filter((c) => !getAccount(`${c.provider}-import`));
64586
- }
64587
- var init_detect = __esm(() => {
64588
- init_catalog();
64589
- init_store();
64590
- });
64591
-
64592
64507
  // src/accounts/onboard.ts
64593
64508
  var exports_onboard = {};
64594
64509
  __export(exports_onboard, {
64595
- testAccount: () => testAccount2,
64596
- cliLoginArgs: () => cliLoginArgs2,
64597
- cliAuthStatus: () => cliAuthStatus2,
64510
+ testAccount: () => testAccount,
64511
+ cliLoginArgs: () => cliLoginArgs,
64512
+ cliAuthStatus: () => cliAuthStatus,
64598
64513
  addableProviders: () => addableProviders,
64599
- addCliAccount: () => addCliAccount2,
64600
- addByPastedKey: () => addByPastedKey2,
64601
- addAzureFoundryAccount: () => addAzureFoundryAccount2,
64602
- addAzureAccount: () => addAzureAccount2,
64603
- addApiKeyAccount: () => addApiKeyAccount2
64604
- });
64605
- import { mkdirSync as mkdirSync11 } from "node:fs";
64606
- import { join as join15 } from "node:path";
64607
- import { homedir as homedir13 } from "node:os";
64608
- async function addApiKeyAccount2(provider, key, opts = {}) {
64514
+ addCliAccount: () => addCliAccount,
64515
+ addByPastedKey: () => addByPastedKey,
64516
+ addAzureFoundryAccount: () => addAzureFoundryAccount,
64517
+ addAzureAccount: () => addAzureAccount,
64518
+ addApiKeyAccount: () => addApiKeyAccount
64519
+ });
64520
+ import { mkdirSync as mkdirSync7 } from "node:fs";
64521
+ import { join as join10 } from "node:path";
64522
+ import { homedir as homedir8 } from "node:os";
64523
+ async function addApiKeyAccount(provider, key, opts = {}) {
64524
+ provider = normalizeProviderId(provider);
64609
64525
  const cat = catalogProvider(provider);
64610
64526
  if (!cat)
64611
- return { ok: false, message: `unknown provider "${provider}" — see /accounts catalog` };
64527
+ return { ok: false, message: `unknown provider "${provider}" — use /onboard providers` };
64612
64528
  if (cat.group === "cli")
64613
64529
  return { ok: false, message: `${cat.label} is a subscription account — use /login ${provider} (P3), not a key` };
64614
64530
  if (cat.authKind !== "api-key" && cat.authKind !== "openai-compat") {
64615
64531
  return { ok: false, message: `${cat.label} needs ${cat.authKind} credentials — use the guided add (P2)` };
64616
64532
  }
64617
- const id = opts.id ?? `${provider}-${shortId2()}`;
64533
+ const id = opts.id ?? `${provider}-${shortId()}`;
64618
64534
  const ref = `${id}:api-key`;
64619
64535
  await setSecret(ref, key.trim());
64620
64536
  const account = {
@@ -64630,7 +64546,7 @@ async function addApiKeyAccount2(provider, key, opts = {}) {
64630
64546
  putAccount(account);
64631
64547
  return { ok: true, account, message: `added ${account.label} (${id})` };
64632
64548
  }
64633
- function azureResourceName2(input) {
64549
+ function azureResourceName(input) {
64634
64550
  const s2 = input.trim();
64635
64551
  try {
64636
64552
  const host = new URL(s2).hostname;
@@ -64639,7 +64555,7 @@ function azureResourceName2(input) {
64639
64555
  return s2;
64640
64556
  }
64641
64557
  }
64642
- function azureFoundryBaseUrl2(endpoint) {
64558
+ function azureFoundryBaseUrl(endpoint) {
64643
64559
  const trimmed = endpoint.trim().replace(/\/+$/, "");
64644
64560
  if (/\/openai\/v1$/i.test(trimmed))
64645
64561
  return trimmed;
@@ -64647,32 +64563,32 @@ function azureFoundryBaseUrl2(endpoint) {
64647
64563
  return `${trimmed}/v1`;
64648
64564
  return `${trimmed}/openai/v1`;
64649
64565
  }
64650
- async function addAzureFoundryAccount2(endpoint, key, opts = {}) {
64566
+ async function addAzureFoundryAccount(endpoint, key, opts = {}) {
64651
64567
  if (!/^https?:\/\//i.test(endpoint) || !key.trim())
64652
64568
  return { ok: false, message: "usage: /account add azure <foundry-endpoint> <api-key>" };
64653
64569
  const host = new URL(endpoint).hostname;
64654
- const slug4 = host.split(".")[0]?.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "") || shortId2();
64655
- const id = opts.id ?? `azure-foundry-${slug4}`;
64570
+ const slug3 = host.split(".")[0]?.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "") || shortId();
64571
+ const id = opts.id ?? `azure-foundry-${slug3}`;
64656
64572
  const ref = `${id}:api-key`;
64657
64573
  await setSecret(ref, key.trim());
64658
64574
  const account = {
64659
64575
  id,
64660
- label: opts.label ?? `Azure Foundry (${slug4})`,
64576
+ label: opts.label ?? `Azure Foundry (${slug3})`,
64661
64577
  provider: "azure-foundry",
64662
64578
  exec: "in-loop",
64663
64579
  auth: { kind: "openai-compat", ref },
64664
- baseUrl: azureFoundryBaseUrl2(endpoint),
64580
+ baseUrl: azureFoundryBaseUrl(endpoint),
64665
64581
  enabled: true,
64666
64582
  addedAt: Date.now()
64667
64583
  };
64668
64584
  putAccount(account);
64669
64585
  return { ok: true, account, message: `added ${account.label} (${id})` };
64670
64586
  }
64671
- async function addAzureAccount2(resourceOrEndpoint, key, opts = {}) {
64672
- const resourceName = azureResourceName2(resourceOrEndpoint);
64587
+ async function addAzureAccount(resourceOrEndpoint, key, opts = {}) {
64588
+ const resourceName = azureResourceName(resourceOrEndpoint);
64673
64589
  if (!resourceName || !key.trim())
64674
64590
  return { ok: false, message: "usage: /account add azure <resource-or-endpoint> <api-key> [api-version]" };
64675
- const id = opts.id ?? `azure-${resourceName.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "") || shortId2()}`;
64591
+ const id = opts.id ?? `azure-${resourceName.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "") || shortId()}`;
64676
64592
  const ref = `${id}:api-key`;
64677
64593
  await setSecret(ref, key.trim());
64678
64594
  const account = {
@@ -64687,24 +64603,24 @@ async function addAzureAccount2(resourceOrEndpoint, key, opts = {}) {
64687
64603
  putAccount(account);
64688
64604
  return { ok: true, account, message: `added ${account.label} (${id})` };
64689
64605
  }
64690
- function cliProfileDir2(id) {
64691
- const home6 = process.env.GEARBOX_HOME || join15(homedir13(), ".gearbox");
64692
- return join15(home6, "cli", id);
64606
+ function cliProfileDir(id) {
64607
+ const home5 = process.env.GEARBOX_HOME || join10(homedir8(), ".gearbox");
64608
+ return join10(home5, "cli", id);
64693
64609
  }
64694
- function addCliAccount2(provider, name31) {
64610
+ function addCliAccount(provider, name31) {
64695
64611
  const cat = catalogProvider(provider);
64696
64612
  if (!cat || cat.group !== "cli" || !cat.binary)
64697
64613
  return { ok: false, message: `"${provider}" is not a CLI subscription provider` };
64698
64614
  if (!which(cat.binary))
64699
64615
  return { ok: false, message: `the ${cat.binary} binary isn't on your PATH — install it first` };
64700
- const slug4 = name31 ? name31.trim().toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "") : "";
64701
- const id = slug4 ? `${provider}-${slug4}` : provider;
64702
- const profile = slug4 ? cliProfileDir2(id) : undefined;
64616
+ const slug3 = name31 ? name31.trim().toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "") : "";
64617
+ const id = slug3 ? `${provider}-${slug3}` : provider;
64618
+ const profile = slug3 ? cliProfileDir(id) : undefined;
64703
64619
  if (profile)
64704
- mkdirSync11(profile, { recursive: true });
64620
+ mkdirSync7(profile, { recursive: true });
64705
64621
  const account = {
64706
64622
  id,
64707
- label: slug4 ? `${cat.label.replace(/ \(.*\)$/, "")} (${name31.trim()})` : cat.label,
64623
+ label: slug3 ? `${cat.label.replace(/ \(.*\)$/, "")} (${name31.trim()})` : cat.label,
64708
64624
  provider,
64709
64625
  exec: "cli",
64710
64626
  auth: { kind: "cli", binary: cat.binary, loginProfile: profile },
@@ -64715,7 +64631,7 @@ function addCliAccount2(provider, name31) {
64715
64631
  putAccount(account);
64716
64632
  return { ok: true, account, message: `${account.label} ready — runs via the ${cat.binary} CLI${profile ? " (separate login)" : ""}` };
64717
64633
  }
64718
- async function cliAuthStatus2(binary, profile) {
64634
+ async function cliAuthStatus(binary, profile) {
64719
64635
  const env3 = subscriptionEnv(binary, profile);
64720
64636
  const readBoth = async (cmd, timeoutMs = 5000) => {
64721
64637
  const p = spawnProc(cmd, { stdin: "ignore", stdout: "pipe", stderr: "pipe", env: env3 });
@@ -64768,16 +64684,16 @@ ${e2}`.trim(), timedOut };
64768
64684
  return { loggedIn: false };
64769
64685
  }
64770
64686
  }
64771
- function cliLoginArgs2(binary) {
64687
+ function cliLoginArgs(binary) {
64772
64688
  return binary === "codex" ? ["login"] : ["auth", "login"];
64773
64689
  }
64774
- async function addByPastedKey2(key) {
64690
+ async function addByPastedKey(key) {
64775
64691
  const provider = detectProviderByKey(key);
64776
64692
  if (!provider)
64777
64693
  return { ok: false, message: "couldn't identify the provider from that key — use /accounts add <provider> <key>" };
64778
- return addApiKeyAccount2(provider, key);
64694
+ return addApiKeyAccount(provider, key);
64779
64695
  }
64780
- async function testAccount2(a) {
64696
+ async function testAccount(a) {
64781
64697
  const creds = await resolveCreds(a);
64782
64698
  if (!creds.apiKey && a.auth.kind !== "cli")
64783
64699
  return { ok: false, message: "no key stored" };
@@ -64788,17 +64704,17 @@ async function testAccount2(a) {
64788
64704
  headers: { "x-api-key": creds.apiKey ?? "", "anthropic-version": "2023-06-01", "content-type": "application/json" },
64789
64705
  body: JSON.stringify({ model: "claude-haiku-4-5", messages: [{ role: "user", content: "hi" }] })
64790
64706
  });
64791
- return r3.ok ? { ok: true, message: "credential works" } : { ok: false, message: await errMessage2(r3) };
64707
+ return r3.ok ? { ok: true, message: "credential works" } : { ok: false, message: await errMessage(r3) };
64792
64708
  }
64793
64709
  if (a.provider === "google") {
64794
64710
  const r3 = await fetch(`https://generativelanguage.googleapis.com/v1beta/models?key=${creds.apiKey ?? ""}`);
64795
- return r3.ok ? { ok: true, message: "credential works" } : { ok: false, message: await errMessage2(r3) };
64711
+ return r3.ok ? { ok: true, message: "credential works" } : { ok: false, message: await errMessage(r3) };
64796
64712
  }
64797
64713
  const base2 = creds.baseURL ?? "https://api.openai.com/v1";
64798
64714
  const r2 = await fetch(`${base2.replace(/\/$/, "")}/models`, {
64799
64715
  headers: { Authorization: `Bearer ${creds.apiKey ?? ""}`, ...creds.headers ?? {} }
64800
64716
  });
64801
- return r2.ok ? { ok: true, message: "credential works" } : { ok: false, message: await errMessage2(r2) };
64717
+ return r2.ok ? { ok: true, message: "credential works" } : { ok: false, message: await errMessage(r2) };
64802
64718
  } catch (e2) {
64803
64719
  return { ok: false, message: e2?.message ?? "request failed" };
64804
64720
  }
@@ -64806,7 +64722,7 @@ async function testAccount2(a) {
64806
64722
  function addableProviders() {
64807
64723
  return CATALOG.filter((p) => p.authKind === "api-key" || p.authKind === "openai-compat").map((p) => ({ id: p.id, label: p.label, group: p.group }));
64808
64724
  }
64809
- async function errMessage2(r2) {
64725
+ async function errMessage(r2) {
64810
64726
  try {
64811
64727
  const j = await r2.json();
64812
64728
  const m2 = j?.error?.message ?? j?.message ?? j?.error;
@@ -64815,73 +64731,18 @@ async function errMessage2(r2) {
64815
64731
  } catch {}
64816
64732
  return `HTTP ${r2.status}`;
64817
64733
  }
64818
- function shortId2() {
64734
+ function shortId() {
64819
64735
  return Date.now().toString(36).slice(-4) + Math.floor(Math.random() * 1296).toString(36).padStart(2, "0");
64820
64736
  }
64821
64737
  var init_onboard = __esm(() => {
64822
64738
  init_store();
64823
64739
  init_catalog();
64740
+ init_onboarding();
64824
64741
  init_resolve();
64825
64742
  init_cli_backend();
64826
64743
  init_proc();
64827
64744
  });
64828
64745
 
64829
- // src/accounts/catalog.ts
64830
- var exports_catalog = {};
64831
- __export(exports_catalog, {
64832
- detectProviderByKey: () => detectProviderByKey2,
64833
- catalogProvider: () => catalogProvider2,
64834
- CATALOG: () => CATALOG2
64835
- });
64836
- function catalogProvider2(id) {
64837
- return BY_ID3.get(id);
64838
- }
64839
- function detectProviderByKey2(key) {
64840
- const k = key.trim();
64841
- const ranked = CATALOG2.flatMap((p) => (p.keyPrefix ?? []).map((pre) => ({ id: p.id, pre }))).sort((a, b) => b.pre.length - a.pre.length);
64842
- return ranked.find(({ pre }) => k.startsWith(pre))?.id;
64843
- }
64844
- var CATALOG2, BY_ID3;
64845
- var init_catalog2 = __esm(() => {
64846
- CATALOG2 = [
64847
- { id: "anthropic", label: "Anthropic", group: "native", exec: "in-loop", authKind: "api-key", envVars: ["ANTHROPIC_API_KEY"], keyPrefix: ["sk-ant-"], signupUrl: "https://console.anthropic.com/settings/keys", defaultModels: ["claude-sonnet-4-6", "claude-haiku-4-5", "claude-opus-4-8"] },
64848
- { id: "openai", label: "OpenAI", group: "native", exec: "in-loop", authKind: "api-key", envVars: ["OPENAI_API_KEY"], keyPrefix: ["sk-proj-", "sk-"], signupUrl: "https://platform.openai.com/api-keys", defaultModels: ["gpt-5.5", "gpt-5.5-pro", "gpt-5.5-mini"] },
64849
- { id: "google", label: "Google Gemini", group: "native", exec: "in-loop", authKind: "api-key", envVars: ["GOOGLE_GENERATIVE_AI_API_KEY", "GEMINI_API_KEY"], keyPrefix: ["AIza"], signupUrl: "https://aistudio.google.com/apikey", defaultModels: ["gemini-3.5-flash", "gemini-3.1-pro-preview", "gemini-3.1-flash-lite"] },
64850
- { id: "deepseek", label: "DeepSeek", group: "native", exec: "in-loop", authKind: "api-key", envVars: ["DEEPSEEK_API_KEY"], baseUrl: "https://api.deepseek.com/v1", signupUrl: "https://platform.deepseek.com/api_keys", defaultModels: ["deepseek-v4-pro", "deepseek-v4-flash"] },
64851
- { id: "xai", label: "xAI (Grok)", group: "openai-compat", exec: "in-loop", authKind: "openai-compat", envVars: ["XAI_API_KEY"], keyPrefix: ["xai-"], baseUrl: "https://api.x.ai/v1", signupUrl: "https://console.x.ai", defaultModels: ["grok-4.3", "grok-4.1-fast"] },
64852
- { id: "mistral", label: "Mistral", group: "openai-compat", exec: "in-loop", authKind: "openai-compat", envVars: ["MISTRAL_API_KEY"], baseUrl: "https://api.mistral.ai/v1", signupUrl: "https://console.mistral.ai/api-keys", defaultModels: ["mistral-large-latest", "codestral-latest"] },
64853
- { id: "groq", label: "Groq", group: "openai-compat", exec: "in-loop", authKind: "openai-compat", envVars: ["GROQ_API_KEY"], keyPrefix: ["gsk_"], baseUrl: "https://api.groq.com/openai/v1", signupUrl: "https://console.groq.com/keys", defaultModels: ["llama-3.3-70b-versatile", "moonshotai/kimi-k2-instruct"] },
64854
- { id: "together", label: "Together AI", group: "openai-compat", exec: "in-loop", authKind: "openai-compat", envVars: ["TOGETHER_API_KEY"], baseUrl: "https://api.together.xyz/v1", signupUrl: "https://api.together.ai/settings/api-keys", defaultModels: ["deepseek-ai/DeepSeek-V3", "Qwen/Qwen2.5-Coder-32B-Instruct"] },
64855
- { id: "fireworks", label: "Fireworks", group: "openai-compat", exec: "in-loop", authKind: "openai-compat", envVars: ["FIREWORKS_API_KEY"], keyPrefix: ["fw_"], baseUrl: "https://api.fireworks.ai/inference/v1", signupUrl: "https://fireworks.ai/account/api-keys", defaultModels: ["accounts/fireworks/models/deepseek-v3"] },
64856
- { id: "deepinfra", label: "DeepInfra", group: "openai-compat", exec: "in-loop", authKind: "openai-compat", envVars: ["DEEPINFRA_API_KEY"], baseUrl: "https://api.deepinfra.com/v1/openai", signupUrl: "https://deepinfra.com/dash/api_keys" },
64857
- { id: "cerebras", label: "Cerebras", group: "openai-compat", exec: "in-loop", authKind: "openai-compat", envVars: ["CEREBRAS_API_KEY"], keyPrefix: ["csk-"], baseUrl: "https://api.cerebras.ai/v1", signupUrl: "https://cloud.cerebras.ai", defaultModels: ["qwen-3-coder-480b", "llama-3.3-70b"] },
64858
- { id: "perplexity", label: "Perplexity", group: "openai-compat", exec: "in-loop", authKind: "openai-compat", envVars: ["PERPLEXITY_API_KEY"], keyPrefix: ["pplx-"], baseUrl: "https://api.perplexity.ai", signupUrl: "https://www.perplexity.ai/settings/api", defaultModels: ["sonar-pro", "sonar-reasoning-pro"] },
64859
- { id: "baseten", label: "Baseten", group: "openai-compat", exec: "in-loop", authKind: "openai-compat", envVars: ["BASETEN_API_KEY"], baseUrl: "https://inference.baseten.co/v1", signupUrl: "https://app.baseten.co/settings/api_keys" },
64860
- { id: "moonshot", label: "Moonshot (Kimi)", group: "openai-compat", exec: "in-loop", authKind: "openai-compat", envVars: ["MOONSHOT_API_KEY"], baseUrl: "https://api.moonshot.ai/v1", signupUrl: "https://platform.moonshot.ai/console/api-keys", defaultModels: ["kimi-k2-0905-preview"] },
64861
- { id: "zai", label: "Z.ai (GLM)", group: "openai-compat", exec: "in-loop", authKind: "openai-compat", envVars: ["ZAI_API_KEY", "ZHIPU_API_KEY"], baseUrl: "https://api.z.ai/api/paas/v4", signupUrl: "https://z.ai/manage-apikey/apikey-list", defaultModels: ["glm-4.6", "glm-4.5-air"] },
64862
- { id: "nebius", label: "Nebius AI Studio", group: "openai-compat", exec: "in-loop", authKind: "openai-compat", envVars: ["NEBIUS_API_KEY"], baseUrl: "https://api.studio.nebius.com/v1", signupUrl: "https://studio.nebius.com" },
64863
- { id: "hyperbolic", label: "Hyperbolic", group: "openai-compat", exec: "in-loop", authKind: "openai-compat", envVars: ["HYPERBOLIC_API_KEY"], baseUrl: "https://api.hyperbolic.xyz/v1", signupUrl: "https://app.hyperbolic.xyz/settings" },
64864
- { id: "sambanova", label: "SambaNova", group: "openai-compat", exec: "in-loop", authKind: "openai-compat", envVars: ["SAMBANOVA_API_KEY"], baseUrl: "https://api.sambanova.ai/v1", signupUrl: "https://cloud.sambanova.ai/apis" },
64865
- { id: "novita", label: "Novita", group: "openai-compat", exec: "in-loop", authKind: "openai-compat", envVars: ["NOVITA_API_KEY"], baseUrl: "https://api.novita.ai/v3/openai", signupUrl: "https://novita.ai/settings/key-management" },
64866
- { id: "openrouter", label: "OpenRouter", group: "gateway", exec: "in-loop", authKind: "openai-compat", envVars: ["OPENROUTER_API_KEY"], keyPrefix: ["sk-or-"], baseUrl: "https://openrouter.ai/api/v1", signupUrl: "https://openrouter.ai/keys", notes: "Hundreds of models via one key. extraHeaders HTTP-Referer/X-Title recommended." },
64867
- { id: "vercel-gateway", label: "Vercel AI Gateway", group: "gateway", exec: "in-loop", authKind: "openai-compat", envVars: ["AI_GATEWAY_API_KEY"], baseUrl: "https://ai-gateway.vercel.sh/v1", signupUrl: "https://vercel.com/docs/ai-gateway", notes: "Spend + credit telemetry; feeds the future ACCOUNT pillar." },
64868
- { id: "requesty", label: "Requesty", group: "gateway", exec: "in-loop", authKind: "openai-compat", envVars: ["REQUESTY_API_KEY"], baseUrl: "https://router.requesty.ai/v1", signupUrl: "https://app.requesty.ai" },
64869
- { id: "portkey", label: "Portkey", group: "gateway", exec: "in-loop", authKind: "openai-compat", envVars: ["PORTKEY_API_KEY"], baseUrl: "https://api.portkey.ai/v1", signupUrl: "https://app.portkey.ai", notes: "Config-driven routing via x-portkey-* headers." },
64870
- { id: "litellm", label: "LiteLLM proxy", group: "gateway", exec: "in-loop", authKind: "openai-compat", envVars: ["LITELLM_API_KEY"], signupUrl: "https://docs.litellm.ai/docs/simple_proxy", notes: "Self-hosted; set baseUrl to your proxy." },
64871
- { id: "azure-foundry", label: "Azure AI Foundry", group: "gateway", exec: "in-loop", authKind: "openai-compat", envVars: ["AZURE_AI_FOUNDRY_API_KEY", "AZURE_AI_INFERENCE_API_KEY"], signupUrl: "https://ai.azure.com", defaultModels: ["gpt-5.5", "gpt-5.5-mini", "gpt-4.1", "o4-mini"], notes: "OpenAI-compatible Foundry endpoint. Use baseUrl ending in /openai/v1." },
64872
- { id: "bedrock", label: "Amazon Bedrock", group: "cloud", exec: "in-loop", authKind: "aws", envVars: ["AWS_ACCESS_KEY_ID", "AWS_SECRET_ACCESS_KEY", "AWS_REGION", "AWS_PROFILE"], keyPrefix: ["AKIA", "ASIA"], signupUrl: "https://console.aws.amazon.com/bedrock", defaultModels: ["anthropic.claude-sonnet-4-20250514-v1:0"], notes: "Needs @ai-sdk/amazon-bedrock (P2)." },
64873
- { id: "vertex", label: "Google Vertex AI", group: "cloud", exec: "in-loop", authKind: "vertex", envVars: ["GOOGLE_VERTEX_PROJECT", "GOOGLE_VERTEX_LOCATION", "GOOGLE_APPLICATION_CREDENTIALS"], signupUrl: "https://console.cloud.google.com/vertex-ai", defaultModels: ["gemini-3.1-pro-preview"], notes: "ADC or a service-account JSON." },
64874
- { id: "azure", label: "Azure OpenAI", group: "cloud", exec: "in-loop", authKind: "azure", envVars: ["AZURE_API_KEY", "AZURE_RESOURCE_NAME"], signupUrl: "https://oai.azure.com", notes: "Needs @ai-sdk/azure (P2); resourceName + deployment." },
64875
- { id: "ollama", label: "Ollama (local)", group: "local", exec: "in-loop", authKind: "openai-compat", envVars: [], baseUrl: "http://localhost:11434/v1", signupUrl: "https://ollama.com", defaultModels: ["qwen2.5-coder:7b", "llama3.3"], notes: "No key; runs on your machine." },
64876
- { id: "lmstudio", label: "LM Studio (local)", group: "local", exec: "in-loop", authKind: "openai-compat", envVars: [], baseUrl: "http://localhost:1234/v1", signupUrl: "https://lmstudio.ai" },
64877
- { id: "vllm", label: "vLLM (local/self-host)", group: "local", exec: "in-loop", authKind: "openai-compat", envVars: [], baseUrl: "http://localhost:8000/v1", signupUrl: "https://docs.vllm.ai" },
64878
- { id: "llamacpp", label: "llama.cpp (local)", group: "local", exec: "in-loop", authKind: "openai-compat", envVars: [], baseUrl: "http://localhost:8080/v1", signupUrl: "https://github.com/ggml-org/llama.cpp" },
64879
- { id: "claude-cli", label: "Claude (Pro/Max via claude CLI)", group: "cli", exec: "cli", authKind: "cli", envVars: [], binary: "claude", signupUrl: "https://claude.com/product/claude-code", defaultModels: ["claude-opus-4-8", "claude-sonnet-4-6"], notes: "Wraps the official binary (like Conductor). Runs its own tools/permissions. ToS-clean: no token is read." },
64880
- { id: "codex-cli", label: "ChatGPT (Plus/Pro via codex CLI)", group: "cli", exec: "cli", authKind: "cli", envVars: [], binary: "codex", signupUrl: "https://developers.openai.com/codex/cli", defaultModels: ["gpt-5.5", "gpt-5.4", "gpt-5.4-mini"], notes: "Wraps the official binary. Runs its own tools/permissions. ToS-clean." }
64881
- ];
64882
- BY_ID3 = new Map(CATALOG2.map((p) => [p.id, p]));
64883
- });
64884
-
64885
64746
  // node_modules/ink/build/render.js
64886
64747
  import { Stream } from "node:stream";
64887
64748
  import process12 from "node:process";
@@ -70406,12 +70267,13 @@ var import_react20 = __toESM(require_react(), 1);
70406
70267
  // node_modules/ink/build/hooks/use-focus-manager.js
70407
70268
  var import_react21 = __toESM(require_react(), 1);
70408
70269
  // src/cli.tsx
70409
- import { execFileSync as execFileSync4 } from "child_process";
70410
- import { resolve as resolve11 } from "path";
70411
- import { existsSync as existsSync10 } from "fs";
70270
+ import { execFileSync as execFileSync4 } from "node:child_process";
70271
+ import { resolve as resolve11 } from "node:path";
70272
+ import { existsSync as existsSync8 } from "node:fs";
70412
70273
 
70413
70274
  // src/ui/App.tsx
70414
70275
  var import_react26 = __toESM(require_react(), 1);
70276
+
70415
70277
  // src/ui/theme.ts
70416
70278
  var color = {
70417
70279
  accent: "#7DD3FC",
@@ -118658,6 +118520,7 @@ var COMMANDS = [
118658
118520
  { name: "/context", usage: "/context", desc: "see what's loaded and how many tokens it uses", group: "chat" },
118659
118521
  { name: "/memory", usage: "/memory [note]", desc: "show or add facts to remember (or start a line with #)", group: "chat" },
118660
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" },
118661
118524
  { name: "/cost", usage: "/cost", desc: "see what you've spent per account", group: "accounts" },
118662
118525
  { name: "/copy", usage: "/copy", desc: "copy the last reply to the clipboard", group: "output" },
118663
118526
  { name: "/export", usage: "/export [file]", desc: "save the conversation to a file", group: "output" },
@@ -119403,6 +119266,9 @@ function detectImageMode() {
119403
119266
  return "blocks";
119404
119267
  }
119405
119268
  var resolved = null;
119269
+ function setImageMode(m2) {
119270
+ resolved = m2;
119271
+ }
119406
119272
  function getImageMode() {
119407
119273
  return resolved ?? detectImageMode();
119408
119274
  }
@@ -119413,6 +119279,30 @@ function idColor(id) {
119413
119279
  const bytes = [id >> 16 & 255, id >> 8 & 255, id & 255];
119414
119280
  return "#" + bytes.map((x2) => x2.toString(16).padStart(2, "0")).join("");
119415
119281
  }
119282
+ function transmitOne(id, b64, cols, rows) {
119283
+ const ESC2 = "\x1B";
119284
+ const CHUNK = 4096;
119285
+ if (b64.length <= CHUNK) {
119286
+ return `${ESC2}_Ga=T,U=1,i=${id},c=${cols},r=${rows},f=100,q=2;${b64}${ESC2}\\`;
119287
+ }
119288
+ let out = "";
119289
+ for (let i2 = 0;i2 < b64.length; i2 += CHUNK) {
119290
+ const chunk2 = b64.slice(i2, i2 + CHUNK);
119291
+ const more = i2 + CHUNK < b64.length ? 1 : 0;
119292
+ out += i2 === 0 ? `${ESC2}_Ga=T,U=1,i=${id},c=${cols},r=${rows},f=100,q=2,m=${more};${chunk2}${ESC2}\\` : `${ESC2}_Gm=${more};${chunk2}${ESC2}\\`;
119293
+ }
119294
+ return out;
119295
+ }
119296
+ function transmitAll() {
119297
+ let out = "";
119298
+ for (const variant of VARIANTS) {
119299
+ for (const size2 of SIZES) {
119300
+ const data = GHOSTS[variant][size2];
119301
+ out += transmitOne(imageId(variant, size2), GHOST_PNG[variant], data[0]?.length ?? 0, data.length);
119302
+ }
119303
+ }
119304
+ return out;
119305
+ }
119416
119306
  function placeholderRows(cols, rows) {
119417
119307
  const lines = [];
119418
119308
  for (let r2 = 0;r2 < rows; r2++) {
@@ -121297,6 +121187,9 @@ function listSessions() {
121297
121187
  return [];
121298
121188
  }
121299
121189
  }
121190
+ function latestSession() {
121191
+ return listSessions()[0] ?? null;
121192
+ }
121300
121193
  var histFile = () => join4(dir(), "history.json");
121301
121194
  function loadHistory() {
121302
121195
  try {
@@ -133323,335 +133216,10 @@ function friendlyToolPhase(name31) {
133323
133216
  // src/ui/App.tsx
133324
133217
  init_resolve();
133325
133218
  init_store();
133326
-
133327
- // src/accounts/detect.ts
133328
- init_catalog();
133329
- init_store();
133330
- import { readFileSync as readFileSync11, existsSync as existsSync6 } from "node:fs";
133331
- import { join as join9 } from "node:path";
133332
- import { homedir as homedir7 } from "node:os";
133333
- function detectEnvCreds() {
133334
- const out = [];
133335
- for (const p of CATALOG) {
133336
- if (p.authKind !== "api-key" && p.authKind !== "openai-compat")
133337
- continue;
133338
- for (const ev of p.envVars) {
133339
- const v = process.env[ev];
133340
- if (v) {
133341
- out.push({ provider: p.id, label: p.label, envVar: ev, value: v });
133342
- break;
133343
- }
133344
- }
133345
- }
133346
- return out;
133347
- }
133348
- async function importEnvCred(c) {
133349
- const id = `${c.provider}-env`;
133350
- const ref = `${id}:api-key`;
133351
- await setSecret(ref, c.value);
133352
- const cat = CATALOG.find((p) => p.id === c.provider);
133353
- const account = {
133354
- id,
133355
- label: `${c.label} (from ${c.envVar})`,
133356
- provider: c.provider,
133357
- exec: "in-loop",
133358
- auth: cat.authKind === "openai-compat" ? { kind: "openai-compat", ref } : { kind: "api-key", ref },
133359
- baseUrl: cat.baseUrl,
133360
- enabled: true,
133361
- addedAt: Date.now()
133362
- };
133363
- putAccount(account);
133364
- return account;
133365
- }
133366
- function importableEnvCreds() {
133367
- return detectEnvCreds().filter((c) => !getAccount(`${c.provider}-env`));
133368
- }
133369
- function awsIni(file5, profile = "default") {
133370
- if (!existsSync6(file5))
133371
- return {};
133372
- const out = {};
133373
- let cur = "";
133374
- for (const raw of readFileSync11(file5, "utf8").split(`
133375
- `)) {
133376
- const line = raw.trim();
133377
- if (line.startsWith("["))
133378
- cur = line.slice(1, -1).replace(/^profile\s+/, "");
133379
- else if (cur === profile && line.includes("=")) {
133380
- const i2 = line.indexOf("=");
133381
- out[line.slice(0, i2).trim().toLowerCase()] = line.slice(i2 + 1).trim();
133382
- }
133383
- }
133384
- return out;
133385
- }
133386
- function detectCloudCreds() {
133387
- const out = [];
133388
- const home5 = homedir7();
133389
- const creds = awsIni(join9(home5, ".aws", "credentials"));
133390
- const conf = awsIni(join9(home5, ".aws", "config"));
133391
- const akid = process.env.AWS_ACCESS_KEY_ID ?? creds.aws_access_key_id;
133392
- const secret = process.env.AWS_SECRET_ACCESS_KEY ?? creds.aws_secret_access_key;
133393
- const region = process.env.AWS_REGION ?? process.env.AWS_DEFAULT_REGION ?? conf.region;
133394
- if (akid && secret) {
133395
- out.push({
133396
- provider: "bedrock",
133397
- label: "Amazon Bedrock",
133398
- source: process.env.AWS_ACCESS_KEY_ID ? "env" : "~/.aws/credentials",
133399
- aws: { accessKeyId: akid, secretAccessKey: secret, sessionToken: process.env.AWS_SESSION_TOKEN ?? creds.aws_session_token, region: region ?? "us-east-1" }
133400
- });
133401
- }
133402
- if (process.env.AZURE_API_KEY && process.env.AZURE_RESOURCE_NAME) {
133403
- out.push({ provider: "azure", label: "Azure OpenAI", source: "env", azure: { resourceName: process.env.AZURE_RESOURCE_NAME, apiKey: process.env.AZURE_API_KEY } });
133404
- }
133405
- if (process.env.GOOGLE_VERTEX_PROJECT) {
133406
- out.push({ provider: "vertex", label: "Google Vertex AI", source: "env", vertex: { project: process.env.GOOGLE_VERTEX_PROJECT, location: process.env.GOOGLE_VERTEX_LOCATION ?? "us-central1" } });
133407
- }
133408
- return out;
133409
- }
133410
- async function importCloudCred(c) {
133411
- const id = `${c.provider}-import`;
133412
- let auth;
133413
- if (c.aws) {
133414
- await setSecret(`${id}:akid`, c.aws.accessKeyId);
133415
- await setSecret(`${id}:secret`, c.aws.secretAccessKey);
133416
- if (c.aws.sessionToken)
133417
- await setSecret(`${id}:token`, c.aws.sessionToken);
133418
- auth = { kind: "aws", accessKeyIdRef: `${id}:akid`, secretKeyRef: `${id}:secret`, sessionTokenRef: c.aws.sessionToken ? `${id}:token` : undefined, region: c.aws.region };
133419
- } else if (c.azure) {
133420
- await setSecret(`${id}:api-key`, c.azure.apiKey);
133421
- auth = { kind: "azure", resourceName: c.azure.resourceName, ref: `${id}:api-key` };
133422
- } else {
133423
- auth = { kind: "vertex", project: c.vertex.project, location: c.vertex.location, adc: true };
133424
- }
133425
- const account = { id, label: `${c.label} (from ${c.source})`, provider: c.provider, exec: "in-loop", auth, enabled: true, addedAt: Date.now() };
133426
- putAccount(account);
133427
- return account;
133428
- }
133429
- function importableCloudCreds() {
133430
- return detectCloudCreds().filter((c) => !getAccount(`${c.provider}-import`));
133431
- }
133432
-
133433
- // src/accounts/onboard.ts
133434
- init_store();
133435
- init_catalog();
133436
- init_resolve();
133437
- init_cli_backend();
133438
- init_proc();
133439
- import { mkdirSync as mkdirSync7 } from "node:fs";
133440
- import { join as join10 } from "node:path";
133441
- import { homedir as homedir8 } from "node:os";
133442
- async function addApiKeyAccount(provider, key, opts = {}) {
133443
- const cat = catalogProvider(provider);
133444
- if (!cat)
133445
- return { ok: false, message: `unknown provider "${provider}" — see /accounts catalog` };
133446
- if (cat.group === "cli")
133447
- return { ok: false, message: `${cat.label} is a subscription account — use /login ${provider} (P3), not a key` };
133448
- if (cat.authKind !== "api-key" && cat.authKind !== "openai-compat") {
133449
- return { ok: false, message: `${cat.label} needs ${cat.authKind} credentials — use the guided add (P2)` };
133450
- }
133451
- const id = opts.id ?? `${provider}-${shortId()}`;
133452
- const ref = `${id}:api-key`;
133453
- await setSecret(ref, key.trim());
133454
- const account = {
133455
- id,
133456
- label: opts.label ?? cat.label,
133457
- provider,
133458
- exec: "in-loop",
133459
- auth: cat.authKind === "openai-compat" ? { kind: "openai-compat", ref } : { kind: "api-key", ref },
133460
- baseUrl: cat.baseUrl,
133461
- enabled: true,
133462
- addedAt: Date.now()
133463
- };
133464
- putAccount(account);
133465
- return { ok: true, account, message: `added ${account.label} (${id})` };
133466
- }
133467
- function azureResourceName(input) {
133468
- const s2 = input.trim();
133469
- try {
133470
- const host = new URL(s2).hostname;
133471
- return host.split(".")[0] || s2;
133472
- } catch {
133473
- return s2;
133474
- }
133475
- }
133476
- function azureFoundryBaseUrl(endpoint) {
133477
- const trimmed = endpoint.trim().replace(/\/+$/, "");
133478
- if (/\/openai\/v1$/i.test(trimmed))
133479
- return trimmed;
133480
- if (/\/openai$/i.test(trimmed))
133481
- return `${trimmed}/v1`;
133482
- return `${trimmed}/openai/v1`;
133483
- }
133484
- async function addAzureFoundryAccount(endpoint, key, opts = {}) {
133485
- if (!/^https?:\/\//i.test(endpoint) || !key.trim())
133486
- return { ok: false, message: "usage: /account add azure <foundry-endpoint> <api-key>" };
133487
- const host = new URL(endpoint).hostname;
133488
- const slug3 = host.split(".")[0]?.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "") || shortId();
133489
- const id = opts.id ?? `azure-foundry-${slug3}`;
133490
- const ref = `${id}:api-key`;
133491
- await setSecret(ref, key.trim());
133492
- const account = {
133493
- id,
133494
- label: opts.label ?? `Azure Foundry (${slug3})`,
133495
- provider: "azure-foundry",
133496
- exec: "in-loop",
133497
- auth: { kind: "openai-compat", ref },
133498
- baseUrl: azureFoundryBaseUrl(endpoint),
133499
- enabled: true,
133500
- addedAt: Date.now()
133501
- };
133502
- putAccount(account);
133503
- return { ok: true, account, message: `added ${account.label} (${id})` };
133504
- }
133505
- async function addAzureAccount(resourceOrEndpoint, key, opts = {}) {
133506
- const resourceName = azureResourceName(resourceOrEndpoint);
133507
- if (!resourceName || !key.trim())
133508
- return { ok: false, message: "usage: /account add azure <resource-or-endpoint> <api-key> [api-version]" };
133509
- const id = opts.id ?? `azure-${resourceName.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "") || shortId()}`;
133510
- const ref = `${id}:api-key`;
133511
- await setSecret(ref, key.trim());
133512
- const account = {
133513
- id,
133514
- label: opts.label ?? `Azure (${resourceName})`,
133515
- provider: "azure",
133516
- exec: "in-loop",
133517
- auth: { kind: "azure", resourceName, ref, apiVersion: opts.apiVersion },
133518
- enabled: true,
133519
- addedAt: Date.now()
133520
- };
133521
- putAccount(account);
133522
- return { ok: true, account, message: `added ${account.label} (${id})` };
133523
- }
133524
- function cliProfileDir(id) {
133525
- const home5 = process.env.GEARBOX_HOME || join10(homedir8(), ".gearbox");
133526
- return join10(home5, "cli", id);
133527
- }
133528
- function addCliAccount(provider, name31) {
133529
- const cat = catalogProvider(provider);
133530
- if (!cat || cat.group !== "cli" || !cat.binary)
133531
- return { ok: false, message: `"${provider}" is not a CLI subscription provider` };
133532
- if (!which(cat.binary))
133533
- return { ok: false, message: `the ${cat.binary} binary isn't on your PATH — install it first` };
133534
- const slug3 = name31 ? name31.trim().toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "") : "";
133535
- const id = slug3 ? `${provider}-${slug3}` : provider;
133536
- const profile = slug3 ? cliProfileDir(id) : undefined;
133537
- if (profile)
133538
- mkdirSync7(profile, { recursive: true });
133539
- const account = {
133540
- id,
133541
- label: slug3 ? `${cat.label.replace(/ \(.*\)$/, "")} (${name31.trim()})` : cat.label,
133542
- provider,
133543
- exec: "cli",
133544
- auth: { kind: "cli", binary: cat.binary, loginProfile: profile },
133545
- models: cat.defaultModels,
133546
- enabled: true,
133547
- addedAt: Date.now()
133548
- };
133549
- putAccount(account);
133550
- return { ok: true, account, message: `${account.label} ready — runs via the ${cat.binary} CLI${profile ? " (separate login)" : ""}` };
133551
- }
133552
- async function cliAuthStatus(binary, profile) {
133553
- const env3 = subscriptionEnv(binary, profile);
133554
- const readBoth = async (cmd, timeoutMs = 5000) => {
133555
- const p = spawnProc(cmd, { stdin: "ignore", stdout: "pipe", stderr: "pipe", env: env3 });
133556
- let timedOut = false;
133557
- const timer = setTimeout(() => {
133558
- timedOut = true;
133559
- try {
133560
- p.kill();
133561
- } catch {}
133562
- }, timeoutMs);
133563
- try {
133564
- const [o, e2] = await Promise.all([readStream(p.stdout), readStream(p.stderr)]);
133565
- await p.exited.catch(() => {});
133566
- return { out: `${o}
133567
- ${e2}`.trim(), timedOut };
133568
- } finally {
133569
- clearTimeout(timer);
133570
- }
133571
- };
133572
- try {
133573
- if (binary === "codex") {
133574
- const { out: out2, timedOut: timedOut2 } = await readBoth(["codex", "login", "status"]);
133575
- if (timedOut2)
133576
- return { loggedIn: false, detail: "`codex login status` timed out" };
133577
- const loggedIn = /logged in|signed in|account:|email|using chatgpt/i.test(out2) && !/not logged in|not signed in/i.test(out2);
133578
- const email3 = out2.match(/[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}/i)?.[0]?.toLowerCase();
133579
- const detail = loggedIn ? out2.split(`
133580
- `).map((l) => l.trim()).find((l) => /@|plan|chatgpt/i.test(l))?.slice(0, 80) || "ChatGPT" : undefined;
133581
- return { loggedIn, detail, identity: email3 ? `codex:${email3}` : undefined, identityLabel: email3 };
133582
- }
133583
- const { out, timedOut } = await readBoth(["claude", "auth", "status"]);
133584
- if (timedOut)
133585
- return { loggedIn: false, detail: "`claude auth status` timed out" };
133586
- const m2 = out.match(/\{[^{}]*"loggedIn"[\s\S]*?\}/);
133587
- try {
133588
- const j = JSON.parse(m2 ? m2[0] : out);
133589
- const parts = [];
133590
- if (j.email)
133591
- parts.push(j.email);
133592
- if (j.subscriptionType)
133593
- parts.push(`Claude ${String(j.subscriptionType).replace(/^\w/, (c) => c.toUpperCase())}`);
133594
- else if (j.authMethod && j.authMethod !== "claude.ai")
133595
- parts.push(`auth: ${j.authMethod}`);
133596
- const email3 = typeof j.email === "string" ? j.email.toLowerCase() : undefined;
133597
- return { loggedIn: !!j.loggedIn, detail: parts.join(" · ") || undefined, identity: email3 ? `claude:${email3}` : undefined, identityLabel: email3 };
133598
- } catch {
133599
- return { loggedIn: /"loggedIn"\s*:\s*true/.test(out) };
133600
- }
133601
- } catch {
133602
- return { loggedIn: false };
133603
- }
133604
- }
133605
- function cliLoginArgs(binary) {
133606
- return binary === "codex" ? ["login"] : ["auth", "login"];
133607
- }
133608
- async function addByPastedKey(key) {
133609
- const provider = detectProviderByKey(key);
133610
- if (!provider)
133611
- return { ok: false, message: "couldn't identify the provider from that key — use /accounts add <provider> <key>" };
133612
- return addApiKeyAccount(provider, key);
133613
- }
133614
- async function testAccount(a) {
133615
- const creds = await resolveCreds(a);
133616
- if (!creds.apiKey && a.auth.kind !== "cli")
133617
- return { ok: false, message: "no key stored" };
133618
- try {
133619
- if (a.provider === "anthropic") {
133620
- const r3 = await fetch("https://api.anthropic.com/v1/messages/count_tokens", {
133621
- method: "POST",
133622
- headers: { "x-api-key": creds.apiKey ?? "", "anthropic-version": "2023-06-01", "content-type": "application/json" },
133623
- body: JSON.stringify({ model: "claude-haiku-4-5", messages: [{ role: "user", content: "hi" }] })
133624
- });
133625
- return r3.ok ? { ok: true, message: "credential works" } : { ok: false, message: await errMessage(r3) };
133626
- }
133627
- if (a.provider === "google") {
133628
- const r3 = await fetch(`https://generativelanguage.googleapis.com/v1beta/models?key=${creds.apiKey ?? ""}`);
133629
- return r3.ok ? { ok: true, message: "credential works" } : { ok: false, message: await errMessage(r3) };
133630
- }
133631
- const base2 = creds.baseURL ?? "https://api.openai.com/v1";
133632
- const r2 = await fetch(`${base2.replace(/\/$/, "")}/models`, {
133633
- headers: { Authorization: `Bearer ${creds.apiKey ?? ""}`, ...creds.headers ?? {} }
133634
- });
133635
- return r2.ok ? { ok: true, message: "credential works" } : { ok: false, message: await errMessage(r2) };
133636
- } catch (e2) {
133637
- return { ok: false, message: e2?.message ?? "request failed" };
133638
- }
133639
- }
133640
- async function errMessage(r2) {
133641
- try {
133642
- const j = await r2.json();
133643
- const m2 = j?.error?.message ?? j?.message ?? j?.error;
133644
- if (typeof m2 === "string" && m2)
133645
- return `${m2} (HTTP ${r2.status})`;
133646
- } catch {}
133647
- return `HTTP ${r2.status}`;
133648
- }
133649
- function shortId() {
133650
- return Date.now().toString(36).slice(-4) + Math.floor(Math.random() * 1296).toString(36).padStart(2, "0");
133651
- }
133652
-
133653
- // src/ui/App.tsx
133219
+ init_detect();
133220
+ init_onboard();
133654
133221
  init_catalog();
133222
+ init_onboarding();
133655
133223
  init_cli_backend();
133656
133224
 
133657
133225
  // src/accounts/balance.ts
@@ -133764,72 +133332,6 @@ ${summary}` },
133764
133332
  return { messages, summarizedTurns: old.length, before: before2, after: after2 };
133765
133333
  }
133766
133334
 
133767
- // src/agent/mock.ts
133768
- var sleep = (ms) => new Promise((r2) => setTimeout(r2, ms));
133769
- async function stream(text2, onEvent, chunk2 = 3, delay3 = 8) {
133770
- for (let i2 = 0;i2 < text2.length; i2 += chunk2) {
133771
- onEvent({ type: "text", text: text2.slice(i2, i2 + chunk2) });
133772
- await sleep(delay3);
133773
- }
133774
- }
133775
- async function streamWrite(id, path, content, onEvent, stop) {
133776
- onEvent({ type: "tool-start", id, name: "write_file", arg: "" });
133777
- onEvent({ type: "tool-stream", id, arg: path });
133778
- for (let i2 = 0;i2 < content.length; i2 += 8) {
133779
- if (stop())
133780
- return;
133781
- onEvent({ type: "tool-stream", id, delta: content.slice(i2, i2 + 8) });
133782
- await sleep(16);
133783
- }
133784
- const diff2 = content.replace(/\n$/, "").split(`
133785
- `).map((text2) => ({ sign: "+", text: text2 }));
133786
- onEvent({ type: "tool-end", id, ok: true, summary: `wrote ${path} (+${diff2.length} −0)`, diff: diff2 });
133787
- }
133788
- async function runTaskMock(opts) {
133789
- const { prompt, messages, onEvent, signal } = opts;
133790
- const stop = () => signal?.aborted === true;
133791
- await stream(`Sure — let me take a look around first.
133792
- `, onEvent);
133793
- if (stop())
133794
- return done(messages, onEvent);
133795
- onEvent({ type: "tool-start", id: "1", name: "list_dir", arg: "." });
133796
- await sleep(260);
133797
- if (stop())
133798
- return done(messages, onEvent);
133799
- onEvent({ type: "tool-end", id: "1", ok: true, summary: "src · package.json · README.md · 5 more" });
133800
- onEvent({ type: "tool-start", id: "2", name: "read_file", arg: "src/cli.tsx" });
133801
- await sleep(220);
133802
- if (stop())
133803
- return done(messages, onEvent);
133804
- onEvent({ type: "tool-end", id: "2", ok: true, summary: "renders the Ink app · 38 lines" });
133805
- await stream(`
133806
- Here's a quick file — watch it stream in:
133807
- `, onEvent);
133808
- if (stop())
133809
- return done(messages, onEvent);
133810
- const demoFile = `# hello.py — written live in demo mode
133811
-
133812
- def greet(name: str) -> str:
133813
- return f"Hello, {name}!"
133814
-
133815
- if __name__ == "__main__":
133816
- for who in ("world", "gearbox", "Boo"):
133817
- print(greet(who))
133818
- `;
133819
- await streamWrite("3", "hello.py", demoFile, onEvent, stop);
133820
- if (stop())
133821
- return done(messages, onEvent);
133822
- await stream(`
133823
- 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}".
133824
- `, onEvent);
133825
- return done(messages, onEvent);
133826
- }
133827
- function done(messages, onEvent) {
133828
- const usage = { inputTokens: 0, outputTokens: 0 };
133829
- onEvent({ type: "done", usage });
133830
- return { messages, usage };
133831
- }
133832
-
133833
133335
  // src/ui/clipboard.ts
133834
133336
  init_proc();
133835
133337
  function osc52(text2) {
@@ -134184,11 +133686,11 @@ function ActivityRail({ items, width }) {
134184
133686
  ]
134185
133687
  }, undefined, true, undefined, this);
134186
133688
  }
134187
- function App2({ selector: initialSelector, demo, runner, fullscreen = false, resumeId }) {
133689
+ function App2({ selector: initialSelector, runner, fullscreen = false, resumeId }) {
134188
133690
  const { exit } = use_app_default();
134189
133691
  const { stdin, isRawModeSupported, setRawMode } = use_stdin_default();
134190
133692
  const { columns, rows } = useTerminalSize();
134191
- const online = useOnline(20000, !demo);
133693
+ const online = useOnline(20000, true);
134192
133694
  const width = columns;
134193
133695
  const splashSize = rows >= 24 && columns >= 42 ? "big" : rows >= 13 && columns >= 22 ? "mini" : "none";
134194
133696
  const [items, setItems] = import_react26.useState([]);
@@ -134267,10 +133769,6 @@ function App2({ selector: initialSelector, demo, runner, fullscreen = false, res
134267
133769
  const t2 = setInterval(() => setElapsed(Math.floor((Date.now() - start) / 1000)), 500);
134268
133770
  return () => clearInterval(t2);
134269
133771
  }, [busy]);
134270
- import_react26.useEffect(() => {
134271
- if (firstRunRef.current)
134272
- updatePrefs({ onboarded: true });
134273
- }, []);
134274
133772
  import_react26.useEffect(() => {
134275
133773
  const proj = basename2(process.cwd());
134276
133774
  setTitle(busy ? `✳ ${proj} · working` : `${proj} · gearbox`);
@@ -134331,8 +133829,6 @@ function App2({ selector: initialSelector, demo, runner, fullscreen = false, res
134331
133829
  setTimeout(pumpPerm, 0);
134332
133830
  };
134333
133831
  import_react26.useEffect(() => {
134334
- if (demo)
134335
- return;
134336
133832
  const acctId = loadPrefs().activeAccount;
134337
133833
  if (!acctId)
134338
133834
  return;
@@ -134344,7 +133840,7 @@ function App2({ selector: initialSelector, demo, runner, fullscreen = false, res
134344
133840
  setActiveCliModelId(undefined);
134345
133841
  setActiveCli({ id: a.id, label: bin });
134346
133842
  }
134347
- }, [demo]);
133843
+ }, []);
134348
133844
  import_react26.useEffect(() => {
134349
133845
  setPermissionHandler((req) => new Promise((resolve11) => {
134350
133846
  if (modeRef.current === "auto-accept" && (req.kind === "write" || req.kind === "edit")) {
@@ -134586,8 +134082,6 @@ function App2({ selector: initialSelector, demo, runner, fullscreen = false, res
134586
134082
  };
134587
134083
  }, [stdin, fullscreen, rows, scrollBy, copyWithFeedback]);
134588
134084
  const persist = import_react26.useCallback(() => {
134589
- if (demo)
134590
- return;
134591
134085
  const s2 = sessionRef.current;
134592
134086
  if (!itemsRef.current.length)
134593
134087
  return;
@@ -134601,7 +134095,7 @@ function App2({ selector: initialSelector, demo, runner, fullscreen = false, res
134601
134095
  items: itemsRef.current,
134602
134096
  turns: s2.turns
134603
134097
  });
134604
- }, [demo]);
134098
+ }, []);
134605
134099
  const loadInto = (s2) => {
134606
134100
  idRef.current = s2.items.reduce((m2, i2) => Math.max(m2, i2.id), 0) + 1;
134607
134101
  setItems(s2.items);
@@ -134761,10 +134255,24 @@ function App2({ selector: initialSelector, demo, runner, fullscreen = false, res
134761
134255
  const [lastPick, setLastPick] = import_react26.useState(null);
134762
134256
  const [activeCli, setActiveCli] = import_react26.useState(null);
134763
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]);
134764
134272
  const model = lastPick?.model ?? choice?.model ?? null;
134765
- const modelLabel = demo ? "demo · no key" : activeCli ? `${activeCli.label}${activeCliModel ? ` · ${activeCliModel}` : ""}` : model?.label ?? "none";
134273
+ const modelLabel = setupRequired ? "setup required" : activeCli ? `${activeCli.label}${activeCliModel ? ` · ${activeCliModel}` : ""}` : model?.label ?? "none";
134766
134274
  const subscription = activeCli ? activeCli.label : null;
134767
- const routing = demo || activeCli ? null : lastPick?.reason ?? choice?.reason ?? null;
134275
+ const routing = setupRequired || activeCli ? null : lastPick?.reason ?? choice?.reason ?? null;
134768
134276
  const ctxPct = !activeCli && model && lastInput > 0 ? Math.round(lastInput / model.contextWindow * 100) : null;
134769
134277
  const push = (it) => setItems((prev) => [...prev, it]);
134770
134278
  const pushPhase = (label, detail) => {
@@ -134835,8 +134343,6 @@ function App2({ selector: initialSelector, demo, runner, fullscreen = false, res
134835
134343
  };
134836
134344
  };
134837
134345
  const defaultRunner = import_react26.useCallback(async ({ prompt, messages, onEvent, selector: sel, signal }) => {
134838
- if (demo)
134839
- return runTaskMock({ prompt, messages, onEvent, signal });
134840
134346
  const cli = activeCliRef.current;
134841
134347
  if (cli) {
134842
134348
  routedRef.current = null;
@@ -134869,10 +134375,8 @@ function App2({ selector: initialSelector, demo, runner, fullscreen = false, res
134869
134375
  const produced = r2.messages.slice(ctx.length);
134870
134376
  const ledger = sanitizeToolPairs([...messages, { role: "user", content: prompt }, ...produced]);
134871
134377
  return { messages: ledger, usage: r2.usage };
134872
- }, [demo]);
134378
+ }, []);
134873
134379
  const compactNow = import_react26.useCallback(async (keepRecent, signal) => {
134874
- if (demo)
134875
- return "compaction needs a model (no key in demo)";
134876
134380
  let model2;
134877
134381
  try {
134878
134382
  model2 = selectorRef.current.select({ prompt: "", kind: "summarize" }).model;
@@ -134886,7 +134390,7 @@ function App2({ selector: initialSelector, demo, runner, fullscreen = false, res
134886
134390
  const saved = res.before - res.after;
134887
134391
  const savedStr = saved >= 1000 ? `${(saved / 1000).toFixed(1)}k` : String(Math.max(0, saved));
134888
134392
  return `compacted ${res.summarizedTurns} earlier turn${res.summarizedTurns > 1 ? "s" : ""} · ~${savedStr} tokens freed`;
134889
- }, [demo]);
134393
+ }, []);
134890
134394
  const MODE_NOTE = {
134891
134395
  normal: "normal mode — I'll ask before writes, edits, and shell",
134892
134396
  "auto-accept": "auto-accept edits — file writes/edits apply without asking (shell still gated)",
@@ -135134,7 +134638,7 @@ function App2({ selector: initialSelector, demo, runner, fullscreen = false, res
135134
134638
  recordUsage({ accountId: acctId, inputTokens: r2.usage.inputTokens, outputTokens: r2.usage.outputTokens, costUSD: cost, estimated: cm?.costUSD == null });
135135
134639
  if (cm?.rates?.length)
135136
134640
  recordRateLimits(acctId, cm.rates);
135137
- if (!demo && !ac.signal.aborted) {
134641
+ if (!ac.signal.aborted) {
135138
134642
  try {
135139
134643
  const cm2 = selectorRef.current.select({ prompt: "", kind: "summarize" }).model;
135140
134644
  const budget = Math.max(8000, cm2.contextWindow - 32000);
@@ -135512,13 +135016,26 @@ function App2({ selector: initialSelector, demo, runner, fullscreen = false, res
135512
135016
  }
135513
135017
  })();
135514
135018
  if (!m2) {
135515
- notice("no model available — set a key to see the working set");
135019
+ notice(`no model available — add a provider first
135020
+
135021
+ ` + onboardingSummary(onboardingState));
135516
135022
  return;
135517
135023
  }
135518
135024
  const { sections } = buildContext({ history: msgRef.current, userText: lastPromptRef.current || "(your next message)", model: m2, plan: modeRef.current === "plan" });
135519
135025
  push({ kind: "context", id: idRef.current++, view: buildContextView(sections, m2.contextWindow, process.cwd()) });
135520
135026
  return;
135521
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
+ }
135522
135039
  case "accounts":
135523
135040
  case "account": {
135524
135041
  echo(text2);
@@ -135786,10 +135303,6 @@ function App2({ selector: initialSelector, demo, runner, fullscreen = false, res
135786
135303
  notice("busy — try /compact once the current turn finishes");
135787
135304
  return;
135788
135305
  }
135789
- if (demo) {
135790
- notice("compaction needs a model (no key in demo)");
135791
- return;
135792
- }
135793
135306
  setBusy(true);
135794
135307
  setVerb("Compacting context");
135795
135308
  setMascotState("thinking");
@@ -135827,7 +135340,7 @@ function App2({ selector: initialSelector, demo, runner, fullscreen = false, res
135827
135340
  notice(`/${name31} hit an error: ${(e2?.message ?? String(e2)).split(`
135828
135341
  `)[0]}`);
135829
135342
  }
135830
- }, [exit, runTurn]);
135343
+ }, [exit, runTurn, onboardingState]);
135831
135344
  const submit = import_react26.useCallback((value) => {
135832
135345
  let text2 = value.trim();
135833
135346
  if (pasteStoreRef.current.size) {
@@ -135881,6 +135394,13 @@ function App2({ selector: initialSelector, demo, runner, fullscreen = false, res
135881
135394
  handleCommand(text2);
135882
135395
  return;
135883
135396
  }
135397
+ if (setupRequired) {
135398
+ echo(text2);
135399
+ notice(`set up a provider before sending a task
135400
+
135401
+ ` + onboardingSummary(onboardingState));
135402
+ return;
135403
+ }
135884
135404
  if (busyRef.current) {
135885
135405
  queueRef.current.push(text2);
135886
135406
  setQueued([...queueRef.current]);
@@ -135888,7 +135408,7 @@ function App2({ selector: initialSelector, demo, runner, fullscreen = false, res
135888
135408
  return;
135889
135409
  }
135890
135410
  runTurn(text2);
135891
- }, [handleCommand, runTurn]);
135411
+ }, [handleCommand, runTurn, setupRequired, onboardingState]);
135892
135412
  import_react26.useEffect(() => {
135893
135413
  if (busy || queueRef.current.length === 0)
135894
135414
  return;
@@ -136212,78 +135732,169 @@ function App2({ selector: initialSelector, demo, runner, fullscreen = false, res
136212
135732
  skin: ghostSkin,
136213
135733
  size: splashSize
136214
135734
  }, undefined, false, undefined, this),
136215
- /* @__PURE__ */ jsx_dev_runtime12.jsxDEV(Box_default, {
135735
+ setupRequired ? /* @__PURE__ */ jsx_dev_runtime12.jsxDEV(Box_default, {
136216
135736
  marginTop: 1,
135737
+ flexDirection: "column",
135738
+ alignItems: "center",
136217
135739
  children: [
136218
135740
  /* @__PURE__ */ jsx_dev_runtime12.jsxDEV(Text, {
136219
- color: color.dim,
136220
- children: "talk or type "
135741
+ color: color.text,
135742
+ children: "setup required"
136221
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,
136222
135754
  /* @__PURE__ */ jsx_dev_runtime12.jsxDEV(Text, {
136223
135755
  color: color.faint,
136224
135756
  children: [
136225
- glyph.bullet,
136226
- " "
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)
136227
135762
  ]
136228
135763
  }, undefined, true, undefined, this),
136229
- /* @__PURE__ */ jsx_dev_runtime12.jsxDEV(Text, {
136230
- color: color.accentDim,
136231
- children: "/"
136232
- }, undefined, false, undefined, this),
136233
- /* @__PURE__ */ jsx_dev_runtime12.jsxDEV(Text, {
136234
- color: color.dim,
136235
- children: "commands "
136236
- }, undefined, false, undefined, this),
136237
- /* @__PURE__ */ jsx_dev_runtime12.jsxDEV(Text, {
136238
- color: color.accentDim,
136239
- children: "@"
136240
- }, undefined, false, undefined, this),
136241
- /* @__PURE__ */ jsx_dev_runtime12.jsxDEV(Text, {
136242
- color: color.dim,
136243
- children: "files "
136244
- }, undefined, false, undefined, this),
136245
- /* @__PURE__ */ jsx_dev_runtime12.jsxDEV(Text, {
136246
- color: color.accentDim,
136247
- children: "!"
136248
- }, undefined, false, undefined, this),
136249
- /* @__PURE__ */ jsx_dev_runtime12.jsxDEV(Text, {
136250
- color: color.dim,
136251
- children: "shell"
136252
- }, undefined, false, undefined, this)
136253
- ]
136254
- }, undefined, true, undefined, this),
136255
- firstRunRef.current ? /* @__PURE__ */ jsx_dev_runtime12.jsxDEV(Box_default, {
136256
- marginTop: 1,
136257
- flexDirection: "column",
136258
- alignItems: "center",
136259
- children: [
136260
135764
  /* @__PURE__ */ jsx_dev_runtime12.jsxDEV(Text, {
136261
135765
  color: color.faint,
136262
135766
  children: [
136263
- "new here? press ",
135767
+ "paste-detect: ",
136264
135768
  /* @__PURE__ */ jsx_dev_runtime12.jsxDEV(Text, {
136265
135769
  color: color.accent,
136266
- children: "?"
135770
+ children: "/account add <api-key>"
136267
135771
  }, undefined, false, undefined, this),
136268
- " for shortcuts · ",
135772
+ " · list: ",
136269
135773
  /* @__PURE__ */ jsx_dev_runtime12.jsxDEV(Text, {
136270
135774
  color: color.accent,
136271
- children: "shift+tab"
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 "
136272
135830
  }, undefined, false, undefined, this),
136273
- " cycles modes · ",
136274
135831
  /* @__PURE__ */ jsx_dev_runtime12.jsxDEV(Text, {
136275
- color: color.accent,
136276
- children: "⌃Y"
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: "/"
136277
135841
  }, undefined, false, undefined, this),
136278
- " copies the last reply"
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 "
135853
+ }, undefined, false, undefined, this),
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)
136279
135862
  ]
136280
135863
  }, undefined, true, undefined, this),
136281
- /* @__PURE__ */ jsx_dev_runtime12.jsxDEV(Text, {
136282
- color: color.faint,
136283
- children: demo ? "set ANTHROPIC_API_KEY (or another provider) to start — running in demo mode" : "/config inline on for terminal scrollback · /keys for shortcuts"
136284
- }, undefined, false, undefined, this)
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
136285
135896
  ]
136286
- }, undefined, true, undefined, this) : null
135897
+ }, undefined, true, undefined, this)
136287
135898
  ]
136288
135899
  }, undefined, true, undefined, this);
136289
135900
  const paletteJsx = pickerRows.length || cmdMatches.length || fileMatches.length ? /* @__PURE__ */ jsx_dev_runtime12.jsxDEV(Box_default, {
@@ -136311,7 +135922,7 @@ function App2({ selector: initialSelector, demo, runner, fullscreen = false, res
136311
135922
  value: edit2.value,
136312
135923
  cursor: edit2.cursor,
136313
135924
  selectionAnchor: edit2.selectionAnchor,
136314
- 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",
136315
135926
  suggestion,
136316
135927
  busy,
136317
135928
  width,
@@ -136484,304 +136095,33 @@ function App2({ selector: initialSelector, demo, runner, fullscreen = false, res
136484
136095
  }, undefined, true, undefined, this);
136485
136096
  }
136486
136097
 
136487
- // src/model/selector.ts
136488
- class FixedSelector2 {
136489
- preferredId;
136490
- constructor(preferredId) {
136491
- this.preferredId = preferredId;
136492
- }
136493
- select(_task) {
136494
- const model = pickDefaultModel(this.preferredId);
136495
- if (!model) {
136496
- throw new Error("No model available. Set a key: ANTHROPIC_API_KEY / OPENAI_API_KEY / GOOGLE_GENERATIVE_AI_API_KEY / DEEPSEEK_API_KEY");
136497
- }
136498
- return { model, reason: "fixed default · routing not enabled yet" };
136499
- }
136500
- }
136501
-
136502
- // src/model/router.ts
136503
- var BAR2 = {
136504
- summarize: 0,
136505
- classify: 0,
136506
- search: 0.2,
136507
- chat: 0.3,
136508
- plan: 0.7,
136509
- code: 0.7
136510
- };
136511
- var MUTATION2 = /\b(fix|implement|refactor|edit|modif|debug|rewrite|replace|add|create|delete|remove|patch|migrat|rename)\b/;
136512
- function classify2(prompt) {
136513
- const p = prompt.toLowerCase().trim();
136514
- if (!p)
136515
- return "code";
136516
- if (MUTATION2.test(p))
136517
- return "code";
136518
- if (/\b(summari[sz]e|tl;?dr|recap|condense|digest|gist)\b/.test(p))
136519
- return "summarize";
136520
- if (/\bclassif|\bcategori[sz]|\blabel this\b|\bsentiment\b/.test(p))
136521
- return "classify";
136522
- if (/^(find|search|locate|grep)\b|\bwhere is\b|\bwhich file\b/.test(p))
136523
- return "search";
136524
- return "code";
136525
- }
136526
- function qualityOf2(m2) {
136527
- const pr = profileFor(m2.id);
136528
- if (!pr)
136529
- return 0.5;
136530
- if (pr.quality.sweBenchVerified != null)
136531
- return pr.quality.sweBenchVerified;
136532
- if (pr.quality.intelligenceIndex != null)
136533
- return pr.quality.intelligenceIndex / 100;
136534
- return 0.5;
136535
- }
136536
- function costOf2(m2) {
136537
- const pr = profileFor(m2.id);
136538
- if (!pr)
136539
- return Number.POSITIVE_INFINITY;
136540
- return pr.cost.inUSDPerMtok + 0.2 * pr.cost.outUSDPerMtok;
136541
- }
136542
- function tpsOf2(m2) {
136543
- return profileFor(m2.id)?.latency?.tps ?? 0;
136544
- }
136545
-
136546
- class RoutingSelector2 {
136547
- fallbackId;
136548
- constructor(fallbackId) {
136549
- this.fallbackId = fallbackId;
136550
- }
136551
- select(task) {
136552
- const kind = task.kind ?? classify2(task.prompt);
136553
- const bar = BAR2[kind];
136554
- const available = MODELS.filter((m2) => providerAvailable(m2.provider) && profileFor(m2.id));
136555
- if (available.length === 0) {
136556
- const m2 = pickDefaultModel(this.fallbackId);
136557
- if (!m2) {
136558
- throw new Error("No model available. Set a key: ANTHROPIC_API_KEY / OPENAI_API_KEY / GOOGLE_GENERATIVE_AI_API_KEY / DEEPSEEK_API_KEY");
136559
- }
136560
- return { model: m2, reason: "only model with a key" };
136561
- }
136562
- const need = (task.estTokens ?? 0) * 1.2;
136563
- const fits = need > 0 ? available.filter((m2) => m2.contextWindow >= need) : available;
136564
- const pool = fits.length ? fits : available;
136565
- const clears = pool.filter((m2) => qualityOf2(m2) >= bar);
136566
- const candidates = clears.length ? clears : pool;
136567
- const pref = preferenceFor(kind);
136568
- const preferredPool = pref?.modelId ? pool.find((m2) => m2.id === pref.modelId) : pref?.provider ? pool.find((m2) => m2.provider === pref.provider) : undefined;
136569
- const preferred = pref?.modelId ? candidates.find((m2) => m2.id === pref.modelId) : pref?.provider ? candidates.find((m2) => m2.provider === pref.provider) : undefined;
136570
- if (preferred && qualityOf2(preferred) >= bar) {
136571
- return { model: preferred, reason: `${kind} · remembered preference` };
136572
- }
136573
- candidates.sort((a, b) => costOf2(a) - costOf2(b) || tpsOf2(b) - tpsOf2(a) || qualityOf2(b) - qualityOf2(a));
136574
- const model = candidates[0];
136575
- const skipped = preferredPool && qualityOf2(preferredPool) < bar ? ` · ${preferredPool.label} skipped below quality bar` : "";
136576
- const reason = `${kind} · $${costOf2(model).toFixed(2)}/Mtok${skipped}`;
136577
- return { model, reason };
136578
- }
136579
- }
136580
-
136581
- // src/config.ts
136582
- var config3 = {
136583
- defaultModelId: process.env.GEARBOX_MODEL ?? "claude-sonnet-4-6",
136584
- maxSteps: Number(process.env.GEARBOX_MAX_STEPS ?? 24)
136585
- };
136586
- function anyProviderAvailable() {
136587
- return MODELS.some((m2) => providerAvailable(m2.provider));
136588
- }
136589
-
136590
- // src/providers.ts
136591
- init_store();
136592
- init_catalog();
136593
- var NATIVE2 = new Set(["anthropic", "openai", "google", "deepseek"]);
136594
- var CURATED2 = [
136595
- { id: "claude-opus-4-8", provider: "anthropic", sdkId: "claude-opus-4-8", label: "opus-4.8", contextWindow: 1e6, cost: { inUSDPerMtok: 5, outUSDPerMtok: 25 }, reasoning: true, efforts: ["low", "medium", "high", "xhigh", "max"] },
136596
- { id: "claude-sonnet-4-6", provider: "anthropic", sdkId: "claude-sonnet-4-6", label: "sonnet-4.6", contextWindow: 1e6, cost: { inUSDPerMtok: 3, outUSDPerMtok: 15 }, reasoning: true, efforts: ["low", "medium", "high", "xhigh", "max"] },
136597
- { id: "claude-haiku-4-5", provider: "anthropic", sdkId: "claude-haiku-4-5", label: "haiku-4.5", contextWindow: 200000, cost: { inUSDPerMtok: 1, outUSDPerMtok: 5 } },
136598
- { id: "gpt-5.5", provider: "openai", sdkId: "gpt-5.5", label: "gpt-5.5", contextWindow: 400000, cost: { inUSDPerMtok: 2.5, outUSDPerMtok: 10 }, reasoning: true, efforts: ["none", "minimal", "low", "medium", "high", "xhigh"] },
136599
- { id: "gpt-5.5-pro", provider: "openai", sdkId: "gpt-5.5-pro", label: "gpt-5.5-pro", contextWindow: 400000, cost: { inUSDPerMtok: 15, outUSDPerMtok: 120 }, reasoning: true, efforts: ["none", "minimal", "low", "medium", "high", "xhigh"] },
136600
- { id: "gemini-3.1-pro-preview", provider: "google", sdkId: "gemini-3.1-pro-preview", label: "gemini-3.1-pro", contextWindow: 1e6, cost: { inUSDPerMtok: 2, outUSDPerMtok: 12 }, reasoning: true, efforts: ["minimal", "low", "medium", "high"] },
136601
- { id: "gemini-3.5-flash", provider: "google", sdkId: "gemini-3.5-flash", label: "gemini-3.5-flash", contextWindow: 1e6, cost: { inUSDPerMtok: 0.3, outUSDPerMtok: 2.5 }, reasoning: true, efforts: ["minimal", "low", "medium", "high"] },
136602
- { id: "deepseek-v4-pro", provider: "deepseek", sdkId: "deepseek-v4-pro", label: "deepseek-v4-pro", contextWindow: 128000, cost: { inUSDPerMtok: 0.4, outUSDPerMtok: 1.75 }, reasoning: true },
136603
- { id: "deepseek-v4-flash", provider: "deepseek", sdkId: "deepseek-v4-flash", label: "deepseek-v4-flash", contextWindow: 128000, cost: { inUSDPerMtok: 0.27, outUSDPerMtok: 1.1 } }
136604
- ];
136605
- function generatedModels2() {
136606
- const out = [];
136607
- for (const p of CATALOG) {
136608
- if (p.group === "cli")
136609
- continue;
136610
- for (const m2 of p.defaultModels ?? []) {
136611
- if (CURATED2.some((c) => c.provider === p.id && c.sdkId === m2))
136612
- continue;
136613
- out.push({ id: `${p.id}/${m2}`, provider: p.id, sdkId: m2, label: m2.length > 24 ? m2.slice(0, 24) : m2, contextWindow: 128000 });
136614
- }
136615
- }
136616
- return out;
136617
- }
136618
- var MODELS2 = [...CURATED2, ...generatedModels2()];
136619
-
136620
- // src/ui/image.ts
136621
- var SIZES2 = ["big", "mini", "micro"];
136622
- var VARIANTS2 = Object.keys(GHOST_PNG);
136623
- var DIACRITICS2 = [
136624
- 773,
136625
- 781,
136626
- 782,
136627
- 784,
136628
- 786,
136629
- 829,
136630
- 830,
136631
- 831,
136632
- 838,
136633
- 842,
136634
- 843,
136635
- 844,
136636
- 848,
136637
- 849,
136638
- 850,
136639
- 855,
136640
- 859,
136641
- 867,
136642
- 868,
136643
- 869,
136644
- 870,
136645
- 871,
136646
- 872,
136647
- 873,
136648
- 874,
136649
- 875,
136650
- 876,
136651
- 877,
136652
- 878,
136653
- 879,
136654
- 1155,
136655
- 1156,
136656
- 1157,
136657
- 1158,
136658
- 1159,
136659
- 1426,
136660
- 1427,
136661
- 1428,
136662
- 1429,
136663
- 1431,
136664
- 1432,
136665
- 1433,
136666
- 1436,
136667
- 1437,
136668
- 1438,
136669
- 1439,
136670
- 1440,
136671
- 1441,
136672
- 1448,
136673
- 1449
136674
- ].map((c) => String.fromCodePoint(c));
136675
- function detectImageMode2() {
136676
- const force = process.env.GEARBOX_GHOST;
136677
- if (force === "kitty" || force === "iterm")
136678
- return force;
136679
- return "blocks";
136680
- }
136681
- var resolved2 = null;
136682
- function setImageMode(m2) {
136683
- resolved2 = m2;
136684
- }
136685
- function imageId2(variant, size2) {
136686
- return VARIANTS2.indexOf(variant) * SIZES2.length + SIZES2.indexOf(size2) + 1;
136687
- }
136688
- function transmitOne(id, b64, cols, rows) {
136689
- const ESC2 = "\x1B";
136690
- const CHUNK = 4096;
136691
- if (b64.length <= CHUNK) {
136692
- return `${ESC2}_Ga=T,U=1,i=${id},c=${cols},r=${rows},f=100,q=2;${b64}${ESC2}\\`;
136693
- }
136694
- let out = "";
136695
- for (let i2 = 0;i2 < b64.length; i2 += CHUNK) {
136696
- const chunk2 = b64.slice(i2, i2 + CHUNK);
136697
- const more = i2 + CHUNK < b64.length ? 1 : 0;
136698
- out += i2 === 0 ? `${ESC2}_Ga=T,U=1,i=${id},c=${cols},r=${rows},f=100,q=2,m=${more};${chunk2}${ESC2}\\` : `${ESC2}_Gm=${more};${chunk2}${ESC2}\\`;
136699
- }
136700
- return out;
136701
- }
136702
- function transmitAll() {
136703
- let out = "";
136704
- for (const variant of VARIANTS2) {
136705
- for (const size2 of SIZES2) {
136706
- const data = GHOSTS[variant][size2];
136707
- out += transmitOne(imageId2(variant, size2), GHOST_PNG[variant], data[0]?.length ?? 0, data.length);
136708
- }
136709
- }
136710
- return out;
136711
- }
136712
-
136713
- // src/ui/prefs.ts
136714
- import { homedir as homedir9 } from "node:os";
136715
- import { join as join11, dirname as dirname3 } from "node:path";
136716
- import { readFileSync as readFileSync13, writeFileSync as writeFileSync7, mkdirSync as mkdirSync8 } from "node:fs";
136717
- function file5() {
136718
- const dir2 = process.env.GEARBOX_HOME || join11(homedir9(), ".gearbox");
136719
- return join11(dir2, "prefs.json");
136720
- }
136721
- function loadPrefs2() {
136722
- try {
136723
- return JSON.parse(readFileSync13(file5(), "utf8"));
136724
- } catch {
136725
- return {};
136726
- }
136727
- }
136728
-
136729
- // src/permission.ts
136730
- var granted2 = new Set;
136731
- var yolo2 = false;
136732
- function setYolo2(on) {
136733
- yolo2 = on;
136734
- }
136735
-
136736
- // src/session.ts
136737
- import { mkdirSync as mkdirSync9, readFileSync as readFileSync14, writeFileSync as writeFileSync8, readdirSync as readdirSync4 } from "node:fs";
136738
- import { join as join12 } from "node:path";
136739
- import { homedir as homedir10 } from "node:os";
136740
- var root2 = () => join12(process.env.GEARBOX_HOME || join12(homedir10(), ".gearbox"), "sessions");
136741
- var slug3 = () => process.cwd().replace(/[^a-zA-Z0-9]+/g, "-").replace(/^-+|-+$/g, "") || "root";
136742
- var dir2 = () => join12(root2(), slug3());
136743
- function listSessions2() {
136744
- try {
136745
- return readdirSync4(dir2()).filter((f3) => f3.endsWith(".json") && f3 !== "history.json").map((f3) => {
136746
- try {
136747
- return JSON.parse(readFileSync14(join12(dir2(), f3), "utf8"));
136748
- } catch {
136749
- return null;
136750
- }
136751
- }).filter((s2) => s2 !== null && Array.isArray(s2.items)).sort((a, b) => b.updatedAt - a.updatedAt);
136752
- } catch {
136753
- return [];
136754
- }
136755
- }
136756
- function latestSession() {
136757
- return listSessions2()[0] ?? null;
136758
- }
136759
-
136760
136098
  // src/cli.tsx
136761
- var jsx_dev_runtime13 = __toESM(require_jsx_dev_runtime2(), 1);
136099
+ var jsx_dev_runtime13 = __toESM(require_jsx_dev_runtime(), 1);
136100
+ process.env.LANG = process.env.LANG || "en_US.UTF-8";
136101
+ process.env.LC_ALL = process.env.LC_ALL || "en_US.UTF-8";
136762
136102
  var VERSION16 = "0.1.0";
136763
136103
  var args = process.argv.slice(2);
136764
136104
  if (args[0] === "upgrade" || args[0] === "update") {
136765
- const root3 = resolve11(import.meta.dir, "..");
136766
- if (!existsSync10(resolve11(root3, ".git"))) {
136105
+ const root2 = resolve11(import.meta.dir, "..");
136106
+ if (!existsSync8(resolve11(root2, ".git"))) {
136767
136107
  console.log("This build can't self-update (not a git checkout).");
136768
136108
  console.log("Update by pulling the repo and reinstalling: git pull && bun install");
136769
136109
  process.exit(0);
136770
136110
  }
136771
136111
  try {
136772
- console.log("\u2192 Pulling latest\u2026");
136773
- console.log(execFileSync4("git", ["-C", root3, "pull", "--ff-only"], { encoding: "utf8" }).trim());
136774
- console.log("\u2192 Installing dependencies\u2026");
136775
- execFileSync4("bun", ["install"], { cwd: root3, stdio: "inherit" });
136776
- console.log("\u2713 Gearbox is up to date. Restart any running session to use the new version.");
136112
+ console.log(" Pulling latest");
136113
+ console.log(execFileSync4("git", ["-C", root2, "pull", "--ff-only"], { encoding: "utf8" }).trim());
136114
+ console.log(" Installing dependencies");
136115
+ execFileSync4("bun", ["install"], { cwd: root2, stdio: "inherit" });
136116
+ console.log(" Gearbox is up to date. Restart any running session to use the new version.");
136777
136117
  } catch (e2) {
136778
136118
  console.log("Upgrade failed: " + (e2?.message ?? String(e2)));
136779
- console.log(`Try manually: cd ${root3} && git pull && bun install`);
136119
+ console.log(`Try manually: cd ${root2} && git pull && bun install`);
136780
136120
  }
136781
136121
  process.exit(0);
136782
136122
  }
136783
136123
  if (args.includes("--help") || args.includes("-h")) {
136784
- console.log(`gearbox ${VERSION16} \u2014 multi-provider coding agent for the terminal
136124
+ console.log(`gearbox ${VERSION16} multi-provider coding agent for the terminal
136785
136125
 
136786
136126
  Usage:
136787
136127
  gearbox start in the current directory (it becomes the workspace)
@@ -136798,10 +136138,12 @@ Options:
136798
136138
  -v, --version print version
136799
136139
  -h, --help this help
136800
136140
 
136801
- Set at least one provider key first (each user uses their own):
136802
- ANTHROPIC_API_KEY \xB7 OPENAI_API_KEY \xB7 GOOGLE_GENERATIVE_AI_API_KEY \xB7 DEEPSEEK_API_KEY
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
136803
136145
 
136804
- Models: ${MODELS2.map((m2) => m2.label).join(", ")}
136146
+ Models: ${MODELS.map((m2) => m2.label).join(", ")}
136805
136147
  In-app: / for commands, @ for files, !cmd for shell, shift+tab for plan mode.`);
136806
136148
  process.exit(0);
136807
136149
  }
@@ -136810,43 +136152,43 @@ if (args.includes("--version") || args.includes("-v")) {
136810
136152
  process.exit(0);
136811
136153
  }
136812
136154
  if (args[0] === "auth") {
136813
- const { listAccounts: listAccounts3, loadAccounts: loadAccounts4, removeAccount: removeAccount3 } = await Promise.resolve().then(() => (init_store2(), exports_store));
136814
- const { importableEnvCreds: importableEnvCreds3, importEnvCred: importEnvCred3, importableCloudCreds: importableCloudCreds3, importCloudCred: importCloudCred3 } = await Promise.resolve().then(() => (init_detect(), exports_detect));
136815
- const { addApiKeyAccount: addApiKeyAccount3, addByPastedKey: addByPastedKey3, testAccount: testAccount3, addableProviders: addableProviders2 } = await Promise.resolve().then(() => (init_onboard(), exports_onboard));
136816
- const { detectProviderByKey: detectProviderByKey3 } = await Promise.resolve().then(() => (init_catalog2(), exports_catalog));
136155
+ const { listAccounts: listAccounts2, loadAccounts: loadAccounts3, removeAccount: removeAccount2 } = await Promise.resolve().then(() => (init_store(), exports_store));
136156
+ const { importableEnvCreds: importableEnvCreds2, importEnvCred: importEnvCred2, importableCloudCreds: importableCloudCreds2, importCloudCred: importCloudCred2 } = await Promise.resolve().then(() => (init_detect(), exports_detect));
136157
+ const { addApiKeyAccount: addApiKeyAccount2, addByPastedKey: addByPastedKey2, testAccount: testAccount2, addableProviders: addableProviders2 } = await Promise.resolve().then(() => (init_onboard(), exports_onboard));
136158
+ const { detectProviderByKey: detectProviderByKey2 } = await Promise.resolve().then(() => (init_catalog(), exports_catalog));
136817
136159
  const sub = args[1];
136818
136160
  const rest2 = args.slice(2);
136819
136161
  if (sub === "list" || !sub) {
136820
- const f3 = loadAccounts4();
136162
+ const f3 = loadAccounts3();
136821
136163
  if (!f3.accounts.length)
136822
136164
  console.log("No accounts yet. Add one: gearbox auth add <key> (or) gearbox auth import");
136823
136165
  for (const a of f3.accounts)
136824
- console.log(`${f3.defaults[a.provider] === a.id ? "*" : " "} ${a.id.padEnd(22)} ${a.label}${a.exec === "cli" ? " \xB7 cli" : ""}`);
136825
- const imp = importableEnvCreds3();
136166
+ console.log(`${f3.defaults[a.provider] === a.id ? "*" : " "} ${a.id.padEnd(22)} ${a.label}${a.exec === "cli" ? " · cli" : ""}`);
136167
+ const imp = importableEnvCreds2();
136826
136168
  if (imp.length)
136827
136169
  console.log(`
136828
136170
  Importable from your env (gearbox auth import): ${imp.map((c) => c.envVar).join(", ")}`);
136829
136171
  } else if (sub === "import") {
136830
- const keys2 = importableEnvCreds3();
136831
- const cloud = importableCloudCreds3();
136172
+ const keys2 = importableEnvCreds2();
136173
+ const cloud = importableCloudCreds2();
136832
136174
  for (const c of keys2)
136833
- await importEnvCred3(c);
136175
+ await importEnvCred2(c);
136834
136176
  for (const c of cloud)
136835
- await importCloudCred3(c);
136177
+ await importCloudCred2(c);
136836
136178
  const names = [...keys2.map((c) => c.provider), ...cloud.map((c) => c.provider)];
136837
136179
  console.log(names.length ? `Imported ${names.length}: ${names.join(", ")}` : "Nothing to import.");
136838
136180
  } else if (sub === "add") {
136839
- const res = rest2[0] && !rest2[1] && detectProviderByKey3(rest2[0]) ? await addByPastedKey3(rest2[0]) : rest2[0] && rest2[1] ? await addApiKeyAccount3(rest2[0], rest2[1]) : { ok: false, message: "usage: gearbox auth add <key> | gearbox auth add <provider> <key>" };
136181
+ const res = rest2[0] && !rest2[1] && detectProviderByKey2(rest2[0]) ? await addByPastedKey2(rest2[0]) : rest2[0] && rest2[1] ? await addApiKeyAccount2(rest2[0], rest2[1]) : { ok: false, message: "usage: gearbox auth add <key> | gearbox auth add <provider> <key>" };
136840
136182
  console.log(res.message);
136841
136183
  if (res.ok && res.account) {
136842
- const t2 = await testAccount3(res.account);
136843
- console.log(t2.ok ? " test: \u2713 " + t2.message : " test: \u2717 " + t2.message + " (stored anyway)");
136184
+ const t2 = await testAccount2(res.account);
136185
+ console.log(t2.ok ? " test: " + t2.message : " test: " + t2.message + " (stored anyway)");
136844
136186
  }
136845
136187
  } else if (sub === "test" && rest2[0]) {
136846
- const a = listAccounts3().find((x2) => x2.id === rest2[0]);
136847
- console.log(a ? `${rest2[0]}: ${(await testAccount3(a)).message}` : `no account ${rest2[0]}`);
136188
+ const a = listAccounts2().find((x2) => x2.id === rest2[0]);
136189
+ console.log(a ? `${rest2[0]}: ${(await testAccount2(a)).message}` : `no account ${rest2[0]}`);
136848
136190
  } else if (sub === "rm" && rest2[0]) {
136849
- await removeAccount3(rest2[0]);
136191
+ await removeAccount2(rest2[0]);
136850
136192
  console.log(`removed ${rest2[0]}`);
136851
136193
  } else if (sub === "providers") {
136852
136194
  for (const p of addableProviders2())
@@ -136858,17 +136200,16 @@ Importable from your env (gearbox auth import): ${imp.map((c) => c.envVar).join(
136858
136200
  }
136859
136201
  var mi = args.indexOf("--model");
136860
136202
  var preferred = mi >= 0 ? args[mi + 1] : undefined;
136861
- var demo = !anyProviderAvailable();
136862
- var pinned = preferred ?? loadPrefs2().pinnedModel;
136863
- var selector = pinned ? new FixedSelector2(pinned) : new RoutingSelector2;
136203
+ var pinned = preferred ?? loadPrefs().pinnedModel;
136204
+ var selector = pinned ? new FixedSelector(pinned) : new RoutingSelector;
136864
136205
  if (args.includes("--yolo"))
136865
- setYolo2(true);
136206
+ setYolo(true);
136866
136207
  var resumeId = args.includes("--continue") || args.includes("-c") ? latestSession()?.id ?? undefined : undefined;
136867
- var imageMode = detectImageMode2();
136208
+ var imageMode = detectImageMode();
136868
136209
  setImageMode(imageMode);
136869
136210
  if (process.stdout.isTTY && imageMode === "kitty")
136870
136211
  process.stdout.write(transmitAll());
136871
- var uiPrefs = loadPrefs2();
136212
+ var uiPrefs = loadPrefs();
136872
136213
  var explicitInline = args.includes("--inline") || process.env.GEARBOX_INLINE === "1" || process.env.GEARBOX_FULLSCREEN === "0";
136873
136214
  var explicitFullscreen = args.includes("--fullscreen") || process.env.GEARBOX_FULLSCREEN === "1";
136874
136215
  var wantsInline = explicitInline || !explicitFullscreen && uiPrefs.fullscreen === false;
@@ -136892,7 +136233,6 @@ if (mouse)
136892
136233
  process.stdout.write("\x1B[?1000h\x1B[?1002h\x1B[?1006h");
136893
136234
  var app = render_default(/* @__PURE__ */ jsx_dev_runtime13.jsxDEV(App2, {
136894
136235
  selector,
136895
- demo,
136896
136236
  fullscreen,
136897
136237
  resumeId
136898
136238
  }, undefined, false, undefined, this), { exitOnCtrlC: false });