zidane 5.6.14 → 5.7.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -1
- package/dist/{agent-ClkpElCZ.d.ts → agent-BNS2nx_T.d.ts} +535 -15
- package/dist/agent-BNS2nx_T.d.ts.map +1 -0
- package/dist/chat/pure.d.ts +4 -0
- package/dist/chat/pure.js +3 -0
- package/dist/chat.d.ts +31 -661
- package/dist/chat.d.ts.map +1 -1
- package/dist/chat.js +5 -3
- package/dist/chat.js.map +1 -1
- package/dist/contexts/docker.d.ts +1 -1
- package/dist/contexts/docker.d.ts.map +1 -1
- package/dist/contexts/docker.js.map +1 -1
- package/dist/{contexts-BOtMvzli.js → contexts-BD2U_xpi.js} +2 -2
- package/dist/{contexts-BOtMvzli.js.map → contexts-BD2U_xpi.js.map} +1 -1
- package/dist/contexts.d.ts +3 -3
- package/dist/contexts.js +1 -1
- package/dist/edit-utils-DnfNoj16.js +574 -0
- package/dist/edit-utils-DnfNoj16.js.map +1 -0
- package/dist/{errors-DdZXnyXE.js → errors-CoQnKRf1.js} +32 -2
- package/dist/{errors-DdZXnyXE.js.map → errors-CoQnKRf1.js.map} +1 -1
- package/dist/fetch-url-CPxfiXDa.js +518 -0
- package/dist/fetch-url-CPxfiXDa.js.map +1 -0
- package/dist/image-sniff-B7uFSNO1.js +90 -0
- package/dist/image-sniff-B7uFSNO1.js.map +1 -0
- package/dist/{index-CbS75MD3.d.ts → index-CZOwAJIX.d.ts} +2 -2
- package/dist/index-CZOwAJIX.d.ts.map +1 -0
- package/dist/{index-CTDMMdIy.d.ts → index-Ck_AWt8P.d.ts} +3 -4
- package/dist/index-Ck_AWt8P.d.ts.map +1 -0
- package/dist/{index-v3Tzobqr.d.ts → index-KiS7w0dC.d.ts} +3 -3
- package/dist/index-KiS7w0dC.d.ts.map +1 -0
- package/dist/index.d.ts +6 -6
- package/dist/index.js +13 -12
- package/dist/index.js.map +1 -1
- package/dist/{interpolate-DM1UcKeQ.js → interpolate-TySiqKzc.js} +23 -23
- package/dist/{interpolate-DM1UcKeQ.js.map → interpolate-TySiqKzc.js.map} +1 -1
- package/dist/{login-7tHcckmX.js → login-BDeqENSe.js} +7 -58
- package/dist/login-BDeqENSe.js.map +1 -0
- package/dist/{mcp-DGeB7-3D.js → mcp-Kqzz-Rs_.js} +8 -6
- package/dist/mcp-Kqzz-Rs_.js.map +1 -0
- package/dist/mcp.d.ts +2 -2
- package/dist/mcp.js +1 -1
- package/dist/{messages-Dym8S_YH.js → messages-CvRQTdbR.js} +118 -39
- package/dist/messages-CvRQTdbR.js.map +1 -0
- package/dist/{presets-w9Px_aAm.js → presets-JuOnSI-i.js} +2 -2
- package/dist/{presets-w9Px_aAm.js.map → presets-JuOnSI-i.js.map} +1 -1
- package/dist/presets.d.ts +3 -3
- package/dist/presets.js +1 -1
- package/dist/{providers-beXyD9W9.js → providers-h4HJPbbv.js} +485 -31
- package/dist/providers-h4HJPbbv.js.map +1 -0
- package/dist/providers.d.ts +2 -2
- package/dist/providers.js +3 -3
- package/dist/restate.d.ts +1 -1
- package/dist/restate.d.ts.map +1 -1
- package/dist/restate.js.map +1 -1
- package/dist/session/sqlite.d.ts +1 -1
- package/dist/session/sqlite.d.ts.map +1 -1
- package/dist/session/sqlite.js +1 -1
- package/dist/session/sqlite.js.map +1 -1
- package/dist/{session-BRIsmBSY.js → session-BzLou2_-.js} +2 -2
- package/dist/{session-BRIsmBSY.js.map → session-BzLou2_-.js.map} +1 -1
- package/dist/session.d.ts +2 -2
- package/dist/session.js +2 -2
- package/dist/skills.d.ts +3 -3
- package/dist/skills.js +1 -1
- package/dist/skills.js.map +1 -1
- package/dist/{stats-Lc3zL3RM.js → stats-DAKBEKjc.js} +12 -2
- package/dist/stats-DAKBEKjc.js.map +1 -0
- package/dist/{stdio-loader-EVAF5KlU.js → stdio-loader-Ce68wUmM.js} +4 -4
- package/dist/stdio-loader-Ce68wUmM.js.map +1 -0
- package/dist/tool-formatters-CU-j3a3e.d.ts +1471 -0
- package/dist/tool-formatters-CU-j3a3e.d.ts.map +1 -0
- package/dist/tools/fetch-url.d.ts +70 -0
- package/dist/tools/fetch-url.d.ts.map +1 -0
- package/dist/tools/fetch-url.js +2 -0
- package/dist/tools/web-search.d.ts +7 -0
- package/dist/tools/web-search.d.ts.map +1 -0
- package/dist/tools/web-search.js +190 -0
- package/dist/tools/web-search.js.map +1 -0
- package/dist/{tools-DhrLrOEr.js → tools-BGtJK0vo.js} +1368 -421
- package/dist/tools-BGtJK0vo.js.map +1 -0
- package/dist/tools.d.ts +3 -3
- package/dist/tools.js +1 -1
- package/dist/{turn-operations-UAkOjO-u.js → transcript-anchors-BTSZAPVc.js} +147 -2713
- package/dist/transcript-anchors-BTSZAPVc.js.map +1 -0
- package/dist/{transcript-anchors-D0TR6djV.d.ts → transcript-anchors-DX90kXc4.d.ts} +13 -1299
- package/dist/transcript-anchors-DX90kXc4.d.ts.map +1 -0
- package/dist/tui.d.ts +58 -28
- package/dist/tui.d.ts.map +1 -1
- package/dist/tui.js +1349 -422
- package/dist/tui.js.map +1 -1
- package/dist/turn-operations-CCHfR9eC.js +1938 -0
- package/dist/turn-operations-CCHfR9eC.js.map +1 -0
- package/dist/turn-operations-DDIl4YVk.d.ts +658 -0
- package/dist/turn-operations-DDIl4YVk.d.ts.map +1 -0
- package/dist/{types-oKPBdCmL.js → types-BPw_i5vb.js} +1 -1
- package/dist/types-BPw_i5vb.js.map +1 -0
- package/dist/{types-KukEp-mi.d.ts → types-CEAMIUXw.d.ts} +1 -1
- package/dist/types-CEAMIUXw.d.ts.map +1 -0
- package/dist/types.d.ts +4 -4
- package/dist/types.js +3 -3
- package/docs/CHAT.md +53 -6
- package/docs/SKILL.md +3 -0
- package/docs/TUI.md +7 -0
- package/package.json +18 -2
- package/dist/agent-ClkpElCZ.d.ts.map +0 -1
- package/dist/index-CTDMMdIy.d.ts.map +0 -1
- package/dist/index-CbS75MD3.d.ts.map +0 -1
- package/dist/index-v3Tzobqr.d.ts.map +0 -1
- package/dist/login-7tHcckmX.js.map +0 -1
- package/dist/mcp-DGeB7-3D.js.map +0 -1
- package/dist/messages-Dym8S_YH.js.map +0 -1
- package/dist/providers-beXyD9W9.js.map +0 -1
- package/dist/stats-Lc3zL3RM.js.map +0 -1
- package/dist/stdio-loader-EVAF5KlU.js.map +0 -1
- package/dist/tools-DhrLrOEr.js.map +0 -1
- package/dist/transcript-anchors-D0TR6djV.d.ts.map +0 -1
- package/dist/turn-operations-UAkOjO-u.js.map +0 -1
- package/dist/types-KukEp-mi.d.ts.map +0 -1
- package/dist/types-oKPBdCmL.js.map +0 -1
package/dist/tui.js
CHANGED
|
@@ -1,24 +1,27 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import { A as replaceDynamicSection } from "./messages-
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
1
|
+
import { $ as useMcpAuthDispatch, $t as deriveSessionTitle, A as runOAuthLogin, An as buildUpdateHint, At as clampFps, B as refreshMcpToolsCatalog, Bn as AUTO_COMPACT_MIN_GROWTH_FRACTION, Ct as listProjectFiles, D as formatPathForCwd, Dn as tryOpenBrowser, Dt as SETTINGS_CHOICES, En as useCompletion, Et as SETTINGS_CATEGORIES, Ft as resolveTheme, Gt as useDiscovery, H as subscribeMcpToolsCache, Hn as detectAuth, J as parentServerName, Jn as setProviderCredential, Jt as useConfig, K as buildVisibleMcpRows, Kt as useDiscoveryOptional, M as buildMcpServers, Mr as buildBuildSystem, Nr as buildPlanSystem, O as fetchOAuthRedirect, Ot as SETTINGS_TOGGLES, P as discoverProjectMcps, Pr as envSection, Pt as resolveChipColor, Q as McpAuthProvider, Qn as findGitRoot, R as loadMcpToolsCache, T as suggestSafelistEntry, Tt as DEFAULT_SETTINGS, Ut as createDiscoverySlot, Vn as shouldAutoCompact, W as useMcpToolToggleMap, Wt as DiscoveryProvider, Xn as discoverAgentsMd, Y as createFileMcpCredentialStore, Yt as resolveConfig, _ as useSafeModeQueue, _n as ensureKeybindingsFile, _t as hintsLength, a as useSurfaces, ar as accentColor, at as InteractionsProvider, b as getSafelist, bn as keybindingsPath, bt as generateSessionTitle, c as useStreamBuffer, cn as sumRunCosts, ct as createInteractionTools, d as discoverProjectSkills, dn as toolResultText, dr as TODO_STATUS_GLYPHS, dt as pendingInteractionsFromTurns, en as eventsFromTurns, et as useMcpAuthState, fn as updateToolEventOutcomes, g as useSafeModeActions, gn as KEYBINDING_KEY_COL_WIDTH, gt as clipHintsToWidth, h as SafeModeProvider, ht as EMPTY_HINTS, i as useSelectStyle, in as marginTopFor, j as supportsOAuth, jn as useUpdateCheck, jt as useSettings, k as oauthUsesManualCodePaste, kn as bootTick, kt as SettingsProvider, l as buildSkillsConfig, m as writeSessionExport, mn as KEYBINDING_DEFS, mt as useInteractionsQueue, n as ThemeProvider, nn as listSessionMeta, on as serverToolResultSummary, pt as useInteractionsActions, q as indexOfServerRow, qt as ConfigProvider, r as useColors, rt as splitMarkdownCodeBlocks, s as useTheme, sn as stripSpawnTokensLine, st as buildResumedToolResultsTurn, t as computeTurnAnchors, tn as lastContextSizeFromTurns, tt as getMcpAuthStatus, u as defaultSkillScanPaths, un as toolCallPreview, ut as makeRequestInteraction, vn as formatBindingForDisplay, vt as truncateTrailing, wt as useEnabledToggleSet, x as isOnSafelist, xn as matchesBinding, xr as useActiveTodos, xt as buildHints, y as addToSafelist, yn as groupBindings } from "./transcript-anchors-BTSZAPVc.js";
|
|
2
|
+
import { B as enabledModelOptions, E as cleanupPersistedSession, F as OUTPUT_RESERVE_TOKENS, G as modelSupportsReasoning, O as resolvePersistDir, V as getContextWindow, W as modelOptionsFor, X as restoreModelOptions, Y as piIdOf, d as createAgent, k as resolveTasksDir, z as effectiveContextWindow } from "./tools-BGtJK0vo.js";
|
|
3
|
+
import { a as compactPath, c as formatTaskStatus, d as shortId, i as ageString, l as formatTaskSummary, o as fmtTokens, s as formatDuration, u as previewLine } from "./edit-utils-DnfNoj16.js";
|
|
4
|
+
import { l as errorMessage } from "./errors-CoQnKRf1.js";
|
|
5
|
+
import { A as replaceDynamicSection } from "./messages-CvRQTdbR.js";
|
|
6
|
+
import { n as sniffImageMediaType } from "./image-sniff-B7uFSNO1.js";
|
|
7
|
+
import { n as createProcessContext } from "./contexts-BD2U_xpi.js";
|
|
8
|
+
import { s as McpOAuthProvider, t as connectMcpServers } from "./mcp-Kqzz-Rs_.js";
|
|
9
|
+
import { r as formatTokenUsage, t as effectiveInputFromTurn } from "./stats-DAKBEKjc.js";
|
|
10
|
+
import { a as selectFilesFromSession, b as summaryToTurn, r as buildPostCompactAttachments, s as compactConversation, t as loginMcpServer } from "./login-BDeqENSe.js";
|
|
11
|
+
import { n as loadSession, t as createSession } from "./session-BzLou2_-.js";
|
|
10
12
|
import { createTuiStore } from "./session/sqlite.js";
|
|
13
|
+
import { B as summarizeOutcomes, C as buildContextualDiff, D as extractEditPayload, F as mergeApprovalAndBodyOutcomes, G as createFilesCompletionProvider, H as createSkillsCompletionProvider, I as parseEditOutcomesFromResult, L as resolveApprovalForPayload, N as buildEditOutcomesAnnotation, O as filetypeFromPath, Q as buildLinearRamp, R as rewriteMultiEditHeader, U as uniqueSkillNamesFromReferences, Z as blendHsl, _ as isEditErrorResult, a as TOOL_DISPLAY, b as selectableTurnIds, c as finalizeStreamingMarkdown, d as turnContextSize, f as splitPromptSegments, g as EDIT_TOOL_NAMES, h as indexOfEntry, i as turnAsText, j as summarizeEditPayload, k as previewEditPayload, l as finalizeStreamingMarkdownForOwner, m as filterModelCatalog, n as deleteTurnSafely, o as displayNameFor, p as buildModelCatalog, r as truncateTurnsAt, s as formatToolCall, v as isTurnHighlighted, w as buildUnifiedDiff, x as turnSelectionOwnership, y as isVisible, z as stripEditOutcomesAnnotation } from "./turn-operations-CCHfR9eC.js";
|
|
11
14
|
import { basename, join, relative } from "node:path";
|
|
12
|
-
import {
|
|
13
|
-
import { spawn } from "node:child_process";
|
|
15
|
+
import { Buffer } from "node:buffer";
|
|
14
16
|
import * as fs from "node:fs";
|
|
15
17
|
import { readFileSync, readdirSync, statSync } from "node:fs";
|
|
16
|
-
import {
|
|
18
|
+
import { spawn } from "node:child_process";
|
|
19
|
+
import { homedir } from "node:os";
|
|
17
20
|
import { createContext, createElement, memo, useCallback, useContext, useEffect, useMemo, useRef, useState } from "react";
|
|
21
|
+
import { Fzf, byLengthAsc } from "fzf";
|
|
18
22
|
import { BoxRenderable, CodeRenderable, RGBA, SyntaxStyle, TextRenderable, addDefaultParsers, createCliRenderer, decodePasteBytes, defaultTextareaKeyBindings, getTreeSitterClient, stripAnsiSequences } from "@opentui/core";
|
|
19
23
|
import { createRoot, useKeyboard, useRenderer, useSelectionHandler, useTerminalDimensions } from "@opentui/react";
|
|
20
24
|
import { Fragment, jsx, jsxs } from "@opentui/react/jsx-runtime";
|
|
21
|
-
import { Fzf, byLengthAsc } from "fzf";
|
|
22
25
|
//#region src/tui/modal.tsx
|
|
23
26
|
const ModalContext = createContext(null);
|
|
24
27
|
function ModalRoot({ children }) {
|
|
@@ -2520,6 +2523,418 @@ function TodoInProgressList({ input, dim }) {
|
|
|
2520
2523
|
});
|
|
2521
2524
|
}
|
|
2522
2525
|
//#endregion
|
|
2526
|
+
//#region src/tui/context-panel.tsx
|
|
2527
|
+
/**
|
|
2528
|
+
* Distinct categorical palette for the bar + swatches — kept in lock-step with
|
|
2529
|
+
* the GUI popover (`CATEGORY_COLORS` in `ChatboxControls.tsx`) so both surfaces
|
|
2530
|
+
* read identically. Fixed hues (not theme tokens) so the same category is the
|
|
2531
|
+
* same color across every theme and across both surfaces. Deferred/free fall
|
|
2532
|
+
* through to muted theme tones via {@link colorFor}.
|
|
2533
|
+
*/
|
|
2534
|
+
const CATEGORY_HEX = {
|
|
2535
|
+
systemPrompt: "#4f9dff",
|
|
2536
|
+
rules: "#22d3ee",
|
|
2537
|
+
skills: "#a855f7",
|
|
2538
|
+
mcpInstructions: "#eab308",
|
|
2539
|
+
subagentDefs: "#ec4899",
|
|
2540
|
+
tools: "#22c55e",
|
|
2541
|
+
mcpTools: "#f59e0b",
|
|
2542
|
+
conversation: "#fb923c"
|
|
2543
|
+
};
|
|
2544
|
+
function colorFor(id, COLOR) {
|
|
2545
|
+
return CATEGORY_HEX[id] ?? COLOR.mute;
|
|
2546
|
+
}
|
|
2547
|
+
/** Percent label — `<1%` for tiny non-zero shares, empty at exactly 0. */
|
|
2548
|
+
function pctLabel(tokens, denom) {
|
|
2549
|
+
if (tokens <= 0 || denom <= 0) return "";
|
|
2550
|
+
const raw = tokens / denom * 100;
|
|
2551
|
+
return raw < 1 ? "<1%" : `${Math.round(raw)}%`;
|
|
2552
|
+
}
|
|
2553
|
+
function ContextPanelModal({ breakdown }) {
|
|
2554
|
+
const COLOR = useColors();
|
|
2555
|
+
const [expanded, setExpanded] = useState(() => /* @__PURE__ */ new Set());
|
|
2556
|
+
const expandableIds = useMemo(() => breakdown.categories.filter((c) => c.items && c.items.length > 0).map((c) => c.id), [breakdown]);
|
|
2557
|
+
const [cursor, setCursor] = useState(0);
|
|
2558
|
+
const safeCursor = expandableIds.length === 0 ? 0 : Math.min(cursor, expandableIds.length - 1);
|
|
2559
|
+
useKeyboard((key) => {
|
|
2560
|
+
if (expandableIds.length === 0) return;
|
|
2561
|
+
if (key.name === "up") {
|
|
2562
|
+
setCursor((i) => ((i - 1) % expandableIds.length + expandableIds.length) % expandableIds.length);
|
|
2563
|
+
return;
|
|
2564
|
+
}
|
|
2565
|
+
if (key.name === "down") {
|
|
2566
|
+
setCursor((i) => (i + 1) % expandableIds.length);
|
|
2567
|
+
return;
|
|
2568
|
+
}
|
|
2569
|
+
if (key.name === "return" || key.name === "space") {
|
|
2570
|
+
const id = expandableIds[safeCursor];
|
|
2571
|
+
setExpanded((prev) => {
|
|
2572
|
+
const next = new Set(prev);
|
|
2573
|
+
if (next.has(id)) next.delete(id);
|
|
2574
|
+
else next.add(id);
|
|
2575
|
+
return next;
|
|
2576
|
+
});
|
|
2577
|
+
}
|
|
2578
|
+
});
|
|
2579
|
+
const denom = breakdown.effectiveWindow || breakdown.used || 1;
|
|
2580
|
+
const live = breakdown.categories.filter((c) => !c.deferred);
|
|
2581
|
+
const deferred = breakdown.categories.filter((c) => c.deferred);
|
|
2582
|
+
const pct = Math.round(breakdown.fraction * 100);
|
|
2583
|
+
const usedColor = pct >= 85 ? COLOR.error : pct >= 60 ? COLOR.warn : COLOR.brand;
|
|
2584
|
+
return /* @__PURE__ */ jsxs(Modal, {
|
|
2585
|
+
title: "context window",
|
|
2586
|
+
maxWidth: 76,
|
|
2587
|
+
children: [
|
|
2588
|
+
/* @__PURE__ */ jsxs("box", {
|
|
2589
|
+
style: {
|
|
2590
|
+
flexDirection: "column",
|
|
2591
|
+
flexShrink: 0
|
|
2592
|
+
},
|
|
2593
|
+
children: [
|
|
2594
|
+
/* @__PURE__ */ jsxs("box", {
|
|
2595
|
+
style: {
|
|
2596
|
+
flexDirection: "row",
|
|
2597
|
+
height: 1,
|
|
2598
|
+
flexShrink: 0
|
|
2599
|
+
},
|
|
2600
|
+
children: [
|
|
2601
|
+
/* @__PURE__ */ jsx("text", {
|
|
2602
|
+
wrapMode: "none",
|
|
2603
|
+
fg: COLOR.mute,
|
|
2604
|
+
children: breakdown.modelId
|
|
2605
|
+
}),
|
|
2606
|
+
/* @__PURE__ */ jsx("box", { style: { flexGrow: 1 } }),
|
|
2607
|
+
/* @__PURE__ */ jsxs("text", {
|
|
2608
|
+
wrapMode: "none",
|
|
2609
|
+
children: [
|
|
2610
|
+
/* @__PURE__ */ jsx("span", {
|
|
2611
|
+
fg: usedColor,
|
|
2612
|
+
children: fmtTokens(breakdown.used)
|
|
2613
|
+
}),
|
|
2614
|
+
/* @__PURE__ */ jsx("span", {
|
|
2615
|
+
fg: COLOR.mute,
|
|
2616
|
+
children: ` / ${fmtTokens(breakdown.effectiveWindow)} `
|
|
2617
|
+
}),
|
|
2618
|
+
/* @__PURE__ */ jsx("span", {
|
|
2619
|
+
fg: usedColor,
|
|
2620
|
+
children: `(${pct}%)`
|
|
2621
|
+
})
|
|
2622
|
+
]
|
|
2623
|
+
})
|
|
2624
|
+
]
|
|
2625
|
+
}),
|
|
2626
|
+
/* @__PURE__ */ jsx("box", {
|
|
2627
|
+
style: {
|
|
2628
|
+
height: 1,
|
|
2629
|
+
flexShrink: 0,
|
|
2630
|
+
marginTop: 1
|
|
2631
|
+
},
|
|
2632
|
+
children: /* @__PURE__ */ jsx(StackedBar, {
|
|
2633
|
+
breakdown,
|
|
2634
|
+
denom,
|
|
2635
|
+
COLOR
|
|
2636
|
+
})
|
|
2637
|
+
}),
|
|
2638
|
+
/* @__PURE__ */ jsx("box", { style: {
|
|
2639
|
+
height: 1,
|
|
2640
|
+
flexShrink: 0
|
|
2641
|
+
} }),
|
|
2642
|
+
live.map((cat) => /* @__PURE__ */ jsx(CategoryRows, {
|
|
2643
|
+
cat,
|
|
2644
|
+
denom,
|
|
2645
|
+
COLOR,
|
|
2646
|
+
isCursor: expandableIds[safeCursor] === cat.id,
|
|
2647
|
+
isExpanded: expanded.has(cat.id)
|
|
2648
|
+
}, cat.id)),
|
|
2649
|
+
deferred.length > 0 && /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("box", { style: {
|
|
2650
|
+
height: 1,
|
|
2651
|
+
flexShrink: 0
|
|
2652
|
+
} }), deferred.map((cat) => /* @__PURE__ */ jsx(CategoryRows, {
|
|
2653
|
+
cat,
|
|
2654
|
+
denom,
|
|
2655
|
+
COLOR,
|
|
2656
|
+
isCursor: expandableIds[safeCursor] === cat.id,
|
|
2657
|
+
isExpanded: expanded.has(cat.id)
|
|
2658
|
+
}, cat.id))] }),
|
|
2659
|
+
breakdown.activeSkills && breakdown.activeSkills.length > 0 && /* @__PURE__ */ jsx(ActiveSkillsRow, {
|
|
2660
|
+
skills: breakdown.activeSkills,
|
|
2661
|
+
COLOR
|
|
2662
|
+
}),
|
|
2663
|
+
breakdown.usage && /* @__PURE__ */ jsx(UsageRows, {
|
|
2664
|
+
usage: breakdown.usage,
|
|
2665
|
+
COLOR
|
|
2666
|
+
})
|
|
2667
|
+
]
|
|
2668
|
+
}),
|
|
2669
|
+
breakdown.hasEstimates && /* @__PURE__ */ jsxs("text", {
|
|
2670
|
+
fg: COLOR.dim,
|
|
2671
|
+
children: [/* @__PURE__ */ jsx("span", {
|
|
2672
|
+
fg: COLOR.mute,
|
|
2673
|
+
children: "~"
|
|
2674
|
+
}), " estimated — exact counts unavailable for this provider"]
|
|
2675
|
+
}),
|
|
2676
|
+
/* @__PURE__ */ jsx("text", {
|
|
2677
|
+
fg: COLOR.dim,
|
|
2678
|
+
children: expandableIds.length > 0 ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
2679
|
+
/* @__PURE__ */ jsx("span", {
|
|
2680
|
+
fg: COLOR.warn,
|
|
2681
|
+
children: "↑↓"
|
|
2682
|
+
}),
|
|
2683
|
+
" navigate · ",
|
|
2684
|
+
/* @__PURE__ */ jsx("span", {
|
|
2685
|
+
fg: COLOR.warn,
|
|
2686
|
+
children: "↵/space"
|
|
2687
|
+
}),
|
|
2688
|
+
" expand · ",
|
|
2689
|
+
/* @__PURE__ */ jsx("span", {
|
|
2690
|
+
fg: COLOR.warn,
|
|
2691
|
+
children: "esc"
|
|
2692
|
+
}),
|
|
2693
|
+
" close"
|
|
2694
|
+
] }) : /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("span", {
|
|
2695
|
+
fg: COLOR.warn,
|
|
2696
|
+
children: "esc"
|
|
2697
|
+
}), " close"] })
|
|
2698
|
+
})
|
|
2699
|
+
]
|
|
2700
|
+
});
|
|
2701
|
+
}
|
|
2702
|
+
/**
|
|
2703
|
+
* Single-row stacked bar that fills the panel width. Layout (left → right):
|
|
2704
|
+
* [ colored category segments ][ free space ][ autocompact buffer ]
|
|
2705
|
+
*
|
|
2706
|
+
* Sizing uses `flexGrow` weights (×1000 of the window fraction) so the bar
|
|
2707
|
+
* stretches to the full container width. Each non-zero colored segment also
|
|
2708
|
+
* carries `minWidth: 1` so tiny shares (system/tools at <1% of a 1M window)
|
|
2709
|
+
* stay visible instead of collapsing into one color. The autocompact buffer is
|
|
2710
|
+
* pinned at the far right — reserved tail headroom, consumed last.
|
|
2711
|
+
*/
|
|
2712
|
+
function StackedBar({ breakdown, denom, COLOR }) {
|
|
2713
|
+
const live = breakdown.categories.filter((c) => !c.deferred && c.tokens > 0);
|
|
2714
|
+
const buffer = breakdown.categories.find((c) => c.id === "autocompactBuffer" && c.tokens > 0);
|
|
2715
|
+
const MIN_WEIGHT = 14;
|
|
2716
|
+
const w = (tokens) => Math.max(MIN_WEIGHT, Math.round(tokens / denom * 1e3));
|
|
2717
|
+
const colored = live.map((c) => ({
|
|
2718
|
+
id: c.id,
|
|
2719
|
+
weight: w(c.tokens)
|
|
2720
|
+
}));
|
|
2721
|
+
const coloredWeight = colored.reduce((a, s) => a + s.weight, 0);
|
|
2722
|
+
const bufferWeight = buffer ? Math.round(buffer.tokens / denom * 1e3) : 0;
|
|
2723
|
+
const freeWeight = Math.max(0, 1e3 - coloredWeight - bufferWeight);
|
|
2724
|
+
return /* @__PURE__ */ jsxs("box", {
|
|
2725
|
+
style: {
|
|
2726
|
+
flexDirection: "row",
|
|
2727
|
+
flexGrow: 1,
|
|
2728
|
+
height: 1
|
|
2729
|
+
},
|
|
2730
|
+
children: [
|
|
2731
|
+
colored.map((s, i) => /* @__PURE__ */ jsx("box", { style: {
|
|
2732
|
+
flexGrow: s.weight,
|
|
2733
|
+
flexBasis: 0,
|
|
2734
|
+
height: 1,
|
|
2735
|
+
backgroundColor: colorFor(s.id, COLOR)
|
|
2736
|
+
} }, `${s.id}-${i}`)),
|
|
2737
|
+
freeWeight > 0 && /* @__PURE__ */ jsx("box", { style: {
|
|
2738
|
+
flexGrow: freeWeight,
|
|
2739
|
+
flexBasis: 0,
|
|
2740
|
+
height: 1,
|
|
2741
|
+
backgroundColor: COLOR.mute
|
|
2742
|
+
} }),
|
|
2743
|
+
bufferWeight > 0 && /* @__PURE__ */ jsx("box", { style: {
|
|
2744
|
+
flexGrow: bufferWeight,
|
|
2745
|
+
flexBasis: 0,
|
|
2746
|
+
height: 1,
|
|
2747
|
+
backgroundColor: COLOR.dim
|
|
2748
|
+
} })
|
|
2749
|
+
]
|
|
2750
|
+
});
|
|
2751
|
+
}
|
|
2752
|
+
/**
|
|
2753
|
+
* Currently-active skills. Informational — an activated skill's body lives in
|
|
2754
|
+
* the conversation (already counted there); this surfaces which are loaded.
|
|
2755
|
+
*/
|
|
2756
|
+
function ActiveSkillsRow({ skills, COLOR }) {
|
|
2757
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
2758
|
+
/* @__PURE__ */ jsx("box", { style: {
|
|
2759
|
+
height: 1,
|
|
2760
|
+
flexShrink: 0
|
|
2761
|
+
} }),
|
|
2762
|
+
/* @__PURE__ */ jsx("box", {
|
|
2763
|
+
style: {
|
|
2764
|
+
height: 1,
|
|
2765
|
+
flexShrink: 0
|
|
2766
|
+
},
|
|
2767
|
+
children: /* @__PURE__ */ jsx("text", {
|
|
2768
|
+
wrapMode: "none",
|
|
2769
|
+
fg: COLOR.mute,
|
|
2770
|
+
children: "active skills"
|
|
2771
|
+
})
|
|
2772
|
+
}),
|
|
2773
|
+
skills.map((name) => /* @__PURE__ */ jsx("box", {
|
|
2774
|
+
style: {
|
|
2775
|
+
flexDirection: "row",
|
|
2776
|
+
height: 1,
|
|
2777
|
+
flexShrink: 0
|
|
2778
|
+
},
|
|
2779
|
+
children: /* @__PURE__ */ jsxs("text", {
|
|
2780
|
+
wrapMode: "none",
|
|
2781
|
+
children: [/* @__PURE__ */ jsx("span", {
|
|
2782
|
+
fg: CATEGORY_HEX.skills,
|
|
2783
|
+
children: "✦ "
|
|
2784
|
+
}), /* @__PURE__ */ jsx("span", {
|
|
2785
|
+
fg: COLOR.dim,
|
|
2786
|
+
children: name
|
|
2787
|
+
})]
|
|
2788
|
+
})
|
|
2789
|
+
}, name))
|
|
2790
|
+
] });
|
|
2791
|
+
}
|
|
2792
|
+
/**
|
|
2793
|
+
* Exact last-turn token split (cache read / write / fresh input / output).
|
|
2794
|
+
* Informational — sits below the categories, all values exact (no `~`).
|
|
2795
|
+
*/
|
|
2796
|
+
function UsageRows({ usage, COLOR }) {
|
|
2797
|
+
const rows = [
|
|
2798
|
+
{
|
|
2799
|
+
label: "Cached (read)",
|
|
2800
|
+
tokens: usage.cacheRead
|
|
2801
|
+
},
|
|
2802
|
+
{
|
|
2803
|
+
label: "Cache write",
|
|
2804
|
+
tokens: usage.cacheCreation
|
|
2805
|
+
},
|
|
2806
|
+
{
|
|
2807
|
+
label: "Fresh input",
|
|
2808
|
+
tokens: usage.input
|
|
2809
|
+
},
|
|
2810
|
+
{
|
|
2811
|
+
label: "Output",
|
|
2812
|
+
tokens: usage.output
|
|
2813
|
+
}
|
|
2814
|
+
].filter((r) => r.tokens > 0);
|
|
2815
|
+
if (rows.length === 0) return null;
|
|
2816
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
2817
|
+
/* @__PURE__ */ jsx("box", { style: {
|
|
2818
|
+
height: 1,
|
|
2819
|
+
flexShrink: 0
|
|
2820
|
+
} }),
|
|
2821
|
+
/* @__PURE__ */ jsx("box", {
|
|
2822
|
+
style: {
|
|
2823
|
+
height: 1,
|
|
2824
|
+
flexShrink: 0
|
|
2825
|
+
},
|
|
2826
|
+
children: /* @__PURE__ */ jsx("text", {
|
|
2827
|
+
wrapMode: "none",
|
|
2828
|
+
fg: COLOR.mute,
|
|
2829
|
+
children: "last turn"
|
|
2830
|
+
})
|
|
2831
|
+
}),
|
|
2832
|
+
rows.map((r) => /* @__PURE__ */ jsxs("box", {
|
|
2833
|
+
style: {
|
|
2834
|
+
flexDirection: "row",
|
|
2835
|
+
height: 1,
|
|
2836
|
+
flexShrink: 0
|
|
2837
|
+
},
|
|
2838
|
+
children: [
|
|
2839
|
+
/* @__PURE__ */ jsx("text", {
|
|
2840
|
+
wrapMode: "none",
|
|
2841
|
+
fg: COLOR.mute,
|
|
2842
|
+
children: r.label
|
|
2843
|
+
}),
|
|
2844
|
+
/* @__PURE__ */ jsx("box", { style: { flexGrow: 1 } }),
|
|
2845
|
+
/* @__PURE__ */ jsx("text", {
|
|
2846
|
+
wrapMode: "none",
|
|
2847
|
+
fg: COLOR.dim,
|
|
2848
|
+
children: fmtTokens(r.tokens)
|
|
2849
|
+
})
|
|
2850
|
+
]
|
|
2851
|
+
}, r.label))
|
|
2852
|
+
] });
|
|
2853
|
+
}
|
|
2854
|
+
function CategoryRows({ cat, denom, COLOR, isCursor, isExpanded }) {
|
|
2855
|
+
const SURFACE = useSurfaces();
|
|
2856
|
+
const pct = pctLabel(cat.tokens, denom);
|
|
2857
|
+
const hasItems = !!cat.items && cat.items.length > 0;
|
|
2858
|
+
const labelColor = isCursor ? COLOR.brand : cat.deferred ? COLOR.mute : COLOR.dim;
|
|
2859
|
+
const marker = hasItems ? isExpanded ? " ▾" : " ▸" : "";
|
|
2860
|
+
return /* @__PURE__ */ jsxs("box", {
|
|
2861
|
+
style: {
|
|
2862
|
+
flexDirection: "column",
|
|
2863
|
+
flexShrink: 0
|
|
2864
|
+
},
|
|
2865
|
+
children: [/* @__PURE__ */ jsxs("box", {
|
|
2866
|
+
style: {
|
|
2867
|
+
flexDirection: "row",
|
|
2868
|
+
height: 1,
|
|
2869
|
+
flexShrink: 0,
|
|
2870
|
+
backgroundColor: isCursor && hasItems ? SURFACE.selection : void 0
|
|
2871
|
+
},
|
|
2872
|
+
children: [
|
|
2873
|
+
/* @__PURE__ */ jsxs("text", {
|
|
2874
|
+
wrapMode: "none",
|
|
2875
|
+
children: [
|
|
2876
|
+
/* @__PURE__ */ jsx("span", {
|
|
2877
|
+
fg: colorFor(cat.id, COLOR),
|
|
2878
|
+
children: "■ "
|
|
2879
|
+
}),
|
|
2880
|
+
/* @__PURE__ */ jsx("span", {
|
|
2881
|
+
fg: labelColor,
|
|
2882
|
+
children: cat.label
|
|
2883
|
+
}),
|
|
2884
|
+
marker ? /* @__PURE__ */ jsx("span", {
|
|
2885
|
+
fg: hasItems && isCursor ? COLOR.brand : COLOR.mute,
|
|
2886
|
+
children: marker
|
|
2887
|
+
}) : null
|
|
2888
|
+
]
|
|
2889
|
+
}),
|
|
2890
|
+
/* @__PURE__ */ jsx("box", { style: { flexGrow: 1 } }),
|
|
2891
|
+
/* @__PURE__ */ jsxs("text", {
|
|
2892
|
+
wrapMode: "none",
|
|
2893
|
+
children: [
|
|
2894
|
+
cat.estimated && /* @__PURE__ */ jsx("span", {
|
|
2895
|
+
fg: COLOR.mute,
|
|
2896
|
+
children: "~"
|
|
2897
|
+
}),
|
|
2898
|
+
/* @__PURE__ */ jsx("span", {
|
|
2899
|
+
fg: cat.deferred ? COLOR.mute : COLOR.dim,
|
|
2900
|
+
children: fmtTokens(cat.tokens)
|
|
2901
|
+
}),
|
|
2902
|
+
pct ? /* @__PURE__ */ jsx("span", {
|
|
2903
|
+
fg: COLOR.mute,
|
|
2904
|
+
children: ` ${pct}`
|
|
2905
|
+
}) : null
|
|
2906
|
+
]
|
|
2907
|
+
})
|
|
2908
|
+
]
|
|
2909
|
+
}), isExpanded && hasItems && cat.items.map((item) => /* @__PURE__ */ jsxs("box", {
|
|
2910
|
+
style: {
|
|
2911
|
+
flexDirection: "row",
|
|
2912
|
+
height: 1,
|
|
2913
|
+
paddingLeft: 2,
|
|
2914
|
+
flexShrink: 0
|
|
2915
|
+
},
|
|
2916
|
+
children: [
|
|
2917
|
+
/* @__PURE__ */ jsx("text", {
|
|
2918
|
+
wrapMode: "none",
|
|
2919
|
+
fg: COLOR.mute,
|
|
2920
|
+
children: item.label
|
|
2921
|
+
}),
|
|
2922
|
+
/* @__PURE__ */ jsx("box", { style: { flexGrow: 1 } }),
|
|
2923
|
+
/* @__PURE__ */ jsxs("text", {
|
|
2924
|
+
wrapMode: "none",
|
|
2925
|
+
children: [item.estimated && /* @__PURE__ */ jsx("span", {
|
|
2926
|
+
fg: COLOR.mute,
|
|
2927
|
+
children: "~"
|
|
2928
|
+
}), /* @__PURE__ */ jsx("span", {
|
|
2929
|
+
fg: COLOR.mute,
|
|
2930
|
+
children: fmtTokens(item.tokens)
|
|
2931
|
+
})]
|
|
2932
|
+
})
|
|
2933
|
+
]
|
|
2934
|
+
}, item.id))]
|
|
2935
|
+
});
|
|
2936
|
+
}
|
|
2937
|
+
//#endregion
|
|
2523
2938
|
//#region src/tui/cwd-picker.tsx
|
|
2524
2939
|
const VISIBLE_ROWS$1 = 12;
|
|
2525
2940
|
const HOME = homedir();
|
|
@@ -2667,8 +3082,7 @@ function CwdPickerModal({ currentCwd, onPick }) {
|
|
|
2667
3082
|
start: 0,
|
|
2668
3083
|
slice: results
|
|
2669
3084
|
};
|
|
2670
|
-
|
|
2671
|
-
let start = Math.max(0, safeIndex - half);
|
|
3085
|
+
let start = Math.max(0, safeIndex - Math.floor(VISIBLE_ROWS$1 / 2));
|
|
2672
3086
|
if (start + VISIBLE_ROWS$1 > results.length) start = results.length - VISIBLE_ROWS$1;
|
|
2673
3087
|
return {
|
|
2674
3088
|
start,
|
|
@@ -3007,200 +3421,8 @@ function readToolsByServer(dataDir) {
|
|
|
3007
3421
|
return out;
|
|
3008
3422
|
}
|
|
3009
3423
|
//#endregion
|
|
3010
|
-
//#region src/tui/
|
|
3011
|
-
|
|
3012
|
-
{
|
|
3013
|
-
id: "off",
|
|
3014
|
-
description: "no reasoning — fastest, smallest output"
|
|
3015
|
-
},
|
|
3016
|
-
{
|
|
3017
|
-
id: "minimal",
|
|
3018
|
-
description: "tiny reasoning budget (gpt-5 family)"
|
|
3019
|
-
},
|
|
3020
|
-
{
|
|
3021
|
-
id: "low",
|
|
3022
|
-
description: "short reasoning pass"
|
|
3023
|
-
},
|
|
3024
|
-
{
|
|
3025
|
-
id: "medium",
|
|
3026
|
-
description: "balanced — sensible default"
|
|
3027
|
-
},
|
|
3028
|
-
{
|
|
3029
|
-
id: "high",
|
|
3030
|
-
description: "deep reasoning — slowest, longest"
|
|
3031
|
-
}
|
|
3032
|
-
];
|
|
3033
|
-
const ADAPTIVE_LEVEL = {
|
|
3034
|
-
id: "adaptive",
|
|
3035
|
-
description: "model decides per-turn (Anthropic)"
|
|
3036
|
-
};
|
|
3037
|
-
function EffortPickerModal({ current, supportsAdaptive, onPick }) {
|
|
3038
|
-
const COLOR = useColors();
|
|
3039
|
-
const SURFACE = useSurfaces();
|
|
3040
|
-
const inputRef = useRef(null);
|
|
3041
|
-
const [query, setQuery] = useState("");
|
|
3042
|
-
const levels = useMemo(() => {
|
|
3043
|
-
return (supportsAdaptive ? [...BASE_LEVELS, ADAPTIVE_LEVEL] : BASE_LEVELS).map((l) => ({
|
|
3044
|
-
...l,
|
|
3045
|
-
searchCorpus: `${l.id} ${l.description}`.toLowerCase()
|
|
3046
|
-
}));
|
|
3047
|
-
}, [supportsAdaptive]);
|
|
3048
|
-
const filtered = useMemo(() => {
|
|
3049
|
-
const trimmed = query.trim().toLowerCase();
|
|
3050
|
-
if (!trimmed) return levels;
|
|
3051
|
-
const terms = trimmed.split(/\s+/);
|
|
3052
|
-
return levels.filter((l) => terms.every((t) => l.searchCorpus.includes(t)));
|
|
3053
|
-
}, [levels, query]);
|
|
3054
|
-
const [selectedIdx, setSelectedIdx] = useState(() => {
|
|
3055
|
-
const idx = levels.findIndex((l) => l.id === current);
|
|
3056
|
-
if (idx >= 0) return idx;
|
|
3057
|
-
const fallback = levels.findIndex((l) => l.id === "medium");
|
|
3058
|
-
return fallback < 0 ? 0 : fallback;
|
|
3059
|
-
});
|
|
3060
|
-
const handleQueryChange = useCallback((next) => {
|
|
3061
|
-
setQuery(next);
|
|
3062
|
-
setSelectedIdx(0);
|
|
3063
|
-
}, []);
|
|
3064
|
-
const safeIndex = filtered.length === 0 ? 0 : Math.min(selectedIdx, filtered.length - 1);
|
|
3065
|
-
const commit = () => {
|
|
3066
|
-
const row = filtered[safeIndex];
|
|
3067
|
-
if (row) onPick(row.id);
|
|
3068
|
-
};
|
|
3069
|
-
useEffect(() => {
|
|
3070
|
-
inputRef.current?.focus();
|
|
3071
|
-
}, []);
|
|
3072
|
-
useKeyboard((key) => {
|
|
3073
|
-
if (key.name === "up") {
|
|
3074
|
-
setSelectedIdx((i) => {
|
|
3075
|
-
if (filtered.length === 0) return i;
|
|
3076
|
-
return ((i - 1) % filtered.length + filtered.length) % filtered.length;
|
|
3077
|
-
});
|
|
3078
|
-
return;
|
|
3079
|
-
}
|
|
3080
|
-
if (key.name === "down") {
|
|
3081
|
-
setSelectedIdx((i) => {
|
|
3082
|
-
if (filtered.length === 0) return i;
|
|
3083
|
-
return (i + 1) % filtered.length;
|
|
3084
|
-
});
|
|
3085
|
-
return;
|
|
3086
|
-
}
|
|
3087
|
-
if (key.name === "return") commit();
|
|
3088
|
-
});
|
|
3089
|
-
return /* @__PURE__ */ jsxs(Modal, {
|
|
3090
|
-
title: "select reasoning effort",
|
|
3091
|
-
maxWidth: 80,
|
|
3092
|
-
children: [
|
|
3093
|
-
/* @__PURE__ */ jsx("box", {
|
|
3094
|
-
style: {
|
|
3095
|
-
border: true,
|
|
3096
|
-
borderColor: COLOR.borderActive,
|
|
3097
|
-
paddingLeft: 1,
|
|
3098
|
-
paddingRight: 1,
|
|
3099
|
-
height: 3
|
|
3100
|
-
},
|
|
3101
|
-
children: /* @__PURE__ */ jsx("input", {
|
|
3102
|
-
ref: inputRef,
|
|
3103
|
-
focused: true,
|
|
3104
|
-
placeholder: "search effort levels…",
|
|
3105
|
-
onInput: handleQueryChange,
|
|
3106
|
-
onSubmit: () => {},
|
|
3107
|
-
style: { flexGrow: 1 }
|
|
3108
|
-
})
|
|
3109
|
-
}),
|
|
3110
|
-
/* @__PURE__ */ jsx("box", {
|
|
3111
|
-
style: {
|
|
3112
|
-
flexDirection: "column",
|
|
3113
|
-
flexShrink: 0
|
|
3114
|
-
},
|
|
3115
|
-
children: filtered.length === 0 ? /* @__PURE__ */ jsxs("text", {
|
|
3116
|
-
fg: COLOR.dim,
|
|
3117
|
-
children: [/* @__PURE__ */ jsx("span", {
|
|
3118
|
-
fg: COLOR.mute,
|
|
3119
|
-
children: "no levels match "
|
|
3120
|
-
}), /* @__PURE__ */ jsx("span", {
|
|
3121
|
-
fg: COLOR.warn,
|
|
3122
|
-
children: query.trim()
|
|
3123
|
-
})]
|
|
3124
|
-
}) : filtered.map((level, i) => /* @__PURE__ */ jsx(EffortRow, {
|
|
3125
|
-
level,
|
|
3126
|
-
isCurrent: level.id === current,
|
|
3127
|
-
isFocused: i === safeIndex,
|
|
3128
|
-
highlightBg: SURFACE.selection
|
|
3129
|
-
}, level.id))
|
|
3130
|
-
}),
|
|
3131
|
-
/* @__PURE__ */ jsxs("text", {
|
|
3132
|
-
fg: COLOR.dim,
|
|
3133
|
-
children: [
|
|
3134
|
-
/* @__PURE__ */ jsx("span", {
|
|
3135
|
-
fg: COLOR.warn,
|
|
3136
|
-
children: "↑↓"
|
|
3137
|
-
}),
|
|
3138
|
-
" navigate · ",
|
|
3139
|
-
/* @__PURE__ */ jsx("span", {
|
|
3140
|
-
fg: COLOR.warn,
|
|
3141
|
-
children: "↵"
|
|
3142
|
-
}),
|
|
3143
|
-
" select · ",
|
|
3144
|
-
/* @__PURE__ */ jsx("span", {
|
|
3145
|
-
fg: COLOR.warn,
|
|
3146
|
-
children: "esc"
|
|
3147
|
-
}),
|
|
3148
|
-
" close · ",
|
|
3149
|
-
/* @__PURE__ */ jsx("span", {
|
|
3150
|
-
fg: COLOR.mute,
|
|
3151
|
-
children: `${filtered.length} / ${levels.length} level${levels.length === 1 ? "" : "s"}`
|
|
3152
|
-
})
|
|
3153
|
-
]
|
|
3154
|
-
})
|
|
3155
|
-
]
|
|
3156
|
-
});
|
|
3157
|
-
}
|
|
3158
|
-
/**
|
|
3159
|
-
* Single row in the picker. Mirrors `ModelRow` in `model-picker.tsx`:
|
|
3160
|
-
* `●` marker for the current pick, single-space middle-dot separators,
|
|
3161
|
-
* focused row gets the `surfaces.selection` background lift.
|
|
3162
|
-
*/
|
|
3163
|
-
function EffortRow({ level, isCurrent, isFocused, highlightBg }) {
|
|
3164
|
-
const COLOR = useColors();
|
|
3165
|
-
const marker = isCurrent ? "●" : " ";
|
|
3166
|
-
return /* @__PURE__ */ jsx("box", {
|
|
3167
|
-
style: {
|
|
3168
|
-
height: 1,
|
|
3169
|
-
paddingLeft: 1,
|
|
3170
|
-
paddingRight: 1,
|
|
3171
|
-
flexShrink: 0,
|
|
3172
|
-
backgroundColor: isFocused ? highlightBg : void 0
|
|
3173
|
-
},
|
|
3174
|
-
children: /* @__PURE__ */ jsxs("text", {
|
|
3175
|
-
wrapMode: "none",
|
|
3176
|
-
children: [
|
|
3177
|
-
/* @__PURE__ */ jsx("span", {
|
|
3178
|
-
fg: isCurrent ? COLOR.brand : COLOR.mute,
|
|
3179
|
-
children: marker
|
|
3180
|
-
}),
|
|
3181
|
-
/* @__PURE__ */ jsx("span", {
|
|
3182
|
-
fg: COLOR.mute,
|
|
3183
|
-
children: " "
|
|
3184
|
-
}),
|
|
3185
|
-
/* @__PURE__ */ jsx("span", {
|
|
3186
|
-
fg: isFocused ? COLOR.brand : COLOR.dim,
|
|
3187
|
-
children: level.id
|
|
3188
|
-
}),
|
|
3189
|
-
/* @__PURE__ */ jsx("span", {
|
|
3190
|
-
fg: COLOR.mute,
|
|
3191
|
-
children: " · "
|
|
3192
|
-
}),
|
|
3193
|
-
/* @__PURE__ */ jsx("span", {
|
|
3194
|
-
fg: COLOR.mute,
|
|
3195
|
-
children: level.description
|
|
3196
|
-
})
|
|
3197
|
-
]
|
|
3198
|
-
})
|
|
3199
|
-
});
|
|
3200
|
-
}
|
|
3201
|
-
//#endregion
|
|
3202
|
-
//#region src/tui/keybindings-modal.tsx
|
|
3203
|
-
function KeybindingsModal({ bindings, filePath, onEditFile, onClose }) {
|
|
3424
|
+
//#region src/tui/keybindings-modal.tsx
|
|
3425
|
+
function KeybindingsModal({ bindings, filePath, onEditFile, onClose }) {
|
|
3204
3426
|
const SURFACE = useSurfaces();
|
|
3205
3427
|
const { height: termHeight } = useTerminalDimensions();
|
|
3206
3428
|
const scrollRef = useRef(null);
|
|
@@ -3251,7 +3473,7 @@ function KeybindingsCatalog({ sections }) {
|
|
|
3251
3473
|
flexShrink: 0,
|
|
3252
3474
|
marginTop: sectionIdx === 0 ? 0 : 1
|
|
3253
3475
|
},
|
|
3254
|
-
children: [/* @__PURE__ */ jsx(SectionHeader, { label: section.group }), section.rows.map((row) => /* @__PURE__ */ jsx(BindingRow, {
|
|
3476
|
+
children: [/* @__PURE__ */ jsx(SectionHeader$1, { label: section.group }), section.rows.map((row) => /* @__PURE__ */ jsx(BindingRow, {
|
|
3255
3477
|
def: row.def,
|
|
3256
3478
|
spec: row.spec
|
|
3257
3479
|
}, row.def.action))]
|
|
@@ -3308,7 +3530,7 @@ function KeybindingsEditFileButton({ filePath, highlightBg }) {
|
|
|
3308
3530
|
})]
|
|
3309
3531
|
});
|
|
3310
3532
|
}
|
|
3311
|
-
function SectionHeader({ label }) {
|
|
3533
|
+
function SectionHeader$1({ label }) {
|
|
3312
3534
|
return /* @__PURE__ */ jsx("box", {
|
|
3313
3535
|
style: {
|
|
3314
3536
|
flexShrink: 0,
|
|
@@ -3324,57 +3546,285 @@ function SectionHeader({ label }) {
|
|
|
3324
3546
|
})
|
|
3325
3547
|
});
|
|
3326
3548
|
}
|
|
3327
|
-
function BindingRow({ def, spec }) {
|
|
3549
|
+
function BindingRow({ def, spec }) {
|
|
3550
|
+
const COLOR = useColors();
|
|
3551
|
+
const display = formatBindingForDisplay(spec);
|
|
3552
|
+
const keyText = (display || "—").padEnd(KEYBINDING_KEY_COL_WIDTH, " ");
|
|
3553
|
+
return /* @__PURE__ */ jsxs("box", {
|
|
3554
|
+
style: {
|
|
3555
|
+
flexDirection: "column",
|
|
3556
|
+
flexShrink: 0,
|
|
3557
|
+
paddingLeft: 3,
|
|
3558
|
+
paddingRight: 1
|
|
3559
|
+
},
|
|
3560
|
+
children: [/* @__PURE__ */ jsxs("text", {
|
|
3561
|
+
wrapMode: "none",
|
|
3562
|
+
children: [/* @__PURE__ */ jsx("span", {
|
|
3563
|
+
fg: display ? COLOR.warn : COLOR.mute,
|
|
3564
|
+
children: keyText
|
|
3565
|
+
}), /* @__PURE__ */ jsx("span", {
|
|
3566
|
+
fg: COLOR.dim,
|
|
3567
|
+
children: def.label
|
|
3568
|
+
})]
|
|
3569
|
+
}), /* @__PURE__ */ jsx("box", {
|
|
3570
|
+
style: {
|
|
3571
|
+
flexShrink: 0,
|
|
3572
|
+
paddingLeft: KEYBINDING_KEY_COL_WIDTH
|
|
3573
|
+
},
|
|
3574
|
+
children: /* @__PURE__ */ jsx("text", {
|
|
3575
|
+
wrapMode: "word",
|
|
3576
|
+
fg: COLOR.mute,
|
|
3577
|
+
children: def.description
|
|
3578
|
+
})
|
|
3579
|
+
})]
|
|
3580
|
+
});
|
|
3581
|
+
}
|
|
3582
|
+
function CountsBadge$1({ count }) {
|
|
3583
|
+
const COLOR = useColors();
|
|
3584
|
+
return /* @__PURE__ */ jsxs("text", {
|
|
3585
|
+
wrapMode: "none",
|
|
3586
|
+
children: [
|
|
3587
|
+
/* @__PURE__ */ jsx("span", {
|
|
3588
|
+
fg: COLOR.mute,
|
|
3589
|
+
children: " "
|
|
3590
|
+
}),
|
|
3591
|
+
/* @__PURE__ */ jsx("span", {
|
|
3592
|
+
fg: COLOR.accent,
|
|
3593
|
+
children: String(count)
|
|
3594
|
+
}),
|
|
3595
|
+
/* @__PURE__ */ jsx("span", {
|
|
3596
|
+
fg: COLOR.mute,
|
|
3597
|
+
children: ` action${count === 1 ? "" : "s"} `
|
|
3598
|
+
})
|
|
3599
|
+
]
|
|
3600
|
+
});
|
|
3601
|
+
}
|
|
3602
|
+
//#endregion
|
|
3603
|
+
//#region src/tui/model-options-picker.tsx
|
|
3604
|
+
const BASE_LEVELS$1 = [
|
|
3605
|
+
{
|
|
3606
|
+
id: "off",
|
|
3607
|
+
description: "no reasoning — fastest, smallest output"
|
|
3608
|
+
},
|
|
3609
|
+
{
|
|
3610
|
+
id: "minimal",
|
|
3611
|
+
description: "tiny reasoning budget (gpt-5 family)"
|
|
3612
|
+
},
|
|
3613
|
+
{
|
|
3614
|
+
id: "low",
|
|
3615
|
+
description: "short reasoning pass"
|
|
3616
|
+
},
|
|
3617
|
+
{
|
|
3618
|
+
id: "medium",
|
|
3619
|
+
description: "balanced — sensible default"
|
|
3620
|
+
},
|
|
3621
|
+
{
|
|
3622
|
+
id: "high",
|
|
3623
|
+
description: "deep reasoning — slowest, longest"
|
|
3624
|
+
}
|
|
3625
|
+
];
|
|
3626
|
+
const ADAPTIVE_LEVEL$1 = {
|
|
3627
|
+
id: "adaptive",
|
|
3628
|
+
description: "model decides per-turn (Anthropic)"
|
|
3629
|
+
};
|
|
3630
|
+
function ModelOptionsPickerModal({ supportsReasoning, supportsAdaptive, currentEffort, options, enabled, onPickEffort, onToggleOption }) {
|
|
3631
|
+
const COLOR = useColors();
|
|
3632
|
+
const SURFACE = useSurfaces();
|
|
3633
|
+
const [selectedIdx, setSelectedIdx] = useState(0);
|
|
3634
|
+
const [localEnabled, setLocalEnabled] = useState(() => ({ ...enabled }));
|
|
3635
|
+
const handleToggle = (optionId) => {
|
|
3636
|
+
setLocalEnabled((prev) => ({
|
|
3637
|
+
...prev,
|
|
3638
|
+
[optionId]: !prev[optionId]
|
|
3639
|
+
}));
|
|
3640
|
+
onToggleOption(optionId);
|
|
3641
|
+
};
|
|
3642
|
+
const rows = useMemo(() => {
|
|
3643
|
+
const out = [];
|
|
3644
|
+
if (supportsReasoning) {
|
|
3645
|
+
const levels = supportsAdaptive ? [...BASE_LEVELS$1, ADAPTIVE_LEVEL$1] : BASE_LEVELS$1;
|
|
3646
|
+
for (const level of levels) out.push({
|
|
3647
|
+
kind: "effort",
|
|
3648
|
+
level
|
|
3649
|
+
});
|
|
3650
|
+
}
|
|
3651
|
+
for (const option of options) out.push({
|
|
3652
|
+
kind: "option",
|
|
3653
|
+
option
|
|
3654
|
+
});
|
|
3655
|
+
return out;
|
|
3656
|
+
}, [
|
|
3657
|
+
supportsReasoning,
|
|
3658
|
+
supportsAdaptive,
|
|
3659
|
+
options
|
|
3660
|
+
]);
|
|
3661
|
+
const safeIndex = rows.length === 0 ? 0 : Math.min(selectedIdx, rows.length - 1);
|
|
3662
|
+
const firstOptionIdx = rows.findIndex((r) => r.kind === "option");
|
|
3663
|
+
useKeyboard((key) => {
|
|
3664
|
+
if (key.name === "up") {
|
|
3665
|
+
setSelectedIdx((i) => rows.length === 0 ? i : ((i - 1) % rows.length + rows.length) % rows.length);
|
|
3666
|
+
return;
|
|
3667
|
+
}
|
|
3668
|
+
if (key.name === "down") {
|
|
3669
|
+
setSelectedIdx((i) => rows.length === 0 ? i : (i + 1) % rows.length);
|
|
3670
|
+
return;
|
|
3671
|
+
}
|
|
3672
|
+
if (key.name === "return" || key.name === "space") {
|
|
3673
|
+
const row = rows[safeIndex];
|
|
3674
|
+
if (!row) return;
|
|
3675
|
+
if (row.kind === "effort") onPickEffort(row.level.id);
|
|
3676
|
+
else handleToggle(row.option.id);
|
|
3677
|
+
}
|
|
3678
|
+
});
|
|
3679
|
+
return /* @__PURE__ */ jsxs(Modal, {
|
|
3680
|
+
title: "model options",
|
|
3681
|
+
maxWidth: 80,
|
|
3682
|
+
children: [/* @__PURE__ */ jsxs("box", {
|
|
3683
|
+
style: {
|
|
3684
|
+
flexDirection: "column",
|
|
3685
|
+
flexShrink: 0
|
|
3686
|
+
},
|
|
3687
|
+
children: [supportsReasoning && /* @__PURE__ */ jsx(SectionHeader, {
|
|
3688
|
+
label: "reasoning effort",
|
|
3689
|
+
color: COLOR.mute
|
|
3690
|
+
}), rows.map((row, i) => {
|
|
3691
|
+
const isFocused = i === safeIndex;
|
|
3692
|
+
if (row.kind === "effort") return /* @__PURE__ */ jsx(EffortRow$1, {
|
|
3693
|
+
level: row.level,
|
|
3694
|
+
isCurrent: row.level.id === currentEffort,
|
|
3695
|
+
isFocused,
|
|
3696
|
+
highlightBg: SURFACE.selection
|
|
3697
|
+
}, `effort:${row.level.id}`);
|
|
3698
|
+
return /* @__PURE__ */ jsxs("box", {
|
|
3699
|
+
style: {
|
|
3700
|
+
flexDirection: "column",
|
|
3701
|
+
flexShrink: 0
|
|
3702
|
+
},
|
|
3703
|
+
children: [i === firstOptionIdx && /* @__PURE__ */ jsxs(Fragment, { children: [supportsReasoning && /* @__PURE__ */ jsx("box", { style: {
|
|
3704
|
+
height: 1,
|
|
3705
|
+
flexShrink: 0
|
|
3706
|
+
} }), /* @__PURE__ */ jsx(SectionHeader, {
|
|
3707
|
+
label: "features",
|
|
3708
|
+
color: COLOR.mute
|
|
3709
|
+
})] }), /* @__PURE__ */ jsx(OptionRow, {
|
|
3710
|
+
option: row.option,
|
|
3711
|
+
isEnabled: localEnabled[row.option.id] === true,
|
|
3712
|
+
isFocused,
|
|
3713
|
+
highlightBg: SURFACE.selection
|
|
3714
|
+
})]
|
|
3715
|
+
}, `option:${row.option.id}`);
|
|
3716
|
+
})]
|
|
3717
|
+
}), /* @__PURE__ */ jsxs("text", {
|
|
3718
|
+
fg: COLOR.dim,
|
|
3719
|
+
children: [
|
|
3720
|
+
/* @__PURE__ */ jsx("span", {
|
|
3721
|
+
fg: COLOR.warn,
|
|
3722
|
+
children: "↑↓"
|
|
3723
|
+
}),
|
|
3724
|
+
" navigate · ",
|
|
3725
|
+
/* @__PURE__ */ jsx("span", {
|
|
3726
|
+
fg: COLOR.warn,
|
|
3727
|
+
children: "↵/space"
|
|
3728
|
+
}),
|
|
3729
|
+
" select/toggle · ",
|
|
3730
|
+
/* @__PURE__ */ jsx("span", {
|
|
3731
|
+
fg: COLOR.warn,
|
|
3732
|
+
children: "esc"
|
|
3733
|
+
}),
|
|
3734
|
+
" close"
|
|
3735
|
+
]
|
|
3736
|
+
})]
|
|
3737
|
+
});
|
|
3738
|
+
}
|
|
3739
|
+
function SectionHeader({ label, color }) {
|
|
3740
|
+
return /* @__PURE__ */ jsx("box", {
|
|
3741
|
+
style: {
|
|
3742
|
+
height: 1,
|
|
3743
|
+
paddingLeft: 1,
|
|
3744
|
+
flexShrink: 0
|
|
3745
|
+
},
|
|
3746
|
+
children: /* @__PURE__ */ jsx("text", {
|
|
3747
|
+
wrapMode: "none",
|
|
3748
|
+
children: /* @__PURE__ */ jsx("span", {
|
|
3749
|
+
fg: color,
|
|
3750
|
+
children: label
|
|
3751
|
+
})
|
|
3752
|
+
})
|
|
3753
|
+
});
|
|
3754
|
+
}
|
|
3755
|
+
function EffortRow$1({ level, isCurrent, isFocused, highlightBg }) {
|
|
3756
|
+
const COLOR = useColors();
|
|
3757
|
+
const marker = isCurrent ? "●" : " ";
|
|
3758
|
+
return /* @__PURE__ */ jsx("box", {
|
|
3759
|
+
style: {
|
|
3760
|
+
height: 1,
|
|
3761
|
+
paddingLeft: 1,
|
|
3762
|
+
paddingRight: 1,
|
|
3763
|
+
flexShrink: 0,
|
|
3764
|
+
backgroundColor: isFocused ? highlightBg : void 0
|
|
3765
|
+
},
|
|
3766
|
+
children: /* @__PURE__ */ jsxs("text", {
|
|
3767
|
+
wrapMode: "none",
|
|
3768
|
+
children: [
|
|
3769
|
+
/* @__PURE__ */ jsx("span", {
|
|
3770
|
+
fg: isCurrent ? COLOR.brand : COLOR.mute,
|
|
3771
|
+
children: marker
|
|
3772
|
+
}),
|
|
3773
|
+
/* @__PURE__ */ jsx("span", {
|
|
3774
|
+
fg: COLOR.mute,
|
|
3775
|
+
children: " "
|
|
3776
|
+
}),
|
|
3777
|
+
/* @__PURE__ */ jsx("span", {
|
|
3778
|
+
fg: isFocused ? COLOR.brand : COLOR.dim,
|
|
3779
|
+
children: level.id
|
|
3780
|
+
}),
|
|
3781
|
+
/* @__PURE__ */ jsx("span", {
|
|
3782
|
+
fg: COLOR.mute,
|
|
3783
|
+
children: " · "
|
|
3784
|
+
}),
|
|
3785
|
+
/* @__PURE__ */ jsx("span", {
|
|
3786
|
+
fg: COLOR.mute,
|
|
3787
|
+
children: level.description
|
|
3788
|
+
})
|
|
3789
|
+
]
|
|
3790
|
+
})
|
|
3791
|
+
});
|
|
3792
|
+
}
|
|
3793
|
+
function OptionRow({ option, isEnabled, isFocused, highlightBg }) {
|
|
3328
3794
|
const COLOR = useColors();
|
|
3329
|
-
const
|
|
3330
|
-
|
|
3331
|
-
return /* @__PURE__ */ jsxs("box", {
|
|
3795
|
+
const marker = isEnabled ? "[x]" : "[ ]";
|
|
3796
|
+
return /* @__PURE__ */ jsx("box", {
|
|
3332
3797
|
style: {
|
|
3333
|
-
|
|
3798
|
+
height: 1,
|
|
3799
|
+
paddingLeft: 1,
|
|
3800
|
+
paddingRight: 1,
|
|
3334
3801
|
flexShrink: 0,
|
|
3335
|
-
|
|
3336
|
-
paddingRight: 1
|
|
3802
|
+
backgroundColor: isFocused ? highlightBg : void 0
|
|
3337
3803
|
},
|
|
3338
|
-
children:
|
|
3804
|
+
children: /* @__PURE__ */ jsxs("text", {
|
|
3339
3805
|
wrapMode: "none",
|
|
3340
|
-
children: [
|
|
3341
|
-
|
|
3342
|
-
|
|
3343
|
-
|
|
3344
|
-
|
|
3345
|
-
|
|
3346
|
-
|
|
3347
|
-
|
|
3348
|
-
|
|
3349
|
-
|
|
3350
|
-
|
|
3351
|
-
|
|
3352
|
-
|
|
3353
|
-
|
|
3354
|
-
|
|
3355
|
-
|
|
3356
|
-
|
|
3357
|
-
|
|
3358
|
-
|
|
3359
|
-
}
|
|
3360
|
-
|
|
3361
|
-
|
|
3362
|
-
return /* @__PURE__ */ jsxs("text", {
|
|
3363
|
-
wrapMode: "none",
|
|
3364
|
-
children: [
|
|
3365
|
-
/* @__PURE__ */ jsx("span", {
|
|
3366
|
-
fg: COLOR.mute,
|
|
3367
|
-
children: " "
|
|
3368
|
-
}),
|
|
3369
|
-
/* @__PURE__ */ jsx("span", {
|
|
3370
|
-
fg: COLOR.accent,
|
|
3371
|
-
children: String(count)
|
|
3372
|
-
}),
|
|
3373
|
-
/* @__PURE__ */ jsx("span", {
|
|
3374
|
-
fg: COLOR.mute,
|
|
3375
|
-
children: ` action${count === 1 ? "" : "s"} `
|
|
3376
|
-
})
|
|
3377
|
-
]
|
|
3806
|
+
children: [
|
|
3807
|
+
/* @__PURE__ */ jsx("span", {
|
|
3808
|
+
fg: isEnabled ? COLOR.brand : COLOR.mute,
|
|
3809
|
+
children: marker
|
|
3810
|
+
}),
|
|
3811
|
+
/* @__PURE__ */ jsx("span", {
|
|
3812
|
+
fg: COLOR.mute,
|
|
3813
|
+
children: " "
|
|
3814
|
+
}),
|
|
3815
|
+
/* @__PURE__ */ jsx("span", {
|
|
3816
|
+
fg: isFocused ? COLOR.brand : COLOR.dim,
|
|
3817
|
+
children: option.label
|
|
3818
|
+
}),
|
|
3819
|
+
option.description ? /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("span", {
|
|
3820
|
+
fg: COLOR.mute,
|
|
3821
|
+
children: " · "
|
|
3822
|
+
}), /* @__PURE__ */ jsx("span", {
|
|
3823
|
+
fg: COLOR.mute,
|
|
3824
|
+
children: option.description
|
|
3825
|
+
})] }) : null
|
|
3826
|
+
]
|
|
3827
|
+
})
|
|
3378
3828
|
});
|
|
3379
3829
|
}
|
|
3380
3830
|
//#endregion
|
|
@@ -3442,8 +3892,7 @@ function ModelPickerModal({ providers, modelsFor, current, onPick }) {
|
|
|
3442
3892
|
start: 0,
|
|
3443
3893
|
slice: filtered
|
|
3444
3894
|
};
|
|
3445
|
-
|
|
3446
|
-
let start = Math.max(0, safeIndex - half);
|
|
3895
|
+
let start = Math.max(0, safeIndex - Math.floor(VISIBLE_ROWS / 2));
|
|
3447
3896
|
if (start + VISIBLE_ROWS > filtered.length) start = filtered.length - VISIBLE_ROWS;
|
|
3448
3897
|
return {
|
|
3449
3898
|
start,
|
|
@@ -4525,23 +4974,25 @@ function snippet(s) {
|
|
|
4525
4974
|
}
|
|
4526
4975
|
//#endregion
|
|
4527
4976
|
//#region src/tui/interaction-block.tsx
|
|
4528
|
-
const COMMENT_TEXTAREA_BINDINGS =
|
|
4529
|
-
|
|
4530
|
-
|
|
4531
|
-
|
|
4532
|
-
|
|
4533
|
-
|
|
4534
|
-
|
|
4535
|
-
|
|
4536
|
-
|
|
4537
|
-
|
|
4538
|
-
|
|
4539
|
-
|
|
4540
|
-
|
|
4541
|
-
|
|
4542
|
-
|
|
4543
|
-
|
|
4544
|
-
|
|
4977
|
+
const COMMENT_TEXTAREA_BINDINGS = (() => {
|
|
4978
|
+
return [
|
|
4979
|
+
...defaultTextareaKeyBindings.filter((b) => b.name !== "return" && !(b.name === "a" && b.ctrl && !b.shift && !b.meta)),
|
|
4980
|
+
{
|
|
4981
|
+
name: "a",
|
|
4982
|
+
ctrl: true,
|
|
4983
|
+
action: "select-all"
|
|
4984
|
+
},
|
|
4985
|
+
{
|
|
4986
|
+
name: "return",
|
|
4987
|
+
action: "submit"
|
|
4988
|
+
},
|
|
4989
|
+
{
|
|
4990
|
+
name: "return",
|
|
4991
|
+
shift: true,
|
|
4992
|
+
action: "newline"
|
|
4993
|
+
}
|
|
4994
|
+
];
|
|
4995
|
+
})();
|
|
4545
4996
|
/**
|
|
4546
4997
|
* InteractionBlock — picker UI for `present_plan` and `ask_user` tool calls.
|
|
4547
4998
|
*
|
|
@@ -5615,13 +6066,7 @@ const API_KEY_INPUT_BINDINGS = makeSubmitBindings(false);
|
|
|
5615
6066
|
function findByKey(items, value) {
|
|
5616
6067
|
return typeof value === "string" ? items.find((i) => i.key === value) : void 0;
|
|
5617
6068
|
}
|
|
5618
|
-
|
|
5619
|
-
* Sentinel value used by the picker's "+ add / re-configure" option. Lives
|
|
5620
|
-
* outside the provider key namespace (key strings are at least one char, no
|
|
5621
|
-
* leading `__`) so we can't collide with a real registry entry.
|
|
5622
|
-
*/
|
|
5623
|
-
const WIZARD_OPTION_VALUE = "__wizard__";
|
|
5624
|
-
function AuthScreen({ onPick }) {
|
|
6069
|
+
function AuthScreen({ onPick, initialConfigureKey }) {
|
|
5625
6070
|
const config = useConfig();
|
|
5626
6071
|
const { providers: registry } = config;
|
|
5627
6072
|
const focused = useModalAwareFocus();
|
|
@@ -5632,30 +6077,48 @@ function AuthScreen({ onPick }) {
|
|
|
5632
6077
|
useEffect(() => {
|
|
5633
6078
|
refresh();
|
|
5634
6079
|
}, [refresh]);
|
|
5635
|
-
const [
|
|
6080
|
+
const [configuring, setConfiguring] = useState(() => initialConfigureKey ? registry[initialConfigureKey] ?? null : null);
|
|
5636
6081
|
const available = useMemo(() => providers.filter((p) => p.available), [providers]);
|
|
5637
|
-
const onWizardDone = useCallback(() => {
|
|
5638
|
-
|
|
5639
|
-
|
|
5640
|
-
|
|
5641
|
-
|
|
5642
|
-
|
|
5643
|
-
|
|
5644
|
-
|
|
5645
|
-
|
|
5646
|
-
|
|
5647
|
-
|
|
5648
|
-
|
|
5649
|
-
|
|
6082
|
+
const onWizardDone = useCallback((descriptorKey) => {
|
|
6083
|
+
setConfiguring(null);
|
|
6084
|
+
const detected = detectAuth(config.paths.userDir, registry);
|
|
6085
|
+
setProviders(detected);
|
|
6086
|
+
const configured = detected.find((p) => p.key === descriptorKey);
|
|
6087
|
+
if (configured?.available) onPick(configured);
|
|
6088
|
+
}, [
|
|
6089
|
+
config.paths.userDir,
|
|
6090
|
+
registry,
|
|
6091
|
+
onPick
|
|
6092
|
+
]);
|
|
6093
|
+
const onSelectProvider = useCallback((p) => {
|
|
6094
|
+
if (p.available) {
|
|
6095
|
+
onPick(p);
|
|
6096
|
+
return;
|
|
6097
|
+
}
|
|
6098
|
+
const descriptor = registry[p.key];
|
|
6099
|
+
if (descriptor) setConfiguring(descriptor);
|
|
6100
|
+
}, [registry, onPick]);
|
|
6101
|
+
if (configuring) return /* @__PURE__ */ jsx(SetupWizard, {
|
|
6102
|
+
registry,
|
|
6103
|
+
dataDir: config.paths.userDir,
|
|
6104
|
+
initialDescriptor: configuring,
|
|
6105
|
+
onConfigured: onWizardDone,
|
|
6106
|
+
onCancel: available.length > 0 ? () => setConfiguring(null) : void 0
|
|
6107
|
+
});
|
|
6108
|
+
if (available.length === 0) return /* @__PURE__ */ jsx(SetupWizard, {
|
|
6109
|
+
registry,
|
|
6110
|
+
dataDir: config.paths.userDir,
|
|
6111
|
+
onConfigured: onWizardDone
|
|
6112
|
+
});
|
|
5650
6113
|
const options = [...available.map((p) => ({
|
|
5651
6114
|
name: p.label,
|
|
5652
6115
|
description: p.methods.map((m) => m.detail).join(" · "),
|
|
5653
6116
|
value: p.key
|
|
5654
|
-
})), {
|
|
5655
|
-
name:
|
|
5656
|
-
description: "
|
|
5657
|
-
value:
|
|
5658
|
-
}];
|
|
6117
|
+
})), ...providers.filter((p) => !p.available).map((p) => ({
|
|
6118
|
+
name: p.label,
|
|
6119
|
+
description: "not configured — press ↵ to set up",
|
|
6120
|
+
value: p.key
|
|
6121
|
+
}))];
|
|
5659
6122
|
return /* @__PURE__ */ jsxs("box", {
|
|
5660
6123
|
style: {
|
|
5661
6124
|
flexDirection: "column",
|
|
@@ -5676,57 +6139,114 @@ function AuthScreen({ onPick }) {
|
|
|
5676
6139
|
wrapSelection: true,
|
|
5677
6140
|
onSelect: (_idx, option) => {
|
|
5678
6141
|
if (!option) return;
|
|
5679
|
-
|
|
5680
|
-
|
|
5681
|
-
return;
|
|
5682
|
-
}
|
|
5683
|
-
const provider = findByKey(available, option.value);
|
|
5684
|
-
if (provider) onPick(provider);
|
|
6142
|
+
const provider = findByKey(providers, option.value);
|
|
6143
|
+
if (provider) onSelectProvider(provider);
|
|
5685
6144
|
},
|
|
5686
6145
|
style: { flexGrow: 1 }
|
|
5687
6146
|
})
|
|
5688
6147
|
}), /* @__PURE__ */ jsx(TitleOverlay, { title: "pick a provider" })]
|
|
5689
6148
|
});
|
|
5690
6149
|
}
|
|
5691
|
-
|
|
5692
|
-
|
|
6150
|
+
/**
|
|
6151
|
+
* First credential step for a chosen provider. The method picker only earns
|
|
6152
|
+
* its place when there's a genuine choice — i.e. the provider supports OAuth
|
|
6153
|
+
* in addition to an API key. For API-key-only providers (e.g. `local`,
|
|
6154
|
+
* Cerebras), it's a single-option screen, so we skip it and go straight to the
|
|
6155
|
+
* customFields form / API-key input.
|
|
6156
|
+
*/
|
|
6157
|
+
function firstCredentialStep(descriptor) {
|
|
6158
|
+
if (supportsOAuth(descriptor)) return {
|
|
6159
|
+
kind: "pick-method",
|
|
6160
|
+
descriptor
|
|
6161
|
+
};
|
|
6162
|
+
if (descriptor.customFields && descriptor.customFields.length > 0) return {
|
|
6163
|
+
kind: "enter-custom-fields",
|
|
6164
|
+
descriptor
|
|
6165
|
+
};
|
|
6166
|
+
return {
|
|
6167
|
+
kind: "enter-apikey",
|
|
6168
|
+
descriptor,
|
|
6169
|
+
customFields: {}
|
|
6170
|
+
};
|
|
6171
|
+
}
|
|
6172
|
+
function SetupWizard({ registry, dataDir, initialDescriptor, onConfigured, onCancel }) {
|
|
6173
|
+
const [step, setStep] = useState(initialDescriptor ? firstCredentialStep(initialDescriptor) : { kind: "pick-provider" });
|
|
5693
6174
|
const [error, setError] = useState(null);
|
|
5694
6175
|
const descriptors = useMemo(() => Object.values(registry), [registry]);
|
|
5695
6176
|
const onPickProvider = useCallback((descriptor) => {
|
|
5696
6177
|
setError(null);
|
|
5697
|
-
setStep(
|
|
5698
|
-
kind: "pick-method",
|
|
5699
|
-
descriptor
|
|
5700
|
-
});
|
|
6178
|
+
setStep(firstCredentialStep(descriptor));
|
|
5701
6179
|
}, []);
|
|
5702
6180
|
const onPickMethod = useCallback((descriptor, method) => {
|
|
5703
6181
|
setError(null);
|
|
5704
|
-
if (method === "apikey") setStep({
|
|
5705
|
-
kind: "enter-
|
|
6182
|
+
if (method === "apikey") if (descriptor.customFields && descriptor.customFields.length > 0) setStep({
|
|
6183
|
+
kind: "enter-custom-fields",
|
|
5706
6184
|
descriptor
|
|
5707
6185
|
});
|
|
6186
|
+
else setStep({
|
|
6187
|
+
kind: "enter-apikey",
|
|
6188
|
+
descriptor,
|
|
6189
|
+
customFields: {}
|
|
6190
|
+
});
|
|
5708
6191
|
else setStep({
|
|
5709
6192
|
kind: "oauth-running",
|
|
5710
6193
|
descriptor
|
|
5711
6194
|
});
|
|
5712
6195
|
}, []);
|
|
5713
|
-
|
|
5714
|
-
|
|
5715
|
-
|
|
5716
|
-
|
|
5717
|
-
|
|
5718
|
-
|
|
6196
|
+
/**
|
|
6197
|
+
* Single write path for any wizard outcome that produces an apikey credential.
|
|
6198
|
+
* Centralizes credential persistence + env-var mirroring so the customFields,
|
|
6199
|
+
* API-key, and customFields-only flows can't drift out of sync.
|
|
6200
|
+
*
|
|
6201
|
+
* Env mirroring stays in lockstep with `applyApiKeyEnv`: anything we store
|
|
6202
|
+
* here is what that function would put back on the next launch, so the
|
|
6203
|
+
* in-process env reflects the on-disk truth.
|
|
6204
|
+
*/
|
|
6205
|
+
const saveApiKeyCredential = useCallback((descriptor, apiKey, customFields) => {
|
|
5719
6206
|
try {
|
|
5720
6207
|
setProviderCredential(dataDir, descriptor, {
|
|
5721
6208
|
kind: "apikey",
|
|
5722
|
-
value:
|
|
6209
|
+
value: apiKey,
|
|
6210
|
+
...Object.keys(customFields).length > 0 ? { customFields } : {}
|
|
5723
6211
|
});
|
|
5724
|
-
if (descriptor.envKey) process.env[descriptor.envKey] =
|
|
5725
|
-
|
|
6212
|
+
if (descriptor.envKey && apiKey) process.env[descriptor.envKey] = apiKey;
|
|
6213
|
+
for (const field of descriptor.customFields ?? []) {
|
|
6214
|
+
const v = customFields[field.key];
|
|
6215
|
+
if (typeof v === "string" && v.length > 0) process.env[field.envVar] = v;
|
|
6216
|
+
}
|
|
6217
|
+
onConfigured(descriptor.key);
|
|
5726
6218
|
} catch (err) {
|
|
5727
6219
|
setError(errorMessage(err));
|
|
5728
6220
|
}
|
|
5729
6221
|
}, [dataDir, onConfigured]);
|
|
6222
|
+
const onCustomFieldsSubmit = useCallback((descriptor, values) => {
|
|
6223
|
+
const fields = descriptor.customFields ?? [];
|
|
6224
|
+
const missing = fields.find((f) => f.required && !values[f.key]?.trim());
|
|
6225
|
+
if (missing) {
|
|
6226
|
+
setError(`${missing.label} is required.`);
|
|
6227
|
+
return;
|
|
6228
|
+
}
|
|
6229
|
+
setError(null);
|
|
6230
|
+
const collected = {};
|
|
6231
|
+
for (const field of fields) {
|
|
6232
|
+
const v = values[field.key]?.trim();
|
|
6233
|
+
if (v) collected[field.key] = v;
|
|
6234
|
+
}
|
|
6235
|
+
if (descriptor.envKey) setStep({
|
|
6236
|
+
kind: "enter-apikey",
|
|
6237
|
+
descriptor,
|
|
6238
|
+
customFields: collected
|
|
6239
|
+
});
|
|
6240
|
+
else saveApiKeyCredential(descriptor, "", collected);
|
|
6241
|
+
}, [saveApiKeyCredential]);
|
|
6242
|
+
const onApiKeySubmit = useCallback((descriptor, customFields, value) => {
|
|
6243
|
+
const trimmed = value.trim();
|
|
6244
|
+
if (!trimmed) {
|
|
6245
|
+
setError("API key cannot be empty.");
|
|
6246
|
+
return;
|
|
6247
|
+
}
|
|
6248
|
+
saveApiKeyCredential(descriptor, trimmed, customFields);
|
|
6249
|
+
}, [saveApiKeyCredential]);
|
|
5730
6250
|
const onOAuthError = useCallback((msg) => {
|
|
5731
6251
|
setError(msg);
|
|
5732
6252
|
setStep((prev) => prev.kind === "oauth-running" ? {
|
|
@@ -5734,6 +6254,12 @@ function SetupWizard({ registry, dataDir, onConfigured, onCancel }) {
|
|
|
5734
6254
|
descriptor: prev.descriptor
|
|
5735
6255
|
} : prev);
|
|
5736
6256
|
}, []);
|
|
6257
|
+
const oauthDescriptorRef = useRef(null);
|
|
6258
|
+
oauthDescriptorRef.current = step.kind === "oauth-running" ? step.descriptor : oauthDescriptorRef.current;
|
|
6259
|
+
const onOAuthSuccess = useCallback(() => {
|
|
6260
|
+
const key = oauthDescriptorRef.current?.key;
|
|
6261
|
+
if (key) onConfigured(key);
|
|
6262
|
+
}, [onConfigured]);
|
|
5737
6263
|
if (descriptors.length === 0) return /* @__PURE__ */ jsx(EmptyRegistryNotice, {});
|
|
5738
6264
|
if (step.kind === "pick-provider") return /* @__PURE__ */ jsx(PickProviderStep, {
|
|
5739
6265
|
descriptors,
|
|
@@ -5746,15 +6272,21 @@ function SetupWizard({ registry, dataDir, onConfigured, onCancel }) {
|
|
|
5746
6272
|
error,
|
|
5747
6273
|
onPick: onPickMethod
|
|
5748
6274
|
});
|
|
6275
|
+
if (step.kind === "enter-custom-fields") return /* @__PURE__ */ jsx(EnterCustomFieldsStep, {
|
|
6276
|
+
descriptor: step.descriptor,
|
|
6277
|
+
error,
|
|
6278
|
+
onSubmit: onCustomFieldsSubmit
|
|
6279
|
+
});
|
|
5749
6280
|
if (step.kind === "enter-apikey") return /* @__PURE__ */ jsx(EnterApiKeyStep, {
|
|
5750
6281
|
descriptor: step.descriptor,
|
|
6282
|
+
customFields: step.customFields,
|
|
5751
6283
|
error,
|
|
5752
6284
|
onSubmit: onApiKeySubmit
|
|
5753
6285
|
});
|
|
5754
6286
|
return /* @__PURE__ */ jsx(OAuthRunningStep, {
|
|
5755
6287
|
descriptor: step.descriptor,
|
|
5756
6288
|
dataDir,
|
|
5757
|
-
onSuccess:
|
|
6289
|
+
onSuccess: onOAuthSuccess,
|
|
5758
6290
|
onError: onOAuthError
|
|
5759
6291
|
});
|
|
5760
6292
|
}
|
|
@@ -5802,6 +6334,15 @@ function WizardEscHint() {
|
|
|
5802
6334
|
children: "esc to exit"
|
|
5803
6335
|
});
|
|
5804
6336
|
}
|
|
6337
|
+
/**
|
|
6338
|
+
* Defensive: older descriptor hints ended with a dangling "… Press" (the
|
|
6339
|
+
* one-field-at-a-time wizard appended " enter to continue"). The multi-field
|
|
6340
|
+
* form renders the hint standalone, so trim a trailing "Press" / "press"
|
|
6341
|
+
* (with optional period) to avoid a hanging word. No-op for clean hints.
|
|
6342
|
+
*/
|
|
6343
|
+
function stripTrailingPressHint(hint) {
|
|
6344
|
+
return hint.replace(/\s*press\.?\s*$/i, "");
|
|
6345
|
+
}
|
|
5805
6346
|
function EmptyRegistryNotice() {
|
|
5806
6347
|
const COLOR = useColors();
|
|
5807
6348
|
return /* @__PURE__ */ jsxs(WizardPanel, {
|
|
@@ -5881,9 +6422,23 @@ function PickMethodStep({ descriptor, error, onPick }) {
|
|
|
5881
6422
|
const focused = useModalAwareFocus();
|
|
5882
6423
|
const SELECT_THEME = useSelectStyle();
|
|
5883
6424
|
const options = useMemo(() => {
|
|
6425
|
+
const hasCustomFields = (descriptor.customFields?.length ?? 0) > 0;
|
|
6426
|
+
const hasEnvKey = !!descriptor.envKey;
|
|
6427
|
+
let apikeyName;
|
|
6428
|
+
let apikeyDescription;
|
|
6429
|
+
if (!hasEnvKey && hasCustomFields) {
|
|
6430
|
+
apikeyName = "Configure";
|
|
6431
|
+
apikeyDescription = `configure ${descriptor.label} (no API key required)`;
|
|
6432
|
+
} else if (hasEnvKey && hasCustomFields) {
|
|
6433
|
+
apikeyName = "API key";
|
|
6434
|
+
apikeyDescription = `configure & paste your ${descriptor.label} API key`;
|
|
6435
|
+
} else {
|
|
6436
|
+
apikeyName = "API key";
|
|
6437
|
+
apikeyDescription = `paste your ${descriptor.label} API key`;
|
|
6438
|
+
}
|
|
5884
6439
|
const items = [{
|
|
5885
|
-
name:
|
|
5886
|
-
description:
|
|
6440
|
+
name: apikeyName,
|
|
6441
|
+
description: apikeyDescription,
|
|
5887
6442
|
value: "apikey"
|
|
5888
6443
|
}];
|
|
5889
6444
|
if (supportsOAuth(descriptor)) {
|
|
@@ -5911,13 +6466,139 @@ function PickMethodStep({ descriptor, error, onPick }) {
|
|
|
5911
6466
|
})]
|
|
5912
6467
|
});
|
|
5913
6468
|
}
|
|
5914
|
-
|
|
6469
|
+
/**
|
|
6470
|
+
* Multi-field form for {@link ProviderDescriptor.customFields}. All fields
|
|
6471
|
+
* render on a single page as a stack of inputs; the user moves between them
|
|
6472
|
+
* with ↑/↓ (or tab / shift-tab) and edits any value freely before submitting.
|
|
6473
|
+
* A trailing "save" row submits the whole form.
|
|
6474
|
+
*
|
|
6475
|
+
* Each `<input>` owns its own buffer (none are unmounted while navigating), so
|
|
6476
|
+
* returning to an earlier field shows what was already typed. Required fields
|
|
6477
|
+
* are validated on submit; the first missing one focuses + reports inline.
|
|
6478
|
+
*/
|
|
6479
|
+
function EnterCustomFieldsStep({ descriptor, error, onSubmit }) {
|
|
6480
|
+
const screenFocused = useModalAwareFocus();
|
|
6481
|
+
const COLOR = useColors();
|
|
6482
|
+
const fields = useMemo(() => descriptor.customFields ?? [], [descriptor]);
|
|
6483
|
+
const inputRefs = useRef([]);
|
|
6484
|
+
const SAVE_ROW = fields.length;
|
|
6485
|
+
const [focusedRow, setFocusedRow] = useState(0);
|
|
6486
|
+
const collectValues = useCallback(() => {
|
|
6487
|
+
const values = {};
|
|
6488
|
+
fields.forEach((field, i) => {
|
|
6489
|
+
values[field.key] = inputRefs.current[i]?.value ?? "";
|
|
6490
|
+
});
|
|
6491
|
+
return values;
|
|
6492
|
+
}, [fields]);
|
|
6493
|
+
const submit = useCallback(() => {
|
|
6494
|
+
const values = collectValues();
|
|
6495
|
+
const missingIdx = fields.findIndex((f) => f.required && !values[f.key]?.trim());
|
|
6496
|
+
if (missingIdx >= 0) {
|
|
6497
|
+
setFocusedRow(missingIdx);
|
|
6498
|
+
onSubmit(descriptor, values);
|
|
6499
|
+
return;
|
|
6500
|
+
}
|
|
6501
|
+
onSubmit(descriptor, values);
|
|
6502
|
+
}, [
|
|
6503
|
+
descriptor,
|
|
6504
|
+
fields,
|
|
6505
|
+
collectValues,
|
|
6506
|
+
onSubmit
|
|
6507
|
+
]);
|
|
6508
|
+
const move = useCallback((delta) => {
|
|
6509
|
+
setFocusedRow((prev) => {
|
|
6510
|
+
const next = prev + delta;
|
|
6511
|
+
if (next < 0) return 0;
|
|
6512
|
+
if (next > SAVE_ROW) return SAVE_ROW;
|
|
6513
|
+
return next;
|
|
6514
|
+
});
|
|
6515
|
+
}, [SAVE_ROW]);
|
|
6516
|
+
useKeyboard((key) => {
|
|
6517
|
+
if (!screenFocused) return;
|
|
6518
|
+
if (key.name === "up" || key.name === "tab" && key.shift) {
|
|
6519
|
+
move(-1);
|
|
6520
|
+
return;
|
|
6521
|
+
}
|
|
6522
|
+
if (key.name === "down" || key.name === "tab" && !key.shift) {
|
|
6523
|
+
move(1);
|
|
6524
|
+
return;
|
|
6525
|
+
}
|
|
6526
|
+
if (key.name === "return") if (focusedRow >= SAVE_ROW) submit();
|
|
6527
|
+
else move(1);
|
|
6528
|
+
});
|
|
6529
|
+
return /* @__PURE__ */ jsxs(WizardPanel, {
|
|
6530
|
+
title: `configure ${descriptor.label}`,
|
|
6531
|
+
error,
|
|
6532
|
+
children: [
|
|
6533
|
+
/* @__PURE__ */ jsxs("text", {
|
|
6534
|
+
fg: COLOR.dim,
|
|
6535
|
+
children: [
|
|
6536
|
+
/* @__PURE__ */ jsx("span", {
|
|
6537
|
+
fg: COLOR.model,
|
|
6538
|
+
children: "↑/↓"
|
|
6539
|
+
}),
|
|
6540
|
+
" to move between fields · ",
|
|
6541
|
+
/* @__PURE__ */ jsx("span", {
|
|
6542
|
+
fg: COLOR.model,
|
|
6543
|
+
children: "enter"
|
|
6544
|
+
}),
|
|
6545
|
+
" to advance / save · esc to exit"
|
|
6546
|
+
]
|
|
6547
|
+
}),
|
|
6548
|
+
fields.map((field, i) => {
|
|
6549
|
+
const requiredTag = field.required ? " (required)" : " (optional)";
|
|
6550
|
+
const active = focusedRow === i;
|
|
6551
|
+
return /* @__PURE__ */ jsxs("box", {
|
|
6552
|
+
style: { flexDirection: "column" },
|
|
6553
|
+
children: [
|
|
6554
|
+
/* @__PURE__ */ jsx("text", {
|
|
6555
|
+
fg: active ? COLOR.model : COLOR.dim,
|
|
6556
|
+
children: `${field.label}${requiredTag}`
|
|
6557
|
+
}),
|
|
6558
|
+
field.hint && /* @__PURE__ */ jsx("text", {
|
|
6559
|
+
fg: COLOR.dim,
|
|
6560
|
+
children: stripTrailingPressHint(field.hint)
|
|
6561
|
+
}),
|
|
6562
|
+
/* @__PURE__ */ jsx("box", {
|
|
6563
|
+
style: {
|
|
6564
|
+
border: true,
|
|
6565
|
+
borderColor: active ? COLOR.borderActive : COLOR.border,
|
|
6566
|
+
paddingLeft: 1,
|
|
6567
|
+
paddingRight: 1,
|
|
6568
|
+
height: 3
|
|
6569
|
+
},
|
|
6570
|
+
children: /* @__PURE__ */ jsx("input", {
|
|
6571
|
+
ref: (r) => {
|
|
6572
|
+
inputRefs.current[i] = r;
|
|
6573
|
+
},
|
|
6574
|
+
focused: screenFocused && active,
|
|
6575
|
+
keyBindings: API_KEY_INPUT_BINDINGS,
|
|
6576
|
+
placeholder: field.placeholder ?? field.label,
|
|
6577
|
+
onSubmit: () => {},
|
|
6578
|
+
style: { flexGrow: 1 }
|
|
6579
|
+
})
|
|
6580
|
+
})
|
|
6581
|
+
]
|
|
6582
|
+
}, field.key);
|
|
6583
|
+
}),
|
|
6584
|
+
/* @__PURE__ */ jsx("text", {
|
|
6585
|
+
fg: focusedRow === SAVE_ROW ? COLOR.brand : COLOR.dim,
|
|
6586
|
+
children: focusedRow === SAVE_ROW ? "▶ save" : " save"
|
|
6587
|
+
})
|
|
6588
|
+
]
|
|
6589
|
+
});
|
|
6590
|
+
}
|
|
6591
|
+
function EnterApiKeyStep({ descriptor, customFields, error, onSubmit }) {
|
|
5915
6592
|
const focused = useModalAwareFocus();
|
|
5916
6593
|
const inputRef = useRef(null);
|
|
5917
6594
|
const COLOR = useColors();
|
|
5918
6595
|
const submit = useCallback(() => {
|
|
5919
|
-
onSubmit(descriptor, inputRef.current?.value ?? "");
|
|
5920
|
-
}, [
|
|
6596
|
+
onSubmit(descriptor, customFields, inputRef.current?.value ?? "");
|
|
6597
|
+
}, [
|
|
6598
|
+
descriptor,
|
|
6599
|
+
customFields,
|
|
6600
|
+
onSubmit
|
|
6601
|
+
]);
|
|
5921
6602
|
return /* @__PURE__ */ jsxs(WizardPanel, {
|
|
5922
6603
|
title: `configure ${descriptor.label} — paste API key`,
|
|
5923
6604
|
error,
|
|
@@ -6200,7 +6881,7 @@ function SessionsScreen({ sessions, currentId, focusedSessionId, onPick, onCreat
|
|
|
6200
6881
|
const OVERLAY_RESERVED = 6;
|
|
6201
6882
|
const TITLE_LEN = 8;
|
|
6202
6883
|
const SEP_LEN = 3;
|
|
6203
|
-
const allProjectsLen = showAllProjects ?
|
|
6884
|
+
const allProjectsLen = showAllProjects ? 15 : 0;
|
|
6204
6885
|
const countLen = countSegs.reduce((sum, s) => sum + s.text.length, 0);
|
|
6205
6886
|
const cwdBudget = Math.max(0, termWidth - 4 - TITLE_LEN - OVERLAY_RESERVED) - countLen - SEP_LEN - allProjectsLen;
|
|
6206
6887
|
if (cwdBudget < 6) return countSegs;
|
|
@@ -7033,7 +7714,7 @@ function PromptBlock({ userPrompts, onSubmit, completionProviders, onPopupOpenCh
|
|
|
7033
7714
|
if (statSync(resolved).isFile()) {
|
|
7034
7715
|
const buf = readFileSync(resolved);
|
|
7035
7716
|
const ext = (resolved.split(".").pop() ?? "").toLowerCase();
|
|
7036
|
-
const mediaType = IMAGE_MEDIA_TYPES[ext] ?? MIME_BY_EXT[ext] ?? "application/octet-stream";
|
|
7717
|
+
const mediaType = sniffImageMediaType(buf) ?? IMAGE_MEDIA_TYPES[ext] ?? MIME_BY_EXT[ext] ?? "application/octet-stream";
|
|
7037
7718
|
setAttachments((prev) => [...prev, {
|
|
7038
7719
|
name: basename(resolved),
|
|
7039
7720
|
content: buf,
|
|
@@ -8173,7 +8854,7 @@ function SettingsModal({ skillsCatalog: skillsCatalogProp, mcpsCatalog: mcpsCata
|
|
|
8173
8854
|
mcpToolsByServer
|
|
8174
8855
|
]);
|
|
8175
8856
|
const filteredProviders = useMemo(() => (authentication?.providers ?? []).filter((p) => matchesQuery(providerCorpus(p), query)), [authentication?.providers, query]);
|
|
8176
|
-
const authRowCount = filteredProviders.length
|
|
8857
|
+
const authRowCount = filteredProviders.length;
|
|
8177
8858
|
const filteredSize = {
|
|
8178
8859
|
...Object.fromEntries(SETTINGS_CATEGORIES.map((c) => [c.id, filteredByCategory[c.id].length])),
|
|
8179
8860
|
skills: filteredSkills.length,
|
|
@@ -8367,16 +9048,8 @@ function SettingsModal({ skillsCatalog: skillsCatalogProp, mcpsCatalog: mcpsCata
|
|
|
8367
9048
|
return;
|
|
8368
9049
|
}
|
|
8369
9050
|
if (activeTab === "authentication") {
|
|
8370
|
-
if (cursor === filteredProviders.length || !filteredProviders[cursor]) {
|
|
8371
|
-
actions?.onReauth?.();
|
|
8372
|
-
return;
|
|
8373
|
-
}
|
|
8374
9051
|
const provider = filteredProviders[cursor];
|
|
8375
|
-
if (provider
|
|
8376
|
-
actions.onPickProvider(provider);
|
|
8377
|
-
return;
|
|
8378
|
-
}
|
|
8379
|
-
actions?.onReauth?.();
|
|
9052
|
+
if (provider) actions?.onConfigureProvider?.(provider);
|
|
8380
9053
|
return;
|
|
8381
9054
|
}
|
|
8382
9055
|
return;
|
|
@@ -8893,7 +9566,6 @@ function AuthenticationList({ view, providers, cursor, highlightBg, query }) {
|
|
|
8893
9566
|
const COLOR = useColors();
|
|
8894
9567
|
const home = homedir();
|
|
8895
9568
|
const totalProviders = view.providers?.length ?? 0;
|
|
8896
|
-
const addRowIndex = providers.length;
|
|
8897
9569
|
return /* @__PURE__ */ jsxs("box", {
|
|
8898
9570
|
style: { flexDirection: "column" },
|
|
8899
9571
|
children: [
|
|
@@ -9012,44 +9684,10 @@ function AuthenticationList({ view, providers, cursor, highlightBg, query }) {
|
|
|
9012
9684
|
children: ` ${p.methods.map((m) => `${m.source}: ${displayPath$1(m.detail, home)}`).join(" · ")}`
|
|
9013
9685
|
})]
|
|
9014
9686
|
}, p.key);
|
|
9015
|
-
}),
|
|
9016
|
-
/* @__PURE__ */ jsx(AuthAddRow, {
|
|
9017
|
-
anchorIndex: addRowIndex,
|
|
9018
|
-
focused: cursor === addRowIndex,
|
|
9019
|
-
highlightBg
|
|
9020
9687
|
})
|
|
9021
9688
|
]
|
|
9022
9689
|
});
|
|
9023
9690
|
}
|
|
9024
|
-
function AuthAddRow({ anchorIndex, focused, highlightBg }) {
|
|
9025
|
-
const COLOR = useColors();
|
|
9026
|
-
const bg = focused ? highlightBg : void 0;
|
|
9027
|
-
return /* @__PURE__ */ jsxs("box", {
|
|
9028
|
-
id: anchorIdFor(anchorIndex),
|
|
9029
|
-
style: {
|
|
9030
|
-
flexDirection: "column",
|
|
9031
|
-
flexShrink: 0,
|
|
9032
|
-
marginTop: 1,
|
|
9033
|
-
paddingLeft: 1,
|
|
9034
|
-
paddingRight: 1,
|
|
9035
|
-
backgroundColor: bg
|
|
9036
|
-
},
|
|
9037
|
-
children: [/* @__PURE__ */ jsxs("text", {
|
|
9038
|
-
wrapMode: "none",
|
|
9039
|
-
children: [/* @__PURE__ */ jsx("span", {
|
|
9040
|
-
fg: focused ? COLOR.brand : COLOR.mute,
|
|
9041
|
-
children: focused ? "▶ " : " "
|
|
9042
|
-
}), /* @__PURE__ */ jsx("span", {
|
|
9043
|
-
fg: focused ? COLOR.brand : COLOR.dim,
|
|
9044
|
-
children: "+ add or re-configure a provider"
|
|
9045
|
-
})]
|
|
9046
|
-
}), /* @__PURE__ */ jsx("text", {
|
|
9047
|
-
wrapMode: "none",
|
|
9048
|
-
fg: COLOR.mute,
|
|
9049
|
-
children: " launch the setup wizard"
|
|
9050
|
-
})]
|
|
9051
|
-
});
|
|
9052
|
-
}
|
|
9053
9691
|
function ToggleRow({ id, label, description, enabled, focused, bg }) {
|
|
9054
9692
|
const COLOR = useColors();
|
|
9055
9693
|
return /* @__PURE__ */ jsxs("box", {
|
|
@@ -9600,23 +10238,25 @@ const PREVIEW_CHAR_MAX = 8e3;
|
|
|
9600
10238
|
* keeps a comfortable shape rather than stretching to the full height.
|
|
9601
10239
|
*/
|
|
9602
10240
|
const MAX_MODAL_HEIGHT = 28;
|
|
9603
|
-
const EDIT_TEXTAREA_BINDINGS =
|
|
9604
|
-
|
|
9605
|
-
|
|
9606
|
-
|
|
9607
|
-
|
|
9608
|
-
|
|
9609
|
-
|
|
9610
|
-
|
|
9611
|
-
|
|
9612
|
-
|
|
9613
|
-
|
|
9614
|
-
|
|
9615
|
-
|
|
9616
|
-
|
|
9617
|
-
|
|
9618
|
-
|
|
9619
|
-
|
|
10241
|
+
const EDIT_TEXTAREA_BINDINGS = (() => {
|
|
10242
|
+
return [
|
|
10243
|
+
...defaultTextareaKeyBindings.filter((b) => b.name !== "return" && !(b.name === "a" && b.ctrl && !b.shift && !b.meta)),
|
|
10244
|
+
{
|
|
10245
|
+
name: "a",
|
|
10246
|
+
ctrl: true,
|
|
10247
|
+
action: "select-all"
|
|
10248
|
+
},
|
|
10249
|
+
{
|
|
10250
|
+
name: "return",
|
|
10251
|
+
action: "submit"
|
|
10252
|
+
},
|
|
10253
|
+
{
|
|
10254
|
+
name: "return",
|
|
10255
|
+
shift: true,
|
|
10256
|
+
action: "newline"
|
|
10257
|
+
}
|
|
10258
|
+
];
|
|
10259
|
+
})();
|
|
9620
10260
|
/**
|
|
9621
10261
|
* Extract the editable text from a turn — joins all `text` blocks.
|
|
9622
10262
|
* Non-text blocks (tool_call, tool_result, thinking, etc.) are structural
|
|
@@ -10304,6 +10944,7 @@ function AppShell() {
|
|
|
10304
10944
|
if (!resumeProvider) return "auth";
|
|
10305
10945
|
return lastResumedSessionId ? "chat" : "sessions";
|
|
10306
10946
|
});
|
|
10947
|
+
const [authConfigureKey, setAuthConfigureKey] = useState(void 0);
|
|
10307
10948
|
const [picked, setPicked] = useState(() => initialPicked);
|
|
10308
10949
|
const pickedRef = useRef(picked);
|
|
10309
10950
|
pickedRef.current = picked;
|
|
@@ -10523,13 +11164,12 @@ function AppShell() {
|
|
|
10523
11164
|
const remembered = initialState.lastModelByProvider?.[provider.key];
|
|
10524
11165
|
const model = modelId ?? remembered ?? descriptor.defaultModel ?? descriptor.factory().meta.defaultModel;
|
|
10525
11166
|
const effort = effortForModel(descriptor, model, initialState.lastEffortByModel);
|
|
10526
|
-
|
|
11167
|
+
const opts = restoreModelOptions(descriptor, model, initialState.lastModelOptionsByModel);
|
|
11168
|
+
return {
|
|
10527
11169
|
provider,
|
|
10528
11170
|
model,
|
|
10529
|
-
effort
|
|
10530
|
-
|
|
10531
|
-
provider,
|
|
10532
|
-
model
|
|
11171
|
+
...effort ? { effort } : {},
|
|
11172
|
+
...opts ? { modelOptions: opts } : {}
|
|
10533
11173
|
};
|
|
10534
11174
|
}, [providerRegistry, initialState]);
|
|
10535
11175
|
const cancelRunOnDenial = useCallback((reason) => {
|
|
@@ -10760,6 +11400,25 @@ function AppShell() {
|
|
|
10760
11400
|
});
|
|
10761
11401
|
agent.hooks.hook("stream:thinking", ({ delta, turnId }) => stream.queueStreamDelta("thinking", delta, { turnId }));
|
|
10762
11402
|
agent.hooks.hook("stream:text", ({ delta, turnId }) => stream.queueStreamDelta("markdown", delta, { turnId }));
|
|
11403
|
+
agent.hooks.hook("stream:server_tool_use", ({ id, name, input, turnId }) => {
|
|
11404
|
+
stream.appendImmediate({
|
|
11405
|
+
kind: "tool",
|
|
11406
|
+
text: toolCallPreview(name, input),
|
|
11407
|
+
tool: name,
|
|
11408
|
+
input,
|
|
11409
|
+
callId: id,
|
|
11410
|
+
turnId
|
|
11411
|
+
});
|
|
11412
|
+
});
|
|
11413
|
+
agent.hooks.hook("stream:server_tool_result", ({ toolUseId, toolName, content, turnId }) => {
|
|
11414
|
+
stream.appendImmediate({
|
|
11415
|
+
kind: "tool-result",
|
|
11416
|
+
text: serverToolResultSummary(content),
|
|
11417
|
+
tool: toolName,
|
|
11418
|
+
callId: toolUseId,
|
|
11419
|
+
turnId
|
|
11420
|
+
});
|
|
11421
|
+
});
|
|
10763
11422
|
agent.hooks.hook("tool:before", async ({ callId, name, input, turnId }) => {
|
|
10764
11423
|
registerInFlightTool({
|
|
10765
11424
|
callId,
|
|
@@ -10921,6 +11580,29 @@ function AppShell() {
|
|
|
10921
11580
|
turnId
|
|
10922
11581
|
});
|
|
10923
11582
|
});
|
|
11583
|
+
agent.hooks.hook("child:stream:server_tool_use", ({ id, name, input, childId, depth, turnId }) => {
|
|
11584
|
+
stream.appendImmediate({
|
|
11585
|
+
kind: "tool",
|
|
11586
|
+
text: toolCallPreview(name, input),
|
|
11587
|
+
tool: name,
|
|
11588
|
+
input,
|
|
11589
|
+
callId: id,
|
|
11590
|
+
childId,
|
|
11591
|
+
depth,
|
|
11592
|
+
turnId
|
|
11593
|
+
});
|
|
11594
|
+
});
|
|
11595
|
+
agent.hooks.hook("child:stream:server_tool_result", ({ toolUseId, toolName, content, childId, depth, turnId }) => {
|
|
11596
|
+
stream.appendImmediate({
|
|
11597
|
+
kind: "tool-result",
|
|
11598
|
+
text: serverToolResultSummary(content),
|
|
11599
|
+
tool: toolName,
|
|
11600
|
+
callId: toolUseId,
|
|
11601
|
+
childId,
|
|
11602
|
+
depth,
|
|
11603
|
+
turnId
|
|
11604
|
+
});
|
|
11605
|
+
});
|
|
10924
11606
|
agent.hooks.hook("child:tool:before", ({ callId, name, input, childId, depth, turnId, priorContent }) => {
|
|
10925
11607
|
registerInFlightTool({
|
|
10926
11608
|
callId,
|
|
@@ -11068,9 +11750,11 @@ function AppShell() {
|
|
|
11068
11750
|
setEvents(eventsFromTurns(session.turns, session.runs));
|
|
11069
11751
|
setBusy(true);
|
|
11070
11752
|
try {
|
|
11753
|
+
const runModelOptions = enabledModelOptions(currentPicked.modelOptions);
|
|
11071
11754
|
await agent.run({
|
|
11072
11755
|
model: currentPicked.model,
|
|
11073
|
-
...currentPicked.effort ? { thinking: currentPicked.effort } : {}
|
|
11756
|
+
...currentPicked.effort ? { thinking: currentPicked.effort } : {},
|
|
11757
|
+
...Object.keys(runModelOptions).length > 0 ? { modelOptions: runModelOptions } : {}
|
|
11074
11758
|
});
|
|
11075
11759
|
await session.save().catch((err) => debugLog("resume-interaction: session.save failed", err));
|
|
11076
11760
|
setCurrentSession((prev) => prev ? {
|
|
@@ -11193,6 +11877,7 @@ function AppShell() {
|
|
|
11193
11877
|
const onPickProvider = useCallback(async (p) => {
|
|
11194
11878
|
const next = makePicked(p);
|
|
11195
11879
|
if (!next) return;
|
|
11880
|
+
setAuthConfigureKey(void 0);
|
|
11196
11881
|
setPicked(next);
|
|
11197
11882
|
stateStore.save({
|
|
11198
11883
|
...stateStore.load(),
|
|
@@ -11355,13 +12040,12 @@ function AppShell() {
|
|
|
11355
12040
|
}
|
|
11356
12041
|
});
|
|
11357
12042
|
const nextEffort = descriptor ? effortForModel(descriptor, next.modelId, prior.lastEffortByModel) : void 0;
|
|
11358
|
-
|
|
12043
|
+
const nextOptions = descriptor ? restoreModelOptions(descriptor, next.modelId, prior.lastModelOptionsByModel) : void 0;
|
|
12044
|
+
setPicked({
|
|
11359
12045
|
provider: nextProvider,
|
|
11360
12046
|
model: next.modelId,
|
|
11361
|
-
effort: nextEffort
|
|
11362
|
-
|
|
11363
|
-
provider: nextProvider,
|
|
11364
|
-
model: next.modelId
|
|
12047
|
+
...nextEffort ? { effort: nextEffort } : {},
|
|
12048
|
+
...nextOptions ? { modelOptions: nextOptions } : {}
|
|
11365
12049
|
});
|
|
11366
12050
|
modal.close();
|
|
11367
12051
|
if (providerChanged && currentSession && !busy && !pendingApproval) await activateSession(currentSession.id, nextProvider.key);
|
|
@@ -11394,6 +12078,32 @@ function AppShell() {
|
|
|
11394
12078
|
});
|
|
11395
12079
|
modal.close();
|
|
11396
12080
|
}, [modal, stateStore]);
|
|
12081
|
+
const onToggleModelOption = useCallback((optionId) => {
|
|
12082
|
+
setPicked((prev) => {
|
|
12083
|
+
if (!prev) return prev;
|
|
12084
|
+
const next = {
|
|
12085
|
+
...prev.modelOptions ?? {},
|
|
12086
|
+
[optionId]: !prev.modelOptions?.[optionId]
|
|
12087
|
+
};
|
|
12088
|
+
const prior = stateStore.load();
|
|
12089
|
+
stateStore.save({
|
|
12090
|
+
...prior,
|
|
12091
|
+
lastModelOptionsByModel: {
|
|
12092
|
+
...prior.lastModelOptionsByModel,
|
|
12093
|
+
[prev.model]: next
|
|
12094
|
+
}
|
|
12095
|
+
});
|
|
12096
|
+
return {
|
|
12097
|
+
...prev,
|
|
12098
|
+
modelOptions: next
|
|
12099
|
+
};
|
|
12100
|
+
});
|
|
12101
|
+
}, [stateStore]);
|
|
12102
|
+
const modelOptions = useMemo(() => {
|
|
12103
|
+
if (!picked) return [];
|
|
12104
|
+
const descriptor = providerRegistry[picked.provider.key];
|
|
12105
|
+
return descriptor ? modelOptionsFor(descriptor, picked.model) : [];
|
|
12106
|
+
}, [picked, providerRegistry]);
|
|
11397
12107
|
const modelHasReasoning = useMemo(() => {
|
|
11398
12108
|
if (!picked) return false;
|
|
11399
12109
|
const descriptor = providerRegistry[picked.provider.key];
|
|
@@ -11497,10 +12207,12 @@ function AppShell() {
|
|
|
11497
12207
|
name: att.name
|
|
11498
12208
|
};
|
|
11499
12209
|
})];
|
|
12210
|
+
const runModelOptions = enabledModelOptions(picked.modelOptions);
|
|
11500
12211
|
await agent.run({
|
|
11501
12212
|
model: picked.model,
|
|
11502
12213
|
prompt: runPrompt,
|
|
11503
|
-
...picked.effort ? { thinking: picked.effort } : {}
|
|
12214
|
+
...picked.effort ? { thinking: picked.effort } : {},
|
|
12215
|
+
...Object.keys(runModelOptions).length > 0 ? { modelOptions: runModelOptions } : {}
|
|
11504
12216
|
});
|
|
11505
12217
|
await session.save().catch((err) => debugLog("session.save failed", err));
|
|
11506
12218
|
setCurrentSession((prev) => prev ? {
|
|
@@ -11558,10 +12270,11 @@ function AppShell() {
|
|
|
11558
12270
|
}
|
|
11559
12271
|
})();
|
|
11560
12272
|
}, [picked, runSingleMessage]);
|
|
11561
|
-
const
|
|
12273
|
+
const onConfigureProvider = useMemo(() => {
|
|
11562
12274
|
if (busy || pendingApproval) return void 0;
|
|
11563
|
-
return () => {
|
|
12275
|
+
return (provider) => {
|
|
11564
12276
|
modal.close();
|
|
12277
|
+
setAuthConfigureKey(provider.key);
|
|
11565
12278
|
setScreen("auth");
|
|
11566
12279
|
};
|
|
11567
12280
|
}, [
|
|
@@ -11954,7 +12667,7 @@ function AppShell() {
|
|
|
11954
12667
|
restoredFiles: restoration.restoredFiles,
|
|
11955
12668
|
restoredSkills: restoration.restoredSkills,
|
|
11956
12669
|
model: result.model,
|
|
11957
|
-
inputTokens: (result.usage
|
|
12670
|
+
inputTokens: effectiveInputFromTurn(result.usage),
|
|
11958
12671
|
outputTokens: result.usage.output ?? 0,
|
|
11959
12672
|
effectiveTokens
|
|
11960
12673
|
};
|
|
@@ -12147,10 +12860,6 @@ function AppShell() {
|
|
|
12147
12860
|
}
|
|
12148
12861
|
if (matchesBinding(key, keybindings.openSettings) && screen !== "auth") {
|
|
12149
12862
|
const allProviders = detectAuth(config.paths.userDir, providerRegistry);
|
|
12150
|
-
const onPickProviderFromSettings = (provider) => {
|
|
12151
|
-
modal.close();
|
|
12152
|
-
onPickProvider(provider);
|
|
12153
|
-
};
|
|
12154
12863
|
modal.open(/* @__PURE__ */ jsx(SettingsModal, {
|
|
12155
12864
|
keybindings,
|
|
12156
12865
|
keybindingsPath: keybindingsPath(config.paths.userDir),
|
|
@@ -12161,8 +12870,7 @@ function AppShell() {
|
|
|
12161
12870
|
providers: allProviders
|
|
12162
12871
|
},
|
|
12163
12872
|
actions: {
|
|
12164
|
-
|
|
12165
|
-
onPickProvider: onPickProviderFromSettings,
|
|
12873
|
+
onConfigureProvider,
|
|
12166
12874
|
onOpenKeybindings: onOpenKeybindingsFile,
|
|
12167
12875
|
onLoginMcp,
|
|
12168
12876
|
onLogoutMcp,
|
|
@@ -12196,12 +12904,16 @@ function AppShell() {
|
|
|
12196
12904
|
}));
|
|
12197
12905
|
return;
|
|
12198
12906
|
}
|
|
12199
|
-
if (matchesBinding(key, keybindings.openEffortPicker) && screen === "chat" && picked && !busy && modelHasReasoning) {
|
|
12907
|
+
if (matchesBinding(key, keybindings.openEffortPicker) && screen === "chat" && picked && !busy && (modelHasReasoning || modelOptions.length > 0)) {
|
|
12200
12908
|
const descriptor = providerRegistry[picked.provider.key];
|
|
12201
|
-
modal.open(/* @__PURE__ */ jsx(
|
|
12202
|
-
|
|
12909
|
+
modal.open(/* @__PURE__ */ jsx(ModelOptionsPickerModal, {
|
|
12910
|
+
supportsReasoning: modelHasReasoning,
|
|
12203
12911
|
supportsAdaptive: !!descriptor && piIdOf(descriptor) === "anthropic",
|
|
12204
|
-
|
|
12912
|
+
currentEffort: picked.effort,
|
|
12913
|
+
options: modelOptions,
|
|
12914
|
+
enabled: picked.modelOptions,
|
|
12915
|
+
onPickEffort,
|
|
12916
|
+
onToggleOption: onToggleModelOption
|
|
12205
12917
|
}));
|
|
12206
12918
|
return;
|
|
12207
12919
|
}
|
|
@@ -12212,6 +12924,21 @@ function AppShell() {
|
|
|
12212
12924
|
}));
|
|
12213
12925
|
return;
|
|
12214
12926
|
}
|
|
12927
|
+
if (matchesBinding(key, keybindings.openContextPanel) && screen === "chat" && picked) {
|
|
12928
|
+
const agent = agentRef.current;
|
|
12929
|
+
if (!agent) return;
|
|
12930
|
+
const descriptor = providerRegistry[picked.provider.key];
|
|
12931
|
+
const effWindow = effectiveContextWindow(descriptor ? getContextWindow(descriptor, picked.model) : null) ?? void 0;
|
|
12932
|
+
agent.getContextBreakdown({
|
|
12933
|
+
model: picked.model,
|
|
12934
|
+
...effWindow !== void 0 ? { effectiveWindow: effWindow } : {},
|
|
12935
|
+
autocompactBuffer: OUTPUT_RESERVE_TOKENS,
|
|
12936
|
+
...settings.autoCompact && settings.autoCompactThreshold ? { compactThreshold: settings.autoCompactThreshold } : {}
|
|
12937
|
+
}).then((breakdown) => {
|
|
12938
|
+
if (breakdown && agentRef.current === agent) modal.open(/* @__PURE__ */ jsx(ContextPanelModal, { breakdown }));
|
|
12939
|
+
}).catch((err) => debugLog("getContextBreakdown failed", err));
|
|
12940
|
+
return;
|
|
12941
|
+
}
|
|
12215
12942
|
if (matchesBinding(key, keybindings.openKeybindings) && screen !== "auth") {
|
|
12216
12943
|
modal.open(/* @__PURE__ */ jsx(KeybindingsModal, {
|
|
12217
12944
|
bindings: keybindings,
|
|
@@ -12353,6 +13080,10 @@ function AppShell() {
|
|
|
12353
13080
|
modelColor: COLOR.model,
|
|
12354
13081
|
effortLabel: modelHasReasoning ? picked?.effort ?? "medium" : null,
|
|
12355
13082
|
effortColor: COLOR.warn,
|
|
13083
|
+
modelOptionsLabel: (() => {
|
|
13084
|
+
const on = modelOptions.filter((o) => picked?.modelOptions?.[o.id]);
|
|
13085
|
+
return on.length > 0 ? on.map((o) => o.id).join(", ") : null;
|
|
13086
|
+
})(),
|
|
12356
13087
|
effortKeyColor: COLOR.warn,
|
|
12357
13088
|
agentLabel: pickedAgent.label,
|
|
12358
13089
|
agentColor: accentColor(pickedAgent.accent, COLOR),
|
|
@@ -12374,6 +13105,7 @@ function AppShell() {
|
|
|
12374
13105
|
pickedAgent,
|
|
12375
13106
|
COLOR,
|
|
12376
13107
|
modelHasReasoning,
|
|
13108
|
+
modelOptions,
|
|
12377
13109
|
keybindings,
|
|
12378
13110
|
inFlightTools,
|
|
12379
13111
|
backgroundTasks,
|
|
@@ -12438,7 +13170,10 @@ function AppShell() {
|
|
|
12438
13170
|
paddingRight: 1
|
|
12439
13171
|
},
|
|
12440
13172
|
children: [
|
|
12441
|
-
screen === "auth" && /* @__PURE__ */ jsx(AuthScreen, {
|
|
13173
|
+
screen === "auth" && /* @__PURE__ */ jsx(AuthScreen, {
|
|
13174
|
+
onPick: onPickProvider,
|
|
13175
|
+
initialConfigureKey: authConfigureKey
|
|
13176
|
+
}),
|
|
12442
13177
|
screen === "sessions" && /* @__PURE__ */ jsx(SessionsScreen, {
|
|
12443
13178
|
sessions,
|
|
12444
13179
|
currentId: currentSession?.id ?? null,
|
|
@@ -12725,6 +13460,198 @@ function initTreeSitterWorker() {
|
|
|
12725
13460
|
return getTreeSitterClient().initialize();
|
|
12726
13461
|
}
|
|
12727
13462
|
//#endregion
|
|
13463
|
+
//#region src/tui/effort-picker.tsx
|
|
13464
|
+
const BASE_LEVELS = [
|
|
13465
|
+
{
|
|
13466
|
+
id: "off",
|
|
13467
|
+
description: "no reasoning — fastest, smallest output"
|
|
13468
|
+
},
|
|
13469
|
+
{
|
|
13470
|
+
id: "minimal",
|
|
13471
|
+
description: "tiny reasoning budget (gpt-5 family)"
|
|
13472
|
+
},
|
|
13473
|
+
{
|
|
13474
|
+
id: "low",
|
|
13475
|
+
description: "short reasoning pass"
|
|
13476
|
+
},
|
|
13477
|
+
{
|
|
13478
|
+
id: "medium",
|
|
13479
|
+
description: "balanced — sensible default"
|
|
13480
|
+
},
|
|
13481
|
+
{
|
|
13482
|
+
id: "high",
|
|
13483
|
+
description: "deep reasoning — slowest, longest"
|
|
13484
|
+
}
|
|
13485
|
+
];
|
|
13486
|
+
const ADAPTIVE_LEVEL = {
|
|
13487
|
+
id: "adaptive",
|
|
13488
|
+
description: "model decides per-turn (Anthropic)"
|
|
13489
|
+
};
|
|
13490
|
+
function EffortPickerModal({ current, supportsAdaptive, onPick }) {
|
|
13491
|
+
const COLOR = useColors();
|
|
13492
|
+
const SURFACE = useSurfaces();
|
|
13493
|
+
const inputRef = useRef(null);
|
|
13494
|
+
const [query, setQuery] = useState("");
|
|
13495
|
+
const levels = useMemo(() => {
|
|
13496
|
+
return (supportsAdaptive ? [...BASE_LEVELS, ADAPTIVE_LEVEL] : BASE_LEVELS).map((l) => ({
|
|
13497
|
+
...l,
|
|
13498
|
+
searchCorpus: `${l.id} ${l.description}`.toLowerCase()
|
|
13499
|
+
}));
|
|
13500
|
+
}, [supportsAdaptive]);
|
|
13501
|
+
const filtered = useMemo(() => {
|
|
13502
|
+
const trimmed = query.trim().toLowerCase();
|
|
13503
|
+
if (!trimmed) return levels;
|
|
13504
|
+
const terms = trimmed.split(/\s+/);
|
|
13505
|
+
return levels.filter((l) => terms.every((t) => l.searchCorpus.includes(t)));
|
|
13506
|
+
}, [levels, query]);
|
|
13507
|
+
const [selectedIdx, setSelectedIdx] = useState(() => {
|
|
13508
|
+
const idx = levels.findIndex((l) => l.id === current);
|
|
13509
|
+
if (idx >= 0) return idx;
|
|
13510
|
+
const fallback = levels.findIndex((l) => l.id === "medium");
|
|
13511
|
+
return fallback < 0 ? 0 : fallback;
|
|
13512
|
+
});
|
|
13513
|
+
const handleQueryChange = useCallback((next) => {
|
|
13514
|
+
setQuery(next);
|
|
13515
|
+
setSelectedIdx(0);
|
|
13516
|
+
}, []);
|
|
13517
|
+
const safeIndex = filtered.length === 0 ? 0 : Math.min(selectedIdx, filtered.length - 1);
|
|
13518
|
+
const commit = () => {
|
|
13519
|
+
const row = filtered[safeIndex];
|
|
13520
|
+
if (row) onPick(row.id);
|
|
13521
|
+
};
|
|
13522
|
+
useEffect(() => {
|
|
13523
|
+
inputRef.current?.focus();
|
|
13524
|
+
}, []);
|
|
13525
|
+
useKeyboard((key) => {
|
|
13526
|
+
if (key.name === "up") {
|
|
13527
|
+
setSelectedIdx((i) => {
|
|
13528
|
+
if (filtered.length === 0) return i;
|
|
13529
|
+
return ((i - 1) % filtered.length + filtered.length) % filtered.length;
|
|
13530
|
+
});
|
|
13531
|
+
return;
|
|
13532
|
+
}
|
|
13533
|
+
if (key.name === "down") {
|
|
13534
|
+
setSelectedIdx((i) => {
|
|
13535
|
+
if (filtered.length === 0) return i;
|
|
13536
|
+
return (i + 1) % filtered.length;
|
|
13537
|
+
});
|
|
13538
|
+
return;
|
|
13539
|
+
}
|
|
13540
|
+
if (key.name === "return") commit();
|
|
13541
|
+
});
|
|
13542
|
+
return /* @__PURE__ */ jsxs(Modal, {
|
|
13543
|
+
title: "select reasoning effort",
|
|
13544
|
+
maxWidth: 80,
|
|
13545
|
+
children: [
|
|
13546
|
+
/* @__PURE__ */ jsx("box", {
|
|
13547
|
+
style: {
|
|
13548
|
+
border: true,
|
|
13549
|
+
borderColor: COLOR.borderActive,
|
|
13550
|
+
paddingLeft: 1,
|
|
13551
|
+
paddingRight: 1,
|
|
13552
|
+
height: 3
|
|
13553
|
+
},
|
|
13554
|
+
children: /* @__PURE__ */ jsx("input", {
|
|
13555
|
+
ref: inputRef,
|
|
13556
|
+
focused: true,
|
|
13557
|
+
placeholder: "search effort levels…",
|
|
13558
|
+
onInput: handleQueryChange,
|
|
13559
|
+
onSubmit: () => {},
|
|
13560
|
+
style: { flexGrow: 1 }
|
|
13561
|
+
})
|
|
13562
|
+
}),
|
|
13563
|
+
/* @__PURE__ */ jsx("box", {
|
|
13564
|
+
style: {
|
|
13565
|
+
flexDirection: "column",
|
|
13566
|
+
flexShrink: 0
|
|
13567
|
+
},
|
|
13568
|
+
children: filtered.length === 0 ? /* @__PURE__ */ jsxs("text", {
|
|
13569
|
+
fg: COLOR.dim,
|
|
13570
|
+
children: [/* @__PURE__ */ jsx("span", {
|
|
13571
|
+
fg: COLOR.mute,
|
|
13572
|
+
children: "no levels match "
|
|
13573
|
+
}), /* @__PURE__ */ jsx("span", {
|
|
13574
|
+
fg: COLOR.warn,
|
|
13575
|
+
children: query.trim()
|
|
13576
|
+
})]
|
|
13577
|
+
}) : filtered.map((level, i) => /* @__PURE__ */ jsx(EffortRow, {
|
|
13578
|
+
level,
|
|
13579
|
+
isCurrent: level.id === current,
|
|
13580
|
+
isFocused: i === safeIndex,
|
|
13581
|
+
highlightBg: SURFACE.selection
|
|
13582
|
+
}, level.id))
|
|
13583
|
+
}),
|
|
13584
|
+
/* @__PURE__ */ jsxs("text", {
|
|
13585
|
+
fg: COLOR.dim,
|
|
13586
|
+
children: [
|
|
13587
|
+
/* @__PURE__ */ jsx("span", {
|
|
13588
|
+
fg: COLOR.warn,
|
|
13589
|
+
children: "↑↓"
|
|
13590
|
+
}),
|
|
13591
|
+
" navigate · ",
|
|
13592
|
+
/* @__PURE__ */ jsx("span", {
|
|
13593
|
+
fg: COLOR.warn,
|
|
13594
|
+
children: "↵"
|
|
13595
|
+
}),
|
|
13596
|
+
" select · ",
|
|
13597
|
+
/* @__PURE__ */ jsx("span", {
|
|
13598
|
+
fg: COLOR.warn,
|
|
13599
|
+
children: "esc"
|
|
13600
|
+
}),
|
|
13601
|
+
" close · ",
|
|
13602
|
+
/* @__PURE__ */ jsx("span", {
|
|
13603
|
+
fg: COLOR.mute,
|
|
13604
|
+
children: `${filtered.length} / ${levels.length} level${levels.length === 1 ? "" : "s"}`
|
|
13605
|
+
})
|
|
13606
|
+
]
|
|
13607
|
+
})
|
|
13608
|
+
]
|
|
13609
|
+
});
|
|
13610
|
+
}
|
|
13611
|
+
/**
|
|
13612
|
+
* Single row in the picker. Mirrors `ModelRow` in `model-picker.tsx`:
|
|
13613
|
+
* `●` marker for the current pick, single-space middle-dot separators,
|
|
13614
|
+
* focused row gets the `surfaces.selection` background lift.
|
|
13615
|
+
*/
|
|
13616
|
+
function EffortRow({ level, isCurrent, isFocused, highlightBg }) {
|
|
13617
|
+
const COLOR = useColors();
|
|
13618
|
+
const marker = isCurrent ? "●" : " ";
|
|
13619
|
+
return /* @__PURE__ */ jsx("box", {
|
|
13620
|
+
style: {
|
|
13621
|
+
height: 1,
|
|
13622
|
+
paddingLeft: 1,
|
|
13623
|
+
paddingRight: 1,
|
|
13624
|
+
flexShrink: 0,
|
|
13625
|
+
backgroundColor: isFocused ? highlightBg : void 0
|
|
13626
|
+
},
|
|
13627
|
+
children: /* @__PURE__ */ jsxs("text", {
|
|
13628
|
+
wrapMode: "none",
|
|
13629
|
+
children: [
|
|
13630
|
+
/* @__PURE__ */ jsx("span", {
|
|
13631
|
+
fg: isCurrent ? COLOR.brand : COLOR.mute,
|
|
13632
|
+
children: marker
|
|
13633
|
+
}),
|
|
13634
|
+
/* @__PURE__ */ jsx("span", {
|
|
13635
|
+
fg: COLOR.mute,
|
|
13636
|
+
children: " "
|
|
13637
|
+
}),
|
|
13638
|
+
/* @__PURE__ */ jsx("span", {
|
|
13639
|
+
fg: isFocused ? COLOR.brand : COLOR.dim,
|
|
13640
|
+
children: level.id
|
|
13641
|
+
}),
|
|
13642
|
+
/* @__PURE__ */ jsx("span", {
|
|
13643
|
+
fg: COLOR.mute,
|
|
13644
|
+
children: " · "
|
|
13645
|
+
}),
|
|
13646
|
+
/* @__PURE__ */ jsx("span", {
|
|
13647
|
+
fg: COLOR.mute,
|
|
13648
|
+
children: level.description
|
|
13649
|
+
})
|
|
13650
|
+
]
|
|
13651
|
+
})
|
|
13652
|
+
});
|
|
13653
|
+
}
|
|
13654
|
+
//#endregion
|
|
12728
13655
|
//#region src/tui/mcps-settings.tsx
|
|
12729
13656
|
/**
|
|
12730
13657
|
* MCP server picker. Hierarchical: each server is one row, and an
|
|
@@ -13590,6 +14517,6 @@ async function runTui(options = {}) {
|
|
|
13590
14517
|
process.exit(0);
|
|
13591
14518
|
}
|
|
13592
14519
|
//#endregion
|
|
13593
|
-
export { AgentPickerModal, App, AuthScreen, ChatScreen, CompletionPopup, EffortPickerModal, Footer, InteractionBlock, McpsSettingsModal, Modal, ModalRoot, ModelPickerModal, SessionDetailsModal, SessionsScreen, SettingsModal, SkillsSettingsModal, Spinner, StatusSpinner, TOOL_DISPLAY, TitleOverlay, ToggleListModal, Transcript, TurnDetailsModal, accentColor, buildMdStyle, clipHintsToWidth, computeTurnAnchors, displayNameFor, formatToolCall, hintsLength, isEditErrorResult, isTurnHighlighted, isVisible, marginTopFor, onInputSubmit, renderHintSpans, runTui, selectableTurnIds, splitMarkdownCodeBlocks, splitPromptSegments, truncateTrailing, turnSelectionOwnership, useMdStyle, useModal, useModalAwareFocus };
|
|
14520
|
+
export { AgentPickerModal, App, AuthScreen, ChatScreen, CompletionPopup, EffortPickerModal, Footer, InteractionBlock, McpsSettingsModal, Modal, ModalRoot, ModelOptionsPickerModal, ModelPickerModal, SessionDetailsModal, SessionsScreen, SettingsModal, SkillsSettingsModal, Spinner, StatusSpinner, TOOL_DISPLAY, TitleOverlay, ToggleListModal, Transcript, TurnDetailsModal, accentColor, buildMdStyle, clipHintsToWidth, computeTurnAnchors, displayNameFor, formatToolCall, hintsLength, isEditErrorResult, isTurnHighlighted, isVisible, marginTopFor, onInputSubmit, renderHintSpans, runTui, selectableTurnIds, splitMarkdownCodeBlocks, splitPromptSegments, truncateTrailing, turnSelectionOwnership, useMdStyle, useModal, useModalAwareFocus };
|
|
13594
14521
|
|
|
13595
14522
|
//# sourceMappingURL=tui.js.map
|