zidane 5.2.1 → 5.3.1
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 +7 -5
- package/dist/{agent-CGQajqtC.d.ts → agent-bKs7MRT2.d.ts} +429 -4
- package/dist/agent-bKs7MRT2.d.ts.map +1 -0
- package/dist/chat.d.ts +212 -58
- package/dist/chat.d.ts.map +1 -1
- package/dist/chat.js +2 -2
- package/dist/{errors-COmsomd5.js → errors-Byb0F8B9.js} +44 -2
- package/dist/errors-Byb0F8B9.js.map +1 -0
- package/dist/{index-DwbcFBr_.d.ts → index-BlMvPh9X.d.ts} +29 -3
- package/dist/index-BlMvPh9X.d.ts.map +1 -0
- package/dist/{index-BDP6mA3Y.d.ts → index-CTmNaIDb.d.ts} +2 -2
- package/dist/{index-BDP6mA3Y.d.ts.map → index-CTmNaIDb.d.ts.map} +1 -1
- package/dist/index.d.ts +4 -4
- package/dist/index.js +10 -10
- package/dist/{interpolate-BhmHKD6x.js → interpolate-ERgZUxgg.js} +2 -2
- package/dist/{interpolate-BhmHKD6x.js.map → interpolate-ERgZUxgg.js.map} +1 -1
- package/dist/{login-D7Tp-K5f.js → login-CNS9_8Ue.js} +3 -3
- package/dist/{login-D7Tp-K5f.js.map → login-CNS9_8Ue.js.map} +1 -1
- package/dist/{mcp-B1psg7jf.js → mcp-ZsSFo4Dp.js} +2 -2
- package/dist/{mcp-B1psg7jf.js.map → mcp-ZsSFo4Dp.js.map} +1 -1
- package/dist/mcp.d.ts +1 -1
- package/dist/mcp.js +1 -1
- package/dist/{messages-DsbMYNmt.js → messages-D0xT979U.js} +631 -68
- package/dist/messages-D0xT979U.js.map +1 -0
- package/dist/{presets-AgF0RFx1.js → presets-h5i3kpOP.js} +2 -2
- package/dist/{presets-AgF0RFx1.js.map → presets-h5i3kpOP.js.map} +1 -1
- package/dist/presets.d.ts +2 -2
- package/dist/presets.js +1 -1
- package/dist/{providers-v1Rn2rqG.js → providers-x3LZByR5.js} +38 -6
- package/dist/providers-x3LZByR5.js.map +1 -0
- package/dist/providers.d.ts +2 -2
- package/dist/providers.js +3 -3
- package/dist/session/sqlite.d.ts +1 -1
- package/dist/session/sqlite.js +1 -1
- package/dist/{session-DOJgRXvF.js → session-BHZwxmfr.js} +2 -2
- package/dist/{session-DOJgRXvF.js.map → session-BHZwxmfr.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-BRbbfdJh.js → tools-CWEDS2ZT.js} +251 -47
- package/dist/tools-CWEDS2ZT.js.map +1 -0
- package/dist/tools.d.ts +2 -2
- package/dist/tools.js +1 -1
- package/dist/{transcript-anchors-BBuIoU0x.d.ts → transcript-anchors-DOUqyvXR.d.ts} +28 -4
- package/dist/transcript-anchors-DOUqyvXR.d.ts.map +1 -0
- package/dist/tui.d.ts +29 -3
- package/dist/tui.d.ts.map +1 -1
- package/dist/tui.js +363 -28
- package/dist/tui.js.map +1 -1
- package/dist/{turn-operations-gJ0qtLPv.js → turn-operations-D9HvatsR.js} +396 -89
- package/dist/turn-operations-D9HvatsR.js.map +1 -0
- package/dist/types-IcokUOyC.js.map +1 -1
- package/dist/types.d.ts +2 -2
- package/dist/types.js +1 -1
- package/docs/ARCHITECTURE.md +3 -2
- package/docs/CHAT.md +55 -16
- package/docs/TUI.md +22 -2
- package/package.json +1 -1
- package/dist/agent-CGQajqtC.d.ts.map +0 -1
- package/dist/errors-COmsomd5.js.map +0 -1
- package/dist/index-DwbcFBr_.d.ts.map +0 -1
- package/dist/messages-DsbMYNmt.js.map +0 -1
- package/dist/providers-v1Rn2rqG.js.map +0 -1
- package/dist/tools-BRbbfdJh.js.map +0 -1
- package/dist/transcript-anchors-BBuIoU0x.d.ts.map +0 -1
- package/dist/turn-operations-gJ0qtLPv.js.map +0 -1
package/dist/tui.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import { s as McpOAuthProvider, t as connectMcpServers } from "./mcp-
|
|
4
|
-
import { C as summaryToTurn, a as selectFilesFromSession, r as buildPostCompactAttachments, s as compactConversation, t as loginMcpServer } from "./login-
|
|
1
|
+
import { D as resolvePersistDir, T as cleanupPersistedSession, p as createAgent } from "./tools-CWEDS2ZT.js";
|
|
2
|
+
import { s as errorMessage } from "./errors-Byb0F8B9.js";
|
|
3
|
+
import { s as McpOAuthProvider, t as connectMcpServers } from "./mcp-ZsSFo4Dp.js";
|
|
4
|
+
import { C as summaryToTurn, a as selectFilesFromSession, r as buildPostCompactAttachments, s as compactConversation, t as loginMcpServer } from "./login-CNS9_8Ue.js";
|
|
5
5
|
import { n as formatTokenUsage } from "./stats-DgOvY7wd.js";
|
|
6
|
-
import { n as loadSession, t as createSession } from "./session-
|
|
6
|
+
import { n as loadSession, t as createSession } from "./session-BHZwxmfr.js";
|
|
7
7
|
import { createTuiStore } from "./session/sqlite.js";
|
|
8
|
-
import { $ as useMcpAuthDispatch, $n as bootTick, $t as isVisible, A as getSafelist, At as clampFps, B as supportsOAuth, Bn as uniqueSkillNamesFromReferences, Ct as shortId, D as useSafeModeQueue, Dn as findGitRoot, Dr as accentColor, Dt as SETTINGS_CHOICES, E as useSafeModeActions, En as summarizeOutcomes, Et as DEFAULT_SETTINGS, F as suggestSafelistEntry, Ft as resolveTheme, Gt as ConfigProvider, H as filterModelCatalog, Hn as createFilesCompletionProvider, Ht as DiscoveryProvider, Jn as useCompletion, K as discoverProjectMcps, Kt as useConfig, L as splitPromptSegments, Nn as matchesBinding, Ot as SETTINGS_TOGGLES, Pt as resolveChipColor, Q as McpAuthProvider, Qt as isTurnHighlighted, R as formatPathForCwd, Sn as buildEditOutcomesAnnotation, St as fmtTokens, T as SafeModeProvider, Tn as resolveApprovalForPayload, Tt as useEnabledToggleSet, U as indexOfEntry, Ut as useDiscovery, V as buildModelCatalog, Vt as createDiscoverySlot, W as buildMcpServers, Wt as useDiscoveryOptional, Xn as buildLinearRamp,
|
|
8
|
+
import { $ as useMcpAuthDispatch, $n as bootTick, $t as isVisible, A as getSafelist, At as clampFps, B as supportsOAuth, Bn as uniqueSkillNamesFromReferences, Ct as shortId, D as useSafeModeQueue, Dn as findGitRoot, Dr as accentColor, Dt as SETTINGS_CHOICES, E as useSafeModeActions, En as summarizeOutcomes, Et as DEFAULT_SETTINGS, F as suggestSafelistEntry, Ft as resolveTheme, Gt as ConfigProvider, H as filterModelCatalog, Hn as createFilesCompletionProvider, Ht as DiscoveryProvider, Jn as useCompletion, K as discoverProjectMcps, Kt as useConfig, L as splitPromptSegments, Nn as matchesBinding, Nr as TODO_STATUS_GLYPHS, Ot as SETTINGS_TOGGLES, Pt as resolveChipColor, Q as McpAuthProvider, Qt as isTurnHighlighted, R as formatPathForCwd, Sn as buildEditOutcomesAnnotation, St as fmtTokens, T as SafeModeProvider, Tn as resolveApprovalForPayload, Tt as useEnabledToggleSet, U as indexOfEntry, Ur as useActiveTodos, Ut as useDiscovery, V as buildModelCatalog, Vt as createDiscoverySlot, W as buildMcpServers, Wt as useDiscoveryOptional, Xn as buildLinearRamp, Xt as eventsFromTurns, Y as createFileMcpCredentialStore, Yn as blendHsl, Yt as deriveSessionTitle, Zn as tryOpenBrowser, Zt as isEditErrorResult, _ as turnContextSize, _n as extractEditPayload, _r as modelSupportsReasoning, _t as truncateTrailing, a as computeTurnAnchors, an as selectableTurnIds, at as InteractionsProvider, b as defaultSkillScanPaths, bt as ageString, c as formatToolCall, ct as createInteractionTools, d as useSelectStyle, dn as turnSelectionOwnership, dt as pendingInteractionsFromTurns, ei as buildBuildSystem, en as lastContextSizeFromTurns, er as shouldAutoCompact, et as useMcpAuthState, f as useSurfaces, g as finalizeStreamingMarkdownForOwner, gt as hintsLength, h as finalizeStreamingMarkdown, hr as getContextWindow, ht as clipHintsToWidth, i as turnAsText, j as isOnSafelist, jn as ensureKeybindingsFile, jt as useSettings, k as addToSafelist, kt as SettingsProvider, l as ThemeProvider, ln as toolCallPreview, m as useTheme, mn as buildUnifiedDiff, mt as useInteractionsQueue, n as deleteTurnSafely, o as TOOL_DISPLAY, on as stripSpawnTokensLine, pt as useInteractionsActions, qt as resolveConfig, r as truncateTurnsAt, rn as marginTopFor, rt as splitMarkdownCodeBlocks, s as displayNameFor, sn as sumRunCosts, sr as setProviderCredential, st as buildResumedToolResultsTurn, ti as buildPlanSystem, tn as listSessionMeta, tr as detectAuth, tt as getMcpAuthStatus, u as useColors, un as toolResultText, ut as makeRequestInteraction, v as useStreamBuffer, vn as filetypeFromPath, w as writeSessionExport, wt as listProjectFiles, x as discoverProjectSkills, xr as piIdOf, xt as compactPath, y as buildSkillsConfig, yn as previewEditPayload, yt as generateSessionTitle, z as runOAuthLogin, zn as createSkillsCompletionProvider } from "./turn-operations-D9HvatsR.js";
|
|
9
9
|
import { spawn } from "node:child_process";
|
|
10
10
|
import { Buffer } from "node:buffer";
|
|
11
11
|
import * as fs from "node:fs";
|
|
@@ -80,7 +80,7 @@ function useModalAwareFocus(preferred = true) {
|
|
|
80
80
|
*
|
|
81
81
|
* Uses `useTerminalDimensions()` so it reflows on `SIGWINCH` without remount.
|
|
82
82
|
*/
|
|
83
|
-
function Modal({ title, bottomTitle, onClose, disableEscape = false, children, maxWidth = 92, minWidth = 44, maxHeight, horizontalMargin = 4, verticalMargin = 2 }) {
|
|
83
|
+
function Modal({ title, bottomTitle, rightTitle, onClose, disableEscape = false, children, maxWidth = 92, minWidth = 44, maxHeight, horizontalMargin = 4, verticalMargin = 2 }) {
|
|
84
84
|
const ctx = useContext(ModalContext);
|
|
85
85
|
const dismiss = onClose ?? ctx?.close;
|
|
86
86
|
const COLOR = useColors();
|
|
@@ -91,7 +91,7 @@ function Modal({ title, bottomTitle, onClose, disableEscape = false, children, m
|
|
|
91
91
|
const { width: termWidth, height: termHeight } = useTerminalDimensions();
|
|
92
92
|
const width = Math.max(minWidth, Math.min(maxWidth, termWidth - horizontalMargin * 2));
|
|
93
93
|
const height = maxHeight === void 0 ? void 0 : Math.min(maxHeight, Math.max(0, termHeight - verticalMargin * 2));
|
|
94
|
-
|
|
94
|
+
const panel = /* @__PURE__ */ jsx("box", {
|
|
95
95
|
title: title ? ` ${title} ` : void 0,
|
|
96
96
|
bottomTitle: bottomTitle ? ` ${bottomTitle} ` : void 0,
|
|
97
97
|
bottomTitleAlignment: "right",
|
|
@@ -110,6 +110,21 @@ function Modal({ title, bottomTitle, onClose, disableEscape = false, children, m
|
|
|
110
110
|
},
|
|
111
111
|
children
|
|
112
112
|
});
|
|
113
|
+
if (rightTitle == null) return panel;
|
|
114
|
+
return /* @__PURE__ */ jsxs("box", {
|
|
115
|
+
style: {
|
|
116
|
+
width,
|
|
117
|
+
flexDirection: "column"
|
|
118
|
+
},
|
|
119
|
+
children: [panel, /* @__PURE__ */ jsx("box", {
|
|
120
|
+
style: {
|
|
121
|
+
position: "absolute",
|
|
122
|
+
top: 0,
|
|
123
|
+
right: 1
|
|
124
|
+
},
|
|
125
|
+
children: rightTitle
|
|
126
|
+
})]
|
|
127
|
+
});
|
|
113
128
|
}
|
|
114
129
|
//#endregion
|
|
115
130
|
//#region src/tui/agent-picker.tsx
|
|
@@ -923,7 +938,7 @@ function StatusSpinner({ color }) {
|
|
|
923
938
|
function Transcript({ events, settings, selectedTurnId = null, busy = false }) {
|
|
924
939
|
const COLOR = useColors();
|
|
925
940
|
const items = useMemo(() => partitionTranscript(events, settings), [events, settings]);
|
|
926
|
-
const showThrobber = busy;
|
|
941
|
+
const showThrobber = busy && settings.showThrobber;
|
|
927
942
|
const throbberLabel = events.length > 0 && events[events.length - 1].kind === "thinking" ? "Thinking" : void 0;
|
|
928
943
|
const ownership = useMemo(() => turnSelectionOwnership(events), [events]);
|
|
929
944
|
const scrollboxRef = useRef(null);
|
|
@@ -1145,13 +1160,16 @@ function EventLineImpl({ event, depthOffset = 0 }) {
|
|
|
1145
1160
|
dim: child
|
|
1146
1161
|
})
|
|
1147
1162
|
});
|
|
1148
|
-
return /* @__PURE__ */
|
|
1163
|
+
return /* @__PURE__ */ jsxs("box", {
|
|
1149
1164
|
style: row,
|
|
1150
|
-
children: /* @__PURE__ */ jsx(ToolCallBlock, {
|
|
1165
|
+
children: [/* @__PURE__ */ jsx(ToolCallBlock, {
|
|
1151
1166
|
event,
|
|
1152
1167
|
display: settings.toolCallDisplay === "full" ? "full" : "formatted",
|
|
1153
1168
|
dim: child
|
|
1154
|
-
})
|
|
1169
|
+
}), event.tool === "todowrite" && /* @__PURE__ */ jsx(TodoInProgressList, {
|
|
1170
|
+
input: event.input,
|
|
1171
|
+
dim: child
|
|
1172
|
+
})]
|
|
1155
1173
|
});
|
|
1156
1174
|
case "tool-result": return /* @__PURE__ */ jsx(ToolResultBlock, {
|
|
1157
1175
|
text: event.text,
|
|
@@ -1644,6 +1662,7 @@ const MarkdownBlock = memo(({ text, dim }) => {
|
|
|
1644
1662
|
const SURFACE = useSurfaces();
|
|
1645
1663
|
const mdStyle = useMdStyle();
|
|
1646
1664
|
const renderer = useRenderer();
|
|
1665
|
+
const content = text.replace(/^\n+|\n+$/g, "");
|
|
1647
1666
|
const bag = useRef({
|
|
1648
1667
|
ctx: renderer,
|
|
1649
1668
|
colors: COLOR,
|
|
@@ -1658,7 +1677,7 @@ const MarkdownBlock = memo(({ text, dim }) => {
|
|
|
1658
1677
|
}, [COLOR, SURFACE]);
|
|
1659
1678
|
const renderNode = useMemo(() => makeMarkdownRenderNode(bag), []);
|
|
1660
1679
|
return /* @__PURE__ */ jsx("markdown", {
|
|
1661
|
-
content
|
|
1680
|
+
content,
|
|
1662
1681
|
syntaxStyle: mdStyle,
|
|
1663
1682
|
streaming: true,
|
|
1664
1683
|
internalBlockMode: "coalesced",
|
|
@@ -1966,6 +1985,43 @@ function ToolCallBlock({ event, display, dim }) {
|
|
|
1966
1985
|
]
|
|
1967
1986
|
});
|
|
1968
1987
|
}
|
|
1988
|
+
function TodoInProgressList({ input, dim }) {
|
|
1989
|
+
const COLOR = useColors();
|
|
1990
|
+
const items = useMemo(() => {
|
|
1991
|
+
const raw = input?.todos;
|
|
1992
|
+
if (!Array.isArray(raw)) return [];
|
|
1993
|
+
return raw.flatMap((t) => {
|
|
1994
|
+
if (t == null || typeof t !== "object") return [];
|
|
1995
|
+
const rec = t;
|
|
1996
|
+
if (rec.status !== "in_progress") return [];
|
|
1997
|
+
const id = typeof rec.id === "string" ? rec.id : "";
|
|
1998
|
+
const content = typeof rec.content === "string" ? rec.content : "";
|
|
1999
|
+
if (!id || !content) return [];
|
|
2000
|
+
return [{
|
|
2001
|
+
id,
|
|
2002
|
+
content
|
|
2003
|
+
}];
|
|
2004
|
+
});
|
|
2005
|
+
}, [input]);
|
|
2006
|
+
if (items.length === 0) return null;
|
|
2007
|
+
const glyph = TODO_STATUS_GLYPHS.in_progress;
|
|
2008
|
+
return /* @__PURE__ */ jsx("box", {
|
|
2009
|
+
style: {
|
|
2010
|
+
flexDirection: "column",
|
|
2011
|
+
marginLeft: 2
|
|
2012
|
+
},
|
|
2013
|
+
children: items.map((item) => /* @__PURE__ */ jsxs("text", {
|
|
2014
|
+
wrapMode: "none",
|
|
2015
|
+
children: [/* @__PURE__ */ jsx("span", {
|
|
2016
|
+
fg: COLOR.mute,
|
|
2017
|
+
children: `${glyph} `
|
|
2018
|
+
}), /* @__PURE__ */ jsx("span", {
|
|
2019
|
+
fg: dim ? COLOR.dim : COLOR.warn,
|
|
2020
|
+
children: item.content
|
|
2021
|
+
})]
|
|
2022
|
+
}, item.id))
|
|
2023
|
+
});
|
|
2024
|
+
}
|
|
1969
2025
|
//#endregion
|
|
1970
2026
|
//#region src/tui/discovery-shell.tsx
|
|
1971
2027
|
/**
|
|
@@ -4160,6 +4216,72 @@ function OptionList({ items, initialCursor, onPick }) {
|
|
|
4160
4216
|
});
|
|
4161
4217
|
}
|
|
4162
4218
|
//#endregion
|
|
4219
|
+
//#region src/tui/todo-indicator.tsx
|
|
4220
|
+
/**
|
|
4221
|
+
* Layout budget when truncating the content. The bar never wraps —
|
|
4222
|
+
* single-line by contract — so we subtract every column consumed by
|
|
4223
|
+
* surrounding chrome before measuring how much room is left for the
|
|
4224
|
+
* todo's `content` text.
|
|
4225
|
+
*
|
|
4226
|
+
* - 2 cols ⇒ `<ChatScreen>`'s `border: true` (1 cell each side).
|
|
4227
|
+
* - 2 cols ⇒ this indicator's own `paddingLeft: 1 + paddingRight: 1`
|
|
4228
|
+
* (mirrors the queue block's outer padding so the bar
|
|
4229
|
+
* and queue read as aligned siblings).
|
|
4230
|
+
* - 4 cols ⇒ the indicator's own visible chrome: glyph "◐" (1) +
|
|
4231
|
+
* two spaces (2) + 1 col of trailing breathing room.
|
|
4232
|
+
*
|
|
4233
|
+
* That's 8 cols total of non-content overhead. Below `MIN_VISIBLE_TAIL`
|
|
4234
|
+
* the bar bails — a one-or-two-char tail isn't worth painting.
|
|
4235
|
+
*/
|
|
4236
|
+
const SCREEN_BORDER_COLS = 2;
|
|
4237
|
+
const INDICATOR_PADDING_COLS = 2;
|
|
4238
|
+
const CHROME_COLS = 4;
|
|
4239
|
+
const MIN_VISIBLE_TAIL = 8;
|
|
4240
|
+
function truncateForWidth(text, max) {
|
|
4241
|
+
if (max <= 0) return "";
|
|
4242
|
+
if (text.length <= max) return text;
|
|
4243
|
+
if (max <= 1) return "…";
|
|
4244
|
+
return `${text.slice(0, max - 1)}…`;
|
|
4245
|
+
}
|
|
4246
|
+
function TodoIndicator({ session }) {
|
|
4247
|
+
const { settings } = useSettings();
|
|
4248
|
+
const COLOR = useColors();
|
|
4249
|
+
const { width: termWidth } = useTerminalDimensions();
|
|
4250
|
+
const state = useActiveTodos(session);
|
|
4251
|
+
if (!settings.showTodoIndicator) return null;
|
|
4252
|
+
const item = state.inProgress;
|
|
4253
|
+
if (!item) return null;
|
|
4254
|
+
const usable = Math.max(0, termWidth - SCREEN_BORDER_COLS - INDICATOR_PADDING_COLS - CHROME_COLS);
|
|
4255
|
+
if (usable < MIN_VISIBLE_TAIL) return null;
|
|
4256
|
+
const display = truncateForWidth(item.content.replace(/\s+/g, " ").trim(), usable);
|
|
4257
|
+
return /* @__PURE__ */ jsx("box", {
|
|
4258
|
+
style: {
|
|
4259
|
+
marginTop: 1,
|
|
4260
|
+
flexShrink: 0,
|
|
4261
|
+
flexDirection: "row",
|
|
4262
|
+
paddingLeft: 1,
|
|
4263
|
+
paddingRight: 1
|
|
4264
|
+
},
|
|
4265
|
+
children: /* @__PURE__ */ jsxs("text", {
|
|
4266
|
+
wrapMode: "none",
|
|
4267
|
+
children: [
|
|
4268
|
+
/* @__PURE__ */ jsx("span", {
|
|
4269
|
+
fg: COLOR.warn,
|
|
4270
|
+
children: TODO_STATUS_GLYPHS.in_progress
|
|
4271
|
+
}),
|
|
4272
|
+
/* @__PURE__ */ jsx("span", {
|
|
4273
|
+
fg: COLOR.mute,
|
|
4274
|
+
children: " "
|
|
4275
|
+
}),
|
|
4276
|
+
/* @__PURE__ */ jsx("span", {
|
|
4277
|
+
fg: COLOR.dim,
|
|
4278
|
+
children: display
|
|
4279
|
+
})
|
|
4280
|
+
]
|
|
4281
|
+
})
|
|
4282
|
+
});
|
|
4283
|
+
}
|
|
4284
|
+
//#endregion
|
|
4163
4285
|
//#region src/tui/screens.tsx
|
|
4164
4286
|
/**
|
|
4165
4287
|
* Build a key-binding set for the prompt textarea / API-key input. Strips the
|
|
@@ -4978,7 +5100,7 @@ const CWD_DISPLAY = compactPath(process.cwd());
|
|
|
4978
5100
|
* default-value reference at the prop destructure.
|
|
4979
5101
|
*/
|
|
4980
5102
|
const EMPTY_QUEUED_MESSAGES = [];
|
|
4981
|
-
function ChatScreen({ events, busy, compacting = false, queuedMessages = EMPTY_QUEUED_MESSAGES, queueSelectionIndex = null, queueShortcuts, onEnterQueueFromEmptyPrompt, settings, onSubmit, session, pending, onApproval, pendingInteraction, onInteraction, completionProviders, onPopupOpenChange, selectedTurnId, promptTriggerHints }) {
|
|
5103
|
+
function ChatScreen({ events, busy, compacting = false, queuedMessages = EMPTY_QUEUED_MESSAGES, queueSelectionIndex = null, queueShortcuts, onEnterQueueFromEmptyPrompt, settings, onSubmit, session, pending, onApproval, pendingInteraction, onInteraction, completionProviders, onPopupOpenChange, selectedTurnId, promptTriggerHints, liveSession = null }) {
|
|
4982
5104
|
const COLOR = useColors();
|
|
4983
5105
|
const titleText = session?.title ?? "untitled";
|
|
4984
5106
|
const showSessionShortcut = !!session && !busy && !pending && !pendingInteraction;
|
|
@@ -5077,20 +5199,24 @@ function ChatScreen({ events, busy, compacting = false, queuedMessages = EMPTY_Q
|
|
|
5077
5199
|
}) : pendingInteraction ? /* @__PURE__ */ jsx(InteractionBlock, {
|
|
5078
5200
|
request: pendingInteraction,
|
|
5079
5201
|
onResolve: onInteraction
|
|
5080
|
-
}) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
5081
|
-
|
|
5082
|
-
|
|
5083
|
-
|
|
5084
|
-
|
|
5085
|
-
|
|
5086
|
-
|
|
5087
|
-
|
|
5088
|
-
|
|
5089
|
-
|
|
5090
|
-
|
|
5091
|
-
|
|
5092
|
-
|
|
5093
|
-
|
|
5202
|
+
}) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
5203
|
+
queuedMessages.length > 0 && !completionPopupOpen && /* @__PURE__ */ jsx(QueuedMessagesBlock, {
|
|
5204
|
+
messages: queuedMessages,
|
|
5205
|
+
selectionIndex: queueSelectionIndex,
|
|
5206
|
+
shortcuts: queueShortcuts
|
|
5207
|
+
}),
|
|
5208
|
+
/* @__PURE__ */ jsx(TodoIndicator, { session: liveSession }),
|
|
5209
|
+
/* @__PURE__ */ jsx(PromptBlock, {
|
|
5210
|
+
userPrompts,
|
|
5211
|
+
onSubmit,
|
|
5212
|
+
completionProviders,
|
|
5213
|
+
onPopupOpenChange: handlePopupOpenChange,
|
|
5214
|
+
selectMode: queueSelectionIndex != null ? "queue" : selectedTurnId != null ? "turn" : null,
|
|
5215
|
+
triggerHints: promptTriggerHints,
|
|
5216
|
+
busy,
|
|
5217
|
+
onEnterQueueFromEmpty: onEnterQueueFromEmptyPrompt
|
|
5218
|
+
})
|
|
5219
|
+
] }),
|
|
5094
5220
|
/* @__PURE__ */ jsx(TitleOverlay, {
|
|
5095
5221
|
title: titleText,
|
|
5096
5222
|
meta: metaSegments
|
|
@@ -7276,6 +7402,207 @@ function displayPath$1(path, home) {
|
|
|
7276
7402
|
return path;
|
|
7277
7403
|
}
|
|
7278
7404
|
//#endregion
|
|
7405
|
+
//#region src/tui/todos-modal.tsx
|
|
7406
|
+
/** Floor on the modal height — keeps the header + at least a few rows visible on tiny terminals. */
|
|
7407
|
+
const MIN_MODAL_HEIGHT = 12;
|
|
7408
|
+
/** Ceiling on the modal height — prevents a giant list from blanket-filling a tall window. */
|
|
7409
|
+
const MAX_MODAL_HEIGHT$1 = 36;
|
|
7410
|
+
/**
|
|
7411
|
+
* Per-status palette for a row — the glyph and the content text pick
|
|
7412
|
+
* different tones so a quick scan reads the status from the glyph color
|
|
7413
|
+
* while the row content stays in a calm reading tone:
|
|
7414
|
+
*
|
|
7415
|
+
* pending glyph `mute` · text `dim` — queued / not yet started
|
|
7416
|
+
* in_progress glyph `warn` · text `brand` — currently working (loudest)
|
|
7417
|
+
* completed glyph `accent` · text `dim` — done (success glyph, calm text)
|
|
7418
|
+
* cancelled glyph `error` · text `mute` — explicitly dropped
|
|
7419
|
+
*
|
|
7420
|
+
* All tokens come from the active theme — a runtime theme switch
|
|
7421
|
+
* repaints without touching this component.
|
|
7422
|
+
*/
|
|
7423
|
+
function statusColors(status, COLOR) {
|
|
7424
|
+
switch (status) {
|
|
7425
|
+
case "in_progress": return {
|
|
7426
|
+
glyph: COLOR.warn,
|
|
7427
|
+
text: COLOR.brand
|
|
7428
|
+
};
|
|
7429
|
+
case "completed": return {
|
|
7430
|
+
glyph: COLOR.accent,
|
|
7431
|
+
text: COLOR.dim
|
|
7432
|
+
};
|
|
7433
|
+
case "cancelled": return {
|
|
7434
|
+
glyph: COLOR.error,
|
|
7435
|
+
text: COLOR.mute
|
|
7436
|
+
};
|
|
7437
|
+
default: return {
|
|
7438
|
+
glyph: COLOR.mute,
|
|
7439
|
+
text: COLOR.dim
|
|
7440
|
+
};
|
|
7441
|
+
}
|
|
7442
|
+
}
|
|
7443
|
+
function TodoRow({ item, rowId }) {
|
|
7444
|
+
const COLOR = useColors();
|
|
7445
|
+
const colors = statusColors(item.status, COLOR);
|
|
7446
|
+
return /* @__PURE__ */ jsx("box", {
|
|
7447
|
+
id: rowId,
|
|
7448
|
+
style: {
|
|
7449
|
+
flexShrink: 0,
|
|
7450
|
+
flexDirection: "row"
|
|
7451
|
+
},
|
|
7452
|
+
children: /* @__PURE__ */ jsxs("text", {
|
|
7453
|
+
wrapMode: "word",
|
|
7454
|
+
children: [
|
|
7455
|
+
/* @__PURE__ */ jsx("span", {
|
|
7456
|
+
fg: colors.glyph,
|
|
7457
|
+
children: TODO_STATUS_GLYPHS[item.status]
|
|
7458
|
+
}),
|
|
7459
|
+
/* @__PURE__ */ jsx("span", {
|
|
7460
|
+
fg: COLOR.mute,
|
|
7461
|
+
children: " "
|
|
7462
|
+
}),
|
|
7463
|
+
/* @__PURE__ */ jsx("span", {
|
|
7464
|
+
fg: colors.text,
|
|
7465
|
+
children: item.content
|
|
7466
|
+
})
|
|
7467
|
+
]
|
|
7468
|
+
})
|
|
7469
|
+
});
|
|
7470
|
+
}
|
|
7471
|
+
function TodosModal({ session, agent }) {
|
|
7472
|
+
const COLOR = useColors();
|
|
7473
|
+
const { height: termHeight } = useTerminalDimensions();
|
|
7474
|
+
const [, setTick] = useState(0);
|
|
7475
|
+
useEffect(() => {
|
|
7476
|
+
if (!agent) return;
|
|
7477
|
+
return agent.hooks.hook("tool:after", (ctx) => {
|
|
7478
|
+
if (ctx.name === "todowrite") setTick((t) => t + 1);
|
|
7479
|
+
});
|
|
7480
|
+
}, [agent]);
|
|
7481
|
+
const state = useActiveTodos(session);
|
|
7482
|
+
const scrollRef = useRef(null);
|
|
7483
|
+
const inProgressId = state.inProgress?.id ?? null;
|
|
7484
|
+
useEffect(() => {
|
|
7485
|
+
if (!inProgressId) return;
|
|
7486
|
+
const sb = scrollRef.current;
|
|
7487
|
+
if (!sb) return;
|
|
7488
|
+
const handle = requestAnimationFrame(() => {
|
|
7489
|
+
sb.scrollChildIntoView(`todo-row-${inProgressId}`);
|
|
7490
|
+
});
|
|
7491
|
+
return () => cancelAnimationFrame(handle);
|
|
7492
|
+
}, [inProgressId]);
|
|
7493
|
+
const idealHeight = Math.floor((termHeight - 4) * .66);
|
|
7494
|
+
const maxHeight = Math.max(MIN_MODAL_HEIGHT, Math.min(MAX_MODAL_HEIGHT$1, idealHeight));
|
|
7495
|
+
const display = state.todos.length > 0 ? state.todos : state.archive;
|
|
7496
|
+
const total = display.length;
|
|
7497
|
+
return /* @__PURE__ */ jsx(Modal, {
|
|
7498
|
+
title: "todos",
|
|
7499
|
+
bottomTitle: total > 0 ? `${total} item${total === 1 ? "" : "s"} · esc close` : "esc close",
|
|
7500
|
+
rightTitle: display.length > 0 ? /* @__PURE__ */ jsx(CountsBadge, { items: display }) : null,
|
|
7501
|
+
maxWidth: 100,
|
|
7502
|
+
maxHeight,
|
|
7503
|
+
children: total === 0 ? /* @__PURE__ */ jsxs("text", { children: [
|
|
7504
|
+
/* @__PURE__ */ jsx("span", {
|
|
7505
|
+
fg: COLOR.mute,
|
|
7506
|
+
children: "(no todos yet — the agent hasn't called "
|
|
7507
|
+
}),
|
|
7508
|
+
/* @__PURE__ */ jsx("span", {
|
|
7509
|
+
fg: COLOR.warn,
|
|
7510
|
+
children: "todowrite"
|
|
7511
|
+
}),
|
|
7512
|
+
/* @__PURE__ */ jsx("span", {
|
|
7513
|
+
fg: COLOR.mute,
|
|
7514
|
+
children: ")"
|
|
7515
|
+
})
|
|
7516
|
+
] }) : /* @__PURE__ */ jsx("box", {
|
|
7517
|
+
style: {
|
|
7518
|
+
flexDirection: "column",
|
|
7519
|
+
flexGrow: 1,
|
|
7520
|
+
flexShrink: 1,
|
|
7521
|
+
overflow: "hidden"
|
|
7522
|
+
},
|
|
7523
|
+
children: /* @__PURE__ */ jsx("scrollbox", {
|
|
7524
|
+
ref: scrollRef,
|
|
7525
|
+
focusable: false,
|
|
7526
|
+
stickyScroll: false,
|
|
7527
|
+
style: {
|
|
7528
|
+
flexGrow: 1,
|
|
7529
|
+
flexShrink: 1
|
|
7530
|
+
},
|
|
7531
|
+
children: display.map((item) => /* @__PURE__ */ jsx(TodoRow, {
|
|
7532
|
+
item,
|
|
7533
|
+
rowId: `todo-row-${item.id}`
|
|
7534
|
+
}, item.id))
|
|
7535
|
+
})
|
|
7536
|
+
})
|
|
7537
|
+
});
|
|
7538
|
+
}
|
|
7539
|
+
/**
|
|
7540
|
+
* Right-aligned top-border badge — "{in-progress} in progress ·
|
|
7541
|
+
* {completed} completed". Empty buckets are dropped so a homogeneous
|
|
7542
|
+
* list reads cleanly. Status order is fixed (in-progress first, then
|
|
7543
|
+
* completed) regardless of which buckets are populated — the badge's
|
|
7544
|
+
* shape stays predictable so the eye lands on the live count instantly.
|
|
7545
|
+
*/
|
|
7546
|
+
function CountsBadge({ items }) {
|
|
7547
|
+
const COLOR = useColors();
|
|
7548
|
+
const counts = {
|
|
7549
|
+
pending: 0,
|
|
7550
|
+
in_progress: 0,
|
|
7551
|
+
completed: 0,
|
|
7552
|
+
cancelled: 0
|
|
7553
|
+
};
|
|
7554
|
+
for (const item of items) counts[item.status] += 1;
|
|
7555
|
+
const parts = [];
|
|
7556
|
+
if (counts.in_progress) parts.push({
|
|
7557
|
+
count: counts.in_progress,
|
|
7558
|
+
label: "in progress",
|
|
7559
|
+
color: COLOR.warn
|
|
7560
|
+
});
|
|
7561
|
+
if (counts.completed) parts.push({
|
|
7562
|
+
count: counts.completed,
|
|
7563
|
+
label: "completed",
|
|
7564
|
+
color: COLOR.accent
|
|
7565
|
+
});
|
|
7566
|
+
if (counts.pending) parts.push({
|
|
7567
|
+
count: counts.pending,
|
|
7568
|
+
label: "pending",
|
|
7569
|
+
color: COLOR.dim
|
|
7570
|
+
});
|
|
7571
|
+
if (counts.cancelled) parts.push({
|
|
7572
|
+
count: counts.cancelled,
|
|
7573
|
+
label: "cancelled",
|
|
7574
|
+
color: COLOR.error
|
|
7575
|
+
});
|
|
7576
|
+
if (parts.length === 0) return null;
|
|
7577
|
+
return /* @__PURE__ */ jsxs("text", {
|
|
7578
|
+
wrapMode: "none",
|
|
7579
|
+
children: [
|
|
7580
|
+
/* @__PURE__ */ jsx("span", {
|
|
7581
|
+
fg: COLOR.mute,
|
|
7582
|
+
children: " "
|
|
7583
|
+
}),
|
|
7584
|
+
parts.map((p, i) => /* @__PURE__ */ jsxs("span", { children: [
|
|
7585
|
+
i > 0 && /* @__PURE__ */ jsx("span", {
|
|
7586
|
+
fg: COLOR.mute,
|
|
7587
|
+
children: " · "
|
|
7588
|
+
}),
|
|
7589
|
+
/* @__PURE__ */ jsx("span", {
|
|
7590
|
+
fg: p.color,
|
|
7591
|
+
children: String(p.count)
|
|
7592
|
+
}),
|
|
7593
|
+
/* @__PURE__ */ jsx("span", {
|
|
7594
|
+
fg: COLOR.mute,
|
|
7595
|
+
children: ` ${p.label}`
|
|
7596
|
+
})
|
|
7597
|
+
] }, p.label)),
|
|
7598
|
+
/* @__PURE__ */ jsx("span", {
|
|
7599
|
+
fg: COLOR.mute,
|
|
7600
|
+
children: " "
|
|
7601
|
+
})
|
|
7602
|
+
]
|
|
7603
|
+
});
|
|
7604
|
+
}
|
|
7605
|
+
//#endregion
|
|
7279
7606
|
//#region src/tui/turn-details-modal.tsx
|
|
7280
7607
|
/** Max chars surfaced in the scrollable preview pane. Long enough that almost everything fits without truncation. */
|
|
7281
7608
|
const PREVIEW_CHAR_MAX = 8e3;
|
|
@@ -9375,6 +9702,13 @@ function AppShell() {
|
|
|
9375
9702
|
}));
|
|
9376
9703
|
return;
|
|
9377
9704
|
}
|
|
9705
|
+
if (matchesBinding(key, keybindings.openTodos) && screen === "chat" && currentSession) {
|
|
9706
|
+
modal.open(/* @__PURE__ */ jsx(TodosModal, {
|
|
9707
|
+
session: sessionRef.current,
|
|
9708
|
+
agent: agentRef.current
|
|
9709
|
+
}));
|
|
9710
|
+
return;
|
|
9711
|
+
}
|
|
9378
9712
|
if (matchesBinding(key, keybindings.enterSelectTurnMode) && screen === "chat" && !busy && !pendingApproval && !pendingInteraction) {
|
|
9379
9713
|
enterSelectMode();
|
|
9380
9714
|
return;
|
|
@@ -9508,6 +9842,7 @@ function AppShell() {
|
|
|
9508
9842
|
settings,
|
|
9509
9843
|
onSubmit: onSubmitPrompt,
|
|
9510
9844
|
session: currentSession,
|
|
9845
|
+
liveSession: sessionRef.current,
|
|
9511
9846
|
pending: pendingApproval,
|
|
9512
9847
|
onApproval: resolveHead,
|
|
9513
9848
|
pendingInteraction,
|