cvc-tui 0.4.0 → 0.4.2
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/entry.js +71148 -61
- package/package.json +2 -2
- package/dist/app/completion.js +0 -102
- package/dist/app/createGatewayEventHandler.js +0 -508
- package/dist/app/createSlashHandler.js +0 -101
- package/dist/app/delegationStore.js +0 -51
- package/dist/app/gatewayContext.js +0 -17
- package/dist/app/historyStore.js +0 -123
- package/dist/app/inputBuffer.js +0 -120
- package/dist/app/inputSelectionStore.js +0 -8
- package/dist/app/inputStore.js +0 -28
- package/dist/app/interfaces.js +0 -6
- package/dist/app/overlayStore.js +0 -40
- package/dist/app/promptStore.js +0 -44
- package/dist/app/queueStore.js +0 -25
- package/dist/app/scroll.js +0 -44
- package/dist/app/setupHandoff.js +0 -28
- package/dist/app/slash/commands/core.js +0 -479
- package/dist/app/slash/commands/debug.js +0 -44
- package/dist/app/slash/commands/ops.js +0 -498
- package/dist/app/slash/commands/session.js +0 -431
- package/dist/app/slash/commands/setup.js +0 -20
- package/dist/app/slash/commands/toggles.js +0 -40
- package/dist/app/slash/registry.js +0 -18
- package/dist/app/slash/types.js +0 -1
- package/dist/app/spawnHistoryStore.js +0 -105
- package/dist/app/turnController.js +0 -650
- package/dist/app/turnStore.js +0 -48
- package/dist/app/uiStore.js +0 -36
- package/dist/app/useComposerState.js +0 -265
- package/dist/app/useConfigSync.js +0 -144
- package/dist/app/useInputHandlers.js +0 -403
- package/dist/app/useLongRunToolCharms.js +0 -50
- package/dist/app/useMainApp.js +0 -629
- package/dist/app/useSessionLifecycle.js +0 -175
- package/dist/app/useSubmission.js +0 -287
- package/dist/app.js +0 -15
- package/dist/banner.js +0 -57
- package/dist/components/agentsOverlay.js +0 -474
- package/dist/components/appChrome.js +0 -252
- package/dist/components/appLayout.js +0 -121
- package/dist/components/appOverlays.js +0 -65
- package/dist/components/branding.js +0 -97
- package/dist/components/fpsOverlay.js +0 -22
- package/dist/components/helpHint.js +0 -21
- package/dist/components/markdown.js +0 -501
- package/dist/components/maskedPrompt.js +0 -12
- package/dist/components/messageLine.js +0 -82
- package/dist/components/modelPicker.js +0 -254
- package/dist/components/overlayControls.js +0 -30
- package/dist/components/overlays/confirmPrompt.js +0 -25
- package/dist/components/overlays/helpOverlay.js +0 -76
- package/dist/components/overlays/historySearch.js +0 -49
- package/dist/components/overlays/modelPicker.js +0 -60
- package/dist/components/overlays/overlayUtils.js +0 -19
- package/dist/components/overlays/secretPrompt.js +0 -36
- package/dist/components/overlays/sessionPicker.js +0 -93
- package/dist/components/overlays/skillsHub.js +0 -71
- package/dist/components/prompts.js +0 -95
- package/dist/components/queuedMessages.js +0 -24
- package/dist/components/sessionPicker.js +0 -130
- package/dist/components/skillsHub.js +0 -165
- package/dist/components/streamingAssistant.js +0 -35
- package/dist/components/streamingMarkdown.js +0 -144
- package/dist/components/textInput.js +0 -794
- package/dist/components/themed.js +0 -12
- package/dist/components/thinking.js +0 -496
- package/dist/components/todoPanel.js +0 -40
- package/dist/components/transcript.js +0 -22
- package/dist/config/env.js +0 -18
- package/dist/config/limits.js +0 -22
- package/dist/config/timing.js +0 -18
- package/dist/content/charms.js +0 -5
- package/dist/content/faces.js +0 -21
- package/dist/content/fortunes.js +0 -29
- package/dist/content/hotkeys.js +0 -38
- package/dist/content/placeholders.js +0 -15
- package/dist/content/setup.js +0 -14
- package/dist/content/verbs.js +0 -41
- package/dist/domain/details.js +0 -53
- package/dist/domain/messages.js +0 -63
- package/dist/domain/paths.js +0 -16
- package/dist/domain/providers.js +0 -11
- package/dist/domain/roles.js +0 -6
- package/dist/domain/slash.js +0 -11
- package/dist/domain/usage.js +0 -1
- package/dist/domain/viewport.js +0 -33
- package/dist/gateway/client.js +0 -312
- package/dist/gatewayClient.js +0 -574
- package/dist/gatewayTypes.js +0 -1
- package/dist/hooks/useCompletion.js +0 -86
- package/dist/hooks/useGitBranch.js +0 -58
- package/dist/hooks/useInputHistory.js +0 -12
- package/dist/hooks/useQueue.js +0 -57
- package/dist/hooks/useVirtualHistory.js +0 -401
- package/dist/lib/circularBuffer.js +0 -43
- package/dist/lib/clipboard.js +0 -126
- package/dist/lib/editor.js +0 -41
- package/dist/lib/editor.test.js +0 -58
- package/dist/lib/emoji.js +0 -49
- package/dist/lib/externalCli.js +0 -11
- package/dist/lib/forceTruecolor.js +0 -26
- package/dist/lib/fpsStore.js +0 -36
- package/dist/lib/gracefulExit.js +0 -29
- package/dist/lib/history.js +0 -69
- package/dist/lib/inputMetrics.js +0 -143
- package/dist/lib/liveProgress.js +0 -51
- package/dist/lib/liveProgress.test.js +0 -89
- package/dist/lib/mathUnicode.js +0 -685
- package/dist/lib/memory.js +0 -123
- package/dist/lib/memoryMonitor.js +0 -76
- package/dist/lib/messages.js +0 -3
- package/dist/lib/messages.test.js +0 -25
- package/dist/lib/osc52.js +0 -53
- package/dist/lib/perfPane.js +0 -94
- package/dist/lib/platform.js +0 -312
- package/dist/lib/precisionWheel.js +0 -25
- package/dist/lib/reasoning.js +0 -39
- package/dist/lib/rpc.js +0 -26
- package/dist/lib/subagentTree.js +0 -287
- package/dist/lib/syntax.js +0 -89
- package/dist/lib/terminalModes.js +0 -46
- package/dist/lib/terminalParity.js +0 -48
- package/dist/lib/terminalSetup.js +0 -321
- package/dist/lib/text.js +0 -203
- package/dist/lib/text.test.js +0 -18
- package/dist/lib/todo.js +0 -2
- package/dist/lib/todo.test.js +0 -22
- package/dist/lib/viewportStore.js +0 -82
- package/dist/lib/virtualHeights.js +0 -61
- package/dist/lib/wheelAccel.js +0 -143
- package/dist/theme.js +0 -398
- package/dist/types.js +0 -1
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
-
// @ts-nocheck
|
|
3
|
-
// SPDX-License-Identifier: MIT
|
|
4
|
-
// Ported from CVC Agent (https://github.com/NousResearch/cvc)
|
|
5
|
-
// Original Copyright (c) 2025 Nous Research. CVC adaptations (c) 2026 Jai Kumar Meena.
|
|
6
|
-
import { Text } from '@cvc/ink';
|
|
7
|
-
import { useStore } from '@nanostores/react';
|
|
8
|
-
import { $uiState } from '../app/uiStore.js';
|
|
9
|
-
export function Fg({ bold, c, children, dim, italic, literal, strikethrough, underline, wrap }) {
|
|
10
|
-
const { theme } = useStore($uiState);
|
|
11
|
-
return (_jsx(Text, { color: literal ?? (c && theme.color[c]), dimColor: dim, bold, italic, strikethrough, underline, wrap, children: children }));
|
|
12
|
-
}
|
|
@@ -1,496 +0,0 @@
|
|
|
1
|
-
import { createElement as _createElement } from "react";
|
|
2
|
-
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
3
|
-
// @ts-nocheck
|
|
4
|
-
// SPDX-License-Identifier: MIT
|
|
5
|
-
// Ported from CVC Agent (https://github.com/NousResearch/cvc)
|
|
6
|
-
// Original Copyright (c) 2025 Nous Research. CVC adaptations (c) 2026 Jai Kumar Meena.
|
|
7
|
-
import { Box, NoSelect, Text } from '@cvc/ink';
|
|
8
|
-
import { memo, useEffect, useMemo, useState } from 'react';
|
|
9
|
-
import spinners from 'unicode-animations';
|
|
10
|
-
import { THINKING_COT_MAX } from '../config/limits.js';
|
|
11
|
-
import { sectionMode } from '../domain/details.js';
|
|
12
|
-
import { buildSubagentTree, fmtCost, fmtTokens, formatSummary as formatSpawnSummary, hotnessBucket, peakHotness, sparkline, treeTotals, widthByDepth } from '../lib/subagentTree.js';
|
|
13
|
-
import { boundedLiveRenderText, compactPreview, estimateTokensRough, fmtK, formatToolCall, parseToolTrailResultLine, pick, splitToolDuration, thinkingPreview, toolTrailLabel } from '../lib/text.js';
|
|
14
|
-
const THINK = ['helix', 'breathe', 'orbit', 'dna', 'waverows', 'snake', 'pulse'];
|
|
15
|
-
const TOOL = ['cascade', 'scan', 'diagswipe', 'fillsweep', 'rain', 'columns', 'sparkle'];
|
|
16
|
-
const fmtElapsed = (ms) => {
|
|
17
|
-
const sec = Math.max(0, ms) / 1000;
|
|
18
|
-
return sec < 10 ? `${sec.toFixed(1)}s` : `${Math.round(sec)}s`;
|
|
19
|
-
};
|
|
20
|
-
const nextTreeRails = (rails, branch) => [...rails, branch === 'mid'];
|
|
21
|
-
const treeLead = (rails, branch) => `${rails.map(on => (on ? '│ ' : ' ')).join('')}${branch === 'mid' ? '├─ ' : '└─ '}`;
|
|
22
|
-
// ── Primitives ───────────────────────────────────────────────────────
|
|
23
|
-
function TreeRow({ branch, children, rails = [], stemColor, stemDim = true, t }) {
|
|
24
|
-
const lead = treeLead(rails, branch);
|
|
25
|
-
return (_jsxs(Box, { children: [_jsx(NoSelect, { flexShrink: 0, fromLeftEdge: true, width: lead.length, children: _jsx(Text, { color: stemColor ?? t.color.muted, dim: stemDim, children: lead }) }), _jsx(Box, { flexDirection: "column", flexGrow: 1, children: children })] }));
|
|
26
|
-
}
|
|
27
|
-
function TreeTextRow({ branch, color, content, dimColor, rails = [], t, wrap = 'wrap-trim' }) {
|
|
28
|
-
const text = dimColor ? (_jsx(Text, { color: color, dim: true, wrap: wrap, children: content })) : (_jsx(Text, { color: color, wrap: wrap, children: content }));
|
|
29
|
-
return (_jsx(TreeRow, { branch: branch, rails: rails, t: t, children: text }));
|
|
30
|
-
}
|
|
31
|
-
function TreeNode({ branch, children, header, open, rails = [], stemColor, stemDim, t }) {
|
|
32
|
-
return (_jsxs(Box, { flexDirection: "column", children: [_jsx(TreeRow, { branch: branch, rails: rails, stemColor: stemColor, stemDim: stemDim, t: t, children: header }), open ? children?.(nextTreeRails(rails, branch)) : null] }));
|
|
33
|
-
}
|
|
34
|
-
export function Spinner({ color, variant = 'think' }) {
|
|
35
|
-
const spin = useMemo(() => {
|
|
36
|
-
const raw = spinners[pick(variant === 'tool' ? TOOL : THINK)];
|
|
37
|
-
return { ...raw, frames: raw.frames.map(f => [...f][0] ?? '⠀') };
|
|
38
|
-
}, [variant]);
|
|
39
|
-
const [frame, setFrame] = useState(0);
|
|
40
|
-
useEffect(() => {
|
|
41
|
-
setFrame(0);
|
|
42
|
-
}, [spin]);
|
|
43
|
-
useEffect(() => {
|
|
44
|
-
const id = setInterval(() => setFrame(f => (f + 1) % spin.frames.length), spin.interval);
|
|
45
|
-
return () => clearInterval(id);
|
|
46
|
-
}, [spin]);
|
|
47
|
-
return _jsx(Text, { color: color, children: spin.frames[frame] });
|
|
48
|
-
}
|
|
49
|
-
function Detail({ branch = 'last', color, content, dimColor, rails = [], t }) {
|
|
50
|
-
return _jsx(TreeTextRow, { branch: branch, color: color, content: content, dimColor: dimColor, rails: rails, t: t });
|
|
51
|
-
}
|
|
52
|
-
function StreamCursor({ color, dimColor, streaming = false, visible = false }) {
|
|
53
|
-
const [on, setOn] = useState(true);
|
|
54
|
-
useEffect(() => {
|
|
55
|
-
if (!visible || !streaming) {
|
|
56
|
-
setOn(true);
|
|
57
|
-
return;
|
|
58
|
-
}
|
|
59
|
-
const id = setInterval(() => setOn(v => !v), 420);
|
|
60
|
-
return () => clearInterval(id);
|
|
61
|
-
}, [streaming, visible]);
|
|
62
|
-
if (!visible) {
|
|
63
|
-
return null;
|
|
64
|
-
}
|
|
65
|
-
return dimColor ? (_jsx(Text, { color: color, dim: true, children: streaming && on ? '▍' : ' ' })) : (_jsx(Text, { color: color, children: streaming && on ? '▍' : ' ' }));
|
|
66
|
-
}
|
|
67
|
-
function Chevron({ count, onClick, open, suffix, t, title, tone = 'dim' }) {
|
|
68
|
-
const color = tone === 'error' ? t.color.error : tone === 'warn' ? t.color.warn : t.color.muted;
|
|
69
|
-
return (_jsx(Box, { onClick: (e) => onClick(!!e?.shiftKey || !!e?.ctrlKey), children: _jsxs(Text, { color: color, dim: tone === 'dim', children: [_jsx(Text, { color: t.color.accent, children: open ? '▾ ' : '▸ ' }), title, typeof count === 'number' ? ` (${count})` : '', suffix ? (_jsxs(Text, { color: t.color.statusFg, dim: true, children: [' ', suffix] })) : null] }) }));
|
|
70
|
-
}
|
|
71
|
-
function heatColor(node, peak, theme) {
|
|
72
|
-
const palette = [theme.color.border, theme.color.accent, theme.color.primary, theme.color.warn, theme.color.error];
|
|
73
|
-
const idx = hotnessBucket(node.aggregate.hotness, peak, palette.length);
|
|
74
|
-
// Below the median bucket we keep the default dim stem so cool branches
|
|
75
|
-
// fade into the chrome — only "hot" branches draw the eye.
|
|
76
|
-
if (idx < 2) {
|
|
77
|
-
return undefined;
|
|
78
|
-
}
|
|
79
|
-
return palette[idx];
|
|
80
|
-
}
|
|
81
|
-
function SubagentAccordion({ branch, expanded, node, peak, rails = [], t }) {
|
|
82
|
-
const [open, setOpen] = useState(expanded);
|
|
83
|
-
const [deep, setDeep] = useState(expanded);
|
|
84
|
-
const [openThinking, setOpenThinking] = useState(expanded);
|
|
85
|
-
const [openTools, setOpenTools] = useState(expanded);
|
|
86
|
-
const [openNotes, setOpenNotes] = useState(expanded);
|
|
87
|
-
const [openKids, setOpenKids] = useState(expanded);
|
|
88
|
-
useEffect(() => {
|
|
89
|
-
if (!expanded) {
|
|
90
|
-
return;
|
|
91
|
-
}
|
|
92
|
-
setOpen(true);
|
|
93
|
-
setDeep(true);
|
|
94
|
-
setOpenThinking(true);
|
|
95
|
-
setOpenTools(true);
|
|
96
|
-
setOpenNotes(true);
|
|
97
|
-
setOpenKids(true);
|
|
98
|
-
}, [expanded]);
|
|
99
|
-
const expandAll = () => {
|
|
100
|
-
setOpen(true);
|
|
101
|
-
setDeep(true);
|
|
102
|
-
setOpenThinking(true);
|
|
103
|
-
setOpenTools(true);
|
|
104
|
-
setOpenNotes(true);
|
|
105
|
-
setOpenKids(true);
|
|
106
|
-
};
|
|
107
|
-
const item = node.item;
|
|
108
|
-
const children = node.children;
|
|
109
|
-
const aggregate = node.aggregate;
|
|
110
|
-
const statusTone = item.status === 'failed' ? 'error' : item.status === 'interrupted' ? 'warn' : 'dim';
|
|
111
|
-
const prefix = item.taskCount > 1 ? `[${item.index + 1}/${item.taskCount}] ` : '';
|
|
112
|
-
const goalLabel = item.goal || `Subagent ${item.index + 1}`;
|
|
113
|
-
const title = `${prefix}${open ? goalLabel : compactPreview(goalLabel, 60)}`;
|
|
114
|
-
const summary = compactPreview((item.summary || '').replace(/\s+/g, ' ').trim(), 72);
|
|
115
|
-
// Suffix packs branch rollup: status · elapsed · per-branch tool/agent/token/cost.
|
|
116
|
-
// Emphasises the numbers the user can't easily eyeball from a flat list.
|
|
117
|
-
const statusLabel = item.status === 'queued' ? 'queued' : item.status === 'running' ? 'running' : String(item.status);
|
|
118
|
-
const rollupBits = [statusLabel];
|
|
119
|
-
if (item.durationSeconds) {
|
|
120
|
-
rollupBits.push(fmtElapsed(item.durationSeconds * 1000));
|
|
121
|
-
}
|
|
122
|
-
const localTools = item.toolCount ?? 0;
|
|
123
|
-
const subtreeTools = aggregate.totalTools - localTools;
|
|
124
|
-
if (localTools > 0) {
|
|
125
|
-
rollupBits.push(`${localTools} tool${localTools === 1 ? '' : 's'}`);
|
|
126
|
-
}
|
|
127
|
-
const localTokens = (item.inputTokens ?? 0) + (item.outputTokens ?? 0);
|
|
128
|
-
if (localTokens > 0) {
|
|
129
|
-
rollupBits.push(`${fmtTokens(localTokens)} tok`);
|
|
130
|
-
}
|
|
131
|
-
const localCost = item.costUsd ?? 0;
|
|
132
|
-
if (localCost > 0) {
|
|
133
|
-
rollupBits.push(fmtCost(localCost));
|
|
134
|
-
}
|
|
135
|
-
const filesLocal = (item.filesWritten?.length ?? 0) + (item.filesRead?.length ?? 0);
|
|
136
|
-
if (filesLocal > 0) {
|
|
137
|
-
rollupBits.push(`⎘${filesLocal}`);
|
|
138
|
-
}
|
|
139
|
-
if (children.length > 0) {
|
|
140
|
-
rollupBits.push(`${aggregate.descendantCount}↓`);
|
|
141
|
-
if (subtreeTools > 0) {
|
|
142
|
-
rollupBits.push(`+${subtreeTools}t sub`);
|
|
143
|
-
}
|
|
144
|
-
const subCost = aggregate.costUsd - localCost;
|
|
145
|
-
if (subCost >= 0.01) {
|
|
146
|
-
rollupBits.push(`+${fmtCost(subCost)} sub`);
|
|
147
|
-
}
|
|
148
|
-
if (aggregate.activeCount > 0 && item.status !== 'running') {
|
|
149
|
-
rollupBits.push(`⚡${aggregate.activeCount}`);
|
|
150
|
-
}
|
|
151
|
-
}
|
|
152
|
-
const suffix = rollupBits.join(' · ');
|
|
153
|
-
const thinkingText = item.thinking.join('\n');
|
|
154
|
-
const hasThinking = Boolean(thinkingText);
|
|
155
|
-
const hasTools = item.tools.length > 0;
|
|
156
|
-
const noteRows = [...(summary ? [summary] : []), ...item.notes];
|
|
157
|
-
const hasNotes = noteRows.length > 0;
|
|
158
|
-
const noteColor = statusTone === 'error' ? t.color.error : statusTone === 'warn' ? t.color.warn : t.color.muted;
|
|
159
|
-
const sections = [];
|
|
160
|
-
if (hasThinking) {
|
|
161
|
-
sections.push({
|
|
162
|
-
header: (_jsx(Chevron, { count: item.thinking.length, onClick: shift => {
|
|
163
|
-
if (shift) {
|
|
164
|
-
expandAll();
|
|
165
|
-
}
|
|
166
|
-
else {
|
|
167
|
-
setOpenThinking(v => !v);
|
|
168
|
-
}
|
|
169
|
-
}, open: openThinking, t: t, title: "Thinking" })),
|
|
170
|
-
key: 'thinking',
|
|
171
|
-
open: openThinking,
|
|
172
|
-
render: childRails => (_jsx(Thinking, { active: item.status === 'running', branch: "last", mode: "full", rails: childRails, reasoning: thinkingText, streaming: item.status === 'running', t: t }))
|
|
173
|
-
});
|
|
174
|
-
}
|
|
175
|
-
if (hasTools) {
|
|
176
|
-
sections.push({
|
|
177
|
-
header: (_jsx(Chevron, { count: item.tools.length, onClick: shift => {
|
|
178
|
-
if (shift) {
|
|
179
|
-
expandAll();
|
|
180
|
-
}
|
|
181
|
-
else {
|
|
182
|
-
setOpenTools(v => !v);
|
|
183
|
-
}
|
|
184
|
-
}, open: openTools, t: t, title: "Tool calls" })),
|
|
185
|
-
key: 'tools',
|
|
186
|
-
open: openTools,
|
|
187
|
-
render: childRails => (_jsx(Box, { flexDirection: "column", children: item.tools.map((line, index) => (_jsx(TreeTextRow, { branch: index === item.tools.length - 1 ? 'last' : 'mid', color: t.color.text, content: _jsxs(_Fragment, { children: [_jsx(Text, { color: t.color.accent, children: "\u25CF " }), line] }), rails: childRails, t: t }, `${item.id}-tool-${index}`))) }))
|
|
188
|
-
});
|
|
189
|
-
}
|
|
190
|
-
if (hasNotes) {
|
|
191
|
-
sections.push({
|
|
192
|
-
header: (_jsx(Chevron, { count: noteRows.length, onClick: shift => {
|
|
193
|
-
if (shift) {
|
|
194
|
-
expandAll();
|
|
195
|
-
}
|
|
196
|
-
else {
|
|
197
|
-
setOpenNotes(v => !v);
|
|
198
|
-
}
|
|
199
|
-
}, open: openNotes, t: t, title: "Progress", tone: statusTone })),
|
|
200
|
-
key: 'notes',
|
|
201
|
-
open: openNotes,
|
|
202
|
-
render: childRails => (_jsx(Box, { flexDirection: "column", children: noteRows.map((line, index) => (_jsx(TreeTextRow, { branch: index === noteRows.length - 1 ? 'last' : 'mid', color: noteColor, content: line, dimColor: statusTone === 'dim', rails: childRails, t: t }, `${item.id}-note-${index}`))) }))
|
|
203
|
-
});
|
|
204
|
-
}
|
|
205
|
-
if (children.length > 0) {
|
|
206
|
-
// Nested grandchildren — rendered recursively via SubagentAccordion,
|
|
207
|
-
// sharing the same keybindings / expand semantics as top-level nodes.
|
|
208
|
-
sections.push({
|
|
209
|
-
header: (_jsx(Chevron, { count: children.length, onClick: shift => {
|
|
210
|
-
if (shift) {
|
|
211
|
-
expandAll();
|
|
212
|
-
}
|
|
213
|
-
else {
|
|
214
|
-
setOpenKids(v => !v);
|
|
215
|
-
}
|
|
216
|
-
}, open: openKids, suffix: `d${item.depth + 1} · ${aggregate.descendantCount} total`, t: t, title: "Spawned" })),
|
|
217
|
-
key: 'subagents',
|
|
218
|
-
open: openKids,
|
|
219
|
-
render: childRails => (_jsx(Box, { flexDirection: "column", children: children.map((child, i) => (_jsx(SubagentAccordion, { branch: i === children.length - 1 ? 'last' : 'mid', expanded: expanded || deep, node: child, peak: peak, rails: childRails, t: t }, child.item.id))) }))
|
|
220
|
-
});
|
|
221
|
-
}
|
|
222
|
-
// Heatmap: amber→error gradient on the stem when this branch is "hot"
|
|
223
|
-
// (high tools/sec) relative to the whole tree's peak.
|
|
224
|
-
const stem = heatColor(node, peak, t);
|
|
225
|
-
return (_jsx(TreeNode, { branch: branch, header: _jsx(Chevron, { onClick: shift => {
|
|
226
|
-
if (shift) {
|
|
227
|
-
expandAll();
|
|
228
|
-
return;
|
|
229
|
-
}
|
|
230
|
-
setOpen(v => {
|
|
231
|
-
if (!v) {
|
|
232
|
-
setDeep(false);
|
|
233
|
-
}
|
|
234
|
-
return !v;
|
|
235
|
-
});
|
|
236
|
-
}, open: open, suffix: suffix, t: t, title: title, tone: statusTone }), open: open, rails: rails, stemColor: stem, stemDim: stem == null, t: t, children: childRails => (_jsx(Box, { flexDirection: "column", children: sections.map((section, index) => (_jsx(TreeNode, { branch: index === sections.length - 1 ? 'last' : 'mid', header: section.header, open: section.open, rails: childRails, t: t, children: section.render }, `${item.id}-${section.key}`))) })) }));
|
|
237
|
-
}
|
|
238
|
-
// ── Thinking ─────────────────────────────────────────────────────────
|
|
239
|
-
export const Thinking = memo(function Thinking({ active = false, branch = 'last', mode = 'truncated', rails = [], reasoning, streaming = false, t }) {
|
|
240
|
-
const preview = useMemo(() => {
|
|
241
|
-
const raw = thinkingPreview(reasoning, mode, THINKING_COT_MAX);
|
|
242
|
-
return mode === 'full' ? boundedLiveRenderText(raw) : raw;
|
|
243
|
-
}, [mode, reasoning]);
|
|
244
|
-
const lines = useMemo(() => preview.split('\n').map(line => line.replace(/\t/g, ' ')), [preview]);
|
|
245
|
-
if (!preview && !active) {
|
|
246
|
-
return null;
|
|
247
|
-
}
|
|
248
|
-
return (_jsx(TreeRow, { branch: branch, rails: rails, t: t, children: _jsx(Box, { flexDirection: "column", flexGrow: 1, children: preview ? (mode === 'full' ? (lines.map((line, index) => (_jsxs(Text, { color: t.color.muted, wrap: "wrap-trim", children: [line || ' ', index === lines.length - 1 ? (_jsx(StreamCursor, { color: t.color.muted, streaming: streaming, visible: active })) : null] }, index)))) : (_jsxs(Text, { color: t.color.muted, wrap: "truncate-end", children: [preview, _jsx(StreamCursor, { color: t.color.muted, streaming: streaming, visible: active })] }))) : (_jsx(Text, { color: t.color.muted, children: _jsx(StreamCursor, { color: t.color.muted, streaming: streaming, visible: active }) })) }) }));
|
|
249
|
-
});
|
|
250
|
-
export const ToolTrail = memo(function ToolTrail({ busy = false, commandOverride = false, detailsMode = 'collapsed', outcome = '', reasoningActive = false, reasoning = '', reasoningTokens, reasoningStreaming = false, sections, subagents = [], t, tools = [], toolTokens, trail = [], activity = [] }) {
|
|
251
|
-
const visible = useMemo(() => ({
|
|
252
|
-
thinking: sectionMode('thinking', detailsMode, sections, commandOverride),
|
|
253
|
-
tools: sectionMode('tools', detailsMode, sections, commandOverride),
|
|
254
|
-
subagents: sectionMode('subagents', detailsMode, sections, commandOverride),
|
|
255
|
-
activity: sectionMode('activity', detailsMode, sections, commandOverride)
|
|
256
|
-
}), [commandOverride, detailsMode, sections]);
|
|
257
|
-
const [now, setNow] = useState(() => Date.now());
|
|
258
|
-
// Local toggles own the open state once mounted. Init from the resolved
|
|
259
|
-
// section visibility so default-expanded sections (thinking/tools) render
|
|
260
|
-
// open on first paint; the useEffect below re-syncs when the user mutates
|
|
261
|
-
// visibility at runtime via /details. NEVER OR these against
|
|
262
|
-
// `visible.X === 'expanded'` at render time — that locks the panel open
|
|
263
|
-
// and silently breaks manual chevron clicks for default-expanded
|
|
264
|
-
// sections (regression caught after #14968).
|
|
265
|
-
const [openThinking, setOpenThinking] = useState(visible.thinking === 'expanded');
|
|
266
|
-
const [openTools, setOpenTools] = useState(visible.tools === 'expanded');
|
|
267
|
-
const [openSubagents, setOpenSubagents] = useState(visible.subagents === 'expanded');
|
|
268
|
-
const [deepSubagents, setDeepSubagents] = useState(visible.subagents === 'expanded');
|
|
269
|
-
const [openMeta, setOpenMeta] = useState(visible.activity === 'expanded');
|
|
270
|
-
useEffect(() => {
|
|
271
|
-
if (!tools.length || (visible.tools !== 'expanded' && !openTools)) {
|
|
272
|
-
return;
|
|
273
|
-
}
|
|
274
|
-
const id = setInterval(() => setNow(Date.now()), 500);
|
|
275
|
-
return () => clearInterval(id);
|
|
276
|
-
}, [openTools, tools.length, visible.tools]);
|
|
277
|
-
useEffect(() => {
|
|
278
|
-
setOpenThinking(visible.thinking === 'expanded');
|
|
279
|
-
setOpenTools(visible.tools === 'expanded');
|
|
280
|
-
setOpenSubagents(visible.subagents === 'expanded');
|
|
281
|
-
setOpenMeta(visible.activity === 'expanded');
|
|
282
|
-
}, [visible]);
|
|
283
|
-
const cot = useMemo(() => thinkingPreview(reasoning, 'full', THINKING_COT_MAX), [reasoning]);
|
|
284
|
-
// Spawn-tree derivations must live above any early return so React's
|
|
285
|
-
// rules-of-hooks sees a stable call order. Cheap O(N) builds memoised
|
|
286
|
-
// by subagent-list identity.
|
|
287
|
-
const spawnTree = useMemo(() => buildSubagentTree(subagents), [subagents]);
|
|
288
|
-
const spawnPeak = useMemo(() => peakHotness(spawnTree), [spawnTree]);
|
|
289
|
-
const spawnTotals = useMemo(() => treeTotals(spawnTree), [spawnTree]);
|
|
290
|
-
const spawnWidths = useMemo(() => widthByDepth(spawnTree), [spawnTree]);
|
|
291
|
-
const spawnSpark = useMemo(() => sparkline(spawnWidths), [spawnWidths]);
|
|
292
|
-
const spawnSummaryLabel = useMemo(() => formatSpawnSummary(spawnTotals), [spawnTotals]);
|
|
293
|
-
if (!busy &&
|
|
294
|
-
!trail.length &&
|
|
295
|
-
!tools.length &&
|
|
296
|
-
!subagents.length &&
|
|
297
|
-
!activity.length &&
|
|
298
|
-
!cot &&
|
|
299
|
-
!reasoningActive &&
|
|
300
|
-
!outcome) {
|
|
301
|
-
return null;
|
|
302
|
-
}
|
|
303
|
-
// ── Build groups + meta ────────────────────────────────────────
|
|
304
|
-
const groups = [];
|
|
305
|
-
const meta = [];
|
|
306
|
-
const pushDetail = (row) => (groups.at(-1)?.details ?? meta).push(row);
|
|
307
|
-
for (const [i, line] of trail.entries()) {
|
|
308
|
-
const parsed = parseToolTrailResultLine(line);
|
|
309
|
-
if (parsed) {
|
|
310
|
-
groups.push({
|
|
311
|
-
color: parsed.mark === '✗' ? t.color.error : t.color.text,
|
|
312
|
-
content: parsed.call,
|
|
313
|
-
details: [],
|
|
314
|
-
key: `tr-${i}`,
|
|
315
|
-
label: parsed.call
|
|
316
|
-
});
|
|
317
|
-
if (parsed.detail) {
|
|
318
|
-
pushDetail({
|
|
319
|
-
color: parsed.mark === '✗' ? t.color.error : t.color.muted,
|
|
320
|
-
content: parsed.detail,
|
|
321
|
-
dimColor: parsed.mark !== '✗',
|
|
322
|
-
key: `tr-${i}-d`
|
|
323
|
-
});
|
|
324
|
-
}
|
|
325
|
-
continue;
|
|
326
|
-
}
|
|
327
|
-
if (line.startsWith('drafting ')) {
|
|
328
|
-
const label = toolTrailLabel(line.slice(9).replace(/…$/, '').trim());
|
|
329
|
-
groups.push({
|
|
330
|
-
color: t.color.text,
|
|
331
|
-
content: label,
|
|
332
|
-
details: [{ color: t.color.muted, content: 'drafting...', dimColor: true, key: `tr-${i}-d` }],
|
|
333
|
-
key: `tr-${i}`,
|
|
334
|
-
label
|
|
335
|
-
});
|
|
336
|
-
continue;
|
|
337
|
-
}
|
|
338
|
-
if (line === 'analyzing tool output…') {
|
|
339
|
-
pushDetail({
|
|
340
|
-
color: t.color.muted,
|
|
341
|
-
dimColor: true,
|
|
342
|
-
key: `tr-${i}`,
|
|
343
|
-
content: groups.length ? (_jsxs(_Fragment, { children: [_jsx(Spinner, { color: t.color.accent, variant: "think" }), " ", line] })) : (line)
|
|
344
|
-
});
|
|
345
|
-
continue;
|
|
346
|
-
}
|
|
347
|
-
meta.push({ color: t.color.muted, content: line, dimColor: true, key: `tr-${i}` });
|
|
348
|
-
}
|
|
349
|
-
for (const tool of tools) {
|
|
350
|
-
const label = formatToolCall(tool.name, tool.context || '');
|
|
351
|
-
groups.push({
|
|
352
|
-
color: t.color.text,
|
|
353
|
-
key: tool.id,
|
|
354
|
-
label,
|
|
355
|
-
details: [],
|
|
356
|
-
content: (_jsxs(_Fragment, { children: [_jsx(Spinner, { color: t.color.accent, variant: "tool" }), " ", label, tool.startedAt ? ` (${fmtElapsed(now - tool.startedAt)})` : ''] }))
|
|
357
|
-
});
|
|
358
|
-
}
|
|
359
|
-
for (const item of activity.slice(-4)) {
|
|
360
|
-
const glyph = item.tone === 'error' ? '✗' : item.tone === 'warn' ? '!' : '·';
|
|
361
|
-
const color = item.tone === 'error' ? t.color.error : item.tone === 'warn' ? t.color.warn : t.color.muted;
|
|
362
|
-
meta.push({ color, content: `${glyph} ${item.text}`, dimColor: item.tone === 'info', key: `a-${item.id}` });
|
|
363
|
-
}
|
|
364
|
-
// ── Derived ────────────────────────────────────────────────────
|
|
365
|
-
const hasTools = groups.length > 0;
|
|
366
|
-
const hasSubagents = subagents.length > 0;
|
|
367
|
-
const hasMeta = meta.length > 0;
|
|
368
|
-
const hasThinking = !!cot || reasoningActive || reasoningStreaming;
|
|
369
|
-
const thinkingLive = reasoningActive || reasoningStreaming;
|
|
370
|
-
const tokenCount = reasoningTokens && reasoningTokens > 0 ? reasoningTokens : reasoning ? estimateTokensRough(reasoning) : 0;
|
|
371
|
-
const toolTokenCount = toolTokens ?? 0;
|
|
372
|
-
const totalTokenCount = tokenCount + toolTokenCount;
|
|
373
|
-
const thinkingTokensLabel = tokenCount > 0 ? `~${fmtK(tokenCount)} tokens` : null;
|
|
374
|
-
const toolTokensLabel = toolTokens !== undefined && toolTokens > 0 ? `~${fmtK(toolTokens)} tokens` : undefined;
|
|
375
|
-
const totalTokensLabel = tokenCount > 0 && toolTokenCount > 0 ? `~${fmtK(totalTokenCount)} total` : null;
|
|
376
|
-
const delegateGroups = groups.filter(g => g.label.startsWith('Delegate Task'));
|
|
377
|
-
const inlineDelegateKey = hasSubagents && delegateGroups.length === 1 ? delegateGroups[0].key : null;
|
|
378
|
-
const toolLabel = (group) => {
|
|
379
|
-
const { duration, label } = splitToolDuration(String(group.content));
|
|
380
|
-
return duration ? (_jsxs(_Fragment, { children: [label, _jsx(Text, { color: t.color.statusFg, dim: true, children: duration })] })) : (group.content);
|
|
381
|
-
};
|
|
382
|
-
// ── Backstop: floating alerts when every panel is hidden ─────────
|
|
383
|
-
//
|
|
384
|
-
// Per-section overrides win over the global details_mode (they're computed
|
|
385
|
-
// by sectionMode), so we only collapse to nothing when EVERY section is
|
|
386
|
-
// resolved to hidden — that way `details_mode: hidden` + `sections.tools:
|
|
387
|
-
// expanded` still renders the tools panel. When all panels are hidden
|
|
388
|
-
// AND ambient errors/warnings exist, surface them as a compact inline
|
|
389
|
-
// backstop so quiet-mode users aren't blind to failures.
|
|
390
|
-
const allHidden = visible.thinking === 'hidden' &&
|
|
391
|
-
visible.tools === 'hidden' &&
|
|
392
|
-
visible.subagents === 'hidden' &&
|
|
393
|
-
visible.activity === 'hidden';
|
|
394
|
-
if (allHidden) {
|
|
395
|
-
const alerts = activity.filter(i => i.tone !== 'info').slice(-2);
|
|
396
|
-
return alerts.length ? (_jsx(Box, { flexDirection: "column", children: alerts.map(i => (_jsxs(Text, { color: i.tone === 'error' ? t.color.error : t.color.warn, children: [i.tone === 'error' ? '✗' : '!', " ", i.text] }, `ha-${i.id}`))) })) : null;
|
|
397
|
-
}
|
|
398
|
-
// ── Tree render fragments ──────────────────────────────────────
|
|
399
|
-
//
|
|
400
|
-
// Shift+click on any chevron expands every NON-hidden section at once —
|
|
401
|
-
// hidden sections stay hidden so the override is honoured.
|
|
402
|
-
const expandAll = () => {
|
|
403
|
-
if (visible.thinking !== 'hidden') {
|
|
404
|
-
setOpenThinking(true);
|
|
405
|
-
}
|
|
406
|
-
if (visible.tools !== 'hidden') {
|
|
407
|
-
setOpenTools(true);
|
|
408
|
-
}
|
|
409
|
-
if (visible.subagents !== 'hidden') {
|
|
410
|
-
setOpenSubagents(true);
|
|
411
|
-
setDeepSubagents(true);
|
|
412
|
-
}
|
|
413
|
-
if (visible.activity !== 'hidden') {
|
|
414
|
-
setOpenMeta(true);
|
|
415
|
-
}
|
|
416
|
-
};
|
|
417
|
-
const metaTone = activity.some(i => i.tone === 'error')
|
|
418
|
-
? 'error'
|
|
419
|
-
: activity.some(i => i.tone === 'warn')
|
|
420
|
-
? 'warn'
|
|
421
|
-
: 'dim';
|
|
422
|
-
const renderSubagentList = (rails) => (_jsx(Box, { flexDirection: "column", children: spawnTree.map((node, index) => (_jsx(SubagentAccordion, { branch: index === spawnTree.length - 1 ? 'last' : 'mid', expanded: visible.subagents === 'expanded' || deepSubagents, node: node, peak: spawnPeak, rails: rails, t: t }, node.item.id))) }));
|
|
423
|
-
const panels = [];
|
|
424
|
-
if (hasThinking && visible.thinking !== 'hidden') {
|
|
425
|
-
panels.push({
|
|
426
|
-
header: (_jsx(Box, { onClick: (e) => {
|
|
427
|
-
if (e?.shiftKey || e?.ctrlKey) {
|
|
428
|
-
expandAll();
|
|
429
|
-
}
|
|
430
|
-
else {
|
|
431
|
-
setOpenThinking(v => !v);
|
|
432
|
-
}
|
|
433
|
-
}, children: _jsxs(Text, { color: t.color.muted, dim: !thinkingLive, children: [_jsx(Text, { color: t.color.accent, children: openThinking ? '▾ ' : '▸ ' }), thinkingLive ? (_jsx(Text, { bold: true, color: t.color.text, children: "Thinking" })) : (_jsx(Text, { color: t.color.muted, dim: true, children: "Thinking" })), thinkingTokensLabel ? (_jsxs(Text, { color: t.color.statusFg, dim: true, children: [' ', thinkingTokensLabel] })) : null] }) })),
|
|
434
|
-
key: 'thinking',
|
|
435
|
-
open: openThinking,
|
|
436
|
-
render: rails => (_jsx(Thinking, { active: reasoningActive, branch: "last", mode: "full", rails: rails, reasoning: busy ? reasoning : cot, streaming: busy && reasoningStreaming, t: t }))
|
|
437
|
-
});
|
|
438
|
-
}
|
|
439
|
-
if (hasTools && visible.tools !== 'hidden') {
|
|
440
|
-
panels.push({
|
|
441
|
-
header: (_jsx(Chevron, { count: groups.length, onClick: shift => {
|
|
442
|
-
if (shift) {
|
|
443
|
-
expandAll();
|
|
444
|
-
}
|
|
445
|
-
else {
|
|
446
|
-
setOpenTools(v => !v);
|
|
447
|
-
}
|
|
448
|
-
}, open: openTools, suffix: toolTokensLabel, t: t, title: "Tool calls" })),
|
|
449
|
-
key: 'tools',
|
|
450
|
-
open: openTools,
|
|
451
|
-
render: rails => (_jsx(Box, { flexDirection: "column", children: groups.map((group, index) => {
|
|
452
|
-
const branch = index === groups.length - 1 ? 'last' : 'mid';
|
|
453
|
-
const childRails = nextTreeRails(rails, branch);
|
|
454
|
-
const hasInlineSubagents = inlineDelegateKey === group.key;
|
|
455
|
-
return (_jsxs(Box, { flexDirection: "column", children: [_jsx(TreeTextRow, { branch: branch, color: group.color, content: _jsxs(_Fragment, { children: [_jsx(Text, { color: t.color.accent, children: "\u25CF " }), toolLabel(group)] }), rails: rails, t: t }), group.details.map((detail, detailIndex) => (_createElement(Detail, { ...detail, branch: detailIndex === group.details.length - 1 && !hasInlineSubagents ? 'last' : 'mid', key: detail.key, rails: childRails, t: t }))), hasInlineSubagents ? renderSubagentList(childRails) : null] }, group.key));
|
|
456
|
-
}) }))
|
|
457
|
-
});
|
|
458
|
-
}
|
|
459
|
-
if (hasSubagents && !inlineDelegateKey && visible.subagents !== 'hidden') {
|
|
460
|
-
// Spark + summary give a one-line read on the branch shape before
|
|
461
|
-
// opening the subtree. `/agents` opens the full-screen audit overlay.
|
|
462
|
-
const suffix = spawnSpark ? `${spawnSummaryLabel} ${spawnSpark} (/agents)` : `${spawnSummaryLabel} (/agents)`;
|
|
463
|
-
panels.push({
|
|
464
|
-
header: (_jsx(Chevron, { count: spawnTotals.descendantCount, onClick: shift => {
|
|
465
|
-
if (shift) {
|
|
466
|
-
expandAll();
|
|
467
|
-
setDeepSubagents(true);
|
|
468
|
-
}
|
|
469
|
-
else {
|
|
470
|
-
setOpenSubagents(v => !v);
|
|
471
|
-
setDeepSubagents(false);
|
|
472
|
-
}
|
|
473
|
-
}, open: openSubagents, suffix: suffix, t: t, title: "Spawn tree" })),
|
|
474
|
-
key: 'subagents',
|
|
475
|
-
open: openSubagents,
|
|
476
|
-
render: renderSubagentList
|
|
477
|
-
});
|
|
478
|
-
}
|
|
479
|
-
if (hasMeta && visible.activity !== 'hidden') {
|
|
480
|
-
panels.push({
|
|
481
|
-
header: (_jsx(Chevron, { count: meta.length, onClick: shift => {
|
|
482
|
-
if (shift) {
|
|
483
|
-
expandAll();
|
|
484
|
-
}
|
|
485
|
-
else {
|
|
486
|
-
setOpenMeta(v => !v);
|
|
487
|
-
}
|
|
488
|
-
}, open: openMeta, t: t, title: "Activity", tone: metaTone })),
|
|
489
|
-
key: 'meta',
|
|
490
|
-
open: openMeta,
|
|
491
|
-
render: rails => (_jsx(Box, { flexDirection: "column", children: meta.map((row, index) => (_jsx(TreeTextRow, { branch: index === meta.length - 1 ? 'last' : 'mid', color: row.color, content: row.content, dimColor: row.dimColor, rails: rails, t: t }, row.key))) }))
|
|
492
|
-
});
|
|
493
|
-
}
|
|
494
|
-
const topCount = panels.length + (totalTokensLabel ? 1 : 0);
|
|
495
|
-
return (_jsxs(Box, { flexDirection: "column", children: [panels.map((panel, index) => (_jsx(TreeNode, { branch: index === topCount - 1 ? 'last' : 'mid', header: panel.header, open: panel.open, t: t, children: panel.render }, panel.key))), totalTokensLabel ? (_jsx(TreeTextRow, { branch: "last", color: t.color.statusFg, content: _jsxs(_Fragment, { children: [_jsx(Text, { color: t.color.accent, children: "\u03A3 " }), totalTokensLabel] }), dimColor: true, t: t })) : null, outcome ? (_jsx(Box, { marginTop: 1, children: _jsxs(Text, { color: t.color.muted, dim: true, children: ["\u00B7 ", outcome] }) })) : null] }));
|
|
496
|
-
});
|
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
// @ts-nocheck
|
|
3
|
-
// SPDX-License-Identifier: MIT
|
|
4
|
-
// Ported from CVC Agent (https://github.com/NousResearch/cvc)
|
|
5
|
-
// Original Copyright (c) 2025 Nous Research. CVC adaptations (c) 2026 Jai Kumar Meena.
|
|
6
|
-
import { Box, Text } from '@cvc/ink';
|
|
7
|
-
import { memo, useState } from 'react';
|
|
8
|
-
import { countPendingTodos } from '../lib/liveProgress.js';
|
|
9
|
-
import { todoGlyph, todoTone } from '../lib/todo.js';
|
|
10
|
-
const rowColor = (t, status) => {
|
|
11
|
-
const tone = todoTone(status);
|
|
12
|
-
return tone === 'active' ? t.color.text : tone === 'body' ? t.color.statusFg : t.color.muted;
|
|
13
|
-
};
|
|
14
|
-
export const TodoPanel = memo(function TodoPanel({ collapsed, defaultCollapsed = false, incomplete = false, onToggle, t, todos }) {
|
|
15
|
-
// Fallback local state for archived todos in transcript where there's no
|
|
16
|
-
// external controller. Live TodoPanel passes collapsed+onToggle from the
|
|
17
|
-
// turn store so clicks still work there.
|
|
18
|
-
const [localCollapsed, setLocalCollapsed] = useState(defaultCollapsed);
|
|
19
|
-
const isControlled = typeof collapsed === 'boolean';
|
|
20
|
-
const effectiveCollapsed = isControlled ? collapsed : localCollapsed;
|
|
21
|
-
const handleToggle = () => {
|
|
22
|
-
if (onToggle) {
|
|
23
|
-
onToggle();
|
|
24
|
-
return;
|
|
25
|
-
}
|
|
26
|
-
if (!isControlled) {
|
|
27
|
-
setLocalCollapsed(v => !v);
|
|
28
|
-
}
|
|
29
|
-
};
|
|
30
|
-
if (!todos.length) {
|
|
31
|
-
return null;
|
|
32
|
-
}
|
|
33
|
-
const done = todos.filter(todo => todo.status === 'completed').length;
|
|
34
|
-
const pending = countPendingTodos(todos);
|
|
35
|
-
return (_jsxs(Box, { flexDirection: "column", marginBottom: 1, children: [_jsx(Box, { onClick: handleToggle, children: _jsxs(Text, { color: t.color.muted, children: [_jsx(Text, { color: t.color.accent, children: effectiveCollapsed ? '▸ ' : '▾ ' }), _jsx(Text, { bold: true, color: t.color.text, children: "Todo" }), ' ', _jsxs(Text, { color: t.color.statusFg, dim: true, children: ["(", done, "/", todos.length, ")"] }), incomplete && pending > 0 && (_jsxs(Text, { color: t.color.muted, dim: true, children: [' ', "\u00B7 incomplete \u00B7 ", pending, " still ", pending === 1 ? 'pending' : 'pending/in_progress'] }))] }) }), !effectiveCollapsed && (_jsx(Box, { flexDirection: "column", marginLeft: 2, children: todos.map(todo => {
|
|
36
|
-
const tone = todoTone(todo.status);
|
|
37
|
-
const color = rowColor(t, todo.status);
|
|
38
|
-
return (_jsxs(Text, { color: color, dim: tone === 'dim', children: [_jsxs(Text, { color: color, children: [todoGlyph(todo.status), " "] }), todo.content] }, todo.id));
|
|
39
|
-
}) }))] }));
|
|
40
|
-
});
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { Box, Text } from 'ink';
|
|
3
|
-
import { useStore } from '@nanostores/react';
|
|
4
|
-
import { $messages, $turn } from '../app/turnStore.js';
|
|
5
|
-
import { Markdown, StreamingMarkdown } from './streamingMarkdown.js';
|
|
6
|
-
import { CVC_THEME } from '../types.js';
|
|
7
|
-
const Bubble = ({ msg, streaming }) => {
|
|
8
|
-
const isUser = msg.role === 'user';
|
|
9
|
-
const borderColor = isUser ? CVC_THEME.primary : CVC_THEME.dim;
|
|
10
|
-
const tag = isUser ? 'you' : msg.role === 'assistant' ? 'cvc' : msg.role;
|
|
11
|
-
const tagColor = isUser ? CVC_THEME.primary : CVC_THEME.accent;
|
|
12
|
-
return (_jsxs(Box, { flexDirection: "column", marginBottom: 1, children: [_jsx(Text, { bold: true, color: tagColor, children: `▌ ${tag}` }), _jsx(Box, { borderStyle: "round", borderColor: borderColor, paddingX: 1, flexDirection: "column", children: isUser ? (_jsx(Text, { children: msg.content })) : streaming ? (_jsx(StreamingMarkdown, { content: msg.content })) : (_jsx(Markdown, { text: msg.content })) })] }));
|
|
13
|
-
};
|
|
14
|
-
export const Transcript = () => {
|
|
15
|
-
const messages = useStore($messages);
|
|
16
|
-
const turn = useStore($turn);
|
|
17
|
-
if (messages.length === 0) {
|
|
18
|
-
return (_jsx(Box, { marginY: 1, children: _jsx(Text, { color: CVC_THEME.dim, children: "\u2014 no messages yet \u2014 type below to start \u2014" }) }));
|
|
19
|
-
}
|
|
20
|
-
const lastId = messages[messages.length - 1]?.id;
|
|
21
|
-
return (_jsx(Box, { flexDirection: "column", marginY: 1, children: messages.map((m) => (_jsx(Bubble, { msg: m, streaming: m.role === 'assistant' && m.id === lastId && turn?.status === 'streaming' }, m.id))) }));
|
|
22
|
-
};
|
package/dist/config/env.js
DELETED
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
// @ts-nocheck
|
|
2
|
-
// SPDX-License-Identifier: MIT
|
|
3
|
-
// Ported from CVC Agent (https://github.com/NousResearch/cvc)
|
|
4
|
-
// Original Copyright (c) 2025 Nous Research. CVC adaptations (c) 2026 Jai Kumar Meena.
|
|
5
|
-
const truthy = (v) => /^(?:1|true|yes|on)$/i.test((v ?? '').trim());
|
|
6
|
-
export const STARTUP_RESUME_ID = (process.env.CVC_TUI_RESUME ?? '').trim();
|
|
7
|
-
export const STARTUP_QUERY = (process.env.CVC_TUI_QUERY ?? '').trim();
|
|
8
|
-
export const STARTUP_IMAGE = (process.env.CVC_TUI_IMAGE ?? '').trim();
|
|
9
|
-
export const MOUSE_TRACKING = !truthy(process.env.CVC_TUI_DISABLE_MOUSE);
|
|
10
|
-
export const NO_CONFIRM_DESTRUCTIVE = truthy(process.env.CVC_TUI_NO_CONFIRM);
|
|
11
|
-
// Skip AlternateScreen — TUI renders into the primary buffer so the host
|
|
12
|
-
// terminal's native scrollback captures whatever scrolls off the top.
|
|
13
|
-
// Experiment gate: lets us measure native scroll vs our virtualization on
|
|
14
|
-
// the same pipeline.
|
|
15
|
-
export const INLINE_MODE = truthy(process.env.CVC_TUI_INLINE);
|
|
16
|
-
// Live FPS counter overlay, fed by ink's onFrame (real render rate, not a
|
|
17
|
-
// synthetic timer).
|
|
18
|
-
export const SHOW_FPS = truthy(process.env.CVC_TUI_FPS);
|
package/dist/config/limits.js
DELETED
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
// @ts-nocheck
|
|
2
|
-
// SPDX-License-Identifier: MIT
|
|
3
|
-
// Ported from CVC Agent (https://github.com/NousResearch/cvc)
|
|
4
|
-
// Original Copyright (c) 2025 Nous Research. CVC adaptations (c) 2026 Jai Kumar Meena.
|
|
5
|
-
export const LARGE_PASTE = { chars: 8000, lines: 80 };
|
|
6
|
-
export const LIVE_RENDER_MAX_CHARS = 16_000;
|
|
7
|
-
export const LIVE_RENDER_MAX_LINES = 240;
|
|
8
|
-
// History-render bounds for messages outside FULL_RENDER_TAIL. Each rendered
|
|
9
|
-
// line ≈ 1 Yoga/Text node + inline spans, so this is the dominant lever on
|
|
10
|
-
// cold-mount cost during PageUp catch-up. 16 lines × 25 mounted ≈ 400 nodes
|
|
11
|
-
// — comfortably inside the 16ms per-frame budget. User pages back to
|
|
12
|
-
// recognize, not to read; full re-render once it falls inside the tail.
|
|
13
|
-
export const HISTORY_RENDER_MAX_CHARS = 800;
|
|
14
|
-
export const HISTORY_RENDER_MAX_LINES = 16;
|
|
15
|
-
export const FULL_RENDER_TAIL_ITEMS = 8;
|
|
16
|
-
export const LONG_MSG = 300;
|
|
17
|
-
export const MAX_HISTORY = 800;
|
|
18
|
-
export const THINKING_COT_MAX = 160;
|
|
19
|
-
// Rows per wheel event (pre-accel). 1 keeps Ink's DECSTBM fast path live
|
|
20
|
-
// (each scroll < viewport-1) and produces smooth motion. wheelAccel.ts
|
|
21
|
-
// ramps this on sustained scrolls.
|
|
22
|
-
export const WHEEL_SCROLL_STEP = 1;
|
package/dist/config/timing.js
DELETED
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
// @ts-nocheck
|
|
2
|
-
// SPDX-License-Identifier: MIT
|
|
3
|
-
// Ported from CVC Agent (https://github.com/NousResearch/cvc)
|
|
4
|
-
// Original Copyright (c) 2025 Nous Research. CVC adaptations (c) 2026 Jai Kumar Meena.
|
|
5
|
-
// Centralised timing constants for the CVC TUI.
|
|
6
|
-
// Keep all magic numbers controlling UI cadence in this file.
|
|
7
|
-
export const TIMING = {
|
|
8
|
-
/** Spinner frame interval (ms) */
|
|
9
|
-
SPINNER_FRAME_MS: 80,
|
|
10
|
-
/** Throttle for streaming markdown re-renders (ms) */
|
|
11
|
-
STREAM_THROTTLE_MS: 16,
|
|
12
|
-
/** Debounce on text-input change handlers (ms) */
|
|
13
|
-
INPUT_DEBOUNCE_MS: 0,
|
|
14
|
-
/** Gateway connect retry backoff (ms) */
|
|
15
|
-
GATEWAY_RECONNECT_MS: 1500,
|
|
16
|
-
/** Heartbeat ping interval (ms) */
|
|
17
|
-
HEARTBEAT_MS: 15000,
|
|
18
|
-
};
|
package/dist/content/charms.js
DELETED
|
@@ -1,5 +0,0 @@
|
|
|
1
|
-
// @ts-nocheck
|
|
2
|
-
// SPDX-License-Identifier: MIT
|
|
3
|
-
// Ported from CVC Agent (https://github.com/NousResearch/cvc)
|
|
4
|
-
// Original Copyright (c) 2025 Nous Research. CVC adaptations (c) 2026 Jai Kumar Meena.
|
|
5
|
-
export const LONG_RUN_CHARMS = ['still cooking…', 'polishing edges…', 'asking the void nicely…'];
|