gearbox-code 0.2.3 → 0.2.5
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 +482 -288
- package/package.json +1 -1
package/dist/cli.mjs
CHANGED
|
@@ -138748,7 +138748,7 @@ var COMMANDS = [
|
|
|
138748
138748
|
{ name: "/retry", usage: "/retry", desc: "send your last message again", group: "chat" },
|
|
138749
138749
|
{ name: "/compact", usage: "/compact", desc: "shrink the conversation to free up room", group: "chat" },
|
|
138750
138750
|
{ name: "/context", usage: "/context", desc: "see what's loaded and how many tokens it uses", group: "chat" },
|
|
138751
|
-
{ name: "/ask", usage: "/ask <q>", desc: "ask about Gearbox itself
|
|
138751
|
+
{ name: "/ask", usage: "/ask <q>", desc: "ask about Gearbox itself · answered from its own docs", group: "chat" },
|
|
138752
138752
|
{ name: "/memory", usage: "/memory [note]", desc: "show or add facts to remember (or start a line with #)", group: "chat" },
|
|
138753
138753
|
{ name: "/account", usage: "/account", desc: "list accounts; /account <name> switches, /account login <name> re-auths, /account add adds one", group: "accounts" },
|
|
138754
138754
|
{ name: "/onboard", usage: "/onboard", desc: "first-run setup; provider list and import/add commands", group: "accounts" },
|
|
@@ -138853,10 +138853,10 @@ function formatAccounts(accounts, activeCliId, importable, statuses = {}) {
|
|
|
138853
138853
|
lines.push(` ${st.detail}`);
|
|
138854
138854
|
});
|
|
138855
138855
|
if (!activeCliId)
|
|
138856
|
-
lines.push("", " no subscription active
|
|
138856
|
+
lines.push("", " no subscription active · your API keys auto-route per task");
|
|
138857
138857
|
}
|
|
138858
138858
|
if (importable.length) {
|
|
138859
|
-
lines.push("", "found in your environment
|
|
138859
|
+
lines.push("", "found in your environment · /account import to add:");
|
|
138860
138860
|
for (const c of importable)
|
|
138861
138861
|
lines.push(` + ${c.label} (${c.envVar})`);
|
|
138862
138862
|
}
|
|
@@ -138936,16 +138936,16 @@ function formatModelList(currentId, showAll = false) {
|
|
|
138936
138936
|
rows.push(line(m2));
|
|
138937
138937
|
}
|
|
138938
138938
|
if (hidden)
|
|
138939
|
-
rows.push(` + ${hidden} more on your accounts
|
|
138939
|
+
rows.push(` + ${hidden} more on your accounts · /model all to list · /model <name> to pick`);
|
|
138940
138940
|
} else {
|
|
138941
|
-
rows.push("", "no accounts yet
|
|
138941
|
+
rows.push("", "no accounts yet · /account to add one");
|
|
138942
138942
|
}
|
|
138943
138943
|
if (showAll && rest2.length) {
|
|
138944
138944
|
rows.push("", "needs an account");
|
|
138945
138945
|
for (const m2 of rest2)
|
|
138946
138946
|
rows.push(` ${glyph.off} ${m2.label.padEnd(18)} ${m2.provider}`);
|
|
138947
138947
|
} else if (rest2.length) {
|
|
138948
|
-
rows.push("", ` + ${rest2.length} more once you add a key
|
|
138948
|
+
rows.push("", ` + ${rest2.length} more once you add a key · /model all to list · /account to add one`);
|
|
138949
138949
|
}
|
|
138950
138950
|
return rows.join(`
|
|
138951
138951
|
`);
|
|
@@ -138957,20 +138957,20 @@ function resolveModelSwitch(query) {
|
|
|
138957
138957
|
const MODELS2 = modelRegistry();
|
|
138958
138958
|
const matches2 = MODELS2.filter((m3) => m3.label.toLowerCase().includes(q) || m3.id.toLowerCase().includes(q));
|
|
138959
138959
|
if (matches2.length === 0)
|
|
138960
|
-
return { ok: false, message: `no model matching “${query}”
|
|
138960
|
+
return { ok: false, message: `no model matching “${query}” · /model to list` };
|
|
138961
138961
|
const exact = matches2.find((m3) => m3.label.toLowerCase() === q || m3.id.toLowerCase() === q);
|
|
138962
138962
|
const available = matches2.filter((m3) => providerAvailable(m3.provider));
|
|
138963
138963
|
if (exact) {
|
|
138964
138964
|
if (!providerAvailable(exact.provider))
|
|
138965
|
-
return { ok: false, message: `${exact.label}: no ${exact.provider} account yet
|
|
138965
|
+
return { ok: false, message: `${exact.label}: no ${exact.provider} account yet · /account add ${exact.provider} <key> or set ${envHint(exact.provider)}` };
|
|
138966
138966
|
return { ok: true, modelId: exact.id, message: `model → ${exact.label}` };
|
|
138967
138967
|
}
|
|
138968
138968
|
if (available.length === 0) {
|
|
138969
138969
|
const m3 = matches2[0];
|
|
138970
|
-
return { ok: false, message: `“${query}” matches ${m3.label} but no account for ${m3.provider}
|
|
138970
|
+
return { ok: false, message: `“${query}” matches ${m3.label} but no account for ${m3.provider} · /accounts add ${m3.provider} <key> or set ${envHint(m3.provider)}` };
|
|
138971
138971
|
}
|
|
138972
138972
|
if (available.length > 1) {
|
|
138973
|
-
return { ok: false, message: `“${query}” matches ${available.map((m3) => m3.label).join(", ")}
|
|
138973
|
+
return { ok: false, message: `“${query}” matches ${available.map((m3) => m3.label).join(", ")} · be more specific` };
|
|
138974
138974
|
}
|
|
138975
138975
|
const m2 = available[0];
|
|
138976
138976
|
return { ok: true, modelId: m2.id, message: `model → ${m2.label}` };
|
|
@@ -140309,8 +140309,139 @@ function StatusBar({
|
|
|
140309
140309
|
}, undefined, true, undefined, this);
|
|
140310
140310
|
}
|
|
140311
140311
|
|
|
140312
|
-
// src/ui/components/
|
|
140312
|
+
// src/ui/components/StatusStrip.tsx
|
|
140313
140313
|
var jsx_dev_runtime5 = __toESM(require_jsx_dev_runtime(), 1);
|
|
140314
|
+
function bar(leftPct, cells = 12) {
|
|
140315
|
+
const filled = Math.max(0, Math.min(cells, Math.round(leftPct / 100 * cells)));
|
|
140316
|
+
return "█".repeat(filled) + "░".repeat(cells - filled);
|
|
140317
|
+
}
|
|
140318
|
+
function fmtTok2(n) {
|
|
140319
|
+
return n >= 1000 ? `${(n / 1000).toFixed(1)}k` : String(n);
|
|
140320
|
+
}
|
|
140321
|
+
function StatusStrip({
|
|
140322
|
+
ctxPct,
|
|
140323
|
+
tokens,
|
|
140324
|
+
contextWindow,
|
|
140325
|
+
cost,
|
|
140326
|
+
sub,
|
|
140327
|
+
api: api2,
|
|
140328
|
+
width
|
|
140329
|
+
}) {
|
|
140330
|
+
const Row2 = ({ label, children }) => /* @__PURE__ */ jsx_dev_runtime5.jsxDEV(Text, {
|
|
140331
|
+
children: [
|
|
140332
|
+
/* @__PURE__ */ jsx_dev_runtime5.jsxDEV(Text, {
|
|
140333
|
+
color: color.faint,
|
|
140334
|
+
children: [
|
|
140335
|
+
label.padEnd(8),
|
|
140336
|
+
" "
|
|
140337
|
+
]
|
|
140338
|
+
}, undefined, true, undefined, this),
|
|
140339
|
+
children
|
|
140340
|
+
]
|
|
140341
|
+
}, undefined, true, undefined, this);
|
|
140342
|
+
return /* @__PURE__ */ jsx_dev_runtime5.jsxDEV(Box_default, {
|
|
140343
|
+
width,
|
|
140344
|
+
flexDirection: "column",
|
|
140345
|
+
paddingX: 1,
|
|
140346
|
+
marginTop: 1,
|
|
140347
|
+
children: [
|
|
140348
|
+
/* @__PURE__ */ jsx_dev_runtime5.jsxDEV(Box_default, {
|
|
140349
|
+
justifyContent: "space-between",
|
|
140350
|
+
children: [
|
|
140351
|
+
/* @__PURE__ */ jsx_dev_runtime5.jsxDEV(Text, {
|
|
140352
|
+
color: color.accent,
|
|
140353
|
+
bold: true,
|
|
140354
|
+
children: "usage"
|
|
140355
|
+
}, undefined, false, undefined, this),
|
|
140356
|
+
/* @__PURE__ */ jsx_dev_runtime5.jsxDEV(Text, {
|
|
140357
|
+
color: color.faint,
|
|
140358
|
+
children: "/cost to hide"
|
|
140359
|
+
}, undefined, false, undefined, this)
|
|
140360
|
+
]
|
|
140361
|
+
}, undefined, true, undefined, this),
|
|
140362
|
+
ctxPct != null ? /* @__PURE__ */ jsx_dev_runtime5.jsxDEV(Row2, {
|
|
140363
|
+
label: "context",
|
|
140364
|
+
children: [
|
|
140365
|
+
/* @__PURE__ */ jsx_dev_runtime5.jsxDEV(Text, {
|
|
140366
|
+
color: color.text,
|
|
140367
|
+
children: [
|
|
140368
|
+
100 - ctxPct,
|
|
140369
|
+
"% left"
|
|
140370
|
+
]
|
|
140371
|
+
}, undefined, true, undefined, this),
|
|
140372
|
+
/* @__PURE__ */ jsx_dev_runtime5.jsxDEV(Text, {
|
|
140373
|
+
color: color.faint,
|
|
140374
|
+
children: [
|
|
140375
|
+
" · ",
|
|
140376
|
+
fmtTok2(tokens),
|
|
140377
|
+
contextWindow ? ` / ${fmtTok2(contextWindow)}` : ""
|
|
140378
|
+
]
|
|
140379
|
+
}, undefined, true, undefined, this)
|
|
140380
|
+
]
|
|
140381
|
+
}, undefined, true, undefined, this) : null,
|
|
140382
|
+
sub?.limits?.map((l) => /* @__PURE__ */ jsx_dev_runtime5.jsxDEV(Row2, {
|
|
140383
|
+
label: l.label,
|
|
140384
|
+
children: [
|
|
140385
|
+
/* @__PURE__ */ jsx_dev_runtime5.jsxDEV(Text, {
|
|
140386
|
+
color: l.pct >= 90 ? color.err : color.accentDim,
|
|
140387
|
+
children: bar(100 - l.pct)
|
|
140388
|
+
}, undefined, false, undefined, this),
|
|
140389
|
+
/* @__PURE__ */ jsx_dev_runtime5.jsxDEV(Text, {
|
|
140390
|
+
color: l.pct >= 90 ? color.err : color.text,
|
|
140391
|
+
children: [
|
|
140392
|
+
" ",
|
|
140393
|
+
100 - l.pct,
|
|
140394
|
+
"% left"
|
|
140395
|
+
]
|
|
140396
|
+
}, undefined, true, undefined, this),
|
|
140397
|
+
l.resetsIn ? /* @__PURE__ */ jsx_dev_runtime5.jsxDEV(Text, {
|
|
140398
|
+
color: color.faint,
|
|
140399
|
+
children: [
|
|
140400
|
+
" · ",
|
|
140401
|
+
l.resetsIn
|
|
140402
|
+
]
|
|
140403
|
+
}, undefined, true, undefined, this) : null
|
|
140404
|
+
]
|
|
140405
|
+
}, l.label, true, undefined, this)),
|
|
140406
|
+
sub && !sub.limits?.length ? /* @__PURE__ */ jsx_dev_runtime5.jsxDEV(Row2, {
|
|
140407
|
+
label: "limits",
|
|
140408
|
+
children: /* @__PURE__ */ jsx_dev_runtime5.jsxDEV(Text, {
|
|
140409
|
+
color: color.faint,
|
|
140410
|
+
children: sub.limitNote ?? "not reported yet"
|
|
140411
|
+
}, undefined, false, undefined, this)
|
|
140412
|
+
}, undefined, false, undefined, this) : null,
|
|
140413
|
+
api2?.spend ? /* @__PURE__ */ jsx_dev_runtime5.jsxDEV(Row2, {
|
|
140414
|
+
label: api2.name.slice(0, 8),
|
|
140415
|
+
children: [
|
|
140416
|
+
/* @__PURE__ */ jsx_dev_runtime5.jsxDEV(Text, {
|
|
140417
|
+
color: api2.spendPos ? color.ok : color.faint,
|
|
140418
|
+
children: api2.spend
|
|
140419
|
+
}, undefined, false, undefined, this),
|
|
140420
|
+
api2.balanceLeft ? /* @__PURE__ */ jsx_dev_runtime5.jsxDEV(Text, {
|
|
140421
|
+
color: color.faint,
|
|
140422
|
+
children: [
|
|
140423
|
+
" · ",
|
|
140424
|
+
api2.balanceLeft
|
|
140425
|
+
]
|
|
140426
|
+
}, undefined, true, undefined, this) : null
|
|
140427
|
+
]
|
|
140428
|
+
}, undefined, true, undefined, this) : null,
|
|
140429
|
+
/* @__PURE__ */ jsx_dev_runtime5.jsxDEV(Row2, {
|
|
140430
|
+
label: "session",
|
|
140431
|
+
children: /* @__PURE__ */ jsx_dev_runtime5.jsxDEV(Text, {
|
|
140432
|
+
color: cost >= 0.005 ? color.text : color.faint,
|
|
140433
|
+
children: [
|
|
140434
|
+
"$",
|
|
140435
|
+
cost.toFixed(2)
|
|
140436
|
+
]
|
|
140437
|
+
}, undefined, true, undefined, this)
|
|
140438
|
+
}, undefined, false, undefined, this)
|
|
140439
|
+
]
|
|
140440
|
+
}, undefined, true, undefined, this);
|
|
140441
|
+
}
|
|
140442
|
+
|
|
140443
|
+
// src/ui/components/CommandPalette.tsx
|
|
140444
|
+
var jsx_dev_runtime6 = __toESM(require_jsx_dev_runtime(), 1);
|
|
140314
140445
|
function windowed(items, selected, limit) {
|
|
140315
140446
|
const count = Math.max(1, limit);
|
|
140316
140447
|
const safeSelected = Math.max(0, Math.min(selected, Math.max(items.length - 1, 0)));
|
|
@@ -140328,13 +140459,13 @@ function CommandPalette({ draft, selected = 0, limit = 5, rows, width = 80 }) {
|
|
|
140328
140459
|
const rowWidth = Math.max(20, width - 2);
|
|
140329
140460
|
if (rows?.length) {
|
|
140330
140461
|
const shown2 = windowed(rows, selected, limit);
|
|
140331
|
-
return /* @__PURE__ */
|
|
140462
|
+
return /* @__PURE__ */ jsx_dev_runtime6.jsxDEV(Box_default, {
|
|
140332
140463
|
flexDirection: "column",
|
|
140333
140464
|
paddingX: 1,
|
|
140334
140465
|
marginTop: 1,
|
|
140335
140466
|
children: shown2.rows.map((r2, i2) => {
|
|
140336
140467
|
const active = shown2.start + i2 === selected;
|
|
140337
|
-
return /* @__PURE__ */
|
|
140468
|
+
return /* @__PURE__ */ jsx_dev_runtime6.jsxDEV(Text, {
|
|
140338
140469
|
color: active ? color.text : color.dim,
|
|
140339
140470
|
bold: active,
|
|
140340
140471
|
backgroundColor: active ? color.accentBg : undefined,
|
|
@@ -140347,13 +140478,13 @@ function CommandPalette({ draft, selected = 0, limit = 5, rows, width = 80 }) {
|
|
|
140347
140478
|
if (matches2.length === 0)
|
|
140348
140479
|
return null;
|
|
140349
140480
|
const shown = windowed(matches2, selected, limit);
|
|
140350
|
-
return /* @__PURE__ */
|
|
140481
|
+
return /* @__PURE__ */ jsx_dev_runtime6.jsxDEV(Box_default, {
|
|
140351
140482
|
flexDirection: "column",
|
|
140352
140483
|
paddingX: 1,
|
|
140353
140484
|
marginTop: 1,
|
|
140354
140485
|
children: shown.rows.map((c, i2) => {
|
|
140355
140486
|
const active = shown.start + i2 === selected;
|
|
140356
|
-
return /* @__PURE__ */
|
|
140487
|
+
return /* @__PURE__ */ jsx_dev_runtime6.jsxDEV(Text, {
|
|
140357
140488
|
color: active ? color.text : color.dim,
|
|
140358
140489
|
bold: active,
|
|
140359
140490
|
backgroundColor: active ? color.accentBg : undefined,
|
|
@@ -140364,7 +140495,7 @@ function CommandPalette({ draft, selected = 0, limit = 5, rows, width = 80 }) {
|
|
|
140364
140495
|
}
|
|
140365
140496
|
|
|
140366
140497
|
// src/ui/components/FilePalette.tsx
|
|
140367
|
-
var
|
|
140498
|
+
var jsx_dev_runtime7 = __toESM(require_jsx_dev_runtime(), 1);
|
|
140368
140499
|
function windowed2(items, selected, limit) {
|
|
140369
140500
|
const count = Math.max(1, limit);
|
|
140370
140501
|
const safeSelected = Math.max(0, Math.min(selected, Math.max(items.length - 1, 0)));
|
|
@@ -140377,12 +140508,12 @@ function FilePalette({ matches: matches2, selected = 0, limit = 5, width = 80 })
|
|
|
140377
140508
|
const rowWidth = Math.max(20, width - 2);
|
|
140378
140509
|
if (shown.rows.length === 0)
|
|
140379
140510
|
return null;
|
|
140380
|
-
return /* @__PURE__ */
|
|
140511
|
+
return /* @__PURE__ */ jsx_dev_runtime7.jsxDEV(Box_default, {
|
|
140381
140512
|
flexDirection: "column",
|
|
140382
140513
|
paddingX: 1,
|
|
140383
140514
|
marginTop: 1,
|
|
140384
140515
|
children: [
|
|
140385
|
-
/* @__PURE__ */
|
|
140516
|
+
/* @__PURE__ */ jsx_dev_runtime7.jsxDEV(Text, {
|
|
140386
140517
|
color: color.faint,
|
|
140387
140518
|
children: "@ files · tab to complete"
|
|
140388
140519
|
}, undefined, false, undefined, this),
|
|
@@ -140390,7 +140521,7 @@ function FilePalette({ matches: matches2, selected = 0, limit = 5, width = 80 })
|
|
|
140390
140521
|
const active = shown.start + i2 === selected;
|
|
140391
140522
|
const raw = `${active ? `${glyph.on} ` : " "}${f3}`;
|
|
140392
140523
|
const text = raw.length > rowWidth ? raw.slice(0, Math.max(0, rowWidth - 1)) + "…" : raw.padEnd(rowWidth);
|
|
140393
|
-
return /* @__PURE__ */
|
|
140524
|
+
return /* @__PURE__ */ jsx_dev_runtime7.jsxDEV(Text, {
|
|
140394
140525
|
color: active ? color.text : color.faint,
|
|
140395
140526
|
bold: active,
|
|
140396
140527
|
backgroundColor: active ? color.accentBg : undefined,
|
|
@@ -140669,7 +140800,7 @@ function applyMouse(s2, click) {
|
|
|
140669
140800
|
}
|
|
140670
140801
|
|
|
140671
140802
|
// src/ui/components/Composer.tsx
|
|
140672
|
-
var
|
|
140803
|
+
var jsx_dev_runtime8 = __toESM(require_jsx_dev_runtime(), 1);
|
|
140673
140804
|
function Composer({
|
|
140674
140805
|
value,
|
|
140675
140806
|
cursor,
|
|
@@ -140701,15 +140832,15 @@ function Composer({
|
|
|
140701
140832
|
const cursorHere = line === curLine;
|
|
140702
140833
|
if (!hasSel) {
|
|
140703
140834
|
if (!cursorHere)
|
|
140704
|
-
return /* @__PURE__ */
|
|
140835
|
+
return /* @__PURE__ */ jsx_dev_runtime8.jsxDEV(Text, {
|
|
140705
140836
|
backgroundColor: color.panelBg,
|
|
140706
140837
|
children: ln
|
|
140707
140838
|
}, undefined, false, undefined, this);
|
|
140708
|
-
return /* @__PURE__ */
|
|
140839
|
+
return /* @__PURE__ */ jsx_dev_runtime8.jsxDEV(Text, {
|
|
140709
140840
|
backgroundColor: color.panelBg,
|
|
140710
140841
|
children: [
|
|
140711
140842
|
ln.slice(0, curCol),
|
|
140712
|
-
/* @__PURE__ */
|
|
140843
|
+
/* @__PURE__ */ jsx_dev_runtime8.jsxDEV(Text, {
|
|
140713
140844
|
inverse: true,
|
|
140714
140845
|
backgroundColor: color.panelBg,
|
|
140715
140846
|
children: ln[curCol] ?? " "
|
|
@@ -140718,11 +140849,11 @@ function Composer({
|
|
|
140718
140849
|
]
|
|
140719
140850
|
}, undefined, true, undefined, this);
|
|
140720
140851
|
}
|
|
140721
|
-
return /* @__PURE__ */
|
|
140852
|
+
return /* @__PURE__ */ jsx_dev_runtime8.jsxDEV(Text, {
|
|
140722
140853
|
backgroundColor: color.panelBg,
|
|
140723
140854
|
children: [
|
|
140724
140855
|
ln.slice(0, selStart),
|
|
140725
|
-
/* @__PURE__ */
|
|
140856
|
+
/* @__PURE__ */ jsx_dev_runtime8.jsxDEV(Text, {
|
|
140726
140857
|
inverse: true,
|
|
140727
140858
|
children: ln.slice(selStart, selEnd)
|
|
140728
140859
|
}, undefined, false, undefined, this),
|
|
@@ -140730,34 +140861,34 @@ function Composer({
|
|
|
140730
140861
|
]
|
|
140731
140862
|
}, undefined, true, undefined, this);
|
|
140732
140863
|
};
|
|
140733
|
-
return /* @__PURE__ */
|
|
140864
|
+
return /* @__PURE__ */ jsx_dev_runtime8.jsxDEV(Box_default, {
|
|
140734
140865
|
flexDirection: "column",
|
|
140735
140866
|
width,
|
|
140736
140867
|
marginTop: 1,
|
|
140737
140868
|
children: [
|
|
140738
|
-
/* @__PURE__ */
|
|
140869
|
+
/* @__PURE__ */ jsx_dev_runtime8.jsxDEV(Box_default, {
|
|
140739
140870
|
paddingX: 1,
|
|
140740
|
-
children: vim !== "off" ? /* @__PURE__ */
|
|
140871
|
+
children: vim !== "off" ? /* @__PURE__ */ jsx_dev_runtime8.jsxDEV(jsx_dev_runtime8.Fragment, {
|
|
140741
140872
|
children: [
|
|
140742
|
-
/* @__PURE__ */
|
|
140873
|
+
/* @__PURE__ */ jsx_dev_runtime8.jsxDEV(Text, {
|
|
140743
140874
|
color: vim === "normal" ? color.accent : color.dim,
|
|
140744
140875
|
bold: true,
|
|
140745
140876
|
children: vim === "normal" ? " NORMAL " : " INSERT "
|
|
140746
140877
|
}, undefined, false, undefined, this),
|
|
140747
|
-
/* @__PURE__ */
|
|
140878
|
+
/* @__PURE__ */ jsx_dev_runtime8.jsxDEV(Text, {
|
|
140748
140879
|
color: color.faint,
|
|
140749
140880
|
children: glyph.rule.repeat(Math.max(width - 11, 4))
|
|
140750
140881
|
}, undefined, false, undefined, this)
|
|
140751
140882
|
]
|
|
140752
|
-
}, undefined, true, undefined, this) : /* @__PURE__ */
|
|
140883
|
+
}, undefined, true, undefined, this) : /* @__PURE__ */ jsx_dev_runtime8.jsxDEV(Text, {
|
|
140753
140884
|
color: color.faint,
|
|
140754
140885
|
children: glyph.rule.repeat(Math.max(width - 2, 8))
|
|
140755
140886
|
}, undefined, false, undefined, this)
|
|
140756
140887
|
}, undefined, false, undefined, this),
|
|
140757
|
-
busy ? /* @__PURE__ */
|
|
140888
|
+
busy ? /* @__PURE__ */ jsx_dev_runtime8.jsxDEV(Box_default, {
|
|
140758
140889
|
paddingX: 1,
|
|
140759
140890
|
children: [
|
|
140760
|
-
/* @__PURE__ */
|
|
140891
|
+
/* @__PURE__ */ jsx_dev_runtime8.jsxDEV(Text, {
|
|
140761
140892
|
color: color.faint,
|
|
140762
140893
|
bold: true,
|
|
140763
140894
|
backgroundColor: color.panelBg,
|
|
@@ -140766,16 +140897,16 @@ function Composer({
|
|
|
140766
140897
|
" "
|
|
140767
140898
|
]
|
|
140768
140899
|
}, undefined, true, undefined, this),
|
|
140769
|
-
/* @__PURE__ */
|
|
140900
|
+
/* @__PURE__ */ jsx_dev_runtime8.jsxDEV(Text, {
|
|
140770
140901
|
color: color.faint,
|
|
140771
140902
|
backgroundColor: color.panelBg,
|
|
140772
140903
|
children: value || "…"
|
|
140773
140904
|
}, undefined, false, undefined, this)
|
|
140774
140905
|
]
|
|
140775
|
-
}, undefined, true, undefined, this) : value === "" ? /* @__PURE__ */
|
|
140906
|
+
}, undefined, true, undefined, this) : value === "" ? /* @__PURE__ */ jsx_dev_runtime8.jsxDEV(Box_default, {
|
|
140776
140907
|
paddingX: 1,
|
|
140777
140908
|
children: [
|
|
140778
|
-
/* @__PURE__ */
|
|
140909
|
+
/* @__PURE__ */ jsx_dev_runtime8.jsxDEV(Text, {
|
|
140779
140910
|
color: color.accent,
|
|
140780
140911
|
bold: true,
|
|
140781
140912
|
backgroundColor: color.panelBg,
|
|
@@ -140784,23 +140915,23 @@ function Composer({
|
|
|
140784
140915
|
" "
|
|
140785
140916
|
]
|
|
140786
140917
|
}, undefined, true, undefined, this),
|
|
140787
|
-
/* @__PURE__ */
|
|
140918
|
+
/* @__PURE__ */ jsx_dev_runtime8.jsxDEV(Text, {
|
|
140788
140919
|
inverse: true,
|
|
140789
140920
|
backgroundColor: color.panelBg,
|
|
140790
140921
|
children: " "
|
|
140791
140922
|
}, undefined, false, undefined, this),
|
|
140792
|
-
/* @__PURE__ */
|
|
140923
|
+
/* @__PURE__ */ jsx_dev_runtime8.jsxDEV(Text, {
|
|
140793
140924
|
color: color.faint,
|
|
140794
140925
|
backgroundColor: color.panelBg,
|
|
140795
140926
|
children: suggestion ?? placeholder
|
|
140796
140927
|
}, undefined, false, undefined, this)
|
|
140797
140928
|
]
|
|
140798
|
-
}, undefined, true, undefined, this) : /* @__PURE__ */
|
|
140929
|
+
}, undefined, true, undefined, this) : /* @__PURE__ */ jsx_dev_runtime8.jsxDEV(Box_default, {
|
|
140799
140930
|
flexDirection: "column",
|
|
140800
140931
|
paddingX: 1,
|
|
140801
|
-
children: lines.map((ln, i2) => /* @__PURE__ */
|
|
140932
|
+
children: lines.map((ln, i2) => /* @__PURE__ */ jsx_dev_runtime8.jsxDEV(Box_default, {
|
|
140802
140933
|
children: [
|
|
140803
|
-
/* @__PURE__ */
|
|
140934
|
+
/* @__PURE__ */ jsx_dev_runtime8.jsxDEV(Text, {
|
|
140804
140935
|
color: color.accent,
|
|
140805
140936
|
bold: true,
|
|
140806
140937
|
backgroundColor: color.panelBg,
|
|
@@ -141686,7 +141817,7 @@ function renderGhost(cfg) {
|
|
|
141686
141817
|
}
|
|
141687
141818
|
|
|
141688
141819
|
// src/ui/components/Mascot.tsx
|
|
141689
|
-
var
|
|
141820
|
+
var jsx_dev_runtime9 = __toESM(require_jsx_dev_runtime(), 1);
|
|
141690
141821
|
var SKINS = ["base", "mint", "pink", "golden", "shades"];
|
|
141691
141822
|
var SKIN_CFG = {
|
|
141692
141823
|
base: { palette: "default", face: "happy" },
|
|
@@ -141708,35 +141839,35 @@ function SpriteRow({ row }) {
|
|
|
141708
141839
|
j++;
|
|
141709
141840
|
const n = j - i2;
|
|
141710
141841
|
if (t2 && b)
|
|
141711
|
-
spans.push(/* @__PURE__ */
|
|
141842
|
+
spans.push(/* @__PURE__ */ jsx_dev_runtime9.jsxDEV(Text, {
|
|
141712
141843
|
color: t2,
|
|
141713
141844
|
backgroundColor: b,
|
|
141714
141845
|
children: "▀".repeat(n)
|
|
141715
141846
|
}, i2, false, undefined, this));
|
|
141716
141847
|
else if (t2)
|
|
141717
|
-
spans.push(/* @__PURE__ */
|
|
141848
|
+
spans.push(/* @__PURE__ */ jsx_dev_runtime9.jsxDEV(Text, {
|
|
141718
141849
|
color: t2,
|
|
141719
141850
|
children: "▀".repeat(n)
|
|
141720
141851
|
}, i2, false, undefined, this));
|
|
141721
141852
|
else if (b)
|
|
141722
|
-
spans.push(/* @__PURE__ */
|
|
141853
|
+
spans.push(/* @__PURE__ */ jsx_dev_runtime9.jsxDEV(Text, {
|
|
141723
141854
|
color: b,
|
|
141724
141855
|
children: "▄".repeat(n)
|
|
141725
141856
|
}, i2, false, undefined, this));
|
|
141726
141857
|
else
|
|
141727
|
-
spans.push(/* @__PURE__ */
|
|
141858
|
+
spans.push(/* @__PURE__ */ jsx_dev_runtime9.jsxDEV(Text, {
|
|
141728
141859
|
children: " ".repeat(n)
|
|
141729
141860
|
}, i2, false, undefined, this));
|
|
141730
141861
|
i2 = j;
|
|
141731
141862
|
}
|
|
141732
|
-
return /* @__PURE__ */
|
|
141863
|
+
return /* @__PURE__ */ jsx_dev_runtime9.jsxDEV(Box_default, {
|
|
141733
141864
|
children: spans
|
|
141734
141865
|
}, undefined, false, undefined, this);
|
|
141735
141866
|
}
|
|
141736
141867
|
function Sprite({ data }) {
|
|
141737
|
-
return /* @__PURE__ */
|
|
141868
|
+
return /* @__PURE__ */ jsx_dev_runtime9.jsxDEV(Box_default, {
|
|
141738
141869
|
flexDirection: "column",
|
|
141739
|
-
children: data.map((row, i2) => /* @__PURE__ */
|
|
141870
|
+
children: data.map((row, i2) => /* @__PURE__ */ jsx_dev_runtime9.jsxDEV(SpriteRow, {
|
|
141740
141871
|
row
|
|
141741
141872
|
}, i2, false, undefined, this))
|
|
141742
141873
|
}, undefined, false, undefined, this);
|
|
@@ -141764,9 +141895,9 @@ function AnimatedGhost({ cfg, scale, anim }) {
|
|
|
141764
141895
|
frameCfg.overlay = { kind: anim.overlay, frame: slow };
|
|
141765
141896
|
const data = import_react23.useMemo(() => renderGhost(frameCfg), [JSON.stringify(frameCfg)]);
|
|
141766
141897
|
const shake = anim.shake ? tick % 2 : 0;
|
|
141767
|
-
return /* @__PURE__ */
|
|
141898
|
+
return /* @__PURE__ */ jsx_dev_runtime9.jsxDEV(Box_default, {
|
|
141768
141899
|
marginLeft: shake,
|
|
141769
|
-
children: /* @__PURE__ */
|
|
141900
|
+
children: /* @__PURE__ */ jsx_dev_runtime9.jsxDEV(Sprite, {
|
|
141770
141901
|
data
|
|
141771
141902
|
}, undefined, false, undefined, this)
|
|
141772
141903
|
}, undefined, false, undefined, this);
|
|
@@ -141775,9 +141906,9 @@ function KittyGhost({ variant, size: size2 }) {
|
|
|
141775
141906
|
const data = GHOSTS[variant][size2];
|
|
141776
141907
|
const id = idColor(imageId(variant, size2));
|
|
141777
141908
|
const lines = placeholderRows(data[0]?.length ?? 0, data.length);
|
|
141778
|
-
return /* @__PURE__ */
|
|
141909
|
+
return /* @__PURE__ */ jsx_dev_runtime9.jsxDEV(Box_default, {
|
|
141779
141910
|
flexDirection: "column",
|
|
141780
|
-
children: lines.map((l, i2) => /* @__PURE__ */
|
|
141911
|
+
children: lines.map((l, i2) => /* @__PURE__ */ jsx_dev_runtime9.jsxDEV(Text, {
|
|
141781
141912
|
color: id,
|
|
141782
141913
|
children: l
|
|
141783
141914
|
}, i2, false, undefined, this))
|
|
@@ -141785,29 +141916,29 @@ function KittyGhost({ variant, size: size2 }) {
|
|
|
141785
141916
|
}
|
|
141786
141917
|
function MascotSplash({ skin = "base", size: size2 = "big" }) {
|
|
141787
141918
|
const kitty = getImageMode() === "kitty";
|
|
141788
|
-
return /* @__PURE__ */
|
|
141919
|
+
return /* @__PURE__ */ jsx_dev_runtime9.jsxDEV(Box_default, {
|
|
141789
141920
|
flexDirection: "column",
|
|
141790
141921
|
alignItems: "center",
|
|
141791
141922
|
marginTop: 1,
|
|
141792
141923
|
children: [
|
|
141793
|
-
size2 !== "none" ? kitty ? /* @__PURE__ */
|
|
141924
|
+
size2 !== "none" ? kitty ? /* @__PURE__ */ jsx_dev_runtime9.jsxDEV(KittyGhost, {
|
|
141794
141925
|
variant: skin,
|
|
141795
141926
|
size: size2
|
|
141796
|
-
}, undefined, false, undefined, this) : /* @__PURE__ */
|
|
141927
|
+
}, undefined, false, undefined, this) : /* @__PURE__ */ jsx_dev_runtime9.jsxDEV(AnimatedGhost, {
|
|
141797
141928
|
cfg: skinToCfg(skin),
|
|
141798
141929
|
scale: size2 === "big" ? 2 : 1,
|
|
141799
141930
|
anim: { blink: true }
|
|
141800
141931
|
}, undefined, false, undefined, this) : null,
|
|
141801
|
-
/* @__PURE__ */
|
|
141932
|
+
/* @__PURE__ */ jsx_dev_runtime9.jsxDEV(Box_default, {
|
|
141802
141933
|
marginTop: size2 === "none" ? 0 : 1,
|
|
141803
|
-
children: /* @__PURE__ */
|
|
141934
|
+
children: /* @__PURE__ */ jsx_dev_runtime9.jsxDEV(Text, {
|
|
141804
141935
|
color: color.accent,
|
|
141805
141936
|
bold: true,
|
|
141806
141937
|
children: "gearbox"
|
|
141807
141938
|
}, undefined, false, undefined, this)
|
|
141808
141939
|
}, undefined, false, undefined, this),
|
|
141809
|
-
/* @__PURE__ */
|
|
141810
|
-
children: /* @__PURE__ */
|
|
141940
|
+
/* @__PURE__ */ jsx_dev_runtime9.jsxDEV(Box_default, {
|
|
141941
|
+
children: /* @__PURE__ */ jsx_dev_runtime9.jsxDEV(Text, {
|
|
141811
141942
|
color: color.dim,
|
|
141812
141943
|
children: "one ghost · every model"
|
|
141813
141944
|
}, undefined, false, undefined, this)
|
|
@@ -141817,9 +141948,9 @@ function MascotSplash({ skin = "base", size: size2 = "big" }) {
|
|
|
141817
141948
|
}
|
|
141818
141949
|
|
|
141819
141950
|
// src/ui/components/PermissionPrompt.tsx
|
|
141820
|
-
var
|
|
141951
|
+
var jsx_dev_runtime10 = __toESM(require_jsx_dev_runtime(), 1);
|
|
141821
141952
|
function PermissionPrompt({ req, width }) {
|
|
141822
|
-
return /* @__PURE__ */
|
|
141953
|
+
return /* @__PURE__ */ jsx_dev_runtime10.jsxDEV(Box_default, {
|
|
141823
141954
|
flexDirection: "column",
|
|
141824
141955
|
width,
|
|
141825
141956
|
marginTop: 1,
|
|
@@ -141827,9 +141958,9 @@ function PermissionPrompt({ req, width }) {
|
|
|
141827
141958
|
borderStyle: "round",
|
|
141828
141959
|
borderColor: color.accent,
|
|
141829
141960
|
children: [
|
|
141830
|
-
/* @__PURE__ */
|
|
141961
|
+
/* @__PURE__ */ jsx_dev_runtime10.jsxDEV(Box_default, {
|
|
141831
141962
|
children: [
|
|
141832
|
-
/* @__PURE__ */
|
|
141963
|
+
/* @__PURE__ */ jsx_dev_runtime10.jsxDEV(Text, {
|
|
141833
141964
|
color: color.accent,
|
|
141834
141965
|
bold: true,
|
|
141835
141966
|
children: [
|
|
@@ -141837,7 +141968,7 @@ function PermissionPrompt({ req, width }) {
|
|
|
141837
141968
|
" permission"
|
|
141838
141969
|
]
|
|
141839
141970
|
}, undefined, true, undefined, this),
|
|
141840
|
-
/* @__PURE__ */
|
|
141971
|
+
/* @__PURE__ */ jsx_dev_runtime10.jsxDEV(Text, {
|
|
141841
141972
|
color: color.faint,
|
|
141842
141973
|
children: [
|
|
141843
141974
|
" ",
|
|
@@ -141846,39 +141977,39 @@ function PermissionPrompt({ req, width }) {
|
|
|
141846
141977
|
}, undefined, true, undefined, this)
|
|
141847
141978
|
]
|
|
141848
141979
|
}, undefined, true, undefined, this),
|
|
141849
|
-
/* @__PURE__ */
|
|
141980
|
+
/* @__PURE__ */ jsx_dev_runtime10.jsxDEV(Box_default, {
|
|
141850
141981
|
marginTop: 1,
|
|
141851
|
-
children: /* @__PURE__ */
|
|
141982
|
+
children: /* @__PURE__ */ jsx_dev_runtime10.jsxDEV(Box_default, {
|
|
141852
141983
|
flexGrow: 1,
|
|
141853
|
-
children: /* @__PURE__ */
|
|
141984
|
+
children: /* @__PURE__ */ jsx_dev_runtime10.jsxDEV(Text, {
|
|
141854
141985
|
color: color.text,
|
|
141855
141986
|
wrap: "truncate-end",
|
|
141856
141987
|
children: req.detail
|
|
141857
141988
|
}, undefined, false, undefined, this)
|
|
141858
141989
|
}, undefined, false, undefined, this)
|
|
141859
141990
|
}, undefined, false, undefined, this),
|
|
141860
|
-
/* @__PURE__ */
|
|
141991
|
+
/* @__PURE__ */ jsx_dev_runtime10.jsxDEV(Box_default, {
|
|
141861
141992
|
marginTop: 1,
|
|
141862
141993
|
children: [
|
|
141863
|
-
/* @__PURE__ */
|
|
141994
|
+
/* @__PURE__ */ jsx_dev_runtime10.jsxDEV(Text, {
|
|
141864
141995
|
color: color.accent,
|
|
141865
141996
|
bold: true,
|
|
141866
141997
|
children: "1"
|
|
141867
141998
|
}, undefined, false, undefined, this),
|
|
141868
|
-
/* @__PURE__ */
|
|
141999
|
+
/* @__PURE__ */ jsx_dev_runtime10.jsxDEV(Text, {
|
|
141869
142000
|
color: color.dim,
|
|
141870
142001
|
children: " once"
|
|
141871
142002
|
}, undefined, false, undefined, this),
|
|
141872
|
-
/* @__PURE__ */
|
|
142003
|
+
/* @__PURE__ */ jsx_dev_runtime10.jsxDEV(Text, {
|
|
141873
142004
|
color: color.faint,
|
|
141874
142005
|
children: " "
|
|
141875
142006
|
}, undefined, false, undefined, this),
|
|
141876
|
-
/* @__PURE__ */
|
|
142007
|
+
/* @__PURE__ */ jsx_dev_runtime10.jsxDEV(Text, {
|
|
141877
142008
|
color: color.accent,
|
|
141878
142009
|
bold: true,
|
|
141879
142010
|
children: "2"
|
|
141880
142011
|
}, undefined, false, undefined, this),
|
|
141881
|
-
/* @__PURE__ */
|
|
142012
|
+
/* @__PURE__ */ jsx_dev_runtime10.jsxDEV(Text, {
|
|
141882
142013
|
color: color.dim,
|
|
141883
142014
|
children: [
|
|
141884
142015
|
" always (",
|
|
@@ -141886,33 +142017,33 @@ function PermissionPrompt({ req, width }) {
|
|
|
141886
142017
|
")"
|
|
141887
142018
|
]
|
|
141888
142019
|
}, undefined, true, undefined, this),
|
|
141889
|
-
/* @__PURE__ */
|
|
142020
|
+
/* @__PURE__ */ jsx_dev_runtime10.jsxDEV(Text, {
|
|
141890
142021
|
color: color.faint,
|
|
141891
142022
|
children: " "
|
|
141892
142023
|
}, undefined, false, undefined, this),
|
|
141893
|
-
/* @__PURE__ */
|
|
142024
|
+
/* @__PURE__ */ jsx_dev_runtime10.jsxDEV(Text, {
|
|
141894
142025
|
color: color.accent,
|
|
141895
142026
|
bold: true,
|
|
141896
142027
|
children: "a"
|
|
141897
142028
|
}, undefined, false, undefined, this),
|
|
141898
|
-
/* @__PURE__ */
|
|
142029
|
+
/* @__PURE__ */ jsx_dev_runtime10.jsxDEV(Text, {
|
|
141899
142030
|
color: color.dim,
|
|
141900
142031
|
children: " all · yolo"
|
|
141901
142032
|
}, undefined, false, undefined, this),
|
|
141902
|
-
/* @__PURE__ */
|
|
142033
|
+
/* @__PURE__ */ jsx_dev_runtime10.jsxDEV(Text, {
|
|
141903
142034
|
color: color.faint,
|
|
141904
142035
|
children: " "
|
|
141905
142036
|
}, undefined, false, undefined, this),
|
|
141906
|
-
/* @__PURE__ */
|
|
142037
|
+
/* @__PURE__ */ jsx_dev_runtime10.jsxDEV(Text, {
|
|
141907
142038
|
color: color.err,
|
|
141908
142039
|
bold: true,
|
|
141909
142040
|
children: "3"
|
|
141910
142041
|
}, undefined, false, undefined, this),
|
|
141911
|
-
/* @__PURE__ */
|
|
142042
|
+
/* @__PURE__ */ jsx_dev_runtime10.jsxDEV(Text, {
|
|
141912
142043
|
color: color.dim,
|
|
141913
142044
|
children: " deny"
|
|
141914
142045
|
}, undefined, false, undefined, this),
|
|
141915
|
-
/* @__PURE__ */
|
|
142046
|
+
/* @__PURE__ */ jsx_dev_runtime10.jsxDEV(Text, {
|
|
141916
142047
|
color: color.faint,
|
|
141917
142048
|
children: " · esc"
|
|
141918
142049
|
}, undefined, false, undefined, this)
|
|
@@ -141923,7 +142054,7 @@ function PermissionPrompt({ req, width }) {
|
|
|
141923
142054
|
}
|
|
141924
142055
|
|
|
141925
142056
|
// src/ui/components/Working.tsx
|
|
141926
|
-
var
|
|
142057
|
+
var jsx_dev_runtime11 = __toESM(require_jsx_dev_runtime(), 1);
|
|
141927
142058
|
var THINK_FRAMES = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"];
|
|
141928
142059
|
var STREAM_FRAMES = ["▁", "▂", "▃", "▄", "▅", "▆", "▇", "█", "▇", "▆", "▅", "▄", "▃", "▂"];
|
|
141929
142060
|
var TOOL_FRAMES = ["◐", "◓", "◑", "◒"];
|
|
@@ -141957,16 +142088,16 @@ function Working({
|
|
|
141957
142088
|
const spinner = linger ? "●" : spinFrame(state);
|
|
141958
142089
|
const f3 = Math.floor(Date.now() / 360);
|
|
141959
142090
|
const dots = ["", ".", "..", "..."][f3 % 4];
|
|
141960
|
-
return /* @__PURE__ */
|
|
142091
|
+
return /* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Box_default, {
|
|
141961
142092
|
width,
|
|
141962
142093
|
paddingX: 1,
|
|
141963
142094
|
marginTop: 1,
|
|
141964
142095
|
justifyContent: "space-between",
|
|
141965
142096
|
children: [
|
|
141966
|
-
/* @__PURE__ */
|
|
142097
|
+
/* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text, {
|
|
141967
142098
|
color: labelColor,
|
|
141968
142099
|
children: [
|
|
141969
|
-
/* @__PURE__ */
|
|
142100
|
+
/* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text, {
|
|
141970
142101
|
color: dotColor,
|
|
141971
142102
|
children: [
|
|
141972
142103
|
spinner,
|
|
@@ -141974,22 +142105,22 @@ function Working({
|
|
|
141974
142105
|
]
|
|
141975
142106
|
}, undefined, true, undefined, this),
|
|
141976
142107
|
label,
|
|
141977
|
-
!linger ? /* @__PURE__ */
|
|
142108
|
+
!linger ? /* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text, {
|
|
141978
142109
|
color: color.accentDim,
|
|
141979
142110
|
children: dots
|
|
141980
142111
|
}, undefined, false, undefined, this) : null
|
|
141981
142112
|
]
|
|
141982
142113
|
}, undefined, true, undefined, this),
|
|
141983
|
-
!linger ? /* @__PURE__ */
|
|
142114
|
+
!linger ? /* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text, {
|
|
141984
142115
|
children: [
|
|
141985
|
-
/* @__PURE__ */
|
|
142116
|
+
/* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text, {
|
|
141986
142117
|
color: color.accentDim,
|
|
141987
142118
|
children: [
|
|
141988
142119
|
elapsed,
|
|
141989
142120
|
"s"
|
|
141990
142121
|
]
|
|
141991
142122
|
}, undefined, true, undefined, this),
|
|
141992
|
-
/* @__PURE__ */
|
|
142123
|
+
/* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text, {
|
|
141993
142124
|
color: color.faint,
|
|
141994
142125
|
children: [
|
|
141995
142126
|
tps >= 5 ? ` · ~${tps} tok/s` : "",
|
|
@@ -141997,7 +142128,7 @@ function Working({
|
|
|
141997
142128
|
]
|
|
141998
142129
|
}, undefined, true, undefined, this)
|
|
141999
142130
|
]
|
|
142000
|
-
}, undefined, true, undefined, this) : /* @__PURE__ */
|
|
142131
|
+
}, undefined, true, undefined, this) : /* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text, {
|
|
142001
142132
|
color: color.faint,
|
|
142002
142133
|
children: " "
|
|
142003
142134
|
}, undefined, false, undefined, this)
|
|
@@ -142006,7 +142137,7 @@ function Working({
|
|
|
142006
142137
|
}
|
|
142007
142138
|
|
|
142008
142139
|
// src/ui/components/Viewport.tsx
|
|
142009
|
-
var
|
|
142140
|
+
var jsx_dev_runtime12 = __toESM(require_jsx_dev_runtime(), 1);
|
|
142010
142141
|
function normalized(sel) {
|
|
142011
142142
|
if (!sel)
|
|
142012
142143
|
return null;
|
|
@@ -142024,7 +142155,7 @@ function selectedRangeForLine(sel, absLine) {
|
|
|
142024
142155
|
}
|
|
142025
142156
|
function LineRow({ line, absLine, selection, lineWidth }) {
|
|
142026
142157
|
if (line.length === 0) {
|
|
142027
|
-
return /* @__PURE__ */
|
|
142158
|
+
return /* @__PURE__ */ jsx_dev_runtime12.jsxDEV(Text, {
|
|
142028
142159
|
backgroundColor: color.navy,
|
|
142029
142160
|
children: " ".repeat(lineWidth)
|
|
142030
142161
|
}, undefined, false, undefined, this);
|
|
@@ -142033,7 +142164,7 @@ function LineRow({ line, absLine, selection, lineWidth }) {
|
|
|
142033
142164
|
let pos = 0;
|
|
142034
142165
|
const lineLen = line.reduce((n, s2) => n + s2.text.length, 0);
|
|
142035
142166
|
const trailing = Math.max(0, lineWidth - lineLen);
|
|
142036
|
-
return /* @__PURE__ */
|
|
142167
|
+
return /* @__PURE__ */ jsx_dev_runtime12.jsxDEV(Text, {
|
|
142037
142168
|
children: [
|
|
142038
142169
|
line.flatMap((s2, j) => {
|
|
142039
142170
|
const start = pos;
|
|
@@ -142041,7 +142172,7 @@ function LineRow({ line, absLine, selection, lineWidth }) {
|
|
|
142041
142172
|
pos = end;
|
|
142042
142173
|
if (!range2 || end <= range2[0] || start >= range2[1]) {
|
|
142043
142174
|
return [
|
|
142044
|
-
/* @__PURE__ */
|
|
142175
|
+
/* @__PURE__ */ jsx_dev_runtime12.jsxDEV(Text, {
|
|
142045
142176
|
color: s2.color,
|
|
142046
142177
|
bold: s2.bold,
|
|
142047
142178
|
italic: s2.italic,
|
|
@@ -142054,7 +142185,7 @@ function LineRow({ line, absLine, selection, lineWidth }) {
|
|
|
142054
142185
|
const a = Math.max(range2[0] - start, 0);
|
|
142055
142186
|
const b = Math.min(range2[1] - start, s2.text.length);
|
|
142056
142187
|
return [
|
|
142057
|
-
s2.text.slice(0, a) ? /* @__PURE__ */
|
|
142188
|
+
s2.text.slice(0, a) ? /* @__PURE__ */ jsx_dev_runtime12.jsxDEV(Text, {
|
|
142058
142189
|
color: s2.color,
|
|
142059
142190
|
bold: s2.bold,
|
|
142060
142191
|
italic: s2.italic,
|
|
@@ -142062,11 +142193,11 @@ function LineRow({ line, absLine, selection, lineWidth }) {
|
|
|
142062
142193
|
backgroundColor: s2.bg ?? color.navy,
|
|
142063
142194
|
children: s2.text.slice(0, a)
|
|
142064
142195
|
}, `${j}-a`, false, undefined, this) : null,
|
|
142065
|
-
/* @__PURE__ */
|
|
142196
|
+
/* @__PURE__ */ jsx_dev_runtime12.jsxDEV(Text, {
|
|
142066
142197
|
inverse: true,
|
|
142067
142198
|
children: s2.text.slice(a, b)
|
|
142068
142199
|
}, `${j}-b`, false, undefined, this),
|
|
142069
|
-
s2.text.slice(b) ? /* @__PURE__ */
|
|
142200
|
+
s2.text.slice(b) ? /* @__PURE__ */ jsx_dev_runtime12.jsxDEV(Text, {
|
|
142070
142201
|
color: s2.color,
|
|
142071
142202
|
bold: s2.bold,
|
|
142072
142203
|
italic: s2.italic,
|
|
@@ -142076,7 +142207,7 @@ function LineRow({ line, absLine, selection, lineWidth }) {
|
|
|
142076
142207
|
}, `${j}-c`, false, undefined, this) : null
|
|
142077
142208
|
].filter(Boolean);
|
|
142078
142209
|
}),
|
|
142079
|
-
trailing > 0 ? /* @__PURE__ */
|
|
142210
|
+
trailing > 0 ? /* @__PURE__ */ jsx_dev_runtime12.jsxDEV(Text, {
|
|
142080
142211
|
backgroundColor: color.navy,
|
|
142081
142212
|
children: " ".repeat(trailing)
|
|
142082
142213
|
}, undefined, false, undefined, this) : null
|
|
@@ -142093,25 +142224,25 @@ function Viewport({ lines, scrollTop, height, width, selection }) {
|
|
|
142093
142224
|
const thumb = hasBar ? Math.max(1, Math.round(height / total * height)) : 0;
|
|
142094
142225
|
const maxTop = Math.max(1, total - height);
|
|
142095
142226
|
const thumbStart = hasBar ? Math.min(height - thumb, Math.round(scrollTop / maxTop * (height - thumb))) : 0;
|
|
142096
|
-
return /* @__PURE__ */
|
|
142227
|
+
return /* @__PURE__ */ jsx_dev_runtime12.jsxDEV(Box_default, {
|
|
142097
142228
|
width,
|
|
142098
142229
|
children: [
|
|
142099
|
-
/* @__PURE__ */
|
|
142230
|
+
/* @__PURE__ */ jsx_dev_runtime12.jsxDEV(Box_default, {
|
|
142100
142231
|
flexDirection: "column",
|
|
142101
142232
|
width: width - 1,
|
|
142102
|
-
children: padded.map((l, i2) => /* @__PURE__ */
|
|
142233
|
+
children: padded.map((l, i2) => /* @__PURE__ */ jsx_dev_runtime12.jsxDEV(LineRow, {
|
|
142103
142234
|
line: l,
|
|
142104
142235
|
absLine: scrollTop + i2,
|
|
142105
142236
|
selection,
|
|
142106
142237
|
lineWidth: width - 1
|
|
142107
142238
|
}, i2, false, undefined, this))
|
|
142108
142239
|
}, undefined, false, undefined, this),
|
|
142109
|
-
/* @__PURE__ */
|
|
142240
|
+
/* @__PURE__ */ jsx_dev_runtime12.jsxDEV(Box_default, {
|
|
142110
142241
|
flexDirection: "column",
|
|
142111
142242
|
width: 1,
|
|
142112
142243
|
children: Array.from({ length: height }, (_, i2) => {
|
|
142113
142244
|
const on = hasBar && i2 >= thumbStart && i2 < thumbStart + thumb;
|
|
142114
|
-
return /* @__PURE__ */
|
|
142245
|
+
return /* @__PURE__ */ jsx_dev_runtime12.jsxDEV(Text, {
|
|
142115
142246
|
color: on ? color.accentDim : color.faint,
|
|
142116
142247
|
children: on ? "┃" : hasBar ? "│" : " "
|
|
142117
142248
|
}, i2, false, undefined, this);
|
|
@@ -142366,8 +142497,8 @@ function blockLines(tok, width) {
|
|
|
142366
142497
|
}
|
|
142367
142498
|
case "blockquote": {
|
|
142368
142499
|
const inner = (tok.tokens ?? []).flatMap((t2) => blockLines(t2, Math.max(width - 2, 1)));
|
|
142369
|
-
const
|
|
142370
|
-
return inner.map((l) => [
|
|
142500
|
+
const bar2 = { text: glyph.userBar + " ", color: color.accentDim };
|
|
142501
|
+
return inner.map((l) => [bar2, ...l]);
|
|
142371
142502
|
}
|
|
142372
142503
|
case "hr":
|
|
142373
142504
|
return [[{ text: glyph.rule.repeat(Math.min(width, 24)), color: color.faint }]];
|
|
@@ -143187,14 +143318,14 @@ class RoutingSelector {
|
|
|
143187
143318
|
}
|
|
143188
143319
|
prepare(task) {
|
|
143189
143320
|
const kind = task.kind ?? classify(task.prompt);
|
|
143190
|
-
const
|
|
143321
|
+
const bar2 = BAR[kind];
|
|
143191
143322
|
const required2 = task.requires ?? [];
|
|
143192
143323
|
const ctx = buildRoutingContext(ctx_now());
|
|
143193
143324
|
const estInputTokens = task.estTokens || NOMINAL_INPUT_TOKENS;
|
|
143194
143325
|
const all = this.enumerate(ctx);
|
|
143195
143326
|
if (all.length === 0) {
|
|
143196
143327
|
const m2 = pickDefaultModel(this.fallbackId);
|
|
143197
|
-
return { kind, bar, required: required2, ctx, pool: [], clears: [], estInputTokens, fallback: m2 ?? undefined };
|
|
143328
|
+
return { kind, bar: bar2, required: required2, ctx, pool: [], clears: [], estInputTokens, fallback: m2 ?? undefined };
|
|
143198
143329
|
}
|
|
143199
143330
|
const capable = required2.length ? all.filter((c) => supportsRequirements(c.spec, required2)) : all;
|
|
143200
143331
|
if (capable.length === 0) {
|
|
@@ -143205,8 +143336,8 @@ class RoutingSelector {
|
|
|
143205
143336
|
const fits = need > 0 ? capable.filter((c) => c.spec.contextWindow >= need) : capable;
|
|
143206
143337
|
let pool = fits.length ? fits : capable;
|
|
143207
143338
|
pool = applyGlobalPreference(pool);
|
|
143208
|
-
const clears = pool.filter((c) => qualityOf(c) >=
|
|
143209
|
-
return { kind, bar, required: required2, ctx, pool, clears, estInputTokens };
|
|
143339
|
+
const clears = pool.filter((c) => qualityOf(c) >= bar2);
|
|
143340
|
+
return { kind, bar: bar2, required: required2, ctx, pool, clears, estInputTokens };
|
|
143210
143341
|
}
|
|
143211
143342
|
preferredIn(kind, candidates) {
|
|
143212
143343
|
const pref = preferenceFor(kind);
|
|
@@ -143406,7 +143537,7 @@ function backspaceFilter(panel) {
|
|
|
143406
143537
|
}
|
|
143407
143538
|
|
|
143408
143539
|
// src/ui/components/Panel.tsx
|
|
143409
|
-
var
|
|
143540
|
+
var jsx_dev_runtime13 = __toESM(require_jsx_dev_runtime(), 1);
|
|
143410
143541
|
function accountStateColor3(status) {
|
|
143411
143542
|
if (status === "active")
|
|
143412
143543
|
return color.ok;
|
|
@@ -143431,9 +143562,9 @@ function Panel({
|
|
|
143431
143562
|
const lines = staticLines ?? itemsToLines(panel.items, innerW);
|
|
143432
143563
|
const maxScroll = Math.max(0, lines.length - bodyH);
|
|
143433
143564
|
const scroll = Math.min(panel.scroll, maxScroll);
|
|
143434
|
-
body = /* @__PURE__ */
|
|
143565
|
+
body = /* @__PURE__ */ jsx_dev_runtime13.jsxDEV(Box_default, {
|
|
143435
143566
|
paddingX: 1,
|
|
143436
|
-
children: /* @__PURE__ */
|
|
143567
|
+
children: /* @__PURE__ */ jsx_dev_runtime13.jsxDEV(Viewport, {
|
|
143437
143568
|
lines,
|
|
143438
143569
|
scrollTop: scroll,
|
|
143439
143570
|
height: bodyH,
|
|
@@ -143447,48 +143578,48 @@ function Panel({
|
|
|
143447
143578
|
const start = windowStart(idx, rows.length, bodyH);
|
|
143448
143579
|
const slice2 = rows.slice(start, start + bodyH);
|
|
143449
143580
|
const labelPad = accounts?.labelPad ?? 0;
|
|
143450
|
-
body = /* @__PURE__ */
|
|
143581
|
+
body = /* @__PURE__ */ jsx_dev_runtime13.jsxDEV(Box_default, {
|
|
143451
143582
|
flexDirection: "column",
|
|
143452
143583
|
paddingX: 1,
|
|
143453
|
-
children: rows.length === 0 ? /* @__PURE__ */
|
|
143584
|
+
children: rows.length === 0 ? /* @__PURE__ */ jsx_dev_runtime13.jsxDEV(Text, {
|
|
143454
143585
|
color: color.faint,
|
|
143455
|
-
children: "no accounts yet
|
|
143586
|
+
children: "no accounts yet · /account add to add one"
|
|
143456
143587
|
}, undefined, false, undefined, this) : slice2.map((r2, i2) => {
|
|
143457
143588
|
const sel = start + i2 === idx;
|
|
143458
|
-
return /* @__PURE__ */
|
|
143589
|
+
return /* @__PURE__ */ jsx_dev_runtime13.jsxDEV(Text, {
|
|
143459
143590
|
backgroundColor: sel ? color.accentBg : undefined,
|
|
143460
143591
|
children: [
|
|
143461
|
-
/* @__PURE__ */
|
|
143592
|
+
/* @__PURE__ */ jsx_dev_runtime13.jsxDEV(Text, {
|
|
143462
143593
|
color: sel ? color.accent : color.faint,
|
|
143463
143594
|
children: sel ? "▶ " : " "
|
|
143464
143595
|
}, undefined, false, undefined, this),
|
|
143465
|
-
/* @__PURE__ */
|
|
143596
|
+
/* @__PURE__ */ jsx_dev_runtime13.jsxDEV(Text, {
|
|
143466
143597
|
color: color.text,
|
|
143467
143598
|
bold: r2.active,
|
|
143468
143599
|
children: r2.name.padEnd(labelPad)
|
|
143469
143600
|
}, undefined, false, undefined, this),
|
|
143470
|
-
/* @__PURE__ */
|
|
143601
|
+
/* @__PURE__ */ jsx_dev_runtime13.jsxDEV(Text, {
|
|
143471
143602
|
color: color.faint,
|
|
143472
143603
|
children: [
|
|
143473
143604
|
" ",
|
|
143474
143605
|
r2.type
|
|
143475
143606
|
]
|
|
143476
143607
|
}, undefined, true, undefined, this),
|
|
143477
|
-
/* @__PURE__ */
|
|
143608
|
+
/* @__PURE__ */ jsx_dev_runtime13.jsxDEV(Text, {
|
|
143478
143609
|
color: accountStateColor3(r2.status),
|
|
143479
143610
|
children: [
|
|
143480
143611
|
" ",
|
|
143481
143612
|
r2.status
|
|
143482
143613
|
]
|
|
143483
143614
|
}, undefined, true, undefined, this),
|
|
143484
|
-
r2.detail ? /* @__PURE__ */
|
|
143615
|
+
r2.detail ? /* @__PURE__ */ jsx_dev_runtime13.jsxDEV(Text, {
|
|
143485
143616
|
color: color.faint,
|
|
143486
143617
|
children: [
|
|
143487
143618
|
" · ",
|
|
143488
143619
|
r2.detail
|
|
143489
143620
|
]
|
|
143490
143621
|
}, undefined, true, undefined, this) : null,
|
|
143491
|
-
r2.type === "subscription" && !(r2.detail && r2.detail.includes("@")) ? /* @__PURE__ */
|
|
143622
|
+
r2.type === "subscription" && !(r2.detail && r2.detail.includes("@")) ? /* @__PURE__ */ jsx_dev_runtime13.jsxDEV(Text, {
|
|
143492
143623
|
color: color.accentDim,
|
|
143493
143624
|
children: [
|
|
143494
143625
|
" · /account login ",
|
|
@@ -143496,7 +143627,7 @@ function Panel({
|
|
|
143496
143627
|
" to identify"
|
|
143497
143628
|
]
|
|
143498
143629
|
}, undefined, true, undefined, this) : null,
|
|
143499
|
-
r2.active ? /* @__PURE__ */
|
|
143630
|
+
r2.active ? /* @__PURE__ */ jsx_dev_runtime13.jsxDEV(Text, {
|
|
143500
143631
|
color: color.ok,
|
|
143501
143632
|
children: [
|
|
143502
143633
|
" ",
|
|
@@ -143514,10 +143645,10 @@ function Panel({
|
|
|
143514
143645
|
const idx = clampIndex(panel.index, rows.length);
|
|
143515
143646
|
const start = windowStart(idx, rows.length, bodyH);
|
|
143516
143647
|
const slice2 = rows.slice(start, start + bodyH);
|
|
143517
|
-
body = /* @__PURE__ */
|
|
143648
|
+
body = /* @__PURE__ */ jsx_dev_runtime13.jsxDEV(Box_default, {
|
|
143518
143649
|
flexDirection: "column",
|
|
143519
143650
|
paddingX: 1,
|
|
143520
|
-
children: rows.length === 0 ? /* @__PURE__ */
|
|
143651
|
+
children: rows.length === 0 ? /* @__PURE__ */ jsx_dev_runtime13.jsxDEV(Text, {
|
|
143521
143652
|
color: color.faint,
|
|
143522
143653
|
children: [
|
|
143523
143654
|
"no models match “",
|
|
@@ -143527,23 +143658,23 @@ function Panel({
|
|
|
143527
143658
|
}, undefined, true, undefined, this) : slice2.map((r2, i2) => {
|
|
143528
143659
|
const sel = start + i2 === idx;
|
|
143529
143660
|
const pinned = r2.id === currentModelId;
|
|
143530
|
-
return /* @__PURE__ */
|
|
143661
|
+
return /* @__PURE__ */ jsx_dev_runtime13.jsxDEV(Text, {
|
|
143531
143662
|
backgroundColor: sel ? color.accentBg : undefined,
|
|
143532
143663
|
children: [
|
|
143533
|
-
/* @__PURE__ */
|
|
143664
|
+
/* @__PURE__ */ jsx_dev_runtime13.jsxDEV(Text, {
|
|
143534
143665
|
color: sel ? color.accent : color.faint,
|
|
143535
143666
|
children: sel ? "▶ " : " "
|
|
143536
143667
|
}, undefined, false, undefined, this),
|
|
143537
|
-
/* @__PURE__ */
|
|
143668
|
+
/* @__PURE__ */ jsx_dev_runtime13.jsxDEV(Text, {
|
|
143538
143669
|
color: pinned ? color.ok : color.text,
|
|
143539
143670
|
bold: pinned,
|
|
143540
143671
|
children: r2.label.padEnd(22)
|
|
143541
143672
|
}, undefined, false, undefined, this),
|
|
143542
|
-
/* @__PURE__ */
|
|
143673
|
+
/* @__PURE__ */ jsx_dev_runtime13.jsxDEV(Text, {
|
|
143543
143674
|
color: color.faint,
|
|
143544
143675
|
children: r2.provider
|
|
143545
143676
|
}, undefined, false, undefined, this),
|
|
143546
|
-
pinned ? /* @__PURE__ */
|
|
143677
|
+
pinned ? /* @__PURE__ */ jsx_dev_runtime13.jsxDEV(Text, {
|
|
143547
143678
|
color: color.ok,
|
|
143548
143679
|
children: [
|
|
143549
143680
|
" ",
|
|
@@ -143557,37 +143688,37 @@ function Panel({
|
|
|
143557
143688
|
}, undefined, false, undefined, this);
|
|
143558
143689
|
hint = `filter: ${panel.filter || "(type to filter)"} · ↑↓ · ⏎ pin · esc close`;
|
|
143559
143690
|
}
|
|
143560
|
-
return /* @__PURE__ */
|
|
143691
|
+
return /* @__PURE__ */ jsx_dev_runtime13.jsxDEV(Box_default, {
|
|
143561
143692
|
flexDirection: "column",
|
|
143562
143693
|
width,
|
|
143563
143694
|
height,
|
|
143564
143695
|
children: [
|
|
143565
|
-
/* @__PURE__ */
|
|
143696
|
+
/* @__PURE__ */ jsx_dev_runtime13.jsxDEV(Box_default, {
|
|
143566
143697
|
width,
|
|
143567
143698
|
paddingX: 1,
|
|
143568
143699
|
justifyContent: "space-between",
|
|
143569
143700
|
children: [
|
|
143570
|
-
/* @__PURE__ */
|
|
143701
|
+
/* @__PURE__ */ jsx_dev_runtime13.jsxDEV(Text, {
|
|
143571
143702
|
color: color.accent,
|
|
143572
143703
|
bold: true,
|
|
143573
143704
|
children: panel.title
|
|
143574
143705
|
}, undefined, false, undefined, this),
|
|
143575
|
-
/* @__PURE__ */
|
|
143706
|
+
/* @__PURE__ */ jsx_dev_runtime13.jsxDEV(Text, {
|
|
143576
143707
|
color: color.faint,
|
|
143577
143708
|
children: "esc to close"
|
|
143578
143709
|
}, undefined, false, undefined, this)
|
|
143579
143710
|
]
|
|
143580
143711
|
}, undefined, true, undefined, this),
|
|
143581
|
-
/* @__PURE__ */
|
|
143712
|
+
/* @__PURE__ */ jsx_dev_runtime13.jsxDEV(Box_default, {
|
|
143582
143713
|
flexDirection: "column",
|
|
143583
143714
|
width,
|
|
143584
143715
|
height: bodyH,
|
|
143585
143716
|
children: body
|
|
143586
143717
|
}, undefined, false, undefined, this),
|
|
143587
|
-
/* @__PURE__ */
|
|
143718
|
+
/* @__PURE__ */ jsx_dev_runtime13.jsxDEV(Box_default, {
|
|
143588
143719
|
width,
|
|
143589
143720
|
paddingX: 1,
|
|
143590
|
-
children: /* @__PURE__ */
|
|
143721
|
+
children: /* @__PURE__ */ jsx_dev_runtime13.jsxDEV(Text, {
|
|
143591
143722
|
color: color.faint,
|
|
143592
143723
|
children: hint
|
|
143593
143724
|
}, undefined, false, undefined, this)
|
|
@@ -145518,7 +145649,7 @@ bun run typecheck
|
|
|
145518
145649
|
},
|
|
145519
145650
|
{
|
|
145520
145651
|
file: "CLAUDE.md",
|
|
145521
|
-
text: "# Gearbox — project guide\n\nGearbox is a multi-provider coding harness for the terminal: a beautiful, simple terminal agent that reads/writes code and runs commands, talking to any provider (Anthropic, OpenAI, Google, DeepSeek) through one clean loop.\n\n**The point of the project:** intelligent per-task *model routing* — automatically picking the right model for each task across every provider and account you pay for. Basic routing is live (`RoutingSelector` — classify → quality bar → cheapest winner); the richer engine (shadow-eval, credit/limit penalties, confidence display) layers on top of the same seam. See `DESIGN.md` for the full vision and `experiments/FINDINGS.md` for the validation behind it.\n\n## The one rule that matters\n\n**Keep the routing seam clean.** The agent must never hardcode a model. It asks a `ModelSelector` for the model to use. `RoutingSelector` is the live default (classify task → filter by quality bar → cheapest winner); `FixedSelector` is used only when a model is explicitly pinned (`--model` flag or `/model <name>`). Concretely:\n\n- `src/model/selector.ts` — the seam. `select(task) => ModelChoice` (now carrying an optional `Backend` so the runner can dispatch in-loop vs a subscription seat). Do not bypass it.\n- `src/model/router.ts` — `RoutingSelector` is **account-aware**: it scores `(model, account)` PAIRS, not just models. Candidates = in-loop registry models × the accounts that serve them + flat-rate subscription **seats** (`providers.subscriptionSeats()`, a seat mirrors a canonical model but runs via the vendor binary). Flow: classify → quality bar → context fit → global/`/prefer` preference filter → score → return `{model, reason, backend}`. A seat is ~free until its rate limit, so it wins by default and fails over to metered API as the window fills. `SubscriptionPinSelector`/`FixedSelector` are hard pins (explicit `/account use` or `/model`) that beat auto-routing.\n- `src/model/scoring.ts` — the PURE scorer: `score = costEst + scarcity + switchPenalty + limitPenalty + apiThrottlePenalty − planBonus`, argmin tie-broken deterministically. No I/O; fixture-tested. Every account-state term degrades safely — and where a provider exposes nothing, we ESTIMATE rather than go blind: live API rate-limit headers (`src/model/rate-headers.ts`, parsed from each response → `apiThrottle`, gentle near-empty penalty) and a self-declared budget − tracked spend (`/budget`, an estimated balance feeding scarcity). A missing signal with no estimate is still neutral (no errors per provider).\n- `src/model/routing-context.ts` — `buildRoutingContext()`: the per-turn account-state snapshot (balance where exposed, subscription rate headroom = min over the 5h/weekly windows) read from disk-cached `usage.json`. No network on the hot path; balances refreshed in the background (App effect).\n- `src/model/profiles.ts` — the data corpus: quality, cost, latency, tokenizer calibration, **and the per-model effort vocabulary** (`efforts`) per the provider research. Routing reads this; effort is clamped/omitted against the chosen model's set, never sent unsupported.\n- `src/providers.ts` — maps a provider+model id to an AI SDK model instance. Already multi-provider. Adding a model is data, not code.\n- Every model call captures token usage (`src/agent/run.ts`) so the cost engine has data. Do not drop usage.\n- The UI consumes a normalized `AgentEvent` stream (`src/agent/events.ts`), never the AI SDK's raw types. This decouples the UI from the provider layer and from routing.\n\nIf you find yourself writing `anthropic('claude-...')` anywhere outside `providers.ts`, stop — route it through the selector.\n\n## Layout\n\n```\nsrc/\n cli.tsx entry point; renders the Ink app; picks RoutingSelector by default\n config.ts minimal config (default model, provider from env)\n providers.ts provider+model id -> AI SDK model (multi-provider; contextWindow per model)\n commands.ts slash-command metadata + pure helpers (fuzzy model match, /help, model list)\n tools.ts read / write / edit / list / search / glob / run_shell (AI SDK tools)\n model/\n selector.ts THE ROUTING SEAM — ModelSelector + ModelChoice.backend + FixedSelector (pinned model)\n router.ts RoutingSelector (account-aware): scores (model, account) pairs incl. subscription seats; SubscriptionPinSelector\n scoring.ts PURE scorer: cost + scarcity + limit − plan bonus; deterministic, fixture-tested\n routing-context.ts per-turn account-state snapshot (balance + subscription rate headroom) from usage.json\n cooldown.ts reactive-failover support: classify a failure + park an exhausted account so the router routes around it\n profiles.ts model corpus: quality (SWE-bench), cost ($/Mtok), latency, tokenizer calibration, per-model effort vocab\n tokens.ts calibrated token counting (js-tiktoken × per-model calibration factor)\n preferences.ts persist /prefer kind model choices to ~/.gearbox/routing-preferences.json\n reasoning.ts reasoning/thinking config helpers\n context/\n builder.ts context engine: system + memory + repo map + retrieved files + curated history\n retrieve.ts BM25 lexical retrieval — top-K relevant files for a prompt (no model call)\n repomap.ts repo structure summary for the system prompt\n memory.ts project memory (GEARBOX.md / CLAUDE.md loaded into context)\n compact.ts context compaction (/compact)\n accounts/\n types.ts Account + AuthMethod types (API key, AWS, Azure, Vertex, CLI, OpenAI-compat)\n store.ts accounts.json persistence (~/.gearbox/accounts.json)\n catalog.ts provider catalog (known providers, env vars, labels)\n detect.ts auto-detect env creds + cloud credentials\n onboard.ts interactive add/test account flows; addByPastedKey routes through sniff.ts\n sniff.ts pure credential sniffer: paste anything (key / AWS block / SA JSON / Azure URL / gateway key) → {kind, provider, fields, missing}\n resolve.ts credential resolution (Account → ResolvedCreds) + rank(model) → ordered failover pool (cross-provider, health-sorted)\n discover.ts per-account model discovery (Azure deployments / Foundry / gateway /models) → account.models; catalog defaultModels are seeds, not callable ids\n health.ts account health: classifyError (provider error → state), checkHealth (cached probe, timeout-bounded), recordHealth; no background polling\n usage.ts per-account spend ledger + rate-limit snapshots + balance tracking\n balance.ts provider balance fetch helpers\n help/\n ask.ts /ask corpus: bundled docs + generated command reference, system prompt, meta-question auto-detect\n agent/\n events.ts AgentEvent — normalized stream the UI consumes\n run.ts real agent loop (AI SDK streamText -> AgentEvent), abort-aware; runCompletion = tool-less grounded answer (used by /ask); returns a structured failure (for failover)\n failover.ts runWithFailover: run a turn over the ranked account pool; on a credential failure before output, advance to the next; clear exhaustion errors\n cli-backend.ts claude/codex CLI subprocess backend (for Pro/Max subscriptions)\n mock.ts scripted demo stream (runs with no API key; used by tests)\n ui/\n theme.ts colors + glyphs (the look)\n input.ts pure key→action reducer for the composer (tested)\n history.ts pure ↑/↓ prompt-history nav (tested)\n net.ts background online probe; status bar shows ⚠ offline when down\n useTerminalSize.ts reactive width on resize (everything reflows)\n git.ts current branch for the status line\n App.tsx the Ink app: state, useInput dispatch, commands, turns\n components/ Banner, Transcript, Composer, CommandPalette, StatusBar, PermissionPrompt, Panel\n panel.ts dismissable command-panel model + pure helpers (clamp/window/filter); tested\ntest/ pure-logic + render tests (ink-testing-library); no keys\nDESIGN.md full product vision (routing, requirements, UX)\nexperiments/ prototypes that validated the architecture\n```\n\nThe composer is custom (Ink `useInput` + `src/ui/input.ts`), not a third-party widget — full control over the cursor, ↑/↓ history, and esc-to-interrupt, with no focus/remount fragility. **Multi-line**: ⌃J (or shift/alt+⏎) inserts a newline, ⏎ submits; ↑/↓ move between lines and fall through to history at the top/bottom line; bracketed paste (enabled in `cli.tsx`) inserts multi-line text literally (CR normalized, paste markers stripped) instead of submitting per line. `caretPos()` is the shared line/col helper. **Readline editing** (all pure in `input.ts`, tested): ⌃U/⌃K kill to line start/end, ⌃W / ⌥⌫ kill word, ⌃D forward-delete, ⌥/⌃ + ←→ word-jump, ⌃A/⌃E line home/end. Keys: ⏎ send · ⌃J newline · ↑↓ line/history · ← → cursor · ⌥←→ word · tab complete @file · **shift+tab cycles mode (normal · auto-accept · plan)** · ⌃Y copy last reply · esc interrupt · ⌃c quit. `/keys` shows the cheatsheet.\n\n**Modes & effort.** Three input modes cycled by shift+tab (`App.tsx` `cycleMode`): **normal** (asks before writes/edits/shell), **auto-accept** (file writes/edits apply without asking — the permission broker auto-resolves `write`/`edit`; shell still gated; diffs still render), **plan** (read-only). Plus **yolo** (auto-approve everything) via `/yolo`. **Effort tiers** (`/effort fast|balanced|max`, or `setEffort`) pin the model through the routing seam (fast→haiku, balanced/max→sonnet) — the active mode + `⚡effort` show as badges in the `StatusBar`. **Click pickers** (fullscreen only): clicking the **model** or **effort** label in the status bar opens a floating picker above it (↑↓ select · ⏎ apply · esc close), reusing the same `/model`/`/effort` command path. The slash commands remain the keyboard path. The fragile row+column hit-test lives in pure, tested `statusBarHit`/`statusBarLayout` (`StatusBar.tsx`); `App.tsx` only supplies live layout (composer line count, `PALETTE_ROWS`, the rendered model/effort/mode) and toggles `quickPicker` state. Inline mode has no mouse grab, so the labels stay informational there. **Copy**: ⌃Y / `/copy` copies the last reply via OSC 52 (`src/ui/clipboard.ts`, works over SSH); `/export [file]` writes the transcript to Markdown. **Terminal integration** (`src/ui/terminal.ts`): the tab title (OSC 2) reflects working/idle, and a long turn (>8s) rings the bell + fires a desktop notification (macOS) so you can step away.\n\n**More UX affordances.** **Type-ahead**: prompts submitted while busy are queued (`queueRef`, shown as chips) and sent when the turn ends. **⌃C** interrupts a turn → clears the composer → \"press again to quit\" (`cli.tsx` renders with `exitOnCtrlC:false`). **Large pastes** collapse to a `[Pasted N lines]` chip (`pasteStoreRef`), expanded back on submit. **Fuzzy** `@file`/`/command` pickers (`src/ui/fuzzy.ts` — substring-first, then subsequence scored by boundary+contiguity; tested). **Cost**: live `$` estimate in the status bar from per-turn model+tokens (`estimateCost` + per-model pricing in `providers.ts`). **Syntax highlighting** for code blocks (`src/ui/highlight.ts` — lightweight per-line tokenizer → Ink spans, NEVER raw ANSI; used by both `lines.ts` `clipSpans` and `Markdown.tsx`). `?` on an empty composer shows the cheatsheet (`KEYS_HELP`).\n\n**Sessions** (`src/session.ts`): conversations persist per-project under `~/.gearbox/sessions/<slug>/` (`GEARBOX_HOME` overrides). Each record holds provider-neutral `messages` + the UI `items` + **per-turn `{model, usage, at}`** (routing/cost data — the record is deliberately not single-model). `gearbox --continue`/`-c` resumes the latest; `/resume [n]` lists/loads in-app; `/clear` starts a fresh session. Prompt history persists across runs (`history.json`). Saving is best-effort (never crashes the app); skipped in demo mode.\n\nFeatures: full markdown via **marked** (parse, `marked.lexer`) + **Ink** (render) in `Markdown.tsx` — headings, bold/italic/inline-code, tables, ordered+nested lists, blockquotes, code blocks. NO foreign ANSI in Ink (cli-highlight/marked-terminal were tried and removed — they corrupt Ink's width/wrapping; render marked's token tree as Ink elements instead). Markdown gets a `width` prop (threaded App→Transcript→Markdown) for table/rule sizing. Colored diffs under edits (`src/diff.ts`, edit/write tools return `{summary,diff}`), plan mode (read-only tools + plan prompt; `/plan` or shift+tab), `!cmd` runs a shell command directly (`src/shell.ts`), `@file` mentions (fuzzy picker `src/ui/mention.ts`+`files.ts`; expanded into the model message on send), live \"working · Ns\" timer.\n\n**Boo (the mascot).** A pixel ghost, now **parametric** (`src/ui/ghost/engine.ts`, ported from a Claude Design handoff). A 20×20 pixel sprite composited from composable layers — body (palette) + face (eyes/mouth) + accessory + persona + a frame-driven overlay (tears/dots/confetti/Z's/sparkle/hearts) — then FOLDED into half-block cells (`▀`/`▄`, top px → `t`/glyph color, bottom px → `b`/bg). `renderGhost(cfg)` is the source of truth for the **default blocks path**; it's pure + memoized. The data: 13 faces (`FACES`), 9 palettes (`PALETTES`), 6 accessories, 9 personas (personas/accessories ported but not yet surfaced in the live UI). Ink `color`/`backgroundColor` props only, NEVER raw ANSI (corrupts Ink's width math). PNG paths are **opt-in** via `GEARBOX_GHOST`:\n\n- `GEARBOX_GHOST=kitty` — real PNG via kitty graphics Unicode placeholders (`U+10EEEE`, fg encodes image id, diacritics encode row/col; PNGs transmitted once in `cli.tsx`). NOTE: the placeholder protocol is young and mis-rendered (squished) in Ghostty during testing — kept opt-in until that's solved.\n- `GEARBOX_GHOST=iterm` — OSC 1337 splash banner (iTerm2/WezTerm).\n\n`detectImageMode()` returns `blocks` unless `GEARBOX_GHOST` opts in. Baked PNGs live in `src/ui/mascot-png.ts`; `bun run scripts/ghost-preview.ts` previews the parametric engine (splash + all faces + the in-flow state crops). **Boo is animated but deliberately calm** on the blocks path (`AnimatedGhost` in `Mascot.tsx`): one shared, unhurried 240ms tick (leaf-local `useTick`, never lifted to App root); talk + overlays advance at half that (~480ms). There is NO idle bob/float and NO splash sparkle — motion is a quiet sign of life, not fidgeting (the splash just blinks every ~6s; in-flow only the state-meaningful overlay/talk moves). `GEARBOX_NO_MOTION=1` freezes to frame 0. `/ghost [mood]` cycles the skin (`skinToCfg` maps it to a cfg; `shades` is the cool face + shades accessory).\n\n**Layout: fullscreen by default; inline is opt-in.** **Fullscreen is the default** (alt-screen frame + virtualized scroll region + scrollbar + mouse wheel scroll); `--inline`, `GEARBOX_INLINE=1`, or `/config inline on` (pref `fullscreen: false`) opts into inline mode. `GEARBOX_FULLSCREEN=1` or `--fullscreen` forces fullscreen explicitly. The decision lives in `cli.tsx` (`wantsFullscreen`). Grabbing the mouse for wheel-scroll is exactly what disables native terminal selection, so in fullscreen mode text selection requires the terminal's modifier (e.g. Option-drag in Ghostty). **Inline mode** (the plain `Transcript` component): no alt-screen, no mouse grab — native click-drag selection / scrollback / copy all work with no modifier. The transcript is a **virtualized line buffer**: `src/ui/lines.ts` (`itemsToLines`) flattens items into styled `Line`s (markdown→lines, wrapping, diffs) — INVARIANT: every line ≤ width (tested), so nothing overflows. **Streaming perf**: flattening the markdown-heavy `assistant`/`user` items is super-linear with their length, so `staticItemLines` memoizes per item in a `WeakMap` keyed by object reference (unchanged items keep identity across renders, so only the changing tail re-parses — history is free; running tools are not cached since their spinner animates). On the producer side, assistant **text deltas are coalesced** on a ~45ms flush timer in `App.tsx`'s `onEvent` (mirroring the tool-stream coalescer), so streaming re-renders at ~22fps instead of per-token — both together stop the auto-scroll jitter that grew with reply length. `finishAssistant`/the turn `finally` flush any buffered text before marking done or on interrupt. In fullscreen, `App` renders only the visible window via `Viewport` (`src/ui/components/Viewport.tsx`) at a computed `transcriptHeight = rows − header − footer` (footer over-estimated so the frame never exceeds the screen; alt-screen clips, so under-filling is safe). Fullscreen scroll: mouse wheel (SGR mouse reporting enabled in `cli.tsx`; parsed off raw stdin in `App` since Ink doesn't model mouse — buttons 64/65) and PgUp/PgDn; new output re-pins to the bottom (`atBottomRef`); a scrollbar sits on the right. (In fullscreen, mouse reporting means text selection needs the terminal's modifier, e.g. Option-drag in Ghostty — which is why inline is now the default.) The virtualized buffer replaced an earlier flex/overflow fullscreen that corrupted on tall output. Chrome spans full width; prose wraps ≤100 cols. The plain `Transcript` component is the inline-fallback renderer. `scripts/gen-mascot.ts` still bakes the PNGs + baked sprites (`mascot-sprite.ts` `GHOSTS`) — but those now feed **only the opt-in kitty/iTerm image path** (`image.ts`); the default blocks path renders the parametric engine instead. The splash scales to the terminal (big=2×/mini=1×/none by rows×cols, in `App.tsx`). The inline/working presence is the compact **state ghost** (see below) — a native-resolution head crop so Boo never dominates the transcript.\n\nCommands are grouped in `/help` (models · conversation · accounts · save · modes · settings · other) and `src/commands.ts` carries plain-language descriptions: /model [name] (fuzzy — \"haiku\"; `/model auto` routes, `/model all` lists every provider) /effort [fast|balanced|max] /prefer [kind model] (remember a confirmed routing preference for a task type) /clear /resume /retry /compact /context /memory /ask <q> (answer questions about Gearbox itself from its bundled docs via a cheap routed model; plain meta-questions auto-route here with a visible affordance) /account (unified: list/add/login/use/rm/refresh — `/accounts` and `/login` are hidden aliases; `/account refresh` re-discovers each account's real callable models) /cost /copy /export [file] /plan /yolo /theme /config (theme·vim·notify·inline; `/vim` is a hidden alias) /init /keys /help /exit. **Hidden** (work but not listed): /accounts /login /vim /ghost. **Removed:** /cwd (the working dir now shows in `/context`). `formatModelList` shows usable models first and collapses no-key providers to a one-line count.\n\n**Command panel (fullscreen only).** Big info-dump commands open a dismissable, Esc-closable overlay instead of dumping into the transcript (`Panel.tsx` + pure `panel.ts`, wired in `App.tsx`): `/help` `/keys` `/context` `/cost` `/memory` are scrollable static dumps (reuse `itemsToLines` + `Viewport`); `/account` and `/model` are interactive lists (↑↓ select · ⏎ acts — they just dispatch the equivalent `/account <n>` / `/model <id>` command and close), and `/model` has type-to-filter (127 Foundry models). The panel replaces the transcript Viewport region while open and takes precedence over `welcome`; the key handler is a branch in `useInput` placed after ⌃C so Esc closes the panel rather than interrupting a turn. Short confirmations (`model → haiku`, `remembered`, `✓ added`, errors) stay inline. Inline mode keeps the old inline printing (no alt-screen to overlay). `openInfoPanel` returns false inline so callers fall back to `push`.\n\n**Accounts: reliability by design.** Every subscription, API key, and cloud credential is meant to work all the time. Switching is **by name only** (a stable unique `slug` per account, e.g. `claude-work`; positional numbers are gone — removing an account never repoints another). Each account carries a cached **health** state (`✓ ready · ⚠ expired · ✗ invalid · ⏳ limited · — unknown`) refreshed at natural touchpoints (boot sweep, opening `/account`, on switch, on live failure) — never by background polling; probes are timeout-bounded. A turn runs through a **failover pool**: `resolve.rank(model)` returns every account that can serve the model's family (cross-provider — Claude can fall Anthropic key → Bedrock → Vertex), health-sorted; `agent/failover.ts` tries them best-first and, on a credential-class failure **before any output** (expired/invalid/no-credit/rate-limited), transparently advances to the next and tells the user which account ran. A real (network/model) error or any failure after output streamed does NOT churn the pool. When the pool is exhausted, one consolidated error names each account, why it failed, and the one command to fix it. Expired subscriptions get one-step re-login: `/account login <name>` (and CLI failures name that exact command). `/account add <paste>` runs the credential **sniffer** (`accounts/sniff.ts`) — paste an API key, an AWS access key or credentials block, a Vertex service-account JSON, an Azure endpoint, or a Vercel gateway key, and it identifies the provider, fills the gaps interactively, and live-tests it.\n\n**Permission gate:** `write_file`/`edit_file`/`run_shell` block on a confirm before mutating. Broker: `src/permission.ts` (`requestPermission` in the tools; `setPermissionHandler` installed by `App`; no handler → allow, so tests/headless are unchanged). Decisions: **once** (1), **always** (2, grants that kind for the session), **all/yolo** (a, auto-approves everything until toggled), **deny** (3/esc). YOLO is also toggled by `/yolo` or started with `--yolo`; a `⚡ yolo` badge shows in the status. The `!` prefix is user-initiated so it is NOT gated. Search/nav tools: `search` (ripgrep, Bun-walk fallback) and `glob` (`Bun.Glob`), both read-only (also in plan mode). The working indicator IS Boo now (`components/Working.tsx`): a compact head-crop ghost whose face follows the agent state — thinking (dots) → streaming (talk) → tool (loading dots) → a clean-finish celebrate (party hat + confetti) → error (crying with falling tears). `App.tsx` derives `mascotState` from the `onEvent` stream; the success/error beat **lingers ~1.5s** after the turn (`linger` state — the working line gates on `busy || linger`, since it would otherwise unmount the instant `busy` goes false). Crops are per-state (`stateView`): head (rows 4–14), head+dots (2–14), head+hat (0–14) so overlays outside the head still read. This deliberately supersedes the earlier \"Boo stays on the welcome splash only / in-flow movement reads as noise\" decision — the compact, state-bearing ghost is the point of the design port.\n\n## Conventions\n\n- Runtime: **Bun**. TypeScript + TSX. Run with `bun run src/cli.tsx`.\n- UI: **Ink** (React for terminals) + **@inkjs/ui**. Keep it calm and beautiful: restrained palette (one accent), generous spacing, consistent glyphs. The look lives in `src/ui/theme.ts` — change colors/glyphs there, not inline.\n- Open + free: MIT, no paid dependencies, no hosted backend, no telemetry. The only cost is the user's own model calls on their own keys.\n- Tools must be safe by default: confirm or sandbox anything destructive; never `rm -rf` or write outside the workspace without intent.\n\n## Run it\n\n```bash\nbun install\n# set at least one key:\nexport ANTHROPIC_API_KEY=... # or OPENAI_API_KEY / GOOGLE_GENERATIVE_AI_API_KEY / DEEPSEEK_API_KEY\nbun run src/cli.tsx # or: bun start\n```\n\nWith no key it launches in demo mode (a scripted transcript) so the UI still runs.\n\n## Test\n\n```bash\nbun test # render tests + agent-loop tests; no API key needed\nbun run typecheck # tsc --noEmit\n```"
|
|
145652
|
+
text: "# Gearbox — project guide\n\nGearbox is a multi-provider coding harness for the terminal: a beautiful, simple terminal agent that reads/writes code and runs commands, talking to any provider (Anthropic, OpenAI, Google, DeepSeek) through one clean loop.\n\n**The point of the project:** intelligent per-task *model routing* — automatically picking the right model for each task across every provider and account you pay for. Basic routing is live (`RoutingSelector` — classify → quality bar → cheapest winner); the richer engine (shadow-eval, credit/limit penalties, confidence display) layers on top of the same seam. See `DESIGN.md` for the full vision and `experiments/FINDINGS.md` for the validation behind it.\n\n## The one rule that matters\n\n**Keep the routing seam clean.** The agent must never hardcode a model. It asks a `ModelSelector` for the model to use. `RoutingSelector` is the live default (classify task → filter by quality bar → cheapest winner); `FixedSelector` is used only when a model is explicitly pinned (`--model` flag or `/model <name>`). Concretely:\n\n- `src/model/selector.ts` — the seam. `select(task) => ModelChoice` (now carrying an optional `Backend` so the runner can dispatch in-loop vs a subscription seat). Do not bypass it.\n- `src/model/router.ts` — `RoutingSelector` is **account-aware**: it scores `(model, account)` PAIRS, not just models. Candidates = in-loop registry models × the accounts that serve them + flat-rate subscription **seats** (`providers.subscriptionSeats()`, a seat mirrors a canonical model but runs via the vendor binary). Flow: classify → quality bar → context fit → global/`/prefer` preference filter → score → return `{model, reason, backend}`. A seat is ~free until its rate limit, so it wins by default and fails over to metered API as the window fills. `SubscriptionPinSelector`/`FixedSelector` are hard pins (explicit `/account use` or `/model`) that beat auto-routing.\n- `src/model/scoring.ts` — the PURE scorer: `score = costEst + scarcity + switchPenalty + limitPenalty + apiThrottlePenalty − planBonus`, argmin tie-broken deterministically. No I/O; fixture-tested. Every account-state term degrades safely — and where a provider exposes nothing, we ESTIMATE rather than go blind: live API rate-limit headers (`src/model/rate-headers.ts`, parsed from each response → `apiThrottle`, gentle near-empty penalty) and a self-declared budget − tracked spend (`/budget`, an estimated balance feeding scarcity). A missing signal with no estimate is still neutral (no errors per provider).\n- `src/model/routing-context.ts` — `buildRoutingContext()`: the per-turn account-state snapshot (balance where exposed, subscription rate headroom = min over the 5h/weekly windows) read from disk-cached `usage.json`. No network on the hot path; balances refreshed in the background (App effect).\n- `src/model/profiles.ts` — the data corpus: quality, cost, latency, tokenizer calibration, **and the per-model effort vocabulary** (`efforts`) per the provider research. Routing reads this; effort is clamped/omitted against the chosen model's set, never sent unsupported.\n- `src/providers.ts` — maps a provider+model id to an AI SDK model instance. Already multi-provider. Adding a model is data, not code.\n- Every model call captures token usage (`src/agent/run.ts`) so the cost engine has data. Do not drop usage.\n- The UI consumes a normalized `AgentEvent` stream (`src/agent/events.ts`), never the AI SDK's raw types. This decouples the UI from the provider layer and from routing.\n\nIf you find yourself writing `anthropic('claude-...')` anywhere outside `providers.ts`, stop — route it through the selector.\n\n## Layout\n\n```\nsrc/\n cli.tsx entry point; renders the Ink app; picks RoutingSelector by default\n config.ts minimal config (default model, provider from env)\n providers.ts provider+model id -> AI SDK model (multi-provider; contextWindow per model)\n commands.ts slash-command metadata + pure helpers (fuzzy model match, /help, model list)\n tools.ts read / write / edit / list / search / glob / run_shell (AI SDK tools)\n model/\n selector.ts THE ROUTING SEAM — ModelSelector + ModelChoice.backend + FixedSelector (pinned model)\n router.ts RoutingSelector (account-aware): scores (model, account) pairs incl. subscription seats; SubscriptionPinSelector\n scoring.ts PURE scorer: cost + scarcity + limit − plan bonus; deterministic, fixture-tested\n routing-context.ts per-turn account-state snapshot (balance + subscription rate headroom) from usage.json\n cooldown.ts reactive-failover support: classify a failure + park an exhausted account so the router routes around it\n profiles.ts model corpus: quality (SWE-bench), cost ($/Mtok), latency, tokenizer calibration, per-model effort vocab\n tokens.ts calibrated token counting (js-tiktoken × per-model calibration factor)\n preferences.ts persist /prefer kind model choices to ~/.gearbox/routing-preferences.json\n reasoning.ts reasoning/thinking config helpers\n context/\n builder.ts context engine: system + memory + repo map + retrieved files + curated history\n retrieve.ts BM25 lexical retrieval — top-K relevant files for a prompt (no model call)\n repomap.ts repo structure summary for the system prompt\n memory.ts project memory (GEARBOX.md / CLAUDE.md loaded into context)\n compact.ts context compaction (/compact)\n accounts/\n types.ts Account + AuthMethod types (API key, AWS, Azure, Vertex, CLI, OpenAI-compat)\n store.ts accounts.json persistence (~/.gearbox/accounts.json)\n catalog.ts provider catalog (known providers, env vars, labels)\n detect.ts auto-detect env creds + cloud credentials\n onboard.ts interactive add/test account flows; addByPastedKey routes through sniff.ts\n sniff.ts pure credential sniffer: paste anything (key / AWS block / SA JSON / Azure URL / gateway key) → {kind, provider, fields, missing}\n resolve.ts credential resolution (Account → ResolvedCreds) + rank(model) → ordered failover pool (cross-provider, health-sorted)\n discover.ts per-account model discovery (Azure deployments / Foundry / gateway /models) → account.models; catalog defaultModels are seeds, not callable ids\n health.ts account health: classifyError (provider error → state), checkHealth (cached probe, timeout-bounded), recordHealth; no background polling\n usage.ts per-account spend ledger + rate-limit snapshots + balance tracking\n balance.ts provider balance fetch helpers\n help/\n ask.ts /ask corpus: bundled docs + generated command reference, system prompt, meta-question auto-detect\n agent/\n events.ts AgentEvent — normalized stream the UI consumes\n run.ts real agent loop (AI SDK streamText -> AgentEvent), abort-aware; runCompletion = tool-less grounded answer (used by /ask); returns a structured failure (for failover)\n failover.ts runWithFailover: run a turn over the ranked account pool; on a credential failure before output, advance to the next; clear exhaustion errors\n cli-backend.ts claude/codex CLI subprocess backend (for Pro/Max subscriptions)\n mock.ts scripted demo stream (runs with no API key; used by tests)\n ui/\n theme.ts colors + glyphs (the look)\n input.ts pure key→action reducer for the composer (tested)\n history.ts pure ↑/↓ prompt-history nav (tested)\n net.ts background online probe; status bar shows ⚠ offline when down\n useTerminalSize.ts reactive width on resize (everything reflows)\n git.ts current branch for the status line\n App.tsx the Ink app: state, useInput dispatch, commands, turns\n components/ Banner, Transcript, Composer, CommandPalette, StatusBar, PermissionPrompt, Panel\n panel.ts dismissable command-panel model + pure helpers (clamp/window/filter); tested\ntest/ pure-logic + render tests (ink-testing-library); no keys\nDESIGN.md full product vision (routing, requirements, UX)\nexperiments/ prototypes that validated the architecture\n```\n\nThe composer is custom (Ink `useInput` + `src/ui/input.ts`), not a third-party widget — full control over the cursor, ↑/↓ history, and esc-to-interrupt, with no focus/remount fragility. **Multi-line**: ⌃J (or shift/alt+⏎) inserts a newline, ⏎ submits; ↑/↓ move between lines and fall through to history at the top/bottom line; bracketed paste (enabled in `cli.tsx`) inserts multi-line text literally (CR normalized, paste markers stripped) instead of submitting per line. `caretPos()` is the shared line/col helper. **Readline editing** (all pure in `input.ts`, tested): ⌃U/⌃K kill to line start/end, ⌃W / ⌥⌫ kill word, ⌃D forward-delete, ⌥/⌃ + ←→ word-jump, ⌃A/⌃E line home/end. Keys: ⏎ send · ⌃J newline · ↑↓ line/history · ← → cursor · ⌥←→ word · tab complete @file · **shift+tab cycles mode (normal · auto-accept · plan)** · ⌃Y copy last reply · esc interrupt · ⌃c quit. `/keys` shows the cheatsheet.\n\n**Modes & effort.** Three input modes cycled by shift+tab (`App.tsx` `cycleMode`): **normal** (asks before writes/edits/shell), **auto-accept** (file writes/edits apply without asking — the permission broker auto-resolves `write`/`edit`; shell still gated; diffs still render), **plan** (read-only). Plus **yolo** (auto-approve everything) via `/yolo`. **Effort tiers** (`/effort fast|balanced|max`, or `setEffort`) pin the model through the routing seam (fast→haiku, balanced/max→sonnet) — the active mode + `⚡effort` show as badges in the `StatusBar`. **Click pickers** (fullscreen only): clicking the **model** or **effort** label in the status bar opens a floating picker above it (↑↓ select · ⏎ apply · esc close), reusing the same `/model`/`/effort` command path. The slash commands remain the keyboard path. The fragile row+column hit-test lives in pure, tested `statusBarHit`/`statusBarLayout` (`StatusBar.tsx`); `App.tsx` only supplies live layout (composer line count, `PALETTE_ROWS`, the rendered model/effort/mode) and toggles `quickPicker` state. Inline mode has no mouse grab, so the labels stay informational there. **Copy**: ⌃Y / `/copy` copies the last reply via OSC 52 (`src/ui/clipboard.ts`, works over SSH); `/export [file]` writes the transcript to Markdown. **Terminal integration** (`src/ui/terminal.ts`): the tab title (OSC 2) reflects working/idle, and a long turn (>8s) rings the bell + fires a desktop notification (macOS) so you can step away.\n\n**More UX affordances.** **Type-ahead**: prompts submitted while busy are queued (`queueRef`, shown as chips) and sent when the turn ends. **⌃C** interrupts a turn → clears the composer → \"press again to quit\" (`cli.tsx` renders with `exitOnCtrlC:false`). **Large pastes** collapse to a `[Pasted N lines]` chip (`pasteStoreRef`), expanded back on submit. **Fuzzy** `@file`/`/command` pickers (`src/ui/fuzzy.ts` — substring-first, then subsequence scored by boundary+contiguity; tested). **Cost**: live `$` estimate in the status bar from per-turn model+tokens (`estimateCost` + per-model pricing in `providers.ts`). **Syntax highlighting** for code blocks (`src/ui/highlight.ts` — lightweight per-line tokenizer → Ink spans, NEVER raw ANSI; used by both `lines.ts` `clipSpans` and `Markdown.tsx`). `?` on an empty composer shows the cheatsheet (`KEYS_HELP`).\n\n**Sessions** (`src/session.ts`): conversations persist per-project under `~/.gearbox/sessions/<slug>/` (`GEARBOX_HOME` overrides). Each record holds provider-neutral `messages` + the UI `items` + **per-turn `{model, usage, at}`** (routing/cost data — the record is deliberately not single-model). `gearbox --continue`/`-c` resumes the latest; `/resume [n]` lists/loads in-app; `/clear` starts a fresh session. Prompt history persists across runs (`history.json`). Saving is best-effort (never crashes the app); skipped in demo mode.\n\nFeatures: full markdown via **marked** (parse, `marked.lexer`) + **Ink** (render) in `Markdown.tsx` — headings, bold/italic/inline-code, tables, ordered+nested lists, blockquotes, code blocks. NO foreign ANSI in Ink (cli-highlight/marked-terminal were tried and removed — they corrupt Ink's width/wrapping; render marked's token tree as Ink elements instead). Markdown gets a `width` prop (threaded App→Transcript→Markdown) for table/rule sizing. Colored diffs under edits (`src/diff.ts`, edit/write tools return `{summary,diff}`), plan mode (read-only tools + plan prompt; `/plan` or shift+tab), `!cmd` runs a shell command directly (`src/shell.ts`), `@file` mentions (fuzzy picker `src/ui/mention.ts`+`files.ts`; expanded into the model message on send), live \"working · Ns\" timer.\n\n**Boo (the mascot).** A pixel ghost, now **parametric** (`src/ui/ghost/engine.ts`, ported from a Claude Design handoff). A 20×20 pixel sprite composited from composable layers — body (palette) + face (eyes/mouth) + accessory + persona + a frame-driven overlay (tears/dots/confetti/Z's/sparkle/hearts) — then FOLDED into half-block cells (`▀`/`▄`, top px → `t`/glyph color, bottom px → `b`/bg). `renderGhost(cfg)` is the source of truth for the **default blocks path**; it's pure + memoized. The data: 13 faces (`FACES`), 9 palettes (`PALETTES`), 6 accessories, 9 personas (personas/accessories ported but not yet surfaced in the live UI). Ink `color`/`backgroundColor` props only, NEVER raw ANSI (corrupts Ink's width math). PNG paths are **opt-in** via `GEARBOX_GHOST`:\n\n- `GEARBOX_GHOST=kitty` — real PNG via kitty graphics Unicode placeholders (`U+10EEEE`, fg encodes image id, diacritics encode row/col; PNGs transmitted once in `cli.tsx`). NOTE: the placeholder protocol is young and mis-rendered (squished) in Ghostty during testing — kept opt-in until that's solved.\n- `GEARBOX_GHOST=iterm` — OSC 1337 splash banner (iTerm2/WezTerm).\n\n`detectImageMode()` returns `blocks` unless `GEARBOX_GHOST` opts in. Baked PNGs live in `src/ui/mascot-png.ts`; `bun run scripts/ghost-preview.ts` previews the parametric engine (splash + all faces + the in-flow state crops). **Boo is animated but deliberately calm** on the blocks path (`AnimatedGhost` in `Mascot.tsx`): one shared, unhurried 240ms tick (leaf-local `useTick`, never lifted to App root); talk + overlays advance at half that (~480ms). There is NO idle bob/float and NO splash sparkle — motion is a quiet sign of life, not fidgeting (the splash just blinks every ~6s; in-flow only the state-meaningful overlay/talk moves). `GEARBOX_NO_MOTION=1` freezes to frame 0. `/ghost [mood]` cycles the skin (`skinToCfg` maps it to a cfg; `shades` is the cool face + shades accessory).\n\n**Layout: fullscreen by default; inline is opt-in.** **Fullscreen is the default** (alt-screen frame + virtualized scroll region + scrollbar + mouse wheel scroll); `--inline`, `GEARBOX_INLINE=1`, or `/config inline on` (pref `fullscreen: false`) opts into inline mode. `GEARBOX_FULLSCREEN=1` or `--fullscreen` forces fullscreen explicitly. The decision lives in `cli.tsx` (`wantsFullscreen`). Grabbing the mouse for wheel-scroll is exactly what disables native terminal selection, so in fullscreen mode text selection requires the terminal's modifier (e.g. Option-drag in Ghostty). **Inline mode** (the plain `Transcript` component): no alt-screen, no mouse grab — native click-drag selection / scrollback / copy all work with no modifier. The transcript is a **virtualized line buffer**: `src/ui/lines.ts` (`itemsToLines`) flattens items into styled `Line`s (markdown→lines, wrapping, diffs) — INVARIANT: every line ≤ width (tested), so nothing overflows. **Streaming perf**: flattening the markdown-heavy `assistant`/`user` items is super-linear with their length, so `staticItemLines` memoizes per item in a `WeakMap` keyed by object reference (unchanged items keep identity across renders, so only the changing tail re-parses — history is free; running tools are not cached since their spinner animates). On the producer side, assistant **text deltas are coalesced** on a ~45ms flush timer in `App.tsx`'s `onEvent` (mirroring the tool-stream coalescer), so streaming re-renders at ~22fps instead of per-token — both together stop the auto-scroll jitter that grew with reply length. `finishAssistant`/the turn `finally` flush any buffered text before marking done or on interrupt. In fullscreen, `App` renders only the visible window via `Viewport` (`src/ui/components/Viewport.tsx`) at a computed `transcriptHeight = rows − header − footer` (footer over-estimated so the frame never exceeds the screen; alt-screen clips, so under-filling is safe). Fullscreen scroll: mouse wheel (SGR mouse reporting enabled in `cli.tsx`; parsed off raw stdin in `App` since Ink doesn't model mouse — buttons 64/65) and PgUp/PgDn; new output re-pins to the bottom (`atBottomRef`); a scrollbar sits on the right. (In fullscreen, mouse reporting means text selection needs the terminal's modifier, e.g. Option-drag in Ghostty — which is why inline is now the default.) The virtualized buffer replaced an earlier flex/overflow fullscreen that corrupted on tall output. Chrome spans full width; prose wraps ≤100 cols. The plain `Transcript` component is the inline-fallback renderer. `scripts/gen-mascot.ts` still bakes the PNGs + baked sprites (`mascot-sprite.ts` `GHOSTS`) — but those now feed **only the opt-in kitty/iTerm image path** (`image.ts`); the default blocks path renders the parametric engine instead. The splash scales to the terminal (big=2×/mini=1×/none by rows×cols, in `App.tsx`). The inline/working presence is the compact **state ghost** (see below) — a native-resolution head crop so Boo never dominates the transcript.\n\nCommands are grouped in `/help` (models · conversation · accounts · save · modes · settings · other) and `src/commands.ts` carries plain-language descriptions: /model [name] (fuzzy — \"haiku\"; `/model auto` routes, `/model all` lists every provider) /effort [fast|balanced|max] /prefer [kind model] (remember a confirmed routing preference for a task type) /clear /resume /retry /compact /context /memory /ask <q> (answer questions about Gearbox itself from its bundled docs via a cheap routed model; plain meta-questions auto-route here with a visible affordance) /account (unified: list/add/login/use/rm/refresh — `/accounts` and `/login` are hidden aliases; `/account refresh` re-discovers each account's real callable models) /cost (fullscreen: TOGGLES a persistent usage strip above the composer — context % · subscription 5h/7d headroom · session spend — stays until toggled off, persisted via `prefs.statusPinned`, doesn't capture input; `StatusStrip.tsx`. inline: one-shot card) /copy /export [file] /plan /yolo /theme /config (theme·vim·notify·inline; `/vim` is a hidden alias) /init /keys /help /exit. **Hidden** (work but not listed): /accounts /login /vim /ghost. **Removed:** /cwd (the working dir now shows in `/context`). `formatModelList` shows usable models first and collapses no-key providers to a one-line count.\n\n**Command panel (fullscreen only).** Big info-dump commands open a dismissable, Esc-closable overlay instead of dumping into the transcript (`Panel.tsx` + pure `panel.ts`, wired in `App.tsx`): `/help` `/keys` `/context` `/cost` `/memory` are scrollable static dumps (reuse `itemsToLines` + `Viewport`); `/account` and `/model` are interactive lists (↑↓ select · ⏎ acts — they just dispatch the equivalent `/account <n>` / `/model <id>` command and close), and `/model` has type-to-filter (127 Foundry models). The panel replaces the transcript Viewport region while open and takes precedence over `welcome`; the key handler is a branch in `useInput` placed after ⌃C so Esc closes the panel rather than interrupting a turn. Short confirmations (`model → haiku`, `remembered`, `✓ added`, errors) stay inline. Inline mode keeps the old inline printing (no alt-screen to overlay). `openInfoPanel` returns false inline so callers fall back to `push`.\n\n**Accounts: reliability by design.** Every subscription, API key, and cloud credential is meant to work all the time. Switching is **by name only** (a stable unique `slug` per account, e.g. `claude-work`; positional numbers are gone — removing an account never repoints another). Each account carries a cached **health** state (`✓ ready · ⚠ expired · ✗ invalid · ⏳ limited · — unknown`) refreshed at natural touchpoints (boot sweep, opening `/account`, on switch, on live failure) — never by background polling; probes are timeout-bounded. A turn runs through a **failover pool**: `resolve.rank(model)` returns every account that can serve the model's family (cross-provider — Claude can fall Anthropic key → Bedrock → Vertex), health-sorted; `agent/failover.ts` tries them best-first and, on a credential-class failure **before any output** (expired/invalid/no-credit/rate-limited), transparently advances to the next and tells the user which account ran. A real (network/model) error or any failure after output streamed does NOT churn the pool. When the pool is exhausted, one consolidated error names each account, why it failed, and the one command to fix it. Expired subscriptions get one-step re-login: `/account login <name>` (and CLI failures name that exact command). `/account add <paste>` runs the credential **sniffer** (`accounts/sniff.ts`) — paste an API key, an AWS access key or credentials block, a Vertex service-account JSON, an Azure endpoint, or a Vercel gateway key, and it identifies the provider, fills the gaps interactively, and live-tests it.\n\n**Permission gate:** `write_file`/`edit_file`/`run_shell` block on a confirm before mutating. Broker: `src/permission.ts` (`requestPermission` in the tools; `setPermissionHandler` installed by `App`; no handler → allow, so tests/headless are unchanged). Decisions: **once** (1), **always** (2, grants that kind for the session), **all/yolo** (a, auto-approves everything until toggled), **deny** (3/esc). YOLO is also toggled by `/yolo` or started with `--yolo`; a `⚡ yolo` badge shows in the status. The `!` prefix is user-initiated so it is NOT gated. Search/nav tools: `search` (ripgrep, Bun-walk fallback) and `glob` (`Bun.Glob`), both read-only (also in plan mode). The working indicator IS Boo now (`components/Working.tsx`): a compact head-crop ghost whose face follows the agent state — thinking (dots) → streaming (talk) → tool (loading dots) → a clean-finish celebrate (party hat + confetti) → error (crying with falling tears). `App.tsx` derives `mascotState` from the `onEvent` stream; the success/error beat **lingers ~1.5s** after the turn (`linger` state — the working line gates on `busy || linger`, since it would otherwise unmount the instant `busy` goes false). Crops are per-state (`stateView`): head (rows 4–14), head+dots (2–14), head+hat (0–14) so overlays outside the head still read. This deliberately supersedes the earlier \"Boo stays on the welcome splash only / in-flow movement reads as noise\" decision — the compact, state-bearing ghost is the point of the design port.\n\n## Conventions\n\n- Runtime: **Bun**. TypeScript + TSX. Run with `bun run src/cli.tsx`.\n- UI: **Ink** (React for terminals) + **@inkjs/ui**. Keep it calm and beautiful: restrained palette (one accent), generous spacing, consistent glyphs. The look lives in `src/ui/theme.ts` — change colors/glyphs there, not inline.\n- Open + free: MIT, no paid dependencies, no hosted backend, no telemetry. The only cost is the user's own model calls on their own keys.\n- Tools must be safe by default: confirm or sandbox anything destructive; never `rm -rf` or write outside the workspace without intent.\n\n## Run it\n\n```bash\nbun install\n# set at least one key:\nexport ANTHROPIC_API_KEY=... # or OPENAI_API_KEY / GOOGLE_GENERATIVE_AI_API_KEY / DEEPSEEK_API_KEY\nbun run src/cli.tsx # or: bun start\n```\n\nWith no key it launches in demo mode (a scripted transcript) so the UI still runs.\n\n## Test\n\n```bash\nbun test # render tests + agent-loop tests; no API key needed\nbun run typecheck # tsc --noEmit\n```"
|
|
145522
145653
|
},
|
|
145523
145654
|
{
|
|
145524
145655
|
file: "DESIGN.md",
|
|
@@ -146251,6 +146382,21 @@ async function runVerification(commands, opts) {
|
|
|
146251
146382
|
}
|
|
146252
146383
|
return results;
|
|
146253
146384
|
}
|
|
146385
|
+
function nextStepFor(failures, changedFiles) {
|
|
146386
|
+
if (!failures.length)
|
|
146387
|
+
return changedFiles.length ? "commit changes" : "/context";
|
|
146388
|
+
const joined = failures.join(`
|
|
146389
|
+
`);
|
|
146390
|
+
if (/\bTS1185\b|merge conflict|conflict marker|<<<<<<<|>>>>>>>/i.test(joined)) {
|
|
146391
|
+
const m2 = joined.match(/([\w./-]+\.(?:ts|tsx|js|jsx|mjs|cjs))[(:]/);
|
|
146392
|
+
return m2 ? `resolve the conflict in ${m2[1]}` : "resolve the merge conflict";
|
|
146393
|
+
}
|
|
146394
|
+
const errFiles = [...joined.matchAll(/([\w./-]+\.(?:ts|tsx|js|jsx|mjs|cjs|py|go|rs))[(:]/g)].map((x2) => x2[1]);
|
|
146395
|
+
if (errFiles.length && errFiles.every((f3) => !changedFiles.some((c) => c === f3 || c.endsWith(f3) || f3.endsWith(c)))) {
|
|
146396
|
+
return "likely predates your change — check the repo state";
|
|
146397
|
+
}
|
|
146398
|
+
return "/retry";
|
|
146399
|
+
}
|
|
146254
146400
|
|
|
146255
146401
|
// src/init.ts
|
|
146256
146402
|
function readJson2(path) {
|
|
@@ -146626,7 +146772,7 @@ function gitBranch() {
|
|
|
146626
146772
|
|
|
146627
146773
|
// src/ui/App.tsx
|
|
146628
146774
|
init_proc();
|
|
146629
|
-
var
|
|
146775
|
+
var jsx_dev_runtime14 = __toESM(require_jsx_dev_runtime(), 1);
|
|
146630
146776
|
import { basename as basename3, extname, resolve as resolve12 } from "node:path";
|
|
146631
146777
|
import { existsSync as existsSync11, readFileSync as readFileSync16, statSync as statSync5 } from "node:fs";
|
|
146632
146778
|
import { writeFile as fsWriteFile } from "node:fs/promises";
|
|
@@ -146651,27 +146797,27 @@ function transcriptMarkdown(items) {
|
|
|
146651
146797
|
else if (it.kind === "assistant")
|
|
146652
146798
|
out.push("## Gearbox", "", it.text, "");
|
|
146653
146799
|
else if (it.kind === "tool")
|
|
146654
|
-
out.push(`> \`${it.name}\` ${it.arg}${it.summary ? "
|
|
146800
|
+
out.push(`> \`${it.name}\` ${it.arg}${it.summary ? " · " + it.summary : ""}`, "");
|
|
146655
146801
|
else if (it.kind === "notice")
|
|
146656
146802
|
out.push(`_${it.text}_`, "");
|
|
146657
146803
|
else if (it.kind === "accounts") {
|
|
146658
146804
|
out.push("**accounts**", "", `current: ${it.view.current}`);
|
|
146659
146805
|
for (const r2 of it.view.rows)
|
|
146660
|
-
out.push(`- ${r2.name} (${r2.type})
|
|
146806
|
+
out.push(`- ${r2.name} (${r2.type}) · ${r2.status} · /account ${r2.alias}`);
|
|
146661
146807
|
out.push("");
|
|
146662
146808
|
} else if (it.kind === "usage") {
|
|
146663
146809
|
out.push("**usage · spend & limits**", "");
|
|
146664
146810
|
for (const a of it.view.subscriptions) {
|
|
146665
146811
|
const limits = (a.limits ?? []).map((l) => `${l.label} ${l.pct}%`).join(" · ");
|
|
146666
|
-
out.push(`- ${a.name} (subscription)
|
|
146812
|
+
out.push(`- ${a.name} (subscription) · ${a.turns} turns${limits ? ` · ${limits}` : ""}`);
|
|
146667
146813
|
}
|
|
146668
146814
|
for (const a of it.view.apiKeys)
|
|
146669
|
-
out.push(`- ${a.name} (API key)
|
|
146815
|
+
out.push(`- ${a.name} (API key) · ${a.spend} · ${a.turns} turns · ${a.tok}`);
|
|
146670
146816
|
out.push(`- total API spend ${it.view.totalApiSpend}`, "");
|
|
146671
146817
|
} else if (it.kind === "context") {
|
|
146672
146818
|
out.push("**context · what's loaded**", "");
|
|
146673
146819
|
for (const r2 of it.view.rows)
|
|
146674
|
-
out.push(`- ${r2.label.trim()}
|
|
146820
|
+
out.push(`- ${r2.label.trim()} · ${r2.display.trim()}`);
|
|
146675
146821
|
out.push(`- total ${it.view.total.trim()}${it.view.windowPct != null ? ` (${it.view.windowPct}% of ${it.view.windowLabel})` : ""}`, "");
|
|
146676
146822
|
} else if (it.kind === "error")
|
|
146677
146823
|
out.push(`**error:** ${it.text}`, "");
|
|
@@ -146681,7 +146827,7 @@ function transcriptMarkdown(items) {
|
|
|
146681
146827
|
}
|
|
146682
146828
|
function friendlyError(msg) {
|
|
146683
146829
|
if (isNetworkError(msg))
|
|
146684
|
-
return `can't reach the provider
|
|
146830
|
+
return `can't reach the provider · you appear to be offline. Check your connection, then /retry.`;
|
|
146685
146831
|
return msg;
|
|
146686
146832
|
}
|
|
146687
146833
|
function firstPath(text2) {
|
|
@@ -146776,16 +146922,16 @@ function ActivityRail({ items, width }) {
|
|
|
146776
146922
|
const toolText = tools2.map((t2) => `${t2.status === "running" ? spin2 : t2.status === "err" ? "!" : "✓"} ${t2.name.replace(/_file$/, "").replace("run_shell", "shell")}`).join(" · ");
|
|
146777
146923
|
const checkText = checks4.map((c) => `${c.ok ? "✓" : "!"} ${c.command}`).join(" · ");
|
|
146778
146924
|
const line = [model ? model.model : null, phase ? phase.label : null, toolText || null, checkText || null].filter(Boolean).join(" · ");
|
|
146779
|
-
return /* @__PURE__ */
|
|
146925
|
+
return /* @__PURE__ */ jsx_dev_runtime14.jsxDEV(Box_default, {
|
|
146780
146926
|
paddingX: 1,
|
|
146781
146927
|
marginTop: 1,
|
|
146782
146928
|
width,
|
|
146783
146929
|
children: [
|
|
146784
|
-
/* @__PURE__ */
|
|
146930
|
+
/* @__PURE__ */ jsx_dev_runtime14.jsxDEV(Text, {
|
|
146785
146931
|
color: color.accentDim,
|
|
146786
146932
|
children: "activity "
|
|
146787
146933
|
}, undefined, false, undefined, this),
|
|
146788
|
-
/* @__PURE__ */
|
|
146934
|
+
/* @__PURE__ */ jsx_dev_runtime14.jsxDEV(Text, {
|
|
146789
146935
|
color: color.faint,
|
|
146790
146936
|
children: line.slice(0, Math.max(width - 10, 20))
|
|
146791
146937
|
}, undefined, false, undefined, this)
|
|
@@ -146795,31 +146941,31 @@ function ActivityRail({ items, width }) {
|
|
|
146795
146941
|
function SetupSplash({ state, width, skin, splashSize }) {
|
|
146796
146942
|
const detected = state.importable.length + state.cloudImportable.length;
|
|
146797
146943
|
const panelWidth = Math.min(Math.max(width - 4, 30), 58);
|
|
146798
|
-
return /* @__PURE__ */
|
|
146944
|
+
return /* @__PURE__ */ jsx_dev_runtime14.jsxDEV(Box_default, {
|
|
146799
146945
|
flexDirection: "column",
|
|
146800
146946
|
alignItems: "center",
|
|
146801
146947
|
children: [
|
|
146802
|
-
/* @__PURE__ */
|
|
146948
|
+
/* @__PURE__ */ jsx_dev_runtime14.jsxDEV(MascotSplash, {
|
|
146803
146949
|
skin,
|
|
146804
146950
|
size: splashSize
|
|
146805
146951
|
}, undefined, false, undefined, this),
|
|
146806
|
-
/* @__PURE__ */
|
|
146952
|
+
/* @__PURE__ */ jsx_dev_runtime14.jsxDEV(Box_default, {
|
|
146807
146953
|
marginTop: 1,
|
|
146808
146954
|
flexDirection: "column",
|
|
146809
146955
|
alignItems: "center",
|
|
146810
146956
|
children: [
|
|
146811
|
-
/* @__PURE__ */
|
|
146957
|
+
/* @__PURE__ */ jsx_dev_runtime14.jsxDEV(Text, {
|
|
146812
146958
|
color: color.accent,
|
|
146813
146959
|
bold: true,
|
|
146814
146960
|
children: "gearbox"
|
|
146815
146961
|
}, undefined, false, undefined, this),
|
|
146816
|
-
/* @__PURE__ */
|
|
146962
|
+
/* @__PURE__ */ jsx_dev_runtime14.jsxDEV(Text, {
|
|
146817
146963
|
color: color.dim,
|
|
146818
146964
|
children: "one terminal · every model you already pay for"
|
|
146819
146965
|
}, undefined, false, undefined, this)
|
|
146820
146966
|
]
|
|
146821
146967
|
}, undefined, true, undefined, this),
|
|
146822
|
-
/* @__PURE__ */
|
|
146968
|
+
/* @__PURE__ */ jsx_dev_runtime14.jsxDEV(Box_default, {
|
|
146823
146969
|
marginTop: 2,
|
|
146824
146970
|
width: panelWidth,
|
|
146825
146971
|
borderStyle: "round",
|
|
@@ -146828,18 +146974,18 @@ function SetupSplash({ state, width, skin, splashSize }) {
|
|
|
146828
146974
|
paddingY: 1,
|
|
146829
146975
|
flexDirection: "column",
|
|
146830
146976
|
children: [
|
|
146831
|
-
detected > 0 ? /* @__PURE__ */
|
|
146977
|
+
detected > 0 ? /* @__PURE__ */ jsx_dev_runtime14.jsxDEV(jsx_dev_runtime14.Fragment, {
|
|
146832
146978
|
children: [
|
|
146833
|
-
/* @__PURE__ */
|
|
146979
|
+
/* @__PURE__ */ jsx_dev_runtime14.jsxDEV(Box_default, {
|
|
146834
146980
|
children: [
|
|
146835
|
-
/* @__PURE__ */
|
|
146981
|
+
/* @__PURE__ */ jsx_dev_runtime14.jsxDEV(Text, {
|
|
146836
146982
|
color: color.ok,
|
|
146837
146983
|
children: [
|
|
146838
146984
|
glyph.on,
|
|
146839
146985
|
" "
|
|
146840
146986
|
]
|
|
146841
146987
|
}, undefined, true, undefined, this),
|
|
146842
|
-
/* @__PURE__ */
|
|
146988
|
+
/* @__PURE__ */ jsx_dev_runtime14.jsxDEV(Text, {
|
|
146843
146989
|
color: color.text,
|
|
146844
146990
|
children: [
|
|
146845
146991
|
detected,
|
|
@@ -146850,75 +146996,75 @@ function SetupSplash({ state, width, skin, splashSize }) {
|
|
|
146850
146996
|
}, undefined, true, undefined, this)
|
|
146851
146997
|
]
|
|
146852
146998
|
}, undefined, true, undefined, this),
|
|
146853
|
-
/* @__PURE__ */
|
|
146999
|
+
/* @__PURE__ */ jsx_dev_runtime14.jsxDEV(Box_default, {
|
|
146854
147000
|
marginTop: 1,
|
|
146855
147001
|
children: [
|
|
146856
|
-
/* @__PURE__ */
|
|
147002
|
+
/* @__PURE__ */ jsx_dev_runtime14.jsxDEV(Text, {
|
|
146857
147003
|
color: color.accent,
|
|
146858
147004
|
children: "/account import"
|
|
146859
147005
|
}, undefined, false, undefined, this),
|
|
146860
|
-
/* @__PURE__ */
|
|
147006
|
+
/* @__PURE__ */ jsx_dev_runtime14.jsxDEV(Text, {
|
|
146861
147007
|
color: color.dim,
|
|
146862
147008
|
children: " connect automatically"
|
|
146863
147009
|
}, undefined, false, undefined, this)
|
|
146864
147010
|
]
|
|
146865
147011
|
}, undefined, true, undefined, this),
|
|
146866
|
-
/* @__PURE__ */
|
|
147012
|
+
/* @__PURE__ */ jsx_dev_runtime14.jsxDEV(Box_default, {
|
|
146867
147013
|
marginTop: 1,
|
|
146868
147014
|
children: [
|
|
146869
|
-
/* @__PURE__ */
|
|
147015
|
+
/* @__PURE__ */ jsx_dev_runtime14.jsxDEV(Text, {
|
|
146870
147016
|
color: color.faint,
|
|
146871
147017
|
children: "or add a different key: "
|
|
146872
147018
|
}, undefined, false, undefined, this),
|
|
146873
|
-
/* @__PURE__ */
|
|
147019
|
+
/* @__PURE__ */ jsx_dev_runtime14.jsxDEV(Text, {
|
|
146874
147020
|
color: color.accent,
|
|
146875
147021
|
children: "/account add <api-key>"
|
|
146876
147022
|
}, undefined, false, undefined, this)
|
|
146877
147023
|
]
|
|
146878
147024
|
}, undefined, true, undefined, this)
|
|
146879
147025
|
]
|
|
146880
|
-
}, undefined, true, undefined, this) : /* @__PURE__ */
|
|
147026
|
+
}, undefined, true, undefined, this) : /* @__PURE__ */ jsx_dev_runtime14.jsxDEV(jsx_dev_runtime14.Fragment, {
|
|
146881
147027
|
children: [
|
|
146882
|
-
/* @__PURE__ */
|
|
147028
|
+
/* @__PURE__ */ jsx_dev_runtime14.jsxDEV(Text, {
|
|
146883
147029
|
color: color.dim,
|
|
146884
147030
|
children: "paste or type a key to get started"
|
|
146885
147031
|
}, undefined, false, undefined, this),
|
|
146886
|
-
/* @__PURE__ */
|
|
147032
|
+
/* @__PURE__ */ jsx_dev_runtime14.jsxDEV(Box_default, {
|
|
146887
147033
|
marginTop: 1,
|
|
146888
|
-
children: /* @__PURE__ */
|
|
147034
|
+
children: /* @__PURE__ */ jsx_dev_runtime14.jsxDEV(Text, {
|
|
146889
147035
|
color: color.accent,
|
|
146890
147036
|
children: "/account add <api-key>"
|
|
146891
147037
|
}, undefined, false, undefined, this)
|
|
146892
147038
|
}, undefined, false, undefined, this)
|
|
146893
147039
|
]
|
|
146894
147040
|
}, undefined, true, undefined, this),
|
|
146895
|
-
(state.hasClaudeCli || state.hasCodexCli) && /* @__PURE__ */
|
|
147041
|
+
(state.hasClaudeCli || state.hasCodexCli) && /* @__PURE__ */ jsx_dev_runtime14.jsxDEV(Box_default, {
|
|
146896
147042
|
marginTop: 2,
|
|
146897
147043
|
flexDirection: "column",
|
|
146898
147044
|
children: [
|
|
146899
|
-
/* @__PURE__ */
|
|
147045
|
+
/* @__PURE__ */ jsx_dev_runtime14.jsxDEV(Text, {
|
|
146900
147046
|
color: color.faint,
|
|
146901
147047
|
children: "subscriptions detected"
|
|
146902
147048
|
}, undefined, false, undefined, this),
|
|
146903
|
-
state.hasClaudeCli && /* @__PURE__ */
|
|
147049
|
+
state.hasClaudeCli && /* @__PURE__ */ jsx_dev_runtime14.jsxDEV(Box_default, {
|
|
146904
147050
|
children: [
|
|
146905
|
-
/* @__PURE__ */
|
|
147051
|
+
/* @__PURE__ */ jsx_dev_runtime14.jsxDEV(Text, {
|
|
146906
147052
|
color: color.accent,
|
|
146907
147053
|
children: "/account add claude"
|
|
146908
147054
|
}, undefined, false, undefined, this),
|
|
146909
|
-
/* @__PURE__ */
|
|
147055
|
+
/* @__PURE__ */ jsx_dev_runtime14.jsxDEV(Text, {
|
|
146910
147056
|
color: color.faint,
|
|
146911
147057
|
children: " Claude Pro / Max"
|
|
146912
147058
|
}, undefined, false, undefined, this)
|
|
146913
147059
|
]
|
|
146914
147060
|
}, undefined, true, undefined, this),
|
|
146915
|
-
state.hasCodexCli && /* @__PURE__ */
|
|
147061
|
+
state.hasCodexCli && /* @__PURE__ */ jsx_dev_runtime14.jsxDEV(Box_default, {
|
|
146916
147062
|
children: [
|
|
146917
|
-
/* @__PURE__ */
|
|
147063
|
+
/* @__PURE__ */ jsx_dev_runtime14.jsxDEV(Text, {
|
|
146918
147064
|
color: color.accent,
|
|
146919
147065
|
children: "/account add codex"
|
|
146920
147066
|
}, undefined, false, undefined, this),
|
|
146921
|
-
/* @__PURE__ */
|
|
147067
|
+
/* @__PURE__ */ jsx_dev_runtime14.jsxDEV(Text, {
|
|
146922
147068
|
color: color.faint,
|
|
146923
147069
|
children: " ChatGPT Plus"
|
|
146924
147070
|
}, undefined, false, undefined, this)
|
|
@@ -146928,9 +147074,9 @@ function SetupSplash({ state, width, skin, splashSize }) {
|
|
|
146928
147074
|
}, undefined, true, undefined, this)
|
|
146929
147075
|
]
|
|
146930
147076
|
}, undefined, true, undefined, this),
|
|
146931
|
-
/* @__PURE__ */
|
|
147077
|
+
/* @__PURE__ */ jsx_dev_runtime14.jsxDEV(Box_default, {
|
|
146932
147078
|
marginTop: 1,
|
|
146933
|
-
children: /* @__PURE__ */
|
|
147079
|
+
children: /* @__PURE__ */ jsx_dev_runtime14.jsxDEV(Text, {
|
|
146934
147080
|
color: color.faint,
|
|
146935
147081
|
children: "/onboard · /account · /help"
|
|
146936
147082
|
}, undefined, false, undefined, this)
|
|
@@ -147015,6 +147161,25 @@ function App2({ selector: initialSelector, runner, fullscreen = false, resumeId
|
|
|
147015
147161
|
};
|
|
147016
147162
|
const panelMaxScrollRef = import_react26.useRef(0);
|
|
147017
147163
|
const panelAccountSlugsRef = import_react26.useRef([]);
|
|
147164
|
+
const [statusPinned, setStatusPinnedState] = import_react26.useState(() => Boolean(loadPrefs().statusPinned));
|
|
147165
|
+
const setStatusPinned = (v) => {
|
|
147166
|
+
setStatusPinnedState(v);
|
|
147167
|
+
updatePrefs({ statusPinned: v });
|
|
147168
|
+
};
|
|
147169
|
+
const currentUsageView = () => {
|
|
147170
|
+
const accounts = listAccounts();
|
|
147171
|
+
const resolve13 = (id) => {
|
|
147172
|
+
const a = getAccount(id);
|
|
147173
|
+
if (a) {
|
|
147174
|
+
const bin = a.auth.kind === "cli" ? a.auth.binary : undefined;
|
|
147175
|
+
return { name: accountName(a), kind: a.exec === "cli" ? "sub" : "api", balanceExposed: a.exec !== "cli" && balanceExposed(a.provider), limitNote: a.exec === "cli" ? `${bin === "codex" ? "Codex" : "Claude"} CLI hasn't reported quota windows yet` : undefined };
|
|
147176
|
+
}
|
|
147177
|
+
if (id === "unknown")
|
|
147178
|
+
return { name: "(unattributed)", kind: "api" };
|
|
147179
|
+
return { name: id, kind: "api" };
|
|
147180
|
+
};
|
|
147181
|
+
return buildUsageView(estimateCost(sessionRef.current.turns), resolve13, Date.now(), accounts.map((a) => a.id));
|
|
147182
|
+
};
|
|
147018
147183
|
const buildPanelModelRows = (cur) => modelRegistry().filter((m2) => providerAvailable(m2.provider)).map((m2) => ({ id: m2.id, label: m2.label, provider: m2.provider, current: m2.id === cur }));
|
|
147019
147184
|
const openInfoPanel = (title, item) => {
|
|
147020
147185
|
if (!fullscreen)
|
|
@@ -147152,7 +147317,7 @@ function App2({ selector: initialSelector, runner, fullscreen = false, resumeId
|
|
|
147152
147317
|
} catch {}
|
|
147153
147318
|
}
|
|
147154
147319
|
if (learned)
|
|
147155
|
-
notice(`loaded the real model list for ${learned} account${learned === 1 ? "" : "s"}
|
|
147320
|
+
notice(`loaded the real model list for ${learned} account${learned === 1 ? "" : "s"} · /model to see them`);
|
|
147156
147321
|
})();
|
|
147157
147322
|
}, []);
|
|
147158
147323
|
import_react26.useEffect(() => {
|
|
@@ -147622,7 +147787,7 @@ function App2({ selector: initialSelector, runner, fullscreen = false, resumeId
|
|
|
147622
147787
|
rows2.push(" no named subscription models exposed yet");
|
|
147623
147788
|
for (const m2 of models)
|
|
147624
147789
|
rows2.push(` ${m2.id === currentId ? glyph.on : glyph.off} ${m2.label}`);
|
|
147625
|
-
rows2.push("", `API models are hidden while a subscription is active
|
|
147790
|
+
rows2.push("", `API models are hidden while a subscription is active · /account off returns to API routing
|
|
147626
147791
|
tip: /model haiku (or any API model name) switches directly and leaves the subscription`);
|
|
147627
147792
|
return rows2.join(`
|
|
147628
147793
|
`);
|
|
@@ -147635,7 +147800,7 @@ function App2({ selector: initialSelector, runner, fullscreen = false, resumeId
|
|
|
147635
147800
|
const exact = matches2.find((m3) => m3.label.toLowerCase() === q || m3.id.toLowerCase() === q);
|
|
147636
147801
|
const m2 = exact ?? (matches2.length === 1 ? matches2[0] : undefined);
|
|
147637
147802
|
if (!m2)
|
|
147638
|
-
return { ok: false, message: `"${query}" matches ${matches2.map((x2) => x2.label).join(", ")}
|
|
147803
|
+
return { ok: false, message: `"${query}" matches ${matches2.map((x2) => x2.label).join(", ")} · be more specific` };
|
|
147639
147804
|
return { ok: true, modelId: m2.id, label: m2.label };
|
|
147640
147805
|
};
|
|
147641
147806
|
const setActiveCliModelId = (modelId) => {
|
|
@@ -147757,12 +147922,12 @@ function App2({ selector: initialSelector, runner, fullscreen = false, resumeId
|
|
|
147757
147922
|
if (exact.length === 1)
|
|
147758
147923
|
return { account: exact[0].a };
|
|
147759
147924
|
if (exact.length > 1)
|
|
147760
|
-
return { error: `"${query}" matches ${exact.map(({ a }) => accountName(a)).join(", ")}
|
|
147925
|
+
return { error: `"${query}" matches ${exact.map(({ a }) => accountName(a)).join(", ")} · use the full alias` };
|
|
147761
147926
|
const fuzzy = accounts.map((a) => ({ a, aliases: [...accountAliases(a)] })).filter(({ aliases }) => aliases.some((x2) => x2.includes(q)));
|
|
147762
147927
|
if (fuzzy.length === 1)
|
|
147763
147928
|
return { account: fuzzy[0].a };
|
|
147764
147929
|
if (fuzzy.length > 1)
|
|
147765
|
-
return { error: `"${query}" matches ${fuzzy.map(({ a }) => accountName(a)).join(", ")}
|
|
147930
|
+
return { error: `"${query}" matches ${fuzzy.map(({ a }) => accountName(a)).join(", ")} · use the full alias` };
|
|
147766
147931
|
return { error: `no account matching "${query}"` };
|
|
147767
147932
|
};
|
|
147768
147933
|
const buildAccountView = (accounts, activeCliId, importable, statuses) => {
|
|
@@ -147823,7 +147988,7 @@ function App2({ selector: initialSelector, runner, fullscreen = false, resumeId
|
|
|
147823
147988
|
const _cliEffortRaw = normalizeEffort(effortRef.current, efforts);
|
|
147824
147989
|
if (_cliEffortRaw === null && effortRef.current !== "medium") {
|
|
147825
147990
|
const { level: nearest } = clampEffort(effortRef.current, efforts);
|
|
147826
|
-
const hint = efforts.length ? `
|
|
147991
|
+
const hint = efforts.length ? ` · try /effort ${nearest}` : "";
|
|
147827
147992
|
throw new Error(`effort "${effortRef.current}" is not supported by ${label ?? binary} (supports: ${efforts.join(", ") || "none"}${hint})`);
|
|
147828
147993
|
}
|
|
147829
147994
|
const cliEffort = _cliEffortRaw ?? undefined;
|
|
@@ -147875,12 +148040,12 @@ ${map4}
|
|
|
147875
148040
|
if (isAsk) {
|
|
147876
148041
|
const docs = loadGearboxDocs();
|
|
147877
148042
|
if (!docs) {
|
|
147878
|
-
onEvent({ type: "error", message: "Gearbox docs aren't bundled with this install
|
|
148043
|
+
onEvent({ type: "error", message: "Gearbox docs aren't bundled with this install · can't answer from them." });
|
|
147879
148044
|
return { messages, usage: { inputTokens: 0, outputTokens: 0 } };
|
|
147880
148045
|
}
|
|
147881
148046
|
const choice3 = new RoutingSelector().select({ prompt, kind: "search" });
|
|
147882
148047
|
if (choice3.backend?.kind === "cli") {
|
|
147883
|
-
onEvent({ type: "error", message: "/ask needs an API-key account
|
|
148048
|
+
onEvent({ type: "error", message: "/ask needs an API-key account · it can't run on a subscription. Add one with /account add <key>." });
|
|
147884
148049
|
return { messages, usage: { inputTokens: 0, outputTokens: 0 } };
|
|
147885
148050
|
}
|
|
147886
148051
|
routedRef.current = { model: choice3.model, reason: choice3.reason };
|
|
@@ -147981,7 +148146,7 @@ ${map4}
|
|
|
147981
148146
|
if (_effortRaw === null && effortRef.current !== "medium") {
|
|
147982
148147
|
const supported = effortLevels(choice3.model);
|
|
147983
148148
|
const { level: nearest } = clampEffort(effortRef.current, supported);
|
|
147984
|
-
const hint = supported.length ? `
|
|
148149
|
+
const hint = supported.length ? ` · try /effort ${nearest}` : "";
|
|
147985
148150
|
throw new Error(`effort "${effortRef.current}" is not supported by ${choice3.model.label} (supports: ${supported.join(", ") || "none"}${hint})`);
|
|
147986
148151
|
}
|
|
147987
148152
|
const r2 = await runTask({ model: choice3.model, messages: ctx, onEvent, signal, plan, system, creds, effort: _effortRaw ?? undefined, deferTerminal: true });
|
|
@@ -148042,9 +148207,9 @@ ${map4}
|
|
|
148042
148207
|
return `compacted ${res.summarizedTurns} earlier turn${res.summarizedTurns > 1 ? "s" : ""} · ~${savedStr} tokens freed`;
|
|
148043
148208
|
}, []);
|
|
148044
148209
|
const MODE_NOTE = {
|
|
148045
|
-
normal: "normal mode
|
|
148046
|
-
"auto-accept": "auto-accept edits
|
|
148047
|
-
plan: "plan mode
|
|
148210
|
+
normal: "normal mode · I'll ask before writes, edits, and shell",
|
|
148211
|
+
"auto-accept": "auto-accept edits · file writes/edits apply without asking (shell still gated)",
|
|
148212
|
+
plan: "plan mode · read-only; I'll propose a plan before changing anything"
|
|
148048
148213
|
};
|
|
148049
148214
|
const setModeTo = (next) => {
|
|
148050
148215
|
modeRef.current = next;
|
|
@@ -148076,8 +148241,8 @@ ${map4}
|
|
|
148076
148241
|
effortRef.current = level;
|
|
148077
148242
|
setEffortState(level);
|
|
148078
148243
|
if (!allowed.length)
|
|
148079
|
-
return `
|
|
148080
|
-
return `
|
|
148244
|
+
return ` · effort reset to ${level} (no reasoning support)`;
|
|
148245
|
+
return ` · effort clamped: ${prev} → ${level} (${prev} not supported)`;
|
|
148081
148246
|
};
|
|
148082
148247
|
const setEffort = (raw) => {
|
|
148083
148248
|
const target = effortTarget();
|
|
@@ -148092,7 +148257,7 @@ ${map4}
|
|
|
148092
148257
|
}
|
|
148093
148258
|
effortRef.current = level;
|
|
148094
148259
|
setEffortState(level);
|
|
148095
|
-
notice(`effort: ${level}
|
|
148260
|
+
notice(`effort: ${level} · ${target.label}`);
|
|
148096
148261
|
};
|
|
148097
148262
|
const runInteractive = (cmd, cmdArgs, env3) => {
|
|
148098
148263
|
try {
|
|
@@ -148103,7 +148268,7 @@ ${map4}
|
|
|
148103
148268
|
process.stdout.write("\x1B[?1049l");
|
|
148104
148269
|
process.stdout.write("\x1B[?2004l\x1B[?25h");
|
|
148105
148270
|
process.stdout.write(`
|
|
148106
|
-
→ running \`${cmd} ${cmdArgs.join(" ")}\`
|
|
148271
|
+
→ running \`${cmd} ${cmdArgs.join(" ")}\` · follow the prompts…
|
|
148107
148272
|
|
|
148108
148273
|
`);
|
|
148109
148274
|
const r2 = nodeSpawnSync2(cmd, cmdArgs, { stdio: ["inherit", "inherit", "inherit"], ...env3 ? { env: env3 } : {} });
|
|
@@ -148406,7 +148571,7 @@ ${fetched.join(`
|
|
|
148406
148571
|
const changed = uniq2([...changedFiles]);
|
|
148407
148572
|
const doneChecks = uniq2(checks4);
|
|
148408
148573
|
const failed = uniq2(failures).slice(0, 4);
|
|
148409
|
-
const next = failed.length ?
|
|
148574
|
+
const next = failed.length ? nextStepFor(failed, changed) : changed.length && !doneChecks.length ? "run tests" : changed.length ? "commit changes" : "/context";
|
|
148410
148575
|
if (changed.length || doneChecks.length || failed.length) {
|
|
148411
148576
|
push({ kind: "summary", id: idRef.current++, changed, checks: doneChecks, failures: failed, next });
|
|
148412
148577
|
}
|
|
@@ -148526,7 +148691,7 @@ ${fetched.join(`
|
|
|
148526
148691
|
return;
|
|
148527
148692
|
}
|
|
148528
148693
|
if (a && a.exec !== "cli") {
|
|
148529
|
-
notice(`${accountName(a)} is an API-key account
|
|
148694
|
+
notice(`${accountName(a)} is an API-key account · nothing to re-login. Use /account ${accountSlug(a)} to switch to it, or /account add ${a.provider} <key> to replace the key.`);
|
|
148530
148695
|
return;
|
|
148531
148696
|
}
|
|
148532
148697
|
signInCli(arg2);
|
|
@@ -148560,13 +148725,13 @@ ${fetched.join(`
|
|
|
148560
148725
|
}
|
|
148561
148726
|
const rows2 = sessions.slice(0, 10).map((s2, i2) => ` ${i2 + 1}. ${new Date(s2.updatedAt).toLocaleString()} · ${s2.title || "(untitled)"} (${s2.items.length} msgs)`).join(`
|
|
148562
148727
|
`);
|
|
148563
|
-
notice(`resume a session
|
|
148728
|
+
notice(`resume a session · /resume <n>:
|
|
148564
148729
|
` + rows2);
|
|
148565
148730
|
return;
|
|
148566
148731
|
}
|
|
148567
148732
|
const pick3 = (resumeListRef.current.length ? resumeListRef.current : sessions)[parseInt(arg, 10) - 1];
|
|
148568
148733
|
if (!pick3) {
|
|
148569
|
-
notice(`no session ${arg}
|
|
148734
|
+
notice(`no session ${arg} · /resume to list`);
|
|
148570
148735
|
return;
|
|
148571
148736
|
}
|
|
148572
148737
|
loadInto(pick3);
|
|
@@ -148590,7 +148755,7 @@ ${fetched.join(`
|
|
|
148590
148755
|
setEffort(arg);
|
|
148591
148756
|
} else {
|
|
148592
148757
|
const target = effortTarget();
|
|
148593
|
-
notice(target?.efforts.length ? `effort: ${effortRef.current}
|
|
148758
|
+
notice(target?.efforts.length ? `effort: ${effortRef.current} · ${target.label} supports ${target.efforts.join(", ")}` : "the active model does not expose reasoning efforts");
|
|
148594
148759
|
}
|
|
148595
148760
|
return;
|
|
148596
148761
|
}
|
|
@@ -148627,7 +148792,7 @@ ${fetched.join(`
|
|
|
148627
148792
|
const on = vimRef.current === "off";
|
|
148628
148793
|
setVim(on ? "insert" : "off");
|
|
148629
148794
|
updatePrefs({ vim: on });
|
|
148630
|
-
notice(on ? "vim mode on
|
|
148795
|
+
notice(on ? "vim mode on · esc for normal, i to insert" : "vim mode off");
|
|
148631
148796
|
return;
|
|
148632
148797
|
}
|
|
148633
148798
|
case "config": {
|
|
@@ -148646,10 +148811,10 @@ ${fetched.join(`
|
|
|
148646
148811
|
if (key === "vim") {
|
|
148647
148812
|
setVim(on ? "insert" : "off");
|
|
148648
148813
|
updatePrefs({ vim: on });
|
|
148649
|
-
notice(on ? "vim mode on
|
|
148814
|
+
notice(on ? "vim mode on · esc for normal, i to insert" : "vim mode off");
|
|
148650
148815
|
} else if (key === "inline") {
|
|
148651
148816
|
updatePrefs({ fullscreen: !on });
|
|
148652
|
-
notice(`inline mode ${on ? "on" : "off"}
|
|
148817
|
+
notice(`inline mode ${on ? "on" : "off"} · restart gearbox to apply`);
|
|
148653
148818
|
} else if (key === "notify") {
|
|
148654
148819
|
notifyRef.current = on;
|
|
148655
148820
|
updatePrefs({ notify: on });
|
|
@@ -148664,7 +148829,7 @@ ${fetched.join(`
|
|
|
148664
148829
|
const next = !isYolo();
|
|
148665
148830
|
setYolo(next);
|
|
148666
148831
|
setYoloState(next);
|
|
148667
|
-
notice(next ? "yolo mode ON
|
|
148832
|
+
notice(next ? "yolo mode ON · all file writes and shell commands run without asking" : "yolo mode off · back to asking before writes/edits/shell");
|
|
148668
148833
|
return;
|
|
148669
148834
|
}
|
|
148670
148835
|
case "ghost": {
|
|
@@ -148673,7 +148838,7 @@ ${fetched.join(`
|
|
|
148673
148838
|
if (arg) {
|
|
148674
148839
|
const found = SKINS.find((s2) => s2 === arg.toLowerCase());
|
|
148675
148840
|
if (!found) {
|
|
148676
|
-
notice(`unknown mood: ${arg}
|
|
148841
|
+
notice(`unknown mood: ${arg} · try ${SKINS.join(", ")}`);
|
|
148677
148842
|
return;
|
|
148678
148843
|
}
|
|
148679
148844
|
next = found;
|
|
@@ -148717,7 +148882,7 @@ ${fetched.join(`
|
|
|
148717
148882
|
if (!arg || arg.toLowerCase() === "all") {
|
|
148718
148883
|
const routing2 = selectorRef.current instanceof RoutingSelector;
|
|
148719
148884
|
const activeSub = activeCliRef.current;
|
|
148720
|
-
const mode3 = activeSub ? `now: ${activeSub.binary} subscription${activeCliModelRef.current ? ` · ${cliModelLabel(activeCliModelRef.current)}` : ""}
|
|
148885
|
+
const mode3 = activeSub ? `now: ${activeSub.binary} subscription${activeCliModelRef.current ? ` · ${cliModelLabel(activeCliModelRef.current)}` : ""} · /account off for API routing` : routing2 ? "now: routing on · Gearbox picks per task" : `now: pinned to ${currentId ?? "one model"} · /model auto to route`;
|
|
148721
148886
|
const list2 = activeSub ? formatCliModelList(activeSub.binary, activeCliModelRef.current ?? null) : formatModelList(currentId, arg.toLowerCase() === "all");
|
|
148722
148887
|
notice(list2 + `
|
|
148723
148888
|
|
|
@@ -148727,7 +148892,7 @@ ${fetched.join(`
|
|
|
148727
148892
|
if (arg.toLowerCase() === "auto" || arg.toLowerCase() === "route") {
|
|
148728
148893
|
if (activeCliRef.current) {
|
|
148729
148894
|
setActiveCliModelId(undefined);
|
|
148730
|
-
notice(`subscription model cleared
|
|
148895
|
+
notice(`subscription model cleared · ${activeCliRef.current.binary} will use its default. /account off for API routing`);
|
|
148731
148896
|
return;
|
|
148732
148897
|
}
|
|
148733
148898
|
const left = leaveSubscription();
|
|
@@ -148735,7 +148900,7 @@ ${fetched.join(`
|
|
|
148735
148900
|
setLastPick(null);
|
|
148736
148901
|
routedRef.current = null;
|
|
148737
148902
|
updatePrefs({ pinnedModel: undefined });
|
|
148738
|
-
notice("routing on
|
|
148903
|
+
notice("routing on · Gearbox now picks the model per task (the cheapest that can do the job)" + left);
|
|
148739
148904
|
return;
|
|
148740
148905
|
}
|
|
148741
148906
|
{
|
|
@@ -148752,7 +148917,7 @@ ${fetched.join(`
|
|
|
148752
148917
|
updatePrefs({ pinnedModel: r3.modelId });
|
|
148753
148918
|
const newSpec2 = findModel(r3.modelId);
|
|
148754
148919
|
const effortSuffix2 = applyEffortClamp(newSpec2 ? effortLevels(newSpec2) : []);
|
|
148755
|
-
notice(`${r3.message}
|
|
148920
|
+
notice(`${r3.message} · pinned (left subscription).${left}${effortSuffix2}`);
|
|
148756
148921
|
const kind = classify(lastPromptRef.current ?? "").replace("code", "code");
|
|
148757
148922
|
push({ kind: "preference", id: idRef.current++, text: `Remember ${r3.modelId} for ${kind} tasks?`, acceptCommand: `/prefer ${kind} ${r3.modelId}` });
|
|
148758
148923
|
return;
|
|
@@ -148769,7 +148934,7 @@ ${fetched.join(`
|
|
|
148769
148934
|
updatePrefs({ pinnedModel: r3.modelId });
|
|
148770
148935
|
const newSpec2 = findModel(r3.modelId);
|
|
148771
148936
|
const effortSuffix2 = applyEffortClamp(newSpec2 ? effortLevels(newSpec2) : []);
|
|
148772
|
-
notice(`${r3.message}
|
|
148937
|
+
notice(`${r3.message} · pinned (left subscription).${left}${effortSuffix2}`);
|
|
148773
148938
|
const kind = classify(lastPromptRef.current ?? "").replace("code", "code");
|
|
148774
148939
|
push({ kind: "preference", id: idRef.current++, text: `Remember ${r3.modelId} for ${kind} tasks?`, acceptCommand: `/prefer ${kind} ${r3.modelId}` });
|
|
148775
148940
|
return;
|
|
@@ -148780,7 +148945,7 @@ ${fetched.join(`
|
|
|
148780
148945
|
setActiveCliModelId(cr.modelId);
|
|
148781
148946
|
const newCliModel = cliModelChoices(cli.binary).find((m2) => m2.id === cr.modelId);
|
|
148782
148947
|
const effortSuffix = applyEffortClamp(newCliModel?.efforts ?? []);
|
|
148783
|
-
notice(`subscription model → ${cr.label}
|
|
148948
|
+
notice(`subscription model → ${cr.label} · using ${cli.binary}; tools and permissions still owned by the subscription${effortSuffix}`);
|
|
148784
148949
|
return;
|
|
148785
148950
|
}
|
|
148786
148951
|
const r2 = resolveModelSwitch(arg);
|
|
@@ -148792,11 +148957,20 @@ ${fetched.join(`
|
|
|
148792
148957
|
updatePrefs({ pinnedModel: r2.modelId });
|
|
148793
148958
|
const newSpec = findModel(r2.modelId);
|
|
148794
148959
|
const effortSuffix = applyEffortClamp(newSpec ? effortLevels(newSpec) : []);
|
|
148795
|
-
notice(`${r2.message}
|
|
148960
|
+
notice(`${r2.message} · pinned (persists across sessions). /model auto to route per task again.${left}${effortSuffix}`);
|
|
148796
148961
|
const kind = classify(lastPromptRef.current ?? "").replace("code", "code");
|
|
148797
148962
|
push({ kind: "preference", id: idRef.current++, text: `Remember ${r2.modelId} for ${kind} tasks?`, acceptCommand: `/prefer ${kind} ${r2.modelId}` });
|
|
148798
148963
|
} else {
|
|
148799
|
-
|
|
148964
|
+
const wanted = modelRegistry().find((m2) => [m2.id, m2.label].some((s2) => s2.toLowerCase() === arg.toLowerCase() || s2.toLowerCase().includes(arg.toLowerCase())));
|
|
148965
|
+
const fam = wanted && /claude|anthropic/i.test(`${wanted.provider} ${wanted.id}`) ? "claude-cli" : wanted && /openai|gpt|^o\d/i.test(`${wanted.provider} ${wanted.id}`) ? "codex-cli" : null;
|
|
148966
|
+
const sub = fam ? listAccounts().find((a) => a.provider === fam && a.enabled) : null;
|
|
148967
|
+
if (sub && wanted) {
|
|
148968
|
+
notice(`${r2.message}
|
|
148969
|
+
|
|
148970
|
+
you have a ${accountName(sub)} subscription · use it with /account ${accountSlug(sub)}, or add a key: /account add ${wanted.provider} <key>`);
|
|
148971
|
+
} else {
|
|
148972
|
+
notice(r2.message);
|
|
148973
|
+
}
|
|
148800
148974
|
}
|
|
148801
148975
|
}
|
|
148802
148976
|
return;
|
|
@@ -148826,7 +149000,7 @@ ${fetched.join(`
|
|
|
148826
149000
|
const keys2 = Object.keys(b);
|
|
148827
149001
|
notice(keys2.length ? `budgets (estimates remaining = budget − tracked spend):
|
|
148828
149002
|
` + keys2.map((k) => ` ${k}: $${b[k].amountUSD} ${b[k].period}`).join(`
|
|
148829
|
-
`) : "no budgets set. /budget <provider|account> <amount> [monthly|total]
|
|
149003
|
+
`) : "no budgets set. /budget <provider|account> <amount> [monthly|total] · lets routing estimate remaining credit for providers that don't expose a balance");
|
|
148830
149004
|
return;
|
|
148831
149005
|
}
|
|
148832
149006
|
const [target, amountRaw, periodRaw] = parts;
|
|
@@ -148853,7 +149027,7 @@ ${fetched.join(`
|
|
|
148853
149027
|
}
|
|
148854
149028
|
const facts = loadFacts().trim();
|
|
148855
149029
|
const it = { kind: "notice", id: idRef.current++, text: facts ? `remembered facts:
|
|
148856
|
-
` + facts : "no remembered facts yet
|
|
149030
|
+
` + facts : "no remembered facts yet · add one with #<note> or /memory <note>" };
|
|
148857
149031
|
if (openInfoPanel("memory", it))
|
|
148858
149032
|
return;
|
|
148859
149033
|
echo(text2);
|
|
@@ -148870,7 +149044,7 @@ ${fetched.join(`
|
|
|
148870
149044
|
})();
|
|
148871
149045
|
if (!m2) {
|
|
148872
149046
|
echo(text2);
|
|
148873
|
-
notice(`no model available
|
|
149047
|
+
notice(`no model available · add a provider first
|
|
148874
149048
|
|
|
148875
149049
|
` + onboardingSummary(onboardingState));
|
|
148876
149050
|
return;
|
|
@@ -148887,7 +149061,7 @@ ${fetched.join(`
|
|
|
148887
149061
|
echo(text2);
|
|
148888
149062
|
const sel = selectorRef.current;
|
|
148889
149063
|
if (!sel.explain) {
|
|
148890
|
-
notice("routing is off
|
|
149064
|
+
notice("routing is off · a model or subscription is pinned. Use /model auto to route per task, then /why.");
|
|
148891
149065
|
return;
|
|
148892
149066
|
}
|
|
148893
149067
|
try {
|
|
@@ -149011,7 +149185,7 @@ Example: /mcp add github npx -y @modelcontextprotocol/server-github`);
|
|
|
149011
149185
|
const withHealth = listAccounts();
|
|
149012
149186
|
pushAccounts(buildAccountView(withHealth, activeCliRef.current?.id ?? null, importableEnvCreds(), statuses));
|
|
149013
149187
|
} catch (e2) {
|
|
149014
|
-
notice(`couldn't check subscription accounts
|
|
149188
|
+
notice(`couldn't check subscription accounts · ${e2?.message ?? String(e2)}`);
|
|
149015
149189
|
pushAccounts(buildAccountView(listAccounts(), activeCliRef.current?.id ?? null, importableEnvCreds(), accountStatusCacheRef.current));
|
|
149016
149190
|
}
|
|
149017
149191
|
})();
|
|
@@ -149065,7 +149239,7 @@ Example: /mcp add github npx -y @modelcontextprotocol/server-github`);
|
|
|
149065
149239
|
cliSessionRef.current = undefined;
|
|
149066
149240
|
setActiveCli(null);
|
|
149067
149241
|
updatePrefs({ activeAccount: null });
|
|
149068
|
-
notice("left the subscription
|
|
149242
|
+
notice("left the subscription · back to your API keys");
|
|
149069
149243
|
return;
|
|
149070
149244
|
}
|
|
149071
149245
|
if (subL === "login") {
|
|
@@ -149128,13 +149302,13 @@ Example: /mcp add github npx -y @modelcontextprotocol/server-github`);
|
|
|
149128
149302
|
notice(res.message);
|
|
149129
149303
|
return;
|
|
149130
149304
|
}
|
|
149131
|
-
notice(`${res.message}
|
|
149305
|
+
notice(`${res.message} · testing…`);
|
|
149132
149306
|
const t2 = await testAccount(res.account);
|
|
149133
149307
|
notice(t2.ok ? `✓ added · ${t2.message}` : `added, but the key test failed: ${t2.message}`);
|
|
149134
149308
|
const d = await discoverModels(res.account);
|
|
149135
149309
|
if (d.models.length) {
|
|
149136
149310
|
putAccount({ ...res.account, models: d.models });
|
|
149137
|
-
notice(`found ${d.models.length} model${d.models.length === 1 ? "" : "s"} on this account
|
|
149311
|
+
notice(`found ${d.models.length} model${d.models.length === 1 ? "" : "s"} on this account · /model to pick one`);
|
|
149138
149312
|
} else if (d.note) {
|
|
149139
149313
|
notice(d.note);
|
|
149140
149314
|
}
|
|
@@ -149166,7 +149340,7 @@ Example: /mcp add github npx -y @modelcontextprotocol/server-github`);
|
|
|
149166
149340
|
const keys2 = importableEnvCreds();
|
|
149167
149341
|
const cloud = importableCloudCreds();
|
|
149168
149342
|
if (!keys2.length && !cloud.length) {
|
|
149169
|
-
notice("nothing to import
|
|
149343
|
+
notice("nothing to import · no new provider keys or cloud creds found");
|
|
149170
149344
|
return;
|
|
149171
149345
|
}
|
|
149172
149346
|
for (const c of keys2)
|
|
@@ -149181,7 +149355,7 @@ Example: /mcp add github npx -y @modelcontextprotocol/server-github`);
|
|
|
149181
149355
|
(async () => {
|
|
149182
149356
|
const targets = listAccounts().filter((a) => a.enabled && a.exec !== "cli");
|
|
149183
149357
|
if (!targets.length) {
|
|
149184
|
-
notice("no API/cloud accounts to refresh
|
|
149358
|
+
notice("no API/cloud accounts to refresh · /account add to add one");
|
|
149185
149359
|
return;
|
|
149186
149360
|
}
|
|
149187
149361
|
notice(`refreshing models for ${targets.length} account${targets.length === 1 ? "" : "s"}…`);
|
|
@@ -149209,6 +149383,12 @@ Example: /mcp add github npx -y @modelcontextprotocol/server-github`);
|
|
|
149209
149383
|
}
|
|
149210
149384
|
case "cost":
|
|
149211
149385
|
case "usage": {
|
|
149386
|
+
if (fullscreen) {
|
|
149387
|
+
const on = !statusPinned;
|
|
149388
|
+
setStatusPinned(on);
|
|
149389
|
+
notice(on ? "usage pinned above the composer — /cost to hide" : "usage hidden");
|
|
149390
|
+
return;
|
|
149391
|
+
}
|
|
149212
149392
|
const accounts = listAccounts();
|
|
149213
149393
|
const resolve13 = (id) => {
|
|
149214
149394
|
const a = getAccount(id);
|
|
@@ -149250,7 +149430,7 @@ Example: /mcp add github npx -y @modelcontextprotocol/server-github`);
|
|
|
149250
149430
|
case "compact": {
|
|
149251
149431
|
echo(text2);
|
|
149252
149432
|
if (busyRef.current) {
|
|
149253
|
-
notice("busy
|
|
149433
|
+
notice("busy · try /compact once the current turn finishes");
|
|
149254
149434
|
return;
|
|
149255
149435
|
}
|
|
149256
149436
|
setBusy(true);
|
|
@@ -149274,7 +149454,7 @@ Example: /mcp add github npx -y @modelcontextprotocol/server-github`);
|
|
|
149274
149454
|
case "init":
|
|
149275
149455
|
if (busyRef.current) {
|
|
149276
149456
|
echo(text2);
|
|
149277
|
-
notice("busy
|
|
149457
|
+
notice("busy · try /init again once the current turn finishes");
|
|
149278
149458
|
return;
|
|
149279
149459
|
}
|
|
149280
149460
|
echo(text2);
|
|
@@ -149306,7 +149486,7 @@ Example: /mcp add github npx -y @modelcontextprotocol/server-github`);
|
|
|
149306
149486
|
default: {
|
|
149307
149487
|
echo(text2);
|
|
149308
149488
|
const near = matchCommands(`/${name31}`).filter((c) => c.name !== `/${name31}`)[0];
|
|
149309
|
-
notice(near ? `no /${name31} command
|
|
149489
|
+
notice(near ? `no /${name31} command · did you mean ${near.name}? (/help for all)` : `no /${name31} command · type /help to see what's available`);
|
|
149310
149490
|
return;
|
|
149311
149491
|
}
|
|
149312
149492
|
}
|
|
@@ -149335,7 +149515,7 @@ Example: /mcp add github npx -y @modelcontextprotocol/server-github`);
|
|
|
149335
149515
|
const cmd = text2.slice(1).trim();
|
|
149336
149516
|
echo(text2);
|
|
149337
149517
|
if (!cmd) {
|
|
149338
|
-
notice("run a shell command with !<command>
|
|
149518
|
+
notice("run a shell command with !<command> · e.g. !git status");
|
|
149339
149519
|
return;
|
|
149340
149520
|
}
|
|
149341
149521
|
const id = idRef.current++;
|
|
@@ -149378,7 +149558,7 @@ Example: /mcp add github npx -y @modelcontextprotocol/server-github`);
|
|
|
149378
149558
|
if (busyRef.current) {
|
|
149379
149559
|
queueRef.current.push(text2);
|
|
149380
149560
|
setQueued([...queueRef.current]);
|
|
149381
|
-
notice(`queued (${queueRef.current.length})
|
|
149561
|
+
notice(`queued (${queueRef.current.length}) · sends when the current turn finishes`);
|
|
149382
149562
|
return;
|
|
149383
149563
|
}
|
|
149384
149564
|
if (looksLikeGearboxQuestion(text2)) {
|
|
@@ -149420,7 +149600,7 @@ Example: /mcp add github npx -y @modelcontextprotocol/server-github`);
|
|
|
149420
149600
|
msgRef.current = ms.slice(0, mi);
|
|
149421
149601
|
curAsstRef.current = null;
|
|
149422
149602
|
setEdit({ value: userText, cursor: userText.length });
|
|
149423
|
-
notice("rewound the last turn
|
|
149603
|
+
notice("rewound the last turn · edit and resend");
|
|
149424
149604
|
};
|
|
149425
149605
|
use_input_default((input, key) => {
|
|
149426
149606
|
if (/\[<\d+;\d+;\d+[Mm]/.test(input))
|
|
@@ -149791,6 +149971,11 @@ Example: /mcp add github npx -y @modelcontextprotocol/server-github`);
|
|
|
149791
149971
|
footer += 1;
|
|
149792
149972
|
if (quickPicker && quickRows.length)
|
|
149793
149973
|
footer += quickPickerLimit + 2;
|
|
149974
|
+
const stripView = statusPinned ? currentUsageView() : null;
|
|
149975
|
+
const stripSub = stripView ? stripView.subscriptions.find((s2) => s2.name === activeCli?.label) ?? stripView.subscriptions[0] ?? null : null;
|
|
149976
|
+
const stripApi = stripView ? stripView.apiKeys[0] ?? null : null;
|
|
149977
|
+
if (statusPinned)
|
|
149978
|
+
footer += 2 + (ctxPct != null ? 1 : 0) + (stripSub ? Math.max(1, stripSub.limits?.length ?? 1) : 0) + (stripApi?.spend ? 1 : 0) + 1;
|
|
149794
149979
|
const HEADER = 3;
|
|
149795
149980
|
const transcriptHeight = Math.max(1, rows - HEADER - footer);
|
|
149796
149981
|
const maxScroll = Math.max(0, lines.length - transcriptHeight);
|
|
@@ -149821,87 +150006,87 @@ Example: /mcp add github npx -y @modelcontextprotocol/server-github`);
|
|
|
149821
150006
|
if (atBottomRef.current)
|
|
149822
150007
|
setScrollTop(maxScroll);
|
|
149823
150008
|
}, [lines.length, maxScroll]);
|
|
149824
|
-
const hero = /* @__PURE__ */
|
|
150009
|
+
const hero = /* @__PURE__ */ jsx_dev_runtime14.jsxDEV(Box_default, {
|
|
149825
150010
|
flexDirection: "column",
|
|
149826
150011
|
alignItems: "center",
|
|
149827
|
-
children: setupRequired ? /* @__PURE__ */
|
|
150012
|
+
children: setupRequired ? /* @__PURE__ */ jsx_dev_runtime14.jsxDEV(SetupSplash, {
|
|
149828
150013
|
state: onboardingState,
|
|
149829
150014
|
width,
|
|
149830
150015
|
skin: ghostSkin,
|
|
149831
150016
|
splashSize
|
|
149832
|
-
}, undefined, false, undefined, this) : /* @__PURE__ */
|
|
150017
|
+
}, undefined, false, undefined, this) : /* @__PURE__ */ jsx_dev_runtime14.jsxDEV(jsx_dev_runtime14.Fragment, {
|
|
149833
150018
|
children: [
|
|
149834
|
-
/* @__PURE__ */
|
|
150019
|
+
/* @__PURE__ */ jsx_dev_runtime14.jsxDEV(MascotSplash, {
|
|
149835
150020
|
skin: ghostSkin,
|
|
149836
150021
|
size: splashSize
|
|
149837
150022
|
}, undefined, false, undefined, this),
|
|
149838
|
-
/* @__PURE__ */
|
|
150023
|
+
/* @__PURE__ */ jsx_dev_runtime14.jsxDEV(Box_default, {
|
|
149839
150024
|
marginTop: 1,
|
|
149840
150025
|
children: [
|
|
149841
|
-
/* @__PURE__ */
|
|
150026
|
+
/* @__PURE__ */ jsx_dev_runtime14.jsxDEV(Text, {
|
|
149842
150027
|
color: color.dim,
|
|
149843
150028
|
children: "talk or type "
|
|
149844
150029
|
}, undefined, false, undefined, this),
|
|
149845
|
-
/* @__PURE__ */
|
|
150030
|
+
/* @__PURE__ */ jsx_dev_runtime14.jsxDEV(Text, {
|
|
149846
150031
|
color: color.faint,
|
|
149847
150032
|
children: [
|
|
149848
150033
|
glyph.bullet,
|
|
149849
150034
|
" "
|
|
149850
150035
|
]
|
|
149851
150036
|
}, undefined, true, undefined, this),
|
|
149852
|
-
/* @__PURE__ */
|
|
150037
|
+
/* @__PURE__ */ jsx_dev_runtime14.jsxDEV(Text, {
|
|
149853
150038
|
color: color.accentDim,
|
|
149854
150039
|
children: "/"
|
|
149855
150040
|
}, undefined, false, undefined, this),
|
|
149856
|
-
/* @__PURE__ */
|
|
150041
|
+
/* @__PURE__ */ jsx_dev_runtime14.jsxDEV(Text, {
|
|
149857
150042
|
color: color.dim,
|
|
149858
150043
|
children: "commands "
|
|
149859
150044
|
}, undefined, false, undefined, this),
|
|
149860
|
-
/* @__PURE__ */
|
|
150045
|
+
/* @__PURE__ */ jsx_dev_runtime14.jsxDEV(Text, {
|
|
149861
150046
|
color: color.accentDim,
|
|
149862
150047
|
children: "@"
|
|
149863
150048
|
}, undefined, false, undefined, this),
|
|
149864
|
-
/* @__PURE__ */
|
|
150049
|
+
/* @__PURE__ */ jsx_dev_runtime14.jsxDEV(Text, {
|
|
149865
150050
|
color: color.dim,
|
|
149866
150051
|
children: "files "
|
|
149867
150052
|
}, undefined, false, undefined, this),
|
|
149868
|
-
/* @__PURE__ */
|
|
150053
|
+
/* @__PURE__ */ jsx_dev_runtime14.jsxDEV(Text, {
|
|
149869
150054
|
color: color.accentDim,
|
|
149870
150055
|
children: "!"
|
|
149871
150056
|
}, undefined, false, undefined, this),
|
|
149872
|
-
/* @__PURE__ */
|
|
150057
|
+
/* @__PURE__ */ jsx_dev_runtime14.jsxDEV(Text, {
|
|
149873
150058
|
color: color.dim,
|
|
149874
150059
|
children: "shell"
|
|
149875
150060
|
}, undefined, false, undefined, this)
|
|
149876
150061
|
]
|
|
149877
150062
|
}, undefined, true, undefined, this),
|
|
149878
|
-
firstRunRef.current ? /* @__PURE__ */
|
|
150063
|
+
firstRunRef.current ? /* @__PURE__ */ jsx_dev_runtime14.jsxDEV(Box_default, {
|
|
149879
150064
|
marginTop: 1,
|
|
149880
150065
|
flexDirection: "column",
|
|
149881
150066
|
alignItems: "center",
|
|
149882
150067
|
children: [
|
|
149883
|
-
/* @__PURE__ */
|
|
150068
|
+
/* @__PURE__ */ jsx_dev_runtime14.jsxDEV(Text, {
|
|
149884
150069
|
color: color.faint,
|
|
149885
150070
|
children: [
|
|
149886
150071
|
"new here? press ",
|
|
149887
|
-
/* @__PURE__ */
|
|
150072
|
+
/* @__PURE__ */ jsx_dev_runtime14.jsxDEV(Text, {
|
|
149888
150073
|
color: color.accent,
|
|
149889
150074
|
children: "?"
|
|
149890
150075
|
}, undefined, false, undefined, this),
|
|
149891
150076
|
" for shortcuts · ",
|
|
149892
|
-
/* @__PURE__ */
|
|
150077
|
+
/* @__PURE__ */ jsx_dev_runtime14.jsxDEV(Text, {
|
|
149893
150078
|
color: color.accent,
|
|
149894
150079
|
children: "shift+tab"
|
|
149895
150080
|
}, undefined, false, undefined, this),
|
|
149896
150081
|
" cycles modes · ",
|
|
149897
|
-
/* @__PURE__ */
|
|
150082
|
+
/* @__PURE__ */ jsx_dev_runtime14.jsxDEV(Text, {
|
|
149898
150083
|
color: color.accent,
|
|
149899
150084
|
children: "⌃Y"
|
|
149900
150085
|
}, undefined, false, undefined, this),
|
|
149901
150086
|
" copies the last reply"
|
|
149902
150087
|
]
|
|
149903
150088
|
}, undefined, true, undefined, this),
|
|
149904
|
-
/* @__PURE__ */
|
|
150089
|
+
/* @__PURE__ */ jsx_dev_runtime14.jsxDEV(Text, {
|
|
149905
150090
|
color: color.faint,
|
|
149906
150091
|
children: "/config inline on for terminal scrollback · /keys for shortcuts"
|
|
149907
150092
|
}, undefined, false, undefined, this)
|
|
@@ -149910,17 +150095,17 @@ Example: /mcp add github npx -y @modelcontextprotocol/server-github`);
|
|
|
149910
150095
|
]
|
|
149911
150096
|
}, undefined, true, undefined, this)
|
|
149912
150097
|
}, undefined, false, undefined, this);
|
|
149913
|
-
const paletteJsx = pickerRows.length || cmdMatches.length || fileMatches.length ? /* @__PURE__ */
|
|
150098
|
+
const paletteJsx = pickerRows.length || cmdMatches.length || fileMatches.length ? /* @__PURE__ */ jsx_dev_runtime14.jsxDEV(Box_default, {
|
|
149914
150099
|
flexDirection: "column",
|
|
149915
150100
|
children: [
|
|
149916
|
-
/* @__PURE__ */
|
|
150101
|
+
/* @__PURE__ */ jsx_dev_runtime14.jsxDEV(CommandPalette, {
|
|
149917
150102
|
draft: edit2.value,
|
|
149918
150103
|
selected: selectedPalette,
|
|
149919
150104
|
limit: 7,
|
|
149920
150105
|
rows: pickerRows,
|
|
149921
150106
|
width
|
|
149922
150107
|
}, undefined, false, undefined, this),
|
|
149923
|
-
/* @__PURE__ */
|
|
150108
|
+
/* @__PURE__ */ jsx_dev_runtime14.jsxDEV(FilePalette, {
|
|
149924
150109
|
matches: fileMatches,
|
|
149925
150110
|
selected: selectedPalette,
|
|
149926
150111
|
limit: 5,
|
|
@@ -149928,24 +150113,24 @@ Example: /mcp add github npx -y @modelcontextprotocol/server-github`);
|
|
|
149928
150113
|
}, undefined, false, undefined, this)
|
|
149929
150114
|
]
|
|
149930
150115
|
}, undefined, true, undefined, this) : null;
|
|
149931
|
-
const quickPickerJsx = quickPicker && quickRows.length ? /* @__PURE__ */
|
|
150116
|
+
const quickPickerJsx = quickPicker && quickRows.length ? /* @__PURE__ */ jsx_dev_runtime14.jsxDEV(Box_default, {
|
|
149932
150117
|
flexDirection: "column",
|
|
149933
150118
|
marginTop: 1,
|
|
149934
150119
|
children: [
|
|
149935
|
-
/* @__PURE__ */
|
|
150120
|
+
/* @__PURE__ */ jsx_dev_runtime14.jsxDEV(Box_default, {
|
|
149936
150121
|
paddingX: 1,
|
|
149937
150122
|
children: [
|
|
149938
|
-
/* @__PURE__ */
|
|
150123
|
+
/* @__PURE__ */ jsx_dev_runtime14.jsxDEV(Text, {
|
|
149939
150124
|
color: color.accent,
|
|
149940
150125
|
children: quickPicker === "model" ? "model" : "effort"
|
|
149941
150126
|
}, undefined, false, undefined, this),
|
|
149942
|
-
/* @__PURE__ */
|
|
150127
|
+
/* @__PURE__ */ jsx_dev_runtime14.jsxDEV(Text, {
|
|
149943
150128
|
color: color.faint,
|
|
149944
150129
|
children: " · ↑↓ select · ⏎ apply · esc close"
|
|
149945
150130
|
}, undefined, false, undefined, this)
|
|
149946
150131
|
]
|
|
149947
150132
|
}, undefined, true, undefined, this),
|
|
149948
|
-
/* @__PURE__ */
|
|
150133
|
+
/* @__PURE__ */ jsx_dev_runtime14.jsxDEV(CommandPalette, {
|
|
149949
150134
|
draft: "",
|
|
149950
150135
|
selected: Math.min(quickPickerIndex, quickRows.length - 1),
|
|
149951
150136
|
limit: quickPickerLimit,
|
|
@@ -149954,10 +150139,10 @@ Example: /mcp add github npx -y @modelcontextprotocol/server-github`);
|
|
|
149954
150139
|
}, undefined, false, undefined, this)
|
|
149955
150140
|
]
|
|
149956
150141
|
}, undefined, true, undefined, this) : null;
|
|
149957
|
-
const composerJsx = perm ? /* @__PURE__ */
|
|
150142
|
+
const composerJsx = perm ? /* @__PURE__ */ jsx_dev_runtime14.jsxDEV(PermissionPrompt, {
|
|
149958
150143
|
req: perm,
|
|
149959
150144
|
width
|
|
149960
|
-
}, undefined, false, undefined, this) : /* @__PURE__ */
|
|
150145
|
+
}, undefined, false, undefined, this) : /* @__PURE__ */ jsx_dev_runtime14.jsxDEV(Composer, {
|
|
149961
150146
|
value: edit2.value,
|
|
149962
150147
|
cursor: edit2.cursor,
|
|
149963
150148
|
selectionAnchor: edit2.selectionAnchor,
|
|
@@ -149967,9 +150152,9 @@ Example: /mcp add github npx -y @modelcontextprotocol/server-github`);
|
|
|
149967
150152
|
width,
|
|
149968
150153
|
vim
|
|
149969
150154
|
}, undefined, false, undefined, this);
|
|
149970
|
-
const footerJsx = /* @__PURE__ */
|
|
150155
|
+
const footerJsx = /* @__PURE__ */ jsx_dev_runtime14.jsxDEV(jsx_dev_runtime14.Fragment, {
|
|
149971
150156
|
children: [
|
|
149972
|
-
busy || linger ? /* @__PURE__ */
|
|
150157
|
+
busy || linger ? /* @__PURE__ */ jsx_dev_runtime14.jsxDEV(Working, {
|
|
149973
150158
|
state: mascotState,
|
|
149974
150159
|
skin: ghostSkin,
|
|
149975
150160
|
verb,
|
|
@@ -149984,15 +150169,15 @@ Example: /mcp add github npx -y @modelcontextprotocol/server-github`);
|
|
|
149984
150169
|
linger: linger && !busy,
|
|
149985
150170
|
width
|
|
149986
150171
|
}, undefined, false, undefined, this) : null,
|
|
149987
|
-
busy ? /* @__PURE__ */
|
|
150172
|
+
busy ? /* @__PURE__ */ jsx_dev_runtime14.jsxDEV(ActivityRail, {
|
|
149988
150173
|
items,
|
|
149989
150174
|
width
|
|
149990
150175
|
}, undefined, false, undefined, this) : null,
|
|
149991
|
-
queued.length ? /* @__PURE__ */
|
|
150176
|
+
queued.length ? /* @__PURE__ */ jsx_dev_runtime14.jsxDEV(Box_default, {
|
|
149992
150177
|
paddingX: 1,
|
|
149993
150178
|
marginTop: 1,
|
|
149994
150179
|
flexDirection: "column",
|
|
149995
|
-
children: queued.map((q, i2) => /* @__PURE__ */
|
|
150180
|
+
children: queued.map((q, i2) => /* @__PURE__ */ jsx_dev_runtime14.jsxDEV(Text, {
|
|
149996
150181
|
color: color.faint,
|
|
149997
150182
|
children: [
|
|
149998
150183
|
"↳ queued: ",
|
|
@@ -150000,11 +150185,11 @@ Example: /mcp add github npx -y @modelcontextprotocol/server-github`);
|
|
|
150000
150185
|
]
|
|
150001
150186
|
}, i2, true, undefined, this))
|
|
150002
150187
|
}, undefined, false, undefined, this) : null,
|
|
150003
|
-
mode2 !== "normal" ? /* @__PURE__ */
|
|
150188
|
+
mode2 !== "normal" ? /* @__PURE__ */ jsx_dev_runtime14.jsxDEV(Box_default, {
|
|
150004
150189
|
paddingX: 1,
|
|
150005
150190
|
marginTop: 1,
|
|
150006
150191
|
children: [
|
|
150007
|
-
/* @__PURE__ */
|
|
150192
|
+
/* @__PURE__ */ jsx_dev_runtime14.jsxDEV(Text, {
|
|
150008
150193
|
color: color.accent,
|
|
150009
150194
|
children: [
|
|
150010
150195
|
glyph.notice,
|
|
@@ -150012,7 +150197,7 @@ Example: /mcp add github npx -y @modelcontextprotocol/server-github`);
|
|
|
150012
150197
|
mode2 === "plan" ? "plan mode" : "auto-accept edits"
|
|
150013
150198
|
]
|
|
150014
150199
|
}, undefined, true, undefined, this),
|
|
150015
|
-
/* @__PURE__ */
|
|
150200
|
+
/* @__PURE__ */ jsx_dev_runtime14.jsxDEV(Text, {
|
|
150016
150201
|
color: color.faint,
|
|
150017
150202
|
children: [
|
|
150018
150203
|
" · ",
|
|
@@ -150022,14 +150207,14 @@ Example: /mcp add github npx -y @modelcontextprotocol/server-github`);
|
|
|
150022
150207
|
}, undefined, true, undefined, this)
|
|
150023
150208
|
]
|
|
150024
150209
|
}, undefined, true, undefined, this) : null,
|
|
150025
|
-
search ? /* @__PURE__ */
|
|
150210
|
+
search ? /* @__PURE__ */ jsx_dev_runtime14.jsxDEV(Box_default, {
|
|
150026
150211
|
paddingX: 1,
|
|
150027
150212
|
children: [
|
|
150028
|
-
/* @__PURE__ */
|
|
150213
|
+
/* @__PURE__ */ jsx_dev_runtime14.jsxDEV(Text, {
|
|
150029
150214
|
color: color.accent,
|
|
150030
150215
|
children: "(reverse-i-search)"
|
|
150031
150216
|
}, undefined, false, undefined, this),
|
|
150032
|
-
/* @__PURE__ */
|
|
150217
|
+
/* @__PURE__ */ jsx_dev_runtime14.jsxDEV(Text, {
|
|
150033
150218
|
color: color.text,
|
|
150034
150219
|
children: [
|
|
150035
150220
|
"`",
|
|
@@ -150037,15 +150222,15 @@ Example: /mcp add github npx -y @modelcontextprotocol/server-github`);
|
|
|
150037
150222
|
"`: "
|
|
150038
150223
|
]
|
|
150039
150224
|
}, undefined, true, undefined, this),
|
|
150040
|
-
/* @__PURE__ */
|
|
150225
|
+
/* @__PURE__ */ jsx_dev_runtime14.jsxDEV(Text, {
|
|
150041
150226
|
color: color.dim,
|
|
150042
150227
|
children: searchHistory(historyRef.current, search.q, search.idx) ?? (search.q ? "(no match)" : "")
|
|
150043
150228
|
}, undefined, false, undefined, this)
|
|
150044
150229
|
]
|
|
150045
150230
|
}, undefined, true, undefined, this) : null,
|
|
150046
|
-
copiedNotice ? /* @__PURE__ */
|
|
150231
|
+
copiedNotice ? /* @__PURE__ */ jsx_dev_runtime14.jsxDEV(Box_default, {
|
|
150047
150232
|
paddingX: 1,
|
|
150048
|
-
children: /* @__PURE__ */
|
|
150233
|
+
children: /* @__PURE__ */ jsx_dev_runtime14.jsxDEV(Text, {
|
|
150049
150234
|
color: color.ok,
|
|
150050
150235
|
children: [
|
|
150051
150236
|
glyph.notice,
|
|
@@ -150055,7 +150240,16 @@ Example: /mcp add github npx -y @modelcontextprotocol/server-github`);
|
|
|
150055
150240
|
}, undefined, true, undefined, this)
|
|
150056
150241
|
}, undefined, false, undefined, this) : null,
|
|
150057
150242
|
quickPickerJsx,
|
|
150058
|
-
/* @__PURE__ */
|
|
150243
|
+
statusPinned ? /* @__PURE__ */ jsx_dev_runtime14.jsxDEV(StatusStrip, {
|
|
150244
|
+
ctxPct,
|
|
150245
|
+
tokens,
|
|
150246
|
+
contextWindow: model?.contextWindow ?? null,
|
|
150247
|
+
cost: estimateCost(sessionRef.current.turns),
|
|
150248
|
+
sub: stripSub,
|
|
150249
|
+
api: stripApi,
|
|
150250
|
+
width
|
|
150251
|
+
}, undefined, false, undefined, this) : null,
|
|
150252
|
+
/* @__PURE__ */ jsx_dev_runtime14.jsxDEV(StatusBar, {
|
|
150059
150253
|
model: modelLabel,
|
|
150060
150254
|
branch,
|
|
150061
150255
|
routing,
|
|
@@ -150069,7 +150263,7 @@ Example: /mcp add github npx -y @modelcontextprotocol/server-github`);
|
|
|
150069
150263
|
effort: displayEffort,
|
|
150070
150264
|
online
|
|
150071
150265
|
}, undefined, false, undefined, this),
|
|
150072
|
-
/* @__PURE__ */
|
|
150266
|
+
/* @__PURE__ */ jsx_dev_runtime14.jsxDEV(Box_default, {
|
|
150073
150267
|
height: PALETTE_ROWS,
|
|
150074
150268
|
flexDirection: "column",
|
|
150075
150269
|
children: paletteJsx
|
|
@@ -150077,26 +150271,26 @@ Example: /mcp add github npx -y @modelcontextprotocol/server-github`);
|
|
|
150077
150271
|
composerJsx
|
|
150078
150272
|
]
|
|
150079
150273
|
}, undefined, true, undefined, this);
|
|
150080
|
-
const inlineFooterJsx = /* @__PURE__ */
|
|
150274
|
+
const inlineFooterJsx = /* @__PURE__ */ jsx_dev_runtime14.jsxDEV(jsx_dev_runtime14.Fragment, {
|
|
150081
150275
|
children: [
|
|
150082
150276
|
paletteJsx,
|
|
150083
150277
|
composerJsx
|
|
150084
150278
|
]
|
|
150085
150279
|
}, undefined, true, undefined, this);
|
|
150086
150280
|
if (fullscreen) {
|
|
150087
|
-
return /* @__PURE__ */
|
|
150281
|
+
return /* @__PURE__ */ jsx_dev_runtime14.jsxDEV(Box_default, {
|
|
150088
150282
|
flexDirection: "column",
|
|
150089
150283
|
width,
|
|
150090
150284
|
height: rows,
|
|
150091
150285
|
children: [
|
|
150092
|
-
/* @__PURE__ */
|
|
150286
|
+
/* @__PURE__ */ jsx_dev_runtime14.jsxDEV(Banner, {
|
|
150093
150287
|
model: modelLabel,
|
|
150094
150288
|
cwd: basename3(process.cwd()),
|
|
150095
150289
|
width
|
|
150096
150290
|
}, undefined, false, undefined, this),
|
|
150097
|
-
panel ? /* @__PURE__ */
|
|
150291
|
+
panel ? /* @__PURE__ */ jsx_dev_runtime14.jsxDEV(Box_default, {
|
|
150098
150292
|
paddingX: 1,
|
|
150099
|
-
children: /* @__PURE__ */
|
|
150293
|
+
children: /* @__PURE__ */ jsx_dev_runtime14.jsxDEV(Panel, {
|
|
150100
150294
|
panel,
|
|
150101
150295
|
width: panelW,
|
|
150102
150296
|
height: transcriptHeight,
|
|
@@ -150105,14 +150299,14 @@ Example: /mcp add github npx -y @modelcontextprotocol/server-github`);
|
|
|
150105
150299
|
currentModelId: panelCurrentModel,
|
|
150106
150300
|
staticLines: panelStaticLines
|
|
150107
150301
|
}, undefined, false, undefined, this)
|
|
150108
|
-
}, undefined, false, undefined, this) : welcome ? /* @__PURE__ */
|
|
150302
|
+
}, undefined, false, undefined, this) : welcome ? /* @__PURE__ */ jsx_dev_runtime14.jsxDEV(Box_default, {
|
|
150109
150303
|
height: transcriptHeight,
|
|
150110
150304
|
flexDirection: "column",
|
|
150111
150305
|
justifyContent: "center",
|
|
150112
150306
|
children: hero
|
|
150113
|
-
}, undefined, false, undefined, this) : /* @__PURE__ */
|
|
150307
|
+
}, undefined, false, undefined, this) : /* @__PURE__ */ jsx_dev_runtime14.jsxDEV(Box_default, {
|
|
150114
150308
|
paddingX: 1,
|
|
150115
|
-
children: /* @__PURE__ */
|
|
150309
|
+
children: /* @__PURE__ */ jsx_dev_runtime14.jsxDEV(Viewport, {
|
|
150116
150310
|
lines,
|
|
150117
150311
|
scrollTop: effScroll,
|
|
150118
150312
|
height: transcriptHeight,
|
|
@@ -150124,24 +150318,24 @@ Example: /mcp add github npx -y @modelcontextprotocol/server-github`);
|
|
|
150124
150318
|
]
|
|
150125
150319
|
}, undefined, true, undefined, this);
|
|
150126
150320
|
}
|
|
150127
|
-
const banner = /* @__PURE__ */
|
|
150321
|
+
const banner = /* @__PURE__ */ jsx_dev_runtime14.jsxDEV(Banner, {
|
|
150128
150322
|
model: modelLabel,
|
|
150129
150323
|
cwd: basename3(process.cwd()),
|
|
150130
150324
|
width
|
|
150131
150325
|
}, undefined, false, undefined, this);
|
|
150132
|
-
return /* @__PURE__ */
|
|
150326
|
+
return /* @__PURE__ */ jsx_dev_runtime14.jsxDEV(Box_default, {
|
|
150133
150327
|
flexDirection: "column",
|
|
150134
150328
|
width,
|
|
150135
150329
|
children: [
|
|
150136
|
-
welcome ? /* @__PURE__ */
|
|
150330
|
+
welcome ? /* @__PURE__ */ jsx_dev_runtime14.jsxDEV(jsx_dev_runtime14.Fragment, {
|
|
150137
150331
|
children: [
|
|
150138
150332
|
banner,
|
|
150139
|
-
/* @__PURE__ */
|
|
150333
|
+
/* @__PURE__ */ jsx_dev_runtime14.jsxDEV(Box_default, {
|
|
150140
150334
|
marginTop: 1,
|
|
150141
150335
|
children: hero
|
|
150142
150336
|
}, undefined, false, undefined, this)
|
|
150143
150337
|
]
|
|
150144
|
-
}, undefined, true, undefined, this) : /* @__PURE__ */
|
|
150338
|
+
}, undefined, true, undefined, this) : /* @__PURE__ */ jsx_dev_runtime14.jsxDEV(Transcript, {
|
|
150145
150339
|
items,
|
|
150146
150340
|
width,
|
|
150147
150341
|
header: banner,
|
|
@@ -150155,7 +150349,7 @@ Example: /mcp add github npx -y @modelcontextprotocol/server-github`);
|
|
|
150155
150349
|
// src/cli.tsx
|
|
150156
150350
|
init_providers();
|
|
150157
150351
|
init_permission();
|
|
150158
|
-
var
|
|
150352
|
+
var jsx_dev_runtime15 = __toESM(require_jsx_dev_runtime(), 1);
|
|
150159
150353
|
process.env.LANG = process.env.LANG || "en_US.UTF-8";
|
|
150160
150354
|
process.env.LC_ALL = process.env.LC_ALL || "en_US.UTF-8";
|
|
150161
150355
|
var VERSION16 = "0.1.32";
|
|
@@ -150653,7 +150847,7 @@ if (fullscreen)
|
|
|
150653
150847
|
process.stdout.write("\x1B[?1049h\x1B[2J\x1B[H");
|
|
150654
150848
|
if (mouse)
|
|
150655
150849
|
process.stdout.write("\x1B[?1000h\x1B[?1002h\x1B[?1006h");
|
|
150656
|
-
var app = render_default(/* @__PURE__ */
|
|
150850
|
+
var app = render_default(/* @__PURE__ */ jsx_dev_runtime15.jsxDEV(App2, {
|
|
150657
150851
|
selector,
|
|
150658
150852
|
fullscreen,
|
|
150659
150853
|
resumeId
|