zidane 5.1.13 → 5.1.15
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{agent-skiQGYs2.d.ts → agent-a-mteIEP.d.ts} +19 -4
- package/dist/agent-a-mteIEP.d.ts.map +1 -0
- package/dist/chat.d.ts +172 -7
- package/dist/chat.d.ts.map +1 -1
- package/dist/chat.js +2 -2
- package/dist/{errors-D1lhd6mX.js → errors-COmsomd5.js} +13 -3
- package/dist/{errors-D1lhd6mX.js.map → errors-COmsomd5.js.map} +1 -1
- package/dist/{index-YM7SipFz.d.ts → index-CsdPEjlu.d.ts} +2 -2
- package/dist/{index-YM7SipFz.d.ts.map → index-CsdPEjlu.d.ts.map} +1 -1
- package/dist/{index-CjPh6CRE.d.ts → index-D5gCRi42.d.ts} +2 -2
- package/dist/{index-CjPh6CRE.d.ts.map → index-D5gCRi42.d.ts.map} +1 -1
- package/dist/index.d.ts +3 -3
- package/dist/index.js +10 -10
- package/dist/{interpolate-BI6ovwag.js → interpolate-BhmHKD6x.js} +3 -4
- package/dist/{interpolate-BI6ovwag.js.map → interpolate-BhmHKD6x.js.map} +1 -1
- package/dist/{login-Cc6Q-Fpu.js → login-DrnEZZVv.js} +4 -4
- package/dist/{login-Cc6Q-Fpu.js.map → login-DrnEZZVv.js.map} +1 -1
- package/dist/{mcp-CUt-N8zn.js → mcp-B1psg7jf.js} +4 -4
- package/dist/mcp-B1psg7jf.js.map +1 -0
- package/dist/mcp.d.ts +1 -1
- package/dist/mcp.js +1 -1
- package/dist/{messages-CIkO_aCH.js → messages-DsbMYNmt.js} +26 -34
- package/dist/messages-DsbMYNmt.js.map +1 -0
- package/dist/{presets-Ce79MK4J.js → presets-H8UYtz3b.js} +2 -2
- package/dist/{presets-Ce79MK4J.js.map → presets-H8UYtz3b.js.map} +1 -1
- package/dist/presets.d.ts +2 -2
- package/dist/presets.js +1 -1
- package/dist/{providers-CvriFHFU.js → providers-v1Rn2rqG.js} +40 -14
- package/dist/providers-v1Rn2rqG.js.map +1 -0
- package/dist/providers.d.ts +1 -1
- package/dist/providers.js +2 -2
- package/dist/session/sqlite.d.ts +1 -1
- package/dist/session/sqlite.d.ts.map +1 -1
- package/dist/session/sqlite.js +2 -2
- package/dist/session/sqlite.js.map +1 -1
- package/dist/{session-DtLD1Sl1.js → session-DOJgRXvF.js} +2 -2
- package/dist/{session-DtLD1Sl1.js.map → session-DOJgRXvF.js.map} +1 -1
- package/dist/session.d.ts +1 -1
- package/dist/session.js +2 -2
- package/dist/skills.d.ts +2 -2
- package/dist/skills.js +1 -1
- package/dist/{tools-BG2wMa3X.js → tools-Duptt9yy.js} +16 -20
- package/dist/tools-Duptt9yy.js.map +1 -0
- package/dist/tools.d.ts +2 -2
- package/dist/tools.js +1 -1
- package/dist/{tool-formatters-0aOMYbH-.d.ts → transcript-anchors-YFom211q.d.ts} +242 -97
- package/dist/transcript-anchors-YFom211q.d.ts.map +1 -0
- package/dist/tui.d.ts +55 -39
- package/dist/tui.d.ts.map +1 -1
- package/dist/tui.js +347 -326
- package/dist/tui.js.map +1 -1
- package/dist/{turn-operations-CDmQ2h-T.js → turn-operations-DNKpDGQi.js} +600 -158
- package/dist/turn-operations-DNKpDGQi.js.map +1 -0
- package/dist/{types-Bx_F8jet.js → types-IcokUOyC.js} +11 -4
- package/dist/{types-Bx_F8jet.js.map → types-IcokUOyC.js.map} +1 -1
- package/dist/types.d.ts +2 -2
- package/dist/types.js +2 -2
- package/package.json +1 -1
- package/dist/agent-skiQGYs2.d.ts.map +0 -1
- package/dist/mcp-CUt-N8zn.js.map +0 -1
- package/dist/messages-CIkO_aCH.js.map +0 -1
- package/dist/providers-CvriFHFU.js.map +0 -1
- package/dist/tool-formatters-0aOMYbH-.d.ts.map +0 -1
- package/dist/tools-BG2wMa3X.js.map +0 -1
- package/dist/turn-operations-CDmQ2h-T.js.map +0 -1
package/dist/tui.js
CHANGED
|
@@ -1,18 +1,19 @@
|
|
|
1
|
-
import { S as resolvePersistDir, b as cleanupPersistedSession, d as createAgent } from "./tools-
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
1
|
+
import { S as resolvePersistDir, b as cleanupPersistedSession, d as createAgent } from "./tools-Duptt9yy.js";
|
|
2
|
+
import { o as errorMessage } from "./errors-COmsomd5.js";
|
|
3
|
+
import { s as McpOAuthProvider, t as connectMcpServers } from "./mcp-B1psg7jf.js";
|
|
4
|
+
import { C as summaryToTurn, a as selectFilesFromSession, r as buildPostCompactAttachments, s as compactConversation, t as loginMcpServer } from "./login-DrnEZZVv.js";
|
|
4
5
|
import { n as formatTokenUsage } from "./stats-DgOvY7wd.js";
|
|
5
|
-
import { n as loadSession, t as createSession } from "./session-
|
|
6
|
+
import { n as loadSession, t as createSession } from "./session-DOJgRXvF.js";
|
|
6
7
|
import { createTuiStore } from "./session/sqlite.js";
|
|
7
|
-
import { $ as
|
|
8
|
+
import { $ as useMcpAuthState, $n as setProviderCredential, $t as lastContextSizeFromTurns, A as getSafelist, At as useSettings, B as buildModelCatalog, Bn as useCompletion, Bt as createDiscoverySlot, Cn as ensureKeybindingsFile, Ct as listProjectFiles, D as useSafeModeQueue, Dt as SETTINGS_TOGGLES, E as useSafeModeActions, Et as SETTINGS_CHOICES, F as suggestSafelistEntry, G as discoverProjectMcps, Gn as bootTick, Gt as useConfig, H as indexOfEntry, Hn as buildLinearRamp, Ht as useDiscovery, J as createFileMcpCredentialStore, Jt as deriveSessionTitle, Kn as shouldAutoCompact, Kt as resolveConfig, L as splitPromptSegments, Mn as uniqueSkillNamesFromReferences, Mr as buildBuildSystem, Nr as buildPlanSystem, Nt as resolveChipColor, Ot as SettingsProvider, Pn as createFilesCompletionProvider, Pt as resolveTheme, Q as useMcpAuthDispatch, Qt as isVisible, R as runOAuthLogin, St as shortId, T as SafeModeProvider, Tn as matchesBinding, Tt as DEFAULT_SETTINGS, U as buildMcpServers, Un as tryOpenBrowser, Ut as useDiscoveryOptional, V as filterModelCatalog, Vn as blendHsl, Vt as DiscoveryProvider, Wt as ConfigProvider, Xt as isEditErrorResult, Yt as eventsFromTurns, Z as McpAuthProvider, Zt as isTurnHighlighted, _ as turnContextSize, a as computeTurnAnchors, an as stripSpawnTokensLine, b as defaultSkillScanPaths, bt as compactPath, c as formatToolCall, cn as toolCallPreview, d as useSelectStyle, dn as buildContextualDiff, en as listSessionMeta, et as getMcpAuthStatus, f as useSurfaces, fn as buildUnifiedDiff, ft as useInteractionsActions, g as finalizeStreamingMarkdownForOwner, gn as filetypeFromPath, gt as truncateTrailing, h as finalizeStreamingMarkdown, hn as extractEditPayload, ht as hintsLength, i as turnAsText, in as selectableTurnIds, it as InteractionsProvider, j as isOnSafelist, jn as createSkillsCompletionProvider, k as addToSafelist, kt as clampFps, l as ThemeProvider, ln as toolResultText, lr as modelSupportsReasoning, lt as makeRequestInteraction, m as useTheme, mt as clipHintsToWidth, n as deleteTurnSafely, nn as marginTopFor, nt as splitMarkdownCodeBlocks, o as TOOL_DISPLAY, on as sumRunCosts, ot as buildResumedToolResultsTurn, pr as piIdOf, pt as useInteractionsQueue, qn as detectAuth, r as truncateTurnsAt, s as displayNameFor, sr as getContextWindow, st as createInteractionTools, u as useColors, un as turnSelectionOwnership, ut as pendingInteractionsFromTurns, v as useStreamBuffer, vt as generateSessionTitle, w as writeSessionExport, wt as useEnabledToggleSet, x as discoverProjectSkills, xt as fmtTokens, y as buildSkillsConfig, yn as findGitRoot, yr as accentColor, yt as ageString, z as supportsOAuth } from "./turn-operations-DNKpDGQi.js";
|
|
8
9
|
import { spawn } from "node:child_process";
|
|
9
10
|
import { Buffer } from "node:buffer";
|
|
10
11
|
import * as fs from "node:fs";
|
|
11
12
|
import { homedir } from "node:os";
|
|
12
13
|
import { createContext, createElement, memo, useCallback, useContext, useEffect, useMemo, useRef, useState } from "react";
|
|
14
|
+
import { Fragment, jsx, jsxs } from "@opentui/react/jsx-runtime";
|
|
13
15
|
import { BoxRenderable, CodeRenderable, RGBA, SyntaxStyle, TextRenderable, addDefaultParsers, createCliRenderer, decodePasteBytes, defaultTextareaKeyBindings, getTreeSitterClient, stripAnsiSequences } from "@opentui/core";
|
|
14
16
|
import { createRoot, useKeyboard, useRenderer, useSelectionHandler, useTerminalDimensions } from "@opentui/react";
|
|
15
|
-
import { Fragment, jsx, jsxs } from "@opentui/react/jsx-runtime";
|
|
16
17
|
//#region src/tui/modal.tsx
|
|
17
18
|
const ModalContext = createContext(null);
|
|
18
19
|
function ModalRoot({ children }) {
|
|
@@ -318,95 +319,6 @@ function writeToClipboard(text) {
|
|
|
318
319
|
return osc || helper;
|
|
319
320
|
}
|
|
320
321
|
//#endregion
|
|
321
|
-
//#region src/tui/color-gradient.ts
|
|
322
|
-
/** Parse `#rrggbb` (case-insensitive) into `[r, g, b]` 0–255 integers. */
|
|
323
|
-
function parseHex(hex) {
|
|
324
|
-
const h = hex.replace("#", "");
|
|
325
|
-
return [
|
|
326
|
-
Number.parseInt(h.slice(0, 2), 16),
|
|
327
|
-
Number.parseInt(h.slice(2, 4), 16),
|
|
328
|
-
Number.parseInt(h.slice(4, 6), 16)
|
|
329
|
-
];
|
|
330
|
-
}
|
|
331
|
-
/** Convert sRGB 0–255 → HSL 0–1. */
|
|
332
|
-
function rgbToHsl(r, g, b) {
|
|
333
|
-
r /= 255;
|
|
334
|
-
g /= 255;
|
|
335
|
-
b /= 255;
|
|
336
|
-
const max = Math.max(r, g, b);
|
|
337
|
-
const min = Math.min(r, g, b);
|
|
338
|
-
const l = (max + min) / 2;
|
|
339
|
-
if (max === min) return [
|
|
340
|
-
0,
|
|
341
|
-
0,
|
|
342
|
-
l
|
|
343
|
-
];
|
|
344
|
-
const d = max - min;
|
|
345
|
-
const s = l > .5 ? d / (2 - max - min) : d / (max + min);
|
|
346
|
-
let h;
|
|
347
|
-
if (max === r) h = (g - b) / d + (g < b ? 6 : 0);
|
|
348
|
-
else if (max === g) h = (b - r) / d + 2;
|
|
349
|
-
else h = (r - g) / d + 4;
|
|
350
|
-
return [
|
|
351
|
-
h / 6,
|
|
352
|
-
s,
|
|
353
|
-
l
|
|
354
|
-
];
|
|
355
|
-
}
|
|
356
|
-
/** Convert HSL 0–1 → sRGB 0–255. Standard piecewise formula. */
|
|
357
|
-
function hslToRgb(h, s, l) {
|
|
358
|
-
if (s === 0) return [
|
|
359
|
-
l * 255,
|
|
360
|
-
l * 255,
|
|
361
|
-
l * 255
|
|
362
|
-
];
|
|
363
|
-
const hue2rgb = (p, q, t) => {
|
|
364
|
-
if (t < 0) t += 1;
|
|
365
|
-
if (t > 1) t -= 1;
|
|
366
|
-
if (t < 1 / 6) return p + (q - p) * 6 * t;
|
|
367
|
-
if (t < 1 / 2) return q;
|
|
368
|
-
if (t < 2 / 3) return p + (q - p) * (2 / 3 - t) * 6;
|
|
369
|
-
return p;
|
|
370
|
-
};
|
|
371
|
-
const q = l < .5 ? l * (1 + s) : l + s - l * s;
|
|
372
|
-
const p = 2 * l - q;
|
|
373
|
-
return [
|
|
374
|
-
hue2rgb(p, q, h + 1 / 3) * 255,
|
|
375
|
-
hue2rgb(p, q, h) * 255,
|
|
376
|
-
hue2rgb(p, q, h - 1 / 3) * 255
|
|
377
|
-
];
|
|
378
|
-
}
|
|
379
|
-
function toHex(rgb) {
|
|
380
|
-
const pad = (v) => Math.round(Math.max(0, Math.min(255, v))).toString(16).padStart(2, "0");
|
|
381
|
-
return `#${pad(rgb[0])}${pad(rgb[1])}${pad(rgb[2])}`;
|
|
382
|
-
}
|
|
383
|
-
/**
|
|
384
|
-
* Blend two hex colors in HSL space with shortest-path hue interpolation.
|
|
385
|
-
* `t` ∈ [0, 1]; `t=0` returns `from`, `t=1` returns `to`.
|
|
386
|
-
*/
|
|
387
|
-
function blendHsl(from, to, t) {
|
|
388
|
-
const [r1, g1, b1] = parseHex(from);
|
|
389
|
-
const [r2, g2, b2] = parseHex(to);
|
|
390
|
-
const [h1, s1, l1] = rgbToHsl(r1, g1, b1);
|
|
391
|
-
const [h2, s2, l2] = rgbToHsl(r2, g2, b2);
|
|
392
|
-
let dh = h2 - h1;
|
|
393
|
-
if (dh > .5) dh -= 1;
|
|
394
|
-
else if (dh < -.5) dh += 1;
|
|
395
|
-
return toHex(hslToRgb((h1 + dh * t + 1) % 1, s1 + (s2 - s1) * t, l1 + (l2 - l1) * t));
|
|
396
|
-
}
|
|
397
|
-
/**
|
|
398
|
-
* Static gradient ramp of length `n` going from `from` (index 0) to
|
|
399
|
-
* `to` (index n-1) in HSL space. For the cycling A→B→A→B ramp the
|
|
400
|
-
* throbber uses, see `buildCycleRamp` in `crush-throbber.tsx`.
|
|
401
|
-
*/
|
|
402
|
-
function buildLinearRamp(from, to, n) {
|
|
403
|
-
if (n <= 0) return [];
|
|
404
|
-
if (n === 1) return [blendHsl(from, to, .5)];
|
|
405
|
-
const ramp = [];
|
|
406
|
-
for (let i = 0; i < n; i++) ramp.push(blendHsl(from, to, i / (n - 1)));
|
|
407
|
-
return ramp;
|
|
408
|
-
}
|
|
409
|
-
//#endregion
|
|
410
322
|
//#region src/tui/crush-throbber.tsx
|
|
411
323
|
/** @jsxImportSource @opentui/react */
|
|
412
324
|
const CRUSH_RUNES = "0123456789abcdefABCDEF~!@#$£€%^&*()+=_";
|
|
@@ -947,67 +859,6 @@ function metaSegmentsLength(meta) {
|
|
|
947
859
|
if (typeof meta === "string") return meta.length;
|
|
948
860
|
return meta.reduce((sum, seg) => sum + seg.text.length, 0);
|
|
949
861
|
}
|
|
950
|
-
/**
|
|
951
|
-
* Truncate `text` to at most `max` characters, replacing the trailing
|
|
952
|
-
* overflow with `…`. Edge cases:
|
|
953
|
-
* - `max <= 0` → empty string (no room to render at all).
|
|
954
|
-
* - `max === 1` → just the ellipsis glyph.
|
|
955
|
-
* - `text.length <= max` → unchanged.
|
|
956
|
-
*
|
|
957
|
-
* Trailing-style truncation matches the natural read order of titles:
|
|
958
|
-
* the prefix carries enough signal to identify the surface.
|
|
959
|
-
*
|
|
960
|
-
* Exported for unit-tests; consumers should normally lean on
|
|
961
|
-
* {@link TitleOverlay} instead of calling this directly.
|
|
962
|
-
*/
|
|
963
|
-
function truncateTrailing(text, max) {
|
|
964
|
-
if (max <= 0) return "";
|
|
965
|
-
if (text.length <= max) return text;
|
|
966
|
-
if (max === 1) return "…";
|
|
967
|
-
return `${text.slice(0, max - 1)}…`;
|
|
968
|
-
}
|
|
969
|
-
/**
|
|
970
|
-
* Plain-text width estimate for a list of {@link Hint}s rendered via
|
|
971
|
-
* `renderHintSpans` — `<key> <label> · <key> <label> · …`. Exported so
|
|
972
|
-
* the prompt-box overlay (in `screens.tsx`) can run the same responsive
|
|
973
|
-
* math as the bottom-bar footer when deciding whether trigger hints
|
|
974
|
-
* fit. Pure / total.
|
|
975
|
-
*/
|
|
976
|
-
function hintsLength(hints) {
|
|
977
|
-
if (hints.length === 0) return 0;
|
|
978
|
-
return hints.reduce((sum, h, i) => sum + hintLength(h) + (i > 0 ? 3 : 0), 0);
|
|
979
|
-
}
|
|
980
|
-
/** Plain-text width of a single hint as rendered by {@link renderHintSpans}. */
|
|
981
|
-
function hintLength(h) {
|
|
982
|
-
return h.key.length + 1 + h.label.length + (h.extra ? h.extra.key.length + 1 + h.extra.label.length : 0);
|
|
983
|
-
}
|
|
984
|
-
/** Stable empty list so callers can compare by reference. */
|
|
985
|
-
const EMPTY_HINTS = Object.freeze([]);
|
|
986
|
-
/**
|
|
987
|
-
* Return the longest prefix of `hints` whose rendered width via
|
|
988
|
-
* {@link renderHintSpans} fits within `budget`. Used to degrade hint
|
|
989
|
-
* rows gracefully at narrow terminal widths instead of letting OpenTUI
|
|
990
|
-
* wrap an absolutely-positioned `<text>` mid-segment (which paints the
|
|
991
|
-
* overflow over the prompt box's border and looks like garbled glyphs).
|
|
992
|
-
*
|
|
993
|
-
* Prefix-only (no reordering, no last-hint priority) so the survivors
|
|
994
|
-
* keep their authored order — the user's muscle memory for "leftmost
|
|
995
|
-
* hint = primary action" stays intact as the terminal shrinks.
|
|
996
|
-
*/
|
|
997
|
-
function clipHintsToWidth(hints, budget) {
|
|
998
|
-
if (budget <= 0 || hints.length === 0) return EMPTY_HINTS;
|
|
999
|
-
const out = [];
|
|
1000
|
-
let used = 0;
|
|
1001
|
-
for (let i = 0; i < hints.length; i++) {
|
|
1002
|
-
const h = hints[i];
|
|
1003
|
-
const cost = (i > 0 ? 3 : 0) + hintLength(h);
|
|
1004
|
-
if (used + cost > budget) break;
|
|
1005
|
-
out.push(h);
|
|
1006
|
-
used += cost;
|
|
1007
|
-
}
|
|
1008
|
-
if (out.length === 0) return EMPTY_HINTS;
|
|
1009
|
-
return out.length === hints.length ? hints : out;
|
|
1010
|
-
}
|
|
1011
862
|
function contextIndicatorLength(context) {
|
|
1012
863
|
const ratio = context.max > 0 ? context.used / context.max : 0;
|
|
1013
864
|
const pct = Math.round(ratio * 100);
|
|
@@ -1135,41 +986,6 @@ function Transcript({ events, settings, selectedTurnId = null, busy = false }) {
|
|
|
1135
986
|
});
|
|
1136
987
|
}
|
|
1137
988
|
/**
|
|
1138
|
-
* Per-item anchor ids for auto-scroll. Walks `items` in render order and,
|
|
1139
|
-
* for each event, returns either:
|
|
1140
|
-
* - `'turn-anchor-<turnId>'` — the first event of this turn (the
|
|
1141
|
-
* scrollbox's target).
|
|
1142
|
-
* - `undefined` — later event of an already-tagged turn (or a synthetic
|
|
1143
|
-
* event with no `turnId`).
|
|
1144
|
-
*
|
|
1145
|
-
* `ids[i]` is a tuple per item: length 1 for plain events, length N for
|
|
1146
|
-
* subagent runs (one entry per inner event). `idByTurn` is the inverse
|
|
1147
|
-
* lookup used by the scroll effect. `lastTurnId` is the most-recently-
|
|
1148
|
-
* rendered turn — the scroll effect special-cases it to snap to bottom.
|
|
1149
|
-
*
|
|
1150
|
-
* Exported so the anchor-tagging matrix can be unit-tested without rendering.
|
|
1151
|
-
*/
|
|
1152
|
-
function computeTurnAnchors(items) {
|
|
1153
|
-
const idByTurn = /* @__PURE__ */ new Map();
|
|
1154
|
-
let lastTurnId;
|
|
1155
|
-
const tag = (turnId) => {
|
|
1156
|
-
if (!turnId) return void 0;
|
|
1157
|
-
lastTurnId = turnId;
|
|
1158
|
-
if (idByTurn.has(turnId)) return void 0;
|
|
1159
|
-
const id = `turn-anchor-${turnId}`;
|
|
1160
|
-
idByTurn.set(turnId, id);
|
|
1161
|
-
return id;
|
|
1162
|
-
};
|
|
1163
|
-
const ids = [];
|
|
1164
|
-
for (const item of items) if (item.kind === "event") ids.push([tag(item.event.turnId)]);
|
|
1165
|
-
else ids.push(item.events.map((e) => tag(e.turnId)));
|
|
1166
|
-
return {
|
|
1167
|
-
idByTurn,
|
|
1168
|
-
ids,
|
|
1169
|
-
lastTurnId
|
|
1170
|
-
};
|
|
1171
|
-
}
|
|
1172
|
-
/**
|
|
1173
989
|
* Walk the visible-event list once and group consecutive child events
|
|
1174
990
|
* (`depth > 0`) into runs so we can wrap each run in a single bordered
|
|
1175
991
|
* subagent box.
|
|
@@ -1589,7 +1405,7 @@ var CodeBlockWrapper = class extends BoxRenderable {
|
|
|
1589
1405
|
flexDirection: "column",
|
|
1590
1406
|
flexShrink: 0,
|
|
1591
1407
|
alignSelf: "stretch",
|
|
1592
|
-
backgroundColor: surfaces.
|
|
1408
|
+
backgroundColor: surfaces.modal
|
|
1593
1409
|
});
|
|
1594
1410
|
this.body = body;
|
|
1595
1411
|
this.bag = options.bag;
|
|
@@ -1597,11 +1413,12 @@ var CodeBlockWrapper = class extends BoxRenderable {
|
|
|
1597
1413
|
body.marginTop = 0;
|
|
1598
1414
|
body.marginBottom = 0;
|
|
1599
1415
|
body.drawUnstyledText = false;
|
|
1416
|
+
body.bg = surfaces.modal;
|
|
1600
1417
|
this.header = new BoxRenderable(ctx, {
|
|
1601
1418
|
flexDirection: "row",
|
|
1602
1419
|
height: 1,
|
|
1603
1420
|
alignSelf: "stretch",
|
|
1604
|
-
backgroundColor: surfaces.
|
|
1421
|
+
backgroundColor: surfaces.modal
|
|
1605
1422
|
});
|
|
1606
1423
|
this.langLabel = new TextRenderable(ctx, {
|
|
1607
1424
|
content: options.lang && options.lang.length > 0 ? options.lang : "code",
|
|
@@ -1610,7 +1427,7 @@ var CodeBlockWrapper = class extends BoxRenderable {
|
|
|
1610
1427
|
});
|
|
1611
1428
|
this.spacer = new BoxRenderable(ctx, {
|
|
1612
1429
|
flexGrow: 1,
|
|
1613
|
-
backgroundColor: surfaces.
|
|
1430
|
+
backgroundColor: surfaces.modal
|
|
1614
1431
|
});
|
|
1615
1432
|
this.button = new TextRenderable(ctx, {
|
|
1616
1433
|
content: "[copy]",
|
|
@@ -1653,9 +1470,10 @@ var CodeBlockWrapper = class extends BoxRenderable {
|
|
|
1653
1470
|
* `[copy]`/`[copied]` button colour (which depends on `this.copied`).
|
|
1654
1471
|
*/
|
|
1655
1472
|
applyTheme(colors, surfaces) {
|
|
1656
|
-
this.backgroundColor = surfaces.
|
|
1657
|
-
this.header.backgroundColor = surfaces.
|
|
1658
|
-
this.spacer.backgroundColor = surfaces.
|
|
1473
|
+
this.backgroundColor = surfaces.modal;
|
|
1474
|
+
this.header.backgroundColor = surfaces.modal;
|
|
1475
|
+
this.spacer.backgroundColor = surfaces.modal;
|
|
1476
|
+
this.body.bg = surfaces.modal;
|
|
1659
1477
|
this.langLabel.fg = colors.mute;
|
|
1660
1478
|
this.button.fg = this.copied ? colors.accent : colors.warn;
|
|
1661
1479
|
}
|
|
@@ -1684,11 +1502,23 @@ var CodeBlockWrapper = class extends BoxRenderable {
|
|
|
1684
1502
|
set fg(value) {
|
|
1685
1503
|
this.body.fg = value;
|
|
1686
1504
|
}
|
|
1505
|
+
/**
|
|
1506
|
+
* Always reports the live elevated-panel paint: see the setter doc.
|
|
1507
|
+
*/
|
|
1687
1508
|
get bg() {
|
|
1688
1509
|
return this.body.bg;
|
|
1689
1510
|
}
|
|
1690
|
-
|
|
1691
|
-
|
|
1511
|
+
/**
|
|
1512
|
+
* Pinned to {@link ThemeSurfaces.modal} — the elevated code-panel
|
|
1513
|
+
* surface. The markdown's `applyCodeBlockRenderable` writes `bg` on
|
|
1514
|
+
* every delta from whatever surface the parent `<markdown>` carries
|
|
1515
|
+
* (the prose body paint). Forwarding that through would flip the
|
|
1516
|
+
* code panel back to the prose surface on every keystroke and erase
|
|
1517
|
+
* the visual lift. Theme switches are funnelled through
|
|
1518
|
+
* {@link applyTheme} instead, which rewrites `body.bg` directly.
|
|
1519
|
+
*/
|
|
1520
|
+
set bg(_value) {
|
|
1521
|
+
this.body.bg = this.bag.surfaces.modal;
|
|
1692
1522
|
}
|
|
1693
1523
|
get conceal() {
|
|
1694
1524
|
return this.body.conceal;
|
|
@@ -2007,6 +1837,156 @@ function ToolCallBlock({ event, display, dim }) {
|
|
|
2007
1837
|
});
|
|
2008
1838
|
}
|
|
2009
1839
|
//#endregion
|
|
1840
|
+
//#region src/tui/discovery-shell.tsx
|
|
1841
|
+
/**
|
|
1842
|
+
* SWR throttles. `files` is short so a long-open `@` popover picks up
|
|
1843
|
+
* new files within seconds; `skills` is long because SKILL.md changes
|
|
1844
|
+
* are rare and the walk is cheap enough that we already eager-load it.
|
|
1845
|
+
*/
|
|
1846
|
+
const FILES_REFRESH_THROTTLE_MS = 3e3;
|
|
1847
|
+
const SKILLS_REFRESH_THROTTLE_MS = 3e4;
|
|
1848
|
+
function debugLog$1(...args) {
|
|
1849
|
+
if (process.env.ZIDANE_DEBUG) process.stderr.write(`[zidane/tui] ${args.map(errorMessage).join(" ")}\n`);
|
|
1850
|
+
}
|
|
1851
|
+
function DiscoveryShell({ children }) {
|
|
1852
|
+
const config = useConfig();
|
|
1853
|
+
const dispatchAuth = useMcpAuthDispatch();
|
|
1854
|
+
const dispatchAuthRef = useRef(dispatchAuth);
|
|
1855
|
+
dispatchAuthRef.current = dispatchAuth;
|
|
1856
|
+
const [projectDir] = useState(() => findGitRoot(process.cwd()) ?? process.cwd());
|
|
1857
|
+
const dataDir = config.paths.userDir;
|
|
1858
|
+
const mcpCredentialStore = useMemo(() => createFileMcpCredentialStore(dataDir), [dataDir]);
|
|
1859
|
+
const [skillsCatalog, setSkillsCatalog] = useState([]);
|
|
1860
|
+
const [mcpsCatalog, setMcpsCatalog] = useState([]);
|
|
1861
|
+
const [mcpsErrors, setMcpsErrors] = useState([]);
|
|
1862
|
+
const [filesCatalog, setFilesCatalog] = useState([]);
|
|
1863
|
+
const filesSlotRef = useRef(null);
|
|
1864
|
+
const skillsSlotRef = useRef(null);
|
|
1865
|
+
useEffect(() => {
|
|
1866
|
+
filesSlotRef.current?.abort();
|
|
1867
|
+
skillsSlotRef.current?.abort();
|
|
1868
|
+
setFilesCatalog([]);
|
|
1869
|
+
setSkillsCatalog([]);
|
|
1870
|
+
const filesSlot = createDiscoverySlot({
|
|
1871
|
+
throttleMs: FILES_REFRESH_THROTTLE_MS,
|
|
1872
|
+
walk: (signal) => listProjectFiles({
|
|
1873
|
+
cwd: projectDir,
|
|
1874
|
+
signal
|
|
1875
|
+
}),
|
|
1876
|
+
onLoad: (items) => {
|
|
1877
|
+
if (filesSlotRef.current === filesSlot) setFilesCatalog(items);
|
|
1878
|
+
},
|
|
1879
|
+
onError: (err, phase) => {
|
|
1880
|
+
debugLog$1(`listProjectFiles ${phase} failed`, err);
|
|
1881
|
+
}
|
|
1882
|
+
});
|
|
1883
|
+
const skillsSlot = createDiscoverySlot({
|
|
1884
|
+
throttleMs: SKILLS_REFRESH_THROTTLE_MS,
|
|
1885
|
+
walk: () => discoverProjectSkills({
|
|
1886
|
+
cwd: projectDir,
|
|
1887
|
+
prefix: config.prefix
|
|
1888
|
+
}),
|
|
1889
|
+
onLoad: (items) => {
|
|
1890
|
+
if (skillsSlotRef.current === skillsSlot) setSkillsCatalog(items);
|
|
1891
|
+
},
|
|
1892
|
+
onError: (err, phase) => {
|
|
1893
|
+
debugLog$1(`discoverProjectSkills ${phase} failed`, err);
|
|
1894
|
+
}
|
|
1895
|
+
});
|
|
1896
|
+
filesSlotRef.current = filesSlot;
|
|
1897
|
+
skillsSlotRef.current = skillsSlot;
|
|
1898
|
+
skillsSlot.ensure().then((skills) => bootTick(`discovery:skills (${skills.length})`));
|
|
1899
|
+
try {
|
|
1900
|
+
const { servers, errors } = discoverProjectMcps({
|
|
1901
|
+
cwd: projectDir,
|
|
1902
|
+
prefix: config.prefix
|
|
1903
|
+
});
|
|
1904
|
+
setMcpsCatalog(servers);
|
|
1905
|
+
setMcpsErrors(errors);
|
|
1906
|
+
bootTick(`discovery:mcps (${servers.length} servers, ${errors.length} parse errors)`);
|
|
1907
|
+
for (const entry of servers) {
|
|
1908
|
+
if (entry.config.auth !== "oauth") continue;
|
|
1909
|
+
const hasTokens = !!mcpCredentialStore.load(entry.config.name)?.tokens;
|
|
1910
|
+
dispatchAuthRef.current(hasTokens ? {
|
|
1911
|
+
type: "auth-success",
|
|
1912
|
+
name: entry.config.name
|
|
1913
|
+
} : {
|
|
1914
|
+
type: "auth-required",
|
|
1915
|
+
name: entry.config.name,
|
|
1916
|
+
reason: "no-tokens"
|
|
1917
|
+
});
|
|
1918
|
+
}
|
|
1919
|
+
} catch (err) {
|
|
1920
|
+
debugLog$1("discoverProjectMcps failed", err);
|
|
1921
|
+
}
|
|
1922
|
+
return () => {
|
|
1923
|
+
filesSlot.abort();
|
|
1924
|
+
skillsSlot.abort();
|
|
1925
|
+
};
|
|
1926
|
+
}, [
|
|
1927
|
+
projectDir,
|
|
1928
|
+
config.prefix,
|
|
1929
|
+
mcpCredentialStore
|
|
1930
|
+
]);
|
|
1931
|
+
const ensureFiles = useCallback(() => filesSlotRef.current?.ensure() ?? Promise.resolve([]), []);
|
|
1932
|
+
const ensureSkills = useCallback(() => skillsSlotRef.current?.ensure() ?? Promise.resolve([]), []);
|
|
1933
|
+
const refreshFiles = useCallback(() => filesSlotRef.current?.refresh() ?? Promise.resolve(), []);
|
|
1934
|
+
const refreshSkills = useCallback(() => skillsSlotRef.current?.refresh() ?? Promise.resolve(), []);
|
|
1935
|
+
const refreshMcps = useCallback(() => {
|
|
1936
|
+
try {
|
|
1937
|
+
const { servers, errors } = discoverProjectMcps({
|
|
1938
|
+
cwd: projectDir,
|
|
1939
|
+
prefix: config.prefix
|
|
1940
|
+
});
|
|
1941
|
+
setMcpsCatalog(servers);
|
|
1942
|
+
setMcpsErrors(errors);
|
|
1943
|
+
for (const entry of servers) {
|
|
1944
|
+
if (entry.config.auth !== "oauth") continue;
|
|
1945
|
+
const hasTokens = !!mcpCredentialStore.load(entry.config.name)?.tokens;
|
|
1946
|
+
dispatchAuthRef.current(hasTokens ? {
|
|
1947
|
+
type: "auth-success",
|
|
1948
|
+
name: entry.config.name
|
|
1949
|
+
} : {
|
|
1950
|
+
type: "auth-required",
|
|
1951
|
+
name: entry.config.name,
|
|
1952
|
+
reason: "no-tokens"
|
|
1953
|
+
});
|
|
1954
|
+
}
|
|
1955
|
+
} catch (err) {
|
|
1956
|
+
debugLog$1("refreshMcps failed", err);
|
|
1957
|
+
}
|
|
1958
|
+
return Promise.resolve();
|
|
1959
|
+
}, [
|
|
1960
|
+
projectDir,
|
|
1961
|
+
config.prefix,
|
|
1962
|
+
mcpCredentialStore
|
|
1963
|
+
]);
|
|
1964
|
+
return /* @__PURE__ */ jsx(DiscoveryProvider, {
|
|
1965
|
+
value: useMemo(() => ({
|
|
1966
|
+
skillsCatalog,
|
|
1967
|
+
mcpsCatalog,
|
|
1968
|
+
mcpsErrors,
|
|
1969
|
+
filesCatalog,
|
|
1970
|
+
refreshSkills,
|
|
1971
|
+
refreshMcps,
|
|
1972
|
+
refreshFiles,
|
|
1973
|
+
ensureSkills,
|
|
1974
|
+
ensureFiles
|
|
1975
|
+
}), [
|
|
1976
|
+
skillsCatalog,
|
|
1977
|
+
mcpsCatalog,
|
|
1978
|
+
mcpsErrors,
|
|
1979
|
+
filesCatalog,
|
|
1980
|
+
refreshSkills,
|
|
1981
|
+
refreshMcps,
|
|
1982
|
+
refreshFiles,
|
|
1983
|
+
ensureSkills,
|
|
1984
|
+
ensureFiles
|
|
1985
|
+
]),
|
|
1986
|
+
children
|
|
1987
|
+
});
|
|
1988
|
+
}
|
|
1989
|
+
//#endregion
|
|
2010
1990
|
//#region src/tui/effort-picker.tsx
|
|
2011
1991
|
const BASE_LEVELS = [
|
|
2012
1992
|
{
|
|
@@ -2665,7 +2645,7 @@ function FileEditApprovalModal({ request, onDecide }) {
|
|
|
2665
2645
|
return [fs.readFileSync(targetPath, "utf8"), null];
|
|
2666
2646
|
} catch (e) {
|
|
2667
2647
|
if (e.code === "ENOENT") return ["", null];
|
|
2668
|
-
return ["", e
|
|
2648
|
+
return ["", errorMessage(e)];
|
|
2669
2649
|
}
|
|
2670
2650
|
}, [targetPath]);
|
|
2671
2651
|
const payload = useMemo(() => {
|
|
@@ -3679,7 +3659,7 @@ function SetupWizard({ registry, dataDir, onConfigured, onCancel }) {
|
|
|
3679
3659
|
if (descriptor.envKey) process.env[descriptor.envKey] = trimmed;
|
|
3680
3660
|
onConfigured();
|
|
3681
3661
|
} catch (err) {
|
|
3682
|
-
setError(
|
|
3662
|
+
setError(errorMessage(err));
|
|
3683
3663
|
}
|
|
3684
3664
|
}, [dataDir, onConfigured]);
|
|
3685
3665
|
const onOAuthError = useCallback((msg) => {
|
|
@@ -3935,7 +3915,7 @@ function OAuthRunningStep({ descriptor, dataDir, onSuccess, onError }) {
|
|
|
3935
3915
|
onSuccess();
|
|
3936
3916
|
} catch (err) {
|
|
3937
3917
|
if (cancelled) return;
|
|
3938
|
-
onError(
|
|
3918
|
+
onError(errorMessage(err));
|
|
3939
3919
|
}
|
|
3940
3920
|
})();
|
|
3941
3921
|
return () => {
|
|
@@ -5229,7 +5209,7 @@ function SessionDetailsModal({ session, title, isCurrent, actions, keybindings }
|
|
|
5229
5209
|
setExportStatus("success");
|
|
5230
5210
|
} catch (err) {
|
|
5231
5211
|
if (!mountedRef.current) return;
|
|
5232
|
-
setExportError(
|
|
5212
|
+
setExportError(errorMessage(err));
|
|
5233
5213
|
setExportStatus("failed");
|
|
5234
5214
|
}
|
|
5235
5215
|
};
|
|
@@ -5246,7 +5226,7 @@ function SessionDetailsModal({ session, title, isCurrent, actions, keybindings }
|
|
|
5246
5226
|
setTitleStatus("idle");
|
|
5247
5227
|
} catch (err) {
|
|
5248
5228
|
if (!mountedRef.current || ac.signal.aborted) return;
|
|
5249
|
-
setTitleError(
|
|
5229
|
+
setTitleError(errorMessage(err));
|
|
5250
5230
|
setTitleStatus("failed");
|
|
5251
5231
|
} finally {
|
|
5252
5232
|
if (generationAbortRef.current === ac) generationAbortRef.current = null;
|
|
@@ -5265,7 +5245,7 @@ function SessionDetailsModal({ session, title, isCurrent, actions, keybindings }
|
|
|
5265
5245
|
setCompactStatus("success");
|
|
5266
5246
|
} catch (err) {
|
|
5267
5247
|
if (!mountedRef.current || ac.signal.aborted) return;
|
|
5268
|
-
setCompactError(
|
|
5248
|
+
setCompactError(errorMessage(err));
|
|
5269
5249
|
setCompactStatus("failed");
|
|
5270
5250
|
} finally {
|
|
5271
5251
|
if (compactAbortRef.current === ac) compactAbortRef.current = null;
|
|
@@ -5829,13 +5809,17 @@ function anchorIdFor(index) {
|
|
|
5829
5809
|
}
|
|
5830
5810
|
const COL_TITLE = " ";
|
|
5831
5811
|
const SPACER_CHECKBOX_WIDTH = " ";
|
|
5832
|
-
function SettingsModal({ skillsCatalog
|
|
5812
|
+
function SettingsModal({ skillsCatalog: skillsCatalogProp, mcpsCatalog: mcpsCatalogProp, mcpsErrors: mcpsErrorsProp, actions } = {}) {
|
|
5833
5813
|
const COLOR = useColors();
|
|
5834
5814
|
const SURFACE = useSurfaces();
|
|
5835
5815
|
const { settings, toggle: toggleBoolean, setSetting } = useSettings();
|
|
5836
5816
|
const authState = useMcpAuthState();
|
|
5837
5817
|
const inputRef = useRef(null);
|
|
5838
5818
|
const scrollboxRef = useRef(null);
|
|
5819
|
+
const discovery = useDiscoveryOptional();
|
|
5820
|
+
const skillsCatalog = discovery?.skillsCatalog ?? skillsCatalogProp ?? [];
|
|
5821
|
+
const mcpsCatalog = discovery?.mcpsCatalog ?? mcpsCatalogProp ?? [];
|
|
5822
|
+
const mcpsErrors = discovery?.mcpsErrors ?? mcpsErrorsProp;
|
|
5839
5823
|
const skillsToggle = useEnabledToggleSet({
|
|
5840
5824
|
catalog: skillsCatalog,
|
|
5841
5825
|
keyOf: (s) => s.name,
|
|
@@ -5975,6 +5959,13 @@ function SettingsModal({ skillsCatalog = [], mcpsCatalog = [], mcpsErrors, actio
|
|
|
5975
5959
|
}
|
|
5976
5960
|
if (key.name === "escape" && focusedMcpStatus.kind === "authorizing") actions?.onCancelLoginMcp?.(focusedMcp.config.name);
|
|
5977
5961
|
}
|
|
5962
|
+
if (key.ctrl && key.name === "r") {
|
|
5963
|
+
if (activeTab === "skills" && actions?.onRefreshSkills) {
|
|
5964
|
+
actions.onRefreshSkills();
|
|
5965
|
+
return;
|
|
5966
|
+
}
|
|
5967
|
+
if (activeTab === "mcps" && actions?.onRefreshMcps) actions.onRefreshMcps();
|
|
5968
|
+
}
|
|
5978
5969
|
});
|
|
5979
5970
|
return /* @__PURE__ */ jsxs(Modal, {
|
|
5980
5971
|
title: "settings",
|
|
@@ -6067,7 +6058,9 @@ function SettingsModal({ skillsCatalog = [], mcpsCatalog = [], mcpsErrors, actio
|
|
|
6067
6058
|
children: /* @__PURE__ */ jsx(Hints, {
|
|
6068
6059
|
activeTab,
|
|
6069
6060
|
focusedMcp,
|
|
6070
|
-
focusedMcpStatus
|
|
6061
|
+
focusedMcpStatus,
|
|
6062
|
+
canRefreshSkills: !!actions?.onRefreshSkills,
|
|
6063
|
+
canRefreshMcps: !!actions?.onRefreshMcps
|
|
6071
6064
|
})
|
|
6072
6065
|
})
|
|
6073
6066
|
]
|
|
@@ -6522,11 +6515,12 @@ function renderMcpErrors(errors, home, warnColor) {
|
|
|
6522
6515
|
}, err.path))
|
|
6523
6516
|
});
|
|
6524
6517
|
}
|
|
6525
|
-
function Hints({ activeTab, focusedMcp, focusedMcpStatus }) {
|
|
6518
|
+
function Hints({ activeTab, focusedMcp, focusedMcpStatus, canRefreshSkills, canRefreshMcps }) {
|
|
6526
6519
|
const COLOR = useColors();
|
|
6527
6520
|
const showLogin = activeTab === "mcps" && !!focusedMcp && !!focusedMcpStatus && canLogin$1(focusedMcp, focusedMcpStatus);
|
|
6528
6521
|
const showLogout = activeTab === "mcps" && !!focusedMcpStatus && canLogout$1(focusedMcpStatus);
|
|
6529
6522
|
const showCancel = activeTab === "mcps" && focusedMcpStatus?.kind === "authorizing";
|
|
6523
|
+
const showRefresh = activeTab === "skills" && canRefreshSkills || activeTab === "mcps" && canRefreshMcps;
|
|
6530
6524
|
return /* @__PURE__ */ jsxs("text", {
|
|
6531
6525
|
fg: COLOR.mute,
|
|
6532
6526
|
children: [
|
|
@@ -6561,6 +6555,14 @@ function Hints({ activeTab, focusedMcp, focusedMcpStatus }) {
|
|
|
6561
6555
|
}),
|
|
6562
6556
|
" logout"
|
|
6563
6557
|
] }),
|
|
6558
|
+
showRefresh && /* @__PURE__ */ jsxs("span", { children: [
|
|
6559
|
+
" · ",
|
|
6560
|
+
/* @__PURE__ */ jsx("span", {
|
|
6561
|
+
fg: COLOR.warn,
|
|
6562
|
+
children: "ctrl+R"
|
|
6563
|
+
}),
|
|
6564
|
+
" refresh"
|
|
6565
|
+
] }),
|
|
6564
6566
|
showCancel ? /* @__PURE__ */ jsxs("span", { children: [
|
|
6565
6567
|
" · ",
|
|
6566
6568
|
/* @__PURE__ */ jsx("span", {
|
|
@@ -6976,16 +6978,20 @@ function ThemedShell() {
|
|
|
6976
6978
|
const { settings } = useSettings();
|
|
6977
6979
|
return /* @__PURE__ */ jsx(ThemeProvider, {
|
|
6978
6980
|
theme: useMemo(() => resolveTheme(settings.theme), [settings.theme]),
|
|
6979
|
-
children: /* @__PURE__ */ jsx(MdStyleProvider, { children: /* @__PURE__ */ jsx(ChipStyleProvider, { children: /* @__PURE__ */ jsx(SafeModeProvider, { children: /* @__PURE__ */ jsx(InteractionsProvider, { children: /* @__PURE__ */ jsx(McpAuthProvider, { children: /* @__PURE__ */ jsx(ModalRoot, { children: /* @__PURE__ */ jsx(AppShell, {}) }) }) }) }) }) })
|
|
6981
|
+
children: /* @__PURE__ */ jsx(MdStyleProvider, { children: /* @__PURE__ */ jsx(ChipStyleProvider, { children: /* @__PURE__ */ jsx(SafeModeProvider, { children: /* @__PURE__ */ jsx(InteractionsProvider, { children: /* @__PURE__ */ jsx(McpAuthProvider, { children: /* @__PURE__ */ jsx(DiscoveryShell, { children: /* @__PURE__ */ jsx(ModalRoot, { children: /* @__PURE__ */ jsx(AppShell, {}) }) }) }) }) }) }) })
|
|
6980
6982
|
});
|
|
6981
6983
|
}
|
|
6982
6984
|
function AppShell() {
|
|
6985
|
+
bootTick("AppShell:render-enter");
|
|
6983
6986
|
const renderer = useRenderer();
|
|
6984
6987
|
const modal = useModal();
|
|
6985
6988
|
const config = useConfig();
|
|
6986
6989
|
const { settings } = useSettings();
|
|
6987
6990
|
const COLOR = useColors();
|
|
6988
6991
|
const SURFACE = useSurfaces();
|
|
6992
|
+
useEffect(() => {
|
|
6993
|
+
bootTick("AppShell:first-effect (post-first-paint)");
|
|
6994
|
+
}, []);
|
|
6989
6995
|
const queue = useSafeModeQueue();
|
|
6990
6996
|
const { requestApproval, resolveHead, denyAll } = useSafeModeActions();
|
|
6991
6997
|
const pendingApproval = queue[0] ?? null;
|
|
@@ -7045,70 +7051,11 @@ function AppShell() {
|
|
|
7045
7051
|
safelistRef.current = null;
|
|
7046
7052
|
}, [dataDir, projectDir]);
|
|
7047
7053
|
const sessionSafelistRef = useRef(/* @__PURE__ */ new Set());
|
|
7048
|
-
const
|
|
7049
|
-
const [mcpsCatalog, setMcpsCatalog] = useState([]);
|
|
7050
|
-
const [mcpsErrors, setMcpsErrors] = useState([]);
|
|
7051
|
-
const [filesCatalog, setFilesCatalog] = useState([]);
|
|
7054
|
+
const { skillsCatalog, mcpsCatalog, filesCatalog, ensureFiles: ensureFilesCatalog, ensureSkills: ensureSkillsCatalog, refreshSkills: onRefreshSkills, refreshMcps: onRefreshMcps } = useDiscovery();
|
|
7052
7055
|
const mcpCredentialStore = useMemo(() => createFileMcpCredentialStore(dataDir), [dataDir]);
|
|
7053
7056
|
const dispatchAuth = useMcpAuthDispatch();
|
|
7054
7057
|
const dispatchAuthRef = useRef(dispatchAuth);
|
|
7055
7058
|
dispatchAuthRef.current = dispatchAuth;
|
|
7056
|
-
useEffect(() => {
|
|
7057
|
-
const ac = new AbortController();
|
|
7058
|
-
let cancelled = false;
|
|
7059
|
-
(async () => {
|
|
7060
|
-
try {
|
|
7061
|
-
const skills = await discoverProjectSkills({
|
|
7062
|
-
cwd: projectDir,
|
|
7063
|
-
prefix: config.prefix
|
|
7064
|
-
});
|
|
7065
|
-
if (!cancelled) setSkillsCatalog(skills);
|
|
7066
|
-
} catch (err) {
|
|
7067
|
-
debugLog("discoverProjectSkills failed", err);
|
|
7068
|
-
}
|
|
7069
|
-
})();
|
|
7070
|
-
(async () => {
|
|
7071
|
-
try {
|
|
7072
|
-
const files = await listProjectFiles({
|
|
7073
|
-
cwd: projectDir,
|
|
7074
|
-
signal: ac.signal
|
|
7075
|
-
});
|
|
7076
|
-
if (!cancelled) setFilesCatalog(files);
|
|
7077
|
-
} catch (err) {
|
|
7078
|
-
debugLog("listProjectFiles failed", err);
|
|
7079
|
-
}
|
|
7080
|
-
})();
|
|
7081
|
-
try {
|
|
7082
|
-
const { servers, errors } = discoverProjectMcps({
|
|
7083
|
-
cwd: projectDir,
|
|
7084
|
-
prefix: config.prefix
|
|
7085
|
-
});
|
|
7086
|
-
setMcpsCatalog(servers);
|
|
7087
|
-
setMcpsErrors(errors);
|
|
7088
|
-
for (const entry of servers) {
|
|
7089
|
-
if (entry.config.auth !== "oauth") continue;
|
|
7090
|
-
const hasTokens = !!mcpCredentialStore.load(entry.config.name)?.tokens;
|
|
7091
|
-
dispatchAuthRef.current(hasTokens ? {
|
|
7092
|
-
type: "auth-success",
|
|
7093
|
-
name: entry.config.name
|
|
7094
|
-
} : {
|
|
7095
|
-
type: "auth-required",
|
|
7096
|
-
name: entry.config.name,
|
|
7097
|
-
reason: "no-tokens"
|
|
7098
|
-
});
|
|
7099
|
-
}
|
|
7100
|
-
} catch (err) {
|
|
7101
|
-
debugLog("discoverProjectMcps failed", err);
|
|
7102
|
-
}
|
|
7103
|
-
return () => {
|
|
7104
|
-
cancelled = true;
|
|
7105
|
-
ac.abort();
|
|
7106
|
-
};
|
|
7107
|
-
}, [
|
|
7108
|
-
projectDir,
|
|
7109
|
-
config.prefix,
|
|
7110
|
-
mcpCredentialStore
|
|
7111
|
-
]);
|
|
7112
7059
|
const skillsCatalogRef = useRef(skillsCatalog);
|
|
7113
7060
|
skillsCatalogRef.current = skillsCatalog;
|
|
7114
7061
|
const enabledSkillsRef = useRef(settings.enabledSkills);
|
|
@@ -7119,10 +7066,18 @@ function AppShell() {
|
|
|
7119
7066
|
enabledMcpsRef.current = settings.enabledMcps;
|
|
7120
7067
|
const filesCatalogRef = useRef(filesCatalog);
|
|
7121
7068
|
filesCatalogRef.current = filesCatalog;
|
|
7069
|
+
const ensureFilesCatalogRef = useRef(ensureFilesCatalog);
|
|
7070
|
+
ensureFilesCatalogRef.current = ensureFilesCatalog;
|
|
7071
|
+
const ensureSkillsCatalogRef = useRef(ensureSkillsCatalog);
|
|
7072
|
+
ensureSkillsCatalogRef.current = ensureSkillsCatalog;
|
|
7122
7073
|
const completionProviders = useMemo(() => [createSkillsCompletionProvider({
|
|
7123
7074
|
getCatalog: () => skillsCatalogRef.current,
|
|
7124
|
-
getEnabled: () => enabledSkillsRef.current
|
|
7125
|
-
|
|
7075
|
+
getEnabled: () => enabledSkillsRef.current,
|
|
7076
|
+
ensureCatalog: () => ensureSkillsCatalogRef.current()
|
|
7077
|
+
}), createFilesCompletionProvider({
|
|
7078
|
+
getCatalog: () => filesCatalogRef.current,
|
|
7079
|
+
ensureCatalog: () => ensureFilesCatalogRef.current()
|
|
7080
|
+
})], [filesCatalog, skillsCatalog]);
|
|
7126
7081
|
/**
|
|
7127
7082
|
* Single source of truth for "should this call execute?". Returns true to
|
|
7128
7083
|
* let the call through, false to refuse it. Handles three short-circuits:
|
|
@@ -7618,7 +7573,7 @@ function AppShell() {
|
|
|
7618
7573
|
} catch (err) {
|
|
7619
7574
|
stream.appendImmediate({
|
|
7620
7575
|
kind: "error",
|
|
7621
|
-
text:
|
|
7576
|
+
text: errorMessage(err)
|
|
7622
7577
|
});
|
|
7623
7578
|
} finally {
|
|
7624
7579
|
stream.flushAndUpdate(finalizeStreamingMarkdown);
|
|
@@ -7687,13 +7642,19 @@ function AppShell() {
|
|
|
7687
7642
|
const sessionMatchesProject = settings.showAllProjects || data?.projectRoot != null && data.projectRoot === projectDir;
|
|
7688
7643
|
if (data && sessionMatchesProject) {
|
|
7689
7644
|
await activateSession(lastResumedSessionId, resumeProvider.key);
|
|
7645
|
+
bootTick(`resume:activate (sessionId=${lastResumedSessionId.slice(-8)})`);
|
|
7690
7646
|
return;
|
|
7691
7647
|
}
|
|
7692
7648
|
}
|
|
7693
7649
|
const list = await refreshSessions();
|
|
7694
7650
|
if (cancelled) return;
|
|
7695
|
-
if (list.length === 0)
|
|
7696
|
-
|
|
7651
|
+
if (list.length === 0) {
|
|
7652
|
+
await activateSession(null, resumeProvider.key);
|
|
7653
|
+
bootTick("resume:fresh-session (empty list)");
|
|
7654
|
+
} else {
|
|
7655
|
+
setScreen("sessions");
|
|
7656
|
+
bootTick(`resume:sessions-list (${list.length})`);
|
|
7657
|
+
}
|
|
7697
7658
|
})();
|
|
7698
7659
|
return () => {
|
|
7699
7660
|
cancelled = true;
|
|
@@ -8008,7 +7969,7 @@ function AppShell() {
|
|
|
8008
7969
|
} catch (err) {
|
|
8009
7970
|
stream.appendImmediate({
|
|
8010
7971
|
kind: "error",
|
|
8011
|
-
text:
|
|
7972
|
+
text: errorMessage(err)
|
|
8012
7973
|
});
|
|
8013
7974
|
} finally {
|
|
8014
7975
|
stream.flushAndUpdate(finalizeStreamingMarkdown);
|
|
@@ -8107,7 +8068,7 @@ function AppShell() {
|
|
|
8107
8068
|
if (!agentRef.current) dispatchAuth({
|
|
8108
8069
|
type: "auth-error",
|
|
8109
8070
|
name,
|
|
8110
|
-
error:
|
|
8071
|
+
error: errorMessage(err)
|
|
8111
8072
|
});
|
|
8112
8073
|
} finally {
|
|
8113
8074
|
mcpLoginAbortsRef.current.delete(name);
|
|
@@ -8434,7 +8395,7 @@ function AppShell() {
|
|
|
8434
8395
|
if (abort.signal.aborted) return;
|
|
8435
8396
|
stream.appendImmediate({
|
|
8436
8397
|
kind: "error",
|
|
8437
|
-
text: `Auto-compaction failed: ${
|
|
8398
|
+
text: `Auto-compaction failed: ${errorMessage(err)}`
|
|
8438
8399
|
});
|
|
8439
8400
|
}).finally(() => {
|
|
8440
8401
|
if (autoCompactInFlightRef.current === compactionPromise) {
|
|
@@ -8578,18 +8539,15 @@ function AppShell() {
|
|
|
8578
8539
|
return;
|
|
8579
8540
|
}
|
|
8580
8541
|
if (matchesBinding(key, keybindings.openSettings) && screen !== "auth") {
|
|
8581
|
-
modal.open(/* @__PURE__ */ jsx(SettingsModal, {
|
|
8582
|
-
|
|
8583
|
-
|
|
8584
|
-
|
|
8585
|
-
|
|
8586
|
-
|
|
8587
|
-
|
|
8588
|
-
|
|
8589
|
-
|
|
8590
|
-
onCancelLoginMcp
|
|
8591
|
-
}
|
|
8592
|
-
}));
|
|
8542
|
+
modal.open(/* @__PURE__ */ jsx(SettingsModal, { actions: {
|
|
8543
|
+
onReauth,
|
|
8544
|
+
onOpenKeybindings: onOpenKeybindingsFile,
|
|
8545
|
+
onLoginMcp,
|
|
8546
|
+
onLogoutMcp,
|
|
8547
|
+
onCancelLoginMcp,
|
|
8548
|
+
onRefreshSkills,
|
|
8549
|
+
onRefreshMcps
|
|
8550
|
+
} }));
|
|
8593
8551
|
return;
|
|
8594
8552
|
}
|
|
8595
8553
|
if (matchesBinding(key, keybindings.openSessionDetails)) {
|
|
@@ -8691,23 +8649,16 @@ function AppShell() {
|
|
|
8691
8649
|
drop: keybindings.dropQueuedMessage
|
|
8692
8650
|
}), [keybindings]);
|
|
8693
8651
|
const promptTriggerHints = useMemo(() => {
|
|
8694
|
-
|
|
8695
|
-
if (filesCatalog.length > 0) out.push({
|
|
8652
|
+
return [{
|
|
8696
8653
|
key: "@",
|
|
8697
8654
|
label: "files",
|
|
8698
8655
|
keyColor: resolveChipColor(SURFACE.chips, "files").bg
|
|
8699
|
-
}
|
|
8700
|
-
if (skillsCatalog.length > 0) out.push({
|
|
8656
|
+
}, {
|
|
8701
8657
|
key: "/",
|
|
8702
8658
|
label: "skills",
|
|
8703
8659
|
keyColor: resolveChipColor(SURFACE.chips, "skills").bg
|
|
8704
|
-
}
|
|
8705
|
-
|
|
8706
|
-
}, [
|
|
8707
|
-
filesCatalog,
|
|
8708
|
-
skillsCatalog,
|
|
8709
|
-
SURFACE
|
|
8710
|
-
]);
|
|
8660
|
+
}];
|
|
8661
|
+
}, [SURFACE]);
|
|
8711
8662
|
const contextUsage = useMemo(() => {
|
|
8712
8663
|
if (screen !== "chat" || !picked) return null;
|
|
8713
8664
|
const descriptor = providerRegistry[picked.provider.key];
|
|
@@ -9085,16 +9036,45 @@ function resolveLocalParsers() {
|
|
|
9085
9036
|
return resolved;
|
|
9086
9037
|
}
|
|
9087
9038
|
let registered = false;
|
|
9039
|
+
let workerInitStarted = false;
|
|
9088
9040
|
/**
|
|
9089
|
-
*
|
|
9090
|
-
*
|
|
9091
|
-
*
|
|
9041
|
+
* Synchronously append every URL-fetched + locally-vendored grammar to
|
|
9042
|
+
* OpenTUI's global parser registry. Cheap (just a couple of `Array.push`
|
|
9043
|
+
* calls into a module-level table) and idempotent — subsequent calls
|
|
9044
|
+
* are no-ops.
|
|
9045
|
+
*
|
|
9046
|
+
* Split out from {@link initTreeSitterWorker} so the boot path can land
|
|
9047
|
+
* the registry *synchronously* on its critical path (no awaiting
|
|
9048
|
+
* required) and defer the heavier worker spin-up below until after the
|
|
9049
|
+
* first frame is on screen. OpenTUI's `highlightOnce` self-initialises
|
|
9050
|
+
* the worker on first use anyway — registering parsers ahead of time is
|
|
9051
|
+
* the only piece that genuinely has to happen synchronously.
|
|
9092
9052
|
*/
|
|
9093
|
-
|
|
9053
|
+
function registerTreeSitterParsers() {
|
|
9094
9054
|
if (registered) return;
|
|
9095
9055
|
registered = true;
|
|
9096
9056
|
addDefaultParsers([...EXTRA_PARSERS, ...resolveLocalParsers()]);
|
|
9097
|
-
|
|
9057
|
+
}
|
|
9058
|
+
/**
|
|
9059
|
+
* Spin up OpenTUI's parser worker thread. Idempotent — concurrent
|
|
9060
|
+
* callers share a single in-flight promise; subsequent calls after
|
|
9061
|
+
* resolution are no-ops.
|
|
9062
|
+
*
|
|
9063
|
+
* Safe to fire-and-forget after the renderer mounts: the worker boot
|
|
9064
|
+
* is the heaviest step in tree-sitter setup (~40–100ms on most
|
|
9065
|
+
* machines) and nothing visible needs it until the first fenced code
|
|
9066
|
+
* block highlight, which is many frames away even on the fastest
|
|
9067
|
+
* sessions. If a `<markdown>` element happens to call
|
|
9068
|
+
* `highlightOnce()` before our explicit init completes, OpenTUI's
|
|
9069
|
+
* client guards that call with its own `if (!this.initialized) await
|
|
9070
|
+
* this.initialize()` — no race.
|
|
9071
|
+
*/
|
|
9072
|
+
function initTreeSitterWorker() {
|
|
9073
|
+
if (!workerInitStarted) {
|
|
9074
|
+
workerInitStarted = true;
|
|
9075
|
+
registerTreeSitterParsers();
|
|
9076
|
+
}
|
|
9077
|
+
return getTreeSitterClient().initialize();
|
|
9098
9078
|
}
|
|
9099
9079
|
//#endregion
|
|
9100
9080
|
//#region src/tui/mcps-settings.tsx
|
|
@@ -9125,7 +9105,7 @@ async function setupTreeSitter() {
|
|
|
9125
9105
|
* Errors (`DiscoveryError[]`) surface in a warn-colored preamble so a
|
|
9126
9106
|
* broken `mcps.json` is loud rather than invisible.
|
|
9127
9107
|
*/
|
|
9128
|
-
function McpsSettingsModal({ catalog, errors, onLogin, onLogout, onCancelLogin }) {
|
|
9108
|
+
function McpsSettingsModal({ catalog, errors, onLogin, onLogout, onCancelLogin, onRefresh }) {
|
|
9129
9109
|
const COLOR = useColors();
|
|
9130
9110
|
const home = homedir();
|
|
9131
9111
|
const authState = useMcpAuthState();
|
|
@@ -9166,7 +9146,11 @@ function McpsSettingsModal({ catalog, errors, onLogin, onLogout, onCancelLogin }
|
|
|
9166
9146
|
onLogin(name);
|
|
9167
9147
|
return;
|
|
9168
9148
|
}
|
|
9169
|
-
if (key.name === "o" && canLogout(status))
|
|
9149
|
+
if (key.name === "o" && canLogout(status)) {
|
|
9150
|
+
onLogout(name);
|
|
9151
|
+
return;
|
|
9152
|
+
}
|
|
9153
|
+
if (key.name === "r" && onRefresh) onRefresh();
|
|
9170
9154
|
});
|
|
9171
9155
|
if (catalog.length === 0) return /* @__PURE__ */ jsxs(Modal, {
|
|
9172
9156
|
title: "mcp servers",
|
|
@@ -9227,10 +9211,17 @@ function McpsSettingsModal({ catalog, errors, onLogin, onLogout, onCancelLogin }
|
|
|
9227
9211
|
}),
|
|
9228
9212
|
/* @__PURE__ */ jsxs("text", {
|
|
9229
9213
|
fg: COLOR.mute,
|
|
9230
|
-
children: [
|
|
9231
|
-
|
|
9232
|
-
|
|
9233
|
-
|
|
9214
|
+
children: [
|
|
9215
|
+
onRefresh && /* @__PURE__ */ jsxs("span", { children: [/* @__PURE__ */ jsx("span", {
|
|
9216
|
+
fg: COLOR.warn,
|
|
9217
|
+
children: "r"
|
|
9218
|
+
}), " refresh · "] }),
|
|
9219
|
+
/* @__PURE__ */ jsx("span", {
|
|
9220
|
+
fg: COLOR.warn,
|
|
9221
|
+
children: "esc"
|
|
9222
|
+
}),
|
|
9223
|
+
" close"
|
|
9224
|
+
]
|
|
9234
9225
|
})
|
|
9235
9226
|
]
|
|
9236
9227
|
});
|
|
@@ -9272,7 +9263,7 @@ function McpsSettingsModal({ catalog, errors, onLogin, onLogout, onCancelLogin }
|
|
|
9272
9263
|
})
|
|
9273
9264
|
}),
|
|
9274
9265
|
focusedEntry && focusedStatus && renderDetailPanel(focusedEntry, focusedStatus, COLOR),
|
|
9275
|
-
renderActionHints(focusedEntry, focusedStatus, COLOR)
|
|
9266
|
+
renderActionHints(focusedEntry, focusedStatus, !!onRefresh, COLOR)
|
|
9276
9267
|
]
|
|
9277
9268
|
});
|
|
9278
9269
|
}
|
|
@@ -9383,7 +9374,7 @@ function renderDetailPanel(entry, status, COLOR) {
|
|
|
9383
9374
|
});
|
|
9384
9375
|
return null;
|
|
9385
9376
|
}
|
|
9386
|
-
function renderActionHints(entry, status, COLOR) {
|
|
9377
|
+
function renderActionHints(entry, status, showRefresh, COLOR) {
|
|
9387
9378
|
const effectiveStatus = status ?? { kind: "idle" };
|
|
9388
9379
|
const canL = entry ? canLogin(entry, effectiveStatus) : false;
|
|
9389
9380
|
const canO = canLogout(effectiveStatus);
|
|
@@ -9417,6 +9408,14 @@ function renderActionHints(entry, status, COLOR) {
|
|
|
9417
9408
|
}),
|
|
9418
9409
|
" logout"
|
|
9419
9410
|
] }),
|
|
9411
|
+
showRefresh && /* @__PURE__ */ jsxs("span", { children: [
|
|
9412
|
+
" · ",
|
|
9413
|
+
/* @__PURE__ */ jsx("span", {
|
|
9414
|
+
fg: COLOR.warn,
|
|
9415
|
+
children: "r"
|
|
9416
|
+
}),
|
|
9417
|
+
" refresh"
|
|
9418
|
+
] }),
|
|
9420
9419
|
canCancel && /* @__PURE__ */ jsxs("span", { children: [
|
|
9421
9420
|
" · ",
|
|
9422
9421
|
/* @__PURE__ */ jsx("span", {
|
|
@@ -9467,7 +9466,7 @@ function displayPath(path, home) {
|
|
|
9467
9466
|
* (chat layer) — a GUI shell can build its own toggle list against the
|
|
9468
9467
|
* same hook without pulling OpenTUI.
|
|
9469
9468
|
*/
|
|
9470
|
-
function ToggleListModal({ catalog, keyOf, settingKey, title, renderDetail, emptyState, preamble }) {
|
|
9469
|
+
function ToggleListModal({ catalog, keyOf, settingKey, title, renderDetail, emptyState, preamble, onRefresh }) {
|
|
9471
9470
|
const COLOR = useColors();
|
|
9472
9471
|
const { enabledSet, toggle } = useEnabledToggleSet({
|
|
9473
9472
|
catalog,
|
|
@@ -9486,7 +9485,7 @@ function ToggleListModal({ catalog, keyOf, settingKey, title, renderDetail, empt
|
|
|
9486
9485
|
else if (key.name === "return" || key.name === "space") {
|
|
9487
9486
|
const entry = catalog[safeCursor];
|
|
9488
9487
|
if (entry) toggle(keyOf(entry));
|
|
9489
|
-
}
|
|
9488
|
+
} else if (key.ctrl && key.name === "r" && onRefresh) onRefresh();
|
|
9490
9489
|
});
|
|
9491
9490
|
if (catalog.length === 0) return /* @__PURE__ */ jsxs(Modal, {
|
|
9492
9491
|
title,
|
|
@@ -9495,10 +9494,17 @@ function ToggleListModal({ catalog, keyOf, settingKey, title, renderDetail, empt
|
|
|
9495
9494
|
emptyState,
|
|
9496
9495
|
/* @__PURE__ */ jsxs("text", {
|
|
9497
9496
|
fg: COLOR.mute,
|
|
9498
|
-
children: [
|
|
9499
|
-
|
|
9500
|
-
|
|
9501
|
-
|
|
9497
|
+
children: [
|
|
9498
|
+
onRefresh && /* @__PURE__ */ jsxs("span", { children: [/* @__PURE__ */ jsx("span", {
|
|
9499
|
+
fg: COLOR.warn,
|
|
9500
|
+
children: "ctrl+R"
|
|
9501
|
+
}), " refresh · "] }),
|
|
9502
|
+
/* @__PURE__ */ jsx("span", {
|
|
9503
|
+
fg: COLOR.warn,
|
|
9504
|
+
children: "esc"
|
|
9505
|
+
}),
|
|
9506
|
+
" close"
|
|
9507
|
+
]
|
|
9502
9508
|
})
|
|
9503
9509
|
]
|
|
9504
9510
|
});
|
|
@@ -9548,6 +9554,10 @@ function ToggleListModal({ catalog, keyOf, settingKey, title, renderDetail, empt
|
|
|
9548
9554
|
children: "↵"
|
|
9549
9555
|
}),
|
|
9550
9556
|
" toggle · ",
|
|
9557
|
+
onRefresh && /* @__PURE__ */ jsxs("span", { children: [/* @__PURE__ */ jsx("span", {
|
|
9558
|
+
fg: COLOR.warn,
|
|
9559
|
+
children: "ctrl+R"
|
|
9560
|
+
}), " refresh · "] }),
|
|
9551
9561
|
/* @__PURE__ */ jsx("span", {
|
|
9552
9562
|
fg: COLOR.warn,
|
|
9553
9563
|
children: "esc"
|
|
@@ -9564,8 +9574,13 @@ function ToggleListModal({ catalog, keyOf, settingKey, title, renderDetail, empt
|
|
|
9564
9574
|
* List + toggle modal for discovered skills. State machine + keyboard +
|
|
9565
9575
|
* row geometry live in `<ToggleListModal>`; this file just supplies the
|
|
9566
9576
|
* skill-specific column (description) and the empty-state hint.
|
|
9577
|
+
*
|
|
9578
|
+
* Pass `onRefresh` to expose `ctrl+R` (force re-scan) on the list. The
|
|
9579
|
+
* standalone modal is for embedders — the in-app flow goes through
|
|
9580
|
+
* `<SettingsModal>` which exposes the same affordance via its own
|
|
9581
|
+
* `SettingsActions.onRefreshSkills` plumbing.
|
|
9567
9582
|
*/
|
|
9568
|
-
function SkillsSettingsModal({ catalog }) {
|
|
9583
|
+
function SkillsSettingsModal({ catalog, onRefresh }) {
|
|
9569
9584
|
const COLOR = useColors();
|
|
9570
9585
|
return /* @__PURE__ */ jsx(ToggleListModal, {
|
|
9571
9586
|
catalog,
|
|
@@ -9573,6 +9588,7 @@ function SkillsSettingsModal({ catalog }) {
|
|
|
9573
9588
|
settingKey: "enabledSkills",
|
|
9574
9589
|
title: "skills",
|
|
9575
9590
|
renderDetail: (skill) => skill.description,
|
|
9591
|
+
onRefresh,
|
|
9576
9592
|
emptyState: /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("text", {
|
|
9577
9593
|
fg: COLOR.dim,
|
|
9578
9594
|
children: "No skills discovered."
|
|
@@ -9662,14 +9678,14 @@ let runTuiInvoked = false;
|
|
|
9662
9678
|
async function runTui(options = {}) {
|
|
9663
9679
|
if (runTuiInvoked) throw new Error("runTui() can only be invoked once per process. Compose `<App config={resolveConfig(...)} />` against your own renderer if you need to run multiple TUIs in the same lifetime.");
|
|
9664
9680
|
runTuiInvoked = true;
|
|
9665
|
-
|
|
9666
|
-
|
|
9667
|
-
|
|
9668
|
-
});
|
|
9681
|
+
bootTick("runTui:enter");
|
|
9682
|
+
registerTreeSitterParsers();
|
|
9683
|
+
bootTick("runTui:after-registerTreeSitterParsers");
|
|
9669
9684
|
const config = resolveConfig({
|
|
9670
9685
|
...options,
|
|
9671
9686
|
store: options.store ?? ((paths) => createTuiStore(paths.db))
|
|
9672
9687
|
});
|
|
9688
|
+
bootTick("runTui:after-resolveConfig");
|
|
9673
9689
|
let done = () => {};
|
|
9674
9690
|
const exited = new Promise((resolve) => {
|
|
9675
9691
|
done = resolve;
|
|
@@ -9684,17 +9700,22 @@ async function runTui(options = {}) {
|
|
|
9684
9700
|
maxFps: bootFps,
|
|
9685
9701
|
gatherStats
|
|
9686
9702
|
});
|
|
9703
|
+
bootTick("runTui:after-createCliRenderer");
|
|
9687
9704
|
createRoot(renderer).render(/* @__PURE__ */ jsx(App, { config }));
|
|
9705
|
+
bootTick("runTui:after-mount");
|
|
9706
|
+
initTreeSitterWorker().then(() => bootTick("runTui:after-treeSitterWorker"), (err) => {
|
|
9707
|
+
process.stderr.write(`[zidane/tui] tree-sitter setup failed: ${errorMessage(err)}\n`);
|
|
9708
|
+
});
|
|
9688
9709
|
await exited;
|
|
9689
9710
|
if (gatherStats) try {
|
|
9690
9711
|
const s = renderer.getStats();
|
|
9691
9712
|
process.stderr.write(`[zidane/tui] render stats: fps=${s.fps.toFixed(1)} avgFrame=${s.averageFrameTime.toFixed(2)}ms min=${s.minFrameTime.toFixed(2)}ms max=${s.maxFrameTime.toFixed(2)}ms frames=${s.frameCount}\n`);
|
|
9692
9713
|
} catch (err) {
|
|
9693
|
-
process.stderr.write(`[zidane/tui] render stats unavailable: ${
|
|
9714
|
+
process.stderr.write(`[zidane/tui] render stats unavailable: ${errorMessage(err)}\n`);
|
|
9694
9715
|
}
|
|
9695
9716
|
process.exit(0);
|
|
9696
9717
|
}
|
|
9697
9718
|
//#endregion
|
|
9698
|
-
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, displayNameFor, formatToolCall, hintsLength, isEditErrorResult, isTurnHighlighted, isVisible, marginTopFor, onInputSubmit, renderHintSpans, runTui, selectableTurnIds, splitPromptSegments, turnSelectionOwnership, useMdStyle, useModal, useModalAwareFocus };
|
|
9719
|
+
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 };
|
|
9699
9720
|
|
|
9700
9721
|
//# sourceMappingURL=tui.js.map
|