gearbox-code 0.1.15 → 0.1.16
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.mjs +408 -59
- package/package.json +1 -1
package/dist/cli.mjs
CHANGED
|
@@ -106180,6 +106180,41 @@ function generatedModels() {
|
|
|
106180
106180
|
}
|
|
106181
106181
|
return out;
|
|
106182
106182
|
}
|
|
106183
|
+
function accountModelSpecs() {
|
|
106184
|
+
const out = [];
|
|
106185
|
+
for (const account of listAccounts()) {
|
|
106186
|
+
if (!account.enabled || account.exec === "cli")
|
|
106187
|
+
continue;
|
|
106188
|
+
for (const sdkId of account.models ?? []) {
|
|
106189
|
+
if (!sdkId)
|
|
106190
|
+
continue;
|
|
106191
|
+
if (MODELS.some((m2) => m2.provider === account.provider && m2.sdkId === sdkId))
|
|
106192
|
+
continue;
|
|
106193
|
+
const id = `${account.provider}/${sdkId}`;
|
|
106194
|
+
out.push({
|
|
106195
|
+
id,
|
|
106196
|
+
provider: account.provider,
|
|
106197
|
+
sdkId,
|
|
106198
|
+
label: sdkId.length > 24 ? sdkId.slice(0, 24) : sdkId,
|
|
106199
|
+
contextWindow: 128000,
|
|
106200
|
+
capabilities: { source: "user-configured", tools: "unknown", images: "unknown", jsonSchema: "unknown", usage: "partial" }
|
|
106201
|
+
});
|
|
106202
|
+
}
|
|
106203
|
+
}
|
|
106204
|
+
return out;
|
|
106205
|
+
}
|
|
106206
|
+
function modelRegistry() {
|
|
106207
|
+
const seen = new Set;
|
|
106208
|
+
const out = [];
|
|
106209
|
+
for (const m2 of [...MODELS, ...accountModelSpecs()]) {
|
|
106210
|
+
const key = `${m2.provider}\x00${m2.sdkId}`;
|
|
106211
|
+
if (seen.has(key))
|
|
106212
|
+
continue;
|
|
106213
|
+
seen.add(key);
|
|
106214
|
+
out.push(m2);
|
|
106215
|
+
}
|
|
106216
|
+
return out;
|
|
106217
|
+
}
|
|
106183
106218
|
function envVarFor(provider) {
|
|
106184
106219
|
return ENV_KEY[provider] ?? catalogProvider(provider)?.envVars[0];
|
|
106185
106220
|
}
|
|
@@ -106210,12 +106245,12 @@ function providerAvailable(p) {
|
|
|
106210
106245
|
return ev ? Boolean(process.env[ev]) : false;
|
|
106211
106246
|
}
|
|
106212
106247
|
function findModel(idOrLabel) {
|
|
106213
|
-
return
|
|
106248
|
+
return modelRegistry().find((m2) => m2.id === idOrLabel || m2.label === idOrLabel);
|
|
106214
106249
|
}
|
|
106215
106250
|
function estimateCost(turns) {
|
|
106216
106251
|
let usd2 = 0;
|
|
106217
106252
|
for (const t2 of turns) {
|
|
106218
|
-
const c =
|
|
106253
|
+
const c = modelRegistry().find((m2) => m2.id === t2.model)?.cost;
|
|
106219
106254
|
if (!c)
|
|
106220
106255
|
continue;
|
|
106221
106256
|
usd2 += t2.inputTokens / 1e6 * c.inUSDPerMtok + t2.outputTokens / 1e6 * c.outUSDPerMtok;
|
|
@@ -106281,7 +106316,7 @@ var init_providers = __esm(() => {
|
|
|
106281
106316
|
NATIVE = new Set(["anthropic", "openai", "google", "deepseek"]);
|
|
106282
106317
|
CURATED = [
|
|
106283
106318
|
{ 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"] },
|
|
106284
|
-
{ 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", "
|
|
106319
|
+
{ 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", "max"] },
|
|
106285
106320
|
{ id: "claude-haiku-4-5", provider: "anthropic", sdkId: "claude-haiku-4-5", label: "haiku-4.5", contextWindow: 200000, cost: { inUSDPerMtok: 1, outUSDPerMtok: 5 } },
|
|
106286
106321
|
{ 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"] },
|
|
106287
106322
|
{ 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"] },
|
|
@@ -106497,12 +106532,16 @@ __export(exports_capabilities, {
|
|
|
106497
106532
|
capabilitiesFor: () => capabilitiesFor
|
|
106498
106533
|
});
|
|
106499
106534
|
function providerSource(spec6) {
|
|
106535
|
+
if (spec6.capabilities?.source)
|
|
106536
|
+
return spec6.capabilities.source;
|
|
106500
106537
|
const group = catalogProvider(spec6.provider)?.group;
|
|
106501
106538
|
if (group === "gateway" || group === "openai-compat" || group === "local")
|
|
106502
106539
|
return "seeded";
|
|
106503
106540
|
return "seeded";
|
|
106504
106541
|
}
|
|
106505
106542
|
function exactUsage(spec6) {
|
|
106543
|
+
if (spec6.capabilities?.usage)
|
|
106544
|
+
return spec6.capabilities.usage;
|
|
106506
106545
|
if (spec6.provider === "anthropic" || spec6.provider === "openai" || spec6.provider === "google" || spec6.provider === "deepseek")
|
|
106507
106546
|
return "exact";
|
|
106508
106547
|
const group = catalogProvider(spec6.provider)?.group;
|
|
@@ -106511,6 +106550,8 @@ function exactUsage(spec6) {
|
|
|
106511
106550
|
return "none";
|
|
106512
106551
|
}
|
|
106513
106552
|
function toolSupport(spec6) {
|
|
106553
|
+
if (spec6.capabilities?.tools != null)
|
|
106554
|
+
return spec6.capabilities.tools;
|
|
106514
106555
|
const group = catalogProvider(spec6.provider)?.group;
|
|
106515
106556
|
if (spec6.provider === "anthropic" || spec6.provider === "openai" || spec6.provider === "google" || spec6.provider === "deepseek")
|
|
106516
106557
|
return true;
|
|
@@ -106521,6 +106562,8 @@ function toolSupport(spec6) {
|
|
|
106521
106562
|
return "unknown";
|
|
106522
106563
|
}
|
|
106523
106564
|
function imageSupport(spec6) {
|
|
106565
|
+
if (spec6.capabilities?.images != null)
|
|
106566
|
+
return spec6.capabilities.images;
|
|
106524
106567
|
if (spec6.provider === "anthropic" || spec6.provider === "openai" || spec6.provider === "google" || spec6.provider === "vertex")
|
|
106525
106568
|
return true;
|
|
106526
106569
|
if (spec6.provider === "deepseek")
|
|
@@ -106528,6 +106571,8 @@ function imageSupport(spec6) {
|
|
|
106528
106571
|
return "unknown";
|
|
106529
106572
|
}
|
|
106530
106573
|
function schemaSupport(spec6) {
|
|
106574
|
+
if (spec6.capabilities?.jsonSchema != null)
|
|
106575
|
+
return spec6.capabilities.jsonSchema;
|
|
106531
106576
|
if (spec6.provider === "openai" || spec6.provider === "google" || spec6.provider === "anthropic")
|
|
106532
106577
|
return true;
|
|
106533
106578
|
if (spec6.provider === "deepseek")
|
|
@@ -106551,7 +106596,7 @@ function capabilitiesFor(spec6) {
|
|
|
106551
106596
|
images: imageSupport(spec6),
|
|
106552
106597
|
jsonSchema: schemaSupport(spec6),
|
|
106553
106598
|
reasoningEffort: efforts.length ? efforts : false,
|
|
106554
|
-
systemPrompt: true,
|
|
106599
|
+
systemPrompt: spec6.capabilities?.systemPrompt ?? true,
|
|
106555
106600
|
usage: exactUsage(spec6),
|
|
106556
106601
|
contextWindow: profile?.contextWindow ?? spec6.contextWindow,
|
|
106557
106602
|
maxOutputTokens: profile?.maxOutput,
|
|
@@ -106583,7 +106628,7 @@ function cell(v) {
|
|
|
106583
106628
|
return "?";
|
|
106584
106629
|
return String(v ?? "");
|
|
106585
106630
|
}
|
|
106586
|
-
function formatCapabilityMatrix(models =
|
|
106631
|
+
function formatCapabilityMatrix(models = modelRegistry()) {
|
|
106587
106632
|
const rows = models.map((m2) => {
|
|
106588
106633
|
const c = capabilitiesFor(m2);
|
|
106589
106634
|
return {
|
|
@@ -128749,12 +128794,19 @@ var init_stdio2 = __esm(() => {
|
|
|
128749
128794
|
// src/mcp.ts
|
|
128750
128795
|
var exports_mcp = {};
|
|
128751
128796
|
__export(exports_mcp, {
|
|
128797
|
+
shellSplit: () => shellSplit,
|
|
128798
|
+
removeMcpServer: () => removeMcpServer,
|
|
128799
|
+
reloadMcpConnections: () => reloadMcpConnections,
|
|
128752
128800
|
mcpTools: () => mcpTools,
|
|
128753
128801
|
mcpToolSummary: () => mcpToolSummary,
|
|
128754
|
-
mcpConfigPaths: () => mcpConfigPaths
|
|
128802
|
+
mcpConfigPaths: () => mcpConfigPaths,
|
|
128803
|
+
mcpConfigPath: () => mcpConfigPath,
|
|
128804
|
+
formatMcpConfigList: () => formatMcpConfigList,
|
|
128805
|
+
configuredMcpServers: () => configuredMcpServers,
|
|
128806
|
+
addMcpServer: () => addMcpServer
|
|
128755
128807
|
});
|
|
128756
|
-
import { existsSync as existsSync3, readFileSync as readFileSync7 } from "node:fs";
|
|
128757
|
-
import { join as join7 } from "node:path";
|
|
128808
|
+
import { existsSync as existsSync3, mkdirSync as mkdirSync6, readFileSync as readFileSync7, writeFileSync as writeFileSync6 } from "node:fs";
|
|
128809
|
+
import { dirname as dirname3, join as join7 } from "node:path";
|
|
128758
128810
|
import { homedir as homedir6 } from "node:os";
|
|
128759
128811
|
function readConfigFile(path) {
|
|
128760
128812
|
if (!existsSync3(path))
|
|
@@ -128765,6 +128817,11 @@ function readConfigFile(path) {
|
|
|
128765
128817
|
return {};
|
|
128766
128818
|
}
|
|
128767
128819
|
}
|
|
128820
|
+
function writeConfigFile(path, config3) {
|
|
128821
|
+
mkdirSync6(dirname3(path), { recursive: true });
|
|
128822
|
+
writeFileSync6(path, JSON.stringify(config3, null, 2) + `
|
|
128823
|
+
`, { mode: 384 });
|
|
128824
|
+
}
|
|
128768
128825
|
function expandEnv(value) {
|
|
128769
128826
|
return value.replace(/\$\{([A-Z0-9_]+)\}/gi, (_, name31) => process.env[name31] ?? "");
|
|
128770
128827
|
}
|
|
@@ -128813,6 +128870,9 @@ async function connected() {
|
|
|
128813
128870
|
connectedPromise ??= connectAll();
|
|
128814
128871
|
return connectedPromise;
|
|
128815
128872
|
}
|
|
128873
|
+
function reloadMcpConnections() {
|
|
128874
|
+
connectedPromise = null;
|
|
128875
|
+
}
|
|
128816
128876
|
function formatMcpResult(result2) {
|
|
128817
128877
|
const content = result2?.content ?? [];
|
|
128818
128878
|
if (!Array.isArray(content) || !content.length)
|
|
@@ -128839,6 +128899,122 @@ async function mcpToolSummary() {
|
|
|
128839
128899
|
return rows.flatMap((s2) => s2.tools.map((t2) => `${safeToolName(s2.name, t2.name).padEnd(34)} ${t2.description ?? ""}`)).join(`
|
|
128840
128900
|
`);
|
|
128841
128901
|
}
|
|
128902
|
+
function mcpConfigPath(scope = "project", cwd2 = process.cwd()) {
|
|
128903
|
+
return scope === "global" ? join7(HOME(), "mcp.json") : join7(cwd2, ".gearbox", "mcp.json");
|
|
128904
|
+
}
|
|
128905
|
+
function configuredMcpServers(cwd2 = process.cwd()) {
|
|
128906
|
+
const paths = [
|
|
128907
|
+
{ scope: "global", path: join7(HOME(), "mcp.json") },
|
|
128908
|
+
{ scope: "compat", path: join7(cwd2, ".mcp.json") },
|
|
128909
|
+
{ scope: "project", path: join7(cwd2, ".gearbox", "mcp.json") }
|
|
128910
|
+
];
|
|
128911
|
+
const rows = [];
|
|
128912
|
+
for (const p of paths) {
|
|
128913
|
+
const file5 = readConfigFile(p.path);
|
|
128914
|
+
for (const [name31, config3] of Object.entries(file5.mcpServers ?? file5.servers ?? {})) {
|
|
128915
|
+
if (!config3?.command)
|
|
128916
|
+
continue;
|
|
128917
|
+
rows.push({ name: name31, scope: p.scope, config: config3 });
|
|
128918
|
+
}
|
|
128919
|
+
}
|
|
128920
|
+
return rows;
|
|
128921
|
+
}
|
|
128922
|
+
function formatMcpConfigList(cwd2 = process.cwd()) {
|
|
128923
|
+
const rows = configuredMcpServers(cwd2);
|
|
128924
|
+
if (!rows.length) {
|
|
128925
|
+
return [
|
|
128926
|
+
"MCP servers",
|
|
128927
|
+
" none configured",
|
|
128928
|
+
"",
|
|
128929
|
+
"Add one:",
|
|
128930
|
+
" /mcp add github npx -y @modelcontextprotocol/server-github",
|
|
128931
|
+
" /mcp add --global linear npx -y @modelcontextprotocol/server-linear"
|
|
128932
|
+
].join(`
|
|
128933
|
+
`);
|
|
128934
|
+
}
|
|
128935
|
+
return [
|
|
128936
|
+
"MCP servers",
|
|
128937
|
+
...rows.map((r2) => {
|
|
128938
|
+
const args = r2.config.args?.length ? " " + r2.config.args.join(" ") : "";
|
|
128939
|
+
const off = r2.config.disabled ? " · disabled" : "";
|
|
128940
|
+
return ` ${r2.name.padEnd(18)} ${r2.scope.padEnd(7)} ${r2.config.command}${args}${off}`;
|
|
128941
|
+
}),
|
|
128942
|
+
"",
|
|
128943
|
+
"Tools: /mcp tools",
|
|
128944
|
+
"Remove: /mcp remove <name>"
|
|
128945
|
+
].join(`
|
|
128946
|
+
`);
|
|
128947
|
+
}
|
|
128948
|
+
function shellSplit(input) {
|
|
128949
|
+
const out = [];
|
|
128950
|
+
let cur = "";
|
|
128951
|
+
let quote = null;
|
|
128952
|
+
let esc2 = false;
|
|
128953
|
+
for (const ch of input) {
|
|
128954
|
+
if (esc2) {
|
|
128955
|
+
cur += ch;
|
|
128956
|
+
esc2 = false;
|
|
128957
|
+
continue;
|
|
128958
|
+
}
|
|
128959
|
+
if (ch === "\\") {
|
|
128960
|
+
esc2 = true;
|
|
128961
|
+
continue;
|
|
128962
|
+
}
|
|
128963
|
+
if (quote) {
|
|
128964
|
+
if (ch === quote)
|
|
128965
|
+
quote = null;
|
|
128966
|
+
else
|
|
128967
|
+
cur += ch;
|
|
128968
|
+
continue;
|
|
128969
|
+
}
|
|
128970
|
+
if (ch === "'" || ch === '"') {
|
|
128971
|
+
quote = ch;
|
|
128972
|
+
continue;
|
|
128973
|
+
}
|
|
128974
|
+
if (/\s/.test(ch)) {
|
|
128975
|
+
if (cur) {
|
|
128976
|
+
out.push(cur);
|
|
128977
|
+
cur = "";
|
|
128978
|
+
}
|
|
128979
|
+
continue;
|
|
128980
|
+
}
|
|
128981
|
+
cur += ch;
|
|
128982
|
+
}
|
|
128983
|
+
if (cur)
|
|
128984
|
+
out.push(cur);
|
|
128985
|
+
return out;
|
|
128986
|
+
}
|
|
128987
|
+
function cleanServerName(name31) {
|
|
128988
|
+
return name31.trim().toLowerCase().replace(/[^a-z0-9_.-]+/g, "-").replace(/^-+|-+$/g, "");
|
|
128989
|
+
}
|
|
128990
|
+
function addMcpServer(name31, command, args = [], opts = {}) {
|
|
128991
|
+
const serverName = cleanServerName(name31);
|
|
128992
|
+
if (!serverName || !command)
|
|
128993
|
+
throw new Error("usage: /mcp add <name> <command> [args...]");
|
|
128994
|
+
const path = mcpConfigPath(opts.scope ?? "project", opts.cwd ?? process.cwd());
|
|
128995
|
+
const file5 = readConfigFile(path);
|
|
128996
|
+
const servers = { ...file5.mcpServers ?? file5.servers ?? {} };
|
|
128997
|
+
servers[serverName] = { command, args };
|
|
128998
|
+
writeConfigFile(path, { mcpServers: servers });
|
|
128999
|
+
reloadMcpConnections();
|
|
129000
|
+
return `connected ${serverName} (${opts.scope ?? "project"})`;
|
|
129001
|
+
}
|
|
129002
|
+
function removeMcpServer(name31, opts = {}) {
|
|
129003
|
+
const serverName = cleanServerName(name31);
|
|
129004
|
+
const scopes = opts.scope ? [opts.scope] : ["project", "global"];
|
|
129005
|
+
for (const scope of scopes) {
|
|
129006
|
+
const path = mcpConfigPath(scope, opts.cwd ?? process.cwd());
|
|
129007
|
+
const file5 = readConfigFile(path);
|
|
129008
|
+
const servers = { ...file5.mcpServers ?? file5.servers ?? {} };
|
|
129009
|
+
if (!(serverName in servers))
|
|
129010
|
+
continue;
|
|
129011
|
+
delete servers[serverName];
|
|
129012
|
+
writeConfigFile(path, { mcpServers: servers });
|
|
129013
|
+
reloadMcpConnections();
|
|
129014
|
+
return `removed ${serverName} (${scope})`;
|
|
129015
|
+
}
|
|
129016
|
+
return `no MCP server named ${serverName}`;
|
|
129017
|
+
}
|
|
128842
129018
|
async function mcpTools(onEvent, readOnly = false) {
|
|
128843
129019
|
const rows = await connected();
|
|
128844
129020
|
const out = {};
|
|
@@ -129415,15 +129591,19 @@ __export(exports_onboard, {
|
|
|
129415
129591
|
cliLoginArgs: () => cliLoginArgs,
|
|
129416
129592
|
cliAuthStatus: () => cliAuthStatus,
|
|
129417
129593
|
addableProviders: () => addableProviders,
|
|
129594
|
+
addOpenAICompatAccount: () => addOpenAICompatAccount,
|
|
129418
129595
|
addCliAccount: () => addCliAccount,
|
|
129419
129596
|
addByPastedKey: () => addByPastedKey,
|
|
129420
129597
|
addAzureFoundryAccount: () => addAzureFoundryAccount,
|
|
129421
129598
|
addAzureAccount: () => addAzureAccount,
|
|
129422
129599
|
addApiKeyAccount: () => addApiKeyAccount
|
|
129423
129600
|
});
|
|
129424
|
-
import { mkdirSync as
|
|
129601
|
+
import { mkdirSync as mkdirSync8 } from "node:fs";
|
|
129425
129602
|
import { join as join11 } from "node:path";
|
|
129426
129603
|
import { homedir as homedir9 } from "node:os";
|
|
129604
|
+
function slugify(input) {
|
|
129605
|
+
return input.trim().toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "") || shortId();
|
|
129606
|
+
}
|
|
129427
129607
|
async function addApiKeyAccount(provider, key, opts = {}) {
|
|
129428
129608
|
provider = normalizeProviderId(provider);
|
|
129429
129609
|
const cat = catalogProvider(provider);
|
|
@@ -129450,6 +129630,29 @@ async function addApiKeyAccount(provider, key, opts = {}) {
|
|
|
129450
129630
|
putAccount(account);
|
|
129451
129631
|
return { ok: true, account, message: `added ${account.label} (${id})` };
|
|
129452
129632
|
}
|
|
129633
|
+
async function addOpenAICompatAccount(name31, baseUrl, key, models, opts = {}) {
|
|
129634
|
+
if (!/^https?:\/\//i.test(baseUrl) || !models.length) {
|
|
129635
|
+
return { ok: false, message: "usage: /account add openai-compat <name> <base-url> <api-key> <model> [model...]" };
|
|
129636
|
+
}
|
|
129637
|
+
const known = catalogProvider(normalizeProviderId(name31));
|
|
129638
|
+
const provider = known?.authKind === "openai-compat" ? known.id : `custom-${slugify(name31)}`;
|
|
129639
|
+
const id = opts.id ?? `${provider}-${shortId()}`;
|
|
129640
|
+
const ref = `${id}:api-key`;
|
|
129641
|
+
await setSecret(ref, key.trim());
|
|
129642
|
+
const account = {
|
|
129643
|
+
id,
|
|
129644
|
+
label: opts.label ?? (known?.label ?? (name31.trim() || "OpenAI-compatible")),
|
|
129645
|
+
provider,
|
|
129646
|
+
exec: "in-loop",
|
|
129647
|
+
auth: { kind: "openai-compat", ref },
|
|
129648
|
+
baseUrl: baseUrl.replace(/\/+$/, ""),
|
|
129649
|
+
models,
|
|
129650
|
+
enabled: true,
|
|
129651
|
+
addedAt: Date.now()
|
|
129652
|
+
};
|
|
129653
|
+
putAccount(account);
|
|
129654
|
+
return { ok: true, account, message: `added ${account.label} (${models.length} model${models.length === 1 ? "" : "s"})` };
|
|
129655
|
+
}
|
|
129453
129656
|
function azureResourceName(input) {
|
|
129454
129657
|
const s2 = input.trim();
|
|
129455
129658
|
try {
|
|
@@ -129492,7 +129695,7 @@ async function addAzureAccount(resourceOrEndpoint, key, opts = {}) {
|
|
|
129492
129695
|
const resourceName = azureResourceName(resourceOrEndpoint);
|
|
129493
129696
|
if (!resourceName || !key.trim())
|
|
129494
129697
|
return { ok: false, message: "usage: /account add azure <resource-or-endpoint> <api-key> [api-version]" };
|
|
129495
|
-
const id = opts.id ?? `azure-${resourceName
|
|
129698
|
+
const id = opts.id ?? `azure-${slugify(resourceName)}`;
|
|
129496
129699
|
const ref = `${id}:api-key`;
|
|
129497
129700
|
await setSecret(ref, key.trim());
|
|
129498
129701
|
const account = {
|
|
@@ -129521,7 +129724,7 @@ function addCliAccount(provider, name31) {
|
|
|
129521
129724
|
const id = slug3 ? `${provider}-${slug3}` : provider;
|
|
129522
129725
|
const profile = slug3 ? cliProfileDir(id) : undefined;
|
|
129523
129726
|
if (profile)
|
|
129524
|
-
|
|
129727
|
+
mkdirSync8(profile, { recursive: true });
|
|
129525
129728
|
const account = {
|
|
129526
129729
|
id,
|
|
129527
129730
|
label: slug3 ? `${cat.label.replace(/ \(.*\)$/, "")} (${name31.trim()})` : cat.label,
|
|
@@ -135173,7 +135376,7 @@ var import_react21 = __toESM(require_react(), 1);
|
|
|
135173
135376
|
// src/cli.tsx
|
|
135174
135377
|
import { createInterface } from "node:readline/promises";
|
|
135175
135378
|
import { execFileSync as execFileSync4, spawnSync } from "node:child_process";
|
|
135176
|
-
import { resolve as
|
|
135379
|
+
import { resolve as resolve13 } from "node:path";
|
|
135177
135380
|
import { existsSync as existsSync12 } from "node:fs";
|
|
135178
135381
|
|
|
135179
135382
|
// src/ui/App.tsx
|
|
@@ -139383,6 +139586,7 @@ var COMMANDS = [
|
|
|
139383
139586
|
{ name: "/memory", usage: "/memory [note]", desc: "show or add facts to remember (or start a line with #)", group: "chat" },
|
|
139384
139587
|
{ name: "/account", usage: "/account", desc: "list accounts; /account <number> to switch, /account add to add one", group: "accounts" },
|
|
139385
139588
|
{ name: "/onboard", usage: "/onboard", desc: "first-run setup; provider list and import/add commands", group: "accounts" },
|
|
139589
|
+
{ name: "/mcp", usage: "/mcp", desc: "list or connect MCP servers: /mcp add <name> <command> [args]", group: "accounts" },
|
|
139386
139590
|
{ name: "/cost", usage: "/cost", desc: "see what you've spent per account", group: "accounts" },
|
|
139387
139591
|
{ name: "/copy", usage: "/copy", desc: "copy the last reply to the clipboard", group: "output" },
|
|
139388
139592
|
{ name: "/export", usage: "/export [file]", desc: "save the conversation to a file", group: "output" },
|
|
@@ -139503,9 +139707,10 @@ var ENV_LABEL = {
|
|
|
139503
139707
|
deepseek: "DEEPSEEK_API_KEY"
|
|
139504
139708
|
};
|
|
139505
139709
|
function formatModelList(currentId, showAll = false) {
|
|
139710
|
+
const MODELS2 = modelRegistry();
|
|
139506
139711
|
const line = (m2) => ` ${m2.id === currentId ? glyph.on : glyph.off} ${m2.label.padEnd(18)} ${m2.provider}`;
|
|
139507
|
-
const usable =
|
|
139508
|
-
const rest2 =
|
|
139712
|
+
const usable = MODELS2.filter((m2) => providerAvailable(m2.provider));
|
|
139713
|
+
const rest2 = MODELS2.filter((m2) => !providerAvailable(m2.provider));
|
|
139509
139714
|
const rows = ["models · /model <name> pins one · /model auto routes per task"];
|
|
139510
139715
|
if (usable.length) {
|
|
139511
139716
|
rows.push("", "ready to use");
|
|
@@ -139528,7 +139733,8 @@ function resolveModelSwitch(query) {
|
|
|
139528
139733
|
const q = query.trim().toLowerCase();
|
|
139529
139734
|
if (!q)
|
|
139530
139735
|
return { ok: false, message: "usage: /model <name>" };
|
|
139531
|
-
const
|
|
139736
|
+
const MODELS2 = modelRegistry();
|
|
139737
|
+
const matches2 = MODELS2.filter((m3) => m3.label.toLowerCase().includes(q) || m3.id.toLowerCase().includes(q));
|
|
139532
139738
|
if (matches2.length === 0)
|
|
139533
139739
|
return { ok: false, message: `no model matching “${query}” — /model to list` };
|
|
139534
139740
|
const exact = matches2.find((m3) => m3.label.toLowerCase() === q || m3.id.toLowerCase() === q);
|
|
@@ -142120,10 +142326,10 @@ function pickDefaultModel(preferredId) {
|
|
|
142120
142326
|
const wanted = findModel(pref);
|
|
142121
142327
|
if (wanted && providerAvailable(wanted.provider))
|
|
142122
142328
|
return wanted;
|
|
142123
|
-
return
|
|
142329
|
+
return modelRegistry().find((m2) => providerAvailable(m2.provider));
|
|
142124
142330
|
}
|
|
142125
142331
|
function anyProviderAvailable() {
|
|
142126
|
-
return
|
|
142332
|
+
return modelRegistry().some((m2) => providerAvailable(m2.provider));
|
|
142127
142333
|
}
|
|
142128
142334
|
|
|
142129
142335
|
// src/model/selector.ts
|
|
@@ -142239,7 +142445,7 @@ class RoutingSelector {
|
|
|
142239
142445
|
const kind = task.kind ?? classify(task.prompt);
|
|
142240
142446
|
const bar = BAR[kind];
|
|
142241
142447
|
const required2 = task.requires ?? [];
|
|
142242
|
-
const available =
|
|
142448
|
+
const available = modelRegistry().filter((m2) => providerAvailable(m2.provider));
|
|
142243
142449
|
const capable = required2.length ? available.filter((m2) => supportsRequirements(m2, required2)) : available;
|
|
142244
142450
|
if (available.length > 0 && capable.length === 0) {
|
|
142245
142451
|
const missing = available.slice(0, 4).map((m2) => `${m2.label}: ${missingRequirements(m2, required2).join(", ")}`).join("; ");
|
|
@@ -143204,7 +143410,7 @@ function countTokens(text2, modelId) {
|
|
|
143204
143410
|
}
|
|
143205
143411
|
|
|
143206
143412
|
// src/context/memory.ts
|
|
143207
|
-
import { mkdirSync as
|
|
143413
|
+
import { mkdirSync as mkdirSync7, readFileSync as readFileSync8, writeFileSync as writeFileSync7, existsSync as existsSync5 } from "node:fs";
|
|
143208
143414
|
import { join as join8 } from "node:path";
|
|
143209
143415
|
import { homedir as homedir7 } from "node:os";
|
|
143210
143416
|
var DOC_CANDIDATES = ["GEARBOX.md", "CLAUDE.md", "AGENTS.md"];
|
|
@@ -143240,9 +143446,9 @@ function appendFact(text2, cwd2 = process.cwd()) {
|
|
|
143240
143446
|
if (!fact)
|
|
143241
143447
|
return false;
|
|
143242
143448
|
try {
|
|
143243
|
-
|
|
143449
|
+
mkdirSync7(memDir(cwd2), { recursive: true });
|
|
143244
143450
|
const stamp = new Date().toISOString().slice(0, 10);
|
|
143245
|
-
|
|
143451
|
+
writeFileSync7(factsFile(cwd2), `- [${stamp}] ${fact}
|
|
143246
143452
|
`, { flag: "a" });
|
|
143247
143453
|
return true;
|
|
143248
143454
|
} catch {
|
|
@@ -144109,7 +144315,7 @@ ${summary}` },
|
|
|
144109
144315
|
|
|
144110
144316
|
// src/image.ts
|
|
144111
144317
|
import { existsSync as existsSync8, readFileSync as readFileSync13, statSync as statSync4 } from "node:fs";
|
|
144112
|
-
import { isAbsolute as isAbsolute2, resolve as resolve11 } from "node:path";
|
|
144318
|
+
import { basename as basename2, isAbsolute as isAbsolute2, resolve as resolve11 } from "node:path";
|
|
144113
144319
|
var MAX_IMAGE_BYTES = 8 * 1024 * 1024;
|
|
144114
144320
|
var IMAGE_EXT = {
|
|
144115
144321
|
".png": "image/png",
|
|
@@ -144121,6 +144327,39 @@ var IMAGE_EXT = {
|
|
|
144121
144327
|
function unquotePath(raw) {
|
|
144122
144328
|
return raw.trim().replace(/^file:\/\//, "").replace(/^['"]|['"]$/g, "").replace(/\\ /g, " ");
|
|
144123
144329
|
}
|
|
144330
|
+
function imageMimeForPath(path) {
|
|
144331
|
+
const ext = path.toLowerCase().match(/\.[^.]+$/)?.[0] ?? "";
|
|
144332
|
+
return IMAGE_EXT[ext];
|
|
144333
|
+
}
|
|
144334
|
+
function isImageFilePath(path) {
|
|
144335
|
+
return Boolean(imageMimeForPath(unquotePath(path)));
|
|
144336
|
+
}
|
|
144337
|
+
function shortName(path, max2 = 42) {
|
|
144338
|
+
const name31 = basename2(path);
|
|
144339
|
+
if (name31.length <= max2)
|
|
144340
|
+
return name31;
|
|
144341
|
+
const ext = name31.match(/\.[^.]+$/)?.[0] ?? "";
|
|
144342
|
+
const stem = ext ? name31.slice(0, -ext.length) : name31;
|
|
144343
|
+
return `${stem.slice(0, Math.max(8, max2 - ext.length - 1))}…${ext}`;
|
|
144344
|
+
}
|
|
144345
|
+
function imageChipLabel(path, index2) {
|
|
144346
|
+
return `[image${index2 && index2 > 1 ? ` ${index2}` : ""}: ${shortName(path)}]`;
|
|
144347
|
+
}
|
|
144348
|
+
function escapeRegExp2(s2) {
|
|
144349
|
+
return s2.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
144350
|
+
}
|
|
144351
|
+
function replaceImagePathWithMarker(text2, path, marker16) {
|
|
144352
|
+
const raw = path;
|
|
144353
|
+
const file5 = `file://${raw}`;
|
|
144354
|
+
const escaped = raw.replace(/ /g, "\\ ");
|
|
144355
|
+
const candidates = [file5, raw, escaped];
|
|
144356
|
+
let out = text2;
|
|
144357
|
+
for (const c of candidates) {
|
|
144358
|
+
out = out.replace(new RegExp(`(["'])${escapeRegExp2(c)}\\1`, "g"), marker16);
|
|
144359
|
+
out = out.replace(new RegExp(escapeRegExp2(c), "g"), marker16);
|
|
144360
|
+
}
|
|
144361
|
+
return out;
|
|
144362
|
+
}
|
|
144124
144363
|
function imagePathsInText(text2, cwd2 = process.cwd(), limit = 6) {
|
|
144125
144364
|
const found = [];
|
|
144126
144365
|
const add2 = (rawMatch) => {
|
|
@@ -144146,8 +144385,7 @@ function imagePathsInText(text2, cwd2 = process.cwd(), limit = 6) {
|
|
|
144146
144385
|
}
|
|
144147
144386
|
function loadImageAttachment(path) {
|
|
144148
144387
|
const abs = isAbsolute2(path) ? path : resolve11(process.cwd(), path);
|
|
144149
|
-
const
|
|
144150
|
-
const mimeType = IMAGE_EXT[ext];
|
|
144388
|
+
const mimeType = imageMimeForPath(abs);
|
|
144151
144389
|
if (!mimeType)
|
|
144152
144390
|
throw new Error(`unsupported image type: ${path}`);
|
|
144153
144391
|
const size2 = statSync4(abs).size;
|
|
@@ -144168,7 +144406,7 @@ function imageContent(text2, images) {
|
|
|
144168
144406
|
init_capabilities();
|
|
144169
144407
|
|
|
144170
144408
|
// src/init.ts
|
|
144171
|
-
import { existsSync as existsSync10, readdirSync as readdirSync4, readFileSync as readFileSync15, writeFileSync as
|
|
144409
|
+
import { existsSync as existsSync10, readdirSync as readdirSync4, readFileSync as readFileSync15, writeFileSync as writeFileSync8 } from "node:fs";
|
|
144172
144410
|
import { join as join13 } from "node:path";
|
|
144173
144411
|
|
|
144174
144412
|
// src/verify.ts
|
|
@@ -144327,11 +144565,14 @@ function writeProjectGuide(cwd2 = process.cwd()) {
|
|
|
144327
144565
|
const path = join13(cwd2, "GEARBOX.md");
|
|
144328
144566
|
const before2 = existsSync10(path) ? readFileSync15(path, "utf8") : "";
|
|
144329
144567
|
const after2 = buildProjectGuide(cwd2);
|
|
144330
|
-
|
|
144568
|
+
writeFileSync8(path, after2, "utf8");
|
|
144331
144569
|
const diff2 = computeDiff(before2, after2);
|
|
144332
144570
|
return { path, summary: `wrote GEARBOX.md (${diffStat(diff2)})`, diff: diff2 };
|
|
144333
144571
|
}
|
|
144334
144572
|
|
|
144573
|
+
// src/ui/App.tsx
|
|
144574
|
+
init_mcp();
|
|
144575
|
+
|
|
144335
144576
|
// src/ui/clipboard.ts
|
|
144336
144577
|
init_proc();
|
|
144337
144578
|
function osc52(text2) {
|
|
@@ -144534,7 +144775,7 @@ function gitBranch() {
|
|
|
144534
144775
|
// src/ui/App.tsx
|
|
144535
144776
|
init_proc();
|
|
144536
144777
|
var jsx_dev_runtime12 = __toESM(require_jsx_dev_runtime(), 1);
|
|
144537
|
-
import { basename as
|
|
144778
|
+
import { basename as basename3, extname, resolve as resolve12 } from "node:path";
|
|
144538
144779
|
import { existsSync as existsSync11, readFileSync as readFileSync16, statSync as statSync5 } from "node:fs";
|
|
144539
144780
|
import { writeFile as fsWriteFile } from "node:fs/promises";
|
|
144540
144781
|
import { spawnSync as nodeSpawnSync2 } from "node:child_process";
|
|
@@ -144598,6 +144839,7 @@ function firstPath(text2) {
|
|
|
144598
144839
|
function uniq2(xs) {
|
|
144599
144840
|
return [...new Set(xs)];
|
|
144600
144841
|
}
|
|
144842
|
+
var CLAUDE_CLI_EFFORTS = ["low", "medium", "high", "max"];
|
|
144601
144843
|
var FALLBACK_CODEX_MODELS = [
|
|
144602
144844
|
{ id: "gpt-5.5", label: "gpt-5.5", provider: "codex", efforts: ["low", "medium", "high", "xhigh"] },
|
|
144603
144845
|
{ id: "gpt-5.4", label: "gpt-5.4", provider: "codex", efforts: ["low", "medium", "high", "xhigh"] },
|
|
@@ -144999,7 +145241,7 @@ function App2({ selector: initialSelector, runner, fullscreen = false, resumeId
|
|
|
144999
145241
|
return () => clearInterval(t2);
|
|
145000
145242
|
}, [busy]);
|
|
145001
145243
|
import_react26.useEffect(() => {
|
|
145002
|
-
const proj =
|
|
145244
|
+
const proj = basename3(process.cwd());
|
|
145003
145245
|
setTitle(busy ? `✳ ${proj} · working` : `${proj} · gearbox`);
|
|
145004
145246
|
}, [busy]);
|
|
145005
145247
|
const editRef = import_react26.useRef(edit2);
|
|
@@ -145029,6 +145271,7 @@ function App2({ selector: initialSelector, runner, fullscreen = false, resumeId
|
|
|
145029
145271
|
const activeCliModelRef = import_react26.useRef(undefined);
|
|
145030
145272
|
const cliSessionRef = import_react26.useRef(undefined);
|
|
145031
145273
|
const activeImagesRef = import_react26.useRef([]);
|
|
145274
|
+
const imageChipPathsRef = import_react26.useRef(new Map);
|
|
145032
145275
|
const accountStatusCacheRef = import_react26.useRef({});
|
|
145033
145276
|
const usedAccountRef = import_react26.useRef(null);
|
|
145034
145277
|
const cliMetaRef = import_react26.useRef(null);
|
|
@@ -145072,12 +145315,12 @@ function App2({ selector: initialSelector, runner, fullscreen = false, resumeId
|
|
|
145072
145315
|
}
|
|
145073
145316
|
}, []);
|
|
145074
145317
|
import_react26.useEffect(() => {
|
|
145075
|
-
setPermissionHandler((req) => new Promise((
|
|
145318
|
+
setPermissionHandler((req) => new Promise((resolve13) => {
|
|
145076
145319
|
if (modeRef.current === "auto-accept" && (req.kind === "write" || req.kind === "edit")) {
|
|
145077
|
-
|
|
145320
|
+
resolve13("once");
|
|
145078
145321
|
return;
|
|
145079
145322
|
}
|
|
145080
|
-
permQueue.current.push({ req, resolve:
|
|
145323
|
+
permQueue.current.push({ req, resolve: resolve13 });
|
|
145081
145324
|
pumpPerm();
|
|
145082
145325
|
}));
|
|
145083
145326
|
return () => setPermissionHandler(null);
|
|
@@ -145199,9 +145442,9 @@ function App2({ selector: initialSelector, runner, fullscreen = false, resumeId
|
|
|
145199
145442
|
const y = Number(m2[3]);
|
|
145200
145443
|
const up2 = m2[4] === "m";
|
|
145201
145444
|
if (b === 64)
|
|
145202
|
-
delta -=
|
|
145445
|
+
delta -= 1;
|
|
145203
145446
|
else if (b === 65)
|
|
145204
|
-
delta +=
|
|
145447
|
+
delta += 1;
|
|
145205
145448
|
else {
|
|
145206
145449
|
const off = composerOffset(x2, y);
|
|
145207
145450
|
const point = transcriptPoint(x2, y);
|
|
@@ -145210,9 +145453,9 @@ function App2({ selector: initialSelector, runner, fullscreen = false, resumeId
|
|
|
145210
145453
|
if (isPrimary && isDrag && transcriptMouseAnchorRef.current && !point) {
|
|
145211
145454
|
const bottom = viewportTop + transcriptHeightLiveRef.current - 1;
|
|
145212
145455
|
if (y < viewportTop)
|
|
145213
|
-
scrollBy(-
|
|
145456
|
+
scrollBy(-2);
|
|
145214
145457
|
else if (y > bottom)
|
|
145215
|
-
scrollBy(
|
|
145458
|
+
scrollBy(2);
|
|
145216
145459
|
const edgeLine = y < viewportTop ? scrollTopLiveRef.current : scrollTopLiveRef.current + transcriptHeightLiveRef.current - 1;
|
|
145217
145460
|
const edgeText = lineText(linesRef.current[edgeLine] ?? []);
|
|
145218
145461
|
setTranscriptSel({
|
|
@@ -145372,6 +145615,28 @@ function App2({ selector: initialSelector, runner, fullscreen = false, resumeId
|
|
|
145372
145615
|
transcriptSelectionRef.current = sel;
|
|
145373
145616
|
setTranscriptSelectionState(sel);
|
|
145374
145617
|
};
|
|
145618
|
+
const imageMarkerFor = (path) => {
|
|
145619
|
+
for (const [marker50, existing] of imageChipPathsRef.current) {
|
|
145620
|
+
if (existing === path)
|
|
145621
|
+
return marker50;
|
|
145622
|
+
}
|
|
145623
|
+
let idx = 1;
|
|
145624
|
+
let marker16 = imageChipLabel(path);
|
|
145625
|
+
while (imageChipPathsRef.current.has(marker16)) {
|
|
145626
|
+
idx++;
|
|
145627
|
+
marker16 = imageChipLabel(path, idx);
|
|
145628
|
+
}
|
|
145629
|
+
imageChipPathsRef.current.set(marker16, path);
|
|
145630
|
+
return marker16;
|
|
145631
|
+
};
|
|
145632
|
+
const chipImagePathsIn = (text2) => {
|
|
145633
|
+
const paths = [];
|
|
145634
|
+
for (const [marker16, path] of imageChipPathsRef.current) {
|
|
145635
|
+
if (text2.includes(marker16))
|
|
145636
|
+
paths.push(path);
|
|
145637
|
+
}
|
|
145638
|
+
return paths;
|
|
145639
|
+
};
|
|
145375
145640
|
const cliCatalogId = (binary) => binary.includes("codex") ? "codex-cli" : binary.includes("claude") ? "claude-cli" : "";
|
|
145376
145641
|
const cliModelChoices = (binary) => {
|
|
145377
145642
|
if (binary.includes("codex"))
|
|
@@ -145379,7 +145644,7 @@ function App2({ selector: initialSelector, runner, fullscreen = false, resumeId
|
|
|
145379
145644
|
const provider = binary.includes("claude") ? "anthropic" : binary;
|
|
145380
145645
|
return (catalogProvider(cliCatalogId(binary))?.defaultModels ?? []).map((id) => {
|
|
145381
145646
|
const m2 = findModel(id);
|
|
145382
|
-
return { id, label: m2?.label ?? id, provider, efforts: m2 ? effortLevels(m2) : undefined };
|
|
145647
|
+
return { id, label: m2?.label ?? id, provider, efforts: binary.includes("claude") ? CLAUDE_CLI_EFFORTS : m2 ? effortLevels(m2) : undefined };
|
|
145383
145648
|
});
|
|
145384
145649
|
};
|
|
145385
145650
|
const cliSupportsModel = (binary, modelId) => {
|
|
@@ -145443,7 +145708,7 @@ function App2({ selector: initialSelector, runner, fullscreen = false, resumeId
|
|
|
145443
145708
|
const take2 = (rows2) => rows2.filter((r2) => !q || `${r2.label} ${r2.detail ?? ""} ${r2.value}`.toLowerCase().includes(q)).slice(0, 7);
|
|
145444
145709
|
if (head2 === "/model") {
|
|
145445
145710
|
const cli = activeCliRef.current;
|
|
145446
|
-
const models = cli ? cliModelChoices(cli.binary) :
|
|
145711
|
+
const models = cli ? cliModelChoices(cli.binary) : modelRegistry();
|
|
145447
145712
|
return take2([
|
|
145448
145713
|
{ value: "/model auto", label: "auto", detail: cli ? "use subscription default" : "route per task" },
|
|
145449
145714
|
...models.map((m2) => ({ value: `/model ${m2.label}`, label: m2.label, detail: cli ? `${cli.binary} subscription` : `${m2.provider} · ${m2.id}` }))
|
|
@@ -145634,7 +145899,7 @@ function App2({ selector: initialSelector, runner, fullscreen = false, resumeId
|
|
|
145634
145899
|
const produced = r2.messages.slice(ctx.length);
|
|
145635
145900
|
const imageNote = activeImagesRef.current.length ? `
|
|
145636
145901
|
|
|
145637
|
-
[Attached images: ${activeImagesRef.current.map((img) =>
|
|
145902
|
+
[Attached images: ${activeImagesRef.current.map((img) => basename3(img.path)).join(", ")}]` : "";
|
|
145638
145903
|
const ledger = sanitizeToolPairs([...messages, { role: "user", content: prompt + imageNote }, ...produced]);
|
|
145639
145904
|
return { messages: ledger, usage: r2.usage };
|
|
145640
145905
|
}, []);
|
|
@@ -145721,28 +145986,34 @@ function App2({ selector: initialSelector, runner, fullscreen = false, resumeId
|
|
|
145721
145986
|
}
|
|
145722
145987
|
};
|
|
145723
145988
|
const runTurn = import_react26.useCallback(async (prompt) => {
|
|
145724
|
-
echo(prompt);
|
|
145725
|
-
lastPromptRef.current = prompt;
|
|
145726
145989
|
setVerb(nextVerb());
|
|
145727
145990
|
activeImagesRef.current = [];
|
|
145728
145991
|
let { text: modelPrompt, attached } = expandMentions(prompt);
|
|
145729
145992
|
if (attached.length)
|
|
145730
145993
|
notice(`attached ${attached.length} file${attached.length > 1 ? "s" : ""}: ${attached.join(", ")}`);
|
|
145731
|
-
const imagePaths = imagePathsInText(modelPrompt);
|
|
145994
|
+
const imagePaths = uniq2([...chipImagePathsIn(modelPrompt), ...imagePathsInText(modelPrompt)]);
|
|
145995
|
+
let displayPrompt = prompt;
|
|
145996
|
+
for (const path of imagePaths) {
|
|
145997
|
+
const marker16 = imageMarkerFor(path);
|
|
145998
|
+
modelPrompt = replaceImagePathWithMarker(modelPrompt, path, marker16);
|
|
145999
|
+
displayPrompt = replaceImagePathWithMarker(displayPrompt, path, marker16);
|
|
146000
|
+
}
|
|
145732
146001
|
const images = [];
|
|
145733
146002
|
for (const path of imagePaths) {
|
|
145734
146003
|
try {
|
|
145735
146004
|
images.push(loadImageAttachment(path));
|
|
145736
146005
|
} catch (e2) {
|
|
145737
|
-
notice(`couldn't attach ${path}: ${(e2?.message ?? String(e2)).split(`
|
|
146006
|
+
notice(`couldn't attach ${basename3(path)}: ${(e2?.message ?? String(e2)).split(`
|
|
145738
146007
|
`)[0]}`);
|
|
145739
146008
|
}
|
|
145740
146009
|
}
|
|
145741
146010
|
activeImagesRef.current = images;
|
|
145742
146011
|
if (images.length) {
|
|
145743
|
-
const names = images.map((img) =>
|
|
146012
|
+
const names = images.map((img) => imageMarkerFor(img.path)).join(", ");
|
|
145744
146013
|
notice(`attached ${images.length} image${images.length === 1 ? "" : "s"}: ${names}`);
|
|
145745
146014
|
}
|
|
146015
|
+
echo(displayPrompt);
|
|
146016
|
+
lastPromptRef.current = displayPrompt;
|
|
145746
146017
|
const urls = urlsInText(modelPrompt);
|
|
145747
146018
|
if (urls.length) {
|
|
145748
146019
|
const fetched = [];
|
|
@@ -146348,6 +146619,54 @@ ${fetched.join(`
|
|
|
146348
146619
|
}
|
|
146349
146620
|
return;
|
|
146350
146621
|
}
|
|
146622
|
+
case "mcp": {
|
|
146623
|
+
echo(text2);
|
|
146624
|
+
const parts = shellSplit(arg);
|
|
146625
|
+
const sub = (parts[0] ?? "list").toLowerCase();
|
|
146626
|
+
if (sub === "list" || sub === "servers") {
|
|
146627
|
+
notice(formatMcpConfigList());
|
|
146628
|
+
return;
|
|
146629
|
+
}
|
|
146630
|
+
if (sub === "tools") {
|
|
146631
|
+
notice("checking MCP servers…");
|
|
146632
|
+
mcpToolSummary().then(notice).catch((e2) => notice(`couldn't list MCP tools: ${e2?.message ?? String(e2)}`));
|
|
146633
|
+
return;
|
|
146634
|
+
}
|
|
146635
|
+
if (sub === "paths") {
|
|
146636
|
+
notice(mcpConfigPaths().join(`
|
|
146637
|
+
`));
|
|
146638
|
+
return;
|
|
146639
|
+
}
|
|
146640
|
+
if (sub === "add") {
|
|
146641
|
+
const global2 = parts[1] === "--global";
|
|
146642
|
+
const offset = global2 ? 2 : 1;
|
|
146643
|
+
const serverName = parts[offset] ?? "";
|
|
146644
|
+
const command = parts[offset + 1] ?? "";
|
|
146645
|
+
const commandArgs = parts.slice(offset + 2);
|
|
146646
|
+
try {
|
|
146647
|
+
notice(addMcpServer(serverName, command, commandArgs, { scope: global2 ? "global" : "project" }) + `
|
|
146648
|
+
Restarting is not required; new turns can use the tools.`);
|
|
146649
|
+
} catch (e2) {
|
|
146650
|
+
notice(`${e2?.message ?? String(e2)}
|
|
146651
|
+
Example: /mcp add github npx -y @modelcontextprotocol/server-github`);
|
|
146652
|
+
}
|
|
146653
|
+
return;
|
|
146654
|
+
}
|
|
146655
|
+
if (sub === "remove" || sub === "rm") {
|
|
146656
|
+
const global2 = parts[1] === "--global";
|
|
146657
|
+
const name50 = parts[global2 ? 2 : 1] ?? "";
|
|
146658
|
+
notice(removeMcpServer(name50, { scope: global2 ? "global" : undefined }));
|
|
146659
|
+
return;
|
|
146660
|
+
}
|
|
146661
|
+
notice(`MCP commands:
|
|
146662
|
+
` + ` /mcp list
|
|
146663
|
+
` + ` /mcp tools
|
|
146664
|
+
` + ` /mcp add <name> <command> [args...]
|
|
146665
|
+
` + ` /mcp add --global <name> <command> [args...]
|
|
146666
|
+
` + ` /mcp remove <name>
|
|
146667
|
+
` + " /mcp paths");
|
|
146668
|
+
return;
|
|
146669
|
+
}
|
|
146351
146670
|
case "accounts":
|
|
146352
146671
|
case "account": {
|
|
146353
146672
|
echo(text2);
|
|
@@ -146498,6 +146817,7 @@ ${fetched.join(`
|
|
|
146498
146817
|
` + ` /account add codex <name> a 2nd ChatGPT account, e.g. /account add codex work
|
|
146499
146818
|
` + ` /account add azure <foundry-endpoint> <api-key>
|
|
146500
146819
|
` + ` /account add azure <resource-name> <api-key> [api-version]
|
|
146820
|
+
` + ` /account add openai-compat <name> <base-url> <api-key> <model> [model...]
|
|
146501
146821
|
` + ` /account add <api-key> paste any provider key (auto-detected)
|
|
146502
146822
|
` + " /account add <provider> <api-key> e.g. anthropic, openai, openrouter");
|
|
146503
146823
|
return;
|
|
@@ -146509,6 +146829,10 @@ ${fetched.join(`
|
|
|
146509
146829
|
const azureKey = parts[3] ?? "";
|
|
146510
146830
|
const apiVersion = parts[4];
|
|
146511
146831
|
res = /^https?:\/\//i.test(resource) ? await addAzureFoundryAccount(resource, azureKey) : await addAzureAccount(resource, azureKey, { apiVersion });
|
|
146832
|
+
} else if (["openai-compat", "openai-compatible", "custom", "proxy"].includes(first)) {
|
|
146833
|
+
res = await addOpenAICompatAccount(parts[2] ?? "", parts[3] ?? "", parts[4] ?? "", parts.slice(5));
|
|
146834
|
+
} else if (catalogProvider(first)?.authKind === "openai-compat" && !catalogProvider(first)?.baseUrl && /^https?:\/\//i.test(parts[2] ?? "")) {
|
|
146835
|
+
res = await addOpenAICompatAccount(first, parts[2] ?? "", parts[3] ?? "", parts.slice(4));
|
|
146512
146836
|
} else if (provGiven)
|
|
146513
146837
|
res = await addApiKeyAccount(provGiven, keyVal);
|
|
146514
146838
|
else if (detectProviderByKey(key))
|
|
@@ -146577,7 +146901,7 @@ ${fetched.join(`
|
|
|
146577
146901
|
case "usage": {
|
|
146578
146902
|
echo(text2);
|
|
146579
146903
|
const accounts = listAccounts();
|
|
146580
|
-
const
|
|
146904
|
+
const resolve13 = (id) => {
|
|
146581
146905
|
const a = getAccount(id);
|
|
146582
146906
|
if (a) {
|
|
146583
146907
|
const bin = a.auth.kind === "cli" ? a.auth.binary : undefined;
|
|
@@ -146595,7 +146919,7 @@ ${fetched.join(`
|
|
|
146595
146919
|
const session = estimateCost(sessionRef.current.turns);
|
|
146596
146920
|
const withBalance = accounts.filter((a) => a.exec !== "cli" && balanceExposed(a.provider));
|
|
146597
146921
|
if (!withBalance.length) {
|
|
146598
|
-
pushUsage(buildUsageView(session,
|
|
146922
|
+
pushUsage(buildUsageView(session, resolve13, Date.now(), accounts.map((a) => a.id)));
|
|
146599
146923
|
return;
|
|
146600
146924
|
}
|
|
146601
146925
|
notice("checking balances…");
|
|
@@ -146605,7 +146929,7 @@ ${fetched.join(`
|
|
|
146605
146929
|
if (bal?.remainingUSD != null)
|
|
146606
146930
|
recordBalance(a.id, bal);
|
|
146607
146931
|
}
|
|
146608
|
-
pushUsage(buildUsageView(session,
|
|
146932
|
+
pushUsage(buildUsageView(session, resolve13, Date.now(), accounts.map((a) => a.id)));
|
|
146609
146933
|
})();
|
|
146610
146934
|
return;
|
|
146611
146935
|
}
|
|
@@ -146941,8 +147265,15 @@ ${fetched.join(`
|
|
|
146941
147265
|
if (!busyRef.current && input.length > 3 && !input.includes(`
|
|
146942
147266
|
`)) {
|
|
146943
147267
|
const p = sanitizeInputText(input).trim().replace(/^'|'$/g, "").replace(/\\ /g, " ");
|
|
146944
|
-
|
|
147268
|
+
const abs = p.startsWith("~") ? p.replace(/^~/, process.env.HOME ?? "~") : resolve12(process.cwd(), p);
|
|
147269
|
+
if (/[/\\.]/.test(p) && p.length < 1024 && existsSync11(abs)) {
|
|
146945
147270
|
const e2 = editRef.current;
|
|
147271
|
+
if (isImageFilePath(abs)) {
|
|
147272
|
+
const marker16 = imageMarkerFor(abs);
|
|
147273
|
+
setEdit({ value: e2.value.slice(0, e2.cursor) + marker16 + " " + e2.value.slice(e2.cursor), cursor: e2.cursor + marker16.length + 1 });
|
|
147274
|
+
flashStatus(`attached ${basename3(abs)}`);
|
|
147275
|
+
return;
|
|
147276
|
+
}
|
|
146946
147277
|
const ins = `@${p} `;
|
|
146947
147278
|
setEdit({ value: e2.value.slice(0, e2.cursor) + ins + e2.value.slice(e2.cursor), cursor: e2.cursor + ins.length });
|
|
146948
147279
|
return;
|
|
@@ -147297,7 +147628,7 @@ ${fetched.join(`
|
|
|
147297
147628
|
children: [
|
|
147298
147629
|
/* @__PURE__ */ jsx_dev_runtime12.jsxDEV(Banner, {
|
|
147299
147630
|
model: modelLabel,
|
|
147300
|
-
cwd:
|
|
147631
|
+
cwd: basename3(process.cwd()),
|
|
147301
147632
|
width
|
|
147302
147633
|
}, undefined, false, undefined, this),
|
|
147303
147634
|
welcome ? /* @__PURE__ */ jsx_dev_runtime12.jsxDEV(Box_default, {
|
|
@@ -147321,7 +147652,7 @@ ${fetched.join(`
|
|
|
147321
147652
|
}
|
|
147322
147653
|
const banner = /* @__PURE__ */ jsx_dev_runtime12.jsxDEV(Banner, {
|
|
147323
147654
|
model: modelLabel,
|
|
147324
|
-
cwd:
|
|
147655
|
+
cwd: basename3(process.cwd()),
|
|
147325
147656
|
width
|
|
147326
147657
|
}, undefined, false, undefined, this);
|
|
147327
147658
|
return /* @__PURE__ */ jsx_dev_runtime12.jsxDEV(Box_default, {
|
|
@@ -147353,7 +147684,7 @@ init_permission();
|
|
|
147353
147684
|
var jsx_dev_runtime13 = __toESM(require_jsx_dev_runtime(), 1);
|
|
147354
147685
|
process.env.LANG = process.env.LANG || "en_US.UTF-8";
|
|
147355
147686
|
process.env.LC_ALL = process.env.LC_ALL || "en_US.UTF-8";
|
|
147356
|
-
var VERSION16 = "0.1.
|
|
147687
|
+
var VERSION16 = "0.1.16";
|
|
147357
147688
|
var args = process.argv.slice(2);
|
|
147358
147689
|
var supportsAnsi = process.env.FORCE_COLOR === "1" || process.env.TERM !== "dumb" && process.env.NO_COLOR !== "1" && process.stdout.isTTY;
|
|
147359
147690
|
var ansi = (code) => supportsAnsi ? `\x1B[${code}m` : "";
|
|
@@ -147582,8 +147913,8 @@ async function readStdin() {
|
|
|
147582
147913
|
return input;
|
|
147583
147914
|
}
|
|
147584
147915
|
if (args[0] === "upgrade" || args[0] === "update") {
|
|
147585
|
-
const root2 =
|
|
147586
|
-
if (!existsSync12(
|
|
147916
|
+
const root2 = resolve13(import.meta.dir, "..");
|
|
147917
|
+
if (!existsSync12(resolve13(root2, ".git"))) {
|
|
147587
147918
|
console.log("This build can't self-update (not a git checkout).");
|
|
147588
147919
|
console.log("Update by pulling the repo and reinstalling: git pull && bun install");
|
|
147589
147920
|
process.exit(0);
|
|
@@ -147608,7 +147939,8 @@ Usage:
|
|
|
147608
147939
|
gearbox onboard set up a provider before opening the app
|
|
147609
147940
|
gearbox --model <name> start with a specific model
|
|
147610
147941
|
gearbox --continue resume the most recent session in this directory
|
|
147611
|
-
gearbox mcp list show configured MCP
|
|
147942
|
+
gearbox mcp list show configured MCP servers
|
|
147943
|
+
gearbox mcp add <name> <command> [args...]
|
|
147612
147944
|
gearbox doctor models show provider/model capability matrix
|
|
147613
147945
|
gearbox upgrade pull the latest version + reinstall deps
|
|
147614
147946
|
|
|
@@ -147625,11 +147957,12 @@ Set up at least one provider first:
|
|
|
147625
147957
|
gearbox onboard
|
|
147626
147958
|
gearbox auth add <api-key>
|
|
147627
147959
|
gearbox auth add <provider> <api-key>
|
|
147960
|
+
gearbox auth add openai-compat <name> <base-url> <api-key> <model>
|
|
147628
147961
|
gearbox auth add codex [name]
|
|
147629
147962
|
gearbox auth add claude [name]
|
|
147630
147963
|
gearbox auth import
|
|
147631
147964
|
|
|
147632
|
-
Models: ${
|
|
147965
|
+
Models: ${modelRegistry().map((m2) => m2.label).join(", ")}
|
|
147633
147966
|
In-app: / for commands, @ for files, !cmd for shell, shift+tab for plan mode.`);
|
|
147634
147967
|
process.exit(0);
|
|
147635
147968
|
}
|
|
@@ -147642,15 +147975,31 @@ if (args[0] === "onboard" || args[0] === "setup") {
|
|
|
147642
147975
|
process.exit(0);
|
|
147643
147976
|
}
|
|
147644
147977
|
if (args[0] === "mcp") {
|
|
147645
|
-
const { mcpToolSummary: mcpToolSummary2, mcpConfigPaths: mcpConfigPaths2 } = await Promise.resolve().then(() => (init_mcp(), exports_mcp));
|
|
147978
|
+
const { addMcpServer: addMcpServer2, formatMcpConfigList: formatMcpConfigList2, mcpToolSummary: mcpToolSummary2, mcpConfigPaths: mcpConfigPaths2, removeMcpServer: removeMcpServer2 } = await Promise.resolve().then(() => (init_mcp(), exports_mcp));
|
|
147646
147979
|
const sub = args[1] ?? "list";
|
|
147647
147980
|
if (sub === "list" || sub === "tools") {
|
|
147648
|
-
|
|
147981
|
+
if (sub === "tools")
|
|
147982
|
+
console.log(await mcpToolSummary2());
|
|
147983
|
+
else
|
|
147984
|
+
console.log(formatMcpConfigList2());
|
|
147649
147985
|
} else if (sub === "paths") {
|
|
147650
147986
|
console.log(mcpConfigPaths2().join(`
|
|
147651
147987
|
`));
|
|
147988
|
+
} else if (sub === "add") {
|
|
147989
|
+
const global2 = args[2] === "--global";
|
|
147990
|
+
const offset = global2 ? 3 : 2;
|
|
147991
|
+
try {
|
|
147992
|
+
console.log(addMcpServer2(args[offset] ?? "", args[offset + 1] ?? "", args.slice(offset + 2), { scope: global2 ? "global" : "project" }));
|
|
147993
|
+
} catch (e2) {
|
|
147994
|
+
console.log(e2?.message ?? String(e2));
|
|
147995
|
+
console.log("example: gearbox mcp add github npx -y @modelcontextprotocol/server-github");
|
|
147996
|
+
process.exit(1);
|
|
147997
|
+
}
|
|
147998
|
+
} else if (sub === "remove" || sub === "rm") {
|
|
147999
|
+
const global2 = args[2] === "--global";
|
|
148000
|
+
console.log(removeMcpServer2(args[global2 ? 3 : 2] ?? "", { scope: global2 ? "global" : undefined }));
|
|
147652
148001
|
} else {
|
|
147653
|
-
console.log("gearbox mcp [list|paths]");
|
|
148002
|
+
console.log("gearbox mcp [list|tools|paths|add <name> <command> [args...]|remove <name>]");
|
|
147654
148003
|
}
|
|
147655
148004
|
process.exit(0);
|
|
147656
148005
|
}
|
|
@@ -147667,7 +148016,7 @@ if (args[0] === "doctor") {
|
|
|
147667
148016
|
if (args[0] === "auth") {
|
|
147668
148017
|
const { listAccounts: listAccounts2, loadAccounts: loadAccounts3, removeAccount: removeAccount2 } = await Promise.resolve().then(() => (init_store(), exports_store));
|
|
147669
148018
|
const { importableEnvCreds: importableEnvCreds2, importEnvCred: importEnvCred2, importableCloudCreds: importableCloudCreds2, importCloudCred: importCloudCred2 } = await Promise.resolve().then(() => (init_detect(), exports_detect));
|
|
147670
|
-
const { addApiKeyAccount: addApiKeyAccount2, addByPastedKey: addByPastedKey2, testAccount: testAccount2, addableProviders: addableProviders2, addCliAccount: addCliAccount2, cliAuthStatus: cliAuthStatus2, cliLoginArgs: cliLoginArgs2 } = await Promise.resolve().then(() => (init_onboard(), exports_onboard));
|
|
148019
|
+
const { addApiKeyAccount: addApiKeyAccount2, addByPastedKey: addByPastedKey2, addOpenAICompatAccount: addOpenAICompatAccount2, testAccount: testAccount2, addableProviders: addableProviders2, addCliAccount: addCliAccount2, cliAuthStatus: cliAuthStatus2, cliLoginArgs: cliLoginArgs2 } = await Promise.resolve().then(() => (init_onboard(), exports_onboard));
|
|
147671
148020
|
const { subscriptionEnv: subscriptionEnv2 } = await Promise.resolve().then(() => (init_cli_backend(), exports_cli_backend));
|
|
147672
148021
|
const { detectProviderByKey: detectProviderByKey2 } = await Promise.resolve().then(() => (init_catalog(), exports_catalog));
|
|
147673
148022
|
const sub = args[1];
|
|
@@ -147694,7 +148043,7 @@ Importable from your env (gearbox auth import): ${imp.map((c) => c.envVar).join(
|
|
|
147694
148043
|
} else if (sub === "add") {
|
|
147695
148044
|
const head2 = (rest2[0] ?? "").toLowerCase();
|
|
147696
148045
|
const cliProvider = head2 === "codex" || head2 === "chatgpt" ? "codex-cli" : head2 === "claude" ? "claude-cli" : "";
|
|
147697
|
-
const res = cliProvider ? addCliAccount2(cliProvider, rest2.slice(1).join(" ").trim() || undefined) : 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> | gearbox auth add codex [name]" };
|
|
148046
|
+
const res = cliProvider ? addCliAccount2(cliProvider, rest2.slice(1).join(" ").trim() || undefined) : ["openai-compat", "openai-compatible", "custom", "proxy"].includes(head2) ? await addOpenAICompatAccount2(rest2[1] ?? "", rest2[2] ?? "", rest2[3] ?? "", rest2.slice(4)) : 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> | gearbox auth add openai-compat <name> <base-url> <key> <model> | gearbox auth add codex [name]" };
|
|
147698
148047
|
console.log(res.message);
|
|
147699
148048
|
if (res.ok && res.account) {
|
|
147700
148049
|
if (res.account.exec === "cli" && res.account.auth.kind === "cli") {
|
package/package.json
CHANGED